fix(ci): Mac buildx without osxkeychain; soft-fail screencapture

Headless Air/Mini runners fail docker/setup-buildx when credsStore points
at a missing docker-credential-osxkeychain binary. Point DOCKER_CONFIG at
an empty config for macOS jobs only.

macOS screenshot jobs fail when screencapture has no interactive display;
skip those captures and warn on missing screenshot artifacts instead of
failing the workflow.
This commit is contained in:
cynarAI 2026-09-21 20:12:50 +02:00
parent ee56e1795e
commit a8e08352bc
3 changed files with 36 additions and 10 deletions

View File

@ -65,5 +65,5 @@ jobs:
path: | path: |
apps/desktop/e2e/screenshots/08-setup-macos-native-controls.png apps/desktop/e2e/screenshots/08-setup-macos-native-controls.png
apps/desktop/e2e/screenshots/09-macos-dock.png apps/desktop/e2e/screenshots/09-macos-dock.png
if-no-files-found: error if-no-files-found: warn
retention-days: 1 retention-days: 1

View File

@ -126,6 +126,15 @@ jobs:
- uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 - uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0
with: with:
persist-credentials: false persist-credentials: false
# Headless Mac runners often have credsStore=osxkeychain without the helper binary,
# which breaks buildx bootstrap when pulling moby/buildkit.
- name: Use Docker config without osxkeychain
if: runner.os == 'macOS'
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/docker-config"
printf '{}\n' > "$RUNNER_TEMP/docker-config/config.json"
echo "DOCKER_CONFIG=$RUNNER_TEMP/docker-config" >> "$GITHUB_ENV"
- uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log in to GHCR - name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0

View File

@ -108,11 +108,25 @@ test("first run asks whether to use a local or existing instance", async () => {
await expect(setup.locator(".titlebar")).toHaveCSS("padding-left", "88px"); await expect(setup.locator(".titlebar")).toHaveCSS("padding-left", "88px");
expect((await setup.locator(".titlebar-name").boundingBox())?.x).toBeGreaterThanOrEqual(88); expect((await setup.locator(".titlebar-name").boundingBox())?.x).toBeGreaterThanOrEqual(88);
if (process.platform === "darwin") { if (process.platform === "darwin") {
// Headless/self-hosted Mac runners often lack an interactive display session;
// screencapture then fails with "could not create image from display".
const captureOrSkip = async (args: string[], label: string) => {
try {
await execFileAsync("screencapture", args);
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
if (/could not create image from display|no displays|not authorized|capture failed/i.test(message)) {
console.warn(`screencapture skipped (${label}): ${message}`);
return;
}
throw err;
}
};
if (process.env.CI) { if (process.env.CI) {
await execFileAsync("screencapture", [ await captureOrSkip(
"-x", ["-x", path.join(import.meta.dirname, "screenshots", "09-macos-dock.png")],
path.join(import.meta.dirname, "screenshots", "09-macos-dock.png"), "dock",
]); );
} }
await app.evaluate(({ BrowserWindow }) => { await app.evaluate(({ BrowserWindow }) => {
const window = BrowserWindow.getAllWindows()[0]; const window = BrowserWindow.getAllWindows()[0];
@ -122,11 +136,14 @@ test("first run asks whether to use a local or existing instance", async () => {
window.focus(); window.focus();
}); });
await setup.waitForTimeout(500); await setup.waitForTimeout(500);
await execFileAsync("screencapture", [ await captureOrSkip(
"-x", [
"-R40,40,720,700", "-x",
path.join(import.meta.dirname, "screenshots", "08-setup-macos-native-controls.png"), "-R40,40,720,700",
]); path.join(import.meta.dirname, "screenshots", "08-setup-macos-native-controls.png"),
],
"native-controls",
);
} }
}); });