Improve the support for reusable workflows (#122)
Fix [#32439](https://github.com/go-gitea/gitea/issues/32439) - Support reusable workflows with conditional jobs - Support nesting reusable workflows Reviewed-on: https://gitea.com/gitea/act/pulls/122 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-by: Jason Song <wolfogre@noreply.gitea.com> Co-authored-by: Zettat123 <zettat123@gmail.com> Co-committed-by: Zettat123 <zettat123@gmail.com>
This commit is contained in:
		@@ -73,10 +73,6 @@ func newJobExecutor(info jobInfo, sf stepFactory, rc *RunContext) common.Executo
 | 
			
		||||
 | 
			
		||||
		preExec := step.pre()
 | 
			
		||||
		preSteps = append(preSteps, useStepLogger(rc, stepModel, stepStagePre, func(ctx context.Context) error {
 | 
			
		||||
			if rc.caller != nil { // For Gitea
 | 
			
		||||
				rc.caller.reusedWorkflowJobResults[rc.JobName] = "pending"
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			logger := common.Logger(ctx)
 | 
			
		||||
			preErr := preExec(ctx)
 | 
			
		||||
			if preErr != nil {
 | 
			
		||||
@@ -189,34 +185,7 @@ func setJobResult(ctx context.Context, info jobInfo, rc *RunContext, success boo
 | 
			
		||||
	info.result(jobResult)
 | 
			
		||||
	if rc.caller != nil {
 | 
			
		||||
		// set reusable workflow job result
 | 
			
		||||
 | 
			
		||||
		rc.caller.updateResultLock.Lock()
 | 
			
		||||
		rc.caller.reusedWorkflowJobResults[rc.JobName] = jobResult
 | 
			
		||||
 | 
			
		||||
		allJobDone := true
 | 
			
		||||
		hasFailure := false
 | 
			
		||||
		for _, result := range rc.caller.reusedWorkflowJobResults {
 | 
			
		||||
			if result == "pending" {
 | 
			
		||||
				allJobDone = false
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if result == "failure" {
 | 
			
		||||
				hasFailure = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if allJobDone {
 | 
			
		||||
			reusedWorkflowJobResult := "success"
 | 
			
		||||
			reusedWorkflowJobResultMessage := "succeeded"
 | 
			
		||||
			if hasFailure {
 | 
			
		||||
				reusedWorkflowJobResult = "failure"
 | 
			
		||||
				reusedWorkflowJobResultMessage = "failed"
 | 
			
		||||
			}
 | 
			
		||||
			rc.caller.runContext.result(reusedWorkflowJobResult)
 | 
			
		||||
			logger.WithField("jobResult", reusedWorkflowJobResult).Infof("\U0001F3C1  Job %s", reusedWorkflowJobResultMessage)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rc.caller.updateResultLock.Unlock()
 | 
			
		||||
		rc.caller.setReusedWorkflowJobResult(rc.JobName, jobResult) // For Gitea
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -175,7 +175,11 @@ func newReusableWorkflowExecutor(rc *RunContext, directory string, workflow stri
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return runner.NewPlanExecutor(plan)(ctx)
 | 
			
		||||
		// return runner.NewPlanExecutor(plan)(ctx)
 | 
			
		||||
		return common.NewPipelineExecutor( // For Gitea
 | 
			
		||||
			runner.NewPlanExecutor(plan),
 | 
			
		||||
			setReusedWorkflowCallerResult(rc, runner),
 | 
			
		||||
		)(ctx)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -271,3 +275,47 @@ func newRemoteReusableWorkflow(uses string) *remoteReusableWorkflow {
 | 
			
		||||
		URL:      "https://github.com",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// For Gitea
 | 
			
		||||
func setReusedWorkflowCallerResult(rc *RunContext, runner Runner) common.Executor {
 | 
			
		||||
	return func(ctx context.Context) error {
 | 
			
		||||
		logger := common.Logger(ctx)
 | 
			
		||||
 | 
			
		||||
		runnerImpl, ok := runner.(*runnerImpl)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			logger.Warn("Failed to get caller from runner")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
		caller := runnerImpl.caller
 | 
			
		||||
 | 
			
		||||
		allJobDone := true
 | 
			
		||||
		hasFailure := false
 | 
			
		||||
		for _, result := range caller.reusedWorkflowJobResults {
 | 
			
		||||
			if result == "pending" {
 | 
			
		||||
				allJobDone = false
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			if result == "failure" {
 | 
			
		||||
				hasFailure = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if allJobDone {
 | 
			
		||||
			reusedWorkflowJobResult := "success"
 | 
			
		||||
			reusedWorkflowJobResultMessage := "succeeded"
 | 
			
		||||
			if hasFailure {
 | 
			
		||||
				reusedWorkflowJobResult = "failure"
 | 
			
		||||
				reusedWorkflowJobResultMessage = "failed"
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if rc.caller != nil {
 | 
			
		||||
				rc.caller.setReusedWorkflowJobResult(rc.JobName, reusedWorkflowJobResult)
 | 
			
		||||
			} else {
 | 
			
		||||
				rc.result(reusedWorkflowJobResult)
 | 
			
		||||
				logger.WithField("jobResult", reusedWorkflowJobResult).Infof("\U0001F3C1  Job %s", reusedWorkflowJobResultMessage)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,12 @@ func (rc *RunContext) GetEnv() map[string]string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (rc *RunContext) jobContainerName() string {
 | 
			
		||||
	return createSimpleContainerName(rc.Config.ContainerNamePrefix, "WORKFLOW-"+rc.Run.Workflow.Name, "JOB-"+rc.Name)
 | 
			
		||||
	nameParts := []string{rc.Config.ContainerNamePrefix, "WORKFLOW-" + rc.Run.Workflow.Name, "JOB-" + rc.Name}
 | 
			
		||||
	if rc.caller != nil {
 | 
			
		||||
		nameParts = append(nameParts, "CALLED-BY-"+rc.caller.runContext.JobName)
 | 
			
		||||
	}
 | 
			
		||||
	// return createSimpleContainerName(rc.Config.ContainerNamePrefix, "WORKFLOW-"+rc.Run.Workflow.Name, "JOB-"+rc.Name)
 | 
			
		||||
	return createSimpleContainerName(nameParts...) // For Gitea
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Deprecated: use `networkNameForGitea`
 | 
			
		||||
@@ -653,6 +658,7 @@ func (rc *RunContext) Executor() (common.Executor, error) {
 | 
			
		||||
	return func(ctx context.Context) error {
 | 
			
		||||
		res, err := rc.isEnabled(ctx)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			rc.caller.setReusedWorkflowJobResult(rc.JobName, "failure") // For Gitea
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if res {
 | 
			
		||||
@@ -748,6 +754,10 @@ func (rc *RunContext) isEnabled(ctx context.Context) (bool, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !runJob {
 | 
			
		||||
		if rc.caller != nil { // For Gitea
 | 
			
		||||
			rc.caller.setReusedWorkflowJobResult(rc.JobName, "skipped")
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		l.WithField("jobResult", "skipped").Debugf("Skipping job '%s' due to '%s'", job.Name, job.If.Value)
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -210,6 +210,9 @@ func (runner *runnerImpl) NewPlanExecutor(plan *model.Plan) common.Executor {
 | 
			
		||||
					if len(rc.String()) > maxJobNameLen {
 | 
			
		||||
						maxJobNameLen = len(rc.String())
 | 
			
		||||
					}
 | 
			
		||||
					if rc.caller != nil { // For Gitea
 | 
			
		||||
						rc.caller.setReusedWorkflowJobResult(rc.JobName, "pending")
 | 
			
		||||
					}
 | 
			
		||||
					stageExecutor = append(stageExecutor, func(ctx context.Context) error {
 | 
			
		||||
						jobName := fmt.Sprintf("%-*s", maxJobNameLen, rc.String())
 | 
			
		||||
						executor, err := rc.Executor()
 | 
			
		||||
@@ -281,3 +284,10 @@ func (runner *runnerImpl) newRunContext(ctx context.Context, run *model.Run, mat
 | 
			
		||||
 | 
			
		||||
	return rc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// For Gitea
 | 
			
		||||
func (c *caller) setReusedWorkflowJobResult(jobName string, result string) {
 | 
			
		||||
	c.updateResultLock.Lock()
 | 
			
		||||
	defer c.updateResultLock.Unlock()
 | 
			
		||||
	c.reusedWorkflowJobResults[jobName] = result
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user