Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

daemon(deployment): integrate slack config #661

Merged
merged 3 commits into from
Mar 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -207,13 +207,13 @@ docker-deps:
## mocks: generate Go mocks
.PHONY: mocks
mocks:
counterfeiter -o ./client/runner/mocks/session.go \
go run github.com/maxbrunsfeld/counterfeiter/v6 -o ./client/runner/mocks/session.go \
./client/runner/ssh.go SSHSession
counterfeiter -o ./daemon/inertiad/project/mocks/deployer.go \
go run github.com/maxbrunsfeld/counterfeiter/v6 -o ./daemon/inertiad/project/mocks/deployer.go \
./daemon/inertiad/project/deployment.go Deployer
counterfeiter -o ./daemon/inertiad/build/mocks/builder.go \
go run github.com/maxbrunsfeld/counterfeiter/v6 -o ./daemon/inertiad/build/mocks/builder.go \
./daemon/inertiad/build/builder.go ContainerBuilder
counterfeiter -o ./daemon/inertiad/notify/mocks/notify.go \
go run github.com/maxbrunsfeld/counterfeiter/v6 -o ./daemon/inertiad/notify/mocks/notify.go \
./daemon/inertiad/notify/notifier.go Notifier

## scripts: recompile script assets
Expand Down
1 change: 1 addition & 0 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type UpRequest struct {
GitOptions GitOptions `json:"git_options"`
WebHookSecret string `json:"webhook_secret"`
IntermediaryContainers []string `json:"intermediary_containers"`
SlackNotificationURL string `json:"slack_notification_url"`
}

// GitOptions represents GitHub-related deployment options
Expand Down
12 changes: 9 additions & 3 deletions cfg/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ type Project struct {

// Profile denotes a deployment configuration
type Profile struct {
Name string `toml:"name"`
Branch string `toml:"branch"`
Build *Build `toml:"build"`
Name string `toml:"name"`
Branch string `toml:"branch"`
Build *Build `toml:"build"`
Notifiers *Notifiers `toml:"notifiers"`
}

// Identifier implements identity.Identifier
Expand Down Expand Up @@ -104,3 +105,8 @@ func (p *Project) RemoveProfile(name string) bool {
p.Profiles = asProfiles(ids)
return ok
}

// Notifiers defines options for notifications on a profile
type Notifiers struct {
SlackNotificationURL string `toml:"slack_notification_url"`
}
6 changes: 6 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ type UpRequest struct {
// Up brings the project up on the remote VPS instance specified
// in the deployment object.
func (c *Client) Up(ctx context.Context, req UpRequest) error {
notif := req.Profile.Notifiers
if notif == nil {
notif = &cfg.Notifiers{}
}

resp, err := c.post(ctx, "/up", &api.UpRequest{
Stream: false,
Project: req.Project,
Expand All @@ -103,6 +108,7 @@ func (c *Client) Up(ctx context.Context, req UpRequest) error {
Branch: req.Profile.Branch,
},
IntermediaryContainers: req.Profile.Build.IntermediaryContainers,
SlackNotificationURL: notif.SlackNotificationURL,
})
if err != nil {
return fmt.Errorf("failed to make request: %s", err.Error())
Expand Down
19 changes: 6 additions & 13 deletions daemon/inertiad/daemon/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ func (s *Server) upHandler(w http.ResponseWriter, r *http.Request) {
if upReq.WebHookSecret != "" {
s.state.WebhookSecret = upReq.WebHookSecret
}
s.deployment.SetConfig(project.DeploymentConfig{
conf := project.DeploymentConfig{
ProjectName: upReq.Project,
BuildType: upReq.BuildType,
BuildFilePath: upReq.BuildFilePath,
RemoteURL: gitOpts.RemoteURL,
Branch: gitOpts.Branch,
PemFilePath: crypto.DaemonGithubKeyLocation,
IntermediaryContainers: upReq.IntermediaryContainers,
})
SlackNotificationURL: upReq.SlackNotificationURL,
}
s.deployment.SetConfig(conf)

// Configure streamer
var stream = log.NewStreamer(log.StreamerOptions{
Expand All @@ -55,17 +58,7 @@ func (s *Server) upHandler(w http.ResponseWriter, r *http.Request) {
var skipUpdate = false
if status, _ := s.deployment.GetStatus(s.docker); status.CommitHash == "" {
stream.Println("No deployment detected")
if err = s.deployment.Initialize(
project.DeploymentConfig{
ProjectName: upReq.Project,
BuildType: upReq.BuildType,
BuildFilePath: upReq.BuildFilePath,
RemoteURL: gitOpts.RemoteURL,
Branch: gitOpts.Branch,
PemFilePath: crypto.DaemonGithubKeyLocation,
},
stream,
); err != nil {
if err = s.deployment.Initialize(conf, stream); err != nil {
stream.Error(res.Err(err.Error(), http.StatusPreconditionFailed))
return
}
Expand Down
73 changes: 73 additions & 0 deletions daemon/inertiad/notify/mocks/notify.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions daemon/inertiad/notify/notifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,20 @@ func (n Notifiers) Notify(msg string, opts Options) error {
return errs
}

// Exists checks if the given notifier is already configured
func (n Notifiers) Exists(nt Notifier) bool {
for _, notif := range n {
if notif.IsEqual(nt) {
return true
}
}
return false
}

// Notifier manages notifications
type Notifier interface {
Notify(string, Options) error
IsEqual(Notifier) bool
}

// Options is used to configure formatting of notifications
Expand Down
26 changes: 26 additions & 0 deletions daemon/inertiad/notify/notifier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package notify

import "testing"

func TestNotifiers_Exists(t *testing.T) {
type args struct {
nt Notifier
}
tests := []struct {
name string
n Notifiers
args args
want bool
}{
{"ok: exists", Notifiers{&SlackNotifier{"abcde"}}, args{&SlackNotifier{"abcde"}}, true},
{"not ok: no notifiers", Notifiers{}, args{&SlackNotifier{"abcde"}}, false},
{"not ok: doesnt exist", Notifiers{&SlackNotifier{"robert"}}, args{&SlackNotifier{"abcde"}}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.n.Exists(tt.args.nt); got != tt.want {
t.Errorf("Notifiers.Exists() = %v, want %v", got, tt.want)
}
})
}
}
11 changes: 11 additions & 0 deletions daemon/inertiad/notify/slack.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ func (n *SlackNotifier) Notify(text string, options Options) error {
return nil
}

// IsEqual implements Notifier by checking the provided notifier is a slack notifier
// and if it has the same hook URL
func (n *SlackNotifier) IsEqual(nt Notifier) bool {
switch v := nt.(type) {
case *SlackNotifier:
return n.hookURL == v.hookURL
default:
return false
}
}

func colorToString(color Color) string {
return string(color)
}
32 changes: 32 additions & 0 deletions daemon/inertiad/notify/slack_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package notify

import "testing"

func TestSlackNotifier_IsEqual(t *testing.T) {
type fields struct {
hookURL string
}
type args struct {
nt Notifier
}
tests := []struct {
name string
fields fields
args args
want bool
}{
{"ok: same hook url", fields{"abcde"}, args{&SlackNotifier{"abcde"}}, true},
{"not ok: diff hook url", fields{"robert"}, args{&SlackNotifier{"abcde"}}, false},
{"not ok: not slack notifier", fields{"robert"}, args{nil}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
n := &SlackNotifier{
hookURL: tt.fields.hookURL,
}
if got := n.IsEqual(tt.args.nt); got != tt.want {
t.Errorf("SlackNotifier.IsEqual() = %v, want %v", got, tt.want)
}
})
}
}
16 changes: 14 additions & 2 deletions daemon/inertiad/project/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ type DeploymentConfig struct {
Branch string
PemFilePath string
IntermediaryContainers []string

// TODO: maybe improve format for generic notifiers
SlackNotificationURL string
}

// DeploymentMetadata is used to store metadata relevant
Expand Down Expand Up @@ -166,7 +169,16 @@ func (d *Deployment) SetConfig(cfg DeploymentConfig) {
}
d.intermediaryContainers = cfg.IntermediaryContainers

// TODO: register notifiers
// register notifiers
if len(d.notifiers) == 0 {
d.notifiers = notify.Notifiers{}
}
if cfg.SlackNotificationURL != "" {
nt := notify.NewSlackNotifier(cfg.SlackNotificationURL)
if !d.notifiers.Exists(nt) {
d.notifiers = append(d.notifiers, nt)
}
}
}

// DeployOptions is used to configure how the deployment handles the deploy
Expand Down Expand Up @@ -215,7 +227,7 @@ func (d *Deployment) Deploy(
// Build project
deploy, err := d.builder.Build(strings.ToLower(d.buildType), *conf, cli, out)
if err != nil {
if notifyErr := d.notifiers.Notify("Build error", notify.Options{
if notifyErr := d.notifiers.Notify(fmt.Sprintf("Build error: %s", err), notify.Options{
Color: notify.Red,
}); notifyErr != nil {
fmt.Fprintln(out, notifyErr.Error())
Expand Down
10 changes: 6 additions & 4 deletions daemon/inertiad/project/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ func newDefaultFakeBuilder(builder func() error, stopper func() error) *mocks.Fa
func TestSetConfig(t *testing.T) {
deployment := &Deployment{}
deployment.SetConfig(DeploymentConfig{
ProjectName: "wow",
Branch: "amazing",
BuildType: "best",
BuildFilePath: "/robertcompose.yml",
ProjectName: "wow",
Branch: "amazing",
BuildType: "best",
BuildFilePath: "/robertcompose.yml",
SlackNotificationURL: "https://my.slack.url",
})

assert.Equal(t, "wow", deployment.project)
assert.Equal(t, "amazing", deployment.branch)
assert.Equal(t, "best", deployment.buildType)
assert.Equal(t, "/robertcompose.yml", deployment.buildFilePath)
assert.Len(t, deployment.notifiers, 1)
}

func TestDeployMock(t *testing.T) {
Expand Down