From b1a1505908e232a6c63ffe2736c0b3bee663ddb4 Mon Sep 17 00:00:00 2001 From: Kayla McKay <39921134+kaymckay@users.noreply.github.com> Date: Mon, 21 Mar 2022 09:37:07 -0500 Subject: [PATCH] enhancement: Add ability to attach files to email (#6) * add attachment to email code & tests * clean * switch test image Co-authored-by: David May <1301201+wass3r@users.noreply.github.com> --- DOCS.md | 6 ++ cmd/vela-email/main.go | 23 +++-- cmd/vela-email/plugin.go | 30 +++++-- cmd/vela-email/plugin_test.go | 121 ++++++++++++++++++++------- cmd/vela-email/testdata/example1.txt | 2 + cmd/vela-email/testdata/vela.png | Bin 0 -> 27120 bytes 6 files changed, 139 insertions(+), 43 deletions(-) create mode 100644 cmd/vela-email/testdata/vela.png diff --git a/DOCS.md b/DOCS.md index cedf995..4795dde 100644 --- a/DOCS.md +++ b/DOCS.md @@ -221,6 +221,12 @@ The following parameters are used to configure the image: ### Attachment +| Parameter | Description | Required | Default | Environment Variables | +| ------------ | ------------------------------ | -------- | ------- | -------------------------------------------- | +| `attachment` | file will be attached to email | false | N/A | `PARAMETER_ATTACHMENT`
`EMAIL_ATTACHMENT` | + +### Email Filename + | Parameter | Description | Required | Default | Environment Variables | | ---------- | --------------------------------------------------------- | -------- | ------- | ---------------------------------------- | | `filename` | data in attached file will be used to populate the email. | false | N/A | `PARAMETER_FILENAME`
`EMAIL_FILENAME` | diff --git a/cmd/vela-email/main.go b/cmd/vela-email/main.go index 2251f17..933409e 100644 --- a/cmd/vela-email/main.go +++ b/cmd/vela-email/main.go @@ -104,6 +104,12 @@ func main() { Name: "readreceipt", Usage: "request read receipts and delivery notifications", }, + // Attachment flag + &cli.StringFlag{ + EnvVars: []string{"PARAMETER_ATTACHMENT", "EMAIL_ATTACHMENT"}, + Name: "attachment", + Usage: "file to attach to email", + }, // SmtpHost flags &cli.StringFlag{ EnvVars: []string{"PARAMETER_HOST", "EMAIL_HOST"}, @@ -129,11 +135,11 @@ func main() { Name: "password", Usage: "smtp host password", }, - // Attachment flag + // EmailFilename flag &cli.StringFlag{ EnvVars: []string{"PARAMETER_FILENAME", "EMAIL_FILENAME"}, Name: "filename", - Usage: "file to attach to email", + Usage: "file that contains email information (To, From, Subject, etc.)", }, // TLSConfig flag &cli.BoolFlag{ @@ -229,11 +235,6 @@ func run(c *cli.Context) error { // auth configuration Auth: c.String("auth"), - // attachment configuration - Attachment: &email.Attachment{ - Filename: c.String("filename"), - }, - // email configuration Email: &email.Email{ ReplyTo: c.StringSlice("replyto"), @@ -248,6 +249,14 @@ func run(c *cli.Context) error { ReadReceipt: c.StringSlice("readreceipt"), }, + // email filename configuration + EmailFilename: c.String("filename"), + + // attachment configuration + Attachment: &email.Attachment{ + Filename: c.String("attachment"), + }, + // smtp configuration SMTPHost: &SMTPHost{ Host: c.String("host"), diff --git a/cmd/vela-email/plugin.go b/cmd/vela-email/plugin.go index d4640e6..c00f77c 100644 --- a/cmd/vela-email/plugin.go +++ b/cmd/vela-email/plugin.go @@ -26,8 +26,8 @@ var ( // ErrorMissingEmailFromParam is returned when the plugin is missing the From email parameter. ErrorMissingEmailFromParam = errors.New("missing email parameter: From") - // ErrorEmptyAttach is returned when the plugin finds the provided attachment to be empty. - ErrorEmptyAttach = errors.New("attachment provided is empty") + // ErrorEmptyFile is returned when the plugin finds the provided attachment to be empty. + ErrorEmptyFile = errors.New("file provided is empty") // ErrorMissingSMTPParam is returned when the plugin is missing a smtp host or port parameter. ErrorMissingSMTPParam = errors.New("missing smtp parameter (host/port)") @@ -38,6 +38,8 @@ type ( Plugin struct { // Email arguments loaded for the plugin Email *email.Email + // EmailFilename arguments loaded for the plugin + EmailFilename string // Attachment arguments loaded for the plugin Attachment *email.Attachment // SmtpHost arguments loaded for the plugin @@ -78,17 +80,17 @@ func (p *Plugin) Validate() error { logrus.Info("Validating Parameters...") - if len(p.Attachment.Filename) != 0 { - fileInfo, err := os.Stat(p.Attachment.Filename) + if len(p.EmailFilename) != 0 { + fileInfo, err := os.Stat(p.EmailFilename) if errors.Is(err, os.ErrNotExist) { return os.ErrNotExist } if fileInfo.Size() == 0 { - return ErrorEmptyAttach + return ErrorEmptyFile } - file, err := os.Open(p.Attachment.Filename) + file, err := os.Open(p.EmailFilename) if err != nil { return err } @@ -119,6 +121,22 @@ func (p *Plugin) Validate() error { return ErrorMissingEmailFromParam } + if len(p.Attachment.Filename) != 0 { + fileInfo, err := os.Stat(p.Attachment.Filename) + if errors.Is(err, os.ErrNotExist) { + return os.ErrNotExist + } + + if fileInfo.Size() == 0 { + return ErrorEmptyFile + } + + p.Attachment, err = p.Email.AttachFile(p.Attachment.Filename) + if err != nil { + return err + } + } + if len(p.SMTPHost.Host) == 0 || len(p.SMTPHost.Port) == 0 { return ErrorMissingSMTPParam } diff --git a/cmd/vela-email/plugin_test.go b/cmd/vela-email/plugin_test.go index 3d92764..af1ef1d 100644 --- a/cmd/vela-email/plugin_test.go +++ b/cmd/vela-email/plugin_test.go @@ -26,6 +26,7 @@ var ( Username: "username", Password: "password", } + noAttachment = &email.Attachment{ Filename: "", } @@ -38,10 +39,11 @@ var ( } mockPlugin = &Plugin{ - Email: mockEmail, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, - BuildEnv: mockBuildEnv, + Email: mockEmail, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, + BuildEnv: mockBuildEnv, } ) @@ -68,9 +70,10 @@ func TestValidateSuccess(t *testing.T) { { name: "return no errors: single To email", parameters: Plugin{ - Email: mockEmail, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, + Email: mockEmail, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, }, }, { @@ -80,8 +83,9 @@ func TestValidateSuccess(t *testing.T) { To: []string{"fakemail1@example.com", "fakemail2@example.com"}, From: "fakemail3@example.com", }, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, }, }, { @@ -91,6 +95,7 @@ func TestValidateSuccess(t *testing.T) { To: []string{"fakemail1@example.com", "fakemail2@example.com"}, From: "fakemail3@example.com", }, + EmailFilename: "", SMTPHost: &SMTPHost{ Host: "smtphost.com", Port: "587", @@ -113,8 +118,9 @@ func TestValidateSuccess(t *testing.T) { Sender: "sender", ReadReceipt: []string{"idk"}, }, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, }, }, { @@ -124,9 +130,32 @@ func TestValidateSuccess(t *testing.T) { To: []string{""}, From: "", }, - SMTPHost: mockSMTPHost, + EmailFilename: "testdata/example1.txt", + SMTPHost: mockSMTPHost, Attachment: &email.Attachment{ - Filename: "testdata/example1.txt", + Filename: "", + }, + }, + }, + { + name: "return no errors: add txt attachment to email", + parameters: Plugin{ + Email: mockEmail, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: &email.Attachment{ + Filename: "", + }, + }, + }, + { + name: "return no errors: add png image attachment to email", + parameters: Plugin{ + Email: mockEmail, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: &email.Attachment{ + Filename: "testdata/vela.png", }, }, }, @@ -153,7 +182,8 @@ func TestValidateErrors(t *testing.T) { Email: &email.Email{ From: "fakemail@example.com", }, - Attachment: noAttachment, + EmailFilename: "", + Attachment: noAttachment, }, wantErr: ErrorMissingEmailToParam, }, @@ -163,27 +193,51 @@ func TestValidateErrors(t *testing.T) { Email: &email.Email{ To: []string{"fakemail@example.com"}, }, - Attachment: noAttachment, + EmailFilename: "", + Attachment: noAttachment, }, wantErr: ErrorMissingEmailFromParam, }, { - name: "Email parameters missing from attachment", + name: "Email parameters missing from file", parameters: Plugin{ Email: &email.Email{ To: []string{""}, From: "", }, - SMTPHost: mockSMTPHost, + EmailFilename: "testdata/badattachment.txt", + SMTPHost: mockSMTPHost, Attachment: &email.Attachment{ - Filename: "testdata/badattachment.txt", + Filename: "", }, }, wantErr: io.EOF, }, + { + name: "Email file missing", + parameters: Plugin{ + EmailFilename: "testdata/doesnotexist.txt", + Attachment: &email.Attachment{ + Filename: "", + }, + }, + wantErr: os.ErrNotExist, + }, + { + name: "Email file empty", + parameters: Plugin{ + EmailFilename: "testdata/empty.txt", + Attachment: &email.Attachment{ + Filename: "", + }, + }, + wantErr: ErrorEmptyFile, + }, { name: "Email attachment missing", parameters: Plugin{ + Email: mockEmail, + EmailFilename: "", Attachment: &email.Attachment{ Filename: "testdata/doesnotexist.txt", }, @@ -193,16 +247,19 @@ func TestValidateErrors(t *testing.T) { { name: "Email attachment empty", parameters: Plugin{ + Email: mockEmail, + EmailFilename: "", Attachment: &email.Attachment{ Filename: "testdata/empty.txt", }, }, - wantErr: ErrorEmptyAttach, + wantErr: ErrorEmptyFile, }, { name: "SMTP host missing", parameters: Plugin{ - Email: mockEmail, + Email: mockEmail, + EmailFilename: "", SMTPHost: &SMTPHost{ Port: "1902", }, @@ -213,7 +270,8 @@ func TestValidateErrors(t *testing.T) { { name: "SMTP port missing", parameters: Plugin{ - Email: mockEmail, + Email: mockEmail, + EmailFilename: "", SMTPHost: &SMTPHost{ Host: "smtphost.com", }, @@ -252,9 +310,10 @@ func TestInjectEnvSuccess(t *testing.T) { Subject: DefaultSubject, Text: []byte("This is some text for repo: {{ .VELA_REPO_FULL_NAME }}"), }, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, - BuildEnv: mockBuildEnv, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, + BuildEnv: mockBuildEnv, }, }, { @@ -266,9 +325,10 @@ func TestInjectEnvSuccess(t *testing.T) { Subject: "Commit failure on vela build: {{ .VELA_BUILD_NUMBER }}", Text: []byte("This is some text for repo: {{ .VELA_REPO_FULL_NAME }}"), }, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, - BuildEnv: mockBuildEnv, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, + BuildEnv: mockBuildEnv, }, }, } @@ -319,9 +379,10 @@ func TestInjectEnvBadVar(t *testing.T) { From: "fakemail3@example.com", Subject: "This is a bad subject {{ .SOME_OTHER_VARIABLE }}", }, - SMTPHost: mockSMTPHost, - Attachment: noAttachment, - BuildEnv: mockBuildEnv, + EmailFilename: "", + SMTPHost: mockSMTPHost, + Attachment: noAttachment, + BuildEnv: mockBuildEnv, }, }, } diff --git a/cmd/vela-email/testdata/example1.txt b/cmd/vela-email/testdata/example1.txt index 917b47a..611d575 100644 --- a/cmd/vela-email/testdata/example1.txt +++ b/cmd/vela-email/testdata/example1.txt @@ -1,5 +1,7 @@ From: vela-noreply@fakemail.com To: fakemail1@example.com, fakemail2@example.com +Bcc: fakemail@example.com +Cc: fakemail@example.com Subject: Vela Pipeline for {{ .VELA_REPO_FULL_NAME }} {{ .VELA_BUILD_BRANCH }} Content-Type: text/plain diff --git a/cmd/vela-email/testdata/vela.png b/cmd/vela-email/testdata/vela.png new file mode 100644 index 0000000000000000000000000000000000000000..179db41bed51f38c7801798839b0d82633aedd9b GIT binary patch literal 27120 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 z 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 S3EaZRkds!r|3T8o@BaY<%rLD0 literal 0 HcmV?d00001