From 5143f8e50795b4d30547f072b4c93a73dff858c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Lemeunier?= Date: Wed, 27 Dec 2017 16:50:16 +0100 Subject: [PATCH 1/3] First implementation of misc in hooks. --- commands/deploy.go | 36 ++++++++++++++++++++++++++++++++++-- commands/diff.go | 19 +++---------------- deployers/deployer.go | 29 +++++++++++++++++++++++++++++ hooks/exec_command.go | 4 ++-- hooks/hooks.go | 12 ++++++++++-- hooks/newrelic.go | 17 +++++++++++------ hooks/slack.go | 24 ++++++++++++++++++++---- 7 files changed, 109 insertions(+), 32 deletions(-) diff --git a/commands/deploy.go b/commands/deploy.go index 549adc7..6845bb0 100644 --- a/commands/deploy.go +++ b/commands/deploy.go @@ -10,6 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/remyLemeunier/contactkey/context" "github.com/remyLemeunier/contactkey/deployers" + "github.com/remyLemeunier/contactkey/hooks" "github.com/remyLemeunier/contactkey/utils" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -122,9 +123,18 @@ func (d *Deploy) execute() error { return errors.New(fmt.Sprintf("Version %q is already deployed.", sha1ToDeploy)) } + misc := d.getDiff(sha1ToDeploy) + hookinformation := hooks.HookInformation{ + userName, + d.Env, + d.Service, + podVersion, + misc, + } + log.Println(fmt.Sprintf("Going to deploy pod version %q \n", podVersion)) for _, hook := range d.Context.Hooks { - err = hook.PreDeployment(userName, d.Env, d.Service, podVersion) + err = hook.PreDeployment(hookinformation) if hook.StopOnError() == true && err != nil { return errors.New(fmt.Sprintf("Predeployment failed: %q", err)) } else if err != nil { @@ -146,7 +156,7 @@ func (d *Deploy) execute() error { } for _, hook := range d.Context.Hooks { - err = hook.PostDeployment(userName, d.Env, d.Service, podVersion) + err = hook.PostDeployment(hookinformation) if err != nil { log.Debugln(fmt.Sprintf("PostDeployment failed: %q", err)) } @@ -168,3 +178,25 @@ func (d *Deploy) fill(context *context.Context, service string, env string) { d.Context = context d.Writer = os.Stdout } + +func (d *Deploy) getDiff(sha1ToDeploy string) []string { + var diff []string + uniqueVersions, err := deployers.ListUniqueVcsVersions(d.Context.Deployer, d.Env) + if err != nil { + log.Debugln("Impossible to retrieve unique vcs version: %q", err.Error()) + } + + for _, uniqueVersion := range uniqueVersions { + changes, err := d.Context.Vcs.Diff(uniqueVersion, sha1ToDeploy) + if err != nil { + log.Debugln("Error during diff: %q", err.Error()) + } + + for _, change := range changes.Commits { + displayString := change.AuthorFullName + ":" + change.DisplayId + diff = append(diff, displayString) + } + } + + return diff +} diff --git a/commands/diff.go b/commands/diff.go index 2c6ddaf..159ceae 100644 --- a/commands/diff.go +++ b/commands/diff.go @@ -8,6 +8,7 @@ import ( "github.com/olekukonko/tablewriter" "github.com/remyLemeunier/contactkey/context" + "github.com/remyLemeunier/contactkey/deployers" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -38,23 +39,9 @@ func (d Diff) execute() error { return errors.New(fmt.Sprintf("No sha1 found for service %q \n", d.Service)) } - versions, err := d.Context.Deployer.ListVcsVersions(d.Env) + uniqueVersions, err := deployers.ListUniqueVcsVersions(d.Context.Deployer, d.Env) if err != nil { - return errors.New(fmt.Sprintf("Failed to list versions with error %q \n", err)) - } - - if len(versions) == 0 { - return errors.New(fmt.Sprintf("No service (%q) versions found for the Env: %q \n", d.Service, d.Env)) - } - - // Retrieve only unique versions - encountered := map[string]bool{} - for v := range versions { - encountered[versions[v]] = true - } - uniqueVersions := []string{} - for key := range encountered { - uniqueVersions = append(uniqueVersions, key) + return err } for _, uniqueVersion := range uniqueVersions { diff --git a/deployers/deployer.go b/deployers/deployer.go index 571bd69..8db7eb5 100644 --- a/deployers/deployer.go +++ b/deployers/deployer.go @@ -1,5 +1,10 @@ package deployers +import ( + "errors" + "fmt" +) + type State struct { Step string Progress int @@ -18,3 +23,27 @@ type Deployer interface { ListVcsVersions(env string) ([]string, error) Deploy(env string, podVersion string, c chan State) error } + +func ListUniqueVcsVersions(d Deployer, env string) ([]string, error) { + uniqueVersions := []string{} + versions, err := d.ListVcsVersions(env) + if err != nil { + return uniqueVersions, errors.New(fmt.Sprintf("Failed to list versions with error %q \n", err)) + } + + if len(versions) == 0 { + return uniqueVersions, errors.New(fmt.Sprintf("No versions found for the Env: %q \n", env)) + } + + // Retrieve only unique versions + encountered := map[string]bool{} + for v := range versions { + encountered[versions[v]] = true + } + + for key := range encountered { + uniqueVersions = append(uniqueVersions, key) + } + + return uniqueVersions, nil +} diff --git a/hooks/exec_command.go b/hooks/exec_command.go index 7a7438a..8747013 100644 --- a/hooks/exec_command.go +++ b/hooks/exec_command.go @@ -29,11 +29,11 @@ func (e ExecCommand) Init() error { return executeCommands(e.OnInit) } -func (e ExecCommand) PreDeployment(username string, env string, service string, podVersion string) error { +func (e ExecCommand) PreDeployment(hookinformation HookInformation) error { return executeCommands(e.OnPreDeploy) } -func (e ExecCommand) PostDeployment(username string, env string, service string, podVersion string) error { +func (e ExecCommand) PostDeployment(hookinformation HookInformation) error { return executeCommands(e.OnPostDeploy) } diff --git a/hooks/hooks.go b/hooks/hooks.go index 220a4d8..7b70fae 100644 --- a/hooks/hooks.go +++ b/hooks/hooks.go @@ -1,8 +1,16 @@ package hooks +type HookInformation struct { + UserName string + Env string + Service string + PodVersion string + Miscellaneous []string +} + type Hooks interface { Init() error - PreDeployment(userName string, env string, service string, podVersion string) error - PostDeployment(userName string, env string, service string, podVersion string) error + PreDeployment(hookinformation HookInformation) error + PostDeployment(hookinformation HookInformation) error StopOnError() bool } diff --git a/hooks/newrelic.go b/hooks/newrelic.go index 832e7c6..d092189 100644 --- a/hooks/newrelic.go +++ b/hooks/newrelic.go @@ -42,14 +42,14 @@ func (c NewRelicClient) Init() error { return nil } -func (c NewRelicClient) PreDeployment(userName string, env string, service string, podVersion string) error { +func (c NewRelicClient) PreDeployment(hookinformation HookInformation) error { var filter bytes.Buffer filterTmpl, err := template.New("filter").Parse(c.ApplicationFilter) if err != nil { return err } - if err := filterTmpl.Execute(&filter, struct{ env string }{env}); err != nil { + if err := filterTmpl.Execute(&filter, struct{ env string }{hookinformation.Env}); err != nil { } appId, err := c.findApplicationId(filter.String()) @@ -58,16 +58,21 @@ func (c NewRelicClient) PreDeployment(userName string, env string, service strin } c.ApplicationId = appId - description := fmt.Sprintf("Deploying %s %s on %s", service, podVersion, env) + var changelog string + for _, line := range hookinformation.Miscellaneous { + changelog = changelog + " " + line + "\n" + } + description := fmt.Sprintf("Deploying %s %s on %s", hookinformation.Service, hookinformation.PodVersion, hookinformation.Env) d := &NewRelicDeployment{ description: description, - revision: podVersion, - user: userName, + revision: hookinformation.PodVersion, + user: hookinformation.UserName, + changelog: changelog, } return c.CreateDeployment(d) } -func (c NewRelicClient) PostDeployment(userName string, env string, service string, podVersion string) error { +func (c NewRelicClient) PostDeployment(hookinformation HookInformation) error { return nil } diff --git a/hooks/slack.go b/hooks/slack.go index 6256e16..3b89851 100644 --- a/hooks/slack.go +++ b/hooks/slack.go @@ -43,12 +43,28 @@ func (s Slack) Init() error { } // @TODO Later we could pass directly messages and use the go templater instead. -func (s Slack) PreDeployment(username string, env string, service string, podVersion string) error { - return s.postMessage(fmt.Sprintf("[%q]Start, update service %q version %q %q", env, service, podVersion, username)) +func (s Slack) PreDeployment(hookinformation HookInformation) error { + return s.postMessage( + fmt.Sprintf( + "[%q]Start, update service %q version %q %q", + hookinformation.Env, + hookinformation.Service, + hookinformation.PodVersion, + hookinformation.UserName, + ), + ) } -func (s Slack) PostDeployment(username string, env string, service string, podVersion string) error { - return s.postMessage(fmt.Sprintf("[%q]End, update service %q version %q by %q", env, service, podVersion, username)) +func (s Slack) PostDeployment(hookinformation HookInformation) error { + return s.postMessage( + fmt.Sprintf( + "[%q]End, update service %q version %q by %q", + hookinformation.Env, + hookinformation.Service, + hookinformation.PodVersion, + hookinformation.UserName, + ), + ) } func (s Slack) postMessage(message string) error { From f44b83e731c72315f7da8a37cf5d686fdebd36db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Lemeunier?= Date: Wed, 27 Dec 2017 17:17:30 +0100 Subject: [PATCH 2/3] Test added for ListUniqueVcsVersions --- deployers/deployer_test.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/deployers/deployer_test.go b/deployers/deployer_test.go index e15e532..9d4802e 100644 --- a/deployers/deployer_test.go +++ b/deployers/deployer_test.go @@ -6,3 +6,28 @@ import ( func TestDeployerRegistry(t *testing.T) { } + +func TestListUniqueVcsVersions(t *testing.T) { + envs := make(map[string]string) + envs["staging"] = "staging" + execCommand = mockggn + d := DeployerGgn{ + Service: "webhooks", + Pod: "pod-webhooks", + Environments: envs, + VcsRegexp: "-(.+)", + } + + uniqueVersions, err := ListUniqueVcsVersions(&d, "staging") + if err != nil { + t.Fatalf("Error trying to retrieve unique version: %q", err) + } + + if len(uniqueVersions) != 1 { + t.Fatalf("uniqueVersions len should be 1 instead got %s", len(uniqueVersions)) + } + + if uniqueVersions[0] != "1" { + t.Error("uniqueVersion should \"1\" instead got %s", uniqueVersions[0]) + } +} From 5bc936358415163b608eecac81f75bc75b75f7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Lemeunier?= Date: Wed, 27 Dec 2017 17:32:29 +0100 Subject: [PATCH 3/3] test added for getDiff --- commands/commands_test.go | 8 +++++++- commands/deploy_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/commands/commands_test.go b/commands/commands_test.go index c5cd10a..65a40b4 100644 --- a/commands/commands_test.go +++ b/commands/commands_test.go @@ -41,7 +41,13 @@ func (v SourcesMock) RetrieveSha1ForProject(branch string) (string, error) { } func (v SourcesMock) Diff(deployedSha1 string, sha1ToDeploy string) (*services.Changes, error) { - return &services.Changes{}, nil + var commits = []services.Commits{} + commits = append(commits, services.Commits{DisplayId: "DisplayId1", AuthorFullName: "AuthorFullName1", AuthorSlug: "AuthorSlug1", Title: "Title1"}) + commits = append(commits, services.Commits{DisplayId: "DisplayId2", AuthorFullName: "AuthorFullName2", AuthorSlug: "AuthorSlug2", Title: "Title2"}) + + return &services.Changes{ + Commits: commits, + }, nil } type BinariesMock struct{} diff --git a/commands/deploy_test.go b/commands/deploy_test.go index 98d2835..0ea8dca 100644 --- a/commands/deploy_test.go +++ b/commands/deploy_test.go @@ -56,3 +56,33 @@ func TestUpdateSlow(t *testing.T) { } ggnCmd.Wait() } + +func TestGetDiff(t *testing.T) { + // Catch stdout + out := new(bytes.Buffer) + writer := io.Writer(out) + log.SetOutput(writer) + + d := &Deploy{ + Context: &context.Context{ + Deployer: &DeployerMockGgn{}, + Vcs: &SourcesMock{}, + Binaries: &BinariesMock{}, + Metrics: utils.NewBlackholeMetricsRegistry(), + }, + Writer: out, + } + + diff := d.getDiff("abcde") + if len(diff) != 2 { + t.Fatalf("diff len should be 2 insead got %s", len(diff)) + } + + if diff[0] != "AuthorFullName1:DisplayId1" { + t.Errorf("Error found %s", diff[0]) + } + + if diff[1] != "AuthorFullName2:DisplayId2" { + t.Errorf("Error found %s", diff[1]) + } +}