Add support for GH_TOKEN and GH_ENTERPRISE_TOKEN
This commit is contained in:
parent
6e1e62f496
commit
a79a0bbfd7
5 changed files with 215 additions and 60 deletions
|
|
@ -136,17 +136,15 @@ func main() {
|
|||
|
||||
cs := cmdFactory.IOStreams.ColorScheme()
|
||||
|
||||
authCheckEnabled := os.Getenv("GITHUB_TOKEN") == "" &&
|
||||
os.Getenv("GITHUB_ENTERPRISE_TOKEN") == "" &&
|
||||
cmd != nil && cmdutil.IsAuthCheckEnabled(cmd)
|
||||
if authCheckEnabled {
|
||||
if !cmdutil.CheckAuth(cfg) {
|
||||
fmt.Fprintln(stderr, cs.Bold("Welcome to GitHub CLI!"))
|
||||
fmt.Fprintln(stderr)
|
||||
fmt.Fprintln(stderr, "To authenticate, please run `gh auth login`.")
|
||||
fmt.Fprintln(stderr, "You can also set the GITHUB_TOKEN environment variable, if preferred.")
|
||||
os.Exit(4)
|
||||
}
|
||||
// _, _, tokenPresent := config.AuthTokenFromEnv(ghinstance.OverridableDefault())
|
||||
// authCheckEnabled := !tokenPresent && cmd != nil && cmdutil.IsAuthCheckEnabled(cmd)
|
||||
authCheckEnabled := cmd != nil && cmdutil.IsAuthCheckEnabled(cmd)
|
||||
if authCheckEnabled && !cmdutil.CheckAuth(cfg) {
|
||||
fmt.Fprintln(stderr, cs.Bold("Welcome to GitHub CLI!"))
|
||||
fmt.Fprintln(stderr)
|
||||
fmt.Fprintln(stderr, "To authenticate, please run `gh auth login`.")
|
||||
fmt.Fprintln(stderr, "You can also set the one of the oauth token environment variables, if preferred.")
|
||||
os.Exit(4)
|
||||
}
|
||||
|
||||
rootCmd.SetArgs(expandedArgs)
|
||||
|
|
@ -248,8 +246,8 @@ func basicClient(currentVersion string) (*api.Client, error) {
|
|||
}
|
||||
opts = append(opts, api.AddHeader("User-Agent", fmt.Sprintf("GitHub CLI %s", currentVersion)))
|
||||
|
||||
token := os.Getenv("GITHUB_TOKEN")
|
||||
if token == "" {
|
||||
token, _, ok := config.AuthTokenFromEnv(ghinstance.Default())
|
||||
if !ok {
|
||||
if c, err := config.ParseDefaultConfig(); err == nil {
|
||||
token, _ = c.Get(ghinstance.Default(), "oauth_token")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
GH_TOKEN = "GH_TOKEN"
|
||||
GITHUB_TOKEN = "GITHUB_TOKEN"
|
||||
GH_ENTERPRISE_TOKEN = "GH_ENTERPRISE_TOKEN"
|
||||
GITHUB_ENTERPRISE_TOKEN = "GITHUB_ENTERPRISE_TOKEN"
|
||||
)
|
||||
|
||||
|
|
@ -28,7 +30,8 @@ func (c *envConfig) Hosts() ([]string, error) {
|
|||
hasDefault = true
|
||||
}
|
||||
}
|
||||
if (err != nil || !hasDefault) && os.Getenv(GITHUB_TOKEN) != "" {
|
||||
_, _, found := AuthTokenFromEnv(ghinstance.Default())
|
||||
if (err != nil || !hasDefault) && found {
|
||||
hosts = append([]string{ghinstance.Default()}, hosts...)
|
||||
return hosts, nil
|
||||
}
|
||||
|
|
@ -42,13 +45,8 @@ func (c *envConfig) Get(hostname, key string) (string, error) {
|
|||
|
||||
func (c *envConfig) GetWithSource(hostname, key string) (string, string, error) {
|
||||
if hostname != "" && key == "oauth_token" {
|
||||
envName := GITHUB_TOKEN
|
||||
if ghinstance.IsEnterprise(hostname) {
|
||||
envName = GITHUB_ENTERPRISE_TOKEN
|
||||
}
|
||||
|
||||
if value := os.Getenv(envName); value != "" {
|
||||
return value, envName, nil
|
||||
if value, name, found := AuthTokenFromEnv(hostname); found {
|
||||
return value, name, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,15 +55,28 @@ func (c *envConfig) GetWithSource(hostname, key string) (string, string, error)
|
|||
|
||||
func (c *envConfig) CheckWriteable(hostname, key string) error {
|
||||
if hostname != "" && key == "oauth_token" {
|
||||
envName := GITHUB_TOKEN
|
||||
if ghinstance.IsEnterprise(hostname) {
|
||||
envName = GITHUB_ENTERPRISE_TOKEN
|
||||
}
|
||||
|
||||
if os.Getenv(envName) != "" {
|
||||
return fmt.Errorf("read-only token in %s cannot be modified", envName)
|
||||
if _, name, found := AuthTokenFromEnv(hostname); found {
|
||||
return fmt.Errorf("read-only token in %s cannot be modified", name)
|
||||
}
|
||||
}
|
||||
|
||||
return c.Config.CheckWriteable(hostname, key)
|
||||
}
|
||||
|
||||
func AuthTokenFromEnv(hostname string) (string, string, bool) {
|
||||
if ghinstance.IsEnterprise(hostname) {
|
||||
if token, found := os.LookupEnv(GH_ENTERPRISE_TOKEN); found {
|
||||
return token, GH_ENTERPRISE_TOKEN, found
|
||||
}
|
||||
|
||||
token, found := os.LookupEnv(GITHUB_ENTERPRISE_TOKEN)
|
||||
return token, GITHUB_ENTERPRISE_TOKEN, found
|
||||
}
|
||||
|
||||
if token, found := os.LookupEnv(GH_TOKEN); found {
|
||||
return token, GH_TOKEN, found
|
||||
}
|
||||
|
||||
token, found := os.LookupEnv(GITHUB_TOKEN)
|
||||
return token, GITHUB_TOKEN, found
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,9 +11,13 @@ import (
|
|||
func TestInheritEnv(t *testing.T) {
|
||||
orig_GITHUB_TOKEN := os.Getenv("GITHUB_TOKEN")
|
||||
orig_GITHUB_ENTERPRISE_TOKEN := os.Getenv("GITHUB_ENTERPRISE_TOKEN")
|
||||
orig_GH_TOKEN := os.Getenv("GH_TOKEN")
|
||||
orig_GH_ENTERPRISE_TOKEN := os.Getenv("GH_ENTERPRISE_TOKEN")
|
||||
t.Cleanup(func() {
|
||||
os.Setenv("GITHUB_TOKEN", orig_GITHUB_TOKEN)
|
||||
os.Setenv("GITHUB_ENTERPRISE_TOKEN", orig_GITHUB_ENTERPRISE_TOKEN)
|
||||
os.Setenv("GH_TOKEN", orig_GH_TOKEN)
|
||||
os.Setenv("GH_ENTERPRISE_TOKEN", orig_GH_ENTERPRISE_TOKEN)
|
||||
})
|
||||
|
||||
type wants struct {
|
||||
|
|
@ -28,15 +32,15 @@ func TestInheritEnv(t *testing.T) {
|
|||
baseConfig string
|
||||
GITHUB_TOKEN string
|
||||
GITHUB_ENTERPRISE_TOKEN string
|
||||
GH_TOKEN string
|
||||
GH_ENTERPRISE_TOKEN string
|
||||
hostname string
|
||||
wants wants
|
||||
}{
|
||||
{
|
||||
name: "blank",
|
||||
baseConfig: ``,
|
||||
GITHUB_TOKEN: "",
|
||||
GITHUB_ENTERPRISE_TOKEN: "",
|
||||
hostname: "github.com",
|
||||
name: "blank",
|
||||
baseConfig: ``,
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string(nil),
|
||||
token: "",
|
||||
|
|
@ -45,11 +49,10 @@ func TestInheritEnv(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "GITHUB_TOKEN over blank config",
|
||||
baseConfig: ``,
|
||||
GITHUB_TOKEN: "OTOKEN",
|
||||
GITHUB_ENTERPRISE_TOKEN: "",
|
||||
hostname: "github.com",
|
||||
name: "GITHUB_TOKEN over blank config",
|
||||
baseConfig: ``,
|
||||
GITHUB_TOKEN: "OTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "OTOKEN",
|
||||
|
|
@ -58,11 +61,34 @@ func TestInheritEnv(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
name: "GITHUB_TOKEN not applicable to GHE",
|
||||
baseConfig: ``,
|
||||
GITHUB_TOKEN: "OTOKEN",
|
||||
GITHUB_ENTERPRISE_TOKEN: "",
|
||||
hostname: "example.org",
|
||||
name: "GH_TOKEN over blank config",
|
||||
baseConfig: ``,
|
||||
GH_TOKEN: "OTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "OTOKEN",
|
||||
source: "GH_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GITHUB_TOKEN not applicable to GHE",
|
||||
baseConfig: ``,
|
||||
GITHUB_TOKEN: "OTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "",
|
||||
source: "~/.config/gh/config.yml",
|
||||
writeable: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_TOKEN not applicable to GHE",
|
||||
baseConfig: ``,
|
||||
GH_TOKEN: "OTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "",
|
||||
|
|
@ -73,7 +99,6 @@ func TestInheritEnv(t *testing.T) {
|
|||
{
|
||||
name: "GITHUB_ENTERPRISE_TOKEN over blank config",
|
||||
baseConfig: ``,
|
||||
GITHUB_TOKEN: "",
|
||||
GITHUB_ENTERPRISE_TOKEN: "ENTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
|
|
@ -83,6 +108,18 @@ func TestInheritEnv(t *testing.T) {
|
|||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_ENTERPRISE_TOKEN over blank config",
|
||||
baseConfig: ``,
|
||||
GH_ENTERPRISE_TOKEN: "ENTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
hosts: []string(nil),
|
||||
token: "ENTOKEN",
|
||||
source: "GH_ENTERPRISE_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "token from file",
|
||||
baseConfig: heredoc.Doc(`
|
||||
|
|
@ -90,9 +127,7 @@ func TestInheritEnv(t *testing.T) {
|
|||
github.com:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GITHUB_TOKEN: "",
|
||||
GITHUB_ENTERPRISE_TOKEN: "",
|
||||
hostname: "github.com",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "OTOKEN",
|
||||
|
|
@ -107,9 +142,8 @@ func TestInheritEnv(t *testing.T) {
|
|||
github.com:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GITHUB_TOKEN: "ENVTOKEN",
|
||||
GITHUB_ENTERPRISE_TOKEN: "",
|
||||
hostname: "github.com",
|
||||
GITHUB_TOKEN: "ENVTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "ENVTOKEN",
|
||||
|
|
@ -117,6 +151,80 @@ func TestInheritEnv(t *testing.T) {
|
|||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_TOKEN shadows token from file",
|
||||
baseConfig: heredoc.Doc(`
|
||||
hosts:
|
||||
github.com:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GH_TOKEN: "ENVTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "ENVTOKEN",
|
||||
source: "GH_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GITHUB_ENTERPRISE_TOKEN shadows token from file",
|
||||
baseConfig: heredoc.Doc(`
|
||||
hosts:
|
||||
example.org:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GITHUB_ENTERPRISE_TOKEN: "ENVTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
hosts: []string{"example.org"},
|
||||
token: "ENVTOKEN",
|
||||
source: "GITHUB_ENTERPRISE_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_ENTERPRISE_TOKEN shadows token from file",
|
||||
baseConfig: heredoc.Doc(`
|
||||
hosts:
|
||||
example.org:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GH_ENTERPRISE_TOKEN: "ENVTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
hosts: []string{"example.org"},
|
||||
token: "ENVTOKEN",
|
||||
source: "GH_ENTERPRISE_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_TOKEN shadows token from GITHUB_TOKEN",
|
||||
baseConfig: ``,
|
||||
GH_TOKEN: "GHTOKEN",
|
||||
GITHUB_TOKEN: "GITHUBTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com"},
|
||||
token: "GHTOKEN",
|
||||
source: "GH_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_ENTERPRISE_TOKEN shadows token from GITHUB_ENTERPRISE_TOKEN",
|
||||
baseConfig: ``,
|
||||
GH_ENTERPRISE_TOKEN: "GHTOKEN",
|
||||
GITHUB_ENTERPRISE_TOKEN: "GITHUBTOKEN",
|
||||
hostname: "example.org",
|
||||
wants: wants{
|
||||
hosts: []string(nil),
|
||||
token: "GHTOKEN",
|
||||
source: "GH_ENTERPRISE_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GITHUB_TOKEN adds host entry",
|
||||
baseConfig: heredoc.Doc(`
|
||||
|
|
@ -124,9 +232,8 @@ func TestInheritEnv(t *testing.T) {
|
|||
example.org:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GITHUB_TOKEN: "ENVTOKEN",
|
||||
GITHUB_ENTERPRISE_TOKEN: "",
|
||||
hostname: "github.com",
|
||||
GITHUB_TOKEN: "ENVTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com", "example.org"},
|
||||
token: "ENVTOKEN",
|
||||
|
|
@ -134,11 +241,48 @@ func TestInheritEnv(t *testing.T) {
|
|||
writeable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GH_TOKEN adds host entry",
|
||||
baseConfig: heredoc.Doc(`
|
||||
hosts:
|
||||
example.org:
|
||||
oauth_token: OTOKEN
|
||||
`),
|
||||
GH_TOKEN: "ENVTOKEN",
|
||||
hostname: "github.com",
|
||||
wants: wants{
|
||||
hosts: []string{"github.com", "example.org"},
|
||||
token: "ENVTOKEN",
|
||||
source: "GH_TOKEN",
|
||||
writeable: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
os.Setenv("GITHUB_TOKEN", tt.GITHUB_TOKEN)
|
||||
os.Setenv("GITHUB_ENTERPRISE_TOKEN", tt.GITHUB_ENTERPRISE_TOKEN)
|
||||
if tt.GITHUB_TOKEN != "" {
|
||||
os.Setenv("GITHUB_TOKEN", tt.GITHUB_TOKEN)
|
||||
} else {
|
||||
os.Unsetenv("GITHUB_TOKEN")
|
||||
}
|
||||
|
||||
if tt.GITHUB_ENTERPRISE_TOKEN != "" {
|
||||
os.Setenv("GITHUB_ENTERPRISE_TOKEN", tt.GITHUB_ENTERPRISE_TOKEN)
|
||||
} else {
|
||||
os.Unsetenv("GITHUB_ENTERPRISE_TOKEN")
|
||||
}
|
||||
|
||||
if tt.GH_TOKEN != "" {
|
||||
os.Setenv("GH_TOKEN", tt.GH_TOKEN)
|
||||
} else {
|
||||
os.Unsetenv("GH_TOKEN")
|
||||
}
|
||||
|
||||
if tt.GH_ENTERPRISE_TOKEN != "" {
|
||||
os.Setenv("GH_ENTERPRISE_TOKEN", tt.GH_ENTERPRISE_TOKEN)
|
||||
} else {
|
||||
os.Unsetenv("GH_ENTERPRISE_TOKEN")
|
||||
}
|
||||
|
||||
baseCfg := NewFromString(tt.baseConfig)
|
||||
cfg := InheritEnv(baseCfg)
|
||||
|
|
|
|||
|
|
@ -119,9 +119,9 @@ original query accepts an '$endCursor: String' variable and that it fetches the
|
|||
`),
|
||||
Annotations: map[string]string{
|
||||
"help:environment": heredoc.Doc(`
|
||||
GITHUB_TOKEN: an authentication token for github.com API requests.
|
||||
GH_TOKEN, GITHUB_TOKEN (in order of procedence): an authentication token for github.com API requests.
|
||||
|
||||
GITHUB_ENTERPRISE_TOKEN: an authentication token for API requests to GitHub Enterprise.
|
||||
GH_ENTERPRISE_TOKEN, GITHUB_ENTERPRISE_TOKEN (in order of procedence): an authentication token for API requests to GitHub Enterprise.
|
||||
|
||||
GH_HOST: make the request to a GitHub host other than github.com.
|
||||
`),
|
||||
|
|
|
|||
|
|
@ -9,10 +9,12 @@ var HelpTopics = map[string]map[string]string{
|
|||
"environment": {
|
||||
"short": "Environment variables that can be used with gh",
|
||||
"long": heredoc.Doc(`
|
||||
GITHUB_TOKEN: an authentication token for github.com API requests. Setting this avoids
|
||||
being prompted to authenticate and takes precedence over previously stored credentials.
|
||||
GH_TOKEN, GITHUB_TOKEN (in order of procedence): an authentication token for github.com
|
||||
API requests. Setting this avoids being prompted to authenticate and takes precedence over
|
||||
previously stored credentials.
|
||||
|
||||
GITHUB_ENTERPRISE_TOKEN: an authentication token for API requests to GitHub Enterprise.
|
||||
GH_ENTERPRISE_TOKEN, GITHUB_ENTERPRISE_TOKEN (in order of precedence): an authentication
|
||||
token for API requests to GitHub Enterprise.
|
||||
|
||||
GH_REPO: specify the GitHub repository in the "[HOST/]OWNER/REPO" format for commands
|
||||
that otherwise operate on a local repository.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue