diff options
Diffstat (limited to 'bridge')
-rw-r--r-- | bridge/github/config.go | 2 | ||||
-rw-r--r-- | bridge/github/export.go | 5 | ||||
-rw-r--r-- | bridge/github/export_test.go | 3 | ||||
-rw-r--r-- | bridge/github/import_test.go | 5 | ||||
-rw-r--r-- | bridge/gitlab/config.go | 159 | ||||
-rw-r--r-- | bridge/gitlab/export.go | 24 | ||||
-rw-r--r-- | bridge/gitlab/export_test.go | 5 | ||||
-rw-r--r-- | bridge/gitlab/import.go | 17 | ||||
-rw-r--r-- | bridge/gitlab/import_test.go | 11 | ||||
-rw-r--r-- | bridge/launchpad/config.go | 26 |
10 files changed, 113 insertions, 144 deletions
diff --git a/bridge/github/config.go b/bridge/github/config.go index 9ede72d4..ed32f398 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -316,7 +316,7 @@ func promptToken() (string, error) { fmt.Println(" - 'repo' : to be able to read private repositories") fmt.Println() - re, err := regexp.Compile(`^[a-zA-Z0-9]{40}`) + re, err := regexp.Compile(`^[a-zA-Z0-9]{40}$`) if err != nil { panic("regexp compile:" + err.Error()) } diff --git a/bridge/github/export.go b/bridge/github/export.go index 663361f5..1e27be4a 100644 --- a/bridge/github/export.go +++ b/bridge/github/export.go @@ -99,7 +99,7 @@ func (ge *githubExporter) cacheAllClient(repo *cache.RepoCache) error { for _, cred := range creds { login, ok := cred.GetMetadata(auth.MetaKeyLogin) if !ok { - _, _ = fmt.Fprintf(os.Stderr, "credential %s is not tagged with Github login\n", cred.ID().Human()) + _, _ = fmt.Fprintf(os.Stderr, "credential %s is not tagged with a Github login\n", cred.ID().Human()) continue } @@ -107,6 +107,9 @@ func (ge *githubExporter) cacheAllClient(repo *cache.RepoCache) error { if err == identity.ErrIdentityNotExist { continue } + if err != nil { + return nil + } if _, ok := ge.identityClient[user.Id()]; !ok { client := buildClient(creds[0].(*auth.Token)) diff --git a/bridge/github/export_test.go b/bridge/github/export_test.go index d2cfb1f9..cb6bacc1 100644 --- a/bridge/github/export_test.go +++ b/bridge/github/export_test.go @@ -144,8 +144,10 @@ func TestPushPull(t *testing.T) { require.NoError(t, err) // set author identity + login := "identity-test" author, err := backend.NewIdentity("test identity", "test@test.org") require.NoError(t, err) + author.SetMetadata(metaKeyGithubLogin, login) err = backend.SetUserIdentity(author) require.NoError(t, err) @@ -177,6 +179,7 @@ func TestPushPull(t *testing.T) { }) token := auth.NewToken(envToken, target) + token.SetMetadata(metaKeyGithubLogin, login) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/github/import_test.go b/bridge/github/import_test.go index 75310ab3..73eaa096 100644 --- a/bridge/github/import_test.go +++ b/bridge/github/import_test.go @@ -21,6 +21,7 @@ import ( func Test_Importer(t *testing.T) { author := identity.NewIdentity("Michael Muré", "batolettre@gmail.com") + tests := []struct { name string url string @@ -140,7 +141,11 @@ func Test_Importer(t *testing.T) { t.Skip("Env var GITHUB_TOKEN_PRIVATE missing") } + login := "test-identity" + author.SetMetadata(metaKeyGithubLogin, login) + token := auth.NewToken(envToken, target) + token.SetMetadata(metaKeyGithubLogin, login) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/gitlab/config.go b/bridge/gitlab/config.go index 0758074c..36daaa68 100644 --- a/bridge/gitlab/config.go +++ b/bridge/gitlab/config.go @@ -19,8 +19,7 @@ import ( "github.com/MichaelMure/git-bug/bridge/core" "github.com/MichaelMure/git-bug/bridge/core/auth" "github.com/MichaelMure/git-bug/cache" - "github.com/MichaelMure/git-bug/entity" - "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/input" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/colors" ) @@ -36,14 +35,12 @@ func (g *Gitlab) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor if params.Owner != "" { fmt.Println("warning: --owner is ineffective for a gitlab bridge") } + if params.Login != "" { + fmt.Println("warning: --login is ineffective for a gitlab bridge") + } conf := make(core.Configuration) var err error - - if (params.CredPrefix != "" || params.TokenRaw != "") && params.URL == "" { - return nil, fmt.Errorf("you must provide a project URL to configure this bridge with a token") - } - var baseUrl string switch { @@ -74,17 +71,6 @@ func (g *Gitlab) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor return nil, fmt.Errorf("base URL (%s) doesn't match the project URL (%s)", params.BaseURL, url) } - user, err := repo.GetUserIdentity() - if err != nil && err != identity.ErrNoIdentitySet { - return nil, err - } - - // default to a "to be filled" user Id if we don't have a valid one yet - userId := auth.DefaultUserId - if user != nil { - userId = user.Id() - } - var cred auth.Credential switch { @@ -93,13 +79,16 @@ func (g *Gitlab) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor if err != nil { return nil, err } - if user != nil && cred.UserId() != user.Id() { - return nil, fmt.Errorf("selected credential don't match the user") - } case params.TokenRaw != "": - cred = auth.NewToken(userId, params.TokenRaw, target) + token := auth.NewToken(params.TokenRaw, target) + login, err := getLoginFromToken(baseUrl, token) + if err != nil { + return nil, err + } + token.SetMetadata(auth.MetaKeyLogin, login) + cred = token default: - cred, err = promptTokenOptions(repo, userId, baseUrl) + cred, err = promptTokenOptions(repo, baseUrl) if err != nil { return nil, err } @@ -153,64 +142,41 @@ func (g *Gitlab) ValidateConfig(conf core.Configuration) error { } func promptBaseUrlOptions() (string, error) { - for { - fmt.Printf("Gitlab base url:\n") - fmt.Printf("[0]: https://gitlab.com\n") - fmt.Printf("[1]: enter your own base url\n") - fmt.Printf("Select option: ") - - line, err := bufio.NewReader(os.Stdin).ReadString('\n') - if err != nil { - return "", err - } - - line = strings.TrimSpace(line) + index, err := input.PromptChoice("Gitlab base url", []string{ + "https://gitlab.com", + "enter your own base url", + }) - index, err := strconv.Atoi(line) - if err != nil || index < 0 || index > 1 { - fmt.Println("invalid input") - continue - } + if err != nil { + return "", err + } - switch index { - case 0: - return defaultBaseURL, nil - case 1: - return promptBaseUrl() - } + if index == 0 { + return defaultBaseURL, nil + } else { + return promptBaseUrl() } } func promptBaseUrl() (string, error) { - for { - fmt.Print("Base url: ") - - line, err := bufio.NewReader(os.Stdin).ReadString('\n') + validator := func(name string, value string) (string, error) { + u, err := url.Parse(value) if err != nil { - return "", err + return err.Error(), nil } - - line = strings.TrimSpace(line) - - ok, err := validateBaseUrl(line) - if err != nil { - return "", err + if u.Scheme == "" { + return "missing scheme", nil } - if ok { - return line, nil + if u.Host == "" { + return "missing host", nil } + return "", nil } -} -func validateBaseUrl(baseUrl string) (bool, error) { - u, err := url.Parse(baseUrl) - if err != nil { - return false, err - } - return u.Scheme != "" && u.Host != "", nil + return input.Prompt("Base url", "url", input.Required, validator) } -func promptTokenOptions(repo repository.RepoConfig, userId entity.Id, baseUrl string) (auth.Credential, error) { +func promptTokenOptions(repo repository.RepoConfig, baseUrl string) (auth.Credential, error) { for { creds, err := auth.List(repo, auth.WithTarget(target), auth.WithKind(auth.KindToken)) if err != nil { @@ -219,11 +185,7 @@ func promptTokenOptions(repo repository.RepoConfig, userId entity.Id, baseUrl st // if we don't have existing token, fast-track to the token prompt if len(creds) == 0 { - value, err := promptToken(baseUrl) - if err != nil { - return nil, err - } - return auth.NewToken(userId, value, target), nil + return promptToken(baseUrl) } fmt.Println() @@ -261,44 +223,44 @@ func promptTokenOptions(repo repository.RepoConfig, userId entity.Id, baseUrl st switch index { case 1: - value, err := promptToken(baseUrl) - if err != nil { - return nil, err - } - return auth.NewToken(userId, value, target), nil + return promptToken(baseUrl) default: return creds[index-2], nil } } } -func promptToken(baseUrl string) (string, error) { +func promptToken(baseUrl string) (*auth.Token, error) { fmt.Printf("You can generate a new token by visiting %s.\n", path.Join(baseUrl, "profile/personal_access_tokens")) fmt.Println("Choose 'Create personal access token' and set the necessary access scope for your repository.") fmt.Println() fmt.Println("'api' access scope: to be able to make api calls") fmt.Println() - re, err := regexp.Compile(`^[a-zA-Z0-9\-\_]{20}`) + re, err := regexp.Compile(`^[a-zA-Z0-9\-\_]{20}$`) if err != nil { panic("regexp compile:" + err.Error()) } - for { - fmt.Print("Enter token: ") + var login string - line, err := bufio.NewReader(os.Stdin).ReadString('\n') + validator := func(name string, value string) (complaint string, err error) { + if !re.MatchString(value) { + return "token has incorrect format", nil + } + login, err = getLoginFromToken(baseUrl, auth.NewToken(value, target)) if err != nil { - return "", err + return fmt.Sprintf("token is invalid: %v", err), nil } + return "", nil + } - token := strings.TrimSpace(line) - if re.MatchString(token) { - return token, nil - } + rawToken, err := input.Prompt("Enter token", "token", input.Required, validator) - fmt.Println("token has incorrect format") - } + token := auth.NewToken(rawToken, target) + token.SetMetadata(auth.MetaKeyLogin, login) + + return token, nil } func promptURL(repo repository.RepoCommon, baseUrl string) (string, error) { @@ -408,8 +370,25 @@ func validateProjectURL(baseUrl, url string, token *auth.Token) (int, error) { project, _, err := client.Projects.GetProject(projectPath, &gitlab.GetProjectOptions{}) if err != nil { - return 0, errors.Wrap(err, "wrong token scope ou inexistent project") + return 0, errors.Wrap(err, "wrong token scope ou non-existent project") } return project.ID, nil } + +func getLoginFromToken(baseUrl string, token *auth.Token) (string, error) { + client, err := buildClient(baseUrl, token) + if err != nil { + return "", err + } + + user, _, err := client.Users.CurrentUser() + if err != nil { + return "", err + } + if user.Username == "" { + return "", fmt.Errorf("gitlab say username is empty") + } + + return user.Username, nil +} diff --git a/bridge/gitlab/export.go b/bridge/gitlab/export.go index 2ba149a2..c5323da4 100644 --- a/bridge/gitlab/export.go +++ b/bridge/gitlab/export.go @@ -3,6 +3,7 @@ package gitlab import ( "context" "fmt" + "os" "strconv" "time" @@ -14,7 +15,7 @@ import ( "github.com/MichaelMure/git-bug/bug" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" - "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/identity" ) var ( @@ -54,20 +55,33 @@ func (ge *gitlabExporter) Init(repo *cache.RepoCache, conf core.Configuration) e return nil } -func (ge *gitlabExporter) cacheAllClient(repo repository.RepoConfig) error { +func (ge *gitlabExporter) cacheAllClient(repo *cache.RepoCache) error { creds, err := auth.List(repo, auth.WithTarget(target), auth.WithKind(auth.KindToken)) if err != nil { return err } for _, cred := range creds { - if _, ok := ge.identityClient[cred.UserId()]; !ok { + login, ok := cred.GetMetadata(auth.MetaKeyLogin) + if !ok { + _, _ = fmt.Fprintf(os.Stderr, "credential %s is not tagged with a Gitlab login\n", cred.ID().Human()) + continue + } + + user, err := repo.ResolveIdentityImmutableMetadata(metaKeyGitlabLogin, login) + if err == identity.ErrIdentityNotExist { + continue + } + if err != nil { + return nil + } + + if _, ok := ge.identityClient[user.Id()]; !ok { client, err := buildClient(ge.conf[keyGitlabBaseUrl], creds[0].(*auth.Token)) if err != nil { return err } - - ge.identityClient[cred.UserId()] = client + ge.identityClient[user.Id()] = client } } diff --git a/bridge/gitlab/export_test.go b/bridge/gitlab/export_test.go index d16defd0..50dbd04a 100644 --- a/bridge/gitlab/export_test.go +++ b/bridge/gitlab/export_test.go @@ -149,8 +149,10 @@ func TestPushPull(t *testing.T) { require.NoError(t, err) // set author identity + login := "test-identity" author, err := backend.NewIdentity("test identity", "test@test.org") require.NoError(t, err) + author.SetMetadata(metaKeyGitlabLogin, login) err = backend.SetUserIdentity(author) require.NoError(t, err) @@ -160,7 +162,8 @@ func TestPushPull(t *testing.T) { tests := testCases(t, backend) - token := auth.NewToken(author.Id(), envToken, target) + token := auth.NewToken(envToken, target) + token.SetMetadata(metaKeyGitlabLogin, login) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/gitlab/import.go b/bridge/gitlab/import.go index fa6bbfb6..d699554b 100644 --- a/bridge/gitlab/import.go +++ b/bridge/gitlab/import.go @@ -13,7 +13,6 @@ import ( "github.com/MichaelMure/git-bug/bug" "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" - "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/text" ) @@ -34,20 +33,7 @@ type gitlabImporter struct { func (gi *gitlabImporter) Init(repo *cache.RepoCache, conf core.Configuration) error { gi.conf = conf - opts := []auth.Option{ - auth.WithTarget(target), - auth.WithKind(auth.KindToken), - } - - user, err := repo.GetUserIdentity() - if err == nil { - opts = append(opts, auth.WithUserId(user.Id())) - } - if err == identity.ErrNoIdentitySet { - opts = append(opts, auth.WithUserId(auth.DefaultUserId)) - } - - creds, err := auth.List(repo, opts...) + creds, err := auth.List(repo, auth.WithTarget(target), auth.WithKind(auth.KindToken)) if err != nil { return err } @@ -403,7 +389,6 @@ func (gi *gitlabImporter) ensurePerson(repo *cache.RepoCache, id int) (*cache.Id i, err = repo.NewIdentityRaw( user.Name, user.PublicEmail, - user.Username, user.AvatarURL, map[string]string{ // because Gitlab diff --git a/bridge/gitlab/import_test.go b/bridge/gitlab/import_test.go index 1e2f5d50..3c0caa55 100644 --- a/bridge/gitlab/import_test.go +++ b/bridge/gitlab/import_test.go @@ -21,6 +21,7 @@ import ( func TestImport(t *testing.T) { author := identity.NewIdentity("Amine Hilaly", "hilalyamine@gmail.com") + tests := []struct { name string url string @@ -94,13 +95,11 @@ func TestImport(t *testing.T) { t.Skip("Env var GITLAB_PROJECT_ID missing") } - err = author.Commit(repo) - require.NoError(t, err) - - err = identity.SetUserIdentity(repo, author) - require.NoError(t, err) + login := "test-identity" + author.SetMetadata(metaKeyGitlabLogin, login) - token := auth.NewToken(author.Id(), envToken, target) + token := auth.NewToken(envToken, target) + token.SetMetadata(metaKeyGitlabLogin, login) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/launchpad/config.go b/bridge/launchpad/config.go index edbd941d..674aff00 100644 --- a/bridge/launchpad/config.go +++ b/bridge/launchpad/config.go @@ -1,17 +1,15 @@ package launchpad import ( - "bufio" "errors" "fmt" "net/http" - "os" "regexp" - "strings" "time" "github.com/MichaelMure/git-bug/bridge/core" "github.com/MichaelMure/git-bug/cache" + "github.com/MichaelMure/git-bug/input" ) var ErrBadProjectURL = errors.New("bad Launchpad project URL") @@ -45,7 +43,7 @@ func (l *Launchpad) Configure(repo *cache.RepoCache, params core.BridgeParams) ( project, err = splitURL(params.URL) default: // get project name from terminal prompt - project, err = promptProjectName() + project, err = input.Prompt("Launchpad project name", "project name", input.Required) } if err != nil { @@ -86,26 +84,6 @@ func (*Launchpad) ValidateConfig(conf core.Configuration) error { return nil } -func promptProjectName() (string, error) { - for { - fmt.Print("Launchpad project name: ") - - line, err := bufio.NewReader(os.Stdin).ReadString('\n') - if err != nil { - return "", err - } - - line = strings.TrimRight(line, "\n") - - if line == "" { - fmt.Println("Project name is empty") - continue - } - - return line, nil - } -} - func validateProject(project string) (bool, error) { url := fmt.Sprintf("%s/%s", apiRoot, project) |