From db893494bb1492a3d9e32787a5ada1dd8f639ef3 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 7 Jan 2020 22:06:42 +0100 Subject: input: better reusable prompt functions --- bridge/github/config.go | 139 +++++------------------------------------------- 1 file changed, 12 insertions(+), 127 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index ea4b622f..8c4bf7c5 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -14,21 +14,19 @@ import ( "sort" "strconv" "strings" - "syscall" "time" text "github.com/MichaelMure/go-term-text" "github.com/pkg/errors" - "golang.org/x/crypto/ssh/terminal" "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" - "github.com/MichaelMure/git-bug/util/interrupt" ) const ( @@ -320,21 +318,14 @@ func promptToken() (string, error) { panic("regexp compile:" + err.Error()) } - for { - fmt.Print("Enter token: ") - - line, err := bufio.NewReader(os.Stdin).ReadString('\n') - if err != nil { - return "", err + validator := func(name string, value string) (complaint string, err error) { + if re.MatchString(value) { + return "", nil } - - token := strings.TrimSpace(line) - if re.MatchString(token) { - return token, nil - } - - fmt.Println("token has incorrect format") + return "token has incorrect format", nil } + + return input.Prompt("Enter token", "token", "", input.Required, validator) } func loginAndRequestToken(owner, project string) (string, error) { @@ -348,17 +339,18 @@ func loginAndRequestToken(owner, project string) (string, error) { fmt.Println() // prompt project visibility to know the token scope needed for the repository - isPublic, err := promptProjectVisibility() + i, err := input.PromptChoice("repository visibility", []string{"public", "private"}) if err != nil { return "", err } + isPublic := i == 0 username, err := promptUsername() if err != nil { return "", err } - password, err := promptPassword() + password, err := input.PromptPassword("Password", "password", input.Required) if err != nil { return "", err } @@ -387,12 +379,12 @@ func loginAndRequestToken(owner, project string) (string, error) { // Handle 2FA is needed OTPHeader := resp.Header.Get("X-GitHub-OTP") if resp.StatusCode == http.StatusUnauthorized && OTPHeader != "" { - otpCode, err := prompt2FA() + otpCode, err := input.PromptPassword("Two-factor authentication code", "code", input.Required) if err != nil { return "", err } - resp, err = requestTokenWith2FA(note, username, password, otpCode, scope) + resp, err = requestTokenWith2FA(note, login, password, otpCode, scope) if err != nil { return "", err } @@ -408,29 +400,6 @@ func loginAndRequestToken(owner, project string) (string, error) { return "", fmt.Errorf("error creating token %v: %v", resp.StatusCode, string(b)) } -func promptUsername() (string, error) { - for { - fmt.Print("username: ") - - line, err := bufio.NewReader(os.Stdin).ReadString('\n') - if err != nil { - return "", err - } - - line = strings.TrimSpace(line) - - ok, err := validateUsername(line) - if err != nil { - return "", err - } - if ok { - return line, nil - } - - fmt.Println("invalid username") - } -} - func promptURL(repo repository.RepoCommon) (string, string, error) { // remote suggestions remotes, err := repo.GetRemotes() @@ -585,87 +554,3 @@ func validateProject(owner, project string, token *auth.Token) (bool, error) { return resp.StatusCode == http.StatusOK, nil } - -func promptPassword() (string, error) { - termState, err := terminal.GetState(int(syscall.Stdin)) - if err != nil { - return "", err - } - - cancel := interrupt.RegisterCleaner(func() error { - return terminal.Restore(int(syscall.Stdin), termState) - }) - defer cancel() - - for { - fmt.Print("password: ") - - bytePassword, err := terminal.ReadPassword(int(syscall.Stdin)) - // new line for coherent formatting, ReadPassword clip the normal new line - // entered by the user - fmt.Println() - - if err != nil { - return "", err - } - - if len(bytePassword) > 0 { - return string(bytePassword), nil - } - - fmt.Println("password is empty") - } -} - -func prompt2FA() (string, error) { - termState, err := terminal.GetState(int(syscall.Stdin)) - if err != nil { - return "", err - } - - cancel := interrupt.RegisterCleaner(func() error { - return terminal.Restore(int(syscall.Stdin), termState) - }) - defer cancel() - - for { - fmt.Print("two-factor authentication code: ") - - byte2fa, err := terminal.ReadPassword(int(syscall.Stdin)) - fmt.Println() - if err != nil { - return "", err - } - - if len(byte2fa) > 0 { - return string(byte2fa), nil - } - - fmt.Println("code is empty") - } -} - -func promptProjectVisibility() (bool, error) { - for { - fmt.Println("[1]: public") - fmt.Println("[2]: private") - fmt.Print("repository visibility: ") - - line, err := bufio.NewReader(os.Stdin).ReadString('\n') - fmt.Println() - if err != nil { - return false, err - } - - line = strings.TrimSpace(line) - - index, err := strconv.Atoi(line) - if err != nil || (index != 1 && index != 2) { - fmt.Println("invalid input") - continue - } - - // return true for public repositories, false for private - return index == 1, nil - } -} -- cgit From 26f0152384f77d2bfd16c6762f5618bc966809a6 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 7 Jan 2020 22:07:25 +0100 Subject: WIP --- bridge/github/config.go | 65 ++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 39 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index 8c4bf7c5..e51f244b 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -22,8 +22,6 @@ 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" @@ -49,12 +47,6 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor conf := make(core.Configuration) var err error - - if (params.CredPrefix != "" || params.TokenRaw != "") && - (params.URL == "" && (params.Project == "" || params.Owner == "")) { - return nil, fmt.Errorf("you must provide a project URL or Owner/Name to configure this bridge with a token") - } - var owner string var project string @@ -87,15 +79,12 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor return nil, fmt.Errorf("invalid parameter owner: %v", owner) } - 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() + login := params.Login + if login == "" { + login, err = input.Prompt("Github login", "", true, validateUsername) + if err != nil { + return nil, err + } } var cred auth.Credential @@ -106,13 +95,11 @@ func (g *Github) 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) + cred = auth.NewToken(params.TokenRaw, target) + cred.Metadata()[auth.MetaKeyLogin] = login default: - cred, err = promptTokenOptions(repo, userId, owner, project) + cred, err = promptTokenOptions(repo, login, owner, project) if err != nil { return nil, err } @@ -170,11 +157,11 @@ func (*Github) ValidateConfig(conf core.Configuration) error { return nil } -func requestToken(note, username, password string, scope string) (*http.Response, error) { - return requestTokenWith2FA(note, username, password, "", scope) +func requestToken(note, login, password string, scope string) (*http.Response, error) { + return requestTokenWith2FA(note, login, password, "", scope) } -func requestTokenWith2FA(note, username, password, otpCode string, scope string) (*http.Response, error) { +func requestTokenWith2FA(note, login, password, otpCode string, scope string) (*http.Response, error) { url := fmt.Sprintf("%s/authorizations", githubV3Url) params := struct { Scopes []string `json:"scopes"` @@ -196,7 +183,7 @@ func requestTokenWith2FA(note, username, password, otpCode string, scope string) return nil, err } - req.SetBasicAuth(username, password) + req.SetBasicAuth(login, password) req.Header.Set("Content-Type", "application/json") if otpCode != "" { @@ -240,9 +227,9 @@ func randomFingerprint() string { return string(b) } -func promptTokenOptions(repo repository.RepoConfig, userId entity.Id, owner, project string) (auth.Credential, error) { +func promptTokenOptions(repo repository.RepoConfig, login, owner, project string) (auth.Credential, error) { for { - creds, err := auth.List(repo, auth.WithUserId(userId), auth.WithTarget(target)) + creds, err := auth.List(repo, auth.WithTarget(target), auth.WithMeta(auth.MetaKeyLogin, login)) if err != nil { return nil, err } @@ -258,10 +245,11 @@ func promptTokenOptions(repo repository.RepoConfig, userId entity.Id, owner, pro fmt.Println("Existing tokens for Github:") for i, cred := range creds { token := cred.(*auth.Token) - fmt.Printf("[%d]: %s => %s (%s)\n", + fmt.Printf("[%d]: %s => %s (login: %s, %s)\n", i+3, colors.Cyan(token.ID().Human()), colors.Red(text.TruncateMax(token.Value, 10)), + token.Metadata()[auth.MetaKeyLogin], token.CreateTime().Format(time.RFC822), ) } @@ -289,13 +277,17 @@ func promptTokenOptions(repo repository.RepoConfig, userId entity.Id, owner, pro if err != nil { return nil, err } - return auth.NewToken(userId, value, target), nil + token := auth.NewToken(value, target) + token.Metadata()[auth.MetaKeyLogin] = login + return token, nil case 2: - value, err := loginAndRequestToken(owner, project) + value, err := loginAndRequestToken(login, owner, project) if err != nil { return nil, err } - return auth.NewToken(userId, value, target), nil + token := auth.NewToken(value, target) + token.Metadata()[auth.MetaKeyLogin] = login + return token, nil default: return creds[index-3], nil } @@ -328,7 +320,7 @@ func promptToken() (string, error) { return input.Prompt("Enter token", "token", "", input.Required, validator) } -func loginAndRequestToken(owner, project string) (string, error) { +func loginAndRequestToken(login, owner, project string) (string, error) { fmt.Println("git-bug will now generate an access token in your Github profile. Your credential are not stored and are only used to generate the token. The token is stored in the global git config.") fmt.Println() fmt.Println("The access scope depend on the type of repository.") @@ -345,11 +337,6 @@ func loginAndRequestToken(owner, project string) (string, error) { } isPublic := i == 0 - username, err := promptUsername() - if err != nil { - return "", err - } - password, err := input.PromptPassword("Password", "password", input.Required) if err != nil { return "", err @@ -369,7 +356,7 @@ func loginAndRequestToken(owner, project string) (string, error) { note := fmt.Sprintf("git-bug - %s/%s", owner, project) - resp, err := requestToken(note, username, password, scope) + resp, err := requestToken(note, login, password, scope) if err != nil { return "", err } -- cgit From ae2f942ef907161af0aba5f3511db72cf9801dca Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sun, 12 Jan 2020 16:38:16 +0100 Subject: more wip --- bridge/github/config.go | 8 ++++++-- bridge/github/config_test.go | 5 ++--- bridge/github/export.go | 45 +++++++++++++++----------------------------- bridge/github/import.go | 16 +--------------- bridge/github/import_test.go | 8 +------- 5 files changed, 25 insertions(+), 57 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index e51f244b..fcb94079 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -81,7 +81,7 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor login := params.Login if login == "" { - login, err = input.Prompt("Github login", "", true, validateUsername) + login, err = input.Prompt("Github login", "login", input.Required, validateUsername) if err != nil { return nil, err } @@ -128,6 +128,10 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor return nil, err } + // Todo: if no user exist with the given login + // - tag the default user with the github login + // - add a command to manually tag a user ? + // don't forget to store the now known valid token if !auth.IdExist(repo, cred.ID()) { err = auth.Store(repo, cred) @@ -317,7 +321,7 @@ func promptToken() (string, error) { return "token has incorrect format", nil } - return input.Prompt("Enter token", "token", "", input.Required, validator) + return input.Prompt("Enter token", "token", input.Required, validator) } func loginAndRequestToken(login, owner, project string) (string, error) { diff --git a/bridge/github/config_test.go b/bridge/github/config_test.go index 9798d26b..d7b1b38d 100644 --- a/bridge/github/config_test.go +++ b/bridge/github/config_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/MichaelMure/git-bug/bridge/core/auth" - "github.com/MichaelMure/git-bug/entity" ) func TestSplitURL(t *testing.T) { @@ -155,8 +154,8 @@ func TestValidateProject(t *testing.T) { t.Skip("Env var GITHUB_TOKEN_PUBLIC missing") } - tokenPrivate := auth.NewToken(entity.UnsetId, envPrivate, target) - tokenPublic := auth.NewToken(entity.UnsetId, envPublic, target) + tokenPrivate := auth.NewToken(envPrivate, target) + tokenPublic := auth.NewToken(envPublic, target) type args struct { owner string diff --git a/bridge/github/export.go b/bridge/github/export.go index 6c089a47..1cc66dee 100644 --- a/bridge/github/export.go +++ b/bridge/github/export.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "strings" "time" @@ -19,6 +20,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/identity" "github.com/MichaelMure/git-bug/repository" ) @@ -33,13 +35,6 @@ type githubExporter struct { // cache identities clients identityClient map[entity.Id]*githubv4.Client - // the client to use for non user-specific queries - // should be the client of the default user - defaultClient *githubv4.Client - - // the token of the default user - defaultToken *auth.Token - // github repository ID repositoryID string @@ -58,43 +53,33 @@ func (ge *githubExporter) Init(repo *cache.RepoCache, conf core.Configuration) e ge.cachedOperationIDs = make(map[entity.Id]string) ge.cachedLabels = make(map[string]string) - user, err := repo.GetUserIdentity() - if err != nil { - return err - } - // preload all clients - err = ge.cacheAllClient(repo) - if err != nil { - return err - } - - ge.defaultClient, err = ge.getClientForIdentity(user.Id()) - if err != nil { - return err - } - - creds, err := auth.List(repo, auth.WithUserId(user.Id()), auth.WithTarget(target), auth.WithKind(auth.KindToken)) + err := ge.cacheAllClient(repo) if err != nil { return err } - if len(creds) == 0 { - return ErrMissingIdentityToken - } - - ge.defaultToken = creds[0].(*auth.Token) - return nil } -func (ge *githubExporter) cacheAllClient(repo repository.RepoConfig) error { +func (ge *githubExporter) 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 { + login, ok := cred.Metadata()[auth.MetaKeyLogin] + if !ok { + _, _ = fmt.Fprintf(os.Stderr, "credential %s is not tagged with Github login\n", cred.ID().Human()) + continue + } + + user, err := repo.ResolveIdentityImmutableMetadata(metaKeyGithubLogin, login) + if err == identity.ErrIdentityNotExist { + continue + } + if _, ok := ge.identityClient[cred.UserId()]; !ok { client := buildClient(creds[0].(*auth.Token)) ge.identityClient[cred.UserId()] = client diff --git a/bridge/github/import.go b/bridge/github/import.go index 39aebccb..aac4f119 100644 --- a/bridge/github/import.go +++ b/bridge/github/import.go @@ -12,7 +12,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" ) @@ -39,20 +38,7 @@ type githubImporter struct { func (gi *githubImporter) 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 } diff --git a/bridge/github/import_test.go b/bridge/github/import_test.go index 57bab61e..75310ab3 100644 --- a/bridge/github/import_test.go +++ b/bridge/github/import_test.go @@ -140,13 +140,7 @@ func Test_Importer(t *testing.T) { t.Skip("Env var GITHUB_TOKEN_PRIVATE missing") } - err = author.Commit(repo) - require.NoError(t, err) - - err = identity.SetUserIdentity(repo, author) - require.NoError(t, err) - - token := auth.NewToken(author.Id(), envToken, target) + token := auth.NewToken(envToken, target) err = auth.Store(repo, token) require.NoError(t, err) -- cgit From b950c2580dfbf7672ee9e5e1e3f5b45c8cbc2788 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 14 Jan 2020 22:02:35 +0100 Subject: more wip --- bridge/github/config.go | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index fcb94079..30e28d0d 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -22,6 +22,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/identity" "github.com/MichaelMure/git-bug/input" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/colors" @@ -81,7 +82,18 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor login := params.Login if login == "" { - login, err = input.Prompt("Github login", "login", input.Required, validateUsername) + validator := func(name string, value string) (string, error) { + ok, err := validateUsername(value) + if err != nil { + return "", err + } + if !ok { + return "invalid login", nil + } + return "", nil + } + + login, err = input.Prompt("Github login", "login", input.Required, validator) if err != nil { return nil, err } @@ -128,6 +140,28 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor return nil, err } + // TODO + func(login string) error { + // if no user exist with the given login + _, err := repo.ResolveIdentityLogin(login) + if err != nil && err != identity.ErrIdentityNotExist { + return err + } + + // tag the default user with the github login, if any + // if not, + user, err := repo.GetUserIdentity() + if err == identity.ErrNoIdentitySet { + return nil + } + if err != nil { + return err + } + + repo.GetUserIdentity() + + }(login) + // Todo: if no user exist with the given login // - tag the default user with the github login // - add a command to manually tag a user ? -- cgit From 8da522d97af3dcaca8a8424e3541705c69779d6f Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 21 Jan 2020 18:49:33 +0100 Subject: wip --- bridge/github/config.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index 30e28d0d..40653afa 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -149,7 +149,6 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor } // tag the default user with the github login, if any - // if not, user, err := repo.GetUserIdentity() if err == identity.ErrNoIdentitySet { return nil @@ -158,7 +157,10 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor return err } - repo.GetUserIdentity() + userLogin, ok := user.ImmutableMetadata()[metaKeyGithubLogin] + if !ok { + user.SetMetadata() + } }(login) -- cgit From 74e91144105790cc997c1d79a7f638e1e3a1f3f8 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Fri, 24 Jan 2020 00:30:13 +0100 Subject: more more wip --- bridge/github/config.go | 37 ++++--------------------------------- bridge/github/export.go | 41 +++++++++++++++++++++++++++++++++++------ bridge/github/export_test.go | 2 +- bridge/github/import.go | 2 -- 4 files changed, 40 insertions(+), 42 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index 40653afa..9ede72d4 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -22,7 +22,6 @@ 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/identity" "github.com/MichaelMure/git-bug/input" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/colors" @@ -109,7 +108,7 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor } case params.TokenRaw != "": cred = auth.NewToken(params.TokenRaw, target) - cred.Metadata()[auth.MetaKeyLogin] = login + cred.SetMetadata(auth.MetaKeyLogin, login) default: cred, err = promptTokenOptions(repo, login, owner, project) if err != nil { @@ -140,34 +139,6 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor return nil, err } - // TODO - func(login string) error { - // if no user exist with the given login - _, err := repo.ResolveIdentityLogin(login) - if err != nil && err != identity.ErrIdentityNotExist { - return err - } - - // tag the default user with the github login, if any - user, err := repo.GetUserIdentity() - if err == identity.ErrNoIdentitySet { - return nil - } - if err != nil { - return err - } - - userLogin, ok := user.ImmutableMetadata()[metaKeyGithubLogin] - if !ok { - user.SetMetadata() - } - - }(login) - - // Todo: if no user exist with the given login - // - tag the default user with the github login - // - add a command to manually tag a user ? - // don't forget to store the now known valid token if !auth.IdExist(repo, cred.ID()) { err = auth.Store(repo, cred) @@ -176,7 +147,7 @@ func (g *Github) Configure(repo *cache.RepoCache, params core.BridgeParams) (cor } } - return conf, nil + return conf, core.FinishConfig(repo, metaKeyGithubLogin, login) } func (*Github) ValidateConfig(conf core.Configuration) error { @@ -318,7 +289,7 @@ func promptTokenOptions(repo repository.RepoConfig, login, owner, project string return nil, err } token := auth.NewToken(value, target) - token.Metadata()[auth.MetaKeyLogin] = login + token.SetMetadata(auth.MetaKeyLogin, login) return token, nil case 2: value, err := loginAndRequestToken(login, owner, project) @@ -326,7 +297,7 @@ func promptTokenOptions(repo repository.RepoConfig, login, owner, project string return nil, err } token := auth.NewToken(value, target) - token.Metadata()[auth.MetaKeyLogin] = login + token.SetMetadata(auth.MetaKeyLogin, login) return token, nil default: return creds[index-3], nil diff --git a/bridge/github/export.go b/bridge/github/export.go index 1cc66dee..663361f5 100644 --- a/bridge/github/export.go +++ b/bridge/github/export.go @@ -21,7 +21,6 @@ import ( "github.com/MichaelMure/git-bug/cache" "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" - "github.com/MichaelMure/git-bug/repository" ) var ( @@ -35,6 +34,13 @@ type githubExporter struct { // cache identities clients identityClient map[entity.Id]*githubv4.Client + // the client to use for non user-specific queries + // should be the client of the default user + defaultClient *githubv4.Client + + // the token of the default user + defaultToken *auth.Token + // github repository ID repositoryID string @@ -53,12 +59,34 @@ func (ge *githubExporter) Init(repo *cache.RepoCache, conf core.Configuration) e ge.cachedOperationIDs = make(map[entity.Id]string) ge.cachedLabels = make(map[string]string) + user, err := repo.GetUserIdentity() + if err != nil { + return err + } + // preload all clients - err := ge.cacheAllClient(repo) + err = ge.cacheAllClient(repo) if err != nil { return err } + ge.defaultClient, err = ge.getClientForIdentity(user.Id()) + if err != nil { + return err + } + + login := user.ImmutableMetadata()[metaKeyGithubLogin] + creds, err := auth.List(repo, auth.WithMeta(metaKeyGithubLogin, login), auth.WithTarget(target), auth.WithKind(auth.KindToken)) + if err != nil { + return err + } + + if len(creds) == 0 { + return ErrMissingIdentityToken + } + + ge.defaultToken = creds[0].(*auth.Token) + return nil } @@ -69,7 +97,7 @@ func (ge *githubExporter) cacheAllClient(repo *cache.RepoCache) error { } for _, cred := range creds { - login, ok := cred.Metadata()[auth.MetaKeyLogin] + login, ok := cred.GetMetadata(auth.MetaKeyLogin) if !ok { _, _ = fmt.Fprintf(os.Stderr, "credential %s is not tagged with Github login\n", cred.ID().Human()) continue @@ -80,9 +108,9 @@ func (ge *githubExporter) cacheAllClient(repo *cache.RepoCache) error { continue } - if _, ok := ge.identityClient[cred.UserId()]; !ok { + if _, ok := ge.identityClient[user.Id()]; !ok { client := buildClient(creds[0].(*auth.Token)) - ge.identityClient[cred.UserId()] = client + ge.identityClient[user.Id()] = client } } @@ -462,11 +490,12 @@ func (ge *githubExporter) cacheGithubLabels(ctx context.Context, gc *githubv4.Cl for hasNextPage { // create a new timeout context at each iteration ctx, cancel := context.WithTimeout(ctx, defaultTimeout) - defer cancel() if err := gc.Query(ctx, &q, variables); err != nil { + cancel() return err } + cancel() for _, label := range q.Repository.Labels.Nodes { ge.cachedLabels[label.Name] = label.ID diff --git a/bridge/github/export_test.go b/bridge/github/export_test.go index 5a0bc653..d2cfb1f9 100644 --- a/bridge/github/export_test.go +++ b/bridge/github/export_test.go @@ -176,7 +176,7 @@ func TestPushPull(t *testing.T) { return deleteRepository(projectName, envUser, envToken) }) - token := auth.NewToken(author.Id(), envToken, target) + token := auth.NewToken(envToken, target) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/github/import.go b/bridge/github/import.go index aac4f119..f2c9a53d 100644 --- a/bridge/github/import.go +++ b/bridge/github/import.go @@ -543,7 +543,6 @@ func (gi *githubImporter) ensurePerson(repo *cache.RepoCache, actor *actor) (*ca i, err = repo.NewIdentityRaw( name, email, - string(actor.Login), string(actor.AvatarUrl), map[string]string{ metaKeyGithubLogin: string(actor.Login), @@ -590,7 +589,6 @@ func (gi *githubImporter) getGhost(repo *cache.RepoCache) (*cache.IdentityCache, return repo.NewIdentityRaw( name, "", - string(q.User.Login), string(q.User.AvatarUrl), map[string]string{ metaKeyGithubLogin: string(q.User.Login), -- cgit From f515b9a1291ddd3e4fe1b43bf5891ab19569e33f Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 4 Feb 2020 00:25:27 +0100 Subject: gitlab also compile --- bridge/github/config.go | 2 +- bridge/github/export.go | 5 ++++- bridge/github/export_test.go | 3 +++ bridge/github/import_test.go | 5 +++++ 4 files changed, 13 insertions(+), 2 deletions(-) (limited to 'bridge/github') 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) -- cgit From 646fd681ffba59d4a74ec3d99558d2ed70b0106b Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 4 Feb 2020 22:05:34 +0100 Subject: it compiles \o/ --- bridge/github/config.go | 9 --------- bridge/github/export.go | 2 +- bridge/github/export_test.go | 2 +- bridge/github/github.go | 21 +++++++++++++++++++++ bridge/github/import.go | 6 ------ bridge/github/import_test.go | 2 +- 6 files changed, 24 insertions(+), 18 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/config.go b/bridge/github/config.go index ed32f398..9477801d 100644 --- a/bridge/github/config.go +++ b/bridge/github/config.go @@ -27,15 +27,6 @@ import ( "github.com/MichaelMure/git-bug/util/colors" ) -const ( - target = "github" - githubV3Url = "https://api.github.com" - keyOwner = "owner" - keyProject = "project" - - defaultTimeout = 60 * time.Second -) - var ( ErrBadProjectURL = errors.New("bad project url") ) diff --git a/bridge/github/export.go b/bridge/github/export.go index 1e27be4a..c363e188 100644 --- a/bridge/github/export.go +++ b/bridge/github/export.go @@ -76,7 +76,7 @@ func (ge *githubExporter) Init(repo *cache.RepoCache, conf core.Configuration) e } login := user.ImmutableMetadata()[metaKeyGithubLogin] - creds, err := auth.List(repo, auth.WithMeta(metaKeyGithubLogin, login), auth.WithTarget(target), auth.WithKind(auth.KindToken)) + creds, err := auth.List(repo, auth.WithMeta(auth.MetaKeyLogin, login), auth.WithTarget(target), auth.WithKind(auth.KindToken)) if err != nil { return err } diff --git a/bridge/github/export_test.go b/bridge/github/export_test.go index cb6bacc1..89040d8f 100644 --- a/bridge/github/export_test.go +++ b/bridge/github/export_test.go @@ -179,7 +179,7 @@ func TestPushPull(t *testing.T) { }) token := auth.NewToken(envToken, target) - token.SetMetadata(metaKeyGithubLogin, login) + token.SetMetadata(auth.MetaKeyLogin, login) err = auth.Store(repo, token) require.NoError(t, err) diff --git a/bridge/github/github.go b/bridge/github/github.go index 874c2d11..19dc8a08 100644 --- a/bridge/github/github.go +++ b/bridge/github/github.go @@ -3,6 +3,7 @@ package github import ( "context" + "time" "github.com/shurcooL/githubv4" "golang.org/x/oauth2" @@ -11,12 +12,32 @@ import ( "github.com/MichaelMure/git-bug/bridge/core/auth" ) +const ( + target = "github" + + metaKeyGithubId = "github-id" + metaKeyGithubUrl = "github-url" + metaKeyGithubLogin = "github-login" + + keyOwner = "owner" + keyProject = "project" + + githubV3Url = "https://api.github.com" + defaultTimeout = 60 * time.Second +) + +var _ core.BridgeImpl = &Github{} + type Github struct{} func (*Github) Target() string { return target } +func (g *Github) LoginMetaKey() string { + return metaKeyGithubLogin +} + func (*Github) NewImporter() core.Importer { return &githubImporter{} } diff --git a/bridge/github/import.go b/bridge/github/import.go index f2c9a53d..6a4c0110 100644 --- a/bridge/github/import.go +++ b/bridge/github/import.go @@ -15,12 +15,6 @@ import ( "github.com/MichaelMure/git-bug/util/text" ) -const ( - metaKeyGithubId = "github-id" - metaKeyGithubUrl = "github-url" - metaKeyGithubLogin = "github-login" -) - // githubImporter implement the Importer interface type githubImporter struct { conf core.Configuration diff --git a/bridge/github/import_test.go b/bridge/github/import_test.go index 73eaa096..a8f8e346 100644 --- a/bridge/github/import_test.go +++ b/bridge/github/import_test.go @@ -145,7 +145,7 @@ func Test_Importer(t *testing.T) { author.SetMetadata(metaKeyGithubLogin, login) token := auth.NewToken(envToken, target) - token.SetMetadata(metaKeyGithubLogin, login) + token.SetMetadata(auth.MetaKeyLogin, login) err = auth.Store(repo, token) require.NoError(t, err) -- cgit From 2e7ac569ad3146e5fa22907d8a4e63d2a524533b Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 8 Feb 2020 17:35:35 +0100 Subject: fix tests ? --- bridge/github/export_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'bridge/github') diff --git a/bridge/github/export_test.go b/bridge/github/export_test.go index 89040d8f..36d43173 100644 --- a/bridge/github/export_test.go +++ b/bridge/github/export_test.go @@ -155,6 +155,11 @@ func TestPushPull(t *testing.T) { defer backend.Close() interrupt.RegisterCleaner(backend.Close) + token := auth.NewToken(envToken, target) + token.SetMetadata(auth.MetaKeyLogin, login) + err = auth.Store(repo, token) + require.NoError(t, err) + tests := testCases(t, backend) // generate project name @@ -178,11 +183,6 @@ func TestPushPull(t *testing.T) { return deleteRepository(projectName, envUser, envToken) }) - token := auth.NewToken(envToken, target) - token.SetMetadata(auth.MetaKeyLogin, login) - err = auth.Store(repo, token) - require.NoError(t, err) - // initialize exporter exporter := &githubExporter{} err = exporter.Init(backend, core.Configuration{ @@ -258,7 +258,7 @@ func TestPushPull(t *testing.T) { // verify bug have same number of original operations require.Len(t, importedBug.Snapshot().Operations, tt.numOrOp) - // verify bugs are taged with origin=github + // verify bugs are tagged with origin=github issueOrigin, ok := importedBug.Snapshot().GetCreateMetadata(core.MetaKeyOrigin) require.True(t, ok) require.Equal(t, issueOrigin, target) -- cgit From 8773929f963b847841fac0d3c42d6278de69b79c Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 8 Feb 2020 22:04:25 +0100 Subject: github: make sure to have a name --- bridge/github/import.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bridge/github') diff --git a/bridge/github/import.go b/bridge/github/import.go index 6a4c0110..ea0ccba3 100644 --- a/bridge/github/import.go +++ b/bridge/github/import.go @@ -534,6 +534,11 @@ func (gi *githubImporter) ensurePerson(repo *cache.RepoCache, actor *actor) (*ca case "Bot": } + // Name is not necessarily set, fallback to login as a name is required in the identity + if name == "" { + name = string(actor.Login) + } + i, err = repo.NewIdentityRaw( name, email, -- cgit From bef35d4c679de81a214c99a30916fa7ebfc3f6a8 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 8 Feb 2020 22:05:13 +0100 Subject: bridge: hopefully fix tests --- bridge/github/export_test.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'bridge/github') diff --git a/bridge/github/export_test.go b/bridge/github/export_test.go index 36d43173..7d6e6fb1 100644 --- a/bridge/github/export_test.go +++ b/bridge/github/export_test.go @@ -148,6 +148,8 @@ func TestPushPull(t *testing.T) { author, err := backend.NewIdentity("test identity", "test@test.org") require.NoError(t, err) author.SetMetadata(metaKeyGithubLogin, login) + err = author.Commit() + require.NoError(t, err) err = backend.SetUserIdentity(author) require.NoError(t, err) -- cgit