diff --git a/pkg/model/workflow.go b/pkg/model/workflow.go index 214927e..4e1d349 100644 --- a/pkg/model/workflow.go +++ b/pkg/model/workflow.go @@ -380,6 +380,42 @@ func commonKeysMatch2(a map[string]interface{}, b map[string]interface{}, m map[ return true } +// JobType describes what type of job we are about to run +type JobType int + +const ( + // StepTypeRun is all steps that have a `run` attribute + JobTypeDefault JobType = iota + + // StepTypeReusableWorkflowLocal is all steps that have a `uses` that is a local workflow in the .github/workflows directory + JobTypeReusableWorkflowLocal + + // JobTypeReusableWorkflowRemote is all steps that have a `uses` that references a workflow file in a github repo + JobTypeReusableWorkflowRemote +) + +func (j JobType) String() string { + switch j { + case JobTypeDefault: + return "default" + case JobTypeReusableWorkflowLocal: + return "local-reusable-workflow" + case JobTypeReusableWorkflowRemote: + return "remote-reusable-workflow" + } + return "unknown" +} + +// Type returns the type of the job +func (j *Job) Type() JobType { + if strings.HasPrefix(j.Uses, "./.github/workflows") && (strings.HasSuffix(j.Uses, ".yml") || strings.HasSuffix(j.Uses, ".yaml")) { + return JobTypeReusableWorkflowLocal + } else if !strings.HasPrefix(j.Uses, "./") && strings.Contains(j.Uses, ".github/workflows") && (strings.Contains(j.Uses, ".yml@") || strings.Contains(j.Uses, ".yaml@")) { + return JobTypeReusableWorkflowRemote + } + return JobTypeDefault +} + // ContainerSpec is the specification of the container to use for the job type ContainerSpec struct { Image string `yaml:"image"` @@ -486,6 +522,12 @@ const ( // StepTypeUsesActionRemote is all steps that have a `uses` that is a reference to a github repo StepTypeUsesActionRemote + // StepTypeReusableWorkflowLocal is all steps that have a `uses` that is a local workflow in the .github/workflows directory + StepTypeReusableWorkflowLocal + + // StepTypeReusableWorkflowRemote is all steps that have a `uses` that references a workflow file in a github repo + StepTypeReusableWorkflowRemote + // StepTypeInvalid is for steps that have invalid step action StepTypeInvalid ) @@ -502,6 +544,10 @@ func (s StepType) String() string { return "remote-action" case StepTypeUsesDockerURL: return "docker" + case StepTypeReusableWorkflowLocal: + return "local-reusable-workflow" + case StepTypeReusableWorkflowRemote: + return "remote-reusable-workflow" } return "unknown" } @@ -519,6 +565,10 @@ func (s *Step) Type() StepType { return StepTypeRun } else if strings.HasPrefix(s.Uses, "docker://") { return StepTypeUsesDockerURL + } else if strings.HasPrefix(s.Uses, "./.github/workflows") && (strings.HasSuffix(s.Uses, ".yml") || strings.HasSuffix(s.Uses, ".yaml")) { + return StepTypeReusableWorkflowLocal + } else if !strings.HasPrefix(s.Uses, "./") && strings.Contains(s.Uses, ".github/workflows") && (strings.Contains(s.Uses, ".yml@") || strings.Contains(s.Uses, ".yaml@")) { + return StepTypeReusableWorkflowRemote } else if strings.HasPrefix(s.Uses, "./") { return StepTypeUsesActionLocal } diff --git a/pkg/model/workflow_test.go b/pkg/model/workflow_test.go index 6d3b307..d978f16 100644 --- a/pkg/model/workflow_test.go +++ b/pkg/model/workflow_test.go @@ -138,6 +138,31 @@ jobs: }) } +func TestReadWorkflow_JobTypes(t *testing.T) { + yaml := ` +name: invalid job definition + +jobs: + default-job: + runs-on: ubuntu-latest + steps: + - run: echo + remote-reusable-workflow: + runs-on: ubuntu-latest + uses: remote/repo/.github/workflows/workflow.yml@main + local-reusable-workflow: + runs-on: ubuntu-latest + uses: ./.github/workflows/workflow.yml +` + + workflow, err := ReadWorkflow(strings.NewReader(yaml)) + assert.NoError(t, err, "read workflow should succeed") + assert.Len(t, workflow.Jobs, 3) + assert.Equal(t, workflow.Jobs["default-job"].Type(), JobTypeDefault) + assert.Equal(t, workflow.Jobs["remote-reusable-workflow"].Type(), JobTypeReusableWorkflowRemote) + assert.Equal(t, workflow.Jobs["local-reusable-workflow"].Type(), JobTypeReusableWorkflowLocal) +} + func TestReadWorkflow_StepsTypes(t *testing.T) { yaml := ` name: invalid step definition