123 lines
2.7 KiB
Go
123 lines
2.7 KiB
Go
package workflow
|
|
|
|
import (
|
|
"errors"
|
|
)
|
|
|
|
type Job struct {
|
|
RunsOn string `yaml:"runs-on"`
|
|
Steps []Step `yaml:"steps"`
|
|
Needs []string `yaml:"needs"`
|
|
// Job name; this isn't guaranteed to be unique.
|
|
Name string `yaml:"name"`
|
|
Defaults struct {
|
|
Run struct {
|
|
WorkingDirectory string `yaml:"working-directory"`
|
|
} `yaml:"run"`
|
|
} `yaml:"defaults"`
|
|
}
|
|
|
|
func (j Job) Validate() []error {
|
|
validationErrors := []error{}
|
|
|
|
if j.RunsOn == "" {
|
|
validationErrors = append(validationErrors, errors.New("Missing \"runs-on\" field on job."))
|
|
}
|
|
|
|
if len(j.Steps) == 0 {
|
|
validationErrors = append(validationErrors, errors.New("Missing \"steps\" field on job."))
|
|
}
|
|
|
|
for _, step := range j.Steps {
|
|
validationErrors = append(validationErrors, step.Validate()...)
|
|
}
|
|
|
|
return validationErrors
|
|
}
|
|
|
|
type Step struct {
|
|
Run string `yaml:"run"`
|
|
WorkingDirectory string `yaml:"working-directory"`
|
|
}
|
|
|
|
func (s Step) Validate() []error {
|
|
validationErrors := []error{}
|
|
|
|
if s.Run == "" {
|
|
validationErrors = append(validationErrors, errors.New("Missing \"run\" field on step."))
|
|
}
|
|
|
|
return validationErrors
|
|
}
|
|
|
|
type Workflow struct {
|
|
SourcePath string
|
|
Jobs map[string]Job `yaml:"jobs"`
|
|
}
|
|
|
|
// Returns the given workflow's job+step working directory inside the container
|
|
// that runs the job.
|
|
//
|
|
// Values considered, in order:
|
|
// - Step working-directory;
|
|
// - Job default run working-directory
|
|
func (w Workflow) GetWorkingDirectory(jobName string, stepIndex int) string {
|
|
jobDefinition := w.Jobs[jobName]
|
|
stepDefinition := jobDefinition.Steps[stepIndex]
|
|
|
|
if stepDefinition.WorkingDirectory != "" {
|
|
return stepDefinition.WorkingDirectory
|
|
}
|
|
|
|
if jobDefinition.Defaults.Run.WorkingDirectory != "" {
|
|
return jobDefinition.Defaults.Run.WorkingDirectory
|
|
}
|
|
|
|
return "."
|
|
}
|
|
|
|
func (w Workflow) Validate() []error {
|
|
validationErrors := []error{}
|
|
|
|
if len(w.Jobs) == 0 {
|
|
validationErrors = append(validationErrors, errors.New("Missing \"jobs\" field on workflow."))
|
|
}
|
|
|
|
for _, job := range w.Jobs {
|
|
validationErrors = append(validationErrors, job.Validate()...)
|
|
}
|
|
|
|
return validationErrors
|
|
}
|
|
|
|
// Creates a deterministic, ordered collection of jobs that respects
|
|
// the jobs's dependencies.
|
|
func (w Workflow) GetJobsAsGroups() [][]Job {
|
|
dependenciesMap := map[string][]string{}
|
|
|
|
for jobLabel, job := range w.Jobs {
|
|
if len(job.Needs) == 0 {
|
|
dependenciesMap[""] = append(dependenciesMap[""], jobLabel)
|
|
}
|
|
|
|
for _, need := range job.Needs {
|
|
dependenciesMap[need] = append(dependenciesMap[need], jobLabel)
|
|
}
|
|
}
|
|
|
|
levels := SplitFlatTreeIntoGroups(dependenciesMap)
|
|
|
|
groups := [][]Job{}
|
|
|
|
for _, jobLabels := range levels {
|
|
jobs := []Job{}
|
|
|
|
for _, jobLabel := range jobLabels {
|
|
jobs = append(jobs, w.Jobs[jobLabel])
|
|
}
|
|
|
|
groups = append(groups, jobs)
|
|
}
|
|
|
|
return groups
|
|
}
|