Repository navigation
oakum 0.3.1
Changed
The workflow init and migrate print identifies the version pull request by head repository and author, not by branch name alone. github.head_ref carries no owner, so in a public repository any fork could name its head branch oakum/version-packages and skip oakum check --strict; a collaborator could do the same from a branch in the repository itself, and so could anyone pushing to the bot's branch, since that raises a synchronize whose pull-request author is still the bot. All four terms hold for any repository, so nothing has to be filled in: they test the head repository and the type of the pull request's author and of the event's sender, never a named account. The skip reaches the genuine version pull request only once its author is a bot whose push retriggers CI — under secrets.GITHUB_TOKEN that pull request raises no workflow run at all, so there is nothing to skip, and the comment above the step now says so rather than warning about a hole that is not one.
oakum ci version-pr says who the token opened the pull request as, on stderr — stdout stays the one URL a caller captures. A run under a personal access token opens it as a person, which the scaffolded skip does not excuse, so every check runs on the version pull request and the only other symptom is a longer bill. The identity is reported where it was measured rather than left to be inferred from a workflow that did or did not fire. It is reported, not read as a verdict: a person settles the question, because that term alone defeats the skip, while a bot does not, since the skip also tests the sender of the event the push raises and no run can see that from here. A response that omits the author, or omits its type, says so instead of defaulting into a verdict.
The workflow init and migrate print surfaces a pr-status run that could not post its report. That step carries continue-on-error, so a GitHub outage does not fail a contributor's check; the same setting also let a report that never posted pass for one that did, and left a green check over a log nobody opens. A step now follows it that, when the step failed, emits a warning into the run summary and names the check above as what still decides. It runs whether or not the check itself passed, since a failed check is exactly when the report matters. A post that fell back to the job summary, the designed path for a fork with no token that can comment, is not a failure and does not warn. oakum's own workflow gains the same step.
Fixed
oakum check prints its refusals as blocks, the deciding line first. Each refusal's summary comes first with its detail indented beneath it, and every refusal that did not decide the exit code follows as also … in the same shape, so a reader meets the verdict before what is subordinate to it, and evidence sits under the line it supports; two looks that fail identically say it once, keeping what each found. Before, each look printed its detail as it ran and its summary at the end, so the management guidance could sit five lines from its summary with three unrelated lines between, and also lines printed before the line they were also-to. tag-drift prints the same block for the same state, and with a stale install pin beside real drift it now exits 1 for the drift and names the pin as also, as check does.
Among refusals of one class, the order check announces decides which one carries the exit code, and the install pin is its own look after the tags. With git wholly unusable, the first line a reader meets says git could not run, not install pin is 9.9.9. Before, the pin was verified inside the tag look and before git was touched, so a stale pin decided for a repository whose git did not work. A base ref git cannot resolve is quoted on the scope line by its first line only; the coverage look still carries the whole failure.
No command loses its output to a panic when the reader has gone away. println! and eprintln! abort on a refused write, so oakum version | head -1 exited 101 — neither ok, unverified, nor error under ADR-0034 — with its files already written and no account of them, and every other command shared the hazard. 0.3.0 said both channels went through a write that reports failure rather than panicking; that was true of check alone.
Every command now prints through writers that do not abort, and they differ by what the line is. A report — a check: scope line, a pending: plan, a migration step — survives a refusal in silence, because a reader who went away chose not to read. A result is the command's return value: the path add wrote, the URL release or ci version-pr opened, the plan status prints and the JSON status --json and plan-intent produce, the body generate --dry-run composes, the listings reachable-tags and detect-release-tools are, the summary version or upgrade gives of what it changed, the created records and the workflow init and migrate hand over, and the plan ci pr-status falls back to stdout when it has neither a token nor a job summary. A result nobody received is a run that did not answer. It exits 2, unverified under ADR-0034: the work landed and the answer did not, the same shape as a migrate that applied every file and could not verify them. Stderr says what already happened, so a caller that captured an empty stdout under set -o pipefail is told rather than left to notice. A descriptor the caller closed outright (>&-) is not a reader who went away: the standard library reports that write as delivered, and the run exits 0.
init and migrate finish every write before reporting a refused record, so a reader that went away does not leave .changeset half-written, and the verdict names each line that never arrived, even when a plan-comparison finding outranks it for the exit code; a write that fails after such a refusal, a gate look that fails beside it, or a comparison that could not run is named in the same verdict. An interactive prompt propagates the refusal because a question that cannot be shown cannot be answered. A release stopped by such a refusal keeps that class through its partial-failure report rather than reading as an error, and that report lists a tag whose GitHub release exists as released and not as remaining. A test fails the build naming any command module that reaches for the macros again.
oakum ci pr-status identifies the version pull request by the same four facts the scaffolded workflow tests — head branch, head repository, and the type of both the author and the sender — where it read the branch name alone. A fork or a collaborator naming a branch oakum/version-packages was treated as the version pull request, which suppressed the coverage comment on their own change. The cost of the other mistake is a redundant comment on the real version pull request, so an event that cannot be read counts as not the version pull request.
oakum ci pr-status reads .changeset/_config.toml once per run. It read it twice, once to choose the channel and once more inside the state builder to compose the plan, so a config edited between the two reads could choose a channel with one config and build the plan with another. status, ci pr-status, and version share one plan pipeline; version carried its own copy of it.
A release assembled from a bump file that declares more than one section renders each under its own heading. A note's first line was the only one read for a section name, so a file carrying ### Added and ### Changed was filed under the first and printed the second inside that block; 0.3.0's own changelog repeats ### Changed and ### Fixed for that reason. A known heading now starts a section wherever it appears, at up to three columns of indentation — the rule CommonMark applies and the one oakum's fence reader already used — while a fourth column is code, an unknown heading such as ### Notes stays body text, and a heading inside a fenced block stays content. A heading with nothing but whitespace under it renders no section rather than a heading over two spaces. A template iterating changes or notes sees the same correction: a bump file's second section is its own entry, sharing that file's commit, pull request and author, rather than a stray heading buried inside the first entry's body. The rows a template rendered before were the bug, not a contract it can keep. MD024 stays disabled repo-wide, because specs and decision records repeat headings by design; the rendered changelog asserts the rule itself instead.
A version run that fails partway names every file it left changed, as a list. Rollback appended ; restoring X also failed (...) to the cause once per file, which buried the last entry of a chain, and the one run where the tree is left half-written was the one that said least about it. The failure now prints the cause, a count, and one path per line. Two states that were silent are now named as files left changed: a staging file the run created and could not remove, and a file the run created and could not remove after the write itself failed. A directory the sweep could not read is named too, on its own line and under its own heading, because it is no evidence of a changed file — the fault that strands a file is the kind that also blocks the listing, so silence would hide a leak exactly when there is one, while counting it as damage sends a reader hunting for a half-written tree that may be intact. A staging file is attributed to this run by a delimited process id rather than a substring match, so a concurrent run's file is not named as this failure's; the wording holds either way. An empty list is documented for what the code checks — every restore reported success and every swept directory could be read — and no longer claims a byte-identical tree, which rollback does not verify because it writes the planned original back without re-reading it.
version writes a file it planned to create with an empty body, where the unchanged-text skip dropped the write and reported success over a file that never appeared. No caller produces one today.
version no longer loses its summary to a panic when the reader has gone away. println! aborts on a refused write, so oakum version | head -1 exited 101 with the manifests, changelogs and bump files already written and no account of any of it — on the one command that performs the irreversible part of a release. The summary now goes through the same write that check was given in 0.3.0, which reports a refusal rather than panicking. Other commands still print directly, which is tracked separately.
Install oakum 0.3.1
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/oakoss/oakum/releases/download/v0.3.1/oakum-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/oakoss/oakum/releases/download/v0.3.1/oakum-installer.ps1 | iex"Install prebuilt binaries via Homebrew
brew install oakoss/tap/oakumInstall prebuilt binaries into your npm project
npm install @oakoss/oakum@0.3.1Download oakum 0.3.1
| File | Platform | Checksum |
|---|---|---|
| oakum-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| oakum-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| oakum-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| oakum-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| oakum-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| oakum-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |
Verifying GitHub Artifact Attestations
The artifacts in this release have attestations generated with GitHub Artifact Attestations. These can be verified by using the GitHub CLI:
gh attestation verify <file-path of downloaded artifact> --repo oakoss/oakumYou can also download the attestation from GitHub and verify against that directly:
gh attestation verify <file-path of downloaded artifact> --bundle <file-path of downloaded attestation>