mirror of
https://github.com/block/buzz.git
synced 2026-10-31 06:21:34 +00:00
## Summary Fixes the two CI workflow defects that turned `main` red most often in the 21–28 Oct 2026 audit: - **Desktop Tauri:** the lane now caches its apt `.deb`s. It no longer re-downloads 62 MB from a slow Ubuntu mirror on every run. - **Windows Rust:** the lane drops a duplicate `cargo check` and gets a 60 min cap, so a cold run can save its cache. It also updates #8613's `scripts/flake-check.test.mjs`, which breaks once the Tauri package list moves into an env var. There are no product code or test-behaviour changes. This is one of seven PRs split out of the `flakey-tests` branch (siblings below). ### Related issue None found. #8613 touched both workflows after the audit, but not these steps. No open PR changes how the Tauri packages are fetched, the Windows timeout, or its Check (workspace) step: - #8422, #8321 and #8373 only add packages to the list, and would now add them to `TAURI_APT_PACKAGES`. - #8414 adds two mesh-llm Tauri steps to the Windows job. If it lands, they must fit the cold budget below. ### CI failures fixed | Lane / test | Failing runs | Cause | Change | |---|---|---|---| | Desktop Tauri, "Install Tauri dependencies (Linux)" (`_ci-desktop.yml`) | 62 jobs in 51 run attempts, 22–27 Oct. On main: 39821769576, 39822883395, 39827234118, 40333705511, 40342468627, 40348069929, 40353619362, 40368315739, 40373404267, 40374519539, 40556742929 | All 3 `ci-apt-retry.sh` attempts hit their 420 s limit while `azure.archive.ubuntu.com` served the 62 MB at 20–65 KB/s. The 25.5 MB `libwebkit2gtk-4.1-0` alone takes a whole attempt, and each attempt loses its partial download. | The package list moves to a job-level `TAURI_APT_PACKAGES`. A new "Resolve Tauri apt archives" step builds the cache key from `apt-get install --print-uris -o Acquire::ForceHash=SHA256` (name, size and SHA256 per file). `actions/cache/restore` uses that key. The install step copies only the restored files whose SHA256 matches the signed index, because apt 2.8.3 reuses any same-size cached `.deb` without hashing it. A best-effort rebuild keeps exactly the listed files. `actions/cache/save` runs only on core-lane pushes after a successful rebuild; PR runs never save. | | Windows Rust (`_ci-rust.yml`) | All on main: 39796569342 (job 119885795086), 39821769576 (119975358772), 39827234118 (119994286695), 39865872891 (120128351939), 40402556064 (121852634685) | Every test passed. Cold steps take 41.3–43.5 min, so the 45 min cap cancelled the `Swatinem/rust-cache` post-run save 1.6–3.7 min in. No cache was written, and the next push was cold again. | Delete "Check (workspace)". The clippy step before it covers the same `--workspace --all-targets` set with `-D warnings`, which saves 2.0–2.8 min. Raise `timeout-minutes` from 45 to 60, with the measured breakdown in a comment: 39–41 min of steps, a ~4.5 min save and ~15 min of margin. | | `scripts/flake-check.test.mjs` "repeat invocations mirror the lanes they stand in for" | None in CI yet: it fails only with this change applied | #8613 added this test after `flakey-tests` branched. It checks that the advisory `flake-tauri` lane installs the same packages as the Desktop Tauri core lane, by regex-matching the inline `apt-get install -y --no-install-recommends \` list in `_ci-desktop.yml`. That list now lives in `TAURI_APT_PACKAGES`, so the regex matched nothing and the test failed with "Desktop Tauri apt packages". | Read `TAURI_APT_PACKAGES` from `_ci-desktop.yml` and compare package names (12 on each side) with `_ci-flake.yml`'s list. Renaming one package in `_ci-flake.yml` still fails the test. Giving the `flake-tauri` lane the same read-only `.deb` restore is a follow-up. | Local evidence is from the original `flakey-tests` commit (9aa768a3b): - The apt steps ran verbatim in Ubuntu 24.04 containers with apt 2.8.3, with the cache restore and the save step's `if:` emulated. - On a miss, the install fetches everything ("Need to get 254 MB"). On an exact hit with the network down, it fetches nothing ("Need to get 0 B/254 MB"). - On a fallback with one `.deb` missing and one corrupted at the same size, the hash check rejects the corrupt file, and apt re-fetches only the corrupt and missing files. - The key was identical in all four simulated jobs. - The Windows numbers come from the jobs API for the five runs above. On this branch, the split session ran the `scripts/` node tests: `ci-selection`, `ci-required-gates`, `ci-apt-retry` and `flake-check` on macOS gave 84 pass, 0 fail and 8 skipped (Linux-only). Before the `flake-check.test.mjs` fix, that test failed 1 case. The same session ran actionlint 1.7.12 with shellcheck, which was clean, and the rust-cache contract scripts, which passed. ### Verification This branch was pushed without further local re-verification, by the user's choice: local test runs were overloading the machine and failing for that reason. **Hosted CI is the check.** It was pushed with `git push --no-verify` over SSH. The pre-push hook runs tests, and the HTTPS token lacks the `workflow` scope. Only hosted CI can show: - The runner's real package list (about 62 MB) and the same key in all three Tauri lanes. - The `actions/cache` round trip. The first PR run misses, because `main` has no key yet. After merge, the first push to `main` saves it. - A cold Windows run saving its cache within the new cap. The next toolchain bump or cache eviction will show it. Remaining risk: after Ubuntu updates a large package, runs fetch it from the mirror until a push to `main` saves a new key. ### Readiness CI-only change. AGENTS.md's readiness steps (agent review, then human confirmation) are still outstanding, so `buzz-review-completed` is not set. ### Merge order Independent of the other six. It merges cleanly onto `main`, and with every sibling, in any order. ### Sibling PRs Split from `flakey-tests` (one PR per area): #8676 (PostgreSQL lease + lane), #8677 (relay E2E helper + Windows shell), #8678 (mobile), #8680 (desktop product races), #8681 (desktop E2E state gates), #8682 (desktop E2E composer + row actions). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Matt Toohey <contact@matttoohey.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
340 lines
15 KiB
YAML
340 lines
15 KiB
YAML
name: CI / Desktop
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
rust:
|
|
required: true
|
|
type: boolean
|
|
desktop:
|
|
required: true
|
|
type: boolean
|
|
desktop_rust:
|
|
required: true
|
|
type: boolean
|
|
outputs:
|
|
desktop_result:
|
|
value: ${{ jobs.results.outputs.desktop_result }}
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
BUZZ_TEST_POSTGRES_PASSWORD: buzz_dev
|
|
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.cache/ms-playwright
|
|
|
|
jobs:
|
|
# Biome, node:test, and the Vite build do not compile Rust, but node:test
|
|
# also pins desktop constants to relay/DB crate sources (for example
|
|
# relayReconnectReplay.test.mjs), so Rust changes select this job too.
|
|
desktop-js:
|
|
name: Desktop JS
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
# Keep in sync with JS_SELECTED in the Desktop gate (pinned by ci-required-gates.test.mjs).
|
|
if: github.event_name == 'push' || inputs.desktop || inputs.rust
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
fetch-depth: 2
|
|
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
|
|
- name: Get pnpm store directory
|
|
id: pnpm-cache
|
|
run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
|
- name: Restore pnpm store cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
restore-keys: pnpm-${{ runner.os }}-
|
|
- name: Install desktop dependencies
|
|
run: just desktop-install-ci
|
|
- name: Desktop lint and format
|
|
run: just desktop-check
|
|
- name: Desktop unit tests
|
|
run: just desktop-test
|
|
- name: Flake check selection tests
|
|
run: node --test scripts/flake-check.test.mjs
|
|
- name: Desktop build
|
|
run: just desktop-build
|
|
- name: Save pnpm store cache
|
|
if: github.event_name == 'push'
|
|
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
|
|
# Tauri Rust lanes run in parallel. The compiled-flags lane only rebuilds
|
|
# buzz_lib under other BUZZ_BUILD_* values, so it restores the core lane's
|
|
# cache read-only; the mesh-llm feature pulls its own dependency graph.
|
|
desktop-tauri:
|
|
name: Desktop Tauri (${{ matrix.lane }})
|
|
runs-on: ubuntu-latest
|
|
# A lane needs up to ~15m. ci-apt-retry.sh bounds the apt steps at ~34m worst
|
|
# case (update ~8.5m + install ~25m); 55m fits both, so a degraded mirror
|
|
# fails with the wrapper's error instead of the job timeout.
|
|
timeout-minutes: 55
|
|
# Keep in sync with RUST_SELECTED in the Desktop gate (pinned by ci-required-gates.test.mjs).
|
|
if: github.event_name == 'push' || inputs.desktop_rust || inputs.rust
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- lane: core
|
|
cache: desktop-core
|
|
save-cache: true
|
|
run: just desktop-tauri-clippy && just desktop-tauri-check && just desktop-tauri-test
|
|
- lane: mesh
|
|
cache: desktop-mesh
|
|
save-cache: true
|
|
run: just desktop-tauri-test-mesh
|
|
- lane: compiled-flags
|
|
cache: desktop-core
|
|
save-cache: false
|
|
run: just desktop-tauri-test-compiled-flags
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
# Resolved and installed by the steps below; the .deb cache key hashes
|
|
# what apt resolves for this list.
|
|
TAURI_APT_PACKAGES: >-
|
|
build-essential
|
|
curl
|
|
file
|
|
libasound2-dev
|
|
libayatana-appindicator3-dev
|
|
libgtk-3-dev
|
|
librsvg2-dev
|
|
libssl-dev
|
|
libwebkit2gtk-4.1-dev
|
|
libxdo-dev
|
|
patchelf
|
|
wget
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
with:
|
|
fetch-depth: 2
|
|
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
|
|
- uses: rui314/setup-mold@7e4f20ad28a2e8ca6fd0892ccf72e2abb706b9c3 # v1
|
|
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32
|
|
with:
|
|
workspaces: desktop/src-tauri
|
|
shared-key: ${{ matrix.cache }}
|
|
save-if: ${{ matrix.save-cache && github.event_name != 'pull_request' }}
|
|
# A degraded Ubuntu mirror serves .debs at ~50 KB/s, and the ~62 MB
|
|
# Tauri download (one 25.5 MB libwebkit2gtk .deb) then outlasts every
|
|
# ci-apt-retry.sh attempt. Cache the .debs in the Actions cache so the
|
|
# mirror only serves `apt-get update` and packages Ubuntu has updated
|
|
# since main last saved.
|
|
- name: Resolve Tauri apt archives
|
|
id: tauri-debs
|
|
run: |
|
|
set -euo pipefail
|
|
CI_APT_ATTEMPT_SECONDS=90 scripts/ci-apt-retry.sh sudo apt-get update
|
|
read -ra packages <<< "$TAURI_APT_PACKAGES"
|
|
# Name, size and SHA256 (from the signed index) of each .deb the
|
|
# install will fetch. The mirror URI is left out so the key doesn't
|
|
# depend on which mirror answered. Runs before the restore:
|
|
# --print-uris omits files that are already in
|
|
# /var/cache/apt/archives.
|
|
sudo apt-get install --print-uris -qq -y --no-install-recommends \
|
|
-o Acquire::ForceHash=SHA256 "${packages[@]}" |
|
|
awk '{print $2, $3, $4}' | sort > "$RUNNER_TEMP/tauri-debs.txt"
|
|
. /etc/os-release
|
|
prefix="tauri-debs-${ID}${VERSION_ID}-"
|
|
echo "prefix=$prefix" >> "$GITHUB_OUTPUT"
|
|
echo "key=$prefix$(sha256sum "$RUNNER_TEMP/tauri-debs.txt" | cut -c1-16)" >> "$GITHUB_OUTPUT"
|
|
- name: Restore Tauri apt archives
|
|
id: tauri-debs-cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ~/.cache/tauri-debs
|
|
key: ${{ steps.tauri-debs.outputs.key }}
|
|
restore-keys: ${{ steps.tauri-debs.outputs.prefix }}
|
|
- name: Install Tauri dependencies (Linux)
|
|
id: tauri-debs-install
|
|
env:
|
|
DEBIAN_FRONTEND: noninteractive
|
|
run: |
|
|
set -euo pipefail
|
|
debs=~/.cache/tauri-debs
|
|
mkdir -p "$debs"
|
|
# apt reuses an archived .deb of the expected size without checking
|
|
# its hash, so seed only restored files whose SHA256 matches the
|
|
# signed index. apt downloads and verifies the rest. sha256sum exits
|
|
# non-zero when a file fails or none is restored; neither is fatal.
|
|
awk '{sub(/^SHA256:/, "", $3); print $3 " " $1}' "$RUNNER_TEMP/tauri-debs.txt" > "$RUNNER_TEMP/tauri-debs.sha256"
|
|
(cd "$debs" && { sha256sum --check --ignore-missing "$RUNNER_TEMP/tauri-debs.sha256" || true; }) |
|
|
sed -n 's/: OK$//p' | (cd "$debs" && xargs -r sudo cp -t /var/cache/apt/archives/)
|
|
read -ra packages <<< "$TAURI_APT_PACKAGES"
|
|
scripts/ci-apt-retry.sh sudo apt-get install -y --no-install-recommends "${packages[@]}"
|
|
# Keep exactly the resolved files, so a restore-keys fallback can't
|
|
# pile up superseded versions. The packages are installed by now, so
|
|
# a failure here only warns and skips the save.
|
|
if rm -rf "$debs" && mkdir -p "$debs" &&
|
|
awk '{print "/var/cache/apt/archives/" $1}' "$RUNNER_TEMP/tauri-debs.txt" | xargs -r cp -t "$debs"; then
|
|
echo "rebuilt=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "::warning::Could not rebuild the Tauri apt archive cache; not saving it."
|
|
fi
|
|
# Like the other caches here, only pushes save; PR runs restore. All
|
|
# three lanes resolve the same key, so one lane saves it.
|
|
- name: Save Tauri apt archives
|
|
if: matrix.lane == 'core' && github.event_name == 'push' && steps.tauri-debs-cache.outputs.cache-hit != 'true' && steps.tauri-debs-install.outputs.rebuilt == 'true'
|
|
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ~/.cache/tauri-debs
|
|
key: ${{ steps.tauri-debs.outputs.key }}
|
|
- name: Desktop Tauri ${{ matrix.lane }}
|
|
run: ${{ matrix.run }}
|
|
env:
|
|
CMAKE_POLICY_VERSION_MINIMUM: "3.5"
|
|
|
|
desktop-smoke-e2e:
|
|
name: Desktop Smoke E2E (${{ matrix.shard }})
|
|
runs-on: ubuntu-latest
|
|
# A smoke shard needs ~12m, and Chromium dependency setup is bounded by
|
|
# ci-apt-retry.sh (~25m worst case). Leave time for the full suite
|
|
# and its reports to finish.
|
|
timeout-minutes: 45
|
|
# Keep in sync with FRONTEND_SELECTED in the Desktop gate (pinned by ci-required-gates.test.mjs).
|
|
if: github.event_name == 'push' || inputs.desktop
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
# Playwright shards smoke specs by test count, not duration; ten
|
|
# shards keep the slowest one near 11 minutes of test time.
|
|
shard: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: cashapp/activate-hermit@cea9af7913204a965fd488637a8d1811bba2e616 # v1
|
|
- name: Get pnpm store directory
|
|
id: pnpm-cache
|
|
run: echo "STORE_PATH=$(pnpm store path --silent)" >> "$GITHUB_OUTPUT"
|
|
- name: Restore pnpm store cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
key: pnpm-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
restore-keys: pnpm-${{ runner.os }}-
|
|
- name: Install desktop dependencies
|
|
run: just desktop-install-ci
|
|
- name: Get Playwright version
|
|
id: pw-version
|
|
run: echo "version=$(cd desktop && node -e "console.log(require('@playwright/test/package.json').version)")" >> "$GITHUB_OUTPUT"
|
|
- name: Restore Playwright browser cache
|
|
id: playwright-cache
|
|
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
|
|
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
|
|
- name: Install Playwright Chromium
|
|
if: steps.playwright-cache.outputs.cache-hit != 'true'
|
|
run: cd desktop && pnpm exec playwright install chromium
|
|
- name: Install Playwright system dependencies
|
|
run: cd desktop && ../scripts/ci-apt-retry.sh pnpm exec playwright install-deps chromium
|
|
- name: Save Playwright browser cache
|
|
if: steps.playwright-cache.outputs.cache-hit != 'true' && github.event_name == 'push' && matrix.shard == 1
|
|
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
|
|
with:
|
|
path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
|
|
key: playwright-${{ runner.os }}-${{ steps.pw-version.outputs.version }}
|
|
- name: Desktop E2E build
|
|
run: pnpm -C desktop build:e2e
|
|
- name: Desktop smoke e2e
|
|
run: cd desktop && pnpm exec playwright test --project=smoke --shard=${{ matrix.shard }}/${{ strategy.job-total }}
|
|
- name: Summarize flaky tests
|
|
if: ${{ !cancelled() }}
|
|
run: node scripts/summarize-flaky-tests.mjs playwright-report.json "Desktop Smoke E2E (${{ matrix.shard }})"
|
|
working-directory: desktop
|
|
- name: Upload desktop smoke e2e artifacts
|
|
if: ${{ !cancelled() }}
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: desktop-smoke-e2e-artifacts-${{ matrix.shard }}
|
|
path: |
|
|
desktop/playwright-report
|
|
desktop/playwright-report.json
|
|
desktop/test-results
|
|
if-no-files-found: ignore
|
|
retention-days: 7
|
|
|
|
desktop:
|
|
name: Desktop
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
needs: [desktop-js, desktop-tauri, desktop-smoke-e2e, desktop-windows-build]
|
|
if: always() && (github.event_name == 'push' || inputs.desktop || inputs.desktop_rust || inputs.rust)
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Check desktop jobs
|
|
env:
|
|
JS_SELECTED: ${{ github.event_name == 'push' || inputs.desktop || inputs.rust }}
|
|
RUST_SELECTED: ${{ github.event_name == 'push' || inputs.desktop_rust || inputs.rust }}
|
|
FRONTEND_SELECTED: ${{ github.event_name == 'push' || inputs.desktop }}
|
|
JS: ${{ needs.desktop-js.result }}
|
|
TAURI: ${{ needs.desktop-tauri.result }}
|
|
SMOKE: ${{ needs.desktop-smoke-e2e.result }}
|
|
WINDOWS: ${{ needs.desktop-windows-build.result }}
|
|
run: |
|
|
# A selected job must succeed; an unselected job must be skipped.
|
|
status=0
|
|
check() {
|
|
local name="$1" selected="$2" result="$3" want=skipped
|
|
[ "$selected" = true ] && want=success
|
|
if [ "$result" != "$want" ]; then
|
|
echo "$name finished with: $result (expected $want)"
|
|
status=1
|
|
fi
|
|
}
|
|
check "Desktop JS" "$JS_SELECTED" "$JS"
|
|
check "Desktop Tauri lanes" "$RUST_SELECTED" "$TAURI"
|
|
check "Desktop Smoke E2E shards" "$FRONTEND_SELECTED" "$SMOKE"
|
|
check "Desktop Windows Build" "$FRONTEND_SELECTED" "$WINDOWS"
|
|
[ "$status" = 0 ] && echo "Desktop jobs passed"
|
|
exit "$status"
|
|
|
|
desktop-windows-build:
|
|
name: Desktop Windows Build
|
|
runs-on: windows-latest
|
|
timeout-minutes: 20
|
|
# Keep in sync with FRONTEND_SELECTED in the Desktop gate (pinned by ci-required-gates.test.mjs).
|
|
if: github.event_name == 'push' || inputs.desktop
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 24.14.1
|
|
package-manager-cache: false
|
|
- uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
|
|
with:
|
|
version: 11.4.0
|
|
- name: Install desktop dependencies
|
|
shell: bash
|
|
run: pnpm install --frozen-lockfile
|
|
- name: Build both protected-feature selections
|
|
shell: pwsh
|
|
run: |
|
|
Remove-Item Env:VITE_BUZZ_BESTIE -ErrorAction SilentlyContinue
|
|
pnpm -C desktop build
|
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
$env:VITE_BUZZ_BESTIE = "1"
|
|
pnpm -C desktop build
|
|
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
|
|
results:
|
|
name: Results
|
|
if: ${{ always() }}
|
|
needs: [desktop]
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
permissions: {}
|
|
outputs:
|
|
desktop_result: ${{ needs.desktop.result }}
|
|
steps:
|
|
- run: echo "Captured Desktop job results"
|