2019-01-12 22:45:25 -06:00
package cmd
import (
2020-02-25 00:11:33 -06:00
"bufio"
2019-01-12 22:45:25 -06:00
"context"
2022-03-22 14:26:10 -05:00
"fmt"
2019-01-12 22:45:25 -06:00
"os"
2019-02-09 20:39:09 -06:00
"path/filepath"
2020-03-02 10:11:46 -06:00
"regexp"
2021-06-23 13:09:27 -05:00
"runtime"
2020-02-25 00:11:33 -06:00
"strings"
2019-01-12 22:45:25 -06:00
2021-01-19 08:30:17 -06:00
"github.com/AlecAivazis/survey/v2"
2021-01-12 00:39:43 -06:00
"github.com/andreaskoch/go-fswatch"
2020-03-06 14:30:24 -06:00
"github.com/joho/godotenv"
2021-04-05 10:51:13 -05:00
"github.com/mitchellh/go-homedir"
2019-02-09 20:39:09 -06:00
gitignore "github.com/sabhiram/go-gitignore"
2019-01-12 22:45:25 -06:00
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
2021-01-19 08:30:17 -06:00
2021-11-10 11:57:22 -06:00
"github.com/nektos/act/pkg/artifacts"
2021-06-23 13:09:27 -05:00
"github.com/nektos/act/pkg/common"
2022-03-22 14:26:10 -05:00
"github.com/nektos/act/pkg/container"
2021-01-19 08:30:17 -06:00
"github.com/nektos/act/pkg/model"
"github.com/nektos/act/pkg/runner"
2019-01-12 22:45:25 -06:00
)
// Execute is the entry point to running the CLI
func Execute ( ctx context . Context , version string ) {
2020-02-04 18:38:41 -06:00
input := new ( Input )
2019-01-12 22:45:25 -06:00
var rootCmd = & cobra . Command {
2021-01-18 13:42:55 -06:00
Use : "act [event name to run]\nIf no event name passed, will default to \"on: push\"" ,
2021-03-30 14:26:25 -05:00
Short : "Run GitHub actions locally by specifying the event name (e.g. `push`) or an action name directly." ,
2019-01-17 02:15:35 -06:00
Args : cobra . MaximumNArgs ( 1 ) ,
2020-02-04 18:38:41 -06:00
RunE : newRunCommand ( ctx , input ) ,
2019-01-17 02:15:35 -06:00
PersistentPreRun : setupLogging ,
Version : version ,
SilenceUsage : true ,
2019-01-12 22:45:25 -06:00
}
2019-02-09 20:39:09 -06:00
rootCmd . Flags ( ) . BoolP ( "watch" , "w" , false , "watch the contents of the local repo and run when files change" )
2020-02-04 18:38:41 -06:00
rootCmd . Flags ( ) . BoolP ( "list" , "l" , false , "list workflows" )
2020-10-12 12:26:22 -05:00
rootCmd . Flags ( ) . BoolP ( "graph" , "g" , false , "draw workflows" )
2020-02-04 18:38:41 -06:00
rootCmd . Flags ( ) . StringP ( "job" , "j" , "" , "run job" )
2022-03-22 14:26:10 -05:00
rootCmd . Flags ( ) . BoolP ( "bug-report" , "" , false , "Display system information for bug report" )
2020-02-17 23:51:49 -06:00
rootCmd . Flags ( ) . StringArrayVarP ( & input . secrets , "secret" , "s" , [ ] string { } , "secret to make available to actions with optional value (e.g. -s mysecret=foo or -s mysecret)" )
2021-06-10 18:12:05 -05:00
rootCmd . Flags ( ) . StringArrayVarP ( & input . envs , "env" , "" , [ ] string { } , "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)" )
2020-02-19 21:16:40 -06:00
rootCmd . Flags ( ) . StringArrayVarP ( & input . platforms , "platform" , "P" , [ ] string { } , "custom image to use per platform (e.g. -P ubuntu-18.04=nektos/act-environments-ubuntu:18.04)" )
2021-12-15 23:11:56 -06:00
rootCmd . Flags ( ) . BoolVarP ( & input . reuseContainers , "reuse" , "r" , false , "don't remove container(s) on successfully completed workflow(s) to maintain state between runs" )
2020-02-24 19:48:21 -06:00
rootCmd . Flags ( ) . BoolVarP ( & input . bindWorkdir , "bind" , "b" , false , "bind working directory to container, rather than copy" )
2021-03-30 14:26:25 -05:00
rootCmd . Flags ( ) . BoolVarP ( & input . forcePull , "pull" , "p" , false , "pull docker image(s) even if already present" )
2021-11-24 09:51:37 -06:00
rootCmd . Flags ( ) . BoolVarP ( & input . forceRebuild , "rebuild" , "" , false , "rebuild local action docker image(s) even if already present" )
2021-01-18 13:42:55 -06:00
rootCmd . Flags ( ) . BoolVarP ( & input . autodetectEvent , "detect-event" , "" , false , "Use first event type from workflow as event that triggered the workflow" )
2020-02-17 23:51:49 -06:00
rootCmd . Flags ( ) . StringVarP ( & input . eventPath , "eventpath" , "e" , "" , "path to event JSON file" )
2020-09-02 09:56:44 -05:00
rootCmd . Flags ( ) . StringVar ( & input . defaultBranch , "defaultbranch" , "" , "the name of the main branch" )
2020-08-01 15:21:49 -05:00
rootCmd . Flags ( ) . BoolVar ( & input . privileged , "privileged" , false , "use privileged mode" )
2021-02-27 10:31:25 -06:00
rootCmd . Flags ( ) . StringVar ( & input . usernsMode , "userns" , "" , "user namespace to use" )
2021-05-03 09:37:20 -05:00
rootCmd . Flags ( ) . BoolVar ( & input . useGitIgnore , "use-gitignore" , true , "Controls whether paths specified in .gitignore should be copied into container" )
2021-06-04 11:06:59 -05:00
rootCmd . Flags ( ) . StringArrayVarP ( & input . containerCapAdd , "container-cap-add" , "" , [ ] string { } , "kernel capabilities to add to the workflow containers (e.g. --container-cap-add SYS_PTRACE)" )
rootCmd . Flags ( ) . StringArrayVarP ( & input . containerCapDrop , "container-cap-drop" , "" , [ ] string { } , "kernel capabilities to remove from the workflow containers (e.g. --container-cap-drop SYS_PTRACE)" )
2021-12-15 23:11:56 -06:00
rootCmd . Flags ( ) . BoolVar ( & input . autoRemove , "rm" , false , "automatically remove container(s)/volume(s) after a workflow(s) failure" )
2020-05-12 02:14:56 -05:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . actor , "actor" , "a" , "nektos/act" , "user that triggered the event" )
2020-05-26 22:29:50 -05:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . workflowsPath , "workflows" , "W" , "./.github/workflows/" , "path to workflow file(s)" )
2021-05-03 09:57:24 -05:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & input . noWorkflowRecurse , "no-recurse" , "" , false , "Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag" )
2020-02-07 00:17:58 -06:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . workdir , "directory" , "C" , "." , "working directory" )
2019-01-17 02:15:35 -06:00
rootCmd . PersistentFlags ( ) . BoolP ( "verbose" , "v" , false , "verbose output" )
2022-03-14 10:33:11 -05:00
rootCmd . PersistentFlags ( ) . BoolVar ( & input . jsonLogger , "json" , false , "Output logs in json format" )
2020-02-20 10:57:18 -06:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & input . noOutput , "quiet" , "q" , false , "disable logging of output from steps" )
2020-02-04 18:38:41 -06:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & input . dryrun , "dryrun" , "n" , false , "dryrun mode" )
2021-01-19 08:31:46 -06:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . secretfile , "secret-file" , "" , ".secrets" , "file with list of secrets to read from (e.g. --secret-file .secrets)" )
2021-01-12 00:28:45 -06:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & input . insecureSecrets , "insecure-secrets" , "" , false , "NOT RECOMMENDED! Doesn't hide secrets while printing logs." )
2020-04-17 12:04:40 -05:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . envfile , "env-file" , "" , ".env" , "environment file to read and use as env in the containers" )
2021-05-02 10:15:13 -05:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . containerArchitecture , "container-architecture" , "" , "" , "Architecture which should be used to run containers, e.g.: linux/amd64. If not specified, will use host default architecture. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms." )
2021-05-23 09:43:09 -05:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . containerDaemonSocket , "container-daemon-socket" , "" , "/var/run/docker.sock" , "Path to Docker daemon socket which will be mounted to containers" )
2021-05-05 11:42:34 -05:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . githubInstance , "github-instance" , "" , "github.com" , "GitHub instance to use. Don't use this if you are not using GitHub Enterprise Server." )
2021-11-10 11:57:22 -06:00
rootCmd . PersistentFlags ( ) . StringVarP ( & input . artifactServerPath , "artifact-server-path" , "" , "" , "Defines the path where the artifact server stores uploads and retrieves downloads from. If not specified the artifact server will not start." )
rootCmd . PersistentFlags ( ) . StringVarP ( & input . artifactServerPort , "artifact-server-port" , "" , "34567" , "Defines the port where the artifact server listens (will only bind to localhost)." )
2022-03-21 06:23:06 -05:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & input . noSkipCheckout , "no-skip-checkout" , "" , false , "Do not skip actions/checkout" )
2020-02-25 00:11:33 -06:00
rootCmd . SetArgs ( args ( ) )
2020-03-06 14:30:24 -06:00
2019-01-12 22:45:25 -06:00
if err := rootCmd . Execute ( ) ; err != nil {
os . Exit ( 1 )
}
}
2021-04-05 10:51:13 -05:00
func configLocations ( ) [ ] string {
home , err := homedir . Dir ( )
if err != nil {
log . Fatal ( err )
}
// reference: https://specifications.freedesktop.org/basedir-spec/latest/ar01s03.html
var actrcXdg string
if xdg , ok := os . LookupEnv ( "XDG_CONFIG_HOME" ) ; ok && xdg != "" {
actrcXdg = filepath . Join ( xdg , ".actrc" )
} else {
actrcXdg = filepath . Join ( home , ".config" , ".actrc" )
}
return [ ] string {
filepath . Join ( home , ".actrc" ) ,
actrcXdg ,
2021-01-19 08:30:17 -06:00
filepath . Join ( "." , ".actrc" ) ,
}
2021-04-05 10:51:13 -05:00
}
func args ( ) [ ] string {
actrc := configLocations ( )
args := make ( [ ] string , 0 )
2021-01-19 08:30:17 -06:00
for _ , f := range actrc {
2022-03-22 14:26:10 -05:00
args = append ( args , readArgsFile ( f , true ) ... )
2020-02-25 00:11:33 -06:00
}
2021-04-05 10:51:13 -05:00
2020-02-25 00:11:33 -06:00
args = append ( args , os . Args [ 1 : ] ... )
return args
}
2022-03-22 14:26:10 -05:00
func bugReport ( ctx context . Context , version string ) error {
var commonSocketPaths = [ ] string {
"/var/run/docker.sock" ,
"/var/run/podman/podman.sock" ,
"$HOME/.colima/docker.sock" ,
"$XDG_RUNTIME_DIR/docker.sock" ,
` \\.\pipe\docker_engine ` ,
}
sprintf := func ( key , val string ) string {
return fmt . Sprintf ( "%-24s%s\n" , key , val )
}
report := sprintf ( "act version:" , version )
report += sprintf ( "GOOS:" , runtime . GOOS )
report += sprintf ( "GOARCH:" , runtime . GOARCH )
report += sprintf ( "NumCPU:" , fmt . Sprint ( runtime . NumCPU ( ) ) )
var dockerHost string
if dockerHost = os . Getenv ( "DOCKER_HOST" ) ; dockerHost == "" {
dockerHost = "DOCKER_HOST environment variable is unset/empty."
}
report += sprintf ( "Docker host:" , dockerHost )
report += fmt . Sprintln ( "Sockets found:" )
for _ , p := range commonSocketPaths {
if strings . HasPrefix ( p , ` $ ` ) {
v := strings . Split ( p , ` / ` ) [ 0 ]
p = strings . Replace ( p , v , os . Getenv ( strings . TrimPrefix ( v , ` $ ` ) ) , 1 )
}
if _ , err := os . Stat ( p ) ; err != nil {
continue
} else {
report += fmt . Sprintf ( "\t%s\n" , p )
}
}
info , err := container . GetHostInfo ( ctx )
if err != nil {
fmt . Println ( report )
return err
}
report += sprintf ( "Config files:" , "" )
for _ , c := range configLocations ( ) {
args := readArgsFile ( c , false )
if len ( args ) > 0 {
report += fmt . Sprintf ( "\t%s:\n" , c )
for _ , l := range args {
report += fmt . Sprintf ( "\t\t%s\n" , l )
}
}
}
report += fmt . Sprintln ( "Docker Engine:" )
report += sprintf ( "\tEngine version:" , info . ServerVersion )
report += sprintf ( "\tEngine runtime:" , info . DefaultRuntime )
report += sprintf ( "\tCgroup version:" , info . CgroupVersion )
report += sprintf ( "\tCgroup driver:" , info . CgroupDriver )
report += sprintf ( "\tStorage driver:" , info . Driver )
report += sprintf ( "\tRegistry URI:" , info . IndexServerAddress )
report += sprintf ( "\tOS:" , info . OperatingSystem )
report += sprintf ( "\tOS type:" , info . OSType )
report += sprintf ( "\tOS version:" , info . OSVersion )
report += sprintf ( "\tOS arch:" , info . Architecture )
report += sprintf ( "\tOS kernel:" , info . KernelVersion )
report += sprintf ( "\tOS CPU:" , fmt . Sprint ( info . NCPU ) )
report += sprintf ( "\tOS memory:" , fmt . Sprintf ( "%d MB" , info . MemTotal / 1024 / 1024 ) )
report += fmt . Sprintln ( "\tSecurity options:" )
for _ , secopt := range info . SecurityOptions {
report += fmt . Sprintf ( "\t\t%s\n" , secopt )
}
fmt . Println ( report )
return nil
}
func readArgsFile ( file string , split bool ) [ ] string {
2020-02-25 00:11:33 -06:00
args := make ( [ ] string , 0 )
f , err := os . Open ( file )
if err != nil {
return args
}
2021-01-12 00:39:43 -06:00
defer func ( ) {
err := f . Close ( )
if err != nil {
log . Errorf ( "Failed to close args file: %v" , err )
}
} ( )
2020-02-25 00:11:33 -06:00
scanner := bufio . NewScanner ( f )
for scanner . Scan ( ) {
2022-03-02 15:41:57 -06:00
arg := strings . TrimSpace ( scanner . Text ( ) )
2022-03-22 14:26:10 -05:00
if strings . HasPrefix ( arg , "-" ) && split {
2020-03-02 10:11:46 -06:00
args = append ( args , regexp . MustCompile ( ` \s ` ) . Split ( arg , 2 ) ... )
2022-03-22 14:26:10 -05:00
} else if ! split {
args = append ( args , arg )
2020-02-25 00:11:33 -06:00
}
}
return args
}
2021-01-12 00:39:43 -06:00
func setupLogging ( cmd * cobra . Command , _ [ ] string ) {
2019-01-17 02:15:35 -06:00
verbose , _ := cmd . Flags ( ) . GetBool ( "verbose" )
if verbose {
log . SetLevel ( log . DebugLevel )
}
}
2020-04-17 12:04:40 -05:00
func readEnvs ( path string , envs map [ string ] string ) bool {
if _ , err := os . Stat ( path ) ; err == nil {
env , err := godotenv . Read ( path )
if err != nil {
log . Fatalf ( "Error loading from %s: %v" , path , err )
}
for k , v := range env {
envs [ k ] = v
}
return true
}
return false
}
2021-05-06 08:30:12 -05:00
//nolint:gocyclo
2020-02-04 18:38:41 -06:00
func newRunCommand ( ctx context . Context , input * Input ) func ( * cobra . Command , [ ] string ) error {
2019-01-12 22:45:25 -06:00
return func ( cmd * cobra . Command , args [ ] string ) error {
2022-03-14 10:33:11 -05:00
if input . jsonLogger {
log . SetFormatter ( & log . JSONFormatter { } )
}
2022-03-22 14:26:10 -05:00
if ok , _ := cmd . Flags ( ) . GetBool ( "bug-report" ) ; ok {
return bugReport ( ctx , cmd . Version )
}
2021-06-23 13:09:27 -05:00
if runtime . GOOS == "darwin" && runtime . GOARCH == "arm64" && input . containerArchitecture == "" {
l := log . New ( )
l . SetFormatter ( & log . TextFormatter {
DisableQuote : true ,
DisableTimestamp : true ,
} )
l . Warnf ( " \U000026A0 You are using Apple M1 chip and you have not specified container architecture, you might encounter issues while running act. If so, try running it with '--container-architecture linux/amd64'. \U000026A0 \n" )
}
2020-04-17 12:04:40 -05:00
log . Debugf ( "Loading environment from %s" , input . Envfile ( ) )
envs := make ( map [ string ] string )
2021-01-14 23:26:01 -06:00
if input . envs != nil {
for _ , envVar := range input . envs {
e := strings . SplitN ( envVar , ` = ` , 2 )
if len ( e ) == 2 {
envs [ e [ 0 ] ] = e [ 1 ]
} else {
envs [ e [ 0 ] ] = ""
}
}
}
2020-04-17 12:04:40 -05:00
_ = readEnvs ( input . Envfile ( ) , envs )
log . Debugf ( "Loading secrets from %s" , input . Secretfile ( ) )
secrets := newSecrets ( input . secrets )
_ = readEnvs ( input . Secretfile ( ) , secrets )
2020-03-06 14:30:24 -06:00
2021-05-03 09:57:24 -05:00
planner , err := model . NewWorkflowPlanner ( input . WorkflowsPath ( ) , input . noWorkflowRecurse )
2019-01-17 02:15:35 -06:00
if err != nil {
return err
}
2020-02-04 18:38:41 -06:00
// Determine the event name
var eventName string
2021-01-18 13:42:55 -06:00
events := planner . GetEvents ( )
if input . autodetectEvent && len ( events ) > 0 {
2021-01-29 08:40:13 -06:00
// set default event type to first event
2020-02-04 18:38:41 -06:00
// this way user dont have to specify the event.
2020-02-10 18:53:14 -06:00
log . Debugf ( "Using detected workflow event: %s" , events [ 0 ] )
eventName = events [ 0 ]
2021-01-18 13:42:55 -06:00
} else {
if len ( args ) > 0 {
eventName = args [ 0 ]
} else if plan := planner . PlanEvent ( "push" ) ; plan != nil {
eventName = "push"
}
2019-01-12 22:45:25 -06:00
}
2019-02-09 20:39:09 -06:00
2020-02-04 18:38:41 -06:00
// build the plan for this run
var plan * model . Plan
if jobID , err := cmd . Flags ( ) . GetString ( "job" ) ; 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 )
2019-02-15 10:34:19 -06:00
}
2020-10-12 12:26:22 -05:00
// check if we should just list the workflows
2020-02-04 18:38:41 -06:00
if list , err := cmd . Flags ( ) . GetBool ( "list" ) ; err != nil {
return err
2020-10-12 12:26:22 -05:00
} else if list {
return printList ( plan )
}
// check if we should just print the graph
if list , err := cmd . Flags ( ) . GetBool ( "graph" ) ; err != nil {
return err
2020-02-04 18:38:41 -06:00
} else if list {
return drawGraph ( plan )
}
2019-02-15 10:34:19 -06:00
2020-09-02 09:56:44 -05:00
// check to see if the main branch was defined
defaultbranch , err := cmd . Flags ( ) . GetString ( "defaultbranch" )
if err != nil {
return err
}
2021-04-05 10:51:13 -05:00
// Check if platforms flag is set, if not, run default image survey
2021-01-29 08:40:13 -06:00
if len ( input . platforms ) == 0 {
2021-04-05 10:51:13 -05:00
cfgFound := false
cfgLocations := configLocations ( )
for _ , v := range cfgLocations {
_ , err := os . Stat ( v )
if os . IsExist ( err ) {
cfgFound = true
2021-01-29 08:40:13 -06:00
}
2021-04-05 10:51:13 -05:00
}
if ! cfgFound && len ( cfgLocations ) > 0 {
if err := defaultImageSurvey ( cfgLocations [ 0 ] ) ; err != nil {
2021-01-29 08:40:13 -06:00
log . Fatal ( err )
}
2022-03-22 14:26:10 -05:00
input . platforms = readArgsFile ( cfgLocations [ 0 ] , true )
2021-01-29 08:40:13 -06:00
}
}
2020-02-04 18:38:41 -06:00
// run the plan
2020-02-07 00:17:58 -06:00
config := & runner . Config {
2021-03-28 23:08:40 -05:00
Actor : input . actor ,
EventName : eventName ,
EventPath : input . EventPath ( ) ,
DefaultBranch : defaultbranch ,
ForcePull : input . forcePull ,
2021-11-24 09:51:37 -06:00
ForceRebuild : input . forceRebuild ,
2021-03-28 23:08:40 -05:00
ReuseContainers : input . reuseContainers ,
Workdir : input . Workdir ( ) ,
BindWorkdir : input . bindWorkdir ,
LogOutput : ! input . noOutput ,
2022-03-14 10:33:11 -05:00
JSONLogger : input . jsonLogger ,
2021-03-28 23:08:40 -05:00
Env : envs ,
Secrets : secrets ,
InsecureSecrets : input . insecureSecrets ,
Platforms : input . newPlatforms ( ) ,
Privileged : input . privileged ,
UsernsMode : input . usernsMode ,
ContainerArchitecture : input . containerArchitecture ,
2021-05-23 09:43:09 -05:00
ContainerDaemonSocket : input . containerDaemonSocket ,
2021-05-03 09:37:20 -05:00
UseGitIgnore : input . useGitIgnore ,
2021-05-05 11:42:34 -05:00
GitHubInstance : input . githubInstance ,
2021-06-04 11:06:59 -05:00
ContainerCapAdd : input . containerCapAdd ,
ContainerCapDrop : input . containerCapDrop ,
2021-06-10 10:09:05 -05:00
AutoRemove : input . autoRemove ,
2021-11-10 11:57:22 -06:00
ArtifactServerPath : input . artifactServerPath ,
ArtifactServerPort : input . artifactServerPort ,
2022-03-21 06:23:06 -05:00
NoSkipCheckout : input . noSkipCheckout ,
2020-02-07 00:17:58 -06:00
}
2021-01-12 00:39:43 -06:00
r , err := runner . New ( config )
2020-02-07 00:17:58 -06:00
if err != nil {
return err
}
2021-11-10 11:57:22 -06:00
cancel := artifacts . Serve ( ctx , input . artifactServerPath , input . artifactServerPort )
2020-02-07 00:17:58 -06:00
ctx = common . WithDryrun ( ctx , input . dryrun )
if watch , err := cmd . Flags ( ) . GetBool ( "watch" ) ; err != nil {
return err
} else if watch {
2021-01-12 00:39:43 -06:00
return watchAndRun ( ctx , r . NewPlanExecutor ( plan ) )
2020-02-07 00:17:58 -06:00
}
2021-11-10 11:57:22 -06:00
executor := r . NewPlanExecutor ( plan ) . Finally ( func ( ctx context . Context ) error {
cancel ( )
return nil
} )
return executor ( ctx )
2019-02-09 20:39:09 -06:00
}
}
2021-04-05 10:51:13 -05:00
func defaultImageSurvey ( actrc string ) error {
var answer string
confirmation := & survey . Select {
Message : "Please choose the default image you want to use with act:\n\n - Large size image: +20GB Docker image, includes almost all tools used on GitHub Actions (IMPORTANT: currently only ubuntu-18.04 platform is available)\n - Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with all actions\n - Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions\n\nDefault image and other options can be changed manually in ~/.actrc (please refer to https://github.com/nektos/act#configuration for additional information about file structure)" ,
Help : "If you want to know why act asks you that, please go to https://github.com/nektos/act/issues/107" ,
Default : "Medium" ,
Options : [ ] string { "Large" , "Medium" , "Micro" } ,
}
err := survey . AskOne ( confirmation , & answer )
if err != nil {
return err
}
var option string
switch answer {
case "Large" :
2021-08-09 11:07:26 -05:00
option = "-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:full-latest\n-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:full-20.04\n-P ubuntu-18.04=ghcr.io/catthehacker/ubuntu:full-18.04\n"
2021-04-05 10:51:13 -05:00
case "Medium" :
2021-09-22 14:43:58 -05:00
option = "-P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest\n-P ubuntu-20.04=ghcr.io/catthehacker/ubuntu:act-20.04\n-P ubuntu-18.04=ghcr.io/catthehacker/ubuntu:act-18.04\n"
2021-04-05 10:51:13 -05:00
case "Micro" :
2021-12-22 13:34:18 -06:00
option = "-P ubuntu-latest=node:16-buster-slim\n-P ubuntu-20.04=node:16-buster-slim\n-P ubuntu-18.04=node:16-buster-slim\n"
2021-04-05 10:51:13 -05:00
}
f , err := os . Create ( actrc )
if err != nil {
return err
}
_ , err = f . WriteString ( option )
if err != nil {
_ = f . Close ( )
return err
}
err = f . Close ( )
if err != nil {
return err
}
return nil
}
2020-02-07 00:17:58 -06:00
func watchAndRun ( ctx context . Context , fn common . Executor ) error {
2019-02-09 20:39:09 -06:00
recurse := true
checkIntervalInSeconds := 2
dir , err := os . Getwd ( )
if err != nil {
return err
}
var ignore * gitignore . GitIgnore
if _ , err := os . Stat ( filepath . Join ( dir , ".gitignore" ) ) ; ! os . IsNotExist ( err ) {
ignore , _ = gitignore . CompileIgnoreFile ( filepath . Join ( dir , ".gitignore" ) )
} else {
ignore = & gitignore . GitIgnore { }
}
folderWatcher := fswatch . NewFolderWatcher (
dir ,
recurse ,
ignore . MatchesPath ,
checkIntervalInSeconds ,
)
folderWatcher . Start ( )
go func ( ) {
for folderWatcher . IsRunning ( ) {
2020-02-07 00:17:58 -06:00
if err = fn ( ctx ) ; err != nil {
2019-02-12 22:32:54 -06:00
break
}
log . Debugf ( "Watching %s for changes" , dir )
2019-02-09 20:39:09 -06:00
for changes := range folderWatcher . ChangeDetails ( ) {
log . Debugf ( "%s" , changes . String ( ) )
2020-02-07 00:17:58 -06:00
if err = fn ( ctx ) ; err != nil {
2019-02-12 22:32:54 -06:00
break
}
2019-02-09 20:39:09 -06:00
log . Debugf ( "Watching %s for changes" , dir )
}
}
} ( )
<- ctx . Done ( )
folderWatcher . Stop ( )
2019-02-12 22:32:54 -06:00
return err
2019-01-12 22:45:25 -06:00
}