prow/cmd/pipeline/controller.go
func reconcile(c reconciler, key string) error {
	logrus.Debugf("reconcile: %s\n", key)

	ctx, namespace, name, err := fromKey(key)
	if err != nil {
		runtime.HandleError(err)
		return nil
	}

	var wantPipelineRun bool
	pj, err := c.getProwJob(name)
	switch {
	case apierrors.IsNotFound(err):
		// Do not want pipeline
	case err != nil:
		return fmt.Errorf("get prowjob: %v", err)
	case pj.Spec.Agent != prowjobv1.TektonAgent:
		// Do not want a pipeline for this job
	case pjutil.ClusterToCtx(pj.Spec.Cluster) != ctx:
		// Build is in wrong cluster, we do not want this build
		logrus.Warnf("%s found in context %s not %s", key, ctx, pjutil.ClusterToCtx(pj.Spec.Cluster))
	case pj.DeletionTimestamp == nil:
		wantPipelineRun = true
	}

	var havePipelineRun bool
	p, err := c.getPipelineRun(ctx, namespace, name)
	switch {
	case apierrors.IsNotFound(err):
		// Do not have a pipeline
	case err != nil:
		return fmt.Errorf("get pipelinerun %s: %v", key, err)
	case p.DeletionTimestamp == nil:
		havePipelineRun = true
	}

	var newPipelineRun bool
	switch {
	case !wantPipelineRun:
		if !havePipelineRun {
			if pj != nil && pj.Spec.Agent == prowjobv1.TektonAgent {
				logrus.Infof("Observed deleted: %s", key)
			}
			return nil
		}

		// Skip deleting if the pipeline run is not created by prow
		switch v, ok := p.Labels[kube.CreatedByProw]; {
		case !ok, v != "true":
			return nil
		}
		logrus.Infof("Delete PipelineRun/%s", key)
		if err = c.deletePipelineRun(ctx, namespace, name); err != nil {
			return fmt.Errorf("delete pipelinerun: %v", err)
		}
		return nil
	case finalState(pj.Status.State):
		logrus.Infof("Observed finished: %s", key)
		return nil
	case wantPipelineRun && pj.Spec.PipelineRunSpec == nil:
		return fmt.Errorf("nil PipelineRunSpec in ProwJob/%s", key)
	case wantPipelineRun && !havePipelineRun:
		id, url, err := c.pipelineID(*pj)
		if err != nil {
			return fmt.Errorf("failed to get pipeline id: %v", err)
		}
		pj.Status.BuildID = id
		pj.Status.URL = url
		newPipelineRun = true
		pr := makePipelineGitResource(*pj)
		logrus.Infof("Create PipelineResource/%s", key)
		if pr, err = c.createPipelineResource(ctx, namespace, pr); err != nil {
			return fmt.Errorf("create PipelineResource/%s: %v", key, err)
		}
		newp, err := makePipelineRun(*pj, pr)
		if err != nil {
			return fmt.Errorf("make PipelineRun/%s: %v", key, err)
		}
		logrus.Infof("Create PipelineRun/%s", key)
		p, err = c.createPipelineRun(ctx, namespace, newp)
		if err != nil {
			jerr := fmt.Errorf("start pipeline: %v", err)
			// Set the prow job in error state to avoid an endless loop when
			// the pipeline cannot be executed (e.g. referenced pipeline does not exist)
			return updateProwJobState(c, key, newPipelineRun, pj, prowjobv1.ErrorState, jerr.Error())
		}
	}

	if p == nil {
		return fmt.Errorf("no pipelinerun found or created for %q, wantPipelineRun was %v", key, wantPipelineRun)
	}
	wantState, wantMsg := prowJobStatus(p.Status)
	return updateProwJobState(c, key, newPipelineRun, pj, wantState, wantMsg)
}
func reconcile(c reconciler, key string) error {
	logrus.Debugf("reconcile: %s\n", key)

	ctx, namespace, name, err := fromKey(key)
	if err != nil {
		runtime.HandleError(err)
		return nil
	}

	var wantPipelineRun bool
	pj, err := c.getProwJob(name)
	switch {
	case apierrors.IsNotFound(err):
		// Do not want pipeline
	case err != nil:
		return fmt.Errorf("get prowjob: %v", err)
	case pj.Spec.Agent != prowjobv1.TektonAgent:
		// Do not want a pipeline for this job
	case pjutil.ClusterToCtx(pj.Spec.Cluster) != ctx:
		// Build is in wrong cluster, we do not want this build
		logrus.Warnf("%s found in context %s not %s", key, ctx, pjutil.ClusterToCtx(pj.Spec.Cluster))
	case pj.DeletionTimestamp == nil:
		wantPipelineRun = true
	}

	var havePipelineRun bool
	p, err := c.getPipelineRun(ctx, namespace, name)
	switch {
	case apierrors.IsNotFound(err):
		// Do not have a pipeline
	case err != nil:
		return fmt.Errorf("get pipelinerun %s: %v", key, err)
	case p.DeletionTimestamp == nil:
		havePipelineRun = true
	}

	var newPipelineRun bool
	switch {
	case !wantPipelineRun:
		if !havePipelineRun {
			if pj != nil && pj.Spec.Agent == prowjobv1.TektonAgent {
				logrus.Infof("Observed deleted: %s", key)
			}
			return nil
		}

		// Skip deleting if the pipeline run is not created by prow
		switch v, ok := p.Labels[kube.CreatedByProw]; {
		case !ok, v != "true":
			return nil
		}
		logrus.Infof("Delete PipelineRun/%s", key)
		if err = c.deletePipelineRun(ctx, namespace, name); err != nil {
			return fmt.Errorf("delete pipelinerun: %v", err)
		}
		return nil
	case finalState(pj.Status.State):
		logrus.Infof("Observed finished: %s", key)
		return nil
	case wantPipelineRun && pj.Spec.PipelineRunSpec == nil:
		return fmt.Errorf("nil PipelineRunSpec in ProwJob/%s", key)
	case wantPipelineRun && !havePipelineRun:
		id, url, err := c.pipelineID(*pj)
		if err != nil {
			return fmt.Errorf("failed to get pipeline id: %v", err)
		}
		pj.Status.BuildID = id
		pj.Status.URL = url
		newPipelineRun = true
		pr := makePipelineGitResource(*pj)
		logrus.Infof("Create PipelineResource/%s", key)
		if pr, err = c.createPipelineResource(ctx, namespace, pr); err != nil {
			return fmt.Errorf("create PipelineResource/%s: %v", key, err)
		}
		newp, err := makePipelineRun(*pj, pr)
		if err != nil {
			return fmt.Errorf("make PipelineRun/%s: %v", key, err)
		}
		logrus.Infof("Create PipelineRun/%s", key)
		p, err = c.createPipelineRun(ctx, namespace, newp)
		if err != nil {
			jerr := fmt.Errorf("start pipeline: %v", err)
			// Set the prow job in error state to avoid an endless loop when
			// the pipeline cannot be executed (e.g. referenced pipeline does not exist)
			return updateProwJobState(c, key, newPipelineRun, pj, prowjobv1.ErrorState, jerr.Error())
		}
	}

	if p == nil {
		return fmt.Errorf("no pipelinerun found or created for %q, wantPipelineRun was %v", key, wantPipelineRun)
	}
	wantState, wantMsg := prowJobStatus(p.Status)
	return updateProwJobState(c, key, newPipelineRun, pj, wantState, wantMsg)
}
// reconcile ensures a tekton prowjob has a corresponding pipeline, updating the prowjob's status as the pipeline progresses.