Skip to content

Commit c5ad019

Browse files
Merge pull request #32 from PowerShellWeb/WebSocket-Action
WebSocket 0.1.1
2 parents a3fca83 + 0a303b7 commit c5ad019

16 files changed

+1494
-45
lines changed

.github/FUNDING.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [StartAutomating]
+349
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
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
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#requires -Module PSDevOps
2+
Import-BuildStep -SourcePath (
3+
Join-Path $PSScriptRoot 'GitHub'
4+
) -BuildSystem GitHubAction
5+
6+
$PSScriptRoot | Split-Path | Push-Location
7+
8+
New-GitHubAction -Name "UseWebSocket" -Description 'Work with WebSockets in PowerShell' -Action WebSocketAction -Icon chevron-right -OutputPath .\action.yml
9+
10+
Pop-Location

CHANGELOG.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
1-
## WebSocket 0.1
2-
31
> Like It? [Star It](https://github.com/PowerShellWeb/WebSocket)
42
> Love It? [Support It](https://github.com/sponsors/StartAutomating)
53
4+
## WebSocket 0.1.1
5+
6+
* WebSocket GitHub Action
7+
* Run any `*.WebSocket.ps1` files in a repository (#24)
8+
* WebSocket container updates
9+
* Container now runs mounted `*.WebSocket.ps1` files (#26)
10+
* Get-WebSocket improvements:
11+
* New Parameters:
12+
* -Maximum (#22)
13+
* -TimeOut (#23)
14+
* -WatchFor (#29)
15+
* -RawText (#30)
16+
* -Binary (#31)
17+
* WebSocket Testing (#25)
18+
* Adding FUNDING.yml (#14)
19+
20+
---
21+
22+
## WebSocket 0.1
23+
624
* Initial Release of WebSocket module
725
* Get-WebSocket gets content from a WebSocket
826
* Docker container for WebSocket

0 commit comments

Comments
 (0)