Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
30cb3dd
Add tests for install Windows 10 SDK command
mokagio Feb 19, 2025
30de013
Add logic to handle new lines and non integers to Win 10 SDK
mokagio Feb 19, 2025
f4f8a64
Add test for Win 10 SDK with string
mokagio Feb 19, 2025
1c308cb
Add dry run flag to install Win 10 SDK script
mokagio Feb 19, 2025
4521151
Update win 10 sdk tests to capture and inspect output
mokagio Feb 19, 2025
8771501
DRY win 10 SDK test logic in test script
mokagio Feb 19, 2025
eb9c63d
Refined test for Windows 10 SDK
mokagio Feb 19, 2025
7e305bf
Restore tests creating .windows-10-sdk where needed
mokagio Feb 19, 2025
16af116
Fix emoji rendering
mokagio Feb 19, 2025
bc562b6
Test fix attempt
mokagio Feb 19, 2025
135509a
Use `| Out-File` over `echo >` to maintain new lines
mokagio Feb 19, 2025
c2892e8
Use `Write-Output` over `Write-Host` to allow for capturing
mokagio Feb 19, 2025
73de2d3
Update tests because the script handles new lines -.-'
mokagio Feb 19, 2025
ef282e0
Remove statement to prevent script error from failing test early
mokagio Feb 19, 2025
54e9aef
Use a text check that is okay with new lines
mokagio Feb 19, 2025
b04ea32
Remove note about `param` required position in PS1 script
mokagio Feb 20, 2025
7764a28
Simplify version file parsing logic in Win 10 SDK install
mokagio Feb 20, 2025
44ed08c
Add test for Win 10 version with trailing whitespaces
mokagio Feb 20, 2025
1748736
Add test for Win 10 SDK with leading whitespaces
mokagio Feb 20, 2025
b34cac1
Remove unnecessary line length check
mokagio Feb 19, 2025
34ae304
Add header doc for `install_windows_10_sdk.ps1`
mokagio Feb 20, 2025
320d84c
Add allow list for Windows versions
mokagio Feb 21, 2025
12e82ba
Add parameter to bypass Windows 10 SDK installation in host setup script
mokagio Feb 21, 2025
8216d5e
Replace all `Write-Host` with `Write-Output`
mokagio Feb 21, 2025
31db443
Add test for skip windows 10 installation behavior
mokagio Feb 21, 2025
de4505e
Add valid .windows-10-sdk-version example in doc
mokagio Feb 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,98 @@ steps:
notify:
- github_commit_status:
context: "pr_changed_files Tests: Edge Cases"

- group: ":windows: install_windows_10_sdk Tests"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about making use of our new pr_changed_files to run this group conditionally?

The nice thing is that this a8c-ci-toolkit repo is the only one for now where it'd actually be easy to use that helper in shared-pipeline-vars to set up an env var you could then use as an if: build.env('HAS_INSTALL_WINDOWS_10_SDK_CHANGES') == 1.

This is because unlike all other repos for which the a8c-ci-toolkit is not loaded on the uploader agent when the main step that does pipeline upload is run on it, our default steps don't include it as a plugin… in this specific repo we don't even need to load it as a plugin because it's already a binary in the working copy of the repo it's trying to run CI on 😛

Which means you should be able to use bin/pr_change_files in this repo directly (instead of having the plugin loaded and having its bin/ folder added to the $PATH) to export HAS_INSTALL_WINDOWS_10_SDK_CHANGES=$(bin/pr_changed_files --stdout --any-match './bin/install_windows_10_sdk.ps1' './tests/test-install-windows-sdk.ps1') 😉

Same for the other one btw.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be neat and great dogfooding.

steps:
- label: ":windows: install_windows_10_sdk Tests - Version file with valid format and version"
command: |
"20348" | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 -ExpectedExitCode 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized the inconsistency we have here between snake_case used for bin/* scripts and kebab-case used for tests/* 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that too, but didn't take the time to write it down or address it. Sounds like an easy follow up PR for me to tackle.

agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with valid format and version"

- label: ":windows: install_windows_10_sdk Tests - Version file with one new line"
command: |
"20348`n" | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 -ExpectedExitCode 0
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with one new line"

- label: ":windows: install_windows_10_sdk Tests - Version file with more than one new line"
command: |
"20348`n`n" | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 -ExpectedExitCode 0
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with more than one new line"

- label: ":windows: install_windows_10_sdk Tests - Version file with leading whitespaces"
command: |
" 19041" | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 -ExpectedExitCode 0
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with leading whitespaces"

- label: ":windows: install_windows_10_sdk Tests - Version file with trailing whitespaces"
command: |
"18362 " | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 -ExpectedExitCode 0
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with trailing whitespaces"

- label: ":windows: install_windows_10_sdk Tests - Version file with a word"
command: |
"not an integer" | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 `
-ExpectedExitCode 1 `
-ExpectedErrorKeyphrase "Expected an integer"
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with a word"

- label: ":windows: install_windows_10_sdk Tests - Missing version file"
command: |
.\tests\test-install-windows-10-sdk.ps1 `
-ExpectedExitCode 1 `
-ExpectedErrorKeyphrase "No Windows 10 SDK version file found at .windows-10-sdk-version"
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with a word"

- label: ":windows: install_windows_10_sdk Tests - Version file with version number that is not in the allowed list"
command: |
"12345" | Out-File .windows-10-sdk-version
.\tests\test-install-windows-10-sdk.ps1 `
-ExpectedExitCode 1 `
-ExpectedErrorKeyphrase "Invalid Windows 10 SDK version: 12345"
agents:
queue: windows
notify:
- github_commit_status:
context: "install_windows_10_sdk Tests - Version file with version number that is not in the allowed list"

- label: ":windows: prepare_windows_host_for_app_distribution Tests - Skip Windows 10 SDK Installation"
command: .\tests\test-prepare-windows-host-for-app-distribution.ps1
agents:
queue: windows
notify:
- github_commit_status:
context: "prepare_windows_host_for_app_distribution Tests - Skip Windows 10 SDK Installation"
55 changes: 51 additions & 4 deletions bin/install_windows_10_sdk.ps1
Original file line number Diff line number Diff line change
@@ -1,17 +1,64 @@
# Install the Windows 10 SDK and Visual Studio Build Tools using the value in .windows-10-sdk-version.
#
# The expected .windows-10-sdk-version format is a integer representing a valid SDK component id.
# The list of valid component ids can be found at
# https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022
#
# Example:
#
# 20348

Comment on lines +3 to +10
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #144 (comment) by @iangmaia

I added the documentation here rather than in the prepare script as per @iangmaia 's comment because it seemed like a better place where to explain the expectation.

Also, I am aware we have two PRs that add docs here, but it felt best to add a manual version in this context to get it over the line while waiting for the LLM-generated doc approach to be discussed, see #159 #160

param (
[switch]$DryRun = $false
)

# Stop script execution when a non-terminating error occurs
$ErrorActionPreference = "Stop"

Write-Host "--- :windows: Installing Windows 10 SDK and Visual Studio Build Tools"
Write-Output "--- :windows: Installing Windows 10 SDK and Visual Studio Build Tools"

# See list at https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022
$allowedVersions = @(
"20348",
"19041",
"18362",
"17763",
"17134",
"16299",
"15063",
"14393"
)

$windowsSDKVersionFile = ".windows-10-sdk-version"
if (-not (Test-Path $windowsSDKVersionFile)) {
Write-Output "[!] No Windows 10 SDK version file found at $windowsSDKVersionFile."
exit 1
}

$windows10SDKVersion = Get-Content $windowsSDKVersionFile
$windows10SDKVersion = (Get-Content -TotalCount 1 $windowsSDKVersionFile).Trim()

if ($windows10SDKVersion -notmatch '^\d+$') {
Write-Output "[!] Invalid version file format."
Write-Output "Expected an integer, got: '$windows10SDKVersion'"
exit 1
}

if ($allowedVersions -notcontains $windows10SDKVersion) {
Write-Output "[!] Invalid Windows 10 SDK version: $windows10SDKVersion"
Write-Output "Allowed versions are:"
foreach ($version in $allowedVersions) {
Write-Output "- $version"
}
Write-Output "More info at https://learn.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-build-tools?view=vs-2022"
exit 1
}

Write-Output "Will attempt to set up Windows 10 ($windows10SDKVersion) SDK and Visual Studio Build Tools..."

Write-Host "Will attempt to set up Windows 10 ($windows10SDKVersion) SDK and Visual Studio Build Tools..."
if ($DryRun) {
Write-Output "Running in dry run mode, finishing here."
exit 0
}

# Download the Visual Studio Build Tools Bootstrapper
Write-Output "~~~ Downloading Visual Studio Build Tools..."
Expand All @@ -26,7 +73,7 @@ If (-not (Test-Path $buildToolsPath)) {
Write-Output "[!] Failed to download Visual Studio Build Tools"
Exit 1
} else {
Write-Output "Successfully downloaded Visual Studio Build Toosl at $buildToolsPath."
Write-Output "Successfully downloaded Visual Studio Build Tools at $buildToolsPath."
}

# Install the Windows SDK and other required components
Expand Down
6 changes: 3 additions & 3 deletions bin/path_aware_refreshenv.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
# Stop script execution when a non-terminating error occurs
$ErrorActionPreference = "Stop"

Write-Host "PATH before refreshenv is $env:PATH"
Write-Output "PATH before refreshenv is $env:PATH"
$originalPath = "$env:PATH"
Write-Host "Calling refreshenv..."
Write-Output "Calling refreshenv..."
refreshenv
$mergedPath = "$env:PATH;$originalPath" -split ";" | Select-Object -Unique -Skip 1
$env:PATH = ($mergedPath -join ";")
Write-Host "PATH after refreshenv is $env:PATH"
Write-Output "PATH after refreshenv is $env:PATH"
41 changes: 25 additions & 16 deletions bin/prepare_windows_host_for_app_distribution.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,28 @@
# - Install the Windows 10 SDK if it detected a `.windows-10-sdk-version` file(2)
#
# (1) The certificate it installs is stored in our AWS SecretsManager storage (`windows-code-signing-certificate` secret ID)
# (2) You can skip the Win10 install even if `.windows-10-sdk-version` file is present by using the `SKIP_WINDOWS_10_SDK_INSTALL=1` env var before calling this script
# (2) You can skip the Windows 10 SDK installation regardless of whether `.windows-10-sdk-version` is present by calling the script with `-SkipWindows10SDKInstallation`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

#
# Note: In addition to calling this script, and depending on your client app, you might want to also install `npm` and the `Node.js` packages used by your client app on the agent too. For that part, you should use the `automattic/nvm` Buildkite plugin on the pipeline step's `plugins:` attribute.
#

param (
[switch]$SkipWindows10SDKInstallation = $false
)

# Stop script execution when a non-terminating error occurs
$ErrorActionPreference = "Stop"

Write-Host "--- :windows: Setting up Windows for app distribution"
Write-Output "--- :windows: Setting up Windows for app distribution"

Write-Host "Current working directory: $PWD"
Write-Output "Current working directory: $PWD"

Write-Host "Enable long path behavior"
Write-Output "Enable long path behavior"
# See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1

# Disable Windows Defender before starting – otherwise our performance is terrible
Write-Host "Disable Windows Defender..."
Write-Output "Disable Windows Defender..."
$avPreference = @(
@{DisableArchiveScanning = $true}
@{DisableAutoExclusions = $true}
Expand Down Expand Up @@ -61,54 +65,59 @@ $avPreference | Foreach-Object {
# https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/microsoft-defender-antivirus-compatibility?view=o365-worldwide
$atpRegPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows Advanced Threat Protection'
if (Test-Path $atpRegPath) {
Write-Host "Set Microsoft Defender Antivirus to passive mode"
Write-Output "Set Microsoft Defender Antivirus to passive mode"
Set-ItemProperty -Path $atpRegPath -Name 'ForceDefenderPassiveMode' -Value '1' -Type 'DWORD'
}

# From https://stackoverflow.com/a/46760714
Write-Host "--- :windows: Setting up Package Manager"
Write-Output "--- :windows: Setting up Package Manager"
$env:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."
Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"

# This should avoid issues with symlinks not being supported in Windows.
#
# See how this build failed
# https://buildkite.com/automattic/beeper-desktop/builds/2895#01919738-7c6e-4b82-8d1d-1c1800481740
Write-Host "--- :windows: :linux: Enable developer mode to use symlinks"
Write-Output "--- :windows: :linux: Enable developer mode to use symlinks"

$developerMode = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

if ($developerMode.State -eq 'Enabled') {
Write-Host "Developer Mode is already enabled."
Write-Output "Developer Mode is already enabled."
} else {
Write-Host "Enabling Developer Mode..."
Write-Output "Enabling Developer Mode..."
try {
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart
} catch {
Write-Host "Failed to enable Developer Mode. Continuing without it..."
Write-Output "Failed to enable Developer Mode. Continuing without it..."
}
}

Write-Host "--- :lock_with_ink_pen: Download Code Signing Certificate"
Write-Output "--- :lock_with_ink_pen: Download Code Signing Certificate"
$certificateBinPath = "certificate.bin"
$EncodedText = aws secretsmanager get-secret-value --secret-id windows-code-signing-certificate `
| jq -r '.SecretString' `
| Out-File $certificateBinPath
$certificatePfxPath = "certificate.pfx"
certutil -decode $certificateBinPath $certificatePfxPath
Write-Host "Code signing certificate downloaded at: $((Get-Item $certificatePfxPath).FullName)"
Write-Output "Code signing certificate downloaded at: $((Get-Item $certificatePfxPath).FullName)"

Write-Host "--- :windows: Checking whether to install Windows 10 SDK..."
Write-Output "--- :windows: Checking whether to install Windows 10 SDK..."

# When using Electron Forge and electron2appx, building Appx requires the Windows 10 SDK
#
# See https://github.com/hermit99/electron-windows-store/tree/v2.1.2?tab=readme-ov-file#usage

if ($SkipWindows10SDKInstallation) {
Write-Output "Run with SkipWindows10SDKInstallation = true. Skipping Windows 10 SDK installation check."
exit 0
}

$windowsSDKVersionFile = ".windows-10-sdk-version"
if (Test-Path $windowsSDKVersionFile) {
Write-Host "Found $windowsSDKVersionFile file, installing Windows 10 SDK..."
Write-Output "Found $windowsSDKVersionFile file, installing Windows 10 SDK..."
& "$PSScriptRoot\install_windows_10_sdk.ps1"
If ($LastExitCode -ne 0) { Exit $LastExitCode }
} else {
Write-Host "No $windowsSDKVersionFile file found, skipping Windows 10 SDK installation."
Write-Output "No $windowsSDKVersionFile file found, skipping Windows 10 SDK installation."
}
48 changes: 48 additions & 0 deletions tests/test-install-windows-10-sdk.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
param (
[int]$ExpectedExitCode = 0,
[string]$ExpectedErrorKeyphrase = ""
)

# Ensure the output is UTF-8 encoded so we can use emojis...
[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$emojiGreenCheck = "$([char]0x2705)"
$emojiRedCross = "$([char]0x274C)"

Write-Output "Running test-install-windows-10-sdk.ps1 with ExpectedExitCode=$ExpectedExitCode and ExpectedErrorKeyphrase=$ExpectedErrorKeyphrase"

if (($ExpectedExitCode -eq 0) -and ($ExpectedErrorKeyphrase -ne "")) {
Write-Output "$emojiRedCross Expected call to succeed (expected error code = 0), but given an error keyphrase to check."
exit 1
}

$output = & "$PSScriptRoot\..\bin\install_windows_10_sdk.ps1" -DryRun
$exitCode = $LASTEXITCODE

if ($exitCode -ne $ExpectedExitCode) {
Write-Output "$emojiRedCross Expected exit code $ExpectedExitCode, got $exitCode"
Write-Output "Output was:"
Write-Output "$output"
exit 1
} else {
Write-Output "$emojiGreenCheck Exit code matches expected value ($ExpectedExitCode)"
}

# Only check error keyphrase if exit code is not 0
if ($exitCode -eq 0) {
exit 0
}

# If keyphrase is empty, assume the caller is satisfied with only testing the exit code
if ($ExpectedErrorKeyphrase -eq "") {
Write-Output "Exit code match expectation and no error keyphrase was provided. Test completed."
exit 0
}

if ($output -match [regex]::Escape($ExpectedErrorKeyphrase)) {
Write-Output "$emojiGreenCheck Error keyphrase matches expected value ($ExpectedErrorKeyphrase)"
Write-Output "Test completed."
} else {
Write-Output "$emojiRedCross Expected error to contain '$ExpectedErrorKeyphrase', but got:"
Write-Output "$output"
exit 1
}
53 changes: 53 additions & 0 deletions tests/test-prepare-windows-host-for-app-distribution.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Tests the prepare_windows_host_for_app_distribution.ps1 script with the -SkipWindows10SDKInstallation parameter.
#
# We only test the skip behavior because the installation takes a "long" time to run.

param (
[int]$ExpectedExitCode = 0
)

# Ensure the output is UTF-8 encoded so we can use emojis...
[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$emojiGreenCheck = "$([char]0x2705)"
$emojiRedCross = "$([char]0x274C)"

Write-Output "Testing prepare_windows_host_for_app_distribution.ps1 with -SkipWindows10SDKInstallation"

# Create a valid SDK version file to ensure it's not being used
$sdkVersion = "20348"
"$sdkVersion" | Out-File .windows-10-sdk-version

# Run the script with skip parameter
$output = & "$PSScriptRoot\..\bin\prepare_windows_host_for_app_distribution.ps1" -SkipWindows10SDKInstallation
$exitCode = $LASTEXITCODE

# Check exit code
if ($exitCode -ne $ExpectedExitCode) {
Write-Output "$emojiRedCross Expected exit code $ExpectedExitCode, got $exitCode"
Write-Output "Output was:"
Write-Output "$output"
exit 1
} else {
Write-Output "$emojiGreenCheck Exit code matches expected value ($ExpectedExitCode)"
}

$expectedSkipMessage = "Run with SkipWindows10SDKInstallation = true. Skipping Windows 10 SDK installation check."
if ($output -match [regex]::Escape($expectedSkipMessage)) {
Write-Output "$emojiGreenCheck Found expected skip message in output"
} else {
Write-Output "$emojiRedCross Expected to find message about skipping due to parameter, but got:"
Write-Output "$output"
exit 1
}

# Verify SDK was not installed by checking the file system
$windowsSDKsRoot = "C:\Program Files (x86)\Windows Kits\10\bin"
$sdkPath = "$windowsSDKsRoot\10.0.$sdkVersion\x64"
If (Test-Path $sdkPath) {
Write-Output "$emojiRedCross Found SDK installation at $sdkPath when it should have been skipped"
exit 1
} else {
Write-Output "$emojiGreenCheck Confirmed SDK was not installed at $sdkPath"
}

Write-Output "Test completed successfully."