• 0.4.1 0003fa1d1c

    0.4.1
    All checks were successful
    CI / test (push) Successful in 1m29s
    CI / release-exercise (push) Has been skipped
    CI / self-guards (push) Successful in 6s
    CI / action-exercise (push) Successful in 5s
    CI / docs-sync-exercise (push) Successful in 5s
    release / release (push) Successful in 11s
    Stable

    andres released this 2026-08-04 16:09:39 +00:00 | 393 commits to main since this release

    Added

    • forge_release_exists, forge_commit_pulls, forge_tag_create,
      forge_release_create and forge_pr_create on both backends, so the
      release path names no client (#191).

    • The forgejo backend serves one PR object at /commits/{sha}/pull where
      GitHub serves an array at /pulls; both verbs emit the array shape, so
      the call site carries one expression (#191).

    • Forgejo creates tags at POST /tags — it serves /git/refs GET-only,
      so GitHub's ref-POST would have 404'd there forever (#191).

    • forgejo_api_base refuses when REPO is empty. Every verb interpolates
      it and every call reaches the network through there, so repos//…
      whose 404 reads as "no release" and "no PRs" — is now impossible (#191).

    • Release asset names are percent-encoded. The hook contract permits any
      filename, and the name travels as a query value: a space made curl reject
      the URL and &/#/+/% silently renamed the asset (#191).

    • lib/forge.sh — the forge selector: forge_detect names the forge from
      the runner's own environment, forge_client names the client it needs, and
      forge_preflight refuses loudly before any sweep when the two disagree
      (#188).

    • The reconcilers and labels-scope run that preflight first, so a
      GitHub-shaped client on a Forgejo instance is a named refusal instead of a
      sweep that reads nothing and reports success (#188).

    • lib/closes_references.sh — the closing-keyword parser, sibling of
      refs_references, so "which issues does this PR close" is answered from a
      PR body rather than from GitHub's GraphQL API (#188).

    • lib/forge-github.sh and lib/forge-forgejo.sh — one call surface, two
      backends, selected by forge_select; no forge branching at the call sites
      (#188).

    • The forgejo backend proves each paginated gather complete against the
      server's x-total-count and refuses loudly when it cannot — a missing
      header is a refusal, not a pass (#188).

    Changed

    • docs/CONSUMERS.md's artifact-hook recovery no longer tells operators to
      run gh release create by hand — on a Forgejo runner there is no gh.
      It names the forge-neutral tag-door path first, with both clients shown
      (#191).

    • issueflow-reconcile gathers open and merged PRs over REST instead of
      gh api graphql. Forgejo serves no GraphQL at all, so the two queries were
      replaced rather than translated; both forges return number and body
      from /pulls in the same shape (#188).

    • forge_api owns the page size, because each forge silently ignores the
      other's parameter: per_page=100 reads 30 items on Forgejo and limit=100
      reads 30 on GitHub, both HTTP 200. No call site names one (#188).

    • Outstanding review requests are derived from the reviews on the current head
      rather than from requested_reviewers, which Forgejo never clears — read
      raw there, a PR would sit at state:bots-reviewing forever (#188).

    Fixed

    • The release doors run on a Forgejo consumer. lib/facts.sh and
      release.yml gathered and published through gh, which the runner image
      does not ship, so the merge door read labeled=no for a correctly
      labeled ceremony PR and the tag door died at the publish (#191).

    • A release fact that could not be read is no longer reported as a definite
      no. A completed read finding no label is still no and still
      fail-closed; a read that did not complete refuses and emits no fact
      (#191).

    • labels-scope no longer fails to compile its jq program on jq 1.6, which
      the Forgejo runner image ships: label is a reserved word in jq's grammar,
      so $label is a syntax error there and every scope derivation died before
      reading the config (#188).

    • labels-reconcile and labels-scope no longer exit 0 on a Forgejo
      consumer having read zero facts — measured on heavy-duty/rig, where the
      sweep printed reconciled. over an empty PR list and scope reported "no
      labeler.yml" for a file that exists (#188).

    • forge_timeline projects Forgejo's label events (.type / .body /
      .user.login) into the GitHub shape (.event / .actor.login) so the
      ruling ladder reads the same board on both forges (#188).

    • forge_pr_activity no longer calls /pulls/{n}/comments on Forgejo
      (HTTP 404); inline review comments come from reviews with
      comments_count > 0 (#188).

    • CI installs shellcheck before linting, matching actionlint — the Forgejo
      runner image does not ship it (#188).

    Downloads