Repository navigation
build: adopt Hephaestus and modernize development workflows - #1
Merged
Merged
Conversation
Release git-parallel with Hephaestus v1.1.0 as one noarch archive
(git-parallel, git-parallel.1, README.md), a checksum file, provenance
attestations and a Homebrew tap pull request for a new git-parallel
formula. Add CI (ShellCheck, actionlint, Renovate validation, behavior
tests on bash 3.2 and bash 5 on Linux and macOS, Hephaestus snapshot,
Homebrew E2E), a tag-triggered release workflow split into read-only
build and environment-gated publish jobs, Renovate, Makefile targets and
release documentation. Existing install/uninstall targets are unchanged.
Fix git-parallel bugs found by the new tests:
- run on the bash 3.2 that ships with macOS (named file descriptors,
`exec {FD}<`, need bash 4.1; job output now goes to temporary files)
- handle repository paths containing spaces
- accept --targets as documented in the help (--target still works)
- reject --jobs 0, which looped forever
- stop child processes on HUP/INT/QUIT/TERM on macOS too (pgrep -P
instead of GNU-only `ps --ppid`) and remove temporary files
- drop the perl dependency from repository discovery
Claude-Session: https://claude.ai/code/session_01RbGbwRHvCEhsKLZfbvbbRg
Pins the Hephaestus action and CLI to 4414722 (magicdrive/hephaestus#22, pseudo-version v1.1.1-0.20261025105032-4414722a804d): the action no longer puts its own Go on PATH or exports GOTOOLCHAIN=local, and redaction no longer hides paths under PWD. This commit only verifies the fix in this repository's CI; it is reverted by the next commit, which returns to the released v1.1.0. Pin v1.1.1 once it is released. Claude-Session: https://claude.ai/code/session_01RbGbwRHvCEhsKLZfbvbbRg
This reverts commit c83547e. Its CI run verified the Hephaestus action and CLI of magicdrive/hephaestus#22 in this repository; the pull request goes back to the released v1.1.0, so that it never asks to merge an unreleased pin. Pin v1.1.1 (its tag's commit) once it is released. Claude-Session: https://claude.ai/code/session_01RbGbwRHvCEhsKLZfbvbbRg
Owner
Author
|
Hephaestus v1.1.1 fix verified in this repository (not yet released) magicdrive/hephaestus#22 stops the Action from putting its own Go 1.26.0 on
After v1.1.1 is released, update the pin to the commit of the v1.1.1 tag, together with |
Pin every magicdrive/hephaestus action to the v1.2.0-rc.1 tag commit (bae0e2b3cbf41ad27299e0cfc3517a6affc7e15e) and HEPHAESTUS_VERSION to v1.2.0-rc.1. From v1.2.0 the action downloads and verifies its release binary and sets up no Go: the release workflow and the hephaestus CI job need none, and the jobs that run Go tools (actionlint, go install for the Homebrew end-to-end test) keep their own setup-go. Follow the hephaestus publish conventions in release.yml: a plan step (id: plan, command: plan) and the tap token check, the read-only tap rehearsal and the tap pull request step run only when steps.plan.outputs.tap == 'publish', so a prerelease never receives the tap token. CI plans a release candidate and a stable release and checks that only the stable one publishes the tap. Add make publish / publish-check / publish-status / publish-watch / publish-help, wired as in Hephaestus's own Makefile: the version reaches the tool through HEPHAESTUS_PUBLISH_* environment variables, never a shell command line. publish and publish-check first run scripts/check-version.sh --from-make, so a tag whose version git-parallel does not report (and the release workflow would refuse) is never pushed. tests/publish-make.sh checks the wiring with a stub tool and runs in CI on GNU Make 4 (Linux) and 3.81 (macOS). Claude-Session: https://claude.ai/code/session_01RbGbwRHvCEhsKLZfbvbbRg
Moves the action and HEPHAESTUS_VERSION from the release candidate v1.2.0-rc.1 (bae0e2b, verified by this pull request's CI) to the stable v1.2.0: magicdrive/hephaestus@160990d, the commit the v1.2.0 tag points to. The release binary, its checksum and its attestation are verified by the action for that commit. Claude-Session: https://claude.ai/code/session_01RbGbwRHvCEhsKLZfbvbbRg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adopt Hephaestus v1.2.0-rc.1 for releases and add the CI, Renovate, Makefile targets and release docs this repository did not have. The new behavior tests found several existing bugs in
git-parallel; the small, safe fixes are included (each covered by a test). The fixes that would change behavior are only listed in Remaining Risks.Hephaestus v1.2.0-rc.1 and
make publishuses: magicdrive/hephaestus@...isbae0e2b3cbf41ad27299e0cfc3517a6affc7e15e # v1.2.0-rc.1(the RC's tag commit) andHEPHAESTUS_VERSION ?= v1.2.0-rc.1. The v1.1.0 pin (550d48f) is gone.PATH/GOTOOLCHAINalone. git-parallel builds nothing, so the release workflow and thehephaestusCI job need no Go. The jobs that run Go tools keep their ownsetup-go:lint(make actionlint) andhomebrew-e2e(go installof the hephaestus CLI).releasejob runs the action withcommand: plan(id: plan). The tap token check,Rehearse the formula and tap pull request (read-only)andGenerate the formula and open a tap pull requestrun onlyif: steps.plan.outputs.tap == 'publish', so a prerelease never receives the tap token. CI plansv0.0.0-rc.1andv0.0.0and requirestrue/skipandfalse/publish.make publish vX.Y.Z(new; alsoVERSION=vX.Y.Zandtag=vX.Y.Z,YES=1skips the prompt),make publish-check|publish-status|publish-watch vX.Y.Z,make publish-help. They call$(PUBLISH) <publish|check|status|watch|help> -from-makewithPUBLISH ?= $(HEPHAESTUS) publish; the version reaches the tool throughHEPHAESTUS_PUBLISH_ARGS/VERSION/TAG, never a shell command line (the Makefile section is the one in Hephaestusdocs/publish.md).make publishandmake publish-checkfirst runscripts/check-version.sh --from-make, which reads the same environment and requiresgit-parallel --versionto be exactly the tag. A tag that the release workflow'sbuildjob would refuse is never pushed.publish-checkreports both the version check and the preflight and fails if either fails; an invalid or missing version stops before the tool runs.check-version.shnow accepts only SemVer 2.0.0 tags with a leadingv(ashephaestus publishdoes) and exits 2 for usage errors.git tag+git pushby hand:make publishchecks, confirms, pushes one annotated tag, follows the release run and verifies the release (assets, attestations, notes, tap PR). There was no previouspublishtarget.version-check,preflightandrelease-checkare unchanged.tests/publish-make.sh(make test-publish, part ofmake check) drives the targets with a stub tool: one call with the right arguments and environment,-j4,make -n; no call for two versions, a malformed version, another target in the same command,publish-helpwith a version, shell metacharacters, or a version the script does not report. CI runs it in everytestjob (GNU Make 4 on Linux, 3.81 on macOS).Before / After
ci.yml: ShellCheck, actionlint, Renovate validation, behavior tests (bash 5 on Linux amd64/arm64 and macOS; bash 3.2 on macOS), Hephaestus check + snapshot, Homebrew E2E (Linux, macOS),ci-gatemake publish vX.Y.Zpushes the tag after its checks;release.ymlonv*tags: full CI → read-only build job →releaseenvironment job (plan, tap dry-run, attestation, GitHub Release, tap PR)git-parallelformula, opened as a PR onmagicdrive/homebrew-tapby the first releaserenovate.json(actions pinned by digest, Makefile tool pins throughcustomManagers)/bin/bash3.2exec: {FD}: not found, exit 127Hephaestus Integration
hephaestus.yaml: nobuilds. One noarch archive (targets: [{os: all, arch: all}]), namedgit-parallel_<version>_noarch.tar.gz, withgit-parallel(0755),git-parallel.1(0644) andREADME.md(0644) at its root. Checksum filegit-parallel_<version>_checksums.txt.release.github:magicdrive/git-parallel,generate_notes: true(there is no changelog).brews:git-parallel,ids: [script], tap root (nodirectory),pull_request.enabled: true,skip_upload: auto, the standardcommit_msg_template.install:bin.install "git-parallel",man1.install "git-parallel.1".test:--version(expects exit 1, see Remaining Risks),--listand-- statusin a new git repository.depends_on: the script now runs on the system bash 3.2 and on later versions, and git is a precondition of a git subcommand.preflight:workflow: release.yml,environment: release.archive,checksum(notbuild,archive,checksum): with no builds configured,hephaestus run --stages buildfails with "no builds are configured".git::parallel::version) and is not generated at release time.scripts/check-version.sh(in the releasebuildjob and inmake preflight) refuses a tag that does not equalgit-parallel --version.CI
.github/workflows/ci.yml(push: main,pull_request,workflow_dispatch,workflow_call;permissions: contents: read; per-ref concurrency that never cancels a run called fromrelease.yml;timeout-minuteson every job):lint:make lint(ShellCheck on all scripts),make actionlint,make renovate-check(--strict)testmatrix: ubuntu-latest bash 5, ubuntu-24.04-arm bash 5, macos-latest/bin/bash3.2, macos-latest Homebrew bash 5. The step checks the bash major version, so a missing bash cannot pass silently. Thenmake testand a--version/--helpsmoke test.testalso runsmake test-publish.hephaestus: the action'scheck, release plans for an RC and a stable version, then a snapshotarchive,checksumwithgithub-token: "". It verifies the archive listing, the modes, the checksum, and that the archived script matches the checkout.homebrew-e2e(ubuntu-latest, macos-latest):make homebrew-e2eci-gate: passes only if every job succeededRelease workflow
.github/workflows/release.ymlfollowsexamples/workflows/release-split-jobs.ymland Hephaestus' own release workflow:ci:uses: ./.github/workflows/ci.ymlon the tagged commitbuild:contents: read, no environment, no secrets. Runs the version check, then the action withstages: archive,checksum,fresh: "true",github-token: "". Verifiesdist/and uploads it.release:needs: [ci, build],environment: release,contents: write,id-token: write,attestations: write. Steps, in order:command: plan(id: plan).dist/.tap == 'publish'.Rehearse the formula and tap pull request (read-only); only whentap == 'publish'.attest-build-provenance(archive and checksum file).command: release.Generate the formula and open a tap pull requestwithgithub-token: ""and the tap token; only whentap == 'publish'.uses:is pinned to a full SHA.PERSONAL_GITHUB_TOKENis not used.Renovate
renovate.json(same baseline as Hephaestus):pinDigests: trueand no automerge. This includesmagicdrive/hephaestus@<sha> # v1.2.0-rc.1.renovate/hephaestus; from a stable pin it does not propose release candidates).customManagersentry tracks the Makefile pins:HEPHAESTUS_VERSION(go),ACTIONLINT_VERSION(go) andRENOVATE_VERSION(npm).renovate-config-validator --strictpasses locally and in CI.Makefile
all,install,uninstall,PREFIXandCURRENTDIRare unchanged, andmakealone still prints the same message.make install/uninstall PREFIX=<tmp>were checked locally. New targets:help,lint,test(TEST_BASH=...),checkactionlint,renovate-checkhephaestus-check,snapshotversion-check tag=,preflight tag=(version-check +hephaestus preflight --strict),release-check tag=homebrew-e2etest-publish;publish,publish-check,publish-status,publish-watch,publish-help(above).PHONYis declared for every target, and the targets work with GNU make 3.81.Release Compatibility
v1.0.2 (the latest release) has no assets and the tap has no
git-parallelformula, so nothing existing has to be matched and no current Homebrew user is affected.git-parallel_X.Y.Z_noarch.tar.gz,git-parallel_X.Y.Z_checksums.txtREADME.md,git-parallel(0755),git-parallel.1(0644), no top-level directory, reproducible (mtime 1980-01-01, uid/gid 0)sha256sum -cformatgit-parallel v1.0.2git-parallel(desc, homepage, MIT, oneurl,bin+man1, test)make installPREFIX=~/localHomebrew Verification
Run with
scripts/homebrew-e2e.shlocally inhomebrew/brew:latest(linux/amd64, Homebrew 4.6.20) and in CI on ubuntu-latest and macos-latest:archive,checksum,formulafor the script's version.urlis pointed at the local archive (file://, same file name and sha256).brew style,brew audit --strict,brew install,brew test.git-parallel --version,git parallel -V, a two-repository run and the man page are checked.brew uninstall.Nothing is written to
magicdrive/homebrew-tap.Security
permissions: contents: read. Write permissions only on thereleasejob.pull_request_target.persist-credentials: falseon every checkout.Tests
tests/run.sh: 20 test groups. The suite is bash 3.2 compatible and builds temporary trees of git repositories. It covers:--version/-V,--help/-h, unknown options and invalid values,--list,--maxdepth,-d/--target/--targets,--silent/--verbose/--color,--freeze.git),:::bare commands,git parallelas a git subcommand.--jobs(a barrier), more repositories than jobs,--jobs 0.Against the original script, the suite fails on:
--targets, and--jobs 0(hangs).Fixes in
git-parallelexec {FD}< <(...)needs bash 4.1, so every run failed on/bin/bash. Job output now goes to per-job temporary files, printed in the same order once the batch finishes (same output as before).perland keeps the same./and/.gitstripping.--targets, as the help and README spell it, was rejected as an unknown option. Both--targetsand--targetare accepted now.--jobs 0(or a non-numericGIT_PARALLEL_DEAULT_JOBS) looped forever. It is now rejected with exit 1.ps --ppidis GNU-only.pgrep -Pis used now, and the temporary files are removed.Remaining Risks
Kept for compatibility, documented by tests:
--version,--helpand--listexit 1.-- commit -m "a b").Changing any of these would break scripts that rely on the current behavior. They are better done as a separate, explicit change.
Other risks:
make publishrefuses to tag if it is not, and the releasebuildjob refuses such a tag.homebrew-e2edepends on the runners' Homebrew.LICENSEfile. The MIT text lives in the script and README, and the formula declareslicense "MIT".Release Migration Notes (owner, before the first release)
make publish-check v1.0.3on this branch fails these owner items (besides the ones that this unmerged branch and the unbumped version cause):environment: thereleaseenvironment's deployment policy allows only branchv*. A tag-push deployment will be rejected. Add a tag policyv*, and remove the branchv*policy: a branch named like a version could read the tap secret.main ruleset: add an active ruleset onmainthat requires the status checkci-gate.tag ruleset: add an active tag ruleset onrefs/tags/v*that forbids deletion and update (not creation).Then:
git::parallel::versionto the new version (e.g.v1.0.3) in a PR and merge it after CI.main:make publish-check vX.Y.Z, thenmake publish vX.Y.Z.git-parallel.rb).See
docs/development/releasing.md. Rollback: revert this PR (no existing release or formula depends on it).https://claude.ai/code/session_01RbGbwRHvCEhsKLZfbvbbRg