-
Notifications
You must be signed in to change notification settings - Fork 14
self-hosted runner: always use latest Git for Windows and GitHub Actions version (plus some PowerShell cleanups) #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4bad4d3
12fbd61
e6066e9
7eebe1e
8ec8c50
d9791f4
9b5edf6
85191a9
862ea54
906ef3b
c14b886
b860d44
bed9b75
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,24 @@ | ||
param ( | ||
# 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. | ||
# https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners | ||
[Parameter(Mandatory=$true)] | ||
[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.")] | ||
[string]$GitHubActionsRunnerToken, | ||
|
||
# GitHub Actions Runner repository. E.g. "https://github.com/MY_ORG" (org-level) or "https://github.com/MY_ORG/MY_REPO" (repo-level) | ||
# https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners | ||
[Parameter(Mandatory=$true)] | ||
[Parameter(Mandatory = $true)] | ||
[ValidateScript({ $_ -like "https://*" })] | ||
[string]$GithubActionsRunnerRegistrationUrl, | ||
|
||
# Actions Runner name. Needs to be unique in the org/repo | ||
[Parameter(Mandatory=$true)] | ||
[Parameter(Mandatory = $true, HelpMessage = "Name of the runner. Needs to be unique in the org/repo")] | ||
[ValidateNotNullOrEmpty()] | ||
[string]$GithubActionsRunnerName, | ||
|
||
# Stop Service immediately (useful for spinning up runners preemptively) | ||
[Parameter(Mandatory=$false)] | ||
[Parameter(Mandatory = $false, HelpMessage = "Stop Service immediately (useful for spinning up runners preemptively)")] | ||
[ValidateSet('true', 'false')] | ||
[string]$StopService = 'true', | ||
|
||
# Path to the Actions Runner. Keep this path short to prevent Long Path issues, e.g. D:\a | ||
[Parameter(Mandatory=$true)] | ||
[Parameter(Mandatory = $true, HelpMessage = "Path to the Actions Runner. Keep this path short to prevent Long Path issues, e.g. D:\a")] | ||
[ValidateNotNullOrEmpty()] | ||
[string]$GitHubActionsRunnerPath | ||
) | ||
|
||
|
@@ -28,15 +27,89 @@ Write-Output "Starting post-deployment script." | |
# ================================= | ||
# TOOL VERSIONS AND OTHER VARIABLES | ||
# ================================= | ||
# | ||
# This header is used for both Git for Windows and GitHub Actions Runner | ||
[hashtable]$GithubHeaders = @{ | ||
"Accept" = "application/vnd.github.v3+json" | ||
"X-GitHub-Api-Version" = "2022-11-28" | ||
} | ||
|
||
$GitForWindowsVersion = "2.39.0" | ||
$GitForWindowsTag = "2.39.0.windows.1" | ||
$GitForWindowsHash = "2eaba567e17784654be77ba997329742d87845c6f15e33c9620f9a331c69a976" | ||
# ================================= | ||
# Get download and hash information for the latest release of Git for Windows | ||
# ================================= | ||
# | ||
# This will return the latest release of Git for Windows download link, hash and the name of the outfile | ||
# Everything will be saved in the object $GitHubGit | ||
# | ||
# url for Github API to get the latest release | ||
[string]$GitHubUrl = "https://api.github.com/repos/git-for-windows/git/releases/latest" | ||
# | ||
# Name of the exe file that should be verified and downloaded | ||
[string]$GithubExeName = "Git-.*-64-bit.exe" | ||
|
||
try { | ||
[System.Object]$GithubRestData = Invoke-RestMethod -Uri $GitHubUrl -Method Get -Headers $GithubHeaders -TimeoutSec 10 | Select-Object -Property assets, body | ||
[System.Object]$GitHubAsset = $GithubRestData.assets | Where-Object { $_.name -match $GithubExeName } | ||
if ($GithubRestData.body -match "\b${[Regex]::Escape($GitHubAsset.name)}.*?\|.*?([a-zA-Z0-9]{64})" -eq $True) { | ||
[System.Object]$GitHubGit = [PSCustomObject]@{ | ||
DownloadUrl = [string]$GitHubAsset.browser_download_url | ||
Hash = [string]$Matches[1].ToUpper() | ||
OutFile = "./git-for-windows-installer.exe" | ||
} | ||
} | ||
else { | ||
Write-Error "Could not find hash for $GithubExeName" | ||
exit 1 | ||
} | ||
} | ||
catch { | ||
Write-Error @" | ||
"Message: "$($_.Exception.Message)`n | ||
"Error Line: "$($_.InvocationInfo.Line)`n | ||
"Line Number: "$($_.InvocationInfo.ScriptLineNumber)`n | ||
"@ | ||
exit 1 | ||
} | ||
|
||
# ================================= | ||
# Obtain the latest GitHub Actions Runner and other GitHub Actions information | ||
# ================================= | ||
# | ||
# Note that the GitHub Actions Runner auto-updates itself by default, but do try to reference a relatively new version here. | ||
$GitHubActionsRunnerVersion = "2.300.2" | ||
$GithubActionsRunnerArch = "arm64" | ||
$GithubActionsRunnerHash = "9409e50d9ad33d8031355ed079b8f56cf3699f35cf5d0ca51e54deed432758ef" | ||
$GithubActionsRunnerLabels = "self-hosted,Windows,ARM64" | ||
# | ||
# This will return the latest release of GitHub Actions Runner download link, hash, Tag, RunnerArch, RunnerLabels and the name of the outfile. | ||
# Everything will be saved in the object $GitHubAction | ||
# | ||
# url for Github API to get the latest release of actions runner | ||
[string]$GitHubActionUrl = "https://api.github.com/repos/actions/runner/releases/latest" | ||
|
||
try { | ||
[System.Object]$GithubActionRestData = Invoke-RestMethod -Uri $GitHubActionUrl -Method Get -Headers $GithubHeaders -TimeoutSec 10 | Select-Object -Property assets, body, tag_name | ||
if ($GithubActionRestData.body -match "<!-- BEGIN SHA win-arm64 -->(.*)<!-- END SHA win-arm64 -->" -eq $True) { | ||
[string]$ActionZipName = "actions-runner-win-arm64-" + [string]$($GithubActionRestData.tag_name.Substring(1)) + ".zip" | ||
|
||
[System.Object]$GitHubAction = [PSCustomObject]@{ | ||
Tag = $GithubActionRestData.tag_name.Substring(1) | ||
Hash = $Matches[1].ToUpper() | ||
RunnerArch = "arm64" | ||
RunnerLabels = "self-hosted,Windows,ARM64" | ||
DownloadUrl = $GithubActionRestData.assets | where-object { $_.name -match $ActionZipName } | Select-Object -ExpandProperty browser_download_url | ||
OutFile = "$($GitHubActionsRunnerPath)\$($ActionZipName)" | ||
} | ||
} | ||
else { | ||
Write-Error "Error: Could not find hash for Github Actions Runner" | ||
exit 1 | ||
} | ||
} | ||
catch { | ||
Write-Error @" | ||
"Message: "$($_.Exception.Message)`n | ||
"Error Line: "$($_.InvocationInfo.Line)`n | ||
"Line Number: "$($_.InvocationInfo.ScriptLineNumber)`n | ||
"@ | ||
exit 1 | ||
} | ||
|
||
# ====================== | ||
# WINDOWS DEVELOPER MODE | ||
|
@@ -60,12 +133,14 @@ Write-Output "Finished adding Microsoft Defender Exclusions." | |
# ====================== | ||
|
||
Write-Output "Downloading Git for Windows..." | ||
$GitForWindowsOutputFile = "./git-for-windows-installer.exe" | ||
$ProgressPreference = 'SilentlyContinue' | ||
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/git-for-windows/git/releases/download/v${GitForWindowsTag}/Git-${GitForWindowsVersion}-64-bit.exe" -OutFile $GitForWindowsOutputFile | ||
Invoke-WebRequest -UseBasicParsing -Uri $GitHubGit.DownloadUrl -OutFile $GitHubGit.OutFile | ||
$ProgressPreference = 'Continue' | ||
|
||
if((Get-FileHash -Path $GitForWindowsOutputFile -Algorithm SHA256).Hash.ToUpper() -ne $GitForWindowsHash.ToUpper()){ throw 'Computed checksum did not match' } | ||
if ((Get-FileHash -Path $GitHubGit.OutFile -Algorithm SHA256).Hash.ToUpper() -ne $GitHubGit.Hash) { | ||
Write-Error "Computed checksum for $($GitHubGit.OutFile) did not match $($GitHubGit.Hash)" | ||
exit 1 | ||
} | ||
|
||
Write-Output "Installing Git for Windows..." | ||
@" | ||
|
@@ -94,7 +169,7 @@ EnablePseudoConsoleSupport=Disabled | |
EnableFSMonitor=Disabled | ||
"@ | Out-File -FilePath "./git-installer-config.inf" | ||
|
||
Start-Process -Wait $GitForWindowsOutputFile '/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF="./git-installer-config.inf"' | ||
Start-Process -Wait $GitHubGit.OutFile '/VERYSILENT /NORESTART /NOCANCEL /SP- /CLOSEAPPLICATIONS /RESTARTAPPLICATIONS /LOADINF="./git-installer-config.inf"' | ||
|
||
Write-Output "Finished installing Git for Windows." | ||
|
||
|
@@ -106,31 +181,73 @@ Write-Output "Downloading GitHub Actions runner..." | |
|
||
mkdir $GitHubActionsRunnerPath | Out-Null | ||
$ProgressPreference = 'SilentlyContinue' | ||
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 | ||
Invoke-WebRequest -UseBasicParsing -Uri $GitHubAction.DownloadUrl -OutFile $GitHubAction.OutFile | ||
$ProgressPreference = 'Continue' | ||
if((Get-FileHash -Path ${GitHubActionsRunnerPath}\actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip -Algorithm SHA256).Hash.ToUpper() -ne $GithubActionsRunnerHash.ToUpper()){ throw 'Computed checksum did not match' } | ||
|
||
Write-Output "Installing GitHub Actions runner ${GitHubActionsRunnerVersion} as a Windows service with labels ${GithubActionsRunnerLabels}..." | ||
if ((Get-FileHash -Path $GitHubAction.OutFile -Algorithm SHA256).Hash.ToUpper() -ne $GitHubAction.hash) { | ||
Write-Error "Computed checksum for $($GitHubAction.OutFile) did not match $($GitHubAction.hash)" | ||
exit 1 | ||
} | ||
|
||
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory("${GitHubActionsRunnerPath}\actions-runner-win-${GithubActionsRunnerArch}-${GitHubActionsRunnerVersion}.zip", $GitHubActionsRunnerPath) | ||
Write-Output "Installing GitHub Actions runner $($GitHubAction.Tag) as a Windows service with labels $($GitHubAction.RunnerLabels)..." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is really interesting information. Since the post-deployment script is run on Azure, and the GitHub workflow that kicks off that deployment has no connection to the actual deployment, I wonder whether there is any way we could manually mirror it into the GitHub workflow run's logs... @dennisameling any ideas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oooh, ooh, I think I found something: https://learn.microsoft.com/en-us/powershell/module/az.resources/get-azdeploymentscriptlog?view=azps-9.3.0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what you mean? Do you want to log information from the script? If so, that's possible. I can even make somethign that can send you a email if you want. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Nice try, but Deployment Scripts are something else than the Custom Script Extension 😉 Let's follow up in this PR for getting the post-deployment script output 👍🏼 |
||
|
||
Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory($GitHubAction.OutFile, $GitHubActionsRunnerPath) | ||
|
||
Write-Output "Configuring the runner to shut down automatically after running" | ||
Set-Content -Path "${GitHubActionsRunnerPath}\shut-down.ps1" -Value "shutdown -s -t 60 -d p:4:0 -c `"workflow job is done`"" | ||
[System.Environment]::SetEnvironmentVariable("ACTIONS_RUNNER_HOOK_JOB_COMPLETED", "${GitHubActionsRunnerPath}\shut-down.ps1", [System.EnvironmentVariableTarget]::Machine) | ||
|
||
Write-Output "Configuring the runner" | ||
cmd.exe /c "${GitHubActionsRunnerPath}\config.cmd" --unattended --ephemeral --name ${GithubActionsRunnerName} --runasservice --labels ${GithubActionsRunnerLabels} --url ${GithubActionsRunnerRegistrationUrl} --token ${GitHubActionsRunnerToken} | ||
cmd.exe /c "${GitHubActionsRunnerPath}\config.cmd" --unattended --ephemeral --name ${GithubActionsRunnerName} --runasservice --labels $($GitHubAction.RunnerLabels) --url ${GithubActionsRunnerRegistrationUrl} --token ${GitHubActionsRunnerToken} | ||
|
||
# Ensure that the service was created. If not, exit with error code. | ||
$MatchedServices = Get-Service -Name "actions.runner.*" | ||
if ($MatchedServices.count -eq 0) { | ||
Write-Error "GitHub Actions service not found (should start with actions.runner). Check the logs in ${GitHubActionsRunnerPath}\_diag for more details." | ||
exit 1 | ||
if ($null -eq (Get-Service -Name "actions.runner.*")) { | ||
Write-Output "Could not find service actions.runner.*, making three more attempts with a 3 second delay in between each attempt..." | ||
|
||
[int]$RetryCountService = 0 | ||
do { | ||
Write-Output "Attempt $($RetryCountService) of 3: Looking for service actions.runner.*..." | ||
$RetryCountService++ | ||
Start-Sleep -Seconds 3 | ||
} | ||
while ($null -eq (Get-Service -Name "actions.runner.*") -or $RetryCountService -gt 3) | ||
|
||
if ($RetryCountService -gt 3) { | ||
Write-Error "GitHub Actions service not found (should start with actions.runner). Check the logs in ${GitHubActionsRunnerPath}\_diag for more details." | ||
exit 1 | ||
} | ||
else { | ||
Write-Output "Found service actions.runner.*" | ||
} | ||
} | ||
|
||
# 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. | ||
if (${StopService} -eq 'true') { | ||
Stop-Service -Name "actions.runner.*" -Verbose | ||
if ($StopService -eq 'true') { | ||
#Collects all running services named actions.runner.* | ||
$GetActionRunnerServices = Get-Service -Name "actions.runner.*" | Where-Object { $_.Status -eq 'Running' } | Select-Object -ExpandProperty Name | ||
|
||
# Loops trough all services and stopping them one by one | ||
foreach ($Service in $GetActionRunnerServices) { | ||
Write-Output "Stopping service $Service" | ||
Stop-Service -Name $Service | ||
|
||
# Making sure that all of the services has been stopped before moving forward | ||
[int]$RetryCount = 0 | ||
do { | ||
Write-Output "Attempt: $($RetryCount) of 5: Waiting for service $Service to stop..." | ||
$RetryCount++ | ||
Start-Sleep -Seconds 5 | ||
} | ||
while ((Get-Service -Name $Service).Status -eq 'running' -or $RetryCount -gt 5) | ||
|
||
if ($RetryCount -gt 5) { | ||
Write-Error "Service $Service failed to stop" | ||
exit 1 | ||
} | ||
else { | ||
Write-Output "Service $Service has been stopped" | ||
} | ||
} | ||
} | ||
|
||
Write-Output "Finished installing GitHub Actions runner." |
Uh oh!
There was an error while loading. Please reload this page.