diff --git a/pkg/vcs/gitlab/mr_status_updater.go b/pkg/vcs/gitlab/mr_status_updater.go index 133a6b6..b8e2955 100644 --- a/pkg/vcs/gitlab/mr_status_updater.go +++ b/pkg/vcs/gitlab/mr_status_updater.go @@ -1,14 +1,20 @@ package gitlab import ( + "errors" "fmt" + "time" + "github.com/cenkalti/backoff/v4" "github.com/hashicorp/go-tfe" "github.com/rs/zerolog/log" gogitlab "github.com/xanzy/go-gitlab" "github.com/zapier/tfbuddy/pkg/runstream" ) +// Sentinel error +var errNoPipelineStatus = errors.New("nil pipeline status") + func (p *RunStatusUpdater) updateCommitStatusForRun(run *tfe.Run, rmd runstream.RunMetadata) { switch run.Status { // https://www.terraform.io/cloud-docs/api-docs/run#run-states @@ -92,7 +98,27 @@ func (p *RunStatusUpdater) updateStatus(state gogitlab.BuildStateValue, action s TargetURL: runUrlForTFRunMetadata(rmd), Description: descriptionForState(state), State: state, - PipelineID: p.getLatestPipelineID(rmd), + } + + // Look up the latest pipeline ID for this MR, since Gitlab is eventually consistent + // Once we have a pipeline ID returned, we know we have a valid pipeline to set commit status for + var pipelineID *int + getPipelineIDFn := func() error { + log.Debug().Msg("getting pipeline status") + pipelineID := p.getLatestPipelineID(rmd) + if pipelineID == nil { + return errNoPipelineStatus + } + return nil + } + + err := backoff.Retry(getPipelineIDFn, configureBackOff()) + if err != nil { + log.Warn().Msg("could not retrieve pipeline id after multiple attempts") + } + if pipelineID != nil { + log.Trace().Int("pipeline_id", *pipelineID).Msg("pipeline status") + status.PipelineID = pipelineID } log.Debug().Interface("new_status", status).Msg("updating Gitlab commit status") @@ -151,3 +177,14 @@ func (p *RunStatusUpdater) getLatestPipelineID(rmd runstream.RunMetadata) *int { } return nil } + +// configureBackOff returns a backoff configuration to use to retry requests +func configureBackOff() *backoff.ExponentialBackOff { + + // Lets setup backoff logic to retry this request for 30 seconds + expBackOff := backoff.NewExponentialBackOff() + expBackOff.MaxInterval = 10 * time.Second + expBackOff.MaxElapsedTime = 30 * time.Second + + return expBackOff +}