Skip to content

Commit 3e4d974

Browse files
bolenscursoragent
andauthored
ci: add Arch Linux coverage with shared Dev Containers (#35)
* ci: add Arch Linux coverage with shared Dev Containers Host Arch jobs on ubuntu-latest inside archlinux containers, collapse the cosmetic pwsh 7.2/7.4 matrix to one runner pwsh per OS, and share the Linux pwsh installer between CI and Ubuntu/Arch Dev Containers. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(ci): install git before Arch checkout Arch containers lack git at job start, so actions/checkout fell back to a REST archive without .git and Get-TestRepoRoot failed. Bootstrap pacman git first, and accept profile markers / GITHUB_WORKSPACE as repo-root fallbacks. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(test): keep Get-TestRepoRoot self-contained after global promote Inlining repo-root markers so promoted Function:\global:Get-TestRepoRoot no longer depends on a sibling helper missing from Pester containers. Also mark the Arch workspace as a git safe.directory. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(test): make Arch CI isolation and platform assertions pass Use read mocks when running as root (chmod 000 is ineffective), stop short-circuiting Get-TestRepoRoot via GITHUB_WORKSPACE, accept pacman in install-hint fallbacks, and tolerate empty PATH as null on Unix. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 5532888 commit 3e4d974

20 files changed

Lines changed: 560 additions & 30 deletions

File tree

.devcontainer/arch/Dockerfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Arch Linux Dev Container — mirrors CI arch-latest (ubuntu host + archlinux container).
2+
FROM archlinux:latest
3+
4+
ARG PWSH_VERSION=7.4.7
5+
ENV POWERSHELL_TELEMETRY_OPTOUT=1 \
6+
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
7+
8+
COPY install-pwsh-linux.sh /tmp/install-pwsh-linux.sh
9+
RUN chmod +x /tmp/install-pwsh-linux.sh \
10+
&& /tmp/install-pwsh-linux.sh "${PWSH_VERSION}" \
11+
&& rm -f /tmp/install-pwsh-linux.sh
12+
13+
WORKDIR /workspace
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"name": "ps-profile (Arch)",
3+
"build": {
4+
"dockerfile": "Dockerfile",
5+
"context": "..",
6+
"args": {
7+
"PWSH_VERSION": "7.4.7"
8+
}
9+
},
10+
"workspaceFolder": "/workspace",
11+
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
12+
"remoteUser": "root",
13+
"postCreateCommand": "pwsh -NoProfile -File .devcontainer/post-create.ps1",
14+
"customizations": {
15+
"vscode": {
16+
"extensions": [
17+
"ms-vscode.powershell",
18+
"ms-azuretools.vscode-docker",
19+
"editorconfig.editorconfig"
20+
],
21+
"settings": {
22+
"terminal.integrated.defaultProfile.linux": "pwsh",
23+
"terminal.integrated.profiles.linux": {
24+
"pwsh": {
25+
"path": "/usr/local/bin/pwsh",
26+
"args": ["-NoLogo"]
27+
}
28+
},
29+
"powershell.powerShellAdditionalExePaths": {
30+
"Dev Container pwsh": "/usr/local/bin/pwsh"
31+
},
32+
"powershell.powerShellDefaultVersion": "Dev Container pwsh"
33+
}
34+
}
35+
}
36+
}

.devcontainer/devcontainer.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "ps-profile (Ubuntu)",
3+
"build": {
4+
"dockerfile": "ubuntu/Dockerfile",
5+
"context": ".",
6+
"args": {
7+
"PWSH_VERSION": "7.4.7",
8+
"UBUNTU_VERSION": "24.04"
9+
}
10+
},
11+
"workspaceFolder": "/workspace",
12+
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
13+
"remoteUser": "root",
14+
"postCreateCommand": "pwsh -NoProfile -File .devcontainer/post-create.ps1",
15+
"customizations": {
16+
"vscode": {
17+
"extensions": [
18+
"ms-vscode.powershell",
19+
"ms-azuretools.vscode-docker",
20+
"editorconfig.editorconfig"
21+
],
22+
"settings": {
23+
"terminal.integrated.defaultProfile.linux": "pwsh",
24+
"terminal.integrated.profiles.linux": {
25+
"pwsh": {
26+
"path": "/usr/local/bin/pwsh",
27+
"args": ["-NoLogo"]
28+
}
29+
},
30+
"powershell.powerShellAdditionalExePaths": {
31+
"Dev Container pwsh": "/usr/local/bin/pwsh"
32+
},
33+
"powershell.powerShellDefaultVersion": "Dev Container pwsh"
34+
}
35+
}
36+
}
37+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/usr/bin/env bash
2+
# Install PowerShell from the official Linux x64 tarball (CI + Dev Containers).
3+
# Usage: install-pwsh-linux.sh [version]
4+
set -euo pipefail
5+
6+
pwsh_version="${1:-7.4.7}"
7+
install_root="/opt/microsoft/powershell/$(echo "${pwsh_version}" | cut -d. -f1,2)"
8+
tarball="powershell-${pwsh_version}-linux-x64.tar.gz"
9+
download_url="https://github.com/PowerShell/PowerShell/releases/download/v${pwsh_version}/${tarball}"
10+
11+
install_deps_arch() {
12+
pacman -Syu --noconfirm
13+
pacman -S --noconfirm \
14+
git \
15+
icu \
16+
openssl \
17+
curl \
18+
ca-certificates \
19+
tar \
20+
gzip \
21+
which \
22+
less \
23+
sudo \
24+
base-devel
25+
}
26+
27+
install_deps_debian() {
28+
export DEBIAN_FRONTEND=noninteractive
29+
apt-get update
30+
apt-get install -y --no-install-recommends \
31+
ca-certificates \
32+
curl \
33+
git \
34+
tar \
35+
gzip \
36+
less \
37+
sudo \
38+
locales \
39+
openssl
40+
41+
# ICU / OpenSSL SONAME packages differ across Ubuntu releases (and t64 transition).
42+
local icu_pkg ssl_pkg
43+
icu_pkg="$(apt-cache search --names-only '^libicu[0-9]+t64$|^libicu[0-9]+$' 2>/dev/null | awk '{print $1}' | sort -V | tail -1 || true)"
44+
if [[ -n "${icu_pkg}" ]]; then
45+
apt-get install -y --no-install-recommends "${icu_pkg}"
46+
fi
47+
for ssl_pkg in libssl3t64 libssl3; do
48+
if apt-cache show "${ssl_pkg}" >/dev/null 2>&1; then
49+
apt-get install -y --no-install-recommends "${ssl_pkg}"
50+
break
51+
fi
52+
done
53+
54+
rm -rf /var/lib/apt/lists/*
55+
}
56+
57+
if [[ -f /etc/arch-release ]]; then
58+
install_deps_arch
59+
elif [[ -f /etc/debian_version ]]; then
60+
install_deps_debian
61+
else
62+
echo "Unsupported distro for install-pwsh-linux.sh (need Arch or Debian/Ubuntu)" >&2
63+
exit 1
64+
fi
65+
66+
mkdir -p "${install_root}"
67+
curl -fsSL -o "/tmp/${tarball}" "${download_url}"
68+
tar -xzf "/tmp/${tarball}" -C "${install_root}"
69+
rm -f "/tmp/${tarball}"
70+
71+
# Tar extract can leave the entrypoint non-executable in some images (exit 126).
72+
chmod a+x "${install_root}/pwsh"
73+
find "${install_root}" -type f -name '*.so*' -exec chmod a+x {} +
74+
75+
# Prefer /usr/local/bin so PATH does not resolve through Arch usr-merge /usr/sbin.
76+
ln -sfn "${install_root}/pwsh" /usr/local/bin/pwsh
77+
ln -sfn "${install_root}/pwsh" /usr/bin/pwsh
78+
79+
command -v pwsh
80+
pwsh -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'

.devcontainer/post-create.ps1

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#Requires -Version 7.0
2+
<#
3+
.SYNOPSIS
4+
Dev Container post-create: install CI-aligned PowerShell modules.
5+
#>
6+
Set-StrictMode -Version Latest
7+
$ErrorActionPreference = 'Stop'
8+
9+
Write-Host 'Configuring PSGallery...'
10+
if (-not (Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue)) {
11+
Register-PSRepository -Default
12+
}
13+
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
14+
15+
Write-Host 'Installing PSScriptAnalyzer...'
16+
Install-Module -Name PSScriptAnalyzer -Scope CurrentUser -Force -AllowClobber
17+
18+
Write-Host 'Installing Pester 5.7.x (CI pin)...'
19+
Install-Module -Name Pester -MinimumVersion 5.7.0 -MaximumVersion 5.7.99 `
20+
-Scope CurrentUser -Force -AllowClobber
21+
$pester = Get-Module -ListAvailable Pester |
22+
Where-Object { $_.Version -ge [version]'5.7.0' -and $_.Version -lt [version]'5.8.0' } |
23+
Sort-Object Version -Descending |
24+
Select-Object -First 1
25+
if (-not $pester) {
26+
throw 'Pester 5.7.x is required but was not installed'
27+
}
28+
Import-Module Pester -RequiredVersion $pester.Version -Force
29+
30+
Write-Host "Ready: pwsh $($PSVersionTable.PSVersion) | Pester $($pester.Version)"
31+
Write-Host 'Try: pwsh -NoProfile -File scripts/utils/code-quality/run-pester-ci-shard.ps1 -Shard unit-library -Quiet'

.devcontainer/run-shard.sh

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env bash
2+
# Build and run a Pester CI shard inside a distro Dev Container image (no IDE required).
3+
# Usage:
4+
# .devcontainer/run-shard.sh ubuntu unit-library
5+
# .devcontainer/run-shard.sh arch coverage-smoke
6+
set -euo pipefail
7+
8+
distro="${1:-}"
9+
shard="${2:-}"
10+
if [[ -z "${distro}" || -z "${shard}" ]]; then
11+
echo "Usage: $0 <ubuntu|arch> <shard-name>" >&2
12+
exit 2
13+
fi
14+
15+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
16+
pwsh_version="${PWSH_VERSION:-7.4.7}"
17+
image="ps-profile-devcontainer:${distro}"
18+
19+
case "${distro}" in
20+
ubuntu)
21+
dockerfile="${repo_root}/.devcontainer/ubuntu/Dockerfile"
22+
context="${repo_root}/.devcontainer"
23+
;;
24+
arch)
25+
dockerfile="${repo_root}/.devcontainer/arch/Dockerfile"
26+
context="${repo_root}/.devcontainer"
27+
;;
28+
*)
29+
echo "Unknown distro '${distro}' (expected ubuntu or arch)" >&2
30+
exit 2
31+
;;
32+
esac
33+
34+
echo "==> Building ${image}"
35+
docker build \
36+
--build-arg "PWSH_VERSION=${pwsh_version}" \
37+
-f "${dockerfile}" \
38+
-t "${image}" \
39+
"${context}"
40+
41+
echo "==> Running shard '${shard}' on ${distro}"
42+
docker run --rm \
43+
-e POWERSHELL_TELEMETRY_OPTOUT=1 \
44+
-v "${repo_root}:/workspace:rw" \
45+
-w /workspace \
46+
"${image}" \
47+
pwsh -NoProfile -Command "
48+
\$ErrorActionPreference = 'Stop'
49+
if (-not (Get-PSRepository -Name PSGallery -ErrorAction SilentlyContinue)) {
50+
Register-PSRepository -Default
51+
}
52+
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
53+
Install-Module -Name Pester -MinimumVersion 5.7.0 -MaximumVersion 5.7.99 -Force -Scope CurrentUser -AllowClobber
54+
\$pester = Get-Module -ListAvailable Pester |
55+
Where-Object { \$_.Version -ge [version]'5.7.0' -and \$_.Version -lt [version]'5.8.0' } |
56+
Sort-Object Version -Descending |
57+
Select-Object -First 1
58+
if (-not \$pester) { throw 'Pester 5.7.x missing' }
59+
Import-Module Pester -RequiredVersion \$pester.Version -Force
60+
& pwsh -NoProfile -NonInteractive -File scripts/utils/code-quality/run-pester-ci-shard.ps1 -Shard '${shard}' -Quiet
61+
"

.devcontainer/ubuntu/Dockerfile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Ubuntu Dev Container — mirrors primary Linux CI host (Debian-family).
2+
ARG UBUNTU_VERSION=24.04
3+
FROM ubuntu:${UBUNTU_VERSION}
4+
5+
ARG PWSH_VERSION=7.4.7
6+
ENV POWERSHELL_TELEMETRY_OPTOUT=1 \
7+
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false
8+
9+
COPY install-pwsh-linux.sh /tmp/install-pwsh-linux.sh
10+
RUN chmod +x /tmp/install-pwsh-linux.sh \
11+
&& /tmp/install-pwsh-linux.sh "${PWSH_VERSION}" \
12+
&& rm -f /tmp/install-pwsh-linux.sh
13+
14+
WORKDIR /workspace
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "ps-profile (Ubuntu)",
3+
"build": {
4+
"dockerfile": "Dockerfile",
5+
"context": "..",
6+
"args": {
7+
"PWSH_VERSION": "7.4.7",
8+
"UBUNTU_VERSION": "24.04"
9+
}
10+
},
11+
"workspaceFolder": "/workspace",
12+
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
13+
"remoteUser": "root",
14+
"postCreateCommand": "pwsh -NoProfile -File .devcontainer/post-create.ps1",
15+
"customizations": {
16+
"vscode": {
17+
"extensions": [
18+
"ms-vscode.powershell",
19+
"ms-azuretools.vscode-docker",
20+
"editorconfig.editorconfig"
21+
],
22+
"settings": {
23+
"terminal.integrated.defaultProfile.linux": "pwsh",
24+
"terminal.integrated.profiles.linux": {
25+
"pwsh": {
26+
"path": "/usr/local/bin/pwsh",
27+
"args": ["-NoLogo"]
28+
}
29+
},
30+
"powershell.powerShellAdditionalExePaths": {
31+
"Dev Container pwsh": "/usr/local/bin/pwsh"
32+
},
33+
"powershell.powerShellDefaultVersion": "Dev Container pwsh"
34+
}
35+
}
36+
}
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Setup Arch Linux for PowerShell
2+
description: Prepare an Arch Linux container with git and PowerShell for CI jobs.
3+
inputs:
4+
pwsh-version:
5+
description: PowerShell version to install from the official Linux tarball (for example 7.4.7).
6+
required: false
7+
default: '7.4.7'
8+
runs:
9+
using: composite
10+
steps:
11+
- name: Install PowerShell on Arch Linux
12+
shell: bash
13+
run: |
14+
set -euo pipefail
15+
script="${GITHUB_WORKSPACE}/.devcontainer/install-pwsh-linux.sh"
16+
chmod +x "${script}"
17+
"${script}" '${{ inputs.pwsh-version }}'

0 commit comments

Comments
 (0)