github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/env/env.go (about) 1 // Package env implements the Pipe interface providing validation of 2 // missing environment variables needed by the release process. 3 package env 4 5 import ( 6 "bufio" 7 "errors" 8 "fmt" 9 "io/fs" 10 "os" 11 "strings" 12 13 "github.com/caarlos0/log" 14 "github.com/goreleaser/goreleaser/internal/logext" 15 "github.com/goreleaser/goreleaser/internal/skips" 16 "github.com/goreleaser/goreleaser/internal/tmpl" 17 "github.com/goreleaser/goreleaser/pkg/context" 18 homedir "github.com/mitchellh/go-homedir" 19 ) 20 21 // ErrMissingToken indicates an error when GITHUB_TOKEN, GITLAB_TOKEN and GITEA_TOKEN are all missing in the environment. 22 var ErrMissingToken = errors.New("missing GITHUB_TOKEN, GITLAB_TOKEN and GITEA_TOKEN") 23 24 // ErrMultipleTokens indicates that multiple tokens are defined. ATM only one of them if allowed. 25 // See https://github.com/goreleaser/goreleaser/pull/809 26 type ErrMultipleTokens struct { 27 tokens []string 28 } 29 30 func (e ErrMultipleTokens) Error() string { 31 return fmt.Sprintf("multiple tokens found, but only one is allowed: %s\n\nLearn more at https://goreleaser.com/errors/multiple-tokens\n", strings.Join(e.tokens, ", ")) 32 } 33 34 // Pipe for env. 35 type Pipe struct{} 36 37 func (Pipe) String() string { 38 return "loading environment variables" 39 } 40 41 func setDefaultTokenFiles(ctx *context.Context) { 42 env := &ctx.Config.EnvFiles 43 if env.GitHubToken == "" { 44 env.GitHubToken = "~/.config/goreleaser/github_token" 45 } 46 if env.GitLabToken == "" { 47 env.GitLabToken = "~/.config/goreleaser/gitlab_token" 48 } 49 if env.GiteaToken == "" { 50 env.GiteaToken = "~/.config/goreleaser/gitea_token" 51 } 52 } 53 54 // Run the pipe. 55 func (Pipe) Run(ctx *context.Context) error { 56 templ := tmpl.New(ctx).WithEnvS(os.Environ()) 57 tEnv := []string{} 58 for i := range ctx.Config.Env { 59 env, err := templ.Apply(ctx.Config.Env[i]) 60 if err != nil { 61 return err 62 } 63 tEnv = append(tEnv, env) 64 } 65 for k, v := range context.ToEnv(tEnv) { 66 ctx.Env[k] = v 67 } 68 69 setDefaultTokenFiles(ctx) 70 githubToken, githubTokenErr := loadEnv("GITHUB_TOKEN", ctx.Config.EnvFiles.GitHubToken) 71 gitlabToken, gitlabTokenErr := loadEnv("GITLAB_TOKEN", ctx.Config.EnvFiles.GitLabToken) 72 giteaToken, giteaTokenErr := loadEnv("GITEA_TOKEN", ctx.Config.EnvFiles.GiteaToken) 73 74 forceToken := ctx.Config.ForceToken 75 if forceToken == "" { 76 forceToken = os.Getenv("GORELEASER_FORCE_TOKEN") 77 } 78 switch strings.ToLower(forceToken) { 79 case "github": 80 gitlabToken = "" 81 giteaToken = "" 82 case "gitlab": 83 githubToken = "" 84 giteaToken = "" 85 case "gitea": 86 githubToken = "" 87 gitlabToken = "" 88 default: 89 var tokens []string 90 if githubToken != "" { 91 tokens = append(tokens, "GITHUB_TOKEN") 92 } 93 if gitlabToken != "" { 94 tokens = append(tokens, "GITLAB_TOKEN") 95 } 96 if giteaToken != "" { 97 tokens = append(tokens, "GITEA_TOKEN") 98 } 99 if len(tokens) > 1 { 100 return ErrMultipleTokens{tokens} 101 } 102 } 103 104 noTokens := githubToken == "" && gitlabToken == "" && giteaToken == "" 105 noTokenErrs := githubTokenErr == nil && gitlabTokenErr == nil && giteaTokenErr == nil 106 107 if err := checkErrors(ctx, noTokens, noTokenErrs, gitlabTokenErr, githubTokenErr, giteaTokenErr); err != nil { 108 return err 109 } 110 111 if gitlabToken != "" { 112 log.Debug("token type: gitlab") 113 ctx.TokenType = context.TokenTypeGitLab 114 ctx.Token = gitlabToken 115 } 116 117 if giteaToken != "" { 118 log.Debug("token type: gitea") 119 ctx.TokenType = context.TokenTypeGitea 120 ctx.Token = giteaToken 121 } 122 123 if githubToken != "" { 124 log.Debug("token type: github") 125 ctx.Token = githubToken 126 } 127 128 if ctx.TokenType == "" { 129 ctx.TokenType = context.TokenTypeGitHub 130 } 131 132 return nil 133 } 134 135 func checkErrors(ctx *context.Context, noTokens, noTokenErrs bool, gitlabTokenErr, githubTokenErr, giteaTokenErr error) error { 136 if ctx.SkipTokenCheck || skips.Any(ctx, skips.Publish) { 137 return nil 138 } 139 if b, err := tmpl.New(ctx).Bool(ctx.Config.Release.Disable); err != nil || b { 140 return err 141 } 142 143 if noTokens && noTokenErrs { 144 return ErrMissingToken 145 } 146 147 if gitlabTokenErr != nil { 148 return fmt.Errorf("failed to load gitlab token: %w", gitlabTokenErr) 149 } 150 151 if githubTokenErr != nil { 152 return fmt.Errorf("failed to load github token: %w", githubTokenErr) 153 } 154 155 if giteaTokenErr != nil { 156 return fmt.Errorf("failed to load gitea token: %w", giteaTokenErr) 157 } 158 return nil 159 } 160 161 func loadEnv(env, path string) (string, error) { 162 val := os.Getenv(env) 163 if val != "" { 164 log.Infof("using token from %s", logext.Keyword("$"+env)) 165 return val, nil 166 } 167 path, err := homedir.Expand(path) 168 if err != nil { 169 return "", err 170 } 171 f, err := os.Open(path) // #nosec 172 if errors.Is(err, fs.ErrNotExist) { 173 return "", nil 174 } 175 if err != nil { 176 return "", err 177 } 178 defer f.Close() 179 log.Infof("using token from %s", logext.Keyword(path)) 180 bts, _, err := bufio.NewReader(f).ReadLine() 181 return string(bts), err 182 }