1
+ <#
2
+ . Synopsis
3
+ GitHub Action for WebSocket
4
+ . Description
5
+ GitHub Action for WebSocket. This will:
6
+
7
+ * Import WebSocket
8
+ * If `-Run` is provided, run that script
9
+ * Otherwise, unless `-SkipScriptFile` is passed, run all *.WebSocket.ps1 files beneath the workflow directory
10
+ * If any `-ActionScript` was provided, run scripts from the action path that match a wildcard pattern.
11
+
12
+ If you will be making changes using the GitHubAPI, you should provide a -GitHubToken
13
+ If none is provided, and ENV:GITHUB_TOKEN is set, this will be used instead.
14
+ Any files changed can be outputted by the script, and those changes can be checked back into the repo.
15
+ Make sure to use the "persistCredentials" option with checkout.
16
+ #>
17
+
18
+ param (
19
+ # A PowerShell Script that uses WebSocket.
20
+ # Any files outputted from the script will be added to the repository.
21
+ # If those files have a .Message attached to them, they will be committed with that message.
22
+ [string ]
23
+ $Run ,
24
+
25
+ # If set, will not process any files named *.WebSocket.ps1
26
+ [switch ]
27
+ $SkipScriptFile ,
28
+
29
+ # A list of modules to be installed from the PowerShell gallery before scripts run.
30
+ [string []]
31
+ $InstallModule ,
32
+
33
+ # If provided, will commit any remaining changes made to the workspace with this commit message.
34
+ [string ]
35
+ $CommitMessage ,
36
+
37
+ # If provided, will checkout a new branch before making the changes.
38
+ # If not provided, will use the current branch.
39
+ [string ]
40
+ $TargetBranch ,
41
+
42
+ # The name of one or more scripts to run, from this action's path.
43
+ [string []]
44
+ $ActionScript ,
45
+
46
+ # The github token to use for requests.
47
+ [string ]
48
+ $GitHubToken = ' {{ secrets.GITHUB_TOKEN }}' ,
49
+
50
+ # The user email associated with a git commit. If this is not provided, it will be set to the username@noreply.github.com.
51
+ [string ]
52
+ $UserEmail ,
53
+
54
+ # The user name associated with a git commit.
55
+ [string ]
56
+ $UserName ,
57
+
58
+ # If set, will not push any changes made to the repository.
59
+ # (they will still be committed unless `-NoCommit` is passed)
60
+ [switch ]
61
+ $NoPush ,
62
+
63
+ # If set, will not commit any changes made to the repository.
64
+ # (this also implies `-NoPush`)
65
+ [switch ]
66
+ $NoCommit
67
+ )
68
+
69
+ $ErrorActionPreference = ' continue'
70
+ " ::group::Parameters" | Out-Host
71
+ [PSCustomObject ]$PSBoundParameters | Format-List | Out-Host
72
+ " ::endgroup::" | Out-Host
73
+
74
+ $gitHubEventJson = [IO.File ]::ReadAllText($env: GITHUB_EVENT_PATH )
75
+ $gitHubEvent =
76
+ if ($env: GITHUB_EVENT_PATH ) {
77
+ $gitHubEventJson | ConvertFrom-Json
78
+ } else { $null }
79
+ " ::group::Parameters" | Out-Host
80
+ $gitHubEvent | Format-List | Out-Host
81
+ " ::endgroup::" | Out-Host
82
+
83
+
84
+ $anyFilesChanged = $false
85
+ $ActionModuleName = ' PSJekyll'
86
+ $actorInfo = $null
87
+
88
+
89
+ $checkDetached = git symbolic- ref - q HEAD
90
+ if ($LASTEXITCODE ) {
91
+ " ::warning::On detached head, skipping action" | Out-Host
92
+ exit 0
93
+ }
94
+
95
+ function InstallActionModule {
96
+ param ([string ]$ModuleToInstall )
97
+ $moduleInWorkspace = Get-ChildItem - Path $env: GITHUB_WORKSPACE - Recurse - File |
98
+ Where-Object Name -eq " $ ( $moduleToInstall ) .psd1" |
99
+ Where-Object {
100
+ $ (Get-Content $_.FullName - Raw) -match ' ModuleVersion'
101
+ }
102
+ if (-not $moduleInWorkspace ) {
103
+ $availableModules = Get-Module - ListAvailable
104
+ if ($availableModules.Name -notcontains $moduleToInstall ) {
105
+ Install-Module $moduleToInstall - Scope CurrentUser - Force - AcceptLicense - AllowClobber
106
+ }
107
+ Import-Module $moduleToInstall - Force - PassThru | Out-Host
108
+ } else {
109
+ Import-Module $moduleInWorkspace.FullName - Force - PassThru | Out-Host
110
+ }
111
+ }
112
+ function ImportActionModule {
113
+ # region -InstallModule
114
+ if ($InstallModule ) {
115
+ " ::group::Installing Modules" | Out-Host
116
+ foreach ($moduleToInstall in $InstallModule ) {
117
+ InstallActionModule - ModuleToInstall $moduleToInstall
118
+ }
119
+ " ::endgroup::" | Out-Host
120
+ }
121
+ # endregion -InstallModule
122
+
123
+ if ($env: GITHUB_ACTION_PATH ) {
124
+ $LocalModulePath = Join-Path $env: GITHUB_ACTION_PATH " $ActionModuleName .psd1"
125
+ if (Test-path $LocalModulePath ) {
126
+ Import-Module $LocalModulePath - Force - PassThru | Out-String
127
+ } else {
128
+ throw " Module '$ActionModuleName ' not found"
129
+ }
130
+ } elseif (-not (Get-Module $ActionModuleName )) {
131
+ throw " Module '$ActionModuleName ' not found"
132
+ }
133
+
134
+ " ::notice title=ModuleLoaded::$ActionModuleName Loaded from Path - $ ( $LocalModulePath ) " | Out-Host
135
+ if ($env: GITHUB_STEP_SUMMARY ) {
136
+ " # $ ( $ActionModuleName ) " |
137
+ Out-File - Append - FilePath $env: GITHUB_STEP_SUMMARY
138
+ }
139
+ }
140
+ function InitializeAction {
141
+ # region Custom
142
+ # endregion Custom
143
+
144
+ # Configure git based on the $env:GITHUB_ACTOR
145
+ if (-not $UserName ) { $UserName = $env: GITHUB_ACTOR }
146
+ if (-not $actorID ) { $actorID = $env: GITHUB_ACTOR_ID }
147
+ $actorInfo =
148
+ if ($GitHubToken -notmatch ' ^\{{2}' -and $GitHubToken -notmatch ' \}{2}$' ) {
149
+ Invoke-RestMethod - Uri " https://api.github.com/user/$actorID " - Headers @ { Authorization = " token $GitHubToken " }
150
+ } else {
151
+ Invoke-RestMethod - Uri " https://api.github.com/user/$actorID "
152
+ }
153
+
154
+ if (-not $UserEmail ) { $UserEmail = " $UserName @noreply.github.com" }
155
+ git config -- global user.email $UserEmail
156
+ git config -- global user.name $actorInfo.name
157
+
158
+ # Pull down any changes
159
+ git pull | Out-Host
160
+
161
+ if ($TargetBranch ) {
162
+ " ::notice title=Expanding target branch string $targetBranch " | Out-Host
163
+ $TargetBranch = $ExecutionContext.SessionState.InvokeCommand.ExpandString ($TargetBranch )
164
+ " ::notice title=Checking out target branch::$targetBranch " | Out-Host
165
+ git checkout - b $TargetBranch | Out-Host
166
+ git pull | Out-Host
167
+ }
168
+ }
169
+
170
+ function InvokeActionModule {
171
+ $myScriptStart = [DateTime ]::Now
172
+ $myScript = $ExecutionContext.SessionState.PSVariable.Get (" Run" ).Value
173
+ if ($myScript ) {
174
+ Invoke-Expression - Command $myScript |
175
+ . ProcessOutput |
176
+ Out-Host
177
+ return
178
+ }
179
+ $myScriptTook = [Datetime ]::Now - $myScriptStart
180
+ $MyScriptFilesStart = [DateTime ]::Now
181
+
182
+ $myScriptList = @ ()
183
+ $shouldSkip = $ExecutionContext.SessionState.PSVariable.Get (" SkipScriptFile" ).Value
184
+ if ($shouldSkip ) {
185
+ return
186
+ }
187
+ $scriptFiles = @ (
188
+ Get-ChildItem - Recurse - Path $env: GITHUB_WORKSPACE |
189
+ Where-Object Name -Match " \.$ ( $ActionModuleName ) \.ps1$"
190
+ if ($ActionScript ) {
191
+ if ($ActionScript -match ' ^\s{0,}/' -and $ActionScript -match ' /\s{0,}$' ) {
192
+ $ActionScriptPattern = $ActionScript.Trim (' /' ).Trim() -as [regex ]
193
+ if ($ActionScriptPattern ) {
194
+ $ActionScriptPattern = [regex ]::new($ActionScript.Trim (' /' ).Trim(), ' IgnoreCase,IgnorePatternWhitespace' , [timespan ]::FromSeconds(0.5 ))
195
+ Get-ChildItem - Recurse - Path $env: GITHUB_ACTION_PATH |
196
+ Where-Object { $_.Name -Match " \.$ ( $ActionModuleName ) \.ps1$" -and $_.FullName -match $ActionScriptPattern }
197
+ }
198
+ } else {
199
+ Get-ChildItem - Recurse - Path $env: GITHUB_ACTION_PATH |
200
+ Where-Object Name -Match " \.$ ( $ActionModuleName ) \.ps1$" |
201
+ Where-Object FullName -Like $ActionScript
202
+ }
203
+ }
204
+ ) | Select-Object - Unique
205
+ $scriptFiles |
206
+ ForEach-Object - Begin {
207
+ if ($env: GITHUB_STEP_SUMMARY ) {
208
+ " ## $ActionModuleName Scripts" |
209
+ Out-File - Append - FilePath $env: GITHUB_STEP_SUMMARY
210
+ }
211
+ } - Process {
212
+ $myScriptList += $_.FullName.Replace ($env: GITHUB_WORKSPACE , ' ' ).TrimStart(' /' )
213
+ $myScriptCount ++
214
+ $scriptFile = $_
215
+ if ($env: GITHUB_STEP_SUMMARY ) {
216
+ " ### $ ( $scriptFile.Fullname -replace [Regex ]::Escape($env: GITHUB_WORKSPACE )) " |
217
+ Out-File - Append - FilePath $env: GITHUB_STEP_SUMMARY
218
+ }
219
+ $scriptCmd = $ExecutionContext.SessionState.InvokeCommand.GetCommand ($scriptFile.FullName , ' ExternalScript' )
220
+ foreach ($requiredModule in $CommandInfo.ScriptBlock.Ast.ScriptRequirements.RequiredModules ) {
221
+ if ($requiredModule.Name -and
222
+ (-not $requiredModule.MaximumVersion ) -and
223
+ (-not $requiredModule.RequiredVersion )
224
+ ) {
225
+ InstallActionModule $requiredModule.Name
226
+ }
227
+ }
228
+ $scriptFileOutputs = . $scriptCmd
229
+ $scriptFileOutputs |
230
+ . ProcessOutput |
231
+ Out-Host
232
+ }
233
+
234
+ $MyScriptFilesTook = [Datetime ]::Now - $MyScriptFilesStart
235
+ $SummaryOfMyScripts = " $myScriptCount $ActionModuleName scripts took $ ( $MyScriptFilesTook.TotalSeconds ) seconds"
236
+ $SummaryOfMyScripts |
237
+ Out-Host
238
+ if ($env: GITHUB_STEP_SUMMARY ) {
239
+ $SummaryOfMyScripts |
240
+ Out-File - Append - FilePath $env: GITHUB_STEP_SUMMARY
241
+ }
242
+ # region Custom
243
+ # endregion Custom
244
+ }
245
+
246
+ function OutError {
247
+ $anyRuntimeExceptions = $false
248
+ foreach ($err in $error ) {
249
+ $errParts = @ (
250
+ " ::error "
251
+ @ (
252
+ if ($err.InvocationInfo.ScriptName ) {
253
+ " file=$ ( $err.InvocationInfo.ScriptName ) "
254
+ }
255
+ if ($err.InvocationInfo.ScriptLineNumber -ge 1 ) {
256
+ " line=$ ( $err.InvocationInfo.ScriptLineNumber ) "
257
+ if ($err.InvocationInfo.OffsetInLine -ge 1 ) {
258
+ " col=$ ( $err.InvocationInfo.OffsetInLine ) "
259
+ }
260
+ }
261
+ if ($err.CategoryInfo.Activity ) {
262
+ " title=$ ( $err.CategoryInfo.Activity ) "
263
+ }
264
+ ) -join ' ,'
265
+ " ::"
266
+ $err.Exception.Message
267
+ if ($err.CategoryInfo.Category -eq ' OperationStopped' -and
268
+ $err.CategoryInfo.Reason -eq ' RuntimeException' ) {
269
+ $anyRuntimeExceptions = $true
270
+ }
271
+ ) -join ' '
272
+ $errParts | Out-Host
273
+ if ($anyRuntimeExceptions ) {
274
+ exit 1
275
+ }
276
+ }
277
+ }
278
+
279
+ function PushActionOutput {
280
+ if ($anyFilesChanged ) {
281
+ " ::notice::$ ( $anyFilesChanged ) Files Changed" | Out-Host
282
+ }
283
+ if ($CommitMessage -or $anyFilesChanged ) {
284
+ if ($CommitMessage ) {
285
+ Get-ChildItem $env: GITHUB_WORKSPACE - Recurse |
286
+ ForEach-Object {
287
+ $gitStatusOutput = git status $_.Fullname - s
288
+ if ($gitStatusOutput ) {
289
+ git add $_.Fullname
290
+ }
291
+ }
292
+
293
+ git commit - m $ExecutionContext.SessionState.InvokeCommand.ExpandString ($CommitMessage )
294
+ }
295
+
296
+ $checkDetached = git symbolic- ref - q HEAD
297
+ if (-not $LASTEXITCODE -and -not $NoPush -and -not $noCommit ) {
298
+ if ($TargetBranch -and $anyFilesChanged ) {
299
+ " ::notice::Pushing Changes to $targetBranch " | Out-Host
300
+ git push -- set-upstream origin $TargetBranch
301
+ } elseif ($anyFilesChanged ) {
302
+ " ::notice::Pushing Changes" | Out-Host
303
+ git push
304
+ }
305
+ " Git Push Output: $ ( $gitPushed | Out-String ) "
306
+ } else {
307
+ " ::notice::Not pushing changes (on detached head)" | Out-Host
308
+ $LASTEXITCODE = 0
309
+ exit 0
310
+ }
311
+ }
312
+ }
313
+
314
+ filter ProcessOutput {
315
+ $out = $_
316
+ $outItem = Get-Item - Path $out - ErrorAction Ignore
317
+ if (-not $outItem -and $out -is [string ]) {
318
+ $out | Out-Host
319
+ if ($env: GITHUB_STEP_SUMMARY ) {
320
+ " > $out " | Out-File - Append - FilePath $env: GITHUB_STEP_SUMMARY
321
+ }
322
+ return
323
+ }
324
+ $fullName , $shouldCommit =
325
+ if ($out -is [IO.FileInfo ]) {
326
+ $out.FullName , (git status $out.Fullname - s)
327
+ } elseif ($outItem ) {
328
+ $outItem.FullName , (git status $outItem.Fullname - s)
329
+ }
330
+ if ($shouldCommit -and -not $NoCommit ) {
331
+ " $fullName has changed, and should be committed" | Out-Host
332
+ git add $fullName
333
+ if ($out.Message ) {
334
+ git commit - m " $ ( $out.Message ) " | Out-Host
335
+ } elseif ($out.CommitMessage ) {
336
+ git commit - m " $ ( $out.CommitMessage ) " | Out-Host
337
+ } elseif ($gitHubEvent.head_commit.message ) {
338
+ git commit - m " $ ( $gitHubEvent.head_commit.message ) " | Out-Host
339
+ }
340
+ $anyFilesChanged = $true
341
+ }
342
+ $out
343
+ }
344
+
345
+ . ImportActionModule
346
+ . InitializeAction
347
+ . InvokeActionModule
348
+ . PushActionOutput
349
+ . OutError
0 commit comments