Agent Skills › pluk-inc/markdown-preview › release-process

release-process

GitHub

管理 Markdown Preview 发布流程,包括版本递增、PR 创建、标签打制及回滚。涵盖 Amore 分发配置(代码签名、公证)及 What's New 窗口更新。

.agents/skills/release-process/SKILL.md pluk-inc/markdown-preview

Trigger Scenarios

创建发布 PR 发布或标记版本 回滚或取消发布 查询 Amore 分发配置

Install

npx skills add pluk-inc/markdown-preview --skill release-process -g -y
More Options

Non-standard path

npx skills add https://github.com/pluk-inc/markdown-preview/tree/main/.agents/skills/release-process -g -y

Use without installing

npx skills use pluk-inc/markdown-preview@release-process

指定 Agent (Claude Code)

npx skills add pluk-inc/markdown-preview --skill release-process -a claude-code -g -y

安装 repo 全部 skill

npx skills add pluk-inc/markdown-preview --all -g -y

预览 repo 内 skill

npx skills add pluk-inc/markdown-preview --list

SKILL.md

Frontmatter
{
    "name": "release-process",
    "description": "Prepare complete release PRs, publish, tag, and roll back Markdown Preview releases — branch\/PR naming, exactly what scripts\/release.sh and scripts\/rollback-release.sh do (including that release.sh publishes live), and the already-wired Amore distribution config (codesign identity, notary profile, EdDSA key). Use when the user asks to create a release PR, release, ship, cut a version, bump the version, tag a release, roll back or unpublish a release, or asks about this project's Amore-specific config (codesign identity, notary keychain profile, EdDSA key, custom domain)."
}

Release pipeline

Branch and PR naming

Every release goes through a dedicated branch and PR — never push the version bump or changelog directly to main.

  • Branch name: release/X.Y.Z — exactly the marketing version, no v prefix, no build number, no suffix. Examples: release/0.0.10, release/1.2.0. Beta cuts use release/X.Y.Z-betaN (e.g. release/0.1.0-beta1).
  • PR title: Release X.Y.Z (N) where N is CURRENT_PROJECT_VERSION. Example: Release 0.0.10 (14). This matches the commit message scripts/release.sh writes for the version-bump commit, so the PR, the bump commit, and the eventual git tag all line up. For betas: Release X.Y.Z-betaN (build).
  • PR body: short Summary (version bump + changelog added), a "What's in X.Y.Z" section that mirrors the changelog bullets, and a Test plan.
  • One PR per release. The branch contains only the bump (Version.xcconfig, edited directly during PR preparation), the new CHANGELOG.md entry, and — only when the user confirms an announcement — the What's New window update (see below). Keep unrelated changes out so the release diff stays auditable.

Create a release PR (prepare only)

A request to "create a release PR" includes both version fields and the changelog. It authorizes editing Version.xcconfig directly; do not defer the bump to publication or open a changelog-only release PR.

  1. Fetch latest origin/main and tags, and inspect existing release PRs before selecting the next version. Reuse an existing open release PR when appropriate. Start a new release branch from latest main; use an isolated worktree if the current checkout has unrelated work.
  2. Use the requested version, or the next patch version in this project's existing release series when unspecified. Increment CURRENT_PROJECT_VERSION by one from the latest release metadata. Check open release PRs to avoid duplicating a version already being prepared.
  3. Update both MARKETING_VERSION and CURRENT_PROJECT_VERSION in Version.xcconfig, and add the matching CHANGELOG.md entry using changelog-maintenance, including contributor credits. Then review the new changelog entry for What's New candidates and ask the user before announcing any (see What's New window below). Without a confirmed pick, leave the window files untouched.
  4. Verify that the PR's complete diff includes the intended version/build values and matching changelog heading; the title must agree with those values. Check git diff --check, unchanged historical notes, and that only these two release metadata files changed — plus the What's New files when the user confirmed an announcement, in which case build the app, run the policy tests, and look at the window as described below. Do not claim app tests were run for metadata-only validation.
  5. Commit, push, and open a ready, non-draft PR titled Release X.Y.Z (N). A release PR is incomplete if the version bump is missing, unless the user explicitly requested changelog-only work.

Do not run scripts/release.sh, including --draft, just to prepare the PR. Building, notarizing, uploading, tagging, and publishing are separate release execution steps; a release PR request alone does not request them.

What's New window

Updated readers see a What's New window once, over their first document window after the update (Help › What's New in Markdown Preview reopens it). It lives in md-preview/Features/WhatsNew/:

  • WhatsNewPolicy.swift — featuresVersion and featuresBuild name the release that introduced the listed features. A reader whose last recorded build is older than featuresBuild sees the window; fresh installs never do. The window title (What's New in Markdown Preview <featuresVersion>) and the Release Notes button (https://github.com/pluk-inc/markdown-preview/releases/tag/v<featuresVersion>) both follow featuresVersion.
  • WhatsNewWindow.swift — WhatsNewFeature.current is the list of features shown.

Always ask before announcing. While preparing a release PR, read the new CHANGELOG.md entry and pick the user-visible features worth announcing. Present them to the user as a proposal — title, description, SF Symbol, and any macOS version limit for each — and wait for explicit confirmation of which ones to use and their wording. Never add, drop, or reword an announcement without that confirmation. If the user picks none, leave WhatsNewPolicy.swift and WhatsNewWindow.swift untouched: the window then does not appear for this release, and readers who already saw the current announcement are not shown it again.

Choosing candidates:

  • Announce what is new to readers of the previous release: new features and visible redesigns. Skip fixes, internal work, and anything that already existed (e.g. announce "wrap code blocks", not "copy code" when copy predates the release).
  • Three to five features. Order them by how much a reader will notice them.
  • A feature that only works on some systems is gated with if #available(macOS NN, *) so readers on older systems do not see it, and its description says so ("On macOS 26 and later, …").

Wording format (match the existing entries):

  • Title: sentence case, about two to five words, no trailing period — e.g. "Find any document fast", "Redesigned formatting bar", "Faster document opening".
  • Description: one short sentence, or two very short ones, about 20 words at most. Say what the reader can do or will notice; name a shortcut when it is the way in (e.g. "Press ⇧⌘O and type part of a file name to open it from the current project.").
  • Symbol: an SF Symbol that exists on macOS 15 (the window also runs there), drawn in the accent tint.

Once the user confirms:

  1. In WhatsNewPolicy.swift, set featuresVersion to the new MARKETING_VERSION and featuresBuild to the new CURRENT_PROJECT_VERSION. They must match Version.xcconfig in the same PR, or the title and release link name the wrong version and readers of the previous release may not see the window.
  2. Replace the entries in WhatsNewFeature.current with the confirmed features.
  3. Add every new title and description to both md-preview/en.lproj/Localizable.strings and md-preview/zh-Hans.lproj/Localizable.strings under /* What's New */, and remove strings that no entry uses any more (keep keys other UI still uses, such as "Search for Document"). Run plutil -lint on both files.
  4. Build the app and run swift test --package-path tests/swift-tests --filter WhatsNewPolicyTests.
  5. Check the window in the Debug build as an updating reader: run defaults delete doc.md-preview.dev MarkdownPreview.whatsNewLastBuild and defaults write doc.md-preview.dev MainSplitView.didSeedInitialState -bool true (a fresh Debug profile otherwise counts as a new install, which never sees the window), launch the built app with a document, and confirm the window lists the confirmed features. Before the release is published, the Release Notes link returns 404; that is expected.

How scripts/release.sh actually works

Read this before running it — the script ships the update, it doesn't just prepare a PR.

Preflight (checked in this order, before anything is changed):

  • the working tree must be clean — commit everything, including the CHANGELOG.md entry, before running the script;
  • a ## [X.Y.Z] entry must already exist in CHANGELOG.md for the version being released (the script only validates and extracts it — it never writes the entry itself; that's the changelog-maintenance skill's job, see below);
  • amore must be logged in (amore whoami);
  • unless --skip-github or --draft, the gh CLI must be installed and authenticated, and an origin remote must exist — if there's no origin, the script falls back to --skip-github on its own with a warning.

jq (used to parse amore's JSON output) is checked later, right before the amore release call — after Version.xcconfig may already have been bumped and committed. If jq is missing when a version bump was needed, you're left with a local "Release X.Y.Z (N)" commit and no actual release; re-running the script once jq is installed is safe, since Version.xcconfig already matches and the sync step becomes a no-op.

What it does, once preflight passes:

  1. Resolves the version and build number (see the flag reference below).
  2. If Version.xcconfig doesn't already match the resolved version/build, updates it and commits directly on whatever branch is currently checked out, as Release X.Y.Z (N).
  3. Extracts that version's release notes from CHANGELOG.md.
  4. Runs amore release — archives, signs, builds the DMG, notarizes, uploads, and — unless --draft was passed — publishes the update to Amore's live appcast (check the current SUFeedURL and Amore configuration as described in AGENTS.md's Release references). This is the actual "ship it" step.
  5. Unless --skip-github or --draft: downloads the DMG, creates and pushes the vX.Y.Z tag, and creates the GitHub release (or, if a release for that tag already exists, uploads the DMG to it as an asset).

The script never pushes the branch itself and never opens or merges the PR. That remains a separate, manual step.

Publish a prepared release

When publication is requested, use the prepared release commit with a clean working tree and run ./scripts/release.sh. It reads the already-bumped version/build and matching changelog; the version sync becomes a no-op. If a version is supplied with --version and the file already matches, the script also retains the prepared build number.

Running the script before opening a PR publishes first unless --draft is passed. Follow the preparation workflow above when the request is for a review PR. If publication creates a tag before the release PR is merged, merge with a regular merge, not squash, to keep the tagged commit in main's ancestry.

Commands

./scripts/release.sh                            # release current Version.xcconfig
./scripts/release.sh --version 0.0.2            # bump marketing version (auto-bumps build)
./scripts/release.sh --version 0.0.2 --build 7  # bump marketing version, force build 7 instead of auto-bumping
./scripts/release.sh --build 7                  # keep current marketing version, force build 7
./scripts/release.sh --beta                     # amore --beta + GH prerelease (still publishes live)
./scripts/release.sh --draft                    # amore --draft, no GH release — the only mode that doesn't publish
./scripts/release.sh --skip-github              # local amore release only (still publishes live; skips tag + GH release)

Before running, add a CHANGELOG.md entry for the version being shipped and commit it — the script refuses to run on a dirty working tree. Always invoke the changelog-maintenance skill by reading its SKILL.md and following its instructions whenever the user asks you to write, generate, or update a changelog entry — do not draft freeform. The skill enforces the project's house format, the Keep-a-Changelog category split (Added / Changed / Fixed / Security), and contributor crediting (it always inspects git log and gh pr list for non-maintainer authors and adds a ### Contributors block with @username GitHub tags when any are found).

Entry shape:

## [0.0.2] – 2026-05-01
Short narrative summary.
- **Bullet for each change.**
- Bug fix bullet.

The en dash (–) between the version and the date matches the project's house style (used in the script's own help text and error messages) — follow it for consistency. The script's parser only checks that the line starts with ## [X.Y.Z]; the date and dash aren't validated, so this is a style convention, not something tooling enforces.

Source of truth: Version.xcconfig for the version numbers, CHANGELOG.md for the notes.

Rolling back a release

./scripts/rollback-release.sh --latest             # unpublish latest, delete GH release+tag
./scripts/rollback-release.sh 0.0.2                # unpublish specific version
./scripts/rollback-release.sh 0.0.2 --delete       # permanently delete on Amore
./scripts/rollback-release.sh 0.0.2 --keep-github  # leave GitHub release in place
./scripts/rollback-release.sh --latest --yes       # skip the confirmation prompt

Default is unpublish (reversible — flips published=false on Amore so it disappears from the appcast). Use --delete only when you're sure; it permanently removes the release. To re-publish after a non-destructive rollback: amore releases update <version> -b doc.md-preview --published true.

Amore configuration (already wired)

  • Hosting: Amore-managed; Info.plist currently uses https://release.md-preview.app/v1/apps/doc.md-preview/appcast.xml. Verify the current Amore hosting configuration before releasing.
  • Codesign identity: Developer ID Application: Mohamed Fauzaan (5P3TSMNV42)
  • Notary keychain profile: md-preview-notary
  • EdDSA public key (in Info.plist SUPublicEDKey): gIQjgqfjkIR+egQ4S1oBLxE/NCDxpXXGdZXSpn04VAY= — private key in login Keychain

To inspect or change: amore config show --bundle-id doc.md-preview / amore config set .... CLI lives at /usr/local/bin/amore.

Version History

  • ffff19f Current 2026-10-19 03:26

    新增对 What's New 窗口的支持,允许在确认后将更新内容纳入发布 PR。

  • 719f2dd 2026-09-22 08:53

    新增要求:准备发布PR时必须包含版本升级(Version.xcconfig),禁止仅提交Changelog而不更新版本号。

  • e1c5c15 2026-09-09 03:18

Same Skill Collection

.agents/skills/changelog-maintenance/SKILL.md
.agents/skills/resolve/SKILL.md
.agents/skills/swift-concurrency/SKILL.md
.agents/skills/amore-cli/SKILL.md

Metadata

Files
0
Version
ffff19f
Hash
737f1bb9
Indexed
2026-09-09 03:18

홈 - 위키
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-10-23 00:56
浙ICP备14020137号-1