func (sq *SubmitQueue) doGithubE2EAndMerge(obj *github.MungeObject) { err := obj.Refresh() if err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown) return } if !sq.validForMerge(obj) { return } if obj.HasLabel(e2eNotRequiredLabel) { obj.MergePR("submit-queue") sq.SetMergeStatus(obj, merged) return } if err := obj.WriteComment(verifySafeToMergeBody); err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown) return } // Wait for the build to start sq.SetMergeStatus(obj, ghE2EWaitingStart) err = obj.WaitForPending([]string{sq.E2EStatusContext, sq.UnitStatusContext}) if err != nil { s := fmt.Sprintf("Failed waiting for PR to start testing: %v", err) sq.SetMergeStatus(obj, s) return } // Wait for the status to go back to something other than pending sq.SetMergeStatus(obj, ghE2ERunning) err = obj.WaitForNotPending([]string{sq.E2EStatusContext, sq.UnitStatusContext}) if err != nil { s := fmt.Sprintf("Failed waiting for PR to finish testing: %v", err) sq.SetMergeStatus(obj, s) return } // Check if the thing we care about is success if ok := obj.IsStatusSuccess([]string{sq.E2EStatusContext, sq.UnitStatusContext}); !ok { sq.SetMergeStatus(obj, ghE2EFailed) return } if !sq.e2eStable() { sq.SetMergeStatus(obj, e2eFailure) return } obj.MergePR("submit-queue") sq.updateMergeRate() sq.SetMergeStatus(obj, merged) return }
func (sq *SubmitQueue) mergePullRequest(obj *github.MungeObject) { obj.MergePR("submit-queue") sq.SetMergeStatus(obj, merged) sq.updateMergeRate() }
func (sq *SubmitQueue) doGithubE2EAndMerge(obj *github.MungeObject) { _, err := obj.RefreshPR() if err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown, true) return } if m, err := obj.IsMerged(); err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown, true) return } else if m { sq.SetMergeStatus(obj, merged, true) return } if mergeable, err := obj.IsMergeable(); err != nil { sq.SetMergeStatus(obj, undeterminedMergability, true) return } else if !mergeable { sq.SetMergeStatus(obj, unmergeable, true) return } body := "@k8s-bot test this [submit-queue is verifying that this PR is safe to merge]" if err := obj.WriteComment(body); err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown, true) return } // Wait for the build to start sq.SetMergeStatus(obj, ghE2EWaitingStart, true) err = obj.WaitForPending([]string{sq.E2EStatusContext, sq.UnitStatusContext}) if err != nil { s := fmt.Sprintf("Failed waiting for PR to start testing: %v", err) sq.SetMergeStatus(obj, s, true) return } // Wait for the status to go back to something other than pending sq.SetMergeStatus(obj, ghE2ERunning, true) err = obj.WaitForNotPending([]string{sq.E2EStatusContext, sq.UnitStatusContext}) if err != nil { s := fmt.Sprintf("Failed waiting for PR to finish testing: %v", err) sq.SetMergeStatus(obj, s, true) return } // Check if the thing we care about is success if ok := obj.IsStatusSuccess([]string{sq.E2EStatusContext, sq.UnitStatusContext}); !ok { sq.SetMergeStatus(obj, ghE2EFailed, true) return } if !sq.e2e.Stable() { sq.flushGithubE2EQueue(e2eFailure) sq.SetMergeStatus(obj, e2eFailure, true) return } obj.MergePR("submit-queue") sq.SetMergeStatus(obj, merged, true) return }
// Munge is the workhorse the will actually make updates to the PR func (sq *SubmitQueue) Munge(obj *github.MungeObject) { if !obj.IsPR() { return } e2e := sq.e2e userSet := sq.userWhitelist if !obj.HasLabels([]string{claYes}) && !obj.HasLabels([]string{claHuman}) { sq.SetMergeStatus(obj, noCLA, false) return } if mergeable, err := obj.IsMergeable(); err != nil { sq.SetMergeStatus(obj, undeterminedMergability, false) return } else if !mergeable { sq.SetMergeStatus(obj, unmergeable, false) return } // Validate the status information for this PR contexts := sq.requiredStatusContexts(obj) if ok := obj.IsStatusSuccess(contexts); !ok { sq.SetMergeStatus(obj, ciFailure, false) return } if !obj.HasLabel(sq.WhitelistOverride) && !userSet.Has(*obj.Issue.User.Login) { if !obj.HasLabel(needsOKToMergeLabel) { obj.AddLabels([]string{needsOKToMergeLabel}) body := "The author of this PR is not in the whitelist for merge, can one of the admins add the 'ok-to-merge' label?" obj.WriteComment(body) } sq.SetMergeStatus(obj, needsok, false) return } // Tidy up the issue list. if obj.HasLabel(needsOKToMergeLabel) { obj.RemoveLabel(needsOKToMergeLabel) } if !obj.HasLabels([]string{"lgtm"}) { sq.SetMergeStatus(obj, noLGTM, false) return } lastModifiedTime := obj.LastModifiedTime() lgtmTime := obj.LabelTime("lgtm") if lastModifiedTime == nil || lgtmTime == nil { glog.Errorf("PR %d was unable to determine when LGTM was added or when last modified", *obj.Issue.Number) sq.SetMergeStatus(obj, unknown, false) return } if lastModifiedTime.After(*lgtmTime) { sq.SetMergeStatus(obj, lgtmEarly, false) return } if !e2e.Stable() { sq.flushGithubE2EQueue(e2eFailure) sq.SetMergeStatus(obj, e2eFailure, false) return } // if there is a 'e2e-not-required' label, just merge it. if obj.HasLabel(e2eNotRequiredLabel) { obj.MergePR("submit-queue") sq.SetMergeStatus(obj, merged, true) return } added := false sq.Lock() if _, ok := sq.githubE2EQueue[*obj.Issue.Number]; !ok { sq.githubE2EQueue[*obj.Issue.Number] = obj sq.githubE2EWakeup <- true added = true } sq.Unlock() if added { sq.SetMergeStatus(obj, ghE2EQueued, true) } return }
func (sq *SubmitQueue) doGithubE2EAndMerge(obj *github.MungeObject) { err := obj.Refresh() if err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown) return } if !sq.validForMerge(obj) { return } if obj.HasLabel(e2eNotRequiredLabel) { obj.MergePR("submit-queue") sq.SetMergeStatus(obj, merged) return } // See if we can skip the retest. headSHA, baseRef, gotHeadSHA := obj.GetHeadAndBase() baseSHA := "" gotBaseSHA := false if gotHeadSHA { baseSHA, gotBaseSHA = obj.GetSHAFromRef(baseRef) } maySkipTest := gotHeadSHA && gotBaseSHA && sq.interruptedMergeBaseSHA == baseSHA && sq.interruptedMergeHeadSHA == headSHA if maySkipTest { glog.Infof("Skipping retest since head and base sha match previous attempt!") atomic.AddInt32(&sq.retestsAvoided, 1) } else { if err := obj.WriteComment(verifySafeToMergeBody); err != nil { glog.Errorf("%d: unknown err: %v", *obj.Issue.Number, err) sq.SetMergeStatus(obj, unknown) return } // Wait for the build to start sq.SetMergeStatus(obj, ghE2EWaitingStart) err = obj.WaitForPending([]string{sq.E2EStatusContext, sq.UnitStatusContext}) if err != nil { s := fmt.Sprintf("Failed waiting for PR to start testing: %v", err) sq.SetMergeStatus(obj, s) return } // re-get the base SHA in case something merged between us checking and // starting the tests. if gotHeadSHA { baseSHA, gotBaseSHA = obj.GetSHAFromRef(baseRef) } // Wait for the status to go back to something other than pending sq.SetMergeStatus(obj, ghE2ERunning) err = obj.WaitForNotPending([]string{sq.E2EStatusContext, sq.UnitStatusContext}) if err != nil { s := fmt.Sprintf("Failed waiting for PR to finish testing: %v", err) sq.SetMergeStatus(obj, s) return } // Check if the thing we care about is success if ok := obj.IsStatusSuccess([]string{sq.E2EStatusContext, sq.UnitStatusContext}); !ok { sq.SetMergeStatus(obj, ghE2EFailed) return } } if !sq.e2eStable(true) { if gotHeadSHA && gotBaseSHA { sq.interruptedMergeBaseSHA = baseSHA sq.interruptedMergeHeadSHA = headSHA } sq.SetMergeStatus(obj, e2eFailure) return } obj.MergePR("submit-queue") sq.updateMergeRate() sq.SetMergeStatus(obj, merged) return }