ci: run every workflow step under Nushell #491
Loading…
Reference in a new issue
No description provided.
Delete branch "chore/BUNYIP-489-nushell-workflow-shell"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
.forgejo/workflows/was half converted: three workflows setshell: nu {0}on most steps while 26run:steps still fell through to the runner's default shell. Mixed is the worst state to be in - a reader cannot tell which shell a step runs under without checking the preceding line, and any step added later silently inherits Bash.The shell is now declared once per job as
defaults.run.shell: nu {0}in all six workflows, and the redundant per-stepshell: nu {0}lines are gone from build-api.yml, build-web.yml and create-release.yml. e2e.yml and e2e-pr.yml keep theirworking-directory: e2edefault and gain the shell alongside it.Two steps carried Bash-only syntax and were rewritten rather than relabelled. check.yml "Cap build parallelism" drops POSIX arithmetic expansion and
>>for$"CARGO_BUILD_JOBS=((sys cpu | length) / 2 | into int)\n" | save --append $env.GITHUB_ENV, the same nproc/2 idiom the build workflows already use. check.yml "Docker builder stage" replaces2>/dev/null || truewith^docker image rm ... | complete | ignore, which captures the exit code and stderr instead of raising, so the first run (tag absent) stays green; the build moves onto one line because Nushell has no backslash continuation.--provenance=falseand the BUNYIP-231 / BUNYIP-241 comments are unchanged. e2e.yml's skip notice usesprintinstead ofecho.scripts/check-workflow-shell.nuis the gate: it parses every file under.forgejo/workflows/, and exits non-zero if a job is missing the Nushell shell default, if a step declares a non-nushell, or if a file parses to no jobs at all (which would otherwise pass vacuously). Its--self-testmode builds three fixtures - a job with no shell default, a step declaringshell: bash, and a converted job - and fails unless the gate rejects the first two and accepts the third, so a gate that stopped detecting anything fails the build. check.yml runs--self-testthen the real check, andjust check-workflow-shelldoes the same locally as part ofjust check.BUNYIP-490 merged to main while this PR was open and rewrote the
scripts/check-*.shguards in Nushell, so main is now merged in and the three conflicts it caused are resolved:just checkkeeps both new prerequisites (check-workflow-shellhere,check-key-env+check-no-bashfrom main), CLAUDE.md keeps both convention bullets, and the getting-started prerequisite names all three Nushell consumers (just recipes,scripts/, workflowrun:steps). The "the .sh guards keep their own shebang, rewrite tracked in BUNYIP-490" clause is dropped from CLAUDE.md and from thescripts/check-workflow-shell.nuheader, since that rewrite has shipped. main's two new check.yml steps invoke.nuguards as external programs and carry no Bash syntax, so the gate passes over the merged workflows unchanged.#BUNYIP-489
`.forgejo/workflows/` was half converted: three workflows set `shell: nu {0}` on most steps while 26 `run:` steps still fell through to the runner's default shell. Mixed is the worst state to be in - a reader cannot tell which shell a step runs under without checking the preceding line, and any step added later silently inherits Bash. The shell is now declared once per job as `defaults.run.shell: nu {0}` in all six workflows, and the redundant per-step `shell: nu {0}` lines are gone from build-api.yml, build-web.yml and create-release.yml. e2e.yml and e2e-pr.yml keep their `working-directory: e2e` default and gain the shell alongside it. Two steps carried Bash-only syntax and were rewritten rather than relabelled. check.yml "Cap build parallelism" drops POSIX arithmetic expansion and `>>` for `$"CARGO_BUILD_JOBS=((sys cpu | length) / 2 | into int)\n" | save --append $env.GITHUB_ENV`, the same nproc/2 idiom the build workflows already use. check.yml "Docker builder stage" replaces `2>/dev/null || true` with `^docker image rm ... | complete | ignore`, which captures the exit code and stderr instead of raising, so the first run (tag absent) stays green; the build moves onto one line because Nushell has no backslash continuation. `--provenance=false` and the BUNYIP-231 / BUNYIP-241 comments are unchanged. e2e.yml's skip notice uses `print` instead of `echo`. `scripts/check-workflow-shell.nu` is the gate: it parses every file under `.forgejo/workflows/`, and exits non-zero if a job is missing the Nushell shell default, if a step declares a non-`nu` shell, or if a file parses to no jobs at all (which would otherwise pass vacuously). Its `--self-test` mode builds three fixtures - a job with no shell default, a step declaring `shell: bash`, and a converted job - and fails unless the gate rejects the first two and accepts the third, so a gate that stopped detecting anything fails the build. check.yml runs `--self-test` then the real check, and `just check-workflow-shell` does the same locally as part of `just check`. The six `./scripts/check-*.sh` guards keep their own shebang, so the calling shell does not change their behaviour; rewriting them in Nushell is tracked in BUNYIP-490 and stays out of this PR. #BUNYIP-489BUNYIP-490 landed on main first and rewrote the `scripts/check-*.sh` guards in Nushell, so the three conflicts are all places this branch described those guards as still being Bash. `just check` keeps both new prerequisites (`check-workflow-shell` from this branch, `check-key-env` + `check-no-bash` from main), CLAUDE.md keeps both convention bullets with the "the .sh guards keep their own shebang, rewrite tracked in BUNYIP-490" clause dropped as spent, and the getting-started prerequisite names all three Nushell consumers (just recipes, `scripts/`, workflow `run:` steps). The same spent clause is dropped from the header comment of `scripts/check-workflow-shell.nu`. The gate still passes over the merged workflows: main's new check.yml steps ("Check the at-rest key stays single", "Check scripts/ stays Nushell") invoke `.nu` guards as external programs and carry no Bash syntax, and all six jobs keep their `defaults.run.shell: nu {0}`. #BUNYIP-489