Skip to content

chore(release): adopt shared forensic release pipeline - #181

Merged
chhoumann merged 2 commits into
masterfrom
chore/shared-release-pipeline
Jul 11, 2026
Merged

chore(release): adopt shared forensic release pipeline#181
chhoumann merged 2 commits into
masterfrom
chore/shared-release-pipeline

Conversation

@chhoumann

Copy link
Copy Markdown
Owner

What and why

Migrates MetaEdit onto the shared forensic PR-to-release pipeline in
chhoumann/obsidian-plugin-workflows.
MetaEdit had no machine-PR release pipeline: it released via a manual
workflow_dispatch semantic-release job. This replaces that whole model with the
same standing-release-PR flow the other plugins now share, so a fix lands once in
the shared repo and MetaEdit picks it up by bumping a pin.

Christian's decision this encodes:

  • PR-to-release is the standard. After every green push to master, the
    per-repo App bot opens or refreshes exactly one standing release PR containing
    only the synchronized version files and generated notes. Merging that PR is
    the sole release act.
    No auto-release, no manual dispatch on the happy path.
  • Full forensics. Everything after "maintainer clicks merge" is treated as
    adversarial until proven otherwise.
  • Per-repo App bots. The release commit and PR are authored by a per-repo
    GitHub App bot the maintainer provisions and controls, replacing the ambient
    github-actions[bot].

The old workflow_dispatch release.yml, version-bump.mjs, the package.json
semantic-release config block, and the version / semantic-release scripts are
removed; the semantic-release dependency tree is pruned. In their place are
three thin caller stubs (trigger + uses:) with all logic in the shared
reusables pinned at @v2 (workflows-ref: v2).

What MetaEdit gains

MetaEdit had no machine-PR release pipeline, so there is no parity table to
preserve - it gains the full guarantee set. Rather than re-tabulate it, see the
shared repo's Security model - what each forensic check defends
against
:
standing-PR provenance, exact version-file diff, commit-message contract + parent,
squash-parent + tree-sha equality, prior-tag ancestry and history, a durable
release-run/<version> recovery branch, and attestation + post-publish asset
re-hash.

Config specifics

  • plugin-name: metaedit, package-manager: pnpm, node-version: "24" (matches
    CI), default-branch: master, release-bot-app-slug: metaedit-release-bot.
  • release-assets: '["main.js","manifest.json","styles.css"]';
    verify-commands is pnpm run lint / pnpm run typecheck / pnpm run test.
  • The prepare stub's workflow_run watches workflows: ["CI"], matching this
    repo's ci.yml name:.
  • Two pins move together: the uses: ...@v2 ref and the workflows-ref: v2
    input; release-trigger.yml has no workflows-ref (pure API forensics, no
    toolkit checkout).
  • Added the repository field to package.json - the shared planner requires it
    to build the release-notes compare/commit/issue URLs (verified in the dry-run
    below). Kept the commitizen/cz config, which drives commit style, not
    releases.

Precondition check (tagged baseline)

The shared planner requires the current package.json version to be tagged with a
published GitHub release, bare tag format (no v prefix). Satisfied:
package.json version 1.10.1 = git tag 1.10.1 = published GitHub release
1.10.1. No pre-first-release action item.

Dry-run plan evidence

Ran the shared repo's release-plan.mjs against this repo's real git history
(node scripts/release-plan.mjs --cwd <metaedit> --package-manager pnpm). Current
master HEAD (0c28dc2), six conventional commits since the 1.10.1 tag,
correctly plans the next release and resolves the newly-added repository field
for its notes URLs:

{
  "baseSha": "0c28dc27e2b841f771cfec9d1acd619a11664f33",
  "previousVersion": "1.10.1",
  "nextVersion": "1.10.2",
  "releaseType": "patch",
  "release": true,
  "notes": "## [1.10.2](https://github.com/chhoumann/MetaEdit/compare/1.10.1...1.10.2) (2026-07-11)\n\n### Bug Fixes\n* **e2e:** call local obsidian-e2e bin directly in Orca archive hook (#178) (556efe7)\n",
  "schemaVersion": 1
}

The previousVersion: 1.10.1 anchor confirms the planner reads the tagged
baseline; release: true -> 1.10.2 is the release the first merged standing PR
would cut.

Gates (all green locally)

pnpm run lint, pnpm run typecheck, pnpm run test (355 tests / 19 files),
pnpm run build. All three caller stubs pass actionlint and PyYAML parse.

REQUIRED BEFORE MERGE - GitHub App setup

The pipeline fails closed without a per-repo release-bot App. Before the next
release, provision it (steps in the shared repo README, "Per-repo GitHub App
setup"):

  1. Create a GitHub App named e.g. MetaEdit Release Bot with slug
    metaedit-release-bot (must match release-bot-app-slug). Repository
    permissions: Contents R/W, Pull requests R/W. No account perms, no webhook.
  2. Generate a private key; install the App on this repo only.
  3. Add repo variable RELEASE_APP_ID (numeric App id) and secret
    RELEASE_APP_PRIVATE_KEY (the full .pem).
  4. If master is protected, add the App as an allowed bypass/merge actor per the
    ruleset (the maintainer still merges; the App only authors).

CI is unaffected meanwhile (Test, Build + Lint, CodeQL, etc. keep running).
This PR deletes the old release flow, so releases are blocked between merge and
App setup
- nothing else breaks. After setup, smoke-test via Actions -> Prepare
release -> Run workflow with the dry-run: true line uncommented before the first
real release.

Replace MetaEdit's semantic-release flow with the shared forensic
PR-to-release pipeline in chhoumann/obsidian-plugin-workflows, consumed
via three thin caller stubs pinned at @v2 (workflows-ref: v2).

- Add the release-prepare, release-trigger, and release caller stubs
  (plugin-name metaedit, package-manager pnpm, node 24, default-branch
  master, release-bot-app-slug metaedit-release-bot, assets main.js +
  manifest.json + styles.css).
- Remove the old workflow_dispatch semantic-release release.yml,
  version-bump.mjs, the package.json semantic-release config block, the
  version + semantic-release scripts, and the semantic-release devDeps.
- Add the repository field the shared planner requires to build release
  notes; keep the commitizen/cz config (drives commit style, not releases).
- Update AGENTS.md release docs to the PR-to-release model.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2779f790ea

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/release-prepare.yml
The shared release pipeline opens its standing PR titled
`release(version): Release <version>`. The PR-title check's allowed
Conventional Commit types did not include `release`, so every generated
release PR would fail the check. Add `release` to the allowed types.

Flagged by the Codex review bot on #181.
@chhoumann
chhoumann merged commit e02e082 into master Jul 11, 2026
8 checks passed
@chhoumann
chhoumann deleted the chore/shared-release-pipeline branch July 11, 2026 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant