diff --git a/internal/pipe/smtp/smtp.go b/internal/pipe/smtp/smtp.go index fb74e25da..b9cb20c8a 100644 --- a/internal/pipe/smtp/smtp.go +++ b/internal/pipe/smtp/smtp.go @@ -7,6 +7,7 @@ import ( "github.com/caarlos0/env/v7" "github.com/caarlos0/log" "github.com/goreleaser/goreleaser/internal/tmpl" + "github.com/goreleaser/goreleaser/pkg/config" "github.com/goreleaser/goreleaser/pkg/context" gomail "gopkg.in/mail.v2" ) @@ -22,9 +23,9 @@ func (Pipe) String() string { return "smtp" } func (Pipe) Skip(ctx *context.Context) bool { return !ctx.Config.Announce.SMTP.Enabled } type Config struct { - Host string `env:"SMTP_HOST,notEmpty"` - Port int `env:"SMTP_PORT,notEmpty"` - Username string `env:"SMTP_USERNAME,notEmpty"` + Host string `env:"SMTP_HOST"` + Port int `env:"SMTP_PORT"` + Username string `env:"SMTP_USERNAME"` Password string `env:"SMTP_PASSWORD,notEmpty"` } @@ -66,9 +67,9 @@ func (Pipe) Announce(ctx *context.Context) error { // Set E-Mail body. You can set plain text or html with text/html m.SetBody("text/plain", body) - var cfg Config - if err := env.Parse(&cfg); err != nil { - return fmt.Errorf("SMTP: %w", err) + cfg, err := getConfig(ctx.Config.Announce.SMTP) + if err != nil { + return err } // Settings for SMTP server @@ -87,3 +88,30 @@ func (Pipe) Announce(ctx *context.Context) error { return nil } + +var ( + errNoPort = fmt.Errorf("SMTP: missing smtp.port or $SMTP_PORT") + errNoUsername = fmt.Errorf("SMTP: missing smtp.username or $SMTP_USERNAME") + errNoHost = fmt.Errorf("SMTP: missing smtp.host or $SMTP_HOST") +) + +func getConfig(smtp config.SMTP) (Config, error) { + cfg := Config{ + Host: smtp.Host, + Port: smtp.Port, + Username: smtp.Username, + } + if err := env.Parse(&cfg); err != nil { + return cfg, fmt.Errorf("SMTP: %w", err) + } + if cfg.Username == "" { + return cfg, errNoUsername + } + if cfg.Host == "" { + return cfg, errNoHost + } + if cfg.Port == 0 { + return cfg, errNoPort + } + return cfg, nil +} diff --git a/internal/pipe/smtp/smtp_test.go b/internal/pipe/smtp/smtp_test.go index 010d9673c..8d541bddc 100644 --- a/internal/pipe/smtp/smtp_test.go +++ b/internal/pipe/smtp/smtp_test.go @@ -1,6 +1,7 @@ package smtp import ( + "strconv" "testing" "github.com/goreleaser/goreleaser/pkg/config" @@ -41,3 +42,91 @@ func TestDefault(t *testing.T) { require.Equal(t, defaultBodyTemplate, ctx.Config.Announce.SMTP.BodyTemplate) require.Equal(t, defaultSubjectTemplate, ctx.Config.Announce.SMTP.SubjectTemplate) } + +func TestGetConfig(t *testing.T) { + t.Run("from env", func(t *testing.T) { + expect := Config{ + Host: "hostname", + Port: 123, + Username: "user", + Password: "secret", + } + t.Setenv("SMTP_HOST", expect.Host) + t.Setenv("SMTP_USERNAME", expect.Username) + t.Setenv("SMTP_PASSWORD", expect.Password) + t.Setenv("SMTP_PORT", strconv.Itoa(expect.Port)) + cfg, err := getConfig(config.SMTP{}) + require.NoError(t, err) + require.Equal(t, expect, cfg) + }) + + t.Run("mixed", func(t *testing.T) { + expect := Config{ + Host: "hostname", + Port: 123, + Username: "user", + Password: "secret", + } + t.Setenv("SMTP_HOST", expect.Host) + t.Setenv("SMTP_PASSWORD", expect.Password) + cfg, err := getConfig(config.SMTP{ + Port: expect.Port, + Username: expect.Username, + }) + require.NoError(t, err) + require.Equal(t, expect, cfg) + }) + + t.Run("from conf", func(t *testing.T) { + expect := Config{ + Host: "hostname", + Port: 123, + Username: "user", + Password: "secret", + } + t.Setenv("SMTP_PASSWORD", expect.Password) + cfg, err := getConfig(config.SMTP{ + Host: expect.Host, + Port: expect.Port, + Username: expect.Username, + }) + require.NoError(t, err) + require.Equal(t, expect, cfg) + }) + + t.Run("no port", func(t *testing.T) { + t.Setenv("SMTP_HOST", "host") + t.Setenv("SMTP_PASSWORD", "pwd") + _, err := getConfig(config.SMTP{ + Username: "user", + }) + require.ErrorIs(t, err, errNoPort) + }) + + t.Run("no username", func(t *testing.T) { + t.Setenv("SMTP_HOST", "host") + t.Setenv("SMTP_PASSWORD", "pwd") + _, err := getConfig(config.SMTP{ + Port: 10, + }) + require.ErrorIs(t, err, errNoUsername) + }) + + t.Run("no host", func(t *testing.T) { + t.Setenv("SMTP_PASSWORD", "pwd") + _, err := getConfig(config.SMTP{ + Port: 10, + Username: "user", + }) + require.ErrorIs(t, err, errNoHost) + }) + + t.Run("no password", func(t *testing.T) { + _, err := getConfig(config.SMTP{ + Port: 10, + Username: "user", + Host: "host", + }) + require.EqualError(t, err, "SMTP: env: environment variable \"SMTP_PASSWORD\" should not be empty") + }) +} diff --git a/www/docs/customization/announce/smtp.md b/www/docs/customization/announce/smtp.md index af5470a4f..5a9f7e188 100644 --- a/www/docs/customization/announce/smtp.md +++ b/www/docs/customization/announce/smtp.md @@ -14,10 +14,12 @@ announce: # Defaults to false. enabled: true - # SMTP Host + # SMTP Host. + # Default from $SMTP_HOST. host: "smtp.gmail.com" # SMTP Port + # Default from $SMTP_PORT. port: 587 # Sender of the email @@ -29,6 +31,7 @@ announce: - "" # Owner of the email + # Default from $SMTP_USERNAME. username: "" # Body template to use within the email.