Skip to content

Commit e9b20e2

Browse files
authored
Merge pull request #19 from rstolpe/main
self-hosted runner: always use latest Git for Windows and GitHub Actions version (plus some PowerShell cleanups)
2 parents 9c4b31a + bed9b75 commit e9b20e2

File tree

1 file changed

+148
-31
lines changed

1 file changed

+148
-31
lines changed

azure-self-hosted-runners/post-deployment-script.ps1

Lines changed: 148 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
param (
2-
# GitHub Actions Runner registration token. Note that these tokens are only valid for one hour after creation, so we always expect the user to provide one.
32
# https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners
4-
[Parameter(Mandatory=$true)]
3+
[Parameter(Mandatory = $true, HelpMessage = "GitHub Actions Runner registration token. Note that these tokens are only valid for one hour after creation, so we always expect the user to provide one.")]
54
[string]$GitHubActionsRunnerToken,
65

76
# GitHub Actions Runner repository. E.g. "https://github.com/MY_ORG" (org-level) or "https://github.com/MY_ORG/MY_REPO" (repo-level)
87
# https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners
9-
[Parameter(Mandatory=$true)]
8+
[Parameter(Mandatory = $true)]
9+
[ValidateScript({ $_ -like "https://*" })]
1010
[string]$GithubActionsRunnerRegistrationUrl,
1111

12-
# Actions Runner name. Needs to be unique in the org/repo
13-
[Parameter(Mandatory=$true)]
12+
[Parameter(Mandatory = $true, HelpMessage = "Name of the runner. Needs to be unique in the org/repo")]
13+
[ValidateNotNullOrEmpty()]
1414
[string]$GithubActionsRunnerName,
1515

16-
# Stop Service immediately (useful for spinning up runners preemptively)
17-
[Parameter(Mandatory=$false)]
16+
[Parameter(Mandatory = $false, HelpMessage = "Stop Service immediately (useful for spinning up runners preemptively)")]
1817
[ValidateSet('true', 'false')]
1918
[string]$StopService = 'true',
2019

21-
# Path to the Actions Runner. Keep this path short to prevent Long Path issues, e.g. D:\a
22-
[Parameter(Mandatory=$true)]
20+
[Parameter(Mandatory = $true, HelpMessage = "Path to the Actions Runner. Keep this path short to prevent Long Path issues, e.g. D:\a")]
21+
[ValidateNotNullOrEmpty()]
2322
[string]$GitHubActionsRunnerPath
2423
)
2524

@@ -28,15 +27,89 @@ Write-Output "Starting post-deployment script."
2827
# =================================
2928
# TOOL VERSIONS AND OTHER VARIABLES
3029
# =================================
30+
#
31+
# This header is used for both Git for Windows and GitHub Actions Runner
32+
[hashtable]$GithubHeaders = @{
33+
"Accept" = "application/vnd.github.v3+json"
34+
"X-GitHub-Api-Version" = "2022-11-28"
35+
}
3136

32-
$GitForWindowsVersion = "2.39.0"
33-
$GitForWindowsTag = "2.39.0.windows.1"
34-
$GitForWindowsHash = "2eaba567e17784654be77ba997329742d87845c6f15e33c9620f9a331c69a976"
37+
# =================================
38+
# Get download and hash information for the latest release of Git for Windows
39+
# =================================
40+
#
41+
# This will return the latest release of Git for Windows download link, hash and the name of the outfile
42+
# Everything will be saved in the object $GitHubGit
43+
#
44+
# url for Github API to get the latest release
45+
[string]$GitHubUrl = "https://api.github.com/repos/git-for-windows/git/releases/latest"
46+
#
47+
# Name of the exe file that should be verified and downloaded
48+
[string]$GithubExeName = "Git-.*-64-bit.exe"
49+
50+
try {
51+
[System.Object]$GithubRestData = Invoke-RestMethod -Uri $GitHubUrl -Method Get -Headers $GithubHeaders -TimeoutSec 10 | Select-Object -Property assets, body
52+
[System.Object]$GitHubAsset = $GithubRestData.assets | Where-Object { $_.name -match $GithubExeName }
53+
if ($GithubRestData.body -match "\b${[Regex]::Escape($GitHubAsset.name)}.*?\|.*?([a-zA-Z0-9]{64})" -eq $True) {
54+
[System.Object]$GitHubGit = [PSCustomObject]@{
55+
DownloadUrl = [string]$GitHubAsset.browser_download_url
56+
Hash = [string]$Matches[1].ToUpper()
57+
OutFile = "./git-for-windows-installer.exe"
58+
}
59+
}
60+
else {
61+
Write-Error "Could not find hash for $GithubExeName"
62+
exit 1
63+
}
64+
}
65+
catch {
66+
Write-Error @"
67+
"Message: "$($_.Exception.Message)`n
68+
"Error Line: "$($_.InvocationInfo.Line)`n
69+
"Line Number: "$($_.InvocationInfo.ScriptLineNumber)`n
70+
"@
71+
exit 1
72+
}
73+
74+
# =================================
75+
# Obtain the latest GitHub Actions Runner and other GitHub Actions information
76+
# =================================
77+
#
3578
# Note that the GitHub Actions Runner auto-updates itself by default, but do try to reference a relatively new version here.
36-
$GitHubActionsRunnerVersion = "2.300.2"
37-
$GithubActionsRunnerArch = "arm64"
38-
$GithubActionsRunnerHash = "9409e50d9ad33d8031355ed079b8f56cf3699f35cf5d0ca51e54deed432758ef"
39-
$GithubActionsRunnerLabels = "self-hosted,Windows,ARM64"
79+
#
80+
# This will return the latest release of GitHub Actions Runner download link, hash, Tag, RunnerArch, RunnerLabels and the name of the outfile.
81+
# Everything will be saved in the object $GitHubAction
82+
#
83+
# url for Github API to get the latest release of actions runner
84+
[string]$GitHubActionUrl = "https://api.github.com/repos/actions/runner/releases/latest"
85+
86+
try {
87+
[System.Object]$GithubActionRestData = Invoke-RestMethod -Uri $GitHubActionUrl -Method Get -Headers $GithubHeaders -TimeoutSec 10 | Select-Object -Property assets, body, tag_name
88+
if ($GithubActionRestData.body -match "<!-- BEGIN SHA win-arm64 -->(.*)<!-- END SHA win-arm64 -->" -eq $True) {
89+
[string]$ActionZipName = "actions-runner-win-arm64-" + [string]$($GithubActionRestData.tag_name.Substring(1)) + ".zip"
90+
91+
[System.Object]$GitHubAction = [PSCustomObject]@{
92+
Tag = $GithubActionRestData.tag_name.Substring(1)
93+
Hash = $Matches[1].ToUpper()
94+
RunnerArch = "arm64"
95+
RunnerLabels = "self-hosted,Windows,ARM64"
96+
DownloadUrl = $GithubActionRestData.assets | where-object { $_.name -match $ActionZipName } | Select-Object -ExpandProperty browser_download_url
97+
OutFile = "$($GitHubActionsRunnerPath)\$($ActionZipName)"
98+
}
99+
}
100+
else {
101+
Write-Error "Error: Could not find hash for Github Actions Runner"
102+
exit 1
103+
}
104+
}
105+
catch {
106+
Write-Error @"
107+
"Message: "$($_.Exception.Message)`n
108+
"Error Line: "$($_.InvocationInfo.Line)`n
109+
"Line Number: "$($_.InvocationInfo.ScriptLineNumber)`n
110+
"@
111+
exit 1
112+
}
40113

41114
# ======================
42115
# WINDOWS DEVELOPER MODE
@@ -60,12 +133,14 @@ Write-Output "Finished adding Microsoft Defender Exclusions."
60133
# ======================
61134

62135
Write-Output "Downloading Git for Windows..."
63-
$GitForWindowsOutputFile = "./git-for-windows-installer.exe"
64136
$ProgressPreference = 'SilentlyContinue'
65-
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/git-for-windows/git/releases/download/v${GitForWindowsTag}/Git-${GitForWindowsVersion}-64-bit.exe" -OutFile $GitForWindowsOutputFile
137+
Invoke-WebRequest -UseBasicParsing -Uri $GitHubGit.DownloadUrl -OutFile $GitHubGit.OutFile
66138
$ProgressPreference = 'Continue'
67139

68-
if((Get-FileHash -Path $GitForWindowsOutputFile -Algorithm SHA256).Hash.ToUpper() -ne $GitForWindowsHash.ToUpper()){ throw 'Computed checksum did not match' }
140+
if ((Get-FileHash -Path $GitHubGit.OutFile -Algorithm SHA256).Hash.ToUpper() -ne $GitHubGit.Hash) {
141+
Write-Error "Computed checksum for $($GitHubGit.OutFile) did not match $($GitHubGit.Hash)"
142+
exit 1
143+
}
69144

70145
Write-Output "Installing Git for Windows..."
71146
@"
@@ -94,7 +169,7 @@ EnablePseudoConsoleSupport=Disabled
94169
EnableFSMonitor=Disabled
95170
"@ | Out-File -FilePath "./git-installer-config.inf"
96171

97-
Start-Process -Wait $GitForWindowsOutputFile '/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF="./git-installer-config.inf"'
172+
Start-Process -Wait $GitHubGit.OutFile '/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF="./git-installer-config.inf"'
98173

99174
Write-Output "Finished installing Git for Windows."
100175

@@ -106,31 +181,73 @@ Write-Output "Downloading GitHub Actions runner..."
106181

107182
mkdir $GitHubActionsRunnerPath | Out-Null
108183
$ProgressPreference = 'SilentlyContinue'
109-
Invoke-WebRequest -UseBasicParsing -Uri https://github.com/actions/runner/releases/download/v${GitHubActionsRunnerVersion}/actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip -OutFile ${GitHubActionsRunnerPath}\actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip
184+
Invoke-WebRequest -UseBasicParsing -Uri $GitHubAction.DownloadUrl -OutFile $GitHubAction.OutFile
110185
$ProgressPreference = 'Continue'
111-
if((Get-FileHash -Path ${GitHubActionsRunnerPath}\actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip -Algorithm SHA256).Hash.ToUpper() -ne $GithubActionsRunnerHash.ToUpper()){ throw 'Computed checksum did not match' }
112186

113-
Write-Output "Installing GitHub Actions runner ${GitHubActionsRunnerVersion} as a Windows service with labels ${GithubActionsRunnerLabels}..."
187+
if ((Get-FileHash -Path $GitHubAction.OutFile -Algorithm SHA256).Hash.ToUpper() -ne $GitHubAction.hash) {
188+
Write-Error "Computed checksum for $($GitHubAction.OutFile) did not match $($GitHubAction.hash)"
189+
exit 1
190+
}
114191

115-
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("${GitHubActionsRunnerPath}\actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip", $GitHubActionsRunnerPath)
192+
Write-Output "Installing GitHub Actions runner $($GitHubAction.Tag) as a Windows service with labels $($GitHubAction.RunnerLabels)..."
193+
194+
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory($GitHubAction.OutFile, $GitHubActionsRunnerPath)
116195

117196
Write-Output "Configuring the runner to shut down automatically after running"
118197
Set-Content -Path "${GitHubActionsRunnerPath}\shut-down.ps1" -Value "shutdown -s -t 60 -d p:4:0 -c `"workflow job is done`""
119198
[System.Environment]::SetEnvironmentVariable("ACTIONS_RUNNER_HOOK_JOB_COMPLETED", "${GitHubActionsRunnerPath}\shut-down.ps1", [System.EnvironmentVariableTarget]::Machine)
120199

121200
Write-Output "Configuring the runner"
122-
cmd.exe /c "${GitHubActionsRunnerPath}\config.cmd" --unattended --ephemeral --name ${GithubActionsRunnerName} --runasservice --labels ${GithubActionsRunnerLabels} --url ${GithubActionsRunnerRegistrationUrl} --token ${GitHubActionsRunnerToken}
201+
cmd.exe /c "${GitHubActionsRunnerPath}\config.cmd" --unattended --ephemeral --name ${GithubActionsRunnerName} --runasservice --labels $($GitHubAction.RunnerLabels) --url ${GithubActionsRunnerRegistrationUrl} --token ${GitHubActionsRunnerToken}
123202

124203
# Ensure that the service was created. If not, exit with error code.
125-
$MatchedServices = Get-Service -Name "actions.runner.*"
126-
if ($MatchedServices.count -eq 0) {
127-
Write-Error "GitHub Actions service not found (should start with actions.runner). Check the logs in ${GitHubActionsRunnerPath}\_diag for more details."
128-
exit 1
204+
if ($null -eq (Get-Service -Name "actions.runner.*")) {
205+
Write-Output "Could not find service actions.runner.*, making three more attempts with a 3 second delay in between each attempt..."
206+
207+
[int]$RetryCountService = 0
208+
do {
209+
Write-Output "Attempt $($RetryCountService) of 3: Looking for service actions.runner.*..."
210+
$RetryCountService++
211+
Start-Sleep -Seconds 3
212+
}
213+
while ($null -eq (Get-Service -Name "actions.runner.*") -or $RetryCountService -gt 3)
214+
215+
if ($RetryCountService -gt 3) {
216+
Write-Error "GitHub Actions service not found (should start with actions.runner). Check the logs in ${GitHubActionsRunnerPath}\_diag for more details."
217+
exit 1
218+
}
219+
else {
220+
Write-Output "Found service actions.runner.*"
221+
}
129222
}
130223

131224
# Immediately stop the service as we want to leave the VM in a deallocated state for later use. The service will automatically be started when Windows starts.
132-
if (${StopService} -eq 'true') {
133-
Stop-Service -Name "actions.runner.*" -Verbose
225+
if ($StopService -eq 'true') {
226+
#Collects all running services named actions.runner.*
227+
$GetActionRunnerServices = Get-Service -Name "actions.runner.*" | Where-Object { $_.Status -eq 'Running' } | Select-Object -ExpandProperty Name
228+
229+
# Loops trough all services and stopping them one by one
230+
foreach ($Service in $GetActionRunnerServices) {
231+
Write-Output "Stopping service $Service"
232+
Stop-Service -Name $Service
233+
234+
# Making sure that all of the services has been stopped before moving forward
235+
[int]$RetryCount = 0
236+
do {
237+
Write-Output "Attempt: $($RetryCount) of 5: Waiting for service $Service to stop..."
238+
$RetryCount++
239+
Start-Sleep -Seconds 5
240+
}
241+
while ((Get-Service -Name $Service).Status -eq 'running' -or $RetryCount -gt 5)
242+
243+
if ($RetryCount -gt 5) {
244+
Write-Error "Service $Service failed to stop"
245+
exit 1
246+
}
247+
else {
248+
Write-Output "Service $Service has been stopped"
249+
}
250+
}
134251
}
135252

136253
Write-Output "Finished installing GitHub Actions runner."

0 commit comments

Comments
 (0)