fix: show workflow info even if on.push is not defined (#1329) (#1335)

* fix: show workflow info even if on.push is not defined (#1329)

To fix listing of workflows in such cases list/graph filtering was split with planning.

Now act supports one of the following list (-l)/graph (-g) cases:
* show all jobs of loaded workflows: act -l
* show specific job JOBNAME: act -l -j JOBNAME
* show jobs of loaded workflows in which event EVENTNAME is set up: act -l EVENTNAME
* show jobs of loaded workflows in which first defined workflow event is set up: act -l --detect-event

For planning it supports:
* running specific job JOBNAME with triggered event determined from:
** CLI argument: act -j JOBNAME EVENTNAME
** first defined in loaded workflows event: act -j  JOBNAME --detect-event
** only defined in loaded workflows event: act -j JOBNAME
** push event by default: act -j JOBNAME

*  running jobs of loaded workflows in which event is set up, event is determined from:
** CLI argument: act EVENTNAME
** first defined in loaded workflows event: act --detect-event
** only defined in loaded workflows event: act
** push event by default: act

Except #1329 this PR fixes #1332, #1318

* Update docs/help
This commit is contained in:
Alex Savchuk 2022-09-29 08:59:52 +03:00 committed by GitHub
parent 13d530302e
commit 21484b5c1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 34 deletions

View file

@ -128,13 +128,17 @@ Download the [latest release](https://github.com/nektos/act/releases/latest) and
# Command structure:
act [<event>] [options]
If no event name passed, will default to "on: push"
If actions handles only one event it will be used as default instead of "on: push"
# List the actions for the default event:
# List all actions for all events:
act -l
# List the actions for a specific event:
act workflow_dispatch -l
# List the actions for a specific job:
act -j test -l
# Run the default (`push`) event:
act

View file

@ -30,7 +30,7 @@ import (
func Execute(ctx context.Context, version string) {
input := new(Input)
var rootCmd = &cobra.Command{
Use: "act [event name to run]\nIf no event name passed, will default to \"on: push\"",
Use: "act [event name to run] [flags]\n\nIf no event name passed, will default to \"on: push\"\nIf actions handles only one event it will be used as default instead of \"on: push\"",
Short: "Run GitHub actions locally by specifying the event name (e.g. `push`) or an action name directly.",
Args: cobra.MaximumNArgs(1),
RunE: newRunCommand(ctx, input),
@ -304,46 +304,90 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
return err
}
// Determine the event name
var eventName string
events := planner.GetEvents()
if input.autodetectEvent && len(events) > 0 {
// set default event type to first event
// this way user dont have to specify the event.
log.Debugf("Using detected workflow event: %s", events[0])
eventName = events[0]
} else {
if len(args) > 0 {
eventName = args[0]
} else if plan := planner.PlanEvent("push"); plan != nil {
eventName = "push"
}
}
// build the plan for this run
var plan *model.Plan
if jobID, err := cmd.Flags().GetString("job"); err != nil {
jobID, err := cmd.Flags().GetString("job")
if err != nil {
return err
} else if jobID != "" {
log.Debugf("Planning job: %s", jobID)
plan = planner.PlanJob(jobID)
} else {
log.Debugf("Planning event: %s", eventName)
plan = planner.PlanEvent(eventName)
}
// check if we should just list the workflows
if list, err := cmd.Flags().GetBool("list"); err != nil {
list, err := cmd.Flags().GetBool("list")
if err != nil {
return err
} else if list {
return printList(plan)
}
// check if we should just print the graph
if list, err := cmd.Flags().GetBool("graph"); err != nil {
// check if we should just draw the graph
graph, err := cmd.Flags().GetBool("graph")
if err != nil {
return err
} else if list {
return drawGraph(plan)
}
// collect all events from loaded workflows
events := planner.GetEvents()
// plan with filtered jobs - to be used for filtering only
var filterPlan *model.Plan
// Determine the event name to be filtered
var filterEventName string = ""
if len(args) > 0 {
log.Debugf("Using first passed in arguments event for filtering: %s", args[0])
filterEventName = args[0]
} else if input.autodetectEvent && len(events) > 0 && len(events[0]) > 0 {
// set default event type to first event from many available
// this way user dont have to specify the event.
log.Debugf("Using first detected workflow event for filtering: %s", events[0])
filterEventName = events[0]
}
if jobID != "" {
log.Debugf("Preparing plan with a job: %s", jobID)
filterPlan = planner.PlanJob(jobID)
} else if filterEventName != "" {
log.Debugf("Preparing plan for a event: %s", filterEventName)
filterPlan = planner.PlanEvent(filterEventName)
} else {
log.Debugf("Preparing plan with all jobs")
filterPlan = planner.PlanAll()
}
if list {
return printList(filterPlan)
}
if graph {
return drawGraph(filterPlan)
}
// plan with triggered jobs
var plan *model.Plan
// Determine the event name to be triggered
var eventName string
if len(args) > 0 {
log.Debugf("Using first passed in arguments event: %s", args[0])
eventName = args[0]
} else if len(events) == 1 && len(events[0]) > 0 {
log.Debugf("Using the only detected workflow event: %s", events[0])
eventName = events[0]
} else if input.autodetectEvent && len(events) > 0 && len(events[0]) > 0 {
// set default event type to first event from many available
// this way user dont have to specify the event.
log.Debugf("Using first detected workflow event: %s", events[0])
eventName = events[0]
} else {
log.Debugf("Using default workflow event: push")
eventName = "push"
}
// build the plan for this run
if jobID != "" {
log.Debugf("Planning job: %s", jobID)
plan = planner.PlanJob(jobID)
} else {
log.Debugf("Planning jobs for event: %s", eventName)
plan = planner.PlanEvent(eventName)
}
// check to see if the main branch was defined

View file

@ -17,6 +17,7 @@ import (
type WorkflowPlanner interface {
PlanEvent(eventName string) *Plan
PlanJob(jobName string) *Plan
PlanAll() *Plan
GetEvents() []string
}
@ -196,6 +197,20 @@ func (wp *workflowPlanner) PlanJob(jobName string) *Plan {
return plan
}
// PlanAll builds a new run to execute in parallel all
func (wp *workflowPlanner) PlanAll() *Plan {
plan := new(Plan)
if len(wp.workflows) == 0 {
log.Debugf("no jobs found for loaded workflows")
}
for _, w := range wp.workflows {
plan.mergeStages(createStages(w, w.GetJobIDs()...))
}
return plan
}
// GetEvents gets all the events in the workflows file
func (wp *workflowPlanner) GetEvents() []string {
events := make([]string, 0)