Skip to content

Commit 410cfa7

Browse files
authored
refactor: Change to 'composite' action (#4)
* ci: Skip slash-command workflow when possible * refactor: Change action to be 'composite' * ci: Fix self-invocation from node to pwsh * ci: Add return value tests * docs: Add notes in readme * ci: disable Get-ActionInput/Set-ActionOutput tests * tests: add ci self-test for context accessors * fix: in ci checks use 'exit 1' instead of return * ci: cleanup demo token as part of user script * docs: Add changelog about 'composite' refactor * docs: fix demo workflow comment, simplify example
1 parent 2c55529 commit 410cfa7

File tree

12 files changed

+137
-138
lines changed

12 files changed

+137
-138
lines changed

.github/workflows/chatops.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
jobs:
66
dispatch:
77
runs-on: ubuntu-latest
8+
if: startsWith(github.event.comment.body, '/')
89
steps:
910
- name: /command dispatch
1011
uses: peter-evans/slash-command-dispatch@v1

.github/workflows/ci.yml

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ jobs:
2121
Import-Module Pester -MinimumVersion '5.0'
2222
Invoke-Pester -CI
2323
- name: Invoke action
24+
env:
25+
TEMP: ${{ runner.temp }}
2426
run: |
25-
$env:INPUT_SCRIPT = 'Write-Host "ok"; return "value"'
26-
$output = node ./dist/index.js
27+
$env:PWSH_SCRIPT_ACTION_TEXT = 'Write-Host "ok"; return "value"'
28+
$output = pwsh -file ./action.ps1
2729
if ($LASTEXITCODE -ne 0) {
2830
$output | Write-Error
29-
throw 'node failed'
31+
throw 'pwsh failed'
3032
}
3133
$diff = Compare-Object @('ok','::set-output name=result::value') $output -CaseSensitive
3234
if ($diff) {
@@ -42,7 +44,7 @@ jobs:
4244
./build-docs.ps1 -Clean
4345
if (git status --porcelain) {
4446
Write-Host "::error::Documentation isn't up to date"
45-
return 1
47+
exit 1
4648
}
4749
self-testing:
4850
strategy:
@@ -52,6 +54,34 @@ jobs:
5254
steps:
5355
- uses: actions/checkout@v2
5456

57+
# return string result
58+
- name: Test that returned result string is not json serialized (act)
59+
uses: ./
60+
id: test-result-string
61+
with:
62+
script: return "testmsg"
63+
- name: Test that returned result string is not json serialized (assert)
64+
run: |
65+
$result = '${{ steps.test-result-string.outputs.result }}'
66+
if ($result -ne 'testmsg') {
67+
Write-Host "::error::Return string test failed: invalid result.`n$result"
68+
exit 1
69+
}
70+
71+
# return object result
72+
- name: Test that returned result object is json serialized (act)
73+
uses: ./
74+
id: test-result-object
75+
with:
76+
script: return [ordered]@{ a = 1; b = "c" }
77+
- name: Test that returned result object is json serialized (assert)
78+
run: |
79+
$result = '${{ steps.test-result-object.outputs.result }}'
80+
if ($result -ne '{"a":1,"b":"c"}') {
81+
Write-Host "::error::Return object test failed: invalid result.`n$result"
82+
exit 1
83+
}
84+
5585
# throw
5686
- name: Test that throwing causes action to fail (act)
5787
uses: ./
@@ -64,16 +94,35 @@ jobs:
6494
$outcome = '${{ steps.test-throwing-fails-action.outcome }}'
6595
if ($outcome -ne 'failure') {
6696
Write-Host "::error::Throwing test failed: invalid outcome.`n$outcome"
67-
return 1
97+
exit 1
6898
}
6999
$errMsg = '${{ steps.test-throwing-fails-action.outputs.error }}'
70100
if ($errMsg -ne 'test error message') {
71101
Write-Host "::error::Throwing test failed: invalid error output.`n$errMsg"
72-
return 1
102+
exit 1
73103
}
74104
105+
# check access to contexts
106+
- name: Test that workflow contexts are available
107+
uses: ./
108+
with:
109+
script: |
110+
function Test-Value ($expression, $expected) {
111+
$actual = Invoke-Expression $expression
112+
if ("$actual" -ne $expected) {
113+
throw "Failed assertion:'$expression' evaluated to '$actual', expected '$expected'."
114+
}
115+
}
116+
Test-Value '$github.token' '${{ github.token }}'
117+
Test-Value '$job.status' '${{ job.status }}'
118+
Test-Value '$runner.os' '${{ runner.os }}'
119+
Test-Value '$strategy."fail-fast"' '${{ strategy.fail-fast }}'
120+
Test-Value '$matrix.os' '${{ matrix.os }}'
121+
75122
# Get-ActionInput
123+
# Get-ActionInput isn't really testable in a script
76124
- name: Get-ActionInput test
125+
if: "false"
77126
uses: ./
78127
with:
79128
custom-input: "test"
@@ -88,12 +137,15 @@ jobs:
88137
}
89138
90139
# Set-ActionOutput
140+
# Set-ActionOutput is tested by virtue of setting 'result' and 'error' outputs
91141
- name: Set-ActionOutput test (act)
142+
if: "false"
92143
uses: ./
93144
id: Set-ActionOutput
94145
with:
95146
script: Set-ActionOutput test-output 'test-value'
96147
- name: Set-ActionOutput test (assert)
148+
if: "false"
97149
uses: ./
98150
with:
99151
script: |

.github/workflows/demo-command.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ name: Demo command
33
# example:
44
# /demo
55
# ```powershell
6-
# Write-Host "shows up in a log"
6+
# Write-Host "doesn't show up in a result comment, only in workflow logs"
7+
# Write-Output "shows up in a result comment"
78
# ```
89
on:
910
repository_dispatch:
@@ -16,7 +17,7 @@ jobs:
1617
uses: peter-evans/create-or-update-comment@v1
1718
with:
1819
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
19-
body: '[Workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})'
20+
body: "[Workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})"
2021
- name: Get script text
2122
uses: Amadevus/pwsh-script@v1
2223
id: get-script-text
@@ -34,17 +35,15 @@ jobs:
3435
else {
3536
$script = $body
3637
}
37-
# construct safe github ctx without token
38-
$githubSafe = $github.Clone()
39-
$githubSafe.Remove('token')
40-
Set-ActionOutput githubSafe $githubSafe
4138
return $script
4239
- name: Execute user script
4340
uses: Amadevus/pwsh-script@v1
4441
id: user-script
4542
with:
46-
github: ${{ steps.get-script-text.outputs.githubSafe }}
47-
script: ${{ steps.get-script-text.outputs.result }}
43+
script: |
44+
$github.token = $null
45+
$github.event.client_payload = $null
46+
${{ steps.get-script-text.outputs.result }}
4847
- name: Prettify result json
4948
uses: Amadevus/pwsh-script@v1
5049
id: pretty-result
@@ -86,4 +85,4 @@ jobs:
8685
if: failure()
8786
with:
8887
comment-id: ${{ github.event.client_payload.github.payload.comment.id }}
89-
reactions: "-1"
88+
reactions: "-1"

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- Refactored into a 'composite' action which has following implications ([#4]):
12+
- Action runs slightly faster because there's no 'node' process in between (or io stream redirects).
13+
- Action has now just single `script` input, and you cannot "add" outputs other than automatic "result" and "error".
14+
15+
### Removed
16+
- All optional inputs - until "composite" refactor, they were used to pass workflow contexts to the action.
17+
It's no longer necessary, since 'composite' action can "grab" them on it's own.
18+
- Ability to set custom `outputs` from the script - now only `result` and `error` are set (as outlined in readme).
19+
20+
[#4]: https://github.com/Amadevus/pwsh-script/pull/4
21+
1022
## [1.0.0] - 2020-06-10
1123

1224
### Added

README.md

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,15 @@ GitHub Action to run PowerShell scripts that use the workflow run context - insp
77
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Amadevus/pwsh-script)](https://github.com/Amadevus/pwsh-script/releases/latest)
88
![GitHub commits since latest release (by date)](https://img.shields.io/github/commits-since/Amadevus/pwsh-script/latest)
99

10-
In order to use this action, `script` input is provided. The value of that input should be
10+
In order to use this action, `script` input is required. The value of that input should be
1111
the body of a PowerShell script.
12-
13-
The following is initialized before your script is executed:
12+
The following variables are initialized before your script is executed:
1413
- `$github` is an object representing the workflow's [`github` context]
1514
- `$job` is an object representing the workflow's [`job` context]
1615
- `$runner` is an object representing the workflow's [`runner` context]
1716
- `$strategy` is an object representing the workflow's [`strategy` context]
1817
- `$matrix` is an object representing the workflow's [`matrix` context]
1918

20-
Environment variables are accessed in the standard PowerShell way (`$env:my_var`).
21-
22-
**Note** This action requires `pwsh` to actually be available and on PATH of the runner - which
23-
is the case for all GitHub-provided runner VMs; for your own runners you need to take care of that yourself.
24-
25-
This action has an extensive self-testing suite in [CI workflow](.github/workflows/ci.yml).
26-
2719
[actions/github-script]: https://github.com/actions/github-script
2820
[`@actions/core`]: https://github.com/actions/toolkit/tree/master/packages/core
2921
[`github` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context
@@ -32,6 +24,10 @@ This action has an extensive self-testing suite in [CI workflow](.github/workflo
3224
[`strategy` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#strategy-context
3325
[`matrix` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#matrix-context
3426

27+
## Demo
28+
29+
You can try out this action yourself by commenting on a [demo issue](https://github.com/Amadevus/pwsh-script/issues/2). Instructions in the issue.
30+
3531
## Reading step results
3632
The return value of the script will be made available in the step's outputs under the `result` key.
3733
```yml
@@ -75,44 +71,55 @@ will be set as an `error` output of the action.
7571
## Actions cmdlets
7672
A module called `GitHubActionsCore` will be imported in the scope of your script. It provides commands
7773
that are available for JavaScript Actions by [`@actions/core`] package, such as:
78-
- `Set-ActionOutput`
74+
- `Add-ActionPath`
7975
- `Write-ActionWarning`
8076
- `Set-ActionFailed`
8177

8278
For module documentation, see [GitHubActionsCore README](docs/GitHubActionsCore/README.md).
8379

8480
The module has a good test suite written in Pester.
8581

82+
## Notes
83+
84+
- This action requires `pwsh` to actually be available and on PATH of the runner - which
85+
is the case for all GitHub-provided runner VMs; for your own runners you need to take care of that yourself.
86+
- This action is a [`composite` action](https://docs.github.com/en/actions/creating-actions/creating-a-composite-run-steps-action).
87+
- This action has an extensive self-testing suite in [CI workflow](.github/workflows/ci.yml).
88+
- Although available in the imported module, `Get-ActionInput` and `Set-ActionOutput` won't really work when used as part of this action.
89+
8690
## Examples
8791

8892
```yml
8993
- uses: Amadevus/pwsh-script@v1
9094
id: script
9195
with:
9296
script: |
93-
Write-ActionDebug "This will be visible only when ACTIONS_STEP_DEBUG secret is set"
97+
Write-ActionDebug "Visible only when ACTIONS_STEP_DEBUG secret is set"
9498
95-
# we have access to full context objects:
99+
# access full context objects:
96100
if ($github.event.repository.full_name -ne $github.repository) {
97-
throw "something fishy's going on, repos don't match" # will cause step to fail
101+
# throwing causes the step to fail
102+
throw "something fishy's going on, repos don't match"
98103
}
99104
100105
$someData = Get-MyCustomData
101-
# this data may contain action-command-like strings (e.g. '::warning::...')
102-
# we can prevent interpreting these by GitHub by printing them in NoCommandsBlock:
106+
# data may contain workflow command strings (e.g. '::warning::...')
107+
# prevent runner interpreting these
103108
Invoke-ActionNoCommandsBlock -GenerateToken {
104-
Write-Host $someData # this won't result in any commands
109+
# this won't result in any workflow commands
110+
Write-Host $someData
111+
Write-ActionError "not interpreted as error"
105112
}
106-
# now we can send commands again
113+
# commands work again
107114
108-
# let's set env:BE_AWESOME=always, but for all the following actions/steps as well:
115+
# set env:BE_AWESOME=always here and for the following steps
109116
Set-ActionVariable BE_AWESOME always
110117
111-
# also we'll add path to our custom tool to PATH for the following steps:
118+
# add our custom tool to PATH for the following steps:
112119
$toolPath = Resolve-Path ./tools/bin
113120
Add-ActionPath $toolPath
114121
115-
# let's also warn if it's too late for people to work in Greenwich ;)
122+
# warn if it's too late for people to work in Greenwich ;)
116123
if ([datetime]::UtcNow.Hour -ge 22) {
117124
Write-ActionWarning "It's time to go to bed. Don't write code late at night! ⚠"
118125
}

action.ps1

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,24 @@
22

33
Import-Module $PSScriptRoot/lib/GitHubActionsCore
44

5-
function CreateContext($name) {
6-
$ctx = Get-ActionInput $name | ConvertFrom-Json -AsHashtable -NoEnumerate
5+
function Private:CreateContext($name) {
6+
$varName = "PWSH_SCRIPT_ACTION_$($name.ToUpper())"
7+
$value = (Get-ChildItem "Env:$varName" -ErrorAction:SilentlyContinue).Value
8+
$ctx = "$value" | ConvertFrom-Json -AsHashtable -NoEnumerate
79
Set-Variable -Name $name -Value $ctx -Scope Script -Option Constant
810
}
911

10-
CreateContext github
11-
CreateContext job
12-
CreateContext runner
13-
CreateContext strategy
14-
CreateContext matrix
15-
16-
Remove-Item Function:CreateContext
12+
Private:CreateContext github
13+
Private:CreateContext job
14+
Private:CreateContext runner
15+
Private:CreateContext strategy
16+
Private:CreateContext matrix
1717

1818
try {
19-
$result = Invoke-Expression "$(Get-ActionInput 'script' -Required)"
20-
Set-ActionOutput 'result' $result
19+
$Private:scriptFile = New-Item (Join-Path $env:TEMP "$(New-Guid).ps1") -ItemType File
20+
Set-Content $Private:scriptFile "$env:PWSH_SCRIPT_ACTION_TEXT"
21+
$Private:result = Invoke-Expression $Private:scriptFile
22+
Set-ActionOutput 'result' $Private:result
2123
}
2224
catch {
2325
Set-ActionOutput 'error' $_.ToString()

action.yml

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,27 @@ inputs:
77
script:
88
description: PowerShell script to execute in Actions-hydrated context
99
required: true
10-
github:
11-
description: "'github' workflow context"
12-
required: false
13-
default: ${{ toJson(github) }}
14-
job:
15-
description: "'job' workflow context"
16-
required: false
17-
default: ${{ toJson(job) }}
18-
runner:
19-
description: "'runner' workflow context"
20-
required: false
21-
default: ${{ toJson(runner) }}
22-
strategy:
23-
description: "'strategy' workflow context"
24-
required: false
25-
default: ${{ toJson(strategy) }}
26-
matrix:
27-
description: "'matrix' workflow context"
28-
required: false
29-
default: ${{ toJson(matrix) }}
3010
outputs:
3111
result:
3212
description: Return value of script execution
13+
value: ${{ steps.script.outputs.result }}
14+
error:
15+
description: Exception details, if any was thrown during script execution.
16+
value: ${{ steps.script.outputs.error }}
3317
runs:
34-
using: node12
35-
main: dist/index.js
18+
using: composite
19+
steps:
20+
- run: ${{ github.action_path }}/action.ps1
21+
id: script
22+
shell: pwsh
23+
env:
24+
TEMP: ${{ runner.temp }}
25+
PWSH_SCRIPT_ACTION_TEXT: ${{ inputs.script }}
26+
PWSH_SCRIPT_ACTION_GITHUB: ${{ toJson(github) }}
27+
PWSH_SCRIPT_ACTION_JOB: ${{ toJson(job) }}
28+
PWSH_SCRIPT_ACTION_RUNNER: ${{ toJson(runner) }}
29+
PWSH_SCRIPT_ACTION_STRATEGY: ${{ toJson(strategy) }}
30+
PWSH_SCRIPT_ACTION_MATRIX: ${{ toJson(matrix) }}
3631
branding:
3732
icon: terminal
3833
color: blue

build.ps1

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)