prow/jenkins/jenkins.go
func (c *Client) EnsureBuildableJob(spec *prowapi.ProwJobSpec) error {
	var jobInfo *JobInfo

	// wait at most 20 seconds for the job to appear
	getJobInfoBackoff := wait.Backoff{
		Duration: time.Duration(10) * time.Second,
		Factor:   1,
		Jitter:   0,
		Steps:    2,
	}

	getJobErr := wait.ExponentialBackoff(getJobInfoBackoff, func() (bool, error) {
		var jobErr error
		jobInfo, jobErr = c.GetJobInfo(spec)

		if jobErr != nil && !strings.Contains(strings.ToLower(jobErr.Error()), "404 not found") {
			return false, jobErr
		}

		return jobInfo != nil, nil
	})

	if getJobErr != nil {
		return fmt.Errorf("Job %v does not exist", spec.Job)
	}

	isParameterized := c.JobParameterized(jobInfo)

	c.logger.Tracef("JobHasParameters: %v", isParameterized)

	if isParameterized || len(jobInfo.Builds) > 0 {
		return nil
	}

	buildErr := c.LaunchBuild(spec, nil)

	if buildErr != nil {
		return buildErr
	}

	backoff := wait.Backoff{
		Duration: time.Duration(5) * time.Second,
		Factor:   1,
		Jitter:   1,
		Steps:    10,
	}

	return wait.ExponentialBackoff(backoff, func() (bool, error) {
		c.logger.Debugf("Waiting for job %v to become parameterized", spec.Job)

		jobInfo, _ := c.GetJobInfo(spec)
		isParameterized := false

		if jobInfo != nil {
			isParameterized = c.JobParameterized(jobInfo)

			if isParameterized && jobInfo.LastBuild != nil {
				c.logger.Debugf("Job %v is now parameterized, aborting the build", spec.Job)
				err := c.Abort(getJobName(spec), jobInfo.LastBuild)

				if err != nil {
					c.logger.Infof("Couldn't abort build #%v for job %v: %v", jobInfo.LastBuild.Number, spec.Job, err)
				}
			}
		}

		// don't stop on (possibly) intermittent errors
		return isParameterized, nil
	})
}
func (c *Client) EnsureBuildableJob(spec *prowapi.ProwJobSpec) error {
	var jobInfo *JobInfo

	// wait at most 20 seconds for the job to appear
	getJobInfoBackoff := wait.Backoff{
		Duration: time.Duration(10) * time.Second,
		Factor:   1,
		Jitter:   0,
		Steps:    2,
	}

	getJobErr := wait.ExponentialBackoff(getJobInfoBackoff, func() (bool, error) {
		var jobErr error
		jobInfo, jobErr = c.GetJobInfo(spec)

		if jobErr != nil && !strings.Contains(strings.ToLower(jobErr.Error()), "404 not found") {
			return false, jobErr
		}

		return jobInfo != nil, nil
	})

	if getJobErr != nil {
		return fmt.Errorf("Job %v does not exist", spec.Job)
	}

	isParameterized := c.JobParameterized(jobInfo)

	c.logger.Tracef("JobHasParameters: %v", isParameterized)

	if isParameterized || len(jobInfo.Builds) > 0 {
		return nil
	}

	buildErr := c.LaunchBuild(spec, nil)

	if buildErr != nil {
		return buildErr
	}

	backoff := wait.Backoff{
		Duration: time.Duration(5) * time.Second,
		Factor:   1,
		Jitter:   1,
		Steps:    10,
	}

	return wait.ExponentialBackoff(backoff, func() (bool, error) {
		c.logger.Debugf("Waiting for job %v to become parameterized", spec.Job)

		jobInfo, _ := c.GetJobInfo(spec)
		isParameterized := false

		if jobInfo != nil {
			isParameterized = c.JobParameterized(jobInfo)

			if isParameterized && jobInfo.LastBuild != nil {
				c.logger.Debugf("Job %v is now parameterized, aborting the build", spec.Job)
				err := c.Abort(getJobName(spec), jobInfo.LastBuild)

				if err != nil {
					c.logger.Infof("Couldn't abort build #%v for job %v: %v", jobInfo.LastBuild.Number, spec.Job, err)
				}
			}
		}

		// don't stop on (possibly) intermittent errors
		return isParameterized, nil
	})
}
// EnsureBuildableJob attempts to detect a job that hasn't yet ran and populated
// its parameters. If detected, it tries to run a build until the job parameters
// are processed, then it aborts the build.