From 39bbde33769dd8ef488b3fc22366d89d5f93c0b4 Mon Sep 17 00:00:00 2001 From: ecrupper Date: Tue, 29 Aug 2023 09:07:26 -0500 Subject: [PATCH 1/3] fix(webhook): repo archive/unarchive interacts with SCM webhook + bonus comment updates --- api/webhook/post.go | 47 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/api/webhook/post.go b/api/webhook/post.go index b3d0fd3b3..87fb8c135 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -113,7 +113,8 @@ func PostWebhook(c *gin.Context) { // -------------------- End of TODO: -------------------- // process the webhook from the source control provider - // comment, number, h, r, b + // + // populate build, hook, repo resources as well as PR Number / PR Comment if necessary webhook, err := scm.FromContext(c).ProcessWebhook(c.Request) if err != nil { retErr := fmt.Errorf("unable to parse webhook: %w", err) @@ -142,7 +143,7 @@ func PostWebhook(c *gin.Context) { return } - // if there were actual changes to the repo, return the repo object + // if there were actual changes to the repo (database call populated ID field), return the repo object if r.GetID() != 0 { c.JSON(http.StatusOK, r) return @@ -345,7 +346,8 @@ func PostWebhook(c *gin.Context) { logrus.Debug("updating status to pending") b.SetStatus(constants.StatusPending) - // if this is a comment on a pull_request event + // if the event is issue_comment and the issue is a pull request, + // call SCM for more data not provided in webhook payload if strings.EqualFold(b.GetEvent(), constants.EventComment) && webhook.PRNumber > 0 { commit, branch, baseref, headref, err := scm.FromContext(c).GetPullRequest(u, repo, webhook.PRNumber) if err != nil { @@ -366,6 +368,7 @@ func PostWebhook(c *gin.Context) { // variable to store changeset files var files []string + // check if the build event is not issue_comment or pull_request if !strings.EqualFold(b.GetEvent(), constants.EventComment) && !strings.EqualFold(b.GetEvent(), constants.EventPull) { @@ -423,7 +426,7 @@ func PostWebhook(c *gin.Context) { time.Sleep(time.Duration(i) * time.Second) } - // send API call to attempt to capture the pipeline + // send database call to attempt to capture the pipeline if we already processed it before pipeline, err = database.FromContext(c).GetPipelineForRepo(ctx, b.GetCommit(), repo) if err != nil { // assume the pipeline doesn't exist in the database yet // send API call to capture the pipeline configuration file @@ -463,7 +466,7 @@ func PostWebhook(c *gin.Context) { return } - // update repo fields with any changes from SCM process + // update DB record of repo (repo) with any changes captured from webhook payload (r) repo.SetTopics(r.GetTopics()) repo.SetBranch(r.GetBranch()) @@ -525,7 +528,7 @@ func PostWebhook(c *gin.Context) { // before compiling. After we're done compiling, we reset the pipeline type. repo.SetPipelineType(pipelineType) - // skip the build if only the init or clone steps are found + // skip the build if pipeline compiled to only the init and clone steps skip := build.SkipEmptyBuild(p) if skip != "" { // set build to successful status @@ -678,6 +681,8 @@ func PostWebhook(c *gin.Context) { ) } +// handleRepositoryEvent is a helper function that processes repository events from the SCM and updates +// the database resources with any relevant changes resulting from the event, such as name changes, transfers, etc. func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *types.Metadata, h *library.Hook, r *library.Repo) (*library.Repo, error) { logrus.Debugf("webhook is repository event, making necessary updates to repo %s", r.GetFullName()) @@ -690,7 +695,7 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *types.Metadat }() switch h.GetEventAction() { - // if action is rename, go through rename routine + // if action is renamed or transferred, go through rename routine case constants.ActionRenamed, constants.ActionTransferred: r, err := renameRepository(ctx, h, r, c, m) if err != nil { @@ -748,6 +753,34 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *types.Metadat dbRepo.SetTopics(r.GetTopics()) } + if c.Value("webhookvalidation").(bool) { + // capture repo owner in order to make updates to SCM webhook + u, err := database.FromContext(c).GetUser(dbRepo.GetUserID()) + if err != nil { + retErr := fmt.Errorf("%s: failed to capture repo owner for %s: %w", baseErr, r.GetFullName(), err) + + h.SetStatus(constants.StatusFailure) + h.SetError(retErr.Error()) + + return nil, err + } + + // if repo was unarchived, enable the webhook. If repo was archived, disable the webhook. + if dbRepo.GetActive() { + // send API call to create the webhook + h, _, err = scm.FromContext(c).Enable(u, dbRepo, h) + if err != nil { + return nil, fmt.Errorf("unable to create webhook for %s: %w", dbRepo.GetFullName(), err) + } + } else { + // send API call to remove the webhook + err = scm.FromContext(c).Disable(u, dbRepo.GetOrg(), dbRepo.GetName()) + if err != nil { + return nil, fmt.Errorf("unable to delete webhook for %s: %w", dbRepo.GetFullName(), err) + } + } + } + // update repo object in the database after applying edits dbRepo, err = database.FromContext(c).UpdateRepo(ctx, dbRepo) if err != nil { From 993664bbc10f47be481b2e388ea8be7f144aa26f Mon Sep 17 00:00:00 2001 From: ecrupper Date: Tue, 29 Aug 2023 09:12:19 -0500 Subject: [PATCH 2/3] revert archive changes --- api/webhook/post.go | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/api/webhook/post.go b/api/webhook/post.go index 87fb8c135..e0ef95223 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -753,34 +753,6 @@ func handleRepositoryEvent(ctx context.Context, c *gin.Context, m *types.Metadat dbRepo.SetTopics(r.GetTopics()) } - if c.Value("webhookvalidation").(bool) { - // capture repo owner in order to make updates to SCM webhook - u, err := database.FromContext(c).GetUser(dbRepo.GetUserID()) - if err != nil { - retErr := fmt.Errorf("%s: failed to capture repo owner for %s: %w", baseErr, r.GetFullName(), err) - - h.SetStatus(constants.StatusFailure) - h.SetError(retErr.Error()) - - return nil, err - } - - // if repo was unarchived, enable the webhook. If repo was archived, disable the webhook. - if dbRepo.GetActive() { - // send API call to create the webhook - h, _, err = scm.FromContext(c).Enable(u, dbRepo, h) - if err != nil { - return nil, fmt.Errorf("unable to create webhook for %s: %w", dbRepo.GetFullName(), err) - } - } else { - // send API call to remove the webhook - err = scm.FromContext(c).Disable(u, dbRepo.GetOrg(), dbRepo.GetName()) - if err != nil { - return nil, fmt.Errorf("unable to delete webhook for %s: %w", dbRepo.GetFullName(), err) - } - } - } - // update repo object in the database after applying edits dbRepo, err = database.FromContext(c).UpdateRepo(ctx, dbRepo) if err != nil { From d9f6cf4d787ae042bf8f51dd65056acc677c27ea Mon Sep 17 00:00:00 2001 From: ecrupper Date: Tue, 29 Aug 2023 09:24:22 -0500 Subject: [PATCH 3/3] more comments --- api/build/executable.go | 1 + api/build/publish.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/api/build/executable.go b/api/build/executable.go index 9df63467d..17ca1c082 100644 --- a/api/build/executable.go +++ b/api/build/executable.go @@ -82,6 +82,7 @@ func GetBuildExecutable(c *gin.Context) { "subject": cl.Subject, }).Infof("reading build executable %s/%d", r.GetFullName(), b.GetNumber()) + // send database call to pop the requested build executable from the table bExecutable, err := database.FromContext(c).PopBuildExecutable(ctx, b.GetID()) if err != nil { retErr := fmt.Errorf("unable to pop build executable: %w", err) diff --git a/api/build/publish.go b/api/build/publish.go index 51f94cff2..3cf20ff02 100644 --- a/api/build/publish.go +++ b/api/build/publish.go @@ -17,9 +17,10 @@ import ( "github.com/sirupsen/logrus" ) -// PublishToQueue is a helper function that creates -// a build item and publishes it to the queue. +// PublishToQueue is a helper function that pushes the build executable to the database +// and publishes a queue item (build, repo, user) to the queue. func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interface, p *pipeline.Build, b *library.Build, r *library.Repo, u *library.User) { + // marshal pipeline build into byte data to add to the build executable object byteExecutable, err := json.Marshal(p) if err != nil { logrus.Errorf("Failed to marshal build executable %d for %s: %v", b.GetNumber(), r.GetFullName(), err) @@ -30,10 +31,12 @@ func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interf return } + // create build executable to push to database bExecutable := new(library.BuildExecutable) bExecutable.SetBuildID(b.GetID()) bExecutable.SetData(byteExecutable) + // send database call to create a build executable err = db.CreateBuildExecutable(ctx, bExecutable) if err != nil { logrus.Errorf("Failed to publish build executable to database %d for %s: %v", b.GetNumber(), r.GetFullName(), err) @@ -44,6 +47,7 @@ func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interf return } + // convert build, repo, and user into queue item item := types.ToItem(b, r, u) logrus.Infof("Converting queue item to json for build %d for %s", b.GetNumber(), r.GetFullName()) @@ -60,6 +64,7 @@ func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interf logrus.Infof("Establishing route for build %d for %s", b.GetNumber(), r.GetFullName()) + // determine the route on which to publish the queue item route, err := queue.Route(&p.Worker) if err != nil { logrus.Errorf("unable to set route for build %d for %s: %v", b.GetNumber(), r.GetFullName(), err) @@ -72,6 +77,7 @@ func PublishToQueue(ctx context.Context, queue queue.Service, db database.Interf logrus.Infof("Publishing item for build %d for %s to queue %s", b.GetNumber(), r.GetFullName(), route) + // push item on to the queue err = queue.Push(context.Background(), route, byteItem) if err != nil { logrus.Errorf("Retrying; Failed to publish build %d for %s: %v", b.GetNumber(), r.GetFullName(), err)