Receber por email
← Voltar para o catálogo

han-release

Cut a Han release: update CHANGELOG.md with the changes since the last release, bump every plugin that changed, tag the suite version vX.Y.Z, and publish a GitHub release whose notes attribute every merged pull request to its author, credit every closed issue to the person who opened it, the people who contributed to it, and the people who worked on the fix, and link back to the full changelog for

88estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add testdouble/han

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/han-release/svg)](https://www.skillteca.com.br/skills/han-release)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Pre-requisites

  • gh CLI: !which gh || echo MISSING
  • jq: !which jq || echo MISSING
  • git repo: !git rev-parse --is-inside-work-tree 2>/dev/null || echo NO

If gh or jq is MISSING, or this is not a git repo: tell the operator which prerequisite is missing and that it must be installed/configured before /han-release can run, then immediately stop. The skill cannot proceed without all three.

Project Context

  • repo: !gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null || git config --get remote.origin.url
  • current branch: !git branch --show-current
  • default branch: !git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##' || echo unknown
  • working tree: !git status --porcelain
  • parent plugin name: !jq -r .name .claude-plugin/marketplace.json 2>/dev/null
  • plugins (name source version): !jq -r '.plugins[] | "\(.name)\t\(.source)\t\(.version)"' .claude-plugin/marketplace.json 2>/dev/null
  • latest release tag: !git fetch --tags --quiet >/dev/null 2>&1; git tag -l 'v*..' --sort=-v:refname | head -n1
  • changelog head: !grep -m1 '^## v' CHANGELOG.md 2>/dev/null

Vocabulary used throughout this skill

  • parent — the meta-plugin whose name equals the marketplace name (parent plugin name above, normally han). It has no skills or agents of its own; it exists to install the children via dependencies. The git tag tracks the parent's version, so the release tag is v{parent target}.
  • children — every other entry in marketplace.json.plugins[] (han.core, han.github, han.reporting, and any future han.* plugin). Each child has its own version line, bumped independently of the others.
  • baseline of a plugin — its version at prev (the latest release tag). For the parent this is prev#. For a child it is the version recorded in that child's plugin.json at prev; if the child did not exist at prev, it is a new plugin (see Step 3).
  • current of a plugin — the version in its working-tree plugin.json.
  • target of a plugin — the version being released for it. The release tag is v{parent target}.
  • prev is the latest release tag (for example v2.7.0; the number without the leading v is prev#). On the first release prev is empty.
  • Each plugin's source directory comes from the source field in marketplace.json (for example ./han.core), so its plugin.json is {source}/.claude-plugin/plugin.json. Use {source} verbatim in every git command: the ./-prefixed form works both after a {ref}: colon (git show {prev}:{source}/...) and as a pathspec (git diff ... -- {source}/). Do not strip the leading ./.

Step 1: Parse the invocation and check release safety

  1. Parse $ARGUMENTS for two independent flags, then treat the remaining free text as optional release context that informs the changelog narrative:
  2. pause_before_publish — true if the argument contains "pause", "review", or "confirm before publish" (case-insensitive). Default false.
  3. draft_release — true if the argument contains "draft". Default false.
  4. The leftover text (anything that is not those flag phrases) is $release_context, passed into the narrative dispatch in Step 5. May be empty.
  1. Working tree must be clean. If working tree from Project Context is non-empty, there are uncommitted or untracked changes. Stop and tell the operator to commit or stash them first. Releasing an unknown working state is unsafe and a pushed tag is hard to reverse. This is a hard stop, not a pause gate.
  1. Branch note (non-blocking). If current branch is not the default branch, do not stop — note in the Step 7 summary that the release is being cut from current branch and the tag will point at that branch's HEAD. The operator chose autonomous; surface the fact, do not block.

Step 2: Determine previous version, commit range, and PR list

  1. prev is latest release tag. If it is empty, this is the first release: there is no previous tag, the commit range is the full history, all compare links are omitted, and every plugin is treated as new (Step 3).
  1. Commit range. With a previous tag: ${prev}..HEAD. First release: the full history (HEAD with no range base).
  1. Nothing to release check. Run git log {range} --oneline. If it is empty, there are no commits since prev. Stop and tell the operator there is nothing to release.
  1. Collect merged PRs in the range. Extract PR numbers from both squash subjects and merge commits:

`` git log {range} --pretty=%s%x00%b | grep -oE '#[0-9]+' | tr -d '#' | sort -un ``

For each number N, run gh pr view N --json number,title,author,url,mergedAt,state. Keep only entries where state is MERGED. Sort the survivors by mergedAt ascending (newest merge last). This is $pr_list. The PR list is repo-wide and appears once per release; it is not split per plugin. Build the PR lines and the changelog bullets per [references/release-notes-format.md](references/release-notes-format.md) and [references/changelog-rules.md](references/changelog-rules.md).

  1. No-PR fallback. If $pr_list is empty (local-only or squash history with no PR refs), record the notable commit subjects from git log {range} --oneline instead, and use the commits form documented in both reference files.
  1. Collect closed issues and their attribution. For each merged PR N in $pr_list, find the issues that PR closed and credit everyone involved. This relates each closed issue to the fix that resolved it.
  • Find the closed issues for the PR. Take the issue numbers from gh pr view N --json closingIssuesReferences --jq '[.closingIssuesReferences[]?.number]' (the GitHub-tracked closing links). As a fallback for older PRs that linked via text, also scan the PR body and commit messages for GitHub closing keywords: gh pr view N --json body,commits --jq '[.body, (.commits[].messageBody)] | join("\n")' and extract #<num> that follow close, closes, closed, fix, fixes, fixed, resolve, resolves, or resolved (case-insensitive). Union the two sets, dedupe.
  • Confirm each is a closed issue. For each candidate number I, run gh issue view I --json number,title,author,state,comments (suppress stderr; redirect 2>/dev/null). Skip the number if the command fails (it is a PR number, not an issue, or does not exist).
  • Gather attribution per issue. Record:
  • opener — .author.login, unless .author.is_bot is true.
  • issue contributors (people who contributed meaningfully) — the people who left a substantive comment on the issue. A reaction is not a comment (a 👍 or other emoji reaction never appears in .comments[]), so reaction-only participants are already excluded. Drive-by comments do not count either. Pull each comment with its author and body (gh issue view I --json comments --jq '.comments[] | select(.author.is_bot|not) | {login: .author.login, body: .body}', stderr suppressed), and treat a comment as a drive-by when its trimmed body is emoji-only, or is a brief acknowledgment or status ping (for example +1, same, me too, bump, following, thanks, any update(s)?), or is shorter than roughly 15 words and adds no detail. A person qualifies only when at least one of their comments is substantive (not a drive-by). Remove the opener and the PR workers so each person is credited once. May be empty.
  • PR workers — for the closing PR N, the union of the PR author, the review authors, and the commit authors: gh pr view N --json author,reviews,commits --jq '[.author.login] + [.reviews[]?.author.login] + [.commits[].authors[].login] | unique'. Drop bot accounts (is_bot where available, plus the web-flow, github-actions, and dependabot logins).
  • Build $issue_list. One entry per closed issue: its number, title, opener, contributors, the closing PR number(s),
Compartilhar X LinkedIn