aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/graphql/models/lazy_bug.go6
-rw-r--r--api/graphql/models/lazy_identity.go6
-rw-r--r--bridge/github/client.go106
-rw-r--r--bridge/github/export.go15
-rw-r--r--bridge/github/import_events.go40
-rw-r--r--bridge/github/import_mediator.go134
-rw-r--r--cache/repo_cache_bug.go4
-rw-r--r--commands/add_test.go32
-rw-r--r--commands/env.go4
-rw-r--r--commands/env_testing.go48
-rw-r--r--commands/rm_test.go17
-rw-r--r--commands/user_create_test.go36
-rw-r--r--entity/dag/example_test.go7
-rw-r--r--go.mod7
-rw-r--r--go.sum51
-rw-r--r--misc/random_bugs/cmd/main.go4
-rw-r--r--repository/gogit.go52
-rw-r--r--repository/gogit_test.go49
-rw-r--r--repository/gogit_testing.go6
19 files changed, 405 insertions, 219 deletions
diff --git a/api/graphql/models/lazy_bug.go b/api/graphql/models/lazy_bug.go
index a7840df2..bc26aaca 100644
--- a/api/graphql/models/lazy_bug.go
+++ b/api/graphql/models/lazy_bug.go
@@ -49,13 +49,13 @@ func NewLazyBug(cache *cache.RepoCache, excerpt *cache.BugExcerpt) *lazyBug {
}
func (lb *lazyBug) load() error {
+ lb.mu.Lock()
+ defer lb.mu.Unlock()
+
if lb.snap != nil {
return nil
}
- lb.mu.Lock()
- defer lb.mu.Unlock()
-
b, err := lb.cache.ResolveBug(lb.excerpt.Id)
if err != nil {
return err
diff --git a/api/graphql/models/lazy_identity.go b/api/graphql/models/lazy_identity.go
index 002c38e4..451bdd54 100644
--- a/api/graphql/models/lazy_identity.go
+++ b/api/graphql/models/lazy_identity.go
@@ -41,13 +41,13 @@ func NewLazyIdentity(cache *cache.RepoCache, excerpt *cache.IdentityExcerpt) *la
}
func (li *lazyIdentity) load() (*cache.IdentityCache, error) {
+ li.mu.Lock()
+ defer li.mu.Unlock()
+
if li.id != nil {
return li.id, nil
}
- li.mu.Lock()
- defer li.mu.Unlock()
-
id, err := li.cache.ResolveIdentity(li.excerpt.Id)
if err != nil {
return nil, fmt.Errorf("cache: missing identity %v", li.excerpt.Id)
diff --git a/bridge/github/client.go b/bridge/github/client.go
index 10f0a03c..00981a56 100644
--- a/bridge/github/client.go
+++ b/bridge/github/client.go
@@ -7,8 +7,9 @@ import (
"strings"
"time"
- "github.com/MichaelMure/git-bug/bridge/core"
"github.com/shurcooL/githubv4"
+
+ "github.com/MichaelMure/git-bug/bridge/core"
)
var _ Client = &githubv4.Client{}
@@ -29,79 +30,69 @@ func newRateLimitHandlerClient(httpClient *http.Client) *rateLimitHandlerClient
return &rateLimitHandlerClient{sc: githubv4.NewClient(httpClient)}
}
-type RateLimitingEvent struct {
- msg string
-}
-
-// mutate calls the github api with a graphql mutation and for each rate limiting event it sends an
-// export result.
+// mutate calls the github api with a graphql mutation and sends a core.ExportResult for each rate limiting event
func (c *rateLimitHandlerClient) mutate(ctx context.Context, m interface{}, input githubv4.Input, vars map[string]interface{}, out chan<- core.ExportResult) error {
// prepare a closure for the mutation
mutFun := func(ctx context.Context) error {
return c.sc.Mutate(ctx, m, input, vars)
}
- limitEvents := make(chan RateLimitingEvent)
- defer close(limitEvents)
- go func() {
- for e := range limitEvents {
- select {
- case <-ctx.Done():
- return
- case out <- core.NewExportRateLimiting(e.msg):
- }
+ callback := func(msg string) {
+ select {
+ case <-ctx.Done():
+ case out <- core.NewExportRateLimiting(msg):
}
- }()
- return c.callAPIAndRetry(mutFun, ctx, limitEvents)
+ }
+ return c.callAPIAndRetry(ctx, mutFun, callback)
}
-// queryWithLimitEvents calls the github api with a graphql query and it sends rate limiting events
-// to a given channel of type RateLimitingEvent.
-func (c *rateLimitHandlerClient) queryWithLimitEvents(ctx context.Context, query interface{}, vars map[string]interface{}, limitEvents chan<- RateLimitingEvent) error {
- // prepare a closure fot the query
+// queryImport calls the github api with a graphql query, and sends an ImportEvent for each rate limiting event
+func (c *rateLimitHandlerClient) queryImport(ctx context.Context, query interface{}, vars map[string]interface{}, importEvents chan<- ImportEvent) error {
+ // prepare a closure for the query
queryFun := func(ctx context.Context) error {
return c.sc.Query(ctx, query, vars)
}
- return c.callAPIAndRetry(queryFun, ctx, limitEvents)
+ callback := func(msg string) {
+ select {
+ case <-ctx.Done():
+ case importEvents <- RateLimitingEvent{msg}:
+ }
+ }
+ return c.callAPIAndRetry(ctx, queryFun, callback)
}
-// queryWithImportEvents calls the github api with a graphql query and it sends rate limiting events
-// to a given channel of type ImportEvent.
-func (c *rateLimitHandlerClient) queryWithImportEvents(ctx context.Context, query interface{}, vars map[string]interface{}, importEvents chan<- ImportEvent) error {
- // forward rate limiting events to channel of import events
- limitEvents := make(chan RateLimitingEvent)
- defer close(limitEvents)
- go func() {
- for e := range limitEvents {
- select {
- case <-ctx.Done():
- return
- case importEvents <- e:
- }
+// queryImport calls the github api with a graphql query, and sends a core.ExportResult for each rate limiting event
+func (c *rateLimitHandlerClient) queryExport(ctx context.Context, query interface{}, vars map[string]interface{}, out chan<- core.ExportResult) error {
+ // prepare a closure for the query
+ queryFun := func(ctx context.Context) error {
+ return c.sc.Query(ctx, query, vars)
+ }
+ callback := func(msg string) {
+ select {
+ case <-ctx.Done():
+ case out <- core.NewExportRateLimiting(msg):
}
- }()
- return c.queryWithLimitEvents(ctx, query, vars, limitEvents)
+ }
+ return c.callAPIAndRetry(ctx, queryFun, callback)
}
-// queryPrintMsgs calls the github api with a graphql query and it prints for ever rate limiting
-// event a message to stdout.
+// queryPrintMsgs calls the github api with a graphql query, and prints a message to stdout for every rate limiting event .
func (c *rateLimitHandlerClient) queryPrintMsgs(ctx context.Context, query interface{}, vars map[string]interface{}) error {
- // print rate limiting events directly to stdout.
- limitEvents := make(chan RateLimitingEvent)
- defer close(limitEvents)
- go func() {
- for e := range limitEvents {
- fmt.Println(e.msg)
- }
- }()
- return c.queryWithLimitEvents(ctx, query, vars, limitEvents)
+ // prepare a closure for the query
+ queryFun := func(ctx context.Context) error {
+ return c.sc.Query(ctx, query, vars)
+ }
+ callback := func(msg string) {
+ fmt.Println(msg)
+ }
+ return c.callAPIAndRetry(ctx, queryFun, callback)
}
// callAPIAndRetry calls the Github GraphQL API (inderectely through callAPIDealWithLimit) and in
// case of error it repeats the request to the Github API. The parameter `apiCall` is intended to be
// a closure containing a query or a mutation to the Github GraphQL API.
-func (c *rateLimitHandlerClient) callAPIAndRetry(apiCall func(context.Context) error, ctx context.Context, events chan<- RateLimitingEvent) error {
+func (c *rateLimitHandlerClient) callAPIAndRetry(ctx context.Context, apiCall func(context.Context) error, rateLimitEvent func(msg string)) error {
var err error
- if err = c.callAPIDealWithLimit(apiCall, ctx, events); err == nil {
+ if err = c.callAPIDealWithLimit(ctx, apiCall, rateLimitEvent); err == nil {
return nil
}
// failure; the reason may be temporary network problems or internal errors
@@ -117,7 +108,7 @@ func (c *rateLimitHandlerClient) callAPIAndRetry(apiCall func(context.Context) e
stop(timer)
return ctx.Err()
case <-timer.C:
- err = c.callAPIDealWithLimit(apiCall, ctx, events)
+ err = c.callAPIDealWithLimit(ctx, apiCall, rateLimitEvent)
if err == nil {
return nil
}
@@ -127,10 +118,10 @@ func (c *rateLimitHandlerClient) callAPIAndRetry(apiCall func(context.Context) e
}
// callAPIDealWithLimit calls the Github GraphQL API and if the Github API returns a rate limiting
-// error, then it waits until the rate limit is reset and it repeats the request to the API. The
+// error, then it waits until the rate limit is reset, and it repeats the request to the API. The
// parameter `apiCall` is intended to be a closure containing a query or a mutation to the Github
// GraphQL API.
-func (c *rateLimitHandlerClient) callAPIDealWithLimit(apiCall func(context.Context) error, ctx context.Context, events chan<- RateLimitingEvent) error {
+func (c *rateLimitHandlerClient) callAPIDealWithLimit(ctx context.Context, apiCall func(context.Context) error, rateLimitCallback func(msg string)) error {
qctx, cancel := context.WithTimeout(ctx, defaultTimeout)
defer cancel()
// call the function fun()
@@ -155,11 +146,8 @@ func (c *rateLimitHandlerClient) callAPIDealWithLimit(apiCall func(context.Conte
resetTime.String(),
)
// Send message about rate limiting event.
- select {
- case <-ctx.Done():
- return ctx.Err()
- case events <- RateLimitingEvent{msg}:
- }
+ rateLimitCallback(msg)
+
// Pause current goroutine
timer := time.NewTimer(time.Until(resetTime))
select {
diff --git a/bridge/github/export.go b/bridge/github/export.go
index 8c40eb74..35d456c2 100644
--- a/bridge/github/export.go
+++ b/bridge/github/export.go
@@ -486,23 +486,10 @@ func (ge *githubExporter) cacheGithubLabels(ctx context.Context, gc *rateLimitHa
}
q := labelsQuery{}
- // When performing the queries we have to forward rate limiting events to the
- // current channel of export results.
- events := make(chan RateLimitingEvent)
- defer close(events)
- go func() {
- for e := range events {
- select {
- case <-ctx.Done():
- return
- case ge.out <- core.NewExportRateLimiting(e.msg):
- }
- }
- }()
hasNextPage := true
for hasNextPage {
- if err := gc.queryWithLimitEvents(ctx, &q, variables, events); err != nil {
+ if err := gc.queryExport(ctx, &q, variables, ge.out); err != nil {
return err
}
diff --git a/bridge/github/import_events.go b/bridge/github/import_events.go
new file mode 100644
index 00000000..7ae86d75
--- /dev/null
+++ b/bridge/github/import_events.go
@@ -0,0 +1,40 @@
+package github
+
+import "github.com/shurcooL/githubv4"
+
+type ImportEvent interface {
+ isImportEvent()
+}
+
+type RateLimitingEvent struct {
+ msg string
+}
+
+func (RateLimitingEvent) isImportEvent() {}
+
+type IssueEvent struct {
+ issue
+}
+
+func (IssueEvent) isImportEvent() {}
+
+type IssueEditEvent struct {
+ issueId githubv4.ID
+ userContentEdit
+}
+
+func (IssueEditEvent) isImportEvent() {}
+
+type TimelineEvent struct {
+ issueId githubv4.ID
+ timelineItem
+}
+
+func (TimelineEvent) isImportEvent() {}
+
+type CommentEditEvent struct {
+ commentId githubv4.ID
+ userContentEdit
+}
+
+func (CommentEditEvent) isImportEvent() {}
diff --git a/bridge/github/import_mediator.go b/bridge/github/import_mediator.go
index db9f877c..be4e3880 100644
--- a/bridge/github/import_mediator.go
+++ b/bridge/github/import_mediator.go
@@ -9,6 +9,7 @@ import (
const (
// These values influence how fast the github graphql rate limit is exhausted.
+
NumIssues = 40
NumIssueEdits = 100
NumTimelineItems = 100
@@ -41,43 +42,6 @@ type importMediator struct {
err error
}
-type ImportEvent interface {
- isImportEvent()
-}
-
-func (RateLimitingEvent) isImportEvent() {}
-
-type IssueEvent struct {
- issue
-}
-
-func (IssueEvent) isImportEvent() {}
-
-type IssueEditEvent struct {
- issueId githubv4.ID
- userContentEdit
-}
-
-func (IssueEditEvent) isImportEvent() {}
-
-type TimelineEvent struct {
- issueId githubv4.ID
- timelineItem
-}
-
-func (TimelineEvent) isImportEvent() {}
-
-type CommentEditEvent struct {
- commentId githubv4.ID
- userContentEdit
-}
-
-func (CommentEditEvent) isImportEvent() {}
-
-func (mm *importMediator) NextImportEvent() ImportEvent {
- return <-mm.importEvents
-}
-
func NewImportMediator(ctx context.Context, client *rateLimitHandlerClient, owner, project string, since time.Time) *importMediator {
mm := importMediator{
gh: client,
@@ -87,48 +51,24 @@ func NewImportMediator(ctx context.Context, client *rateLimitHandlerClient, owne
importEvents: make(chan ImportEvent, ChanCapacity),
err: nil,
}
- go func() {
- mm.fillImportEvents(ctx)
- close(mm.importEvents)
- }()
- return &mm
-}
-type varmap map[string]interface{}
+ go mm.start(ctx)
-func newIssueVars(owner, project string, since time.Time) varmap {
- return varmap{
- "owner": githubv4.String(owner),
- "name": githubv4.String(project),
- "issueSince": githubv4.DateTime{Time: since},
- "issueFirst": githubv4.Int(NumIssues),
- "issueEditLast": githubv4.Int(NumIssueEdits),
- "issueEditBefore": (*githubv4.String)(nil),
- "timelineFirst": githubv4.Int(NumTimelineItems),
- "timelineAfter": (*githubv4.String)(nil),
- "commentEditLast": githubv4.Int(NumCommentEdits),
- "commentEditBefore": (*githubv4.String)(nil),
- }
-}
-
-func newIssueEditVars() varmap {
- return varmap{
- "issueEditLast": githubv4.Int(NumIssueEdits),
- }
+ return &mm
}
-func newTimelineVars() varmap {
- return varmap{
- "timelineFirst": githubv4.Int(NumTimelineItems),
- "commentEditLast": githubv4.Int(NumCommentEdits),
- "commentEditBefore": (*githubv4.String)(nil),
- }
+func (mm *importMediator) start(ctx context.Context) {
+ ctx, cancel := context.WithCancel(ctx)
+ mm.fillImportEvents(ctx)
+ // Make sure we cancel everything when we are done, instead of relying on the parent context
+ // This should unblock pending send to the channel if the capacity was reached and avoid a panic/race when closing.
+ cancel()
+ close(mm.importEvents)
}
-func newCommentEditVars() varmap {
- return varmap{
- "commentEditLast": githubv4.Int(NumCommentEdits),
- }
+// NextImportEvent returns the next ImportEvent, or nil if done.
+func (mm *importMediator) NextImportEvent() ImportEvent {
+ return <-mm.importEvents
}
func (mm *importMediator) Error() error {
@@ -138,7 +78,7 @@ func (mm *importMediator) Error() error {
func (mm *importMediator) User(ctx context.Context, loginName string) (*user, error) {
query := userQuery{}
vars := varmap{"login": githubv4.String(loginName)}
- if err := mm.gh.queryWithImportEvents(ctx, &query, vars, mm.importEvents); err != nil {
+ if err := mm.gh.queryImport(ctx, &query, vars, mm.importEvents); err != nil {
return nil, err
}
return &query.User, nil
@@ -200,7 +140,7 @@ func (mm *importMediator) queryIssueEdits(ctx context.Context, nid githubv4.ID,
vars["issueEditBefore"] = cursor
}
query := issueEditQuery{}
- if err := mm.gh.queryWithImportEvents(ctx, &query, vars, mm.importEvents); err != nil {
+ if err := mm.gh.queryImport(ctx, &query, vars, mm.importEvents); err != nil {
mm.err = err
return nil, false
}
@@ -244,7 +184,7 @@ func (mm *importMediator) queryTimeline(ctx context.Context, nid githubv4.ID, cu
vars["timelineAfter"] = cursor
}
query := timelineQuery{}
- if err := mm.gh.queryWithImportEvents(ctx, &query, vars, mm.importEvents); err != nil {
+ if err := mm.gh.queryImport(ctx, &query, vars, mm.importEvents); err != nil {
mm.err = err
return nil, false
}
@@ -294,7 +234,7 @@ func (mm *importMediator) queryCommentEdits(ctx context.Context, nid githubv4.ID
vars["commentEditBefore"] = cursor
}
query := commentEditQuery{}
- if err := mm.gh.queryWithImportEvents(ctx, &query, vars, mm.importEvents); err != nil {
+ if err := mm.gh.queryImport(ctx, &query, vars, mm.importEvents); err != nil {
mm.err = err
return nil, false
}
@@ -313,7 +253,7 @@ func (mm *importMediator) queryIssue(ctx context.Context, cursor githubv4.String
vars["issueAfter"] = cursor
}
query := issueQuery{}
- if err := mm.gh.queryWithImportEvents(ctx, &query, vars, mm.importEvents); err != nil {
+ if err := mm.gh.queryImport(ctx, &query, vars, mm.importEvents); err != nil {
mm.err = err
return nil, false
}
@@ -334,3 +274,41 @@ func reverse(eds []userContentEdit) chan userContentEdit {
}()
return ret
}
+
+// varmap is a container for Github API's pagination variables
+type varmap map[string]interface{}
+
+func newIssueVars(owner, project string, since time.Time) varmap {
+ return varmap{
+ "owner": githubv4.String(owner),
+ "name": githubv4.String(project),
+ "issueSince": githubv4.DateTime{Time: since},
+ "issueFirst": githubv4.Int(NumIssues),
+ "issueEditLast": githubv4.Int(NumIssueEdits),
+ "issueEditBefore": (*githubv4.String)(nil),
+ "timelineFirst": githubv4.Int(NumTimelineItems),
+ "timelineAfter": (*githubv4.String)(nil),
+ "commentEditLast": githubv4.Int(NumCommentEdits),
+ "commentEditBefore": (*githubv4.String)(nil),
+ }
+}
+
+func newIssueEditVars() varmap {
+ return varmap{
+ "issueEditLast": githubv4.Int(NumIssueEdits),
+ }
+}
+
+func newTimelineVars() varmap {
+ return varmap{
+ "timelineFirst": githubv4.Int(NumTimelineItems),
+ "commentEditLast": githubv4.Int(NumCommentEdits),
+ "commentEditBefore": (*githubv4.String)(nil),
+ }
+}
+
+func newCommentEditVars() varmap {
+ return varmap{
+ "commentEditLast": githubv4.Int(NumCommentEdits),
+ }
+}
diff --git a/cache/repo_cache_bug.go b/cache/repo_cache_bug.go
index bce01926..f8bf5a2f 100644
--- a/cache/repo_cache_bug.go
+++ b/cache/repo_cache_bug.go
@@ -499,14 +499,10 @@ func (c *RepoCache) NewBugRaw(author *IdentityCache, unixTime int64, title strin
// RemoveBug removes a bug from the cache and repo given a bug id prefix
func (c *RepoCache) RemoveBug(prefix string) error {
- c.muBug.RLock()
-
b, err := c.ResolveBugPrefix(prefix)
if err != nil {
- c.muBug.RUnlock()
return err
}
- c.muBug.RUnlock()
c.muBug.Lock()
err = bug.RemoveBug(c.repo, b.Id())
diff --git a/commands/add_test.go b/commands/add_test.go
new file mode 100644
index 00000000..63eda06e
--- /dev/null
+++ b/commands/add_test.go
@@ -0,0 +1,32 @@
+package commands
+
+import (
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func newTestEnvUserAndBug(t *testing.T) (*testEnv, string, string) {
+ t.Helper()
+
+ testEnv, userID := newTestEnvAndUser(t)
+ opts := addOptions{
+ title: "this is a bug title",
+ message: "this is a bug message",
+ messageFile: "",
+ nonInteractive: true,
+ }
+
+ require.NoError(t, runAdd(testEnv.env, opts))
+ require.Regexp(t, "^[0-9A-Fa-f]{7} created\n$", testEnv.out)
+ bugID := strings.Split(testEnv.out.String(), " ")[0]
+ testEnv.out.Reset()
+
+ return testEnv, userID, bugID
+}
+
+func TestAdd(t *testing.T) {
+ _, _, user := newTestEnvUserAndBug(t)
+ require.Regexp(t, "^[0-9A-Fa-f]{7}$", user)
+}
diff --git a/commands/env.go b/commands/env.go
index ac7b789a..a6bca7e4 100644
--- a/commands/env.go
+++ b/commands/env.go
@@ -14,6 +14,8 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
+const gitBugNamespace = "git-bug"
+
// Env is the environment of a command
type Env struct {
repo repository.ClockedRepo
@@ -54,7 +56,7 @@ func loadRepo(env *Env) func(*cobra.Command, []string) error {
return fmt.Errorf("unable to get the current working directory: %q", err)
}
- env.repo, err = repository.OpenGoGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
+ env.repo, err = repository.OpenGoGitRepo(cwd, gitBugNamespace, []repository.ClockLoader{bug.ClockLoader})
if err == repository.ErrNotARepo {
return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
}
diff --git a/commands/env_testing.go b/commands/env_testing.go
new file mode 100644
index 00000000..4de66a9d
--- /dev/null
+++ b/commands/env_testing.go
@@ -0,0 +1,48 @@
+package commands
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/repository"
+)
+
+type testEnv struct {
+ env *Env
+ cwd string
+ out *bytes.Buffer
+}
+
+func newTestEnv(t *testing.T) *testEnv {
+ t.Helper()
+
+ cwd := t.TempDir()
+
+ repo, err := repository.InitGoGitRepo(cwd, gitBugNamespace)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ require.NoError(t, repo.Close())
+ })
+
+ buf := new(bytes.Buffer)
+
+ backend, err := cache.NewRepoCache(repo)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ backend.Close()
+ })
+
+ return &testEnv{
+ env: &Env{
+ repo: repo,
+ backend: backend,
+ out: out{Writer: buf},
+ err: out{Writer: buf},
+ },
+ cwd: cwd,
+ out: buf,
+ }
+}
diff --git a/commands/rm_test.go b/commands/rm_test.go
new file mode 100644
index 00000000..5d4e7cca
--- /dev/null
+++ b/commands/rm_test.go
@@ -0,0 +1,17 @@
+package commands
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestRm(t *testing.T) {
+ testEnv, _, bugID := newTestEnvUserAndBug(t)
+
+ exp := "bug " + bugID + " removed\n"
+
+ require.NoError(t, runRm(testEnv.env, []string{bugID}))
+ require.Equal(t, exp, testEnv.out.String())
+ testEnv.out.Reset()
+}
diff --git a/commands/user_create_test.go b/commands/user_create_test.go
new file mode 100644
index 00000000..223e7ec3
--- /dev/null
+++ b/commands/user_create_test.go
@@ -0,0 +1,36 @@
+package commands
+
+import (
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func newTestEnvAndUser(t *testing.T) (*testEnv, string) {
+ t.Helper()
+
+ testEnv := newTestEnv(t)
+
+ opts := createUserOptions{
+ name: "John Doe",
+ email: "jdoe@example.com",
+ avatarURL: "",
+ nonInteractive: true,
+ }
+
+ require.NoError(t, runUserCreate(testEnv.env, opts))
+
+ userID := strings.TrimSpace(testEnv.out.String())
+ testEnv.out.Reset()
+
+ return testEnv, userID
+}
+
+func TestUserCreateCommand(t *testing.T) {
+ testEnv, userID := newTestEnvAndUser(t)
+
+ require.FileExists(t, filepath.Join(testEnv.cwd, ".git", "refs", "identities", userID))
+ require.FileExists(t, filepath.Join(testEnv.cwd, ".git", "git-bug", "identity-cache"))
+}
diff --git a/entity/dag/example_test.go b/entity/dag/example_test.go
index d034e59d..948d6aeb 100644
--- a/entity/dag/example_test.go
+++ b/entity/dag/example_test.go
@@ -336,14 +336,17 @@ func Read(repo repository.ClockedRepo, id entity.Id) (*ProjectConfig, error) {
}
func Example_entity() {
+ const gitBugNamespace = "git-bug"
// Note: this example ignore errors for readability
// Note: variable names get a little confusing as we are simulating both side in the same function
// Let's start by defining two git repository and connecting them as remote
repoRenePath, _ := os.MkdirTemp("", "")
repoIsaacPath, _ := os.MkdirTemp("", "")
- repoRene, _ := repository.InitGoGitRepo(repoRenePath)
- repoIsaac, _ := repository.InitGoGitRepo(repoIsaacPath)
+ repoRene, _ := repository.InitGoGitRepo(repoRenePath, gitBugNamespace)
+ defer repoRene.Close()
+ repoIsaac, _ := repository.InitGoGitRepo(repoIsaacPath, gitBugNamespace)
+ defer repoIsaac.Close()
_ = repoRene.AddRemote("origin", repoIsaacPath)
_ = repoIsaac.AddRemote("origin", repoRenePath)
diff --git a/go.mod b/go.mod
index 0cca0abc..d137f2c2 100644
--- a/go.mod
+++ b/go.mod
@@ -26,13 +26,12 @@ require (
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f // indirect
github.com/skratchdot/open-golang v0.0.0-20190402232053-79abb63cd66e
github.com/spf13/cobra v1.4.0
- github.com/stretchr/testify v1.7.1
+ github.com/stretchr/testify v1.7.2
github.com/vektah/gqlparser/v2 v2.4.1
- github.com/xanzy/go-gitlab v0.64.0
+ github.com/xanzy/go-gitlab v0.68.0
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838
- golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
+ golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a
golang.org/x/text v0.3.7
- golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
)
diff --git a/go.sum b/go.sum
index afb542a8..8c8a995d 100644
--- a/go.sum
+++ b/go.sum
@@ -199,8 +199,10 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@@ -213,8 +215,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -237,12 +240,13 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
-github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
-github.com/hashicorp/go-retryablehttp v0.6.8 h1:92lWxgpa+fF3FozM4B3UZtHZMJX8T5XT+TFdCxsPyWs=
-github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
+github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
+github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
@@ -362,8 +366,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
+github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tebeka/snowball v0.4.2/go.mod h1:4IfL14h1lvwZcp1sfXuuc7/7yCsvVffTWxWxCLfFpYg=
@@ -378,8 +382,8 @@ github.com/vektah/gqlparser/v2 v2.4.1 h1:QOyEn8DAPMUMARGMeshKDkDgNmVoEaEGiDB0uWx
github.com/vektah/gqlparser/v2 v2.4.1/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
-github.com/xanzy/go-gitlab v0.64.0 h1:rMgQdW9S1w3qvNAH2LYpFd2xh7KNLk+JWJd7sorNuTc=
-github.com/xanzy/go-gitlab v0.64.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM=
+github.com/xanzy/go-gitlab v0.68.0 h1:b2iMQHgZ1V+NyRqLRJVv6RFfr4xnd/AASeS/PETYL0Y=
+github.com/xanzy/go-gitlab v0.68.0/go.mod h1:o4yExCtdaqlM8YGdDJWuZoBmfxBsmA9TPEjs9mx1UO4=
github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
@@ -463,20 +467,20 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2 h1:NWy5+hlRbC7HK+PmcXVUmW1IMyFce7to56IUvhUFm7Y=
+golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
-golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -485,7 +489,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -521,7 +524,6 @@ golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -531,6 +533,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE=
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -548,8 +551,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e h1:EHBhcS0mlXEAVwNyO2dLfjToGsyY4j24pTs2ScHnX7s=
-golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
+golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -614,13 +617,13 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
-google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -671,8 +674,11 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -694,8 +700,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/misc/random_bugs/cmd/main.go b/misc/random_bugs/cmd/main.go
index 010ae6d1..c3506efb 100644
--- a/misc/random_bugs/cmd/main.go
+++ b/misc/random_bugs/cmd/main.go
@@ -11,6 +11,8 @@ import (
// This program will randomly generate a collection of bugs in the repository
// of the current path
func main() {
+ const gitBugNamespace = "git-bug"
+
dir, err := os.Getwd()
if err != nil {
panic(err)
@@ -20,7 +22,7 @@ func main() {
bug.ClockLoader,
}
- repo, err := repository.OpenGoGitRepo(dir, loaders)
+ repo, err := repository.OpenGoGitRepo(dir, gitBugNamespace, loaders)
if err != nil {
panic(err)
}
diff --git a/repository/gogit.go b/repository/gogit.go
index 54677902..71cddfb2 100644
--- a/repository/gogit.go
+++ b/repository/gogit.go
@@ -26,6 +26,7 @@ import (
)
const clockPath = "clocks"
+const indexPath = "indexes"
var _ ClockedRepo = &GoGitRepo{}
var _ TestedRepo = &GoGitRepo{}
@@ -49,8 +50,11 @@ type GoGitRepo struct {
localStorage billy.Filesystem
}
-// OpenGoGitRepo open an already existing repo at the given path
-func OpenGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error) {
+// OpenGoGitRepo opens an already existing repo at the given path and
+// with the specified LocalStorage namespace. Given a repository path
+// of "~/myrepo" and a namespace of "git-bug", local storage for the
+// GoGitRepo will be configured at "~/myrepo/.git/git-bug".
+func OpenGoGitRepo(path, namespace string, clockLoaders []ClockLoader) (*GoGitRepo, error) {
path, err := detectGitPath(path)
if err != nil {
return nil, err
@@ -72,7 +76,7 @@ func OpenGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error)
clocks: make(map[string]lamport.Clock),
indexes: make(map[string]bleve.Index),
keyring: k,
- localStorage: osfs.New(filepath.Join(path, "git-bug")),
+ localStorage: osfs.New(filepath.Join(path, namespace)),
}
for _, loader := range clockLoaders {
@@ -94,8 +98,11 @@ func OpenGoGitRepo(path string, clockLoaders []ClockLoader) (*GoGitRepo, error)
return repo, nil
}
-// InitGoGitRepo create a new empty git repo at the given path
-func InitGoGitRepo(path string) (*GoGitRepo, error) {
+// InitGoGitRepo creates a new empty git repo at the given path and
+// with the specified LocalStorage namespace. Given a repository path
+// of "~/myrepo" and a namespace of "git-bug", local storage for the
+// GoGitRepo will be configured at "~/myrepo/.git/git-bug".
+func InitGoGitRepo(path, namespace string) (*GoGitRepo, error) {
r, err := gogit.PlainInit(path, false)
if err != nil {
return nil, err
@@ -112,12 +119,15 @@ func InitGoGitRepo(path string) (*GoGitRepo, error) {
clocks: make(map[string]lamport.Clock),
indexes: make(map[string]bleve.Index),
keyring: k,
- localStorage: osfs.New(filepath.Join(path, ".git", "git-bug")),
+ localStorage: osfs.New(filepath.Join(path, ".git", namespace)),
}, nil
}
-// InitBareGoGitRepo create a new --bare empty git repo at the given path
-func InitBareGoGitRepo(path string) (*GoGitRepo, error) {
+// InitBareGoGitRepo creates a new --bare empty git repo at the given
+// path and with the specified LocalStorage namespace. Given a repository
+// path of "~/myrepo" and a namespace of "git-bug", local storage for the
+// GoGitRepo will be configured at "~/myrepo/.git/git-bug".
+func InitBareGoGitRepo(path, namespace string) (*GoGitRepo, error) {
r, err := gogit.PlainInit(path, true)
if err != nil {
return nil, err
@@ -134,7 +144,7 @@ func InitBareGoGitRepo(path string) (*GoGitRepo, error) {
clocks: make(map[string]lamport.Clock),
indexes: make(map[string]bleve.Index),
keyring: k,
- localStorage: osfs.New(filepath.Join(path, "git-bug")),
+ localStorage: osfs.New(filepath.Join(path, namespace)),
}, nil
}
@@ -295,7 +305,8 @@ func (repo *GoGitRepo) GetRemotes() (map[string]string, error) {
return result, nil
}
-// LocalStorage return a billy.Filesystem giving access to $RepoPath/.git/git-bug
+// LocalStorage returns a billy.Filesystem giving access to
+// $RepoPath/.git/$Namespace.
func (repo *GoGitRepo) LocalStorage() billy.Filesystem {
return repo.localStorage
}
@@ -309,7 +320,7 @@ func (repo *GoGitRepo) GetBleveIndex(name string) (bleve.Index, error) {
return index, nil
}
- path := filepath.Join(repo.path, "git-bug", "indexes", name)
+ path := filepath.Join(repo.localStorage.Root(), indexPath, name)
index, err := bleve.Open(path)
if err == nil {
@@ -340,21 +351,20 @@ func (repo *GoGitRepo) ClearBleveIndex(name string) error {
repo.indexesMutex.Lock()
defer repo.indexesMutex.Unlock()
- path := filepath.Join(repo.path, "git-bug", "indexes", name)
-
- err := os.RemoveAll(path)
- if err != nil {
- return err
- }
-
if index, ok := repo.indexes[name]; ok {
- err = index.Close()
+ err := index.Close()
if err != nil {
return err
}
delete(repo.indexes, name)
}
+ path := filepath.Join(repo.localStorage.Root(), indexPath, name)
+ err := os.RemoveAll(path)
+ if err != nil {
+ return err
+ }
+
return nil
}
@@ -569,7 +579,7 @@ func (repo *GoGitRepo) StoreCommit(treeHash Hash, parents ...Hash) (Hash, error)
return repo.StoreSignedCommit(treeHash, nil, parents...)
}
-// StoreCommit will store a Git commit with the given Git tree. If signKey is not nil, the commit
+// StoreSignedCommit will store a Git commit with the given Git tree. If signKey is not nil, the commit
// will be signed accordingly.
func (repo *GoGitRepo) StoreSignedCommit(treeHash Hash, signKey *openpgp.Entity, parents ...Hash) (Hash, error) {
cfg, err := repo.r.Config()
@@ -781,7 +791,7 @@ func (repo *GoGitRepo) AllClocks() (map[string]lamport.Clock, error) {
result := make(map[string]lamport.Clock)
- files, err := ioutil.ReadDir(filepath.Join(repo.path, "git-bug", clockPath))
+ files, err := ioutil.ReadDir(filepath.Join(repo.localStorage.Root(), clockPath))
if os.IsNotExist(err) {
return nil, nil
}
diff --git a/repository/gogit_test.go b/repository/gogit_test.go
index a2bb49b9..c376de22 100644
--- a/repository/gogit_test.go
+++ b/repository/gogit_test.go
@@ -15,19 +15,25 @@ func TestNewGoGitRepo(t *testing.T) {
// Plain
plainRoot, err := ioutil.TempDir("", "")
require.NoError(t, err)
- defer os.RemoveAll(plainRoot)
+ t.Cleanup(func() {
+ require.NoError(t, os.RemoveAll(plainRoot))
+ })
- _, err = InitGoGitRepo(plainRoot)
+ plainRepo, err := InitGoGitRepo(plainRoot, namespace)
require.NoError(t, err)
+ require.NoError(t, plainRepo.Close())
plainGitDir := filepath.Join(plainRoot, ".git")
// Bare
bareRoot, err := ioutil.TempDir("", "")
require.NoError(t, err)
- defer os.RemoveAll(bareRoot)
+ t.Cleanup(func() {
+ require.NoError(t, os.RemoveAll(bareRoot))
+ })
- _, err = InitBareGoGitRepo(bareRoot)
+ bareRepo, err := InitBareGoGitRepo(bareRoot, namespace)
require.NoError(t, err)
+ require.NoError(t, bareRepo.Close())
bareGitDir := bareRoot
tests := []struct {
@@ -52,13 +58,14 @@ func TestNewGoGitRepo(t *testing.T) {
}
for i, tc := range tests {
- r, err := OpenGoGitRepo(tc.inPath, nil)
+ r, err := OpenGoGitRepo(tc.inPath, namespace, nil)
if tc.err {
require.Error(t, err, i)
} else {
require.NoError(t, err, i)
assert.Equal(t, filepath.ToSlash(tc.outPath), filepath.ToSlash(r.path), i)
+ require.NoError(t, r.Close())
}
}
}
@@ -66,3 +73,35 @@ func TestNewGoGitRepo(t *testing.T) {
func TestGoGitRepo(t *testing.T) {
RepoTest(t, CreateGoGitTestRepo, CleanupTestRepos)
}
+
+func TestGoGitRepo_Indexes(t *testing.T) {
+ plainRoot := t.TempDir()
+
+ repo, err := InitGoGitRepo(plainRoot, namespace)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ require.NoError(t, repo.Close())
+ })
+
+ // Can create indices
+ indexA, err := repo.GetBleveIndex("a")
+ require.NoError(t, err)
+ require.NotZero(t, indexA)
+ require.FileExists(t, filepath.Join(plainRoot, ".git", namespace, "indexes", "a", "index_meta.json"))
+ require.FileExists(t, filepath.Join(plainRoot, ".git", namespace, "indexes", "a", "store"))
+
+ indexB, err := repo.GetBleveIndex("b")
+ require.NoError(t, err)
+ require.NotZero(t, indexB)
+ require.DirExists(t, filepath.Join(plainRoot, ".git", namespace, "indexes", "b"))
+
+ // Can get an existing index
+ indexA, err = repo.GetBleveIndex("a")
+ require.NoError(t, err)
+ require.NotZero(t, indexA)
+
+ // Can delete an index
+ err = repo.ClearBleveIndex("a")
+ require.NoError(t, err)
+ require.NoDirExists(t, filepath.Join(plainRoot, ".git", namespace, "indexes", "a"))
+}
diff --git a/repository/gogit_testing.go b/repository/gogit_testing.go
index cad776b3..7647c711 100644
--- a/repository/gogit_testing.go
+++ b/repository/gogit_testing.go
@@ -7,6 +7,8 @@ import (
"github.com/99designs/keyring"
)
+const namespace = "git-bug"
+
// This is intended for testing only
func CreateGoGitTestRepo(bare bool) TestedRepo {
@@ -15,7 +17,7 @@ func CreateGoGitTestRepo(bare bool) TestedRepo {
log.Fatal(err)
}
- var creator func(string) (*GoGitRepo, error)
+ var creator func(string, string) (*GoGitRepo, error)
if bare {
creator = InitBareGoGitRepo
@@ -23,7 +25,7 @@ func CreateGoGitTestRepo(bare bool) TestedRepo {
creator = InitGoGitRepo
}
- repo, err := creator(dir)
+ repo, err := creator(dir, namespace)
if err != nil {
log.Fatal(err)
}