├── .github ├── dependabot.yml └── workflows │ ├── chatops.yml │ ├── ci.yml │ ├── demo-command.yml │ └── tag-command.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── action.ps1 ├── action.yml ├── build-docs.ps1 ├── docs └── GitHubActionsCore │ ├── Add-ActionPath.md │ ├── Add-ActionSecret.md │ ├── Enter-ActionOutputGroup.md │ ├── Exit-ActionOutputGroup.md │ ├── Get-ActionInput.md │ ├── Get-ActionIsDebug.md │ ├── Invoke-ActionGroup.md │ ├── Invoke-ActionNoCommandsBlock.md │ ├── README.md │ ├── Send-ActionCommand.md │ ├── Send-ActionFileCommand.md │ ├── Set-ActionCommandEcho.md │ ├── Set-ActionFailed.md │ ├── Set-ActionOutput.md │ ├── Set-ActionVariable.md │ ├── Write-ActionDebug.md │ ├── Write-ActionError.md │ ├── Write-ActionInfo.md │ └── Write-ActionWarning.md ├── lib └── GitHubActionsCore │ ├── GitHubActionsCore.Tests.ps1 │ └── GitHubActionsCore.psm1 └── test.ps1 /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/chatops.yml: -------------------------------------------------------------------------------- 1 | name: ChatOps 2 | on: 3 | issue_comment: 4 | types: [created] 5 | jobs: 6 | dispatch: 7 | runs-on: ubuntu-latest 8 | if: startsWith(github.event.comment.body, '/') 9 | steps: 10 | - name: /command dispatch 11 | uses: peter-evans/slash-command-dispatch@v3 12 | with: 13 | token: ${{ secrets.SLASH_COMMAND_DISPATCH_TOKEN }} 14 | config: > 15 | [ 16 | { 17 | "command": "tag", 18 | "permission": "admin" 19 | }, 20 | { 21 | "command": "demo", 22 | "permission": "none" 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | pull_request: 5 | schedule: 6 | - cron: "0 10 * * 1" # At 10:00 on Monday. 7 | defaults: 8 | run: 9 | shell: pwsh 10 | jobs: 11 | build: 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, macos-latest, windows-latest] 15 | runs-on: ${{ matrix.os }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Test with Pester 19 | run: ./test.ps1 20 | - name: Invoke action 21 | env: 22 | TEMP: ${{ runner.temp }} 23 | run: | 24 | $env:PWSH_SCRIPT_ACTION_TEXT = 'Write-Host "ok"; return "value"' 25 | $output = pwsh -file ./action.ps1 26 | if ($LASTEXITCODE -ne 0) { 27 | Write-Host "::error::Action exited with exit code $LASTEXITCODE and outputted: $output" 28 | throw 29 | } 30 | $diff = Compare-Object @('ok') $output -CaseSensitive 31 | if ($diff) { 32 | $diff | Format-Table | Write-Host 33 | Write-Host "::error::Action output differed from the expected, see above." 34 | throw "Action output differed from the expected" 35 | } 36 | $outFile = Get-Content $env:GITHUB_OUTPUT 37 | $diff = Compare-Object @('result=value') $outFile 38 | if ($diff) { 39 | $diff | Format-Table | Write-Host 40 | Write-Host "::error::Action output file differed from the expected, see above." 41 | throw "Action output file differed from the expected" 42 | } 43 | build-docs: 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v4 47 | - name: Build module docs 48 | uses: ./ 49 | with: 50 | script: | 51 | ./build-docs.ps1 -Clean 52 | git status --porcelain || $(throw "Documentation isn't up to date. Run 'build-docs.ps1' and commit changes.") 53 | self-testing: 54 | strategy: 55 | matrix: 56 | os: [ubuntu-latest, macos-latest, windows-latest] 57 | runs-on: ${{ matrix.os }} 58 | steps: 59 | - uses: actions/checkout@v4 60 | 61 | # return string result 62 | - name: Test that returned result string is not json serialized (act) 63 | uses: ./ 64 | id: test-result-string 65 | with: 66 | script: return "testmsg" 67 | - name: Test that returned result string is not json serialized (assert) 68 | run: | 69 | $result = '${{ steps.test-result-string.outputs.result }}' 70 | if ($result -cne 'testmsg') { 71 | Write-Host "::error::unexpected - Return string test failed: invalid result.`n$result" 72 | exit 1 73 | } 74 | 75 | # return object result 76 | - name: Test that returned result object is json serialized (act) 77 | uses: ./ 78 | id: test-result-object 79 | with: 80 | script: return [ordered]@{ a = 1; b = "c" } 81 | - name: Test that returned result object is json serialized (assert) 82 | run: | 83 | $result = '${{ steps.test-result-object.outputs.result }}' 84 | if ($result -cne '{"a":1,"b":"c"}') { 85 | Write-Host "::error::unexpected - Return object test failed: invalid result.`n$result" 86 | exit 1 87 | } 88 | 89 | # throw 90 | - name: Test that throwing causes action to fail (act) 91 | uses: ./ 92 | id: test-throwing-fails-action 93 | continue-on-error: true 94 | with: 95 | script: 'throw "expected: test error message"' 96 | - name: Test that throwing causes action to fail (assert) 97 | run: | 98 | $outcome = '${{ steps.test-throwing-fails-action.outcome }}' 99 | if ($outcome -cne 'failure') { 100 | Write-Host "::error::unexpected - Throwing test failed: invalid outcome.`n$outcome" 101 | exit 1 102 | } 103 | $errMsg = '${{ steps.test-throwing-fails-action.outputs.error }}' 104 | if ($errMsg -cne 'expected: test error message') { 105 | Write-Host "::error::unexpected - Throwing test failed: invalid error output.`n$errMsg" 106 | exit 1 107 | } 108 | 109 | # check access to contexts 110 | - name: Test that workflow contexts are available 111 | uses: ./ 112 | with: 113 | script: | 114 | function Test-Value ($expression, $expected) { 115 | $actual = Invoke-Expression $expression 116 | if ($actual -cne $expected) { 117 | throw "unexpected: Failed assertion:'$expression' evaluated to '$actual', expected '$expected'." 118 | } 119 | } 120 | Test-Value '$github.token' '${{ github.token }}' 121 | Test-Value '$job.status' '${{ job.status }}' 122 | Test-Value '$runner.os' '${{ runner.os }}' 123 | Test-Value '$strategy."fail-fast"' ([bool]'${{ strategy.fail-fast }}') 124 | Test-Value '$matrix.os' '${{ matrix.os }}' 125 | 126 | # Get-ActionInput 127 | # Get-ActionInput isn't really testable in a script 128 | - name: Get-ActionInput test 129 | if: "false" 130 | uses: ./ 131 | with: 132 | custom-input: "test" 133 | script: | 134 | $script = Get-ActionInput script 135 | if ($script -notlike '$script = Get-ActionInput script*') { 136 | throw "unexpected: Get-ActionInput for 'script' failed.`n$script" 137 | } 138 | $custom = Get-ActionInput custom-input 139 | if ($custom -cne 'test') { 140 | throw "unexpected: Get-ActionInput for 'custom-input' failed.`n$custom" 141 | } 142 | 143 | # Set-ActionOutput 144 | - name: Set-ActionOutput test (act) 145 | id: Set-ActionOutput 146 | run: | 147 | Import-Module ./lib/GitHubActionsCore -Force 148 | Set-ActionOutput testout testval 149 | Set-ActionOutput testout-multiline "testval`n new line `n 3rd line" 150 | Get-Content $env:GITHUB_OUTPUT -Raw | Write-Host 151 | - name: Set-ActionOutput test (assert) 152 | uses: ./ 153 | env: 154 | testout_output: ${{ steps.Set-ActionOutput.outputs.testout }} 155 | testout_multiline_output: ${{ steps.Set-ActionOutput.outputs.testout-multiline }} 156 | with: 157 | script: | 158 | $output = $env:testout_output 159 | if ($output -cne 'testval') { 160 | throw "unexpected: Set-ActionOutput failed.`n$output" 161 | } 162 | $output = $env:testout_multiline_output 163 | if ($output -cne "testval`n new line `n 3rd line") { 164 | throw "unexpected: Set-ActionOutput failed.`n$output" 165 | } 166 | 167 | # Add-ActionPath 168 | - name: Add-ActionPath test (act) 169 | uses: ./ 170 | with: 171 | script: Add-ActionPath 'testing add-path' 172 | - name: Add-ActionPath test (assert) 173 | uses: ./ 174 | with: 175 | script: | 176 | if ($env:PATH -notlike "*testing add-path$([System.IO.Path]::PathSeparator)*") { 177 | throw "unexpected: Add-ActionPath failed.`n$env:PATH" 178 | } 179 | 180 | # Add-ActionSecret 181 | - name: Add-ActionSecret test (manual check whether host-sent value is masked) 182 | uses: ./ 183 | with: 184 | script: | 185 | $secret = [System.Guid]::NewGuid() 186 | Add-ActionSecret $secret 187 | Write-Host $secret 188 | 189 | # Set-ActionVariable 190 | - name: Set-ActionVariable test (act and first assert) 191 | uses: ./ 192 | with: 193 | script: | 194 | $props = [ordered]@{ a = 1; b = 'c' } 195 | Set-ActionVariable testvar $props 196 | Set-ActionVariable testvar_multiline "line1`nline2`nline3" 197 | Get-Content $env:GITHUB_ENV -Raw | Write-Host 198 | if ($env:testvar -cne '{"a":1,"b":"c"}') { 199 | throw "unexpected: Set-ActionVariable failed.`n$env:testvar" 200 | } 201 | - name: Set-ActionVariable test (second assert) 202 | uses: ./ 203 | with: 204 | script: | 205 | if ($env:testvar -cne '{"a":1,"b":"c"}') { 206 | throw "unexpected: Set-ActionVariable failed.`n$env:testvar" 207 | } 208 | if ($env:testvar_multiline -cne "line1`nline2`nline3") { 209 | throw "unexpected: Set-ActionVariable failed.`n$env:testvar_multiline" 210 | } 211 | 212 | # Set-ActionCommandEcho 213 | - name: Set-ActionCommandEcho test (manual check whether commands are shown in log) 214 | uses: ./ 215 | with: 216 | script: | 217 | Set-ActionCommandEcho $false 218 | Set-ActionOutput echo-off "unexpected to show up" # shouldn't show up in logs 219 | Set-ActionCommandEcho $true 220 | Set-ActionOutput echo-on "expected to show up" # should show up in logs 221 | Set-ActionCommandEcho $false 222 | 223 | # Set-ActionFailed 224 | - name: Set-ActionFailed test (act) 225 | uses: ./ 226 | id: Set-ActionFailed 227 | continue-on-error: true 228 | with: 229 | script: | 230 | Set-ActionFailed "expected: test error (this action should have exit code 1 in logs)" 231 | - name: Set-ActionFailed test (assert) 232 | uses: ./ 233 | with: 234 | script: | 235 | $result = '${{ steps.Set-ActionFailed.outcome }}' 236 | if ($result -cne 'failure') { 237 | throw "unexpected: Set-ActionFailed failed.`n$result" 238 | } 239 | 240 | # Get-ActionIsDebug 241 | - name: Get-ActionIsDebug test 242 | uses: ./ 243 | with: 244 | script: | 245 | $result = Get-ActionIsDebug 246 | if ($result -ne ($env:RUNNER_DEBUG -eq '1')) { 247 | throw "unexpected: Get-ActionIsDebug failed.`n$result" 248 | } 249 | 250 | # Invoke-ActionNoCommandsBlock 251 | - name: Invoke-ActionNoCommandsBlock test (manual check) 252 | id: Invoke-ActionNoCommandsBlock 253 | run: | 254 | Import-Module ./lib/GitHubActionsCore -Force 255 | Invoke-ActionNoCommandsBlock -GenerateToken { 256 | Write-ActionError "unexpected: this should not be visible as error" 257 | } 258 | 259 | # Write-Action -Debug, -Info, -Warning, -Error and Grouping are not testable in any sensible manner 260 | - name: Write-Action... and Group... sample runs (manual check) 261 | uses: ./ 262 | continue-on-error: true # since we're printing errors 263 | with: 264 | script: | 265 | Enter-ActionOutputGroup 'testing log levels' 266 | Write-ActionDebug "dbg msg" 267 | Write-ActionInfo "expected: info msg" 268 | Write-ActionWarning "expected: wrn msg" 269 | Write-ActionError "expected: err msg" 270 | Exit-ActionOutputGroup 271 | Invoke-ActionGroup "Invoke-ActionGroup group" { 272 | Write-Host "expected: output within Invoke-ActionGroup" 273 | } 274 | -------------------------------------------------------------------------------- /.github/workflows/demo-command.yml: -------------------------------------------------------------------------------- 1 | name: Demo command 2 | # trigger by chatops '/demo' followed by a PowerShell script in the comment body 3 | # example: 4 | # /demo 5 | # ```powershell 6 | # Write-Host "doesn't show up in a result comment, only in workflow logs" 7 | # Write-Output "shows up in a result comment" 8 | # ``` 9 | on: 10 | repository_dispatch: 11 | types: [demo-command] 12 | jobs: 13 | run-demo: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Add run link to command comment 17 | uses: peter-evans/create-or-update-comment@v4 18 | with: 19 | comment-id: ${{ github.event.client_payload.github.payload.comment.id }} 20 | body: "[Workflow run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" 21 | - uses: actions/checkout@v4 22 | - name: Get script text 23 | uses: ./ 24 | id: get-script-text 25 | with: 26 | script: | 27 | # get body lines, skip first (command) 28 | $bodyLines = $github.event.client_payload.github.payload.comment.body -split '\r?\n' | Select-Object -Skip 1 29 | $body = $bodyLines -join "`n" 30 | $md = $body | ConvertFrom-Markdown 31 | $codeBlocks = [Markdig.Syntax.MarkdownObjectExtensions]::Descendants($md.Tokens) | Where-Object { $_ -is [Markdig.Syntax.CodeBlock] } 32 | if ($codeBlocks) { 33 | $scriptAst = $codeBlocks | Select-Object -First 1 34 | $script = $scriptAst.Lines.ToString() 35 | } 36 | else { 37 | $script = $body 38 | } 39 | return $script 40 | - name: Execute user script 41 | uses: ./ 42 | id: user-script 43 | with: 44 | script: | 45 | $github.token = $null 46 | $github.event.client_payload = $null 47 | ${{ steps.get-script-text.outputs.result }} 48 | - name: Prettify result json 49 | uses: ./ 50 | id: pretty-result 51 | env: 52 | RESULT_JSON: ${{ steps.user-script.outputs.result }} 53 | with: 54 | script: | 55 | $result = $env:RESULT_JSON 56 | if ($result -and $result -match '^[\[\{]') { 57 | try { 58 | return ConvertFrom-Json $result -AsHashtable -NoEnumerate | ConvertTo-Json -Depth 100 59 | } 60 | catch { 61 | Write-Host "Error converting, fallback to returning plain result" 62 | } 63 | } 64 | return $result 65 | - name: Comment with script result in code fence 66 | uses: peter-evans/create-or-update-comment@v4 67 | if: always() 68 | with: 69 | issue-number: ${{ github.event.client_payload.github.payload.issue.number }} 70 | body: | 71 | `result` output: 72 | ``` 73 | ${{ steps.pretty-result.outputs.result }} 74 | ``` 75 | `error` output: 76 | ``` 77 | ${{ steps.user-script.outputs.error }} 78 | ``` 79 | - name: Add reaction to command comment on success 80 | uses: peter-evans/create-or-update-comment@v4 81 | with: 82 | comment-id: ${{ github.event.client_payload.github.payload.comment.id }} 83 | reactions: hooray 84 | - name: Add reaction to command comment on failure 85 | uses: peter-evans/create-or-update-comment@v4 86 | if: failure() 87 | with: 88 | comment-id: ${{ github.event.client_payload.github.payload.comment.id }} 89 | reactions: "-1" 90 | -------------------------------------------------------------------------------- /.github/workflows/tag-command.yml: -------------------------------------------------------------------------------- 1 | name: Tag command 2 | # trigger by chatops '/tag v1.0.0 ref=main force' 3 | # first non-named arg is interpreted as the tag name to be created 4 | # ref defaults to default repo branch and is the ref going to be tagged 5 | # 'force', if specified in args, adds `--force` to tagging operations (to move major tags like v1/v2) 6 | on: 7 | repository_dispatch: 8 | types: [tag-command] 9 | jobs: 10 | tag: 11 | runs-on: ubuntu-latest 12 | env: 13 | tag_name: ${{ github.event.client_payload.slash_command.args.unnamed.arg1 }} 14 | steps: 15 | - name: Add run link to command comment 16 | uses: peter-evans/create-or-update-comment@v4 17 | with: 18 | 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 | - uses: actions/checkout@v4 21 | with: 22 | ref: ${{ github.event.client_payload.slash_command.args.named.ref }} 23 | - name: Resolve version, tag and push 24 | uses: ./ 25 | with: 26 | script: | 27 | $args = $github.event.client_payload.slash_command.args.unnamed 28 | $force = ($args.GetEnumerator() | ? Value -eq 'force') ? '--force' : '' 29 | $tag = $env:tag_name 30 | if (-not $tag) { 31 | throw "Can't create empty-named tag. Please specify tag after command: /tag vX.Y.Z" 32 | } 33 | git tag $tag $force || $(throw "git tag $tag $force failed.") 34 | git push origin $tag $force || $(throw "git push origin $tag $force failed.") 35 | - name: Add tag info and reaction to command comment 36 | uses: peter-evans/create-or-update-comment@v4 37 | with: 38 | comment-id: ${{ github.event.client_payload.github.payload.comment.id }} 39 | body: | 40 | Pushed tag [`${{ env.tag_name }}`][tag] 41 | 42 | [tag]: https://github.com/${{ github.repository }}/tree/${{ env.tag_name }} 43 | reactions: hooray 44 | - name: Add reaction to command comment on failure 45 | uses: peter-evans/create-or-update-comment@v4 46 | if: failure() 47 | with: 48 | comment-id: ${{ github.event.client_payload.github.payload.comment.id }} 49 | reactions: "-1" 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | coverage.xml 352 | testResults.xml 353 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [2.0.3] - 2022-10-18 11 | 12 | ### Changed 13 | 14 | - fix: correctly handle multiline values in `Set-ActionOutput` and `Set-ActionVariable`. ([#18]) 15 | 16 | [#18]: https://github.com/Amadevus/pwsh-script/pull/18 17 | 18 | ## [2.0.2] - 2022-10-17 19 | 20 | ### Changed 21 | 22 | - rename default branch to `main`. 23 | - use [Environment Files] for `Set-ActionOutput` command. ([#14]) 24 | 25 | [#14]: https://github.com/Amadevus/pwsh-script/pull/14 26 | 27 | ## [2.0.1] - 2021-02-05 28 | 29 | ### Added 30 | 31 | - `Send-ActionFileCommand` cmdlet that handles sending commands to [Environment Files] instead of console output ([#8]). 32 | 33 | ### Changed 34 | 35 | - `Add-ActionPath` and `Set-ActionVariable` are updated for [Environment Files] Actions Runner change ([#8]). 36 | 37 | [Environment Files]: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#environment-files 38 | [#8]: https://github.com/Amadevus/pwsh-script/pull/8 39 | 40 | ## [2.0.0] - 2020-09-10 41 | 42 | ### Changed 43 | 44 | - Refactored into a 'composite' action which has following implications ([#4]): 45 | - Action runs slightly faster because there's no 'node' process in between (or io stream redirects). 46 | - Action has now just single `script` input, and you cannot "add" outputs other than automatic "result" and "error". 47 | 48 | ### Removed 49 | 50 | - All optional inputs - until "composite" refactor, they were used to pass workflow contexts to the action. 51 | It's no longer necessary, since 'composite' action can "grab" them on it's own. 52 | - Ability to set custom `outputs` from the script - now only `result` and `error` are set (as outlined in readme). 53 | 54 | [#4]: https://github.com/Amadevus/pwsh-script/pull/4 55 | 56 | ## [1.0.0] - 2020-06-10 57 | 58 | ### Added 59 | 60 | - Initial action code 61 | - `GitHubActionsCore` PowerShell module 62 | 63 | [Unreleased]: https://github.com/Amadevus/pwsh-script/compare/v2.0.3...HEAD 64 | [2.0.3]: https://github.com/Amadevus/pwsh-script/compare/v2.0.2...v2.0.3 65 | [2.0.2]: https://github.com/Amadevus/pwsh-script/compare/v2.0.1...v2.0.2 66 | [2.0.1]: https://github.com/Amadevus/pwsh-script/compare/v2.0.0...v2.0.1 67 | [2.0.0]: https://github.com/Amadevus/pwsh-script/compare/v1.0.0...v2.0.0 68 | [1.0.0]: https://github.com/Amadevus/pwsh-script/releases/tag/v1.0.0 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Amadevus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pwsh-script 2 | 3 | GitHub Action to run PowerShell scripts that use the workflow run context - inspired by [actions/github-script]. 4 | 5 | ![GitHub top language](https://img.shields.io/github/languages/top/Amadevus/pwsh-script?logo=powershell) 6 | [![CI](https://github.com/Amadevus/pwsh-script/workflows/CI/badge.svg?branch=main)](https://github.com/Amadevus/pwsh-script/actions?query=workflow%3ACI) 7 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Amadevus/pwsh-script)](https://github.com/Amadevus/pwsh-script/releases/latest) 8 | ![GitHub commits since latest release (by date)](https://img.shields.io/github/commits-since/Amadevus/pwsh-script/latest) 9 | 10 | In order to use this action, `script` input is required. The value of that input should be 11 | the body of a PowerShell script. 12 | The following variables are initialized before your script is executed: 13 | - `$github` is an object representing the workflow's [`github` context] 14 | - `$job` is an object representing the workflow's [`job` context] 15 | - `$runner` is an object representing the workflow's [`runner` context] 16 | - `$strategy` is an object representing the workflow's [`strategy` context] 17 | - `$matrix` is an object representing the workflow's [`matrix` context] 18 | 19 | [actions/github-script]: https://github.com/actions/github-script 20 | [`@actions/core`]: https://github.com/actions/toolkit/tree/main/packages/core 21 | [`github` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context 22 | [`job` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#job-context 23 | [`runner` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#runner-context 24 | [`strategy` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#strategy-context 25 | [`matrix` context]: https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#matrix-context 26 | 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 | 31 | ## Reading step results 32 | The return value of the script will be made available in the step's outputs under the `result` key. 33 | ```yml 34 | - uses: Amadevus/pwsh-script@v2 35 | id: my-script 36 | with: 37 | script: '1 + 1' 38 | - run: echo "${{ steps.my-script.outputs.result }}" 39 | # should print 2 40 | ``` 41 | 42 | ## Result encoding 43 | 44 | If the script return value is a single string, it'll be set as the value of the `result` output directly. 45 | In any other case, it'll be passed to `ConvertTo-Json $Value -Depth 100 -Compress -EscapeHandling EscapeNonAscii` 46 | and the string result of that call will be set as the output value. 47 | ```yml 48 | - uses: Amadevus/pwsh-script@v2 49 | id: bad-script 50 | with: 51 | script: return [ordered]@{ x = 'a1'; y = 'b2' } 52 | continue-on-error: true 53 | - run: echo '${{ steps.bad-script.outputs.result }}' 54 | # should print {"x":"a1","y":"b2"} 55 | ``` 56 | 57 | ## Error handling 58 | 59 | If the script throws an error/exception, it'll be caught, printed to the log and the error message 60 | will be set as an `error` output of the action. 61 | ```yml 62 | - uses: Amadevus/pwsh-script@v2 63 | id: bad-script 64 | with: 65 | script: 'throw "this fails"' 66 | continue-on-error: true 67 | - run: echo "${{ steps.bad-script.outputs.error }}" 68 | # should print 'this fails' 69 | ``` 70 | 71 | ## Actions cmdlets 72 | A module called `GitHubActionsCore` will be imported in the scope of your script. It provides commands 73 | that are available for JavaScript Actions by [`@actions/core`] package, such as: 74 | - `Add-ActionPath` 75 | - `Write-ActionWarning` 76 | - `Set-ActionFailed` 77 | 78 | For module documentation, see [GitHubActionsCore README](docs/GitHubActionsCore/README.md). 79 | 80 | The module has a good test suite written in Pester. 81 | 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 | 90 | ## Examples 91 | 92 | ```yml 93 | - uses: Amadevus/pwsh-script@v2 94 | id: script 95 | with: 96 | script: | 97 | Write-ActionDebug "Visible only when ACTIONS_STEP_DEBUG secret is set" 98 | 99 | # access full context objects: 100 | if ($github.event.repository.full_name -ne $github.repository) { 101 | # throwing causes the step to fail 102 | throw "something fishy's going on, repos don't match" 103 | } 104 | 105 | $someData = Get-MyCustomData 106 | # data may contain workflow command strings (e.g. '::warning::...') 107 | # prevent runner interpreting these 108 | Invoke-ActionNoCommandsBlock -GenerateToken { 109 | # this won't result in any workflow commands 110 | Write-Host $someData 111 | Write-ActionError "not interpreted as error" 112 | } 113 | # commands work again 114 | 115 | # set env:BE_AWESOME=always here and for the following steps 116 | Set-ActionVariable BE_AWESOME always 117 | 118 | # add our custom tool to PATH for the following steps: 119 | $toolPath = Resolve-Path ./tools/bin 120 | Add-ActionPath $toolPath 121 | 122 | # warn if it's too late for people to work in Greenwich ;) 123 | if ([datetime]::UtcNow.Hour -ge 22) { 124 | Write-ActionWarning "It's time to go to bed. Don't write code late at night! ⚠" 125 | } 126 | ``` 127 | 128 | ## Changelog 129 | 130 | Changelog is kept in [CHANGELOG.md](CHANGELOG.md) 131 | 132 | ## License 133 | 134 | This action is licensed under [MIT license](LICENSE). -------------------------------------------------------------------------------- /action.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | Import-Module $PSScriptRoot/lib/GitHubActionsCore 4 | 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 9 | Set-Variable -Name $name -Value $ctx -Scope Script -Option Constant 10 | } 11 | 12 | Private:CreateContext github 13 | Private:CreateContext job 14 | Private:CreateContext runner 15 | Private:CreateContext strategy 16 | Private:CreateContext matrix 17 | 18 | try { 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 23 | } 24 | catch { 25 | Set-ActionOutput 'error' $_.ToString() 26 | $ErrorView = 'NormalView' 27 | Set-ActionFailed ($_ | Out-String) 28 | } 29 | exit [System.Environment]::ExitCode -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: PowerShell script 2 | author: Amadevus 3 | description: > 4 | Run PowerShell scripts within a hydrated context, 5 | with workflow-command cmdlets; inspired by actions/github-script. 6 | inputs: 7 | script: 8 | description: PowerShell script to execute in Actions-hydrated context 9 | required: true 10 | outputs: 11 | result: 12 | 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 }} 17 | runs: 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) }} 31 | branding: 32 | icon: terminal 33 | color: blue 34 | -------------------------------------------------------------------------------- /build-docs.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | param([switch]$Clean) 3 | $cmd = { 4 | $core = Import-Module ./lib/GitHubActionsCore -PassThru -Scope Local -Force 5 | 6 | $docsPath = 'docs/GitHubActionsCore' 7 | if (-not (Test-Path $docsPath)) { 8 | mkdir $docsPath | Out-Null 9 | } 10 | elseif ($Clean) { 11 | Remove-Item $docsPath -Force -Recurse 12 | } 13 | Write-Output "| Cmdlet | Synopsis |" > $docsPath/README.md 14 | Write-Output "|-|-|" >> $docsPath/README.md 15 | $core.ExportedCommands.Values | ForEach-Object { 16 | Get-Help $_.Name | Select-Object @{ 17 | Name = "Row" 18 | Expression = { 19 | $n = $_.Name.Trim() 20 | $s = $_.Synopsis.Trim() -replace '\r?\n', ' ' 21 | "| [$($n)]($($n).md) | $($s) |" 22 | } 23 | } 24 | } | Select-Object -Expand Row >> $docsPath/README.md 25 | $core.ExportedCommands.Values | ForEach-Object { 26 | Get-Help -Full $_.Name | Select-Object @{ 27 | Name = "Row" 28 | Expression = { 29 | $n = $_.Name.Trim() 30 | "# $n" 31 | "``````" 32 | $_ 33 | "``````" 34 | } 35 | } | Select-Object -Expand Row > "$docsPath/$($_.Name).md" 36 | } 37 | } 38 | pwsh -c $cmd -wd $PSScriptRoot -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Add-ActionPath.md: -------------------------------------------------------------------------------- 1 | # Add-ActionPath 2 | ``` 3 | 4 | NAME 5 | Add-ActionPath 6 | 7 | SYNOPSIS 8 | Prepends path to the PATH (for this action and future actions). 9 | Equivalent of `core.addPath(path)`. 10 | 11 | 12 | SYNTAX 13 | Add-ActionPath [-Path] [-SkipLocal] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Path 21 | The new path to add. 22 | 23 | Required? true 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | -SkipLocal [] 30 | Do not prepend path to current action's/step's environment PATH. 31 | 32 | Required? false 33 | Position? named 34 | Default value False 35 | Accept pipeline input? false 36 | Accept wildcard characters? false 37 | 38 | 39 | This cmdlet supports the common parameters: Verbose, Debug, 40 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 41 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 42 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 43 | 44 | INPUTS 45 | 46 | OUTPUTS 47 | 48 | 49 | RELATED LINKS 50 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path 51 | https://github.com/actions/toolkit/tree/main/packages/core#path-manipulation 52 | 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Add-ActionSecret.md: -------------------------------------------------------------------------------- 1 | # Add-ActionSecret 2 | ``` 3 | 4 | NAME 5 | Add-ActionSecret 6 | 7 | SYNOPSIS 8 | Registers a secret which will get masked from logs. 9 | Equivalent of `core.setSecret(secret)`. 10 | 11 | 12 | SYNTAX 13 | Add-ActionSecret [-Secret] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Secret 21 | The value of the secret. 22 | 23 | Required? true 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | 30 | This cmdlet supports the common parameters: Verbose, Debug, 31 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 32 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 33 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 34 | 35 | INPUTS 36 | 37 | OUTPUTS 38 | 39 | 40 | RELATED LINKS 41 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-log 42 | https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret 43 | 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Enter-ActionOutputGroup.md: -------------------------------------------------------------------------------- 1 | # Enter-ActionOutputGroup 2 | ``` 3 | 4 | NAME 5 | Enter-ActionOutputGroup 6 | 7 | SYNOPSIS 8 | Begin an output group. 9 | Output until the next `groupEnd` will be foldable in this group. 10 | Equivalent of `core.startGroup(name)`. 11 | 12 | 13 | SYNTAX 14 | Enter-ActionOutputGroup [-Name] [] 15 | 16 | 17 | DESCRIPTION 18 | Output until the next `groupEnd` will be foldable in this group. 19 | 20 | 21 | PARAMETERS 22 | -Name 23 | The name of the output group. 24 | 25 | Required? true 26 | Position? 1 27 | Default value 28 | Accept pipeline input? false 29 | Accept wildcard characters? false 30 | 31 | 32 | This cmdlet supports the common parameters: Verbose, Debug, 33 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 34 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 35 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 36 | 37 | INPUTS 38 | 39 | OUTPUTS 40 | 41 | 42 | RELATED LINKS 43 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines 44 | https://github.com/actions/toolkit/tree/main/packages/core#logging 45 | 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Exit-ActionOutputGroup.md: -------------------------------------------------------------------------------- 1 | # Exit-ActionOutputGroup 2 | ``` 3 | 4 | NAME 5 | Exit-ActionOutputGroup 6 | 7 | SYNOPSIS 8 | End an output group. 9 | Equivalent of `core.endGroup()`. 10 | 11 | 12 | SYNTAX 13 | Exit-ActionOutputGroup [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | 21 | This cmdlet supports the common parameters: Verbose, Debug, 22 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 23 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 24 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 25 | 26 | INPUTS 27 | 28 | OUTPUTS 29 | 30 | 31 | RELATED LINKS 32 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines 33 | https://github.com/actions/toolkit/tree/main/packages/core#logging 34 | 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Get-ActionInput.md: -------------------------------------------------------------------------------- 1 | # Get-ActionInput 2 | ``` 3 | 4 | NAME 5 | Get-ActionInput 6 | 7 | SYNOPSIS 8 | Gets the value of an input. The value is also trimmed. 9 | Equivalent of `core.getInput(name)`. 10 | 11 | 12 | SYNTAX 13 | Get-ActionInput [-Name] [-Required] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Name 21 | Name of the input to get 22 | 23 | Required? true 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | -Required [] 30 | Whether the input is required. If required and not present, will throw. 31 | 32 | Required? false 33 | Position? named 34 | Default value False 35 | Accept pipeline input? false 36 | Accept wildcard characters? false 37 | 38 | 39 | This cmdlet supports the common parameters: Verbose, Debug, 40 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 41 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 42 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 43 | 44 | INPUTS 45 | 46 | OUTPUTS 47 | System.String 48 | 49 | 50 | 51 | RELATED LINKS 52 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 53 | https://github.com/actions/toolkit/tree/main/packages/core#inputsoutputs 54 | 55 | ``` 56 | 57 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Get-ActionIsDebug.md: -------------------------------------------------------------------------------- 1 | # Get-ActionIsDebug 2 | ``` 3 | 4 | NAME 5 | Get-ActionIsDebug 6 | 7 | SYNOPSIS 8 | Gets whether Actions Step Debug is on or not. 9 | Equivalent of `core.isDebug()`. 10 | 11 | 12 | SYNTAX 13 | Get-ActionIsDebug [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | 21 | This cmdlet supports the common parameters: Verbose, Debug, 22 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 23 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 24 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 25 | 26 | INPUTS 27 | 28 | OUTPUTS 29 | System.Boolean 30 | 31 | 32 | 33 | RELATED LINKS 34 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 35 | https://github.com/actions/toolkit/tree/main/packages/core#logging 36 | 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Invoke-ActionGroup.md: -------------------------------------------------------------------------------- 1 | # Invoke-ActionGroup 2 | ``` 3 | 4 | NAME 5 | Invoke-ActionGroup 6 | 7 | SYNOPSIS 8 | Executes the argument script block within an output group. 9 | Equivalent of `core.group(name, func)`. 10 | 11 | 12 | SYNTAX 13 | Invoke-ActionGroup [-Name] [-ScriptBlock] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Name 21 | Name of the output group. 22 | 23 | Required? true 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | -ScriptBlock 30 | Script block to execute in between opening and closing output group. 31 | 32 | Required? true 33 | Position? 2 34 | Default value 35 | Accept pipeline input? false 36 | Accept wildcard characters? false 37 | 38 | 39 | This cmdlet supports the common parameters: Verbose, Debug, 40 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 41 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 42 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 43 | 44 | INPUTS 45 | 46 | OUTPUTS 47 | 48 | 49 | RELATED LINKS 50 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines 51 | https://github.com/actions/toolkit/tree/main/packages/core#logging 52 | 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Invoke-ActionNoCommandsBlock.md: -------------------------------------------------------------------------------- 1 | # Invoke-ActionNoCommandsBlock 2 | ``` 3 | 4 | NAME 5 | Invoke-ActionNoCommandsBlock 6 | 7 | SYNOPSIS 8 | Invokes a scriptblock that won't result in any output interpreted as a workflow command. 9 | Useful for printing arbitrary text that may contain command-like text. 10 | No quivalent in `@actions/core` package. 11 | 12 | 13 | SYNTAX 14 | Invoke-ActionNoCommandsBlock [-EndToken] [-ScriptBlock] [] 15 | 16 | Invoke-ActionNoCommandsBlock [-ScriptBlock] -GenerateToken [] 17 | 18 | 19 | DESCRIPTION 20 | 21 | 22 | PARAMETERS 23 | -EndToken 24 | String token to stop workflow commands, used after scriptblock to start workflow commands back. 25 | 26 | Required? true 27 | Position? 1 28 | Default value 29 | Accept pipeline input? false 30 | Accept wildcard characters? false 31 | 32 | -ScriptBlock 33 | Script block to invoke within a no-commands context. 34 | 35 | Required? true 36 | Position? 2 37 | Default value 38 | Accept pipeline input? false 39 | Accept wildcard characters? false 40 | 41 | -GenerateToken [] 42 | Use this to automatically generate a GUID and use it as the EndToken. 43 | 44 | Required? true 45 | Position? named 46 | Default value False 47 | Accept pipeline input? false 48 | Accept wildcard characters? false 49 | 50 | 51 | This cmdlet supports the common parameters: Verbose, Debug, 52 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 53 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 54 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 55 | 56 | INPUTS 57 | 58 | OUTPUTS 59 | 60 | 61 | RELATED LINKS 62 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#stopping-and-starting-workflow-commands 63 | 64 | ``` 65 | 66 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/README.md: -------------------------------------------------------------------------------- 1 | | Cmdlet | Synopsis | 2 | |-|-| 3 | | [Add-ActionPath](Add-ActionPath.md) | Prepends path to the PATH (for this action and future actions). Equivalent of `core.addPath(path)`. | 4 | | [Add-ActionSecret](Add-ActionSecret.md) | Registers a secret which will get masked from logs. Equivalent of `core.setSecret(secret)`. | 5 | | [Enter-ActionOutputGroup](Enter-ActionOutputGroup.md) | Begin an output group. Output until the next `groupEnd` will be foldable in this group. Equivalent of `core.startGroup(name)`. | 6 | | [Exit-ActionOutputGroup](Exit-ActionOutputGroup.md) | End an output group. Equivalent of `core.endGroup()`. | 7 | | [Get-ActionInput](Get-ActionInput.md) | Gets the value of an input. The value is also trimmed. Equivalent of `core.getInput(name)`. | 8 | | [Get-ActionIsDebug](Get-ActionIsDebug.md) | Gets whether Actions Step Debug is on or not. Equivalent of `core.isDebug()`. | 9 | | [Invoke-ActionGroup](Invoke-ActionGroup.md) | Executes the argument script block within an output group. Equivalent of `core.group(name, func)`. | 10 | | [Invoke-ActionNoCommandsBlock](Invoke-ActionNoCommandsBlock.md) | Invokes a scriptblock that won't result in any output interpreted as a workflow command. Useful for printing arbitrary text that may contain command-like text. No quivalent in `@actions/core` package. | 11 | | [Send-ActionCommand](Send-ActionCommand.md) | Sends a command to the hosting Workflow/Action context. Equivalent to `core.issue(cmd, msg)`/`core.issueCommand(cmd, props, msg)`. | 12 | | [Send-ActionFileCommand](Send-ActionFileCommand.md) | Sends a command to an Action Environment File. Equivalent to `core.issueFileCommand(cmd, msg)`. | 13 | | [Set-ActionCommandEcho](Set-ActionCommandEcho.md) | Enables or disables the echoing of commands into stdout for the rest of the step. Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. Equivalent of `core.setCommandEcho(enabled)`. | 14 | | [Set-ActionFailed](Set-ActionFailed.md) | Sets an action status to failed. When the action exits it will be with an exit code of 1. Equivalent of `core.setFailed(message)`. | 15 | | [Set-ActionOutput](Set-ActionOutput.md) | Sets the value of an output. Equivalent of `core.setOutput(name, value)`. | 16 | | [Set-ActionVariable](Set-ActionVariable.md) | Sets env variable for this action and future actions in the job. Equivalent of `core.exportVariable(name, value)`. | 17 | | [Write-ActionDebug](Write-ActionDebug.md) | Writes debug message to user log. Equivalent of `core.debug(message)`. | 18 | | [Write-ActionError](Write-ActionError.md) | Adds an error issue. Equivalent of `core.error(message)`. | 19 | | [Write-ActionInfo](Write-ActionInfo.md) | Writes info to log with console.log. Equivalent of `core.info(message)`. Forwards to Write-Host. | 20 | | [Write-ActionWarning](Write-ActionWarning.md) | Adds a warning issue. Equivalent of `core.warning(message)`. | 21 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Send-ActionCommand.md: -------------------------------------------------------------------------------- 1 | # Send-ActionCommand 2 | ``` 3 | 4 | NAME 5 | Send-ActionCommand 6 | 7 | SYNOPSIS 8 | Sends a command to the hosting Workflow/Action context. 9 | Equivalent to `core.issue(cmd, msg)`/`core.issueCommand(cmd, props, msg)`. 10 | 11 | 12 | SYNTAX 13 | Send-ActionCommand [-Command] [-Properties] [[-Message] ] [] 14 | 15 | Send-ActionCommand [-Command] [[-Message] ] [] 16 | 17 | 18 | DESCRIPTION 19 | Command Format: 20 | ::workflow-command parameter1={data},parameter2={data}::{command value} 21 | 22 | 23 | PARAMETERS 24 | -Command 25 | The workflow command name. 26 | 27 | Required? true 28 | Position? 1 29 | Default value 30 | Accept pipeline input? false 31 | Accept wildcard characters? false 32 | 33 | -Properties 34 | Properties to add to the command. 35 | 36 | Required? true 37 | Position? 2 38 | Default value 39 | Accept pipeline input? false 40 | Accept wildcard characters? false 41 | 42 | -Message 43 | Message to add to the command. 44 | 45 | Required? false 46 | Position? 3 47 | Default value 48 | Accept pipeline input? false 49 | Accept wildcard characters? false 50 | 51 | 52 | This cmdlet supports the common parameters: Verbose, Debug, 53 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 54 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 55 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 56 | 57 | INPUTS 58 | 59 | OUTPUTS 60 | 61 | -------------------------- EXAMPLE 1 -------------------------- 62 | 63 | PS>Send-ActionCommand warning 'This is the user warning message' 64 | ::warning::This is the user warning message 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------- EXAMPLE 2 -------------------------- 72 | 73 | PS>Send-ActionCommand set-secret @{name='mypassword'} 'definitelyNotAPassword!' 74 | ::set-secret name=mypassword::definitelyNotAPassword! 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | RELATED LINKS 83 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#about-workflow-commands 84 | 85 | ``` 86 | 87 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Send-ActionFileCommand.md: -------------------------------------------------------------------------------- 1 | # Send-ActionFileCommand 2 | ``` 3 | 4 | NAME 5 | Send-ActionFileCommand 6 | 7 | SYNOPSIS 8 | Sends a command to an Action Environment File. 9 | Equivalent to `core.issueFileCommand(cmd, msg)`. 10 | 11 | 12 | SYNTAX 13 | Send-ActionFileCommand [-Command] [-Message] [] 14 | 15 | 16 | DESCRIPTION 17 | Appends given message to an Action Environment File. 18 | 19 | 20 | PARAMETERS 21 | -Command 22 | Command (environment file variable suffix) to send message for. 23 | 24 | Required? true 25 | Position? 1 26 | Default value 27 | Accept pipeline input? false 28 | Accept wildcard characters? false 29 | 30 | -Message 31 | Message to append. 32 | 33 | Required? true 34 | Position? 2 35 | Default value 36 | Accept pipeline input? true (ByValue) 37 | Accept wildcard characters? false 38 | 39 | 40 | This cmdlet supports the common parameters: Verbose, Debug, 41 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 42 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 43 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 44 | 45 | INPUTS 46 | 47 | OUTPUTS 48 | 49 | -------------------------- EXAMPLE 1 -------------------------- 50 | 51 | PS>Send-ActionFileCommand ENV 'myvar=value' 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------- EXAMPLE 2 -------------------------- 59 | 60 | PS>'myvar=value', 'myvar2=novalue' | Send-ActionFileCommand ENV 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | RELATED LINKS 69 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files 70 | 71 | ``` 72 | 73 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Set-ActionCommandEcho.md: -------------------------------------------------------------------------------- 1 | # Set-ActionCommandEcho 2 | ``` 3 | 4 | NAME 5 | Set-ActionCommandEcho 6 | 7 | SYNOPSIS 8 | Enables or disables the echoing of commands into stdout for the rest of the step. 9 | Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 10 | Equivalent of `core.setCommandEcho(enabled)`. 11 | 12 | 13 | SYNTAX 14 | Set-ActionCommandEcho [-Enabled] [] 15 | 16 | 17 | DESCRIPTION 18 | 19 | 20 | PARAMETERS 21 | -Enabled 22 | $true to enable echoing, $false to disable. 23 | 24 | Required? true 25 | Position? 1 26 | Default value False 27 | Accept pipeline input? false 28 | Accept wildcard characters? false 29 | 30 | 31 | This cmdlet supports the common parameters: Verbose, Debug, 32 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 33 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 34 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 35 | 36 | INPUTS 37 | 38 | OUTPUTS 39 | 40 | 41 | RELATED LINKS 42 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#echoing-command-outputs 43 | 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Set-ActionFailed.md: -------------------------------------------------------------------------------- 1 | # Set-ActionFailed 2 | ``` 3 | 4 | NAME 5 | Set-ActionFailed 6 | 7 | SYNOPSIS 8 | Sets an action status to failed. 9 | When the action exits it will be with an exit code of 1. 10 | Equivalent of `core.setFailed(message)`. 11 | 12 | 13 | SYNTAX 14 | Set-ActionFailed [[-Message] ] [] 15 | 16 | 17 | DESCRIPTION 18 | 19 | 20 | PARAMETERS 21 | -Message 22 | Add issue message. 23 | 24 | Required? false 25 | Position? 1 26 | Default value 27 | Accept pipeline input? false 28 | Accept wildcard characters? false 29 | 30 | 31 | This cmdlet supports the common parameters: Verbose, Debug, 32 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 33 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 34 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 35 | 36 | INPUTS 37 | 38 | OUTPUTS 39 | 40 | 41 | RELATED LINKS 42 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 43 | https://github.com/actions/toolkit/tree/main/packages/core#exit-codes 44 | 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Set-ActionOutput.md: -------------------------------------------------------------------------------- 1 | # Set-ActionOutput 2 | ``` 3 | 4 | NAME 5 | Set-ActionOutput 6 | 7 | SYNOPSIS 8 | Sets the value of an output. 9 | Equivalent of `core.setOutput(name, value)`. 10 | 11 | 12 | SYNTAX 13 | Set-ActionOutput [-Name] [-Value] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Name 21 | Name of the output to set. 22 | 23 | Required? true 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | -Value 30 | Value to store. Non-string values will be converted to a string via ConvertTo-Json. 31 | 32 | Required? true 33 | Position? 2 34 | Default value 35 | Accept pipeline input? false 36 | Accept wildcard characters? false 37 | 38 | 39 | This cmdlet supports the common parameters: Verbose, Debug, 40 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 41 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 42 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 43 | 44 | INPUTS 45 | 46 | OUTPUTS 47 | 48 | 49 | RELATED LINKS 50 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter 51 | https://github.com/actions/toolkit/tree/main/packages/core#inputsoutputs 52 | 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Set-ActionVariable.md: -------------------------------------------------------------------------------- 1 | # Set-ActionVariable 2 | ``` 3 | 4 | NAME 5 | Set-ActionVariable 6 | 7 | SYNOPSIS 8 | Sets env variable for this action and future actions in the job. 9 | Equivalent of `core.exportVariable(name, value)`. 10 | 11 | 12 | SYNTAX 13 | Set-ActionVariable [-Name] [-Value] [-SkipLocal] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Name 21 | The name of the variable to set. 22 | 23 | Required? true 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | -Value 30 | The value of the variable. Non-string values will be converted to a string via ConvertTo-Json. 31 | 32 | Required? true 33 | Position? 2 34 | Default value 35 | Accept pipeline input? false 36 | Accept wildcard characters? false 37 | 38 | -SkipLocal [] 39 | Do not set variable in current action's/step's environment. 40 | 41 | Required? false 42 | Position? named 43 | Default value False 44 | Accept pipeline input? false 45 | Accept wildcard characters? false 46 | 47 | 48 | This cmdlet supports the common parameters: Verbose, Debug, 49 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 50 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 51 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 52 | 53 | INPUTS 54 | 55 | OUTPUTS 56 | 57 | 58 | RELATED LINKS 59 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable 60 | https://github.com/actions/toolkit/tree/main/packages/core#exporting-variables 61 | 62 | ``` 63 | 64 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Write-ActionDebug.md: -------------------------------------------------------------------------------- 1 | # Write-ActionDebug 2 | ``` 3 | 4 | NAME 5 | Write-ActionDebug 6 | 7 | SYNOPSIS 8 | Writes debug message to user log. 9 | Equivalent of `core.debug(message)`. 10 | 11 | 12 | SYNTAX 13 | Write-ActionDebug [[-Message] ] [] 14 | 15 | 16 | DESCRIPTION 17 | 18 | 19 | PARAMETERS 20 | -Message 21 | Debug message. 22 | 23 | Required? false 24 | Position? 1 25 | Default value 26 | Accept pipeline input? false 27 | Accept wildcard characters? false 28 | 29 | 30 | This cmdlet supports the common parameters: Verbose, Debug, 31 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 32 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 33 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 34 | 35 | INPUTS 36 | 37 | OUTPUTS 38 | 39 | 40 | RELATED LINKS 41 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-debug-message 42 | https://github.com/actions/toolkit/tree/main/packages/core#logging 43 | 44 | ``` 45 | 46 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Write-ActionError.md: -------------------------------------------------------------------------------- 1 | # Write-ActionError 2 | ``` 3 | 4 | NAME 5 | Write-ActionError 6 | 7 | SYNOPSIS 8 | Adds an error issue. 9 | Equivalent of `core.error(message)`. 10 | 11 | 12 | SYNTAX 13 | Write-ActionError [[-Message] ] [-File] [-Line] [-Column] [] 14 | 15 | Write-ActionError [[-Message] ] [-File] [-Line] [] 16 | 17 | Write-ActionError [[-Message] ] [-File] [] 18 | 19 | Write-ActionError [[-Message] ] [] 20 | 21 | 22 | DESCRIPTION 23 | 24 | 25 | PARAMETERS 26 | -Message 27 | Error issue message. 28 | 29 | Required? false 30 | Position? 1 31 | Default value 32 | Accept pipeline input? false 33 | Accept wildcard characters? false 34 | 35 | -File 36 | Filename where the issue occured. 37 | 38 | Required? true 39 | Position? 2 40 | Default value 41 | Accept pipeline input? false 42 | Accept wildcard characters? false 43 | 44 | -Line 45 | Line number of the File where the issue occured. 46 | 47 | Required? true 48 | Position? 3 49 | Default value 0 50 | Accept pipeline input? false 51 | Accept wildcard characters? false 52 | 53 | -Column 54 | Column number in Line in File where the issue occured. 55 | 56 | Required? true 57 | Position? 4 58 | Default value 0 59 | Accept pipeline input? false 60 | Accept wildcard characters? false 61 | 62 | 63 | This cmdlet supports the common parameters: Verbose, Debug, 64 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 65 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 66 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 67 | 68 | INPUTS 69 | 70 | OUTPUTS 71 | 72 | NOTES 73 | 74 | 75 | File, Line and Column parameters are supported by the actual workflow command, 76 | but not available in `@actions/core` package. 77 | 78 | 79 | RELATED LINKS 80 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message 81 | https://github.com/actions/toolkit/tree/main/packages/core#logging 82 | 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Write-ActionInfo.md: -------------------------------------------------------------------------------- 1 | # Write-ActionInfo 2 | ``` 3 | 4 | NAME 5 | Write-ActionInfo 6 | 7 | SYNOPSIS 8 | Writes info to log with console.log. 9 | Equivalent of `core.info(message)`. 10 | Forwards to Write-Host. 11 | 12 | 13 | SYNTAX 14 | Write-ActionInfo [[-Message] ] [] 15 | 16 | 17 | DESCRIPTION 18 | 19 | 20 | PARAMETERS 21 | -Message 22 | Info message. 23 | 24 | Required? false 25 | Position? 1 26 | Default value 27 | Accept pipeline input? false 28 | Accept wildcard characters? false 29 | 30 | 31 | This cmdlet supports the common parameters: Verbose, Debug, 32 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 33 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 34 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 35 | 36 | INPUTS 37 | 38 | OUTPUTS 39 | 40 | 41 | RELATED LINKS 42 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 43 | https://github.com/actions/toolkit/tree/main/packages/core#logging 44 | 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /docs/GitHubActionsCore/Write-ActionWarning.md: -------------------------------------------------------------------------------- 1 | # Write-ActionWarning 2 | ``` 3 | 4 | NAME 5 | Write-ActionWarning 6 | 7 | SYNOPSIS 8 | Adds a warning issue. 9 | Equivalent of `core.warning(message)`. 10 | 11 | 12 | SYNTAX 13 | Write-ActionWarning [[-Message] ] [-File] [-Line] [-Column] [] 14 | 15 | Write-ActionWarning [[-Message] ] [-File] [-Line] [] 16 | 17 | Write-ActionWarning [[-Message] ] [-File] [] 18 | 19 | Write-ActionWarning [[-Message] ] [] 20 | 21 | 22 | DESCRIPTION 23 | 24 | 25 | PARAMETERS 26 | -Message 27 | Warning issue message. 28 | 29 | Required? false 30 | Position? 1 31 | Default value 32 | Accept pipeline input? false 33 | Accept wildcard characters? false 34 | 35 | -File 36 | Filename where the issue occured. 37 | 38 | Required? true 39 | Position? 2 40 | Default value 41 | Accept pipeline input? false 42 | Accept wildcard characters? false 43 | 44 | -Line 45 | Line number of the File where the issue occured. 46 | 47 | Required? true 48 | Position? 3 49 | Default value 0 50 | Accept pipeline input? false 51 | Accept wildcard characters? false 52 | 53 | -Column 54 | Column number in Line in File where the issue occured. 55 | 56 | Required? true 57 | Position? 4 58 | Default value 0 59 | Accept pipeline input? false 60 | Accept wildcard characters? false 61 | 62 | 63 | This cmdlet supports the common parameters: Verbose, Debug, 64 | ErrorAction, ErrorVariable, WarningAction, WarningVariable, 65 | OutBuffer, PipelineVariable, and OutVariable. For more information, see 66 | about_CommonParameters (https://go.microsoft.com/fwlink/?LinkID=113216). 67 | 68 | INPUTS 69 | 70 | OUTPUTS 71 | 72 | NOTES 73 | 74 | 75 | File, Line and Column parameters are supported by the actual workflow command, 76 | but not available in `@actions/core` package. 77 | 78 | 79 | RELATED LINKS 80 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message 81 | https://github.com/actions/toolkit/tree/main/packages/core#logging 82 | 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /lib/GitHubActionsCore/GitHubActionsCore.Tests.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Module @{ ModuleName = 'Pester'; ModuleVersion = '5.1' } 2 | 3 | BeforeAll { 4 | Import-Module $PSScriptRoot -Force 5 | } 6 | 7 | Describe 'Get-ActionInput' { 8 | BeforeEach { 9 | $env:INPUT_TEST_INPUT = $null 10 | } 11 | Context "When requested input doesn't exist" { 12 | It "Should return empty string" { 13 | $result = Get-ActionInput TEST_INPUT 14 | $result | Should -Be '' 15 | } 16 | It "Given Required switch, it throws" { 17 | { 18 | Get-ActionInput TEST_INPUT -Required 19 | } | Should -Throw 20 | } 21 | } 22 | Context "When requested input exists" { 23 | It "Should return it's value" { 24 | $env:INPUT_TEST_INPUT = 'test value' 25 | 26 | $result = Get-ActionInput TEST_INPUT 27 | 28 | $result | Should -Be 'test value' 29 | } 30 | It "Should trim the returned value" { 31 | $env:INPUT_TEST_INPUT = "`n test value `n `n" 32 | 33 | $result = Get-ActionInput TEST_INPUT 34 | 35 | $result | Should -Be 'test value' 36 | } 37 | } 38 | Context "When input name contains spaces" { 39 | It "Should replace them with underscores" { 40 | $env:INPUT_TEST_INPUT = 'test value' 41 | 42 | $result = Get-ActionInput 'test input' 43 | 44 | $result | Should -Be 'test value' 45 | } 46 | } 47 | AfterEach { 48 | $env:INPUT_TEST_INPUT = $null 49 | } 50 | } 51 | Describe 'Set-ActionOutput' { 52 | BeforeAll { 53 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 54 | $oldGithubOut = $env:GITHUB_OUTPUT 55 | } 56 | BeforeEach { 57 | $env:GITHUB_OUTPUT = $null 58 | } 59 | AfterAll { 60 | $env:GITHUB_OUTPUT = $oldGithubOut 61 | } 62 | Context "Given value ''" -Foreach @( 63 | @{ Value = ''; ExpectedCmd = ''; ExpectedEnv = $null } 64 | @{ Value = 'test value'; ExpectedCmd = 'test value'; ExpectedEnv = 'test value' } 65 | @{ Value = "test `n multiline `r`n value"; ExpectedCmd = 'test %0A multiline %0D%0A value'; ExpectedEnv = "test `n multiline `r`n value"; Multiline = $true } 66 | @{ Value = 'A % B'; ExpectedCmd = 'A %25 B'; ExpectedEnv = 'A % B' } 67 | @{ Value = [ordered]@{ a = '1x'; b = '2y' }; ExpectedCmd = '{"a":"1x","b":"2y"}'; ExpectedEnv = '{"a":"1x","b":"2y"}' } 68 | ) { 69 | Context "When GITHUB_OUTPUT not set" { 70 | BeforeAll { 71 | Mock Write-Host { } -ModuleName GitHubActionsCore 72 | } 73 | It "Sends command with ''" { 74 | Set-ActionOutput 'my-result' $Value 75 | 76 | Should -Invoke Write-Host -ParameterFilter { 77 | $Object -eq "::set-output name=my-result::$ExpectedCmd" 78 | } -ModuleName GitHubActionsCore 79 | } 80 | } 81 | Context "When GITHUB_OUTPUT is set" { 82 | BeforeEach { 83 | $testPath = 'TestDrive:/out-cmd.env' 84 | Set-Content $testPath '' -NoNewline 85 | $env:GITHUB_OUTPUT = $testPath 86 | } 87 | It "Appends command file with formatted command ''" { 88 | Set-ActionOutput 'my-result' $Value 89 | 90 | $eol = [System.Environment]::NewLine 91 | if ($Multiline) { 92 | $null, $delimiter = (Get-Content $testPath)[0] -split "<<" 93 | Get-Content $testPath -Raw 94 | | Should -BeExactly "my-result<<$delimiter${eol}$ExpectedEnv${eol}$delimiter${eol}" 95 | } 96 | else { 97 | Get-Content $testPath -Raw 98 | | Should -BeExactly "my-result=$ExpectedEnv${eol}" 99 | } 100 | } 101 | } 102 | } 103 | } 104 | Describe 'Add-ActionSecret' { 105 | BeforeAll { 106 | Mock Write-Host { } -ModuleName GitHubActionsCore 107 | } 108 | It "Sends appropriate workflow command to host" { 109 | Add-ActionSecret 'test value' 110 | 111 | Should -Invoke Write-Host -ParameterFilter { 112 | $Object -eq '::add-mask::test value' 113 | } -ModuleName GitHubActionsCore 114 | } 115 | } 116 | Describe 'Set-ActionVariable' { 117 | BeforeAll { 118 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 119 | $oldGithubEnv = $env:GITHUB_ENV 120 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 121 | $oldTestVar = $env:TESTVAR 122 | } 123 | BeforeEach { 124 | $env:GITHUB_ENV = $null 125 | $env:TESTVAR = $null 126 | } 127 | AfterAll { 128 | $env:GITHUB_ENV = $oldGithubEnv 129 | $env:TESTVAR = $oldTestVar 130 | } 131 | Context "Given value ''" -Foreach @( 132 | @{ Value = ''; ExpectedCmd = ''; ExpectedEnv = $null } 133 | @{ Value = 'test value'; ExpectedCmd = 'test value'; ExpectedEnv = 'test value' } 134 | @{ Value = "test `n multiline `r`n value"; ExpectedCmd = 'test %0A multiline %0D%0A value'; ExpectedEnv = "test `n multiline `r`n value"; Multiline = $true } 135 | @{ Value = 'A % B'; ExpectedCmd = 'A %25 B'; ExpectedEnv = 'A % B' } 136 | @{ Value = [ordered]@{ a = '1x'; b = '2y' }; ExpectedCmd = '{"a":"1x","b":"2y"}'; ExpectedEnv = '{"a":"1x","b":"2y"}' } 137 | ) { 138 | Context "When GITHUB_ENV not set" { 139 | BeforeAll { 140 | Mock Write-Host { } -ModuleName GitHubActionsCore 141 | } 142 | It "Sends command with '' and sets env var to ''" { 143 | Set-ActionVariable TESTVAR $Value 144 | 145 | $env:TESTVAR | Should -Be $ExpectedEnv 146 | Should -Invoke Write-Host -ParameterFilter { 147 | $Object -eq "::set-env name=TESTVAR::$ExpectedCmd" 148 | } -ModuleName GitHubActionsCore 149 | } 150 | It "Sends command with '' and doesn't set env var due to -SkipLocal" { 151 | Set-ActionVariable TESTVAR $Value -SkipLocal 152 | 153 | $env:TESTVAR | Should -BeNullOrEmpty 154 | Should -Invoke Write-Host -ParameterFilter { 155 | $Object -eq "::set-env name=TESTVAR::$ExpectedCmd" 156 | } -ModuleName GitHubActionsCore 157 | } 158 | } 159 | Context "When GITHUB_ENV is set" { 160 | BeforeEach { 161 | $testPath = 'TestDrive:/env-cmd.env' 162 | Set-Content $testPath '' -NoNewline 163 | $env:GITHUB_ENV = $testPath 164 | } 165 | It "Appends command file with formatted command and sets env var to ''" { 166 | Set-ActionVariable TESTVAR $Value 167 | 168 | $env:TESTVAR | Should -Be $ExpectedEnv 169 | $eol = [System.Environment]::NewLine 170 | if ($Multiline) { 171 | $null, $delimiter = (Get-Content $testPath)[0] -split "<<" 172 | Get-Content $testPath -Raw 173 | | Should -BeExactly "TESTVAR<<$delimiter${eol}$ExpectedEnv${eol}$delimiter${eol}" 174 | } 175 | else { 176 | Get-Content $testPath -Raw 177 | | Should -BeExactly "TESTVAR=$ExpectedEnv${eol}" 178 | } 179 | } 180 | It "Appends command file with formatted command and doesn't set env var due to -SkipLocal" { 181 | Set-ActionVariable TESTVAR $Value -SkipLocal 182 | 183 | $env:TESTVAR | Should -BeNullOrEmpty 184 | $eol = [System.Environment]::NewLine 185 | if ($Multiline) { 186 | $null, $delimiter = (Get-Content $testPath)[0] -split "<<" 187 | Get-Content $testPath -Raw 188 | | Should -BeExactly "TESTVAR<<$delimiter${eol}$ExpectedEnv${eol}$delimiter${eol}" 189 | } 190 | else { 191 | Get-Content $testPath -Raw 192 | | Should -BeExactly "TESTVAR=$ExpectedEnv${eol}" 193 | } 194 | } 195 | } 196 | } 197 | } 198 | Describe 'Add-ActionPath' { 199 | BeforeAll { 200 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 201 | $oldPath = $env:PATH 202 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 203 | $oldGithubPath = $env:GITHUB_PATH 204 | } 205 | BeforeEach { 206 | $env:PATH = $oldPath 207 | $env:GITHUB_PATH = $null 208 | } 209 | AfterAll { 210 | $env:PATH = $oldPath 211 | $env:GITHUB_PATH = $oldGithubPath 212 | } 213 | Context "When GITHUB_PATH is not set" { 214 | BeforeAll { 215 | Mock Write-Host { } -ModuleName GitHubActionsCore 216 | } 217 | It "Sends appropriate workflow command to host and prepends PATH" { 218 | Add-ActionPath 'test path' 219 | 220 | $env:PATH | Should -BeLike "test path$([System.IO.Path]::PathSeparator)*" -Because 'PATH should be also prepended in current scope' 221 | Should -Invoke Write-Host -ParameterFilter { 222 | $Object -eq '::add-path::test path' 223 | } -ModuleName GitHubActionsCore 224 | } 225 | It "Given SkipLocal switch, sends command but doesn't change PATH" { 226 | $path = $env:PATH 227 | 228 | Add-ActionPath 'test path' -SkipLocal 229 | 230 | $env:PATH | Should -Be $path -Because "PATH shouldn't be modified" 231 | Should -Invoke Write-Host -ParameterFilter { 232 | $Object -eq '::add-path::test path' 233 | } -ModuleName GitHubActionsCore 234 | } 235 | } 236 | Context "When GITHUB_PATH is set" { 237 | BeforeEach { 238 | $testPath = 'TestDrive:/path-cmd.env' 239 | Set-Content $testPath '' -NoNewline 240 | $env:GITHUB_PATH = $testPath 241 | } 242 | It "Sends appropriate workflow command to command file and prepends PATH" { 243 | Add-ActionPath 'test path' 244 | 245 | $env:PATH | Should -BeLike "test path$([System.IO.Path]::PathSeparator)*" -Because 'PATH should be also prepended in current scope' 246 | Get-Content $testPath -Raw 247 | | Should -BeExactly "test path$([System.Environment]::NewLine)" 248 | } 249 | It "Sends appropriate workflow command to command file but doesn't change PATH due to -SkipLocal" { 250 | $path = $env:PATH 251 | 252 | Add-ActionPath 'test path' -SkipLocal 253 | 254 | $env:PATH | Should -Be $path -Because "PATH shouldn't be modified" 255 | Get-Content $testPath -Raw 256 | | Should -BeExactly "test path$([System.Environment]::NewLine)" 257 | } 258 | } 259 | } 260 | Describe 'Set-ActionCommandEcho' { 261 | BeforeAll { 262 | Mock Write-Host { } -ModuleName GitHubActionsCore 263 | } 264 | It "Given '' should send a workflow command to turn echoing commands " -TestCases @( 265 | @{ Value = $false; Expected = 'off' } 266 | @{ Value = $true; Expected = 'on' } 267 | ) { 268 | Set-ActionCommandEcho $Value 269 | 270 | Should -Invoke Write-Host -ParameterFilter { 271 | $Object -eq "::echo::$Expected" 272 | } -ModuleName GitHubActionsCore 273 | } 274 | } 275 | Describe 'Set-ActionFailed' { 276 | BeforeAll { 277 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 278 | $oldExitCode = [System.Environment]::ExitCode 279 | Mock Write-Host { } -ModuleName GitHubActionsCore 280 | } 281 | BeforeEach { 282 | [System.Environment]::ExitCode = 0 283 | } 284 | It "Given message '' should send error command with message ' and set ExitCode to 1" -TestCases @( 285 | @{ Value = $null; Expected = '' } 286 | @{ Value = ''; Expected = '' } 287 | @{ Value = 'fail'; Expected = 'fail' } 288 | @{ Value = "first fail line`nsecond fail line"; Expected = 'first fail line%0Asecond fail line' } 289 | ) { 290 | Set-ActionFailed $Value 291 | 292 | [System.Environment]::ExitCode | Should -Be 1 -Because 'this exit code is expected to be used upon exit' 293 | Should -Invoke Write-Host -ParameterFilter { 294 | $Object -eq "::error::$Expected" 295 | } -ModuleName GitHubActionsCore 296 | } 297 | AfterAll { 298 | [System.Environment]::ExitCode = $oldExitCode 299 | } 300 | } 301 | Describe 'Get-ActionIsDebug' { 302 | BeforeAll { 303 | Mock Write-Host { } -ModuleName GitHubActionsCore 304 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 305 | $oldEnvRunnerDebug = $env:RUNNER_DEBUG 306 | } 307 | BeforeEach { 308 | $env:RUNNER_DEBUG = $null 309 | } 310 | AfterAll { 311 | $env:RUNNER_DEBUG = $oldEnvRunnerDebug 312 | } 313 | It 'Given env var is not set, return false' { 314 | $result = Get-ActionIsDebug 315 | 316 | $result | Should -BeExactly $false 317 | } 318 | It "Given env var is set to '' it returns ''" -TestCases @( 319 | @{ Value = $null; Expected = $false } 320 | @{ Value = 0; Expected = $false } 321 | @{ Value = 2; Expected = $false } 322 | @{ Value = 1; Expected = $true } 323 | @{ Value = '1'; Expected = $true } 324 | @{ Value = 'true'; Expected = $false } 325 | ) { 326 | $env:RUNNER_DEBUG = $Value 327 | 328 | $result = Get-ActionIsDebug 329 | 330 | $result | Should -BeExactly $Expected 331 | } 332 | } 333 | Describe 'Write-ActionError' { 334 | BeforeAll { 335 | Mock Write-Host { } -ModuleName GitHubActionsCore 336 | } 337 | It "Given a message '' sends a workflow command with it" -TestCases @( 338 | @{ Value = $null; Expected = '' } 339 | @{ Value = 'my error'; Expected = 'my error' } 340 | @{ Value = "my error`nsecond line"; Expected = 'my error%0Asecond line' } 341 | ) { 342 | Write-ActionError $Value 343 | Should -Invoke Write-Host -ParameterFilter { 344 | $Object -eq "::error::$Expected" 345 | } -ModuleName GitHubActionsCore 346 | } 347 | } 348 | Describe 'Write-ActionWarning' { 349 | BeforeAll { 350 | Mock Write-Host { } -ModuleName GitHubActionsCore 351 | } 352 | It "Given a message '' sends a workflow command with it" -TestCases @( 353 | @{ Value = $null; Expected = '' } 354 | @{ Value = 'my warning'; Expected = 'my warning' } 355 | @{ Value = "my warning`nsecond line"; Expected = 'my warning%0Asecond line' } 356 | ) { 357 | Write-ActionWarning $Value 358 | Should -Invoke Write-Host -ParameterFilter { 359 | $Object -eq "::warning::$Expected" 360 | } -ModuleName GitHubActionsCore 361 | } 362 | } 363 | 364 | Describe 'Write-ActionInfo' { 365 | BeforeAll { 366 | Mock Write-Host { } -ModuleName GitHubActionsCore 367 | } 368 | It "Given a message '' sends it to host" -TestCases @( 369 | @{ Value = 'my log'; Expected = 'my log' } 370 | @{ Value = "my log`nnewline"; Expected = "my log`nnewline" } 371 | ) { 372 | Write-ActionInfo $Value 373 | Should -Invoke Write-Host -ParameterFilter { 374 | $Object -eq $Expected 375 | } -ModuleName GitHubActionsCore 376 | } 377 | } 378 | Describe 'Enter-ActionOutputGroup' { 379 | BeforeAll { 380 | Mock Write-Host { } -ModuleName GitHubActionsCore 381 | } 382 | It "Given '' sends a workflow command with it" -TestCases @( 383 | @{ Name = 'my group'; Expected = 'my group' } 384 | @{ Name = 'my group with percent%'; Expected = 'my group with percent%25' } 385 | ) { 386 | Enter-ActionOutputGroup $Name 387 | Should -Invoke Write-Host -ParameterFilter { 388 | $Object -eq "::group::$Expected" 389 | } -ModuleName GitHubActionsCore 390 | } 391 | } 392 | Describe 'Exit-ActionOutputGroup' { 393 | BeforeAll { 394 | Mock Write-Host { } -ModuleName GitHubActionsCore 395 | } 396 | It "Sends a workflow command" { 397 | Exit-ActionOutputGroup 398 | Should -Invoke Write-Host -ParameterFilter { 399 | $Object -eq '::endgroup::' 400 | } -ModuleName GitHubActionsCore 401 | } 402 | } 403 | Describe 'Invoke-ActionGroup' { 404 | BeforeAll { 405 | Mock Write-Host { } -ModuleName GitHubActionsCore 406 | } 407 | It "Given a scriptblock, sends a workflow command before and after it" { 408 | Invoke-ActionGroup 'my group' { 409 | Write-Output 'doing stuff' 410 | } 411 | @('::group::my group', '::endgroup::') | ForEach-Object { 412 | $cmd = $_ 413 | Should -Invoke Write-Host -ParameterFilter { 414 | $Object -eq $cmd 415 | } -ModuleName GitHubActionsCore 416 | } 417 | } 418 | } 419 | Describe 'Invoke-ActionNoCommandsBlock' { 420 | BeforeAll { 421 | Mock Write-Host { } -ModuleName GitHubActionsCore 422 | } 423 | It "Given a scriptblock, sends a workflow command before and after it" { 424 | Invoke-ActionNoCommandsBlock 'my block' { 425 | Write-Output 'doing stuff' 426 | } 427 | @('::stop-commands::my block', '::my block::') | ForEach-Object { 428 | $cmd = $_ 429 | Should -Invoke Write-Host -ParameterFilter { 430 | $Object -eq $cmd 431 | } -ModuleName GitHubActionsCore 432 | } 433 | } 434 | } 435 | Describe 'Send-ActionCommand' { 436 | BeforeAll { 437 | Mock Write-Host { } -ModuleName GitHubActionsCore 438 | } 439 | It "Given no command ('') throws" -TestCases @( 440 | @{ Value = $null } 441 | @{ Value = '' } 442 | ) { 443 | { 444 | Send-ActionCommand -Command $Value 445 | } | Should -Throw "Cannot validate argument on parameter 'Command'. The argument is null or empty.*" 446 | } 447 | It "Given a command with message '' writes '' to host" -TestCases @( 448 | @{ Msg = $null; Expected = '::test-cmd::' } 449 | @{ Msg = ''; Expected = '::test-cmd::' } 450 | @{ Msg = 'a'; Expected = '::test-cmd::a' } 451 | @{ Msg = "a `r `n b : c % d"; Expected = '::test-cmd::a %0D %0A b : c %25 d' } 452 | ) { 453 | Send-ActionCommand test-cmd -Message $Msg 454 | 455 | Should -Invoke Write-Host -ParameterFilter { 456 | $Object -eq $Expected 457 | } -ModuleName GitHubActionsCore 458 | } 459 | It "Given a command with params '' writes '' to host" -TestCases @( 460 | @{ Params = @{ a = $null; b = '' }; Expected = '::test-cmd::' } 461 | @{ Params = @{ a = 'A' }; Expected = '::test-cmd a=A::' } 462 | @{ Params = [ordered]@{ a = 'A'; b = 'B' }; Expected = '::test-cmd a=A,b=B::' } 463 | @{ Params = [ordered]@{ a = "A `r B `n C : D , E % F" }; Expected = '::test-cmd a=A %0D B %0A C %3A D %2C E %25 F::' } 464 | ) { 465 | Send-ActionCommand test-cmd $Params 466 | 467 | Should -Invoke Write-Host -ParameterFilter { 468 | $Object -eq $Expected 469 | } -ModuleName GitHubActionsCore 470 | } 471 | } 472 | 473 | Describe 'Send-ActionFileCommand' { 474 | BeforeAll { 475 | [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'Used in AfterAll')] 476 | $oldGithubTestcmd = $env:GITHUB_TESTCMD 477 | } 478 | BeforeEach { 479 | $testPath = 'TestDrive:/testcmd.env' 480 | $env:GITHUB_TESTCMD = $testPath 481 | } 482 | AfterAll { 483 | $env:GITHUB_TESTCMD = $oldGithubTestcmd 484 | } 485 | Context "When file doesn't exist" { 486 | BeforeEach { 487 | Remove-Item $testPath -Force -ea:Ignore 488 | } 489 | It "Given no command ('') throws" -TestCases @( 490 | @{ Value = $null } 491 | @{ Value = '' } 492 | ) { 493 | { 494 | Send-ActionFileCommand -Command $Value -Message 'foobar' 495 | } | Should -Throw "Cannot validate argument on parameter 'Command'. The argument is null or empty.*" 496 | } 497 | It "Given command for which env var doesn't exist" { 498 | $env:GITHUB_TESTCMD = $null 499 | { 500 | Send-ActionFileCommand -Command TESTCMD -Message 'foobar' 501 | } | Should -Throw 'Unable to find environment variable for file command TESTCMD' 502 | } 503 | It "Given command for which file doesn't exist" { 504 | { 505 | Send-ActionFileCommand -Command TESTCMD -Message 'foobar' 506 | } | Should -Throw 'Missing file at path: *testcmd.env' 507 | } 508 | } 509 | Context 'When file exists' { 510 | BeforeEach { 511 | Set-Content $testPath '' -NoNewline 512 | } 513 | It "Given a command with message '' writes '' to a file" -TestCases @( 514 | @{ Msg = ''; Expected = $null } 515 | @{ Msg = 'a'; Expected = $null } 516 | @{ Msg = "a `r `n b : c % d"; Expected = $null } 517 | @{ Msg = 1; Expected = $null } 518 | @{ Msg = $true; Expected = 'true' } 519 | @{ Msg = [ordered]@{ a = 1; b = $false }; Expected = '{"a":1,"b":false}' } 520 | ) { 521 | Send-ActionFileCommand TESTCMD -Message $Msg 522 | 523 | Get-Content $testPath -Raw | Should -BeExactly (($Expected ?? "$Msg") + [System.Environment]::NewLine) 524 | } 525 | } 526 | } 527 | -------------------------------------------------------------------------------- /lib/GitHubActionsCore/GitHubActionsCore.psm1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | ## Adapted from: 4 | ## https://github.com/ebekker/pwsh-github-action-base/blob/b19583aaecd66696896e9b7dbc9f419e2fca458b/lib/ActionsCore.ps1 5 | ## 6 | ## which in turn was adapted from: 7 | ## https://github.com/actions/toolkit/blob/c65fe87e339d3dd203274c62d0f36f405d78e8a0/packages/core/src/core.ts 8 | 9 | <# 10 | .SYNOPSIS 11 | Sets env variable for this action and future actions in the job. 12 | Equivalent of `core.exportVariable(name, value)`. 13 | .PARAMETER Name 14 | The name of the variable to set. 15 | .PARAMETER Value 16 | The value of the variable. Non-string values will be converted to a string via ConvertTo-Json. 17 | .PARAMETER SkipLocal 18 | Do not set variable in current action's/step's environment. 19 | .LINK 20 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable 21 | .LINK 22 | https://github.com/actions/toolkit/tree/main/packages/core#exporting-variables 23 | #> 24 | function Set-ActionVariable { 25 | [CmdletBinding()] 26 | param( 27 | [Parameter(Position = 0, Mandatory)] 28 | [ValidateNotNullOrEmpty()] 29 | [string]$Name, 30 | 31 | [Parameter(Position = 1, Mandatory)] 32 | [AllowNull()] 33 | [AllowEmptyString()] 34 | [AllowEmptyCollection()] 35 | [object]$Value, 36 | 37 | [switch]$SkipLocal 38 | ) 39 | $convertedValue = ConvertTo-ActionCommandValue $Value 40 | ## To take effect in the current action/step 41 | if (-not $SkipLocal) { 42 | [System.Environment]::SetEnvironmentVariable($Name, $convertedValue) 43 | } 44 | 45 | ## To take effect for all subsequent actions/steps 46 | if ($env:GITHUB_ENV) { 47 | $commandValue = ConvertTo-ActionKeyValueFileCommand $Name $Value 48 | Send-ActionFileCommand -Command ENV -Message $commandValue 49 | } 50 | else { 51 | Send-ActionCommand set-env @{ 52 | name = $Name 53 | } -Message $convertedValue 54 | } 55 | } 56 | 57 | <# 58 | .SYNOPSIS 59 | Registers a secret which will get masked from logs. 60 | Equivalent of `core.setSecret(secret)`. 61 | .PARAMETER Secret 62 | The value of the secret. 63 | .LINK 64 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#masking-a-value-in-log 65 | .LINK 66 | https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret 67 | #> 68 | function Add-ActionSecret { 69 | [CmdletBinding()] 70 | param( 71 | [Parameter(Position = 0, Mandatory)] 72 | [ValidateNotNullOrEmpty()] 73 | [string]$Secret 74 | ) 75 | 76 | Send-ActionCommand add-mask $Secret 77 | } 78 | 79 | <# 80 | .SYNOPSIS 81 | Prepends path to the PATH (for this action and future actions). 82 | Equivalent of `core.addPath(path)`. 83 | .PARAMETER Path 84 | The new path to add. 85 | .PARAMETER SkipLocal 86 | Do not prepend path to current action's/step's environment PATH. 87 | .LINK 88 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#adding-a-system-path 89 | .LINK 90 | https://github.com/actions/toolkit/tree/main/packages/core#path-manipulation 91 | #> 92 | function Add-ActionPath { 93 | [CmdletBinding()] 94 | param( 95 | [Parameter(Position = 0, Mandatory)] 96 | [ValidateNotNullOrEmpty()] 97 | [string]$Path, 98 | 99 | [switch]$SkipLocal 100 | ) 101 | 102 | ## To take effect in the current action/step 103 | if (-not $SkipLocal) { 104 | $oldPath = [System.Environment]::GetEnvironmentVariable('PATH') 105 | $newPath = "$Path$([System.IO.Path]::PathSeparator)$oldPath" 106 | [System.Environment]::SetEnvironmentVariable('PATH', $newPath) 107 | } 108 | 109 | ## To take effect for all subsequent actions/steps 110 | if ($env:GITHUB_PATH) { 111 | Send-ActionFileCommand -Command PATH -Message $Path 112 | } 113 | else { 114 | Send-ActionCommand -Command add-path -Message $Path 115 | } 116 | } 117 | 118 | ## Used to identify inputs from env vars in Action/Workflow context 119 | if (-not (Get-Variable -Scope Script -Name INPUT_PREFIX -ErrorAction SilentlyContinue)) { 120 | Set-Variable -Scope Script -Option Constant -Name INPUT_PREFIX -Value 'INPUT_' 121 | } 122 | 123 | <# 124 | .SYNOPSIS 125 | Gets the value of an input. The value is also trimmed. 126 | Equivalent of `core.getInput(name)`. 127 | .PARAMETER Name 128 | Name of the input to get 129 | .PARAMETER Required 130 | Whether the input is required. If required and not present, will throw. 131 | .LINK 132 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 133 | .LINK 134 | https://github.com/actions/toolkit/tree/main/packages/core#inputsoutputs 135 | #> 136 | function Get-ActionInput { 137 | [CmdletBinding()] 138 | [OutputType([string])] 139 | param( 140 | [Parameter(Position = 0, Mandatory)] 141 | [ValidateNotNullOrEmpty()] 142 | [string]$Name, 143 | 144 | [switch]$Required 145 | ) 146 | 147 | $cleanName = ($Name -replace ' ', '_').ToUpper() 148 | $inputValue = Get-ChildItem "Env:$($INPUT_PREFIX)$($cleanName)" -ErrorAction SilentlyContinue 149 | if ($Required -and (-not $inputValue)) { 150 | throw "Input required and not supplied: $($Name)" 151 | } 152 | 153 | return "$($inputValue.Value)".Trim() 154 | } 155 | 156 | <# 157 | .SYNOPSIS 158 | Sets the value of an output. 159 | Equivalent of `core.setOutput(name, value)`. 160 | .PARAMETER Name 161 | Name of the output to set. 162 | .PARAMETER Value 163 | Value to store. Non-string values will be converted to a string via ConvertTo-Json. 164 | .LINK 165 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-output-parameter 166 | .LINK 167 | https://github.com/actions/toolkit/tree/main/packages/core#inputsoutputs 168 | #> 169 | function Set-ActionOutput { 170 | [CmdletBinding()] 171 | param( 172 | [Parameter(Position = 0, Mandatory)] 173 | [ValidateNotNullOrEmpty()] 174 | [string]$Name, 175 | 176 | [Parameter(Position = 1, Mandatory)] 177 | [AllowNull()] 178 | [AllowEmptyString()] 179 | [AllowEmptyCollection()] 180 | [object]$Value 181 | ) 182 | 183 | if ($env:GITHUB_OUTPUT) { 184 | $commandValue = ConvertTo-ActionKeyValueFileCommand $Name $Value 185 | Send-ActionFileCommand -Command OUTPUT -Message $commandValue 186 | } 187 | else { 188 | Send-ActionCommand set-output @{ 189 | name = $Name 190 | } -Message (ConvertTo-ActionCommandValue $Value) 191 | } 192 | } 193 | 194 | <# 195 | .SYNOPSIS 196 | Enables or disables the echoing of commands into stdout for the rest of the step. 197 | Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set. 198 | Equivalent of `core.setCommandEcho(enabled)`. 199 | .PARAMETER Enabled 200 | $true to enable echoing, $false to disable. 201 | .LINK 202 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#echoing-command-outputs 203 | #># 204 | function Set-ActionCommandEcho { 205 | [CmdletBinding()] 206 | param( 207 | [Parameter(Mandatory, Position = 0)] 208 | [bool]$Enabled 209 | ) 210 | 211 | Send-ActionCommand echo ($Enabled ? 'on' : 'off') 212 | } 213 | 214 | <# 215 | .SYNOPSIS 216 | Sets an action status to failed. 217 | When the action exits it will be with an exit code of 1. 218 | Equivalent of `core.setFailed(message)`. 219 | .PARAMETER Message 220 | Add issue message. 221 | .LINK 222 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 223 | .LINK 224 | https://github.com/actions/toolkit/tree/main/packages/core#exit-codes 225 | #> 226 | function Set-ActionFailed { 227 | [CmdletBinding()] 228 | param( 229 | [Parameter(Position = 0)] 230 | [string]$Message = "" 231 | ) 232 | [System.Environment]::ExitCode = 1 233 | Write-ActionError $Message 234 | } 235 | 236 | <# 237 | .SYNOPSIS 238 | Gets whether Actions Step Debug is on or not. 239 | Equivalent of `core.isDebug()`. 240 | .LINK 241 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 242 | .LINK 243 | https://github.com/actions/toolkit/tree/main/packages/core#logging 244 | #> 245 | function Get-ActionIsDebug { 246 | [CmdletBinding()] 247 | [OutputType([bool])] 248 | param() 249 | return '1' -eq (Get-Item Env:RUNNER_DEBUG -ErrorAction SilentlyContinue).Value 250 | } 251 | 252 | <# 253 | .SYNOPSIS 254 | Writes debug message to user log. 255 | Equivalent of `core.debug(message)`. 256 | .PARAMETER Message 257 | Debug message. 258 | .LINK 259 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-debug-message 260 | .LINK 261 | https://github.com/actions/toolkit/tree/main/packages/core#logging 262 | #> 263 | function Write-ActionDebug { 264 | [CmdletBinding()] 265 | param( 266 | [Parameter(Position = 0)] 267 | [string]$Message = "" 268 | ) 269 | 270 | Send-ActionCommand debug $Message 271 | } 272 | 273 | <# 274 | .SYNOPSIS 275 | Adds an error issue. 276 | Equivalent of `core.error(message)`. 277 | .PARAMETER Message 278 | Error issue message. 279 | .PARAMETER File 280 | Filename where the issue occured. 281 | .PARAMETER Line 282 | Line number of the File where the issue occured. 283 | .PARAMETER Column 284 | Column number in Line in File where the issue occured. 285 | .NOTES 286 | File, Line and Column parameters are supported by the actual workflow command, 287 | but not available in `@actions/core` package. 288 | .LINK 289 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message 290 | .LINK 291 | https://github.com/actions/toolkit/tree/main/packages/core#logging 292 | #> 293 | function Write-ActionError { 294 | [CmdletBinding()] 295 | param( 296 | [Parameter(Position = 0, ParameterSetName = 'MsgOnly')] 297 | [Parameter(Position = 0, ParameterSetName = 'File')] 298 | [Parameter(Position = 0, ParameterSetName = 'Line')] 299 | [Parameter(Position = 0, ParameterSetName = 'Column')] 300 | [string]$Message = "", 301 | 302 | [Parameter(Position = 1, ParameterSetName = 'File', Mandatory)] 303 | [Parameter(Position = 1, ParameterSetName = 'Line', Mandatory)] 304 | [Parameter(Position = 1, ParameterSetName = 'Column', Mandatory)] 305 | [string]$File, 306 | 307 | [Parameter(Position = 2, ParameterSetName = 'Line', Mandatory)] 308 | [Parameter(Position = 2, ParameterSetName = 'Column', Mandatory)] 309 | [int]$Line, 310 | 311 | [Parameter(Position = 3, ParameterSetName = 'Column', Mandatory)] 312 | [int]$Column 313 | ) 314 | $params = [ordered]@{ } 315 | if ($File) { 316 | $params['file'] = $File 317 | } 318 | if ($PSCmdlet.ParameterSetName -in 'Column', 'Line') { 319 | $params['line'] = $Line 320 | } 321 | if ($PSCmdlet.ParameterSetName -eq 'Column') { 322 | $params['col'] = $Column 323 | } 324 | Send-ActionCommand error $params -Message $Message 325 | } 326 | 327 | <# 328 | .SYNOPSIS 329 | Adds a warning issue. 330 | Equivalent of `core.warning(message)`. 331 | .PARAMETER Message 332 | Warning issue message. 333 | .PARAMETER File 334 | Filename where the issue occured. 335 | .PARAMETER Line 336 | Line number of the File where the issue occured. 337 | .PARAMETER Column 338 | Column number in Line in File where the issue occured. 339 | .NOTES 340 | File, Line and Column parameters are supported by the actual workflow command, 341 | but not available in `@actions/core` package. 342 | .LINK 343 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message 344 | .LINK 345 | https://github.com/actions/toolkit/tree/main/packages/core#logging 346 | #> 347 | function Write-ActionWarning { 348 | [CmdletBinding()] 349 | param( 350 | [Parameter(Position = 0, ParameterSetName = 'MsgOnly')] 351 | [Parameter(Position = 0, ParameterSetName = 'File')] 352 | [Parameter(Position = 0, ParameterSetName = 'Line')] 353 | [Parameter(Position = 0, ParameterSetName = 'Column')] 354 | [string]$Message = "", 355 | 356 | [Parameter(Position = 1, ParameterSetName = 'File', Mandatory)] 357 | [Parameter(Position = 1, ParameterSetName = 'Line', Mandatory)] 358 | [Parameter(Position = 1, ParameterSetName = 'Column', Mandatory)] 359 | [string]$File, 360 | 361 | [Parameter(Position = 2, ParameterSetName = 'Line', Mandatory)] 362 | [Parameter(Position = 2, ParameterSetName = 'Column', Mandatory)] 363 | [int]$Line, 364 | 365 | [Parameter(Position = 3, ParameterSetName = 'Column', Mandatory)] 366 | [int]$Column 367 | ) 368 | $params = [ordered]@{ } 369 | if ($File) { 370 | $params['file'] = $File 371 | } 372 | if ($PSCmdlet.ParameterSetName -in 'Column', 'Line') { 373 | $params['line'] = $Line 374 | } 375 | if ($PSCmdlet.ParameterSetName -eq 'Column') { 376 | $params['col'] = $Column 377 | } 378 | Send-ActionCommand warning $params -Message $Message 379 | } 380 | 381 | <# 382 | .SYNOPSIS 383 | Writes info to log with console.log. 384 | Equivalent of `core.info(message)`. 385 | Forwards to Write-Host. 386 | .PARAMETER Message 387 | Info message. 388 | .LINK 389 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions 390 | .LINK 391 | https://github.com/actions/toolkit/tree/main/packages/core#logging 392 | #> 393 | function Write-ActionInfo { 394 | [CmdletBinding()] 395 | param( 396 | [Parameter(Position = 0)] 397 | [string]$Message = "" 398 | ) 399 | 400 | Write-Host "$($Message)" 401 | } 402 | 403 | <# 404 | .SYNOPSIS 405 | Begin an output group. 406 | Output until the next `groupEnd` will be foldable in this group. 407 | Equivalent of `core.startGroup(name)`. 408 | .DESCRIPTION 409 | Output until the next `groupEnd` will be foldable in this group. 410 | .PARAMETER Name 411 | The name of the output group. 412 | .LINK 413 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines 414 | .LINK 415 | https://github.com/actions/toolkit/tree/main/packages/core#logging 416 | #> 417 | function Enter-ActionOutputGroup { 418 | [CmdletBinding()] 419 | param( 420 | [Parameter(Position = 0, Mandatory)] 421 | [ValidateNotNullOrEmpty()] 422 | [string]$Name 423 | ) 424 | 425 | Send-ActionCommand group $Name 426 | } 427 | 428 | <# 429 | .SYNOPSIS 430 | End an output group. 431 | Equivalent of `core.endGroup()`. 432 | .LINK 433 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines 434 | .LINK 435 | https://github.com/actions/toolkit/tree/main/packages/core#logging 436 | #> 437 | function Exit-ActionOutputGroup { 438 | [CmdletBinding()] 439 | param() 440 | Send-ActionCommand endgroup 441 | } 442 | 443 | <# 444 | .SYNOPSIS 445 | Executes the argument script block within an output group. 446 | Equivalent of `core.group(name, func)`. 447 | .PARAMETER Name 448 | Name of the output group. 449 | .PARAMETER ScriptBlock 450 | Script block to execute in between opening and closing output group. 451 | .LINK 452 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#grouping-log-lines 453 | .LINK 454 | https://github.com/actions/toolkit/tree/main/packages/core#logging 455 | #> 456 | function Invoke-ActionGroup { 457 | [CmdletBinding()] 458 | param( 459 | [Parameter(Position = 0, Mandatory)] 460 | [ValidateNotNullOrEmpty()] 461 | [string]$Name, 462 | 463 | [Parameter(Position = 1, Mandatory)] 464 | [scriptblock]$ScriptBlock 465 | ) 466 | 467 | Enter-ActionOutputGroup -Name $Name 468 | try { 469 | return $ScriptBlock.Invoke() 470 | } 471 | finally { 472 | Exit-ActionOutputGroup 473 | } 474 | } 475 | <# 476 | .SYNOPSIS 477 | Invokes a scriptblock that won't result in any output interpreted as a workflow command. 478 | Useful for printing arbitrary text that may contain command-like text. 479 | No quivalent in `@actions/core` package. 480 | .PARAMETER EndToken 481 | String token to stop workflow commands, used after scriptblock to start workflow commands back. 482 | .PARAMETER ScriptBlock 483 | Script block to invoke within a no-commands context. 484 | .PARAMETER GenerateToken 485 | Use this to automatically generate a GUID and use it as the EndToken. 486 | .LINK 487 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#stopping-and-starting-workflow-commands 488 | #> 489 | function Invoke-ActionNoCommandsBlock { 490 | [CmdletBinding()] 491 | param( 492 | [Parameter(Position = 0, ParameterSetName = 'SetToken', Mandatory)] 493 | [ValidateNotNullOrEmpty()] 494 | [string]$EndToken, 495 | 496 | [Parameter(Position = 1, ParameterSetName = 'SetToken', Mandatory)] 497 | [Parameter(Position = 0, ParameterSetName = 'GenToken', Mandatory)] 498 | [scriptblock]$ScriptBlock, 499 | 500 | [Parameter(ParameterSetName = 'GenToken', Mandatory)] 501 | [switch]$GenerateToken 502 | ) 503 | $tokenValue = $GenerateToken ? [System.Guid]::NewGuid().ToString() : $EndToken 504 | Send-ActionCommand stop-commands $tokenValue 505 | try { 506 | return $ScriptBlock.Invoke() 507 | } 508 | finally { 509 | Send-ActionCommand $tokenValue 510 | } 511 | } 512 | 513 | ## Used to signal output that is a command to Action/Workflow context 514 | if (-not (Get-Variable -Scope Script -Name CMD_STRING -ErrorAction SilentlyContinue)) { 515 | Set-Variable -Scope Script -Option Constant -Name CMD_STRING -Value '::' 516 | } 517 | 518 | <# 519 | .SYNOPSIS 520 | Sends a command to the hosting Workflow/Action context. 521 | Equivalent to `core.issue(cmd, msg)`/`core.issueCommand(cmd, props, msg)`. 522 | .DESCRIPTION 523 | Command Format: 524 | ::workflow-command parameter1={data},parameter2={data}::{command value} 525 | .PARAMETER Command 526 | The workflow command name. 527 | .PARAMETER Properties 528 | Properties to add to the command. 529 | .PARAMETER Message 530 | Message to add to the command. 531 | .EXAMPLE 532 | PS> Send-ActionCommand warning 'This is the user warning message' 533 | ::warning::This is the user warning message 534 | .EXAMPLE 535 | PS> Send-ActionCommand set-secret @{name='mypassword'} 'definitelyNotAPassword!' 536 | ::set-secret name=mypassword::definitelyNotAPassword! 537 | .LINK 538 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#about-workflow-commands 539 | #> 540 | function Send-ActionCommand { 541 | [CmdletBinding()] 542 | param( 543 | [Parameter(Position = 0, Mandatory)] 544 | [ValidateNotNullOrEmpty()] 545 | [string]$Command, 546 | 547 | [Parameter(ParameterSetName = "WithProps", Position = 1, Mandatory)] 548 | [System.Collections.IDictionary]$Properties, 549 | 550 | [Parameter(ParameterSetName = "WithProps", Position = 2)] 551 | [Parameter(ParameterSetName = "SkipProps", Position = 1)] 552 | [string]$Message = '' 553 | ) 554 | 555 | $cmdStr = ConvertTo-ActionCommandString $Command $Properties $Message 556 | Write-Host $cmdStr 557 | } 558 | 559 | <# 560 | .SYNOPSIS 561 | Sends a command to an Action Environment File. 562 | Equivalent to `core.issueFileCommand(cmd, msg)`. 563 | .DESCRIPTION 564 | Appends given message to an Action Environment File. 565 | .PARAMETER Command 566 | Command (environment file variable suffix) to send message for. 567 | .PARAMETER Message 568 | Message to append. 569 | .EXAMPLE 570 | PS> Send-ActionFileCommand ENV 'myvar=value' 571 | .EXAMPLE 572 | PS> 'myvar=value', 'myvar2=novalue' | Send-ActionFileCommand ENV 573 | .LINK 574 | https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files 575 | #> 576 | function Send-ActionFileCommand { 577 | [CmdletBinding()] 578 | param ( 579 | [Parameter(Position = 0, Mandatory)] 580 | [ValidateNotNullOrEmpty()] 581 | [string]$Command, 582 | 583 | [Parameter(Position = 1, Mandatory, ValueFromPipeline)] 584 | [psobject]$Message 585 | ) 586 | begin { 587 | $filePath = [System.Environment]::GetEnvironmentVariable("GITHUB_$Command") 588 | if (-not $filePath) { 589 | throw "Unable to find environment variable for file command $Command" 590 | } 591 | if (-not (Test-Path $filePath -PathType Leaf)) { 592 | throw "Missing file at path: $filePath" 593 | } 594 | } 595 | process { 596 | ConvertTo-ActionCommandValue $Message | Out-File -FilePath $filePath -Append 597 | } 598 | } 599 | 600 | ########################################################################### 601 | ## Internal Implementation 602 | ########################################################################### 603 | 604 | <# 605 | .SYNOPSIS 606 | Convert command, properties and message into a single-line workflow command. 607 | .PARAMETER Command 608 | The workflow command name. 609 | .PARAMETER Properties 610 | Properties to add to the command. 611 | .PARAMETER Message 612 | Message to add to the command. 613 | #> 614 | function ConvertTo-ActionCommandString { 615 | [CmdletBinding()] 616 | [OutputType([string])] 617 | param( 618 | [Parameter(Position = 0, Mandatory)] 619 | [string]$Command, 620 | 621 | [Parameter(Position = 1)] 622 | [System.Collections.IDictionary]$Properties, 623 | 624 | [Parameter(Position = 2)] 625 | [AllowNull()] 626 | [AllowEmptyString()] 627 | [AllowEmptyCollection()] 628 | [object]$Message 629 | ) 630 | 631 | if (-not $Command) { 632 | $Command = 'missing.command' 633 | } 634 | 635 | $cmdStr = "$($CMD_STRING)$($Command)" 636 | if ($Properties.Count -gt 0) { 637 | $first = $true 638 | foreach ($key in $Properties.Keys) { 639 | $val = ConvertTo-ActionEscapedProperty $Properties[$key] 640 | if ($val) { 641 | if ($first) { 642 | $first = $false 643 | $cmdStr += ' ' 644 | } 645 | else { 646 | $cmdStr += ',' 647 | } 648 | $cmdStr += "$($key)=$($val)" 649 | } 650 | } 651 | } 652 | $cmdStr += $CMD_STRING 653 | $cmdStr += ConvertTo-ActionEscapedData $Message 654 | 655 | return $cmdStr 656 | } 657 | 658 | <# 659 | .SYNOPSIS 660 | Formats a key-value pair into a string so it can be saved into an environment file. 661 | .DESCRIPTION 662 | Formats a key-value pair. If the command-converted value contains newlines, the format used 663 | is {name}<<{delimiter}EOL{converted-value}EOL{delimiter}. Otherwise, {name}={value} is used. 664 | .LINK 665 | https://github.com/actions/toolkit/blob/ffb7e3e14ed5e28ae00e9c49ba02b2764d57a6b7/packages/core/src/file-command.ts#L27-L47 666 | #> 667 | function ConvertTo-ActionKeyValueFileCommand { 668 | [CmdletBinding()] 669 | [OutputType([string])] 670 | param( 671 | [Parameter(Mandatory, Position = 0)] 672 | [string]$Name, 673 | 674 | [Parameter(Mandatory, Position = 1)] 675 | [AllowNull()] 676 | [AllowEmptyString()] 677 | [AllowEmptyCollection()] 678 | [object]$Value 679 | ) 680 | $convertedValue = ConvertTo-ActionCommandValue $Value 681 | if ($convertedValue -notmatch '\n') { 682 | return "$Name=$convertedValue" 683 | } 684 | $delimiter = "ghadelimiter_$(New-Guid)" 685 | if ($Name -contains $delimiter) { 686 | throw "Unexpected input: name should not contain the delimiter `"$delimiter`"" 687 | } 688 | if ($convertedValue -contains $delimiter) { 689 | throw "Unexpected input: value should not contain the delimiter `"$delimiter`"" 690 | } 691 | $eol = [System.Environment]::NewLine 692 | return "$Name<<$delimiter$eol$convertedValue$eol$delimiter" 693 | } 694 | 695 | <# 696 | .SYNOPSIS 697 | Sanitizes an input into a string so it can be passed into issueCommand safely. 698 | Equivalent of `core.toCommandValue(input)`. 699 | .PARAMETER Value 700 | Input to sanitize into a string. 701 | #> 702 | function ConvertTo-ActionCommandValue { 703 | [CmdletBinding()] 704 | [OutputType([string])] 705 | param( 706 | [Parameter(Mandatory, Position = 0)] 707 | [AllowNull()] 708 | [AllowEmptyString()] 709 | [AllowEmptyCollection()] 710 | [object]$Value 711 | ) 712 | if ($null -eq $Value) { 713 | return '' 714 | } 715 | if ($Value -is [string]) { 716 | return $Value 717 | } 718 | return ConvertTo-Json $Value -Depth 100 -Compress -EscapeHandling EscapeNonAscii 719 | } 720 | 721 | ## Escaping based on https://github.com/actions/toolkit/blob/3e40dd39cc56303a2451f5b175068dbefdc11c18/packages/core/src/command.ts#L92-L105 722 | function ConvertTo-ActionEscapedData { 723 | [CmdletBinding()] 724 | [OutputType([string])] 725 | param( 726 | [Parameter(Mandatory, Position = 0)] 727 | [AllowNull()] 728 | [AllowEmptyString()] 729 | [AllowEmptyCollection()] 730 | [object]$Value 731 | ) 732 | return (ConvertTo-ActionCommandValue $Value). 733 | Replace("%", '%25'). 734 | Replace("`r", '%0D'). 735 | Replace("`n", '%0A') 736 | } 737 | 738 | function ConvertTo-ActionEscapedProperty { 739 | [CmdletBinding()] 740 | [OutputType([string])] 741 | param( 742 | [Parameter(Mandatory, Position = 0)] 743 | [AllowNull()] 744 | [AllowEmptyString()] 745 | [AllowEmptyCollection()] 746 | [object]$Value 747 | ) 748 | return (ConvertTo-ActionCommandValue $Value). 749 | Replace("%", '%25'). 750 | Replace("`r", '%0D'). 751 | Replace("`n", '%0A'). 752 | Replace(':', '%3A'). 753 | Replace(',', '%2C') 754 | } 755 | 756 | Export-ModuleMember ` 757 | Add-ActionPath, 758 | Add-ActionSecret, 759 | Enter-ActionOutputGroup, 760 | Exit-ActionOutputGroup, 761 | Get-ActionInput, 762 | Get-ActionInputs, 763 | Get-ActionIsDebug, 764 | Invoke-ActionGroup, 765 | Invoke-ActionNoCommandsBlock, 766 | Send-ActionCommand, 767 | Send-ActionFileCommand, 768 | Set-ActionCommandEcho, 769 | Set-ActionFailed, 770 | Set-ActionOutput, 771 | Set-ActionVariable, 772 | Write-ActionDebug, 773 | Write-ActionError, 774 | Write-ActionInfo, 775 | Write-ActionWarning 776 | -------------------------------------------------------------------------------- /test.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [Parameter()] 4 | [switch] 5 | $CI = ($env:CI -eq 'true') 6 | ) 7 | 8 | if (Get-Module Pester | ? Version -LT '5.1') { 9 | Install-Module -Name Pester -Force -SkipPublisherCheck -MinimumVersion '5.1' -PassThru 10 | | Import-Module Pester -MinimumVersion '5.1' 11 | } 12 | Invoke-Pester -CI:$CI --------------------------------------------------------------------------------