prow/tide/tide.go
func accumulateBatch(presubmits map[int][]config.Presubmit, prs []PullRequest, pjs []prowapi.ProwJob, log *logrus.Entry) ([]PullRequest, []PullRequest) {
	log.Debug("accumulating PRs for batch testing")
	if len(presubmits) == 0 {
		log.Debug("no presubmits configured, no batch can be triggered")
		return nil, nil
	}
	prNums := make(map[int]PullRequest)
	for _, pr := range prs {
		prNums[int(pr.Number)] = pr
	}
	type accState struct {
		prs       []PullRequest
		jobStates map[string]simpleState
		// Are the pull requests in the ref still acceptable? That is, do they
		// still point to the heads of the PRs?
		validPulls bool
	}
	states := make(map[string]*accState)
	for _, pj := range pjs {
		if pj.Spec.Type != prowapi.BatchJob {
			continue
		}
		// First validate the batch job's refs.
		ref := pj.Spec.Refs.String()
		if _, ok := states[ref]; !ok {
			state := &accState{
				jobStates:  make(map[string]simpleState),
				validPulls: true,
			}
			for _, pull := range pj.Spec.Refs.Pulls {
				if pr, ok := prNums[pull.Number]; ok && string(pr.HeadRefOID) == pull.SHA {
					state.prs = append(state.prs, pr)
				} else if !ok {
					state.validPulls = false
					log.WithField("batch", ref).WithFields(pr.logFields()).Debug("batch job invalid, PR left pool")
					break
				} else {
					state.validPulls = false
					log.WithField("batch", ref).WithFields(pr.logFields()).Debug("batch job invalid, PR HEAD changed")
					break
				}
			}
			states[ref] = state
		}
		if !states[ref].validPulls {
			// The batch contains a PR ref that has changed. Skip it.
			continue
		}

		// Batch job refs are valid. Now accumulate job states by batch ref.
		context := pj.Spec.Context
		jobState := toSimpleState(pj.Status.State)
		// Store the best result for this ref+context.
		if s, ok := states[ref].jobStates[context]; !ok || s == failureState || jobState == successState {
			states[ref].jobStates[context] = jobState
		}
	}
	var pendingBatch, successBatch []PullRequest
	for ref, state := range states {
		if !state.validPulls {
			continue
		}
		requiredPresubmits := sets.NewString()
		for _, pr := range state.prs {
			for _, job := range presubmits[int(pr.Number)] {
				requiredPresubmits.Insert(job.Context)
			}
		}
		overallState := successState
		for _, p := range requiredPresubmits.List() {
			if s, ok := state.jobStates[p]; !ok || s == failureState {
				overallState = failureState
				log.WithField("batch", ref).Debugf("batch invalid, required presubmit %s is not passing", p)
				break
			} else if s == pendingState && overallState == successState {
				overallState = pendingState
			}
		}
		switch overallState {
		// Currently we only consider 1 pending batch and 1 success batch at a time.
		// If more are somehow present they will be ignored.
		case pendingState:
			pendingBatch = state.prs
		case successState:
			successBatch = state.prs
		}
	}
	return successBatch, pendingBatch
}
func accumulateBatch(presubmits map[int][]config.Presubmit, prs []PullRequest, pjs []prowapi.ProwJob, log *logrus.Entry) ([]PullRequest, []PullRequest) {
	log.Debug("accumulating PRs for batch testing")
	if len(presubmits) == 0 {
		log.Debug("no presubmits configured, no batch can be triggered")
		return nil, nil
	}
	prNums := make(map[int]PullRequest)
	for _, pr := range prs {
		prNums[int(pr.Number)] = pr
	}
	type accState struct {
		prs       []PullRequest
		jobStates map[string]simpleState
		// Are the pull requests in the ref still acceptable? That is, do they
		// still point to the heads of the PRs?
		validPulls bool
	}
	states := make(map[string]*accState)
	for _, pj := range pjs {
		if pj.Spec.Type != prowapi.BatchJob {
			continue
		}
		// First validate the batch job's refs.
		ref := pj.Spec.Refs.String()
		if _, ok := states[ref]; !ok {
			state := &accState{
				jobStates:  make(map[string]simpleState),
				validPulls: true,
			}
			for _, pull := range pj.Spec.Refs.Pulls {
				if pr, ok := prNums[pull.Number]; ok && string(pr.HeadRefOID) == pull.SHA {
					state.prs = append(state.prs, pr)
				} else if !ok {
					state.validPulls = false
					log.WithField("batch", ref).WithFields(pr.logFields()).Debug("batch job invalid, PR left pool")
					break
				} else {
					state.validPulls = false
					log.WithField("batch", ref).WithFields(pr.logFields()).Debug("batch job invalid, PR HEAD changed")
					break
				}
			}
			states[ref] = state
		}
		if !states[ref].validPulls {
			// The batch contains a PR ref that has changed. Skip it.
			continue
		}

		// Batch job refs are valid. Now accumulate job states by batch ref.
		context := pj.Spec.Context
		jobState := toSimpleState(pj.Status.State)
		// Store the best result for this ref+context.
		if s, ok := states[ref].jobStates[context]; !ok || s == failureState || jobState == successState {
			states[ref].jobStates[context] = jobState
		}
	}
	var pendingBatch, successBatch []PullRequest
	for ref, state := range states {
		if !state.validPulls {
			continue
		}
		requiredPresubmits := sets.NewString()
		for _, pr := range state.prs {
			for _, job := range presubmits[int(pr.Number)] {
				requiredPresubmits.Insert(job.Context)
			}
		}
		overallState := successState
		for _, p := range requiredPresubmits.List() {
			if s, ok := state.jobStates[p]; !ok || s == failureState {
				overallState = failureState
				log.WithField("batch", ref).Debugf("batch invalid, required presubmit %s is not passing", p)
				break
			} else if s == pendingState && overallState == successState {
				overallState = pendingState
			}
		}
		switch overallState {
		// Currently we only consider 1 pending batch and 1 success batch at a time.
		// If more are somehow present they will be ignored.
		case pendingState:
			pendingBatch = state.prs
		case successState:
			successBatch = state.prs
		}
	}
	return successBatch, pendingBatch
}
func accumulateBatch ( presubmits map [ int ] [ ] config . Presubmit , prs [ ] PullRequest , pjs [ ] prowapi . ProwJob , log * logrus . Entry ) ( [ ] PullRequest , [ ] PullRequest ) { log . Debug ( " " ) if len ( presubmits ) == 0 { log . Debug ( " " ) return nil , nil } prNums := make ( map [ int ] PullRequest ) for _ , pr := range prs { prNums [ int ( pr . Number ) ] = pr } type accState struct { prs [ ] PullRequest jobStates map [ string ] simpleState // Are the pull requests in the ref still acceptable? That is, do they // still point to the heads of the PRs? validPulls bool } states := make ( map [ string ] * accState ) for _ , pj := range pjs { if pj . Spec . Type != prowapi . BatchJob { continue } // First validate the batch job's refs. ref := pj . Spec . Refs . String ( ) if _ , ok := states [ ref ] ; ! ok { state := & accState { jobStates : make ( map [ string ] simpleState ) , validPulls : true , } for _ , pull := range pj . Spec . Refs . Pulls { if pr , ok := prNums [ pull . Number ] ; ok && string ( pr . HeadRefOID ) == pull . SHA { state . prs = append ( state . prs , pr ) } else if ! ok { state . validPulls = false log . WithField ( " " , ref ) . WithFields ( pr . logFields ( ) ) . Debug ( " " ) break } else { state . validPulls = false log . WithField ( " " , ref ) . WithFields ( pr . logFields ( ) ) . Debug ( " " ) break } } states [ ref ] = state } if ! states [ ref ] . validPulls { // The batch contains a PR ref that has changed. Skip it. continue } // Batch job refs are valid. Now accumulate job states by batch ref. context := pj . Spec . Context jobState := toSimpleState ( pj . Status . State ) // Store the best result for this ref+context. if s , ok := states [ ref ] . jobStates [ context ] ; ! ok || s == failureState || jobState == successState { states [ ref ] . jobStates [ context ] = jobState } } var pendingBatch , successBatch [ ] PullRequest for ref , state := range states { if ! state . validPulls { continue } requiredPresubmits := sets . NewString ( ) for _ , pr := range state . prs { for _ , job := range presubmits [ int ( pr . Number ) ] { requiredPresubmits . Insert ( job . Context ) } } overallState := successState for _ , p := range requiredPresubmits . List ( ) { if s , ok := state . jobStates [ p ] ; ! ok || s == failureState { overallState = failureState log . WithField ( " " , ref ) . Debugf ( " " , p ) break } else if s == pendingState && overallState == successState { overallState = pendingState } } switch overallState { // Currently we only consider 1 pending batch and 1 success batch at a time. // If more are somehow present they will be ignored. case pendingState : pendingBatch = state . prs case successState : successBatch = state . prs } } return successBatch , pendingBatch }
// accumulateBatch returns a list of PRs that can be merged after passing batch
// testing, if any exist. It also returns a list of PRs currently being batch
// tested.
accumulateBatch returns a list of PRs that can be merged after passing batch testing if any exist . It also returns a list of PRs currently being batch tested .