From 1d47ba8a3217ca32e7f85f8c70c5fd1ebb93049f Mon Sep 17 00:00:00 2001 From: Laszlo Fogas Date: Mon, 17 Jun 2019 10:48:40 +0200 Subject: [PATCH] Status line for each pipeline on Github --- remote/bitbucket/bitbucket.go | 2 +- remote/bitbucket/bitbucket_test.go | 2 +- remote/bitbucketserver/bitbucketserver.go | 2 +- remote/coding/coding.go | 2 +- remote/gerrit/gerrit.go | 2 +- remote/gitea/gitea.go | 2 +- remote/gitea/gitea_test.go | 6 +++--- remote/github/github.go | 19 +++++++++++++----- remote/gitlab/gitlab.go | 2 +- remote/gitlab3/gitlab.go | 2 +- remote/gogs/gogs.go | 2 +- remote/gogs/gogs_test.go | 2 +- remote/remote.go | 6 +++--- server/build.go | 24 ++++++++++++++--------- server/hook.go | 22 +++++++++++++-------- server/rpc.go | 22 ++++++++++++++++++--- 16 files changed, 78 insertions(+), 41 deletions(-) diff --git a/remote/bitbucket/bitbucket.go b/remote/bitbucket/bitbucket.go index 143d2aff1..6f2ff1841 100644 --- a/remote/bitbucket/bitbucket.go +++ b/remote/bitbucket/bitbucket.go @@ -214,7 +214,7 @@ func (c *config) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] } // Status creates a build status for the Bitbucket commit. -func (c *config) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *config) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { status := internal.BuildStatus{ State: convertStatus(b.Status), Desc: convertDesc(b.Status), diff --git a/remote/bitbucket/bitbucket_test.go b/remote/bitbucket/bitbucket_test.go index 3c9af60b2..854007c9e 100644 --- a/remote/bitbucket/bitbucket_test.go +++ b/remote/bitbucket/bitbucket_test.go @@ -283,7 +283,7 @@ func Test_bitbucket(t *testing.T) { }) g.It("Should update the status", func() { - err := c.Status(fakeUser, fakeRepo, fakeBuild, "http://127.0.0.1") + err := c.Status(fakeUser, fakeRepo, fakeBuild, "http://127.0.0.1", nil) g.Assert(err == nil).IsTrue() }) diff --git a/remote/bitbucketserver/bitbucketserver.go b/remote/bitbucketserver/bitbucketserver.go index 9e14a377a..e0b747327 100644 --- a/remote/bitbucketserver/bitbucketserver.go +++ b/remote/bitbucketserver/bitbucketserver.go @@ -184,7 +184,7 @@ func (c *Config) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] } // Status is not supported by the bitbucketserver driver. -func (c *Config) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *Config) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { status := internal.BuildStatus{ State: convertStatus(b.Status), Desc: convertDesc(b.Status), diff --git a/remote/coding/coding.go b/remote/coding/coding.go index e488bc2c9..7255b2448 100644 --- a/remote/coding/coding.go +++ b/remote/coding/coding.go @@ -243,7 +243,7 @@ func (c *Coding) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] } // Status sends the commit status to the remote system. -func (c *Coding) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *Coding) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { // EMPTY: not implemented in Coding OAuth API return nil } diff --git a/remote/gerrit/gerrit.go b/remote/gerrit/gerrit.go index a78b9d530..f5fd526c3 100644 --- a/remote/gerrit/gerrit.go +++ b/remote/gerrit/gerrit.go @@ -108,7 +108,7 @@ func (c *client) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] } // Status is not supported by the Gogs driver. -func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { return nil } diff --git a/remote/gitea/gitea.go b/remote/gitea/gitea.go index 9efaca9e2..14b4bdb54 100644 --- a/remote/gitea/gitea.go +++ b/remote/gitea/gitea.go @@ -254,7 +254,7 @@ func (c *client) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] } // Status is supported by the Gitea driver. -func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { client := c.newClientToken(u.Token) status := getStatus(b.Status) diff --git a/remote/gitea/gitea_test.go b/remote/gitea/gitea_test.go index a6607bdf2..ab0933c2c 100644 --- a/remote/gitea/gitea_test.go +++ b/remote/gitea/gitea_test.go @@ -18,10 +18,10 @@ import ( "net/http/httptest" "testing" - "github.com/laszlocph/drone-oss-08/model" - "github.com/laszlocph/drone-oss-08/remote/gitea/fixtures" "github.com/franela/goblin" "github.com/gin-gonic/gin" + "github.com/laszlocph/drone-oss-08/model" + "github.com/laszlocph/drone-oss-08/remote/gitea/fixtures" ) func Test_gitea(t *testing.T) { @@ -149,7 +149,7 @@ func Test_gitea(t *testing.T) { }) g.It("Should return nil from send build status", func() { - err := c.Status(fakeUser, fakeRepo, fakeBuild, "http://gitea.io") + err := c.Status(fakeUser, fakeRepo, fakeBuild, "http://gitea.io", nil) g.Assert(err == nil).IsTrue() }) diff --git a/remote/github/github.go b/remote/github/github.go index bcce1b48c..a4cdb3dc4 100644 --- a/remote/github/github.go +++ b/remote/github/github.go @@ -430,17 +430,17 @@ func matchingHooks(hooks []github.Hook, rawurl string) *github.Hook { // Status sends the commit status to the remote system. // An example would be the GitHub pull request status. -func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { client := c.newClientToken(u.Token) switch b.Event { case "deployment": return deploymentStatus(client, r, b, link) default: - return repoStatus(client, r, b, link, c.Context) + return repoStatus(client, r, b, link, c.Context, proc) } } -func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link, ctx string) error { +func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link, ctx string, proc *model.Proc) error { context := ctx switch b.Event { case model.EventPull: @@ -451,10 +451,19 @@ func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link, ctx } } + status := github.String(convertStatus(b.Status)) + desc := github.String(convertDesc(b.Status)) + + if proc != nil { + context += "/" + proc.Name + status = github.String(convertStatus(proc.State)) + desc = github.String(convertDesc(proc.State)) + } + data := github.RepoStatus{ Context: github.String(context), - State: github.String(convertStatus(b.Status)), - Description: github.String(convertDesc(b.Status)), + State: status, + Description: desc, TargetURL: github.String(link), } _, _, err := client.Repositories.CreateStatus(r.Owner, r.Name, b.Commit, &data) diff --git a/remote/gitlab/gitlab.go b/remote/gitlab/gitlab.go index a0e60725b..910433ea8 100644 --- a/remote/gitlab/gitlab.go +++ b/remote/gitlab/gitlab.go @@ -345,7 +345,7 @@ func (c *Gitlab) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] // NOTE Currently gitlab doesn't support status for commits and events, // also if we want get MR status in gitlab we need implement a special plugin for gitlab, // gitlab uses API to fetch build status on client side. But for now we skip this. -func (g *Gitlab) Status(u *model.User, repo *model.Repo, b *model.Build, link string) error { +func (g *Gitlab) Status(u *model.User, repo *model.Repo, b *model.Build, link string, proc *model.Proc) error { client := NewClient(g.URL, u.Token, g.SkipVerify) status := getStatus(b.Status) diff --git a/remote/gitlab3/gitlab.go b/remote/gitlab3/gitlab.go index 7009271ee..73aafdbdf 100644 --- a/remote/gitlab3/gitlab.go +++ b/remote/gitlab3/gitlab.go @@ -345,7 +345,7 @@ func (c *Gitlab) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] // NOTE Currently gitlab doesn't support status for commits and events, // also if we want get MR status in gitlab we need implement a special plugin for gitlab, // gitlab uses API to fetch build status on client side. But for now we skip this. -func (g *Gitlab) Status(u *model.User, repo *model.Repo, b *model.Build, link string) error { +func (g *Gitlab) Status(u *model.User, repo *model.Repo, b *model.Build, link string, proc *model.Proc) error { client := NewClient(g.URL, u.Token, g.SkipVerify) status := getStatus(b.Status) diff --git a/remote/gogs/gogs.go b/remote/gogs/gogs.go index f6d1aa7ca..7b641384e 100644 --- a/remote/gogs/gogs.go +++ b/remote/gogs/gogs.go @@ -207,7 +207,7 @@ func (c *client) Dir(u *model.User, r *model.Repo, b *model.Build, f string) ([] } // Status is not supported by the Gogs driver. -func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string) error { +func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { return nil } diff --git a/remote/gogs/gogs_test.go b/remote/gogs/gogs_test.go index 961eae460..20f847646 100644 --- a/remote/gogs/gogs_test.go +++ b/remote/gogs/gogs_test.go @@ -163,7 +163,7 @@ func Test_gogs(t *testing.T) { g.It("Should return no-op for usupporeted features", func() { _, err1 := c.Auth("octocat", "4vyW6b49Z") - err2 := c.Status(nil, nil, nil, "") + err2 := c.Status(nil, nil, nil, "", nil) err3 := c.Deactivate(nil, nil, "") g.Assert(err1 != nil).IsTrue() g.Assert(err2 == nil).IsTrue() diff --git a/remote/remote.go b/remote/remote.go index 22563cf47..558aae222 100644 --- a/remote/remote.go +++ b/remote/remote.go @@ -55,7 +55,7 @@ type Remote interface { // Status sends the commit status to the remote system. // An example would be the GitHub pull request status. - Status(u *model.User, r *model.Repo, b *model.Build, link string) error + Status(u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error // Netrc returns a .netrc file that can be used to clone // private repositories from a remote system. @@ -127,8 +127,8 @@ func Perm(c context.Context, u *model.User, owner, repo string) (*model.Perm, er // Status sends the commit status to the remote system. // An example would be the GitHub pull request status. -func Status(c context.Context, u *model.User, r *model.Repo, b *model.Build, link string) error { - return FromContext(c).Status(u, r, b, link) +func Status(c context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { + return FromContext(c).Status(u, r, b, link, proc) } // Netrc returns a .netrc file that can be used to clone diff --git a/server/build.go b/server/build.go index 943539308..df2efc093 100644 --- a/server/build.go +++ b/server/build.go @@ -307,14 +307,6 @@ func PostApproval(c *gin.Context) { } } - defer func() { - uri := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, build.Number) - err = remote_.Status(user, repo, build, uri) - if err != nil { - logrus.Errorf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) - } - }() - var yamls []*remote.FileMeta for _, y := range configs { yamls = append(yamls, &remote.FileMeta{Data: []byte(y.Data), Name: y.Name}) @@ -346,6 +338,20 @@ func PostApproval(c *gin.Context) { logrus.Errorf("error persisting procs %s/%d: %s", repo.FullName, build.Number, err) } + defer func() { + for _, item := range buildItems { + uri := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, build.Number) + if len(buildItems) > 1 { + err = remote_.Status(user, repo, build, uri, item.Proc) + } else { + err = remote_.Status(user, repo, build, uri, nil) + } + if err != nil { + logrus.Errorf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) + } + } + }() + publishToTopic(c, build, repo) queueBuild(build, repo, buildItems) } @@ -380,7 +386,7 @@ func PostDecline(c *gin.Context) { } uri := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, build.Number) - err = remote_.Status(user, repo, build, uri) + err = remote_.Status(user, repo, build, uri, nil) if err != nil { logrus.Errorf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) } diff --git a/server/hook.go b/server/hook.go index 8efa17218..8bbd5b9e3 100644 --- a/server/hook.go +++ b/server/hook.go @@ -221,14 +221,6 @@ func PostHook(c *gin.Context) { // get the previous build so that we can send status change notifications last, _ := store.GetBuildLastBefore(c, repo, build.Branch, build.ID) - defer func() { - uri := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, build.Number) - err = remote_.Status(user, repo, build, uri) - if err != nil { - logrus.Errorf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) - } - }() - b := procBuilder{ Repo: repo, Curr: build, @@ -255,6 +247,20 @@ func PostHook(c *gin.Context) { logrus.Errorf("error persisting procs %s/%d: %s", repo.FullName, build.Number, err) } + defer func() { + for _, item := range buildItems { + uri := fmt.Sprintf("%s/%s/%d", httputil.GetURL(c.Request), repo.FullName, build.Number) + if len(buildItems) > 1 { + err = remote_.Status(user, repo, build, uri, item.Proc) + } else { + err = remote_.Status(user, repo, build, uri, nil) + } + if err != nil { + logrus.Errorf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) + } + } + }() + publishToTopic(c, build, repo) queueBuild(build, repo, buildItems) } diff --git a/server/rpc.go b/server/rpc.go index 6bd288459..c552ea195 100644 --- a/server/rpc.go +++ b/server/rpc.go @@ -401,7 +401,13 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error { log.Printf("error: done: cannot update build_id %d final state: %s", build.ID, err) } - s.updateRemoteStatus(repo, build) + if !isMultiPipeline(procs) { + s.updateRemoteStatus(repo, build, nil) + } + } + + if isMultiPipeline(procs) { + s.updateRemoteStatus(repo, build, proc) } if err := s.logger.Close(c, id); err != nil { @@ -413,6 +419,16 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error { return nil } +func isMultiPipeline(procs []*model.Proc) bool { + countPPIDZero := 0 + for _, proc := range procs { + if proc.PPID == 0 { + countPPIDZero++ + } + } + return countPPIDZero > 1 +} + // Log implements the rpc.Log function func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error { entry := new(logging.Entry) @@ -474,7 +490,7 @@ func buildStatus(procs []*model.Proc) string { return status } -func (s *RPC) updateRemoteStatus(repo *model.Repo, build *model.Build) { +func (s *RPC) updateRemoteStatus(repo *model.Repo, build *model.Build, proc *model.Proc) { user, err := s.store.GetUser(repo.UserID) if err == nil { if refresher, ok := s.remote.(remote.Refresher); ok { @@ -484,7 +500,7 @@ func (s *RPC) updateRemoteStatus(repo *model.Repo, build *model.Build) { } } uri := fmt.Sprintf("%s/%s/%d", s.host, repo.FullName, build.Number) - err = s.remote.Status(user, repo, build, uri) + err = s.remote.Status(user, repo, build, uri, proc) if err != nil { logrus.Errorf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) }