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 [email protected] .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