Skip to content

Commit 767e6a8

Browse files
Input (#1524)
* added input flags * added input as part of the action event and added test cases * updated readme Co-authored-by: ChristopherHX <[email protected]>
1 parent b2fb9e6 commit 767e6a8

File tree

6 files changed

+96
-11
lines changed

6 files changed

+96
-11
lines changed

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ It will save that information to `~/.actrc`, please refer to [Configuration](#co
186186
--github-instance string GitHub instance to use. Don't use this if you are not using GitHub Enterprise Server. (default "github.com")
187187
-g, --graph draw workflows
188188
-h, --help help for act
189+
--input stringArray action input to make available to actions (e.g. --input myinput=foo)
190+
--input-file string input file to read and use as action input (default ".input")
189191
--insecure-secrets NOT RECOMMENDED! Doesn't hide secrets while printing logs.
190192
-j, --job string run job
191193
-l, --list list workflows
@@ -408,7 +410,7 @@ act pull_request -e pull-request.json
408410

409411
Act will properly provide `github.head_ref` and `github.base_ref` to the action as expected.
410412

411-
## Pass Inputs to Manually Triggered Workflows
413+
# Pass Inputs to Manually Triggered Workflows
412414

413415
Example workflow file
414416

@@ -434,6 +436,14 @@ jobs:
434436
echo "Hello ${{ github.event.inputs.NAME }} and ${{ github.event.inputs.SOME_VALUE }}!"
435437
```
436438

439+
## via input or input-file flag
440+
441+
- `act --input NAME=somevalue` - use `somevalue` as the value for `NAME` input.
442+
- `act --input-file my.input` - load input values from `my.input` file.
443+
- input file format is the same as `.env` format
444+
445+
## via JSON
446+
437447
Example JSON payload file conveniently named `payload.json`
438448

439449
```json

cmd/input.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ type Input struct {
1717
bindWorkdir bool
1818
secrets []string
1919
envs []string
20+
inputs []string
2021
platforms []string
2122
dryrun bool
2223
forcePull bool
2324
forceRebuild bool
2425
noOutput bool
2526
envfile string
27+
inputfile string
2628
secretfile string
2729
insecureSecrets bool
2830
defaultBranch string
@@ -84,3 +86,8 @@ func (i *Input) WorkflowsPath() string {
8486
func (i *Input) EventPath() string {
8587
return i.resolve(i.eventPath)
8688
}
89+
90+
// Inputfile returns the path to the input file
91+
func (i *Input) Inputfile() string {
92+
return i.resolve(i.inputfile)
93+
}

cmd/root.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func Execute(ctx context.Context, version string) {
4747
rootCmd.Flags().StringVar(&input.remoteName, "remote-name", "origin", "git remote name that will be used to retrieve url of git repo")
4848
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)")
4949
rootCmd.Flags().StringArrayVarP(&input.envs, "env", "", []string{}, "env to make available to actions with optional value (e.g. --env myenv=foo or --env myenv)")
50+
rootCmd.Flags().StringArrayVarP(&input.inputs, "input", "", []string{}, "action input to make available to actions (e.g. --input myinput=foo)")
5051
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)")
5152
rootCmd.Flags().BoolVarP(&input.reuseContainers, "reuse", "r", false, "don't remove container(s) on successfully completed workflow(s) to maintain state between runs")
5253
rootCmd.Flags().BoolVarP(&input.bindWorkdir, "bind", "b", false, "bind working directory to container, rather than copy")
@@ -74,6 +75,7 @@ func Execute(ctx context.Context, version string) {
7475
rootCmd.PersistentFlags().StringVarP(&input.secretfile, "secret-file", "", ".secrets", "file with list of secrets to read from (e.g. --secret-file .secrets)")
7576
rootCmd.PersistentFlags().BoolVarP(&input.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.")
7677
rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
78+
rootCmd.PersistentFlags().StringVarP(&input.inputfile, "input-file", "", ".input", "input file to read and use as action input")
7779
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.")
7880
rootCmd.PersistentFlags().StringVarP(&input.containerDaemonSocket, "container-daemon-socket", "", "/var/run/docker.sock", "Path to Docker daemon socket which will be mounted to containers")
7981
rootCmd.PersistentFlags().StringVarP(&input.containerOptions, "container-options", "", "", "Custom docker container options for the job container without an options property in the job definition")
@@ -249,6 +251,21 @@ func setupLogging(cmd *cobra.Command, _ []string) {
249251
}
250252
}
251253

254+
func parseEnvs(env []string, envs map[string]string) bool {
255+
if env != nil {
256+
for _, envVar := range env {
257+
e := strings.SplitN(envVar, `=`, 2)
258+
if len(e) == 2 {
259+
envs[e[0]] = e[1]
260+
} else {
261+
envs[e[0]] = ""
262+
}
263+
}
264+
return true
265+
}
266+
return false
267+
}
268+
252269
func readEnvs(path string, envs map[string]string) bool {
253270
if _, err := os.Stat(path); err == nil {
254271
env, err := godotenv.Read(path)
@@ -285,18 +302,14 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
285302

286303
log.Debugf("Loading environment from %s", input.Envfile())
287304
envs := make(map[string]string)
288-
if input.envs != nil {
289-
for _, envVar := range input.envs {
290-
e := strings.SplitN(envVar, `=`, 2)
291-
if len(e) == 2 {
292-
envs[e[0]] = e[1]
293-
} else {
294-
envs[e[0]] = ""
295-
}
296-
}
297-
}
305+
_ = parseEnvs(input.envs, envs)
298306
_ = readEnvs(input.Envfile(), envs)
299307

308+
log.Debugf("Loading action inputs from %s", input.Inputfile())
309+
inputs := make(map[string]string)
310+
_ = parseEnvs(input.inputs, inputs)
311+
_ = readEnvs(input.Inputfile(), inputs)
312+
300313
log.Debugf("Loading secrets from %s", input.Secretfile())
301314
secrets := newSecrets(input.secrets)
302315
_ = readEnvs(input.Secretfile(), secrets)
@@ -444,6 +457,7 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
444457
JSONLogger: input.jsonLogger,
445458
Env: envs,
446459
Secrets: secrets,
460+
Inputs: inputs,
447461
Token: secrets["GITHUB_TOKEN"],
448462
InsecureSecrets: input.insecureSecrets,
449463
Platforms: input.newPlatforms(),

pkg/runner/runner.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package runner
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"os"
78

@@ -31,6 +32,7 @@ type Config struct {
3132
LogOutput bool // log the output from docker run
3233
JSONLogger bool // use json or text logger
3334
Env map[string]string // env for containers
35+
Inputs map[string]string // manually passed action inputs
3436
Secrets map[string]string // list of secrets
3537
Token string // GitHub token
3638
InsecureSecrets bool // switch hiding output when printing to terminal
@@ -81,6 +83,15 @@ func (runner *runnerImpl) configure() (Runner, error) {
8183
return nil, err
8284
}
8385
runner.eventJSON = string(eventJSONBytes)
86+
} else if len(runner.config.Inputs) != 0 {
87+
eventMap := map[string]map[string]string{
88+
"inputs": runner.config.Inputs,
89+
}
90+
eventJSON, err := json.Marshal(eventMap)
91+
if err != nil {
92+
return nil, err
93+
}
94+
runner.eventJSON = string(eventJSON)
8495
}
8596
return runner, nil
8697
}

pkg/runner/runner_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func (j *TestJobFileInfo) runTest(ctx context.Context, t *testing.T, cfg *Config
9494
ReuseContainers: false,
9595
Env: cfg.Env,
9696
Secrets: cfg.Secrets,
97+
Inputs: cfg.Inputs,
9798
GitHubInstance: "github.com",
9899
ContainerArchitecture: cfg.ContainerArchitecture,
99100
}
@@ -419,6 +420,27 @@ func TestRunEventSecrets(t *testing.T) {
419420
tjfi.runTest(context.Background(), t, &Config{Secrets: secrets, Env: env})
420421
}
421422

423+
func TestRunActionInputs(t *testing.T) {
424+
if testing.Short() {
425+
t.Skip("skipping integration test")
426+
}
427+
workflowPath := "input-from-cli"
428+
429+
tjfi := TestJobFileInfo{
430+
workdir: workdir,
431+
workflowPath: workflowPath,
432+
eventName: "workflow_dispatch",
433+
errorMessage: "",
434+
platforms: platforms,
435+
}
436+
437+
inputs := map[string]string{
438+
"SOME_INPUT": "input",
439+
}
440+
441+
tjfi.runTest(context.Background(), t, &Config{Inputs: inputs})
442+
}
443+
422444
func TestRunEventPullRequest(t *testing.T) {
423445
if testing.Short() {
424446
t.Skip("skipping integration test")
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
on:
2+
workflow_dispatch:
3+
inputs:
4+
NAME:
5+
description: "A random input name for the workflow"
6+
type: string
7+
required: true
8+
SOME_VALUE:
9+
description: "Some other input to pass"
10+
type: string
11+
required: true
12+
13+
jobs:
14+
test:
15+
name: Test
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Test with inputs
20+
run: |
21+
[ -z "${{ github.event.inputs.SOME_INPUT }}" ] && exit 1 || exit 0

0 commit comments

Comments
 (0)