From e316374508a8fe1bc6a39594c18f33ce3129fd31 Mon Sep 17 00:00:00 2001 From: Ali Al Dallal Date: Thu, 13 Aug 2026 17:19:29 -0400 Subject: [PATCH 1/2] fix: release notes block was invalid YAML + workflow-lint gate The v0.2.0 run failed with zero jobs: --notes' multi-line string put continuation lines at column 0 inside a run:| literal block, which terminates the scalar and breaks the document. Notes now build line-by-line (indented) into a notes-file. Gate added so the class is caught at commit time, not tag time: scripts/check-workflow-yaml.sh (parse every workflow; lefthook + CI, one script both callers) plus actionlint in CI's new workflow-lint job, wired into ci-gate. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FJ8wStsHyu7XPLTspNjMnQ --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ .github/workflows/release.yml | 19 +++++++++++++------ lefthook.yml | 3 +++ scripts/check-workflow-yaml.sh | 21 +++++++++++++++++++++ 4 files changed, 57 insertions(+), 6 deletions(-) create mode 100755 scripts/check-workflow-yaml.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 029f17df..08ecc032 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,6 +88,25 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - run: ./scripts/check-loc.sh + # Mirrors lefthook.yml's own workflow-yaml job -- same script, plus + # actionlint for semantic checks the parse can't see. Unconditional + # like file-loc-limit: GitHub only parses a workflow when its trigger + # fires, so a syntax error in a tag-triggered workflow otherwise + # merges through green CI and detonates at release time (v0.2.0's + # first run). + workflow-lint: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: ./scripts/check-workflow-yaml.sh + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 + with: + go-version: '1.25' + cache: false + - run: go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.7 + - run: actionlint + # Mirrors lefthook.yml's own comment-hygiene job -- same script # (.claude/rules/comments.md is the standard it enforces). Grep-only, # so like file-loc-limit it needs no build setup and no changes gate. @@ -421,6 +440,7 @@ jobs: needs: - changes - file-loc-limit + - workflow-lint - comment-hygiene - ui-copy - rules-frontmatter diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01448aef..0b926949 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -116,15 +116,22 @@ jobs: - name: Create GitHub release env: GH_TOKEN: ${{ github.token }} - # --notes text is prepended to the generated notes; the app is - # ad-hoc signed (no Apple Developer ID), so first launch needs - # the standard right-click -> Open confirmation. + # --notes-file text is prepended to the generated notes; the app + # is ad-hoc signed (no Apple Developer ID), so first launch + # needs the standard right-click -> Open confirmation. Notes are + # built line-by-line into a file: every line of a run:| block + # must stay indented (an unindented continuation terminates the + # literal scalar -- the v0.2.0 first-run failure), and backticks + # must stay escaped inside double quotes (command substitution). run: | + { + echo "## Install" + echo "" + echo "Download the \`.zip\`, unzip, and drag \`mill.app\` to Applications — no build needed. First launch: **right-click the app → Open → Open** (it is ad-hoc signed, not notarized — macOS asks once). Verify the download came from this repo's CI: \`gh attestation verify -R ${GITHUB_REPOSITORY}\`. Prefer building from source? \`git clone\` + the README's few commands work on any Mac." + } > /tmp/release-notes.md gh release create "${GITHUB_REF_NAME}" \ --repo "${GITHUB_REPOSITORY}" \ --title "${GITHUB_REF_NAME}" \ --generate-notes \ - --notes "## Install - -Download the \`.zip\`, unzip, and drag \`mill.app\` to Applications — no build needed. First launch: **right-click the app → Open → Open** (it is ad-hoc signed, not notarized — macOS asks once). Verify the download came from this repo's CI: \`gh attestation verify -R ${GITHUB_REPOSITORY}\`. Prefer building from source? \`git clone\` + the README's few commands work on any Mac." \ + --notes-file /tmp/release-notes.md \ dist/* diff --git a/lefthook.yml b/lefthook.yml index 4cb403ba..b5e81e4f 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -8,6 +8,9 @@ pre-commit: - name: file-loc-limit glob: "*.{go,ts,tsx}" run: ./scripts/check-loc.sh + - name: workflow-yaml + glob: ".github/workflows/*.yml" + run: ./scripts/check-workflow-yaml.sh - name: comment-hygiene glob: "*.{go,ts,tsx}" run: ./scripts/check-comment-hygiene.sh diff --git a/scripts/check-workflow-yaml.sh b/scripts/check-workflow-yaml.sh new file mode 100755 index 00000000..3918b92a --- /dev/null +++ b/scripts/check-workflow-yaml.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Every .github/workflows/*.yml must parse as YAML. GitHub only parses a +# workflow when its trigger fires, so a syntax error in a rarely-fired +# workflow (release.yml runs only on tags) can merge through green CI +# and fail at the worst moment -- exactly what happened to v0.2.0's +# first run: a run:| block's unindented continuation line terminated +# the literal scalar. Parse-only here (no new local tooling; python3 + +# PyYAML ship with macOS dev setups and ubuntu runners); CI's +# workflow-lint job additionally runs actionlint for semantic checks. +set -euo pipefail +cd "$(dirname "$0")/.." + +fail=0 +for f in .github/workflows/*.yml; do + if ! python3 -c "import yaml, sys; yaml.safe_load(open(sys.argv[1]))" "$f" 2>/tmp/workflow-yaml-err; then + echo "INVALID YAML: $f" + cat /tmp/workflow-yaml-err + fail=1 + fi +done +exit $fail From 270bb05759996c7d9813fab6805204b1c2960150 Mon Sep 17 00:00:00 2001 From: Ali Al Dallal Date: Thu, 13 Aug 2026 17:36:25 -0400 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20install=20Task=20via=20go=20install?= =?UTF-8?q?=20=E2=80=94=20the=20setup-task=20action=20wrapper=20is=20GPL-3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dependency-review deny-licenses flagged arduino/setup-task (the action is GPL-3.0; Task itself is MIT) once this PR touched release.yml's uses: lines. go install of the MIT tool, version-pinned, drops both the license hit and a third-party action. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FJ8wStsHyu7XPLTspNjMnQ --- .github/workflows/release.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0b926949..5ccbf50d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,9 +67,13 @@ jobs: node-version: '22' cache: 'npm' cache-dependency-path: frontend/package-lock.json - - uses: arduino/setup-task@c0bc642852239c2689f73f4ea6459c29405f3c52 # v3.0.0 - - name: Install wails3 CLI - run: go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-beta.6 + # Task installed via go install, not arduino/setup-task: the tool + # itself is MIT but that ACTION wrapper is GPL-3.0, which trips + # dependency-review's deny-licenses on any PR touching this file. + - name: Install Task and wails3 CLI + run: | + go install github.com/go-task/task/v3/cmd/task@v3.52.0 + go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-beta.6 # task build already chains: go mod tidy -> generate icons -> install # frontend deps -> generate bindings -> frontend build -> go build. # No GoReleaser (see ADR-0002 / wailsapp/wails#747, closed wont-fix) --