From 557a9503367fae9edc7eedc5252fd0a89b4854a0 Mon Sep 17 00:00:00 2001 From: jyviko <2501648+jyviko@users.noreply.github.com> Date: Wed, 14 Oct 2026 09:43:47 -0400 Subject: [PATCH] ci: packaging lint for the workflows, packaging scripts and desktop metadata The release pipeline's scripts and metadata were exercised only by a full release run. A workflow of a few seconds, no Rust build, now checks them on every push to develop and pull request that touches .github/workflows or packaging, and on demand: actionlint (pinned, checksum-verified, with shellcheck on every run: script), shellcheck on the packaging scripts and AppRun, a parse and PSScriptAnalyzer pass (errors and warnings) over the Windows scripts, xmllint on the macOS property lists, desktop-file-validate on the desktop entry, and the entry's StartupWMClass against the app id the window sets. Adapted from SolidCraft's packaging-lint.yml (itself from PhotoCraft's). Closes #121 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01NmAttHhUZTokgPeEJia8sm --- .github/workflows/packaging-lint.yml | 79 ++++++++++++++++++++++++++++ ATTRIBUTION.md | 1 + 2 files changed, 80 insertions(+) create mode 100644 .github/workflows/packaging-lint.yml diff --git a/.github/workflows/packaging-lint.yml b/.github/workflows/packaging-lint.yml new file mode 100644 index 0000000..a8b781a --- /dev/null +++ b/.github/workflows/packaging-lint.yml @@ -0,0 +1,79 @@ +# Quick static checks for the release pipeline (seconds, no Rust build): workflow syntax, the +# packaging shell and PowerShell scripts, the macOS property lists and the Linux desktop entry. +# These files are otherwise exercised only by a full release run (release.yml). +# Adapted from SolidCraft's packaging-lint.yml, itself adapted from PhotoCraft's (see ATTRIBUTION.md). +name: Packaging lint + +on: + push: + branches: [develop] + paths: [".github/workflows/**", "packaging/**"] + pull_request: + paths: [".github/workflows/**", "packaging/**"] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: packaging-lint-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + name: Packaging lint + runs-on: ubuntu-24.04 + timeout-minutes: 10 + env: + ACTIONLINT_VERSION: 1.7.12 + ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 + PSSCRIPTANALYZER_VERSION: 1.24.0 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Install tools + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends shellcheck desktop-file-utils libxml2-utils + archive="$RUNNER_TEMP/actionlint.tar.gz" + curl -fsSL -o "$archive" \ + "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" + echo "$ACTIONLINT_SHA256 $archive" | sha256sum -c - + tar -xzf "$archive" -C "$RUNNER_TEMP" actionlint + - name: actionlint + # Also runs shellcheck on every `run:` script. + run: '"$RUNNER_TEMP/actionlint" -color' + - name: shellcheck + # packaging/.shellcheckrc lets the scripts' `source=../env.sh` directives resolve. + run: shellcheck packaging/*.sh packaging/*/*.sh packaging/linux/AppRun + - name: PowerShell + shell: pwsh + run: | + $failed = $false + foreach ($f in Get-ChildItem packaging/windows/*.ps1) { + $errors = $null + [System.Management.Automation.Language.Parser]::ParseFile($f.FullName, [ref]$null, [ref]$errors) | Out-Null + if ($errors) { + $errors | ForEach-Object { Write-Output "::error file=$($f.FullName),line=$($_.Extent.StartLineNumber)::$($_.Message)" } + $failed = $true + } else { + Write-Output "parsed $($f.Name)" + } + } + if ($failed) { exit 1 } + if (-not (Get-Module -ListAvailable PSScriptAnalyzer | Where-Object Version -eq $env:PSSCRIPTANALYZER_VERSION)) { + Install-Module PSScriptAnalyzer -RequiredVersion $env:PSSCRIPTANALYZER_VERSION -Scope CurrentUser -Force + } + Import-Module PSScriptAnalyzer -RequiredVersion $env:PSSCRIPTANALYZER_VERSION + $issues = Invoke-ScriptAnalyzer -Path packaging/windows -Recurse -Severity Error, Warning + $issues | ForEach-Object { Write-Output "::error file=$($_.ScriptPath),line=$($_.Line)::$($_.RuleName): $($_.Message)" } + if ($issues) { exit 1 } + - name: Property lists and desktop entry + run: | + app_id="$(sed -n 's/^APP_ID=//p' packaging/env.sh)" + test -n "$app_id" + xmllint --noout packaging/macos/*.plist* + desktop="packaging/linux/$app_id.desktop" + desktop-file-validate "$desktop" + # The window's X11 class / Wayland app_id is packaging's APP_ID (apps/fieldcraft/src/main.rs). + grep -qx "StartupWMClass=$app_id" "$desktop" + grep -qF "const APP_ID: &str = \"$app_id\";" apps/fieldcraft/src/main.rs diff --git a/ATTRIBUTION.md b/ATTRIBUTION.md index e6d5423..21eb6db 100644 --- a/ATTRIBUTION.md +++ b/ATTRIBUTION.md @@ -176,6 +176,7 @@ is committed and listed here with its exports. | packaging/macos/import-cert.sh | VectorCraft `packaging/macos/import-cert.sh` | MIT OR Apache-2.0 | | packaging/windows/check-exe.ps1 | SolidCraft `packaging/windows/check-icon.ps1` | MIT OR Apache-2.0 | | .github/workflows/release.yml, .github/release-notes.md, docs/releasing.md | SolidCraft `.github/workflows/release.yml`, `.github/release-notes.md`, `docs/releasing.md`; VectorCraft `.github/workflows/release.yml` | MIT OR Apache-2.0 | +| .github/workflows/packaging-lint.yml | SolidCraft `.github/workflows/packaging-lint.yml` (itself adapted from PhotoCraft, https://github.com/storytold/photocraft, Apache-2.0) | MIT OR Apache-2.0 | ## Test oracles