From 9bf1668b3f83997f6fdecf1410bf0f586c3c11f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Fri, 19 Feb 2021 15:37:11 +0100 Subject: [PATCH 1/2] Fix `auth git-credential` when the token comes from environment When a token such as GH_TOKEN is set through environment variables and `~/.config/gh/hosts.yml` is non-existent, the `auth git-credential get` command used to fail due to missing username. Since GitHub username isn't at all required for token authentication, use the `x-access-token` faux username instead of trying to obtain one from a config file. --- pkg/cmd/auth/gitcredential/helper.go | 16 ++++++++--- pkg/cmd/auth/gitcredential/helper_test.go | 34 +++++++++++++++++++++-- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/pkg/cmd/auth/gitcredential/helper.go b/pkg/cmd/auth/gitcredential/helper.go index c62cef3a8..4f80afbe7 100644 --- a/pkg/cmd/auth/gitcredential/helper.go +++ b/pkg/cmd/auth/gitcredential/helper.go @@ -11,8 +11,10 @@ import ( "github.com/spf13/cobra" ) +const tokenUser = "x-access-token" + type config interface { - Get(string, string) (string, error) + GetWithSource(string, string) (string, string, error) } type CredentialOptions struct { @@ -98,13 +100,19 @@ func helperRun(opts *CredentialOptions) error { return err } - gotUser, _ := cfg.Get(wants["host"], "user") - gotToken, _ := cfg.Get(wants["host"], "oauth_token") + var gotUser string + gotToken, source, _ := cfg.GetWithSource(wants["host"], "oauth_token") + if strings.HasSuffix(source, "_TOKEN") { + gotUser = tokenUser + } else { + gotUser, _, _ = cfg.GetWithSource(wants["host"], "user") + } + if gotUser == "" || gotToken == "" { return cmdutil.SilentError } - if wants["username"] != "" && !strings.EqualFold(wants["username"], gotUser) { + if wants["username"] != "" && gotUser != tokenUser && !strings.EqualFold(wants["username"], gotUser) { return cmdutil.SilentError } diff --git a/pkg/cmd/auth/gitcredential/helper_test.go b/pkg/cmd/auth/gitcredential/helper_test.go index 336d4ef34..c8f449526 100644 --- a/pkg/cmd/auth/gitcredential/helper_test.go +++ b/pkg/cmd/auth/gitcredential/helper_test.go @@ -10,8 +10,8 @@ import ( type tinyConfig map[string]string -func (c tinyConfig) Get(host, key string) (string, error) { - return c[fmt.Sprintf("%s:%s", host, key)], nil +func (c tinyConfig) GetWithSource(host, key string) (string, string, error) { + return c[fmt.Sprintf("%s:%s", host, key)], c["_source"], nil } func Test_helperRun(t *testing.T) { @@ -29,6 +29,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -53,6 +54,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -78,6 +80,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -101,6 +104,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", }, nil }, @@ -119,6 +123,7 @@ func Test_helperRun(t *testing.T) { Operation: "get", Config: func() (config, error) { return tinyConfig{ + "_source": "/Users/monalisa/.config/gh/hosts.yml", "example.com:user": "monalisa", "example.com:oauth_token": "OTOKEN", }, nil @@ -133,6 +138,31 @@ func Test_helperRun(t *testing.T) { wantStdout: "", wantStderr: "", }, + { + name: "token from env", + opts: CredentialOptions{ + Operation: "get", + Config: func() (config, error) { + return tinyConfig{ + "_source": "GITHUB_ENTERPRISE_TOKEN", + "example.com:oauth_token": "OTOKEN", + }, nil + }, + }, + input: heredoc.Doc(` + protocol=https + host=example.com + username=hubot + `), + wantErr: false, + wantStdout: heredoc.Doc(` + protocol=https + host=example.com + username=x-access-token + password=OTOKEN + `), + wantStderr: "", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 27aea42d8a43951b880145fcbbd42b262ed6af08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Tue, 23 Feb 2021 12:10:56 +0100 Subject: [PATCH 2/2] Avoid upgrade notice for recent release if gh is under Homebrew prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before, when gh detected there was a new release in the `cli/cli` repo, it would show this notice: A new release of gh is available: {V1} → {V2} Additionally, when the release was more than 24h old, we would show this to Homebrew users: To upgrade, run: brew update && brew upgrade gh Ref. feb4acc2c00ce42d5ed67252ae1ec66addeb786d This change makes it so that the original notice "A new release of gh is available" is NOT shown to Homebrew users unless the release is older than 24h. We effectively hide the fact that any release happened until we're sure that the version bump has made it to `homebrew-core`. --- cmd/gh/main.go | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/gh/main.go b/cmd/gh/main.go index a0eba09a5..e20452808 100644 --- a/cmd/gh/main.go +++ b/cmd/gh/main.go @@ -163,12 +163,19 @@ func main() { newRelease := <-updateMessageChan if newRelease != nil { - ghExe, _ := os.Executable() + isHomebrew := false + if ghExe, err := os.Executable(); err == nil { + isHomebrew = isUnderHomebrew(ghExe) + } + if isHomebrew && isRecentRelease(newRelease.PublishedAt) { + // do not notify Homebrew users before the version bump had a chance to get merged into homebrew-core + return + } fmt.Fprintf(stderr, "\n\n%s %s → %s\n", ansi.Color("A new release of gh is available:", "yellow"), ansi.Color(buildVersion, "cyan"), ansi.Color(newRelease.Version, "cyan")) - if suggestBrewUpgrade(newRelease, ghExe) { + if isHomebrew { fmt.Fprintf(stderr, "To upgrade, run: %s\n", "brew update && brew upgrade gh") } fmt.Fprintf(stderr, "%s\n\n", @@ -265,13 +272,12 @@ func apiVerboseLog() api.ClientOption { return api.VerboseLog(colorable.NewColorable(os.Stderr), logTraffic, colorize) } -// Suggest to `brew upgrade gh` only if gh was found under homebrew prefix and when the release was -// published over 24h ago, allowing homebrew-core ample time to merge the formula bump. -func suggestBrewUpgrade(rel *update.ReleaseInfo, ghBinary string) bool { - if rel.PublishedAt.IsZero() || time.Since(rel.PublishedAt) < time.Duration(time.Hour*24) { - return false - } +func isRecentRelease(publishedAt time.Time) bool { + return !publishedAt.IsZero() && time.Since(publishedAt) < time.Hour*24 +} +// Check whether the gh binary was found under the Homebrew prefix +func isUnderHomebrew(ghBinary string) bool { brewExe, err := safeexec.LookPath("brew") if err != nil { return false