예제 #1
0
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
}
예제 #2
0
func (sq *SubmitQueue) mergePullRequest(obj *github.MungeObject) {
	obj.MergePR("submit-queue")
	sq.SetMergeStatus(obj, merged)
	sq.updateMergeRate()
}
예제 #3
0
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
}
예제 #4
0
// 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
}
예제 #5
0
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
}