Skip to content

Commit

Permalink
feat: allow to forcefully use a token when multiple are set (#3910)
Browse files Browse the repository at this point in the history
This would allow to, when multiple tokens are set in the environment,
force which one you want to use.

The need for this comes from the fact gitea sets both `GITHUB_TOKEN` and
`GITEA_TOKEN`, and doesn't allow to easily disable either.

With this, users can add a `GORELEASER_FORCE_TOKEN=gitea` to force the
gitea client to be used.

I'm not sure what's the best name for this env yet, happy to hear
suggestions.

Also improved the `env_test.go` file a bit, as it was kinda messy with
env vars...

refs https://github.com/orgs/goreleaser/discussions/3900

---------

Signed-off-by: Carlos A Becker <caarlos0@users.noreply.github.com>
  • Loading branch information
caarlos0 committed Apr 5, 2023
1 parent 00b2175 commit dc6a4e7
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 55 deletions.
36 changes: 24 additions & 12 deletions internal/pipe/env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,30 @@ func (Pipe) Run(ctx *context.Context) error {
gitlabToken, gitlabTokenErr := loadEnv("GITLAB_TOKEN", ctx.Config.EnvFiles.GitLabToken)
giteaToken, giteaTokenErr := loadEnv("GITEA_TOKEN", ctx.Config.EnvFiles.GiteaToken)

var tokens []string
if githubToken != "" {
tokens = append(tokens, "GITHUB_TOKEN")
}
if gitlabToken != "" {
tokens = append(tokens, "GITLAB_TOKEN")
}
if giteaToken != "" {
tokens = append(tokens, "GITEA_TOKEN")
}
if len(tokens) > 1 {
return ErrMultipleTokens{tokens}
switch os.Getenv("GORELEASER_FORCE_TOKEN") {
case "github":
gitlabToken = ""
giteaToken = ""
case "gitlab":
githubToken = ""
giteaToken = ""
case "gitea":
githubToken = ""
gitlabToken = ""
default:
var tokens []string
if githubToken != "" {
tokens = append(tokens, "GITHUB_TOKEN")
}
if gitlabToken != "" {
tokens = append(tokens, "GITLAB_TOKEN")
}
if giteaToken != "" {
tokens = append(tokens, "GITEA_TOKEN")
}
if len(tokens) > 1 {
return ErrMultipleTokens{tokens}
}
}

noTokens := githubToken == "" && gitlabToken == "" && giteaToken == ""
Expand Down
105 changes: 63 additions & 42 deletions internal/pipe/env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ import (
"github.com/stretchr/testify/require"
)

func TestMain(m *testing.M) {
restores := map[string]string{}
for _, key := range []string{"GITHUB_TOKEN", "GITEA_TOKEN", "GITLAB_TOKEN"} {
prevValue, ok := os.LookupEnv(key)
if ok {
_ = os.Unsetenv(key)
restores[key] = prevValue
}
}

code := m.Run()

for k, v := range restores {
_ = os.Setenv(k, v)
}

os.Exit(code)
}

func TestDescription(t *testing.T) {
require.NotEmpty(t, Pipe{}.String())
}
Expand Down Expand Up @@ -44,8 +63,8 @@ func TestSetDefaultTokenFiles(t *testing.T) {
},
})
ctx.Env["FOOBAR"] = "old foobar"
os.Setenv("BAR", "lebar")
os.Setenv("GITHUB_TOKEN", "fake")
t.Setenv("BAR", "lebar")
t.Setenv("GITHUB_TOKEN", "fake")
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, "FOO_lebar", ctx.Env["FOO"])
require.Equal(t, "foobar", ctx.Env["FOOBAR"])
Expand All @@ -62,83 +81,99 @@ func TestSetDefaultTokenFiles(t *testing.T) {
})

t.Run("no token", func(t *testing.T) {
ctx := testctx.New()
require.EqualError(t, Pipe{}.Run(ctx), ErrMissingToken.Error())
})
}

func TestForceToken(t *testing.T) {
t.Run("github", func(t *testing.T) {
t.Setenv("GITHUB_TOKEN", "fake")
t.Setenv("GORELEASER_FORCE_TOKEN", "github")
ctx := testctx.New()
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, context.TokenTypeGitHub, ctx.TokenType)
})
t.Run("gitlab", func(t *testing.T) {
t.Setenv("GITLAB_TOKEN", "fake")
t.Setenv("GORELEASER_FORCE_TOKEN", "gitlab")
ctx := testctx.New()
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, ctx.TokenType, context.TokenTypeGitHub)
require.Equal(t, context.TokenTypeGitLab, ctx.TokenType)
})
t.Run("gitea", func(t *testing.T) {
t.Setenv("GITEA_TOKEN", "fake")
t.Setenv("GORELEASER_FORCE_TOKEN", "gitea")
ctx := testctx.New()
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, context.TokenTypeGitea, ctx.TokenType)
})
}

func TestValidGithubEnv(t *testing.T) {
require.NoError(t, os.Setenv("GITHUB_TOKEN", "asdf"))
t.Setenv("GITHUB_TOKEN", "asdf")
ctx := testctx.New()
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, "asdf", ctx.Token)
require.Equal(t, context.TokenTypeGitHub, ctx.TokenType)
// so the tests do not depend on each other
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
}

func TestValidGitlabEnv(t *testing.T) {
require.NoError(t, os.Setenv("GITLAB_TOKEN", "qwertz"))
t.Setenv("GITLAB_TOKEN", "qwertz")
ctx := testctx.New()
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, "qwertz", ctx.Token)
require.Equal(t, context.TokenTypeGitLab, ctx.TokenType)
// so the tests do not depend on each other
require.NoError(t, os.Unsetenv("GITLAB_TOKEN"))
}

func TestValidGiteaEnv(t *testing.T) {
require.NoError(t, os.Setenv("GITEA_TOKEN", "token"))
t.Setenv("GITEA_TOKEN", "token")
ctx := testctx.New()
require.NoError(t, Pipe{}.Run(ctx))
require.Equal(t, "token", ctx.Token)
require.Equal(t, context.TokenTypeGitea, ctx.TokenType)
// so the tests do not depend on each other
require.NoError(t, os.Unsetenv("GITEA_TOKEN"))
}

func TestInvalidEnv(t *testing.T) {
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
require.NoError(t, os.Unsetenv("GITLAB_TOKEN"))
ctx := testctx.New()
require.Error(t, Pipe{}.Run(ctx))
require.EqualError(t, Pipe{}.Run(ctx), ErrMissingToken.Error())
}

func TestMultipleEnvTokens(t *testing.T) {
require.NoError(t, os.Setenv("GITHUB_TOKEN", "asdf"))
require.NoError(t, os.Setenv("GITLAB_TOKEN", "qwertz"))
require.NoError(t, os.Setenv("GITEA_TOKEN", "token"))
t.Setenv("GITHUB_TOKEN", "asdf")
t.Setenv("GITLAB_TOKEN", "qwertz")
t.Setenv("GITEA_TOKEN", "token")
ctx := testctx.New()
require.Error(t, Pipe{}.Run(ctx))
require.EqualError(t, Pipe{}.Run(ctx), "multiple tokens found, but only one is allowed: GITHUB_TOKEN, GITLAB_TOKEN, GITEA_TOKEN\n\nLearn more at https://goreleaser.com/errors/multiple-tokens\n")
}

func TestMultipleEnvTokensForce(t *testing.T) {
t.Setenv("GITHUB_TOKEN", "asdf")
t.Setenv("GITLAB_TOKEN", "qwertz")
t.Setenv("GITEA_TOKEN", "token")
ctx := testctx.New()
require.Error(t, Pipe{}.Run(ctx))
require.EqualError(t, Pipe{}.Run(ctx), "multiple tokens found, but only one is allowed: GITHUB_TOKEN, GITLAB_TOKEN, GITEA_TOKEN\n\nLearn more at https://goreleaser.com/errors/multiple-tokens\n")
// so the tests do not depend on each other
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
require.NoError(t, os.Unsetenv("GITLAB_TOKEN"))
require.NoError(t, os.Unsetenv("GITEA_TOKEN"))
}

func TestEmptyGithubFileEnv(t *testing.T) {
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
ctx := testctx.New()
require.Error(t, Pipe{}.Run(ctx))
}

func TestEmptyGitlabFileEnv(t *testing.T) {
require.NoError(t, os.Unsetenv("GITLAB_TOKEN"))
ctx := testctx.New()
require.Error(t, Pipe{}.Run(ctx))
}

func TestEmptyGiteaFileEnv(t *testing.T) {
require.NoError(t, os.Unsetenv("GITEA_TOKEN"))
ctx := testctx.New()
require.Error(t, Pipe{}.Run(ctx))
}

func TestEmptyGithubEnvFile(t *testing.T) {
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
f, err := os.CreateTemp(t.TempDir(), "token")
require.NoError(t, err)
require.NoError(t, f.Close())
Expand All @@ -152,7 +187,6 @@ func TestEmptyGithubEnvFile(t *testing.T) {
}

func TestEmptyGitlabEnvFile(t *testing.T) {
require.NoError(t, os.Unsetenv("GITLAB_TOKEN"))
f, err := os.CreateTemp(t.TempDir(), "token")
require.NoError(t, err)
require.NoError(t, f.Close())
Expand All @@ -166,7 +200,6 @@ func TestEmptyGitlabEnvFile(t *testing.T) {
}

func TestEmptyGiteaEnvFile(t *testing.T) {
require.NoError(t, os.Unsetenv("GITEA_TOKEN"))
f, err := os.CreateTemp(t.TempDir(), "token")
require.NoError(t, err)
require.NoError(t, f.Close())
Expand All @@ -180,14 +213,11 @@ func TestEmptyGiteaEnvFile(t *testing.T) {
}

func TestInvalidEnvChecksSkipped(t *testing.T) {
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
ctx := testctx.New(testctx.SkipPublish)
require.NoError(t, Pipe{}.Run(ctx))
}

func TestInvalidEnvReleaseDisabled(t *testing.T) {
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))

t.Run("true", func(t *testing.T) {
ctx := testctx.NewWithCfg(config.Project{
Env: []string{},
Expand Down Expand Up @@ -228,21 +258,16 @@ func TestInvalidEnvReleaseDisabled(t *testing.T) {
})
}

func TestInvalidEnvReleaseDisabledTmpl(t *testing.T) {
require.NoError(t, os.Unsetenv("GITHUB_TOKEN"))
}

func TestLoadEnv(t *testing.T) {
const env = "SUPER_SECRET_ENV_NOPE"

t.Run("env exists", func(t *testing.T) {
env := "SUPER_SECRET_ENV"
require.NoError(t, os.Setenv(env, "1"))
t.Setenv(env, "1")
v, err := loadEnv(env, "nope")
require.NoError(t, err)
require.Equal(t, "1", v)
})
t.Run("env file exists", func(t *testing.T) {
env := "SUPER_SECRET_ENV_NOPE"
require.NoError(t, os.Unsetenv(env))
f, err := os.CreateTemp(t.TempDir(), "token")
require.NoError(t, err)
fmt.Fprintf(f, "123")
Expand All @@ -252,8 +277,6 @@ func TestLoadEnv(t *testing.T) {
require.Equal(t, "123", v)
})
t.Run("env file with an empty line at the end", func(t *testing.T) {
env := "SUPER_SECRET_ENV_NOPE"
require.NoError(t, os.Unsetenv(env))
f, err := os.CreateTemp(t.TempDir(), "token")
require.NoError(t, err)
fmt.Fprintf(f, "123\n")
Expand All @@ -263,8 +286,6 @@ func TestLoadEnv(t *testing.T) {
require.Equal(t, "123", v)
})
t.Run("env file is not readable", func(t *testing.T) {
env := "SUPER_SECRET_ENV_NOPE"
require.NoError(t, os.Unsetenv(env))
f, err := os.CreateTemp(t.TempDir(), "token")
require.NoError(t, err)
fmt.Fprintf(f, "123")
Expand Down
12 changes: 11 additions & 1 deletion www/docs/errors/multiple-tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,21 @@ to force one of them, you can explicitly disable the others by setting them to a
file you know won't exist:

```yaml

# .goreleaser.yaml
env_files:
gitlab_token: ~/nope
gitea_token: ~/nope
```

## Forcing a specific token

This will prevent using both GitLab and Gitea tokens.

If GoReleaser is being run with more than one of the `*_TOKEN` environment
variables and you can't unset any of them, you can force GoReleaser to use a
specific one by exporting a `GORELEASER_FORCE_TOKEN` environment variable.

So, for instance, if you have both `GITHUB_TOKEN` and `GITEA_TOKEN` set and want
GoReleaser to pick `GITEA_TOKEN`, you can set `GORELEASER_FORCE_TOKEN=gitea`.
GoReleaser will then unset `GITHUB_TOKEN` and proceed.

0 comments on commit dc6a4e7

Please sign in to comment.