161 lines
4.1 KiB
Go
161 lines
4.1 KiB
Go
package actions
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
|
|
"github.com/actions/workflow-parser/model"
|
|
"github.com/actions/workflow-parser/parser"
|
|
"github.com/nektos/act/common"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type runnerImpl struct {
|
|
config *RunnerConfig
|
|
workflowConfig *model.Configuration
|
|
tempDir string
|
|
eventJSON string
|
|
}
|
|
|
|
// NewRunner Creates a new Runner
|
|
func NewRunner(runnerConfig *RunnerConfig) (Runner, error) {
|
|
runner := &runnerImpl{
|
|
config: runnerConfig,
|
|
}
|
|
|
|
init := common.NewPipelineExecutor(
|
|
runner.setupTempDir,
|
|
runner.setupWorkingDir,
|
|
runner.setupWorkflows,
|
|
runner.setupEvent,
|
|
)
|
|
|
|
return runner, init()
|
|
}
|
|
|
|
func (runner *runnerImpl) setupTempDir() error {
|
|
var err error
|
|
runner.tempDir, err = ioutil.TempDir("", "act-")
|
|
return err
|
|
}
|
|
|
|
func (runner *runnerImpl) setupWorkingDir() error {
|
|
var err error
|
|
runner.config.WorkingDir, err = filepath.Abs(runner.config.WorkingDir)
|
|
log.Debugf("Setting working dir to %s", runner.config.WorkingDir)
|
|
return err
|
|
}
|
|
|
|
func (runner *runnerImpl) setupWorkflows() error {
|
|
runner.config.WorkflowPath = runner.resolvePath(runner.config.WorkflowPath)
|
|
log.Debugf("Loading workflow config from %s", runner.config.WorkflowPath)
|
|
workflowReader, err := os.Open(runner.config.WorkflowPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer workflowReader.Close()
|
|
|
|
runner.workflowConfig, err = parser.Parse(workflowReader)
|
|
return err
|
|
}
|
|
|
|
func (runner *runnerImpl) setupEvent() error {
|
|
runner.eventJSON = "{}"
|
|
if runner.config.EventPath != "" {
|
|
runner.config.EventPath = runner.resolvePath(runner.config.EventPath)
|
|
log.Debugf("Reading event.json from %s", runner.config.EventPath)
|
|
eventJSONBytes, err := ioutil.ReadFile(runner.config.EventPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
runner.eventJSON = string(eventJSONBytes)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (runner *runnerImpl) resolvePath(path string) string {
|
|
if path == "" {
|
|
return path
|
|
}
|
|
if !filepath.IsAbs(path) {
|
|
path = filepath.Join(runner.config.WorkingDir, path)
|
|
}
|
|
return path
|
|
}
|
|
|
|
// ListEvents gets all the events in the workflows file
|
|
func (runner *runnerImpl) ListEvents() []string {
|
|
log.Debugf("Listing all events")
|
|
events := make([]string, 0)
|
|
for _, w := range runner.workflowConfig.Workflows {
|
|
events = append(events, w.On)
|
|
}
|
|
|
|
// sort the list based on depth of dependencies
|
|
sort.Slice(events, func(i, j int) bool {
|
|
return events[i] < events[j]
|
|
})
|
|
|
|
return events
|
|
}
|
|
|
|
// GraphEvent builds an execution path
|
|
func (runner *runnerImpl) GraphEvent(eventName string) ([][]string, error) {
|
|
log.Debugf("Listing actions for event '%s'", eventName)
|
|
resolves := runner.resolveEvent(eventName)
|
|
return newExecutionGraph(runner.workflowConfig, resolves...), nil
|
|
}
|
|
|
|
// RunAction runs a set of actions in parallel, and their dependencies
|
|
func (runner *runnerImpl) RunActions(actionNames ...string) error {
|
|
log.Debugf("Running actions %+q", actionNames)
|
|
graph := newExecutionGraph(runner.workflowConfig, actionNames...)
|
|
|
|
pipeline := make([]common.Executor, 0)
|
|
for _, actions := range graph {
|
|
stage := make([]common.Executor, 0)
|
|
for _, actionName := range actions {
|
|
stage = append(stage, runner.newActionExecutor(actionName))
|
|
}
|
|
pipeline = append(pipeline, common.NewParallelExecutor(stage...))
|
|
}
|
|
|
|
executor := common.NewPipelineExecutor(pipeline...)
|
|
return executor()
|
|
}
|
|
|
|
// RunEvent runs the actions for a single event
|
|
func (runner *runnerImpl) RunEvent() error {
|
|
log.Debugf("Running event '%s'", runner.config.EventName)
|
|
resolves := runner.resolveEvent(runner.config.EventName)
|
|
log.Debugf("Running actions %s -> %s", runner.config.EventName, resolves)
|
|
return runner.RunActions(resolves...)
|
|
}
|
|
|
|
func (runner *runnerImpl) Close() error {
|
|
return os.RemoveAll(runner.tempDir)
|
|
}
|
|
|
|
// get list of resolves for an event
|
|
func (runner *runnerImpl) resolveEvent(eventName string) []string {
|
|
workflows := runner.workflowConfig.GetWorkflows(eventName)
|
|
resolves := make([]string, 0)
|
|
for _, workflow := range workflows {
|
|
for _, resolve := range workflow.Resolves {
|
|
found := false
|
|
for _, r := range resolves {
|
|
if r == resolve {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
resolves = append(resolves, resolve)
|
|
}
|
|
}
|
|
}
|
|
return resolves
|
|
}
|