Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions .claude/skills/prepare-release/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
---
name: prepare-release
description: >
Automate the HSSM pre-release workflow: update changelog, update docs announcement banner,
build docs locally, and create a draft GitHub release. Use this skill whenever the user mentions
"prepare release", "release prep", "pre-release checklist", "update changelog for release",
or any variation of getting ready to publish a new version of HSSM. Also trigger when the user
references the release workflow steps (changelog + announcement + docs build + draft release).
---

# Prepare Release

This skill automates the pre-release checklist for the HSSM package. It assumes the version
in `pyproject.toml` has already been bumped. The skill walks through four steps:

1. Update the changelog (`docs/changelog.md`)
2. Update the announcement banner (`docs/overrides/main.html`)
3. Build docs locally to verify they compile
4. Run the notebook check workflow in CI
5. Create a draft GitHub release

## Conventions

- **Version in pyproject.toml**: no prefix (e.g., `0.3.0`)
- **Git tags**: `v` prefix (e.g., `v0.3.0`)
- **Changelog headings**: no prefix (e.g., `### 0.3.0`)
- **Doc deployment**: happens automatically in CI when a release is *published* — this skill only creates a *draft*

## Step 1: Read the current version

Read `pyproject.toml` and extract the `version` field (line 3). Store this as `VERSION` for the remaining steps.

## Step 2: Gather changes since the last release

Find the most recent git tag:

```bash
git tag --list 'v*' --sort=-version:refname | head -1
```

Then collect commits since that tag:

```bash
git log <LATEST_TAG>..HEAD --oneline
```

Also look at merged PRs specifically, since they tend to be the most meaningful changelog entries:

```bash
git log <LATEST_TAG>..HEAD --oneline --grep="Merge pull request"
```

If useful, also check `gh pr list --state merged --base main --limit 30` for PR titles and descriptions to better understand what each change does.

## Step 3: Draft the changelog entry

Using the gathered commits and PR info, draft a changelog entry that matches the existing
format in `docs/changelog.md`. The format is:

```markdown
### {VERSION}

This version includes the following changes:

1. Description of first change.
2. Description of second change.
...
```

Guidelines for writing the changelog:
- Synthesize commits into human-readable descriptions — don't just paste commit messages
- Group related commits into single entries
- Focus on user-facing changes: new features, bug fixes, breaking changes, new tutorials
- Skip pure CI/infra changes unless they affect users (e.g., new Python version support)
- Use the style and tone of existing entries as a guide

**Important: Show the draft changelog to the user and ask for their review before writing it to the file.** Use `AskUserQuestion` or just present it inline and wait for confirmation. The user may want to reword entries, add context, or remove items.

## Step 4: Write the changelog

After user approval, insert the new version section into `docs/changelog.md` immediately after the `# Changelog` heading on line 1. Add a blank line before and after the new section.

## Step 5: Update the announcement banner

Edit `docs/overrides/main.html`. Find the line containing the version announcement (pattern: `v{OLD_VERSION} is released!`) and replace it with:

```html
<span class="right-margin"> v{VERSION} is released! </span>
```

Only change the version number — leave the surrounding HTML and Jinja2 template structure untouched.

## Step 6: Build docs locally

Run:

```bash
uv run --group notebook --group docs mkdocs build
```

Check that the command exits with code 0. If it fails:
- Show the error output to the user
- Do NOT proceed to creating the release
- Help debug the issue

If it succeeds, confirm to the user and move on.

## Step 7: Run the notebook check workflow

Trigger the `check_notebooks.yml` workflow on the current branch to verify all notebooks execute successfully:

```bash
gh workflow run "Check notebooks" --ref $(git branch --show-current)
```

Then monitor the run:

```bash
# Wait a few seconds for the run to register, then find it
gh run list --workflow="Check notebooks" --limit 1 --json databaseId,status,conclusion
```

Use `gh run watch <RUN_ID>` to stream the status, or poll with `gh run view <RUN_ID>` periodically.

- If the workflow **succeeds**, confirm to the user and proceed to the draft release.
- If the workflow **fails**, show the user the failure details using `gh run view <RUN_ID> --log-failed` and help debug. Do NOT proceed to creating the release until notebooks pass.

## Step 8: Create a draft GitHub release

Run:

```bash
gh release create v{VERSION} --draft --title "v{VERSION}" --generate-notes --target main
```

The `--draft` flag ensures nothing is published (and therefore no CI release pipeline is triggered).
The `--generate-notes` flag uses GitHub's auto-generated release notes from merged PRs.

## Step 9: Report

Tell the user:
- The draft release URL (from the `gh release create` output)
- A summary of what was done: changelog updated, banner updated, docs build verified, draft release created
- Remind them that publishing the release will trigger the full CI pipeline (tests, PyPI publish, docs deploy)
2 changes: 2 additions & 0 deletions .github/workflows/check_notebooks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ jobs:
"rlssm_rlwm_model.ipynb"
"rlssm_tutorial.ipynb"
"add_custom_rlssm_model.ipynb"
"hssm_tutorial_workshop_1.ipynb"
"hssm_tutorial_workshop_2.ipynb"
)

EXIT_CODE=0
Expand Down
150 changes: 150 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Prepare Release (AI-assisted)

# This workflow uses Claude to automate pre-release tasks:
# 1. Generate changelog from merged PRs
# 2. Update the docs announcement banner
# 3. Verify docs build
# 4. Create a draft GitHub release
#
# Triggered manually. Claude generates a PR with the changelog and banner
# updates, then native steps verify the docs build and create the draft release.

on:
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g., 0.3.0). Must match the version in pyproject.toml."
required: true
type: string

permissions:
contents: write
pull-requests: write

jobs:
prepare-changelog-and-banner:
name: Generate changelog and update banner via Claude
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.create-pr.outputs.pr_number }}
branch: ${{ steps.branch.outputs.name }}

steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0 # Full history needed for git log

- name: Create release prep branch
id: branch
run: |
BRANCH="release-prep/v${{ inputs.version }}"
git checkout -b "$BRANCH"
echo "name=$BRANCH" >> "$GITHUB_OUTPUT"

- name: Run Claude to update changelog and banner
uses: anthropics/claude-code-action@beta
with:
prompt: |
You are preparing release v${{ inputs.version }} of the HSSM package.

## Task 1: Update the changelog

1. Find the latest git tag: `git tag --list 'v*' --sort=-version:refname | head -1`
2. Gather changes: `git log <tag>..HEAD --oneline`
3. Read `docs/changelog.md` to see the existing format
4. Insert a new section after the `# Changelog` heading with this format:

```
### ${{ inputs.version }}

This version includes the following changes:

1. Human-readable description of change
2. ...
```

Synthesize commits into user-facing descriptions. Focus on features, bug fixes,
and breaking changes. Skip CI-only changes.

## Task 2: Update the announcement banner

Edit `docs/overrides/main.html`. Find the line with the version announcement
(pattern: `vX.Y.Z is released!`) and replace the version with v${{ inputs.version }}.

## Important
- Changelog headings use NO "v" prefix (e.g., ### 0.3.0)
- Git tags use "v" prefix (e.g., v0.3.0)
- Only modify docs/changelog.md and docs/overrides/main.html
Comment on lines +49 to +78
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Should we just tell Claude to use the skill rather than providing a different context here?

anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

- name: Commit changes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add docs/changelog.md docs/overrides/main.html
git commit -m "docs: update changelog and banner for v${{ inputs.version }}"
git push origin "${{ steps.branch.outputs.name }}"

- name: Create pull request
id: create-pr
run: |
PR_URL=$(gh pr create \
--title "docs: prepare release v${{ inputs.version }}" \
--body "## Summary
- Updated \`docs/changelog.md\` with v${{ inputs.version }} entries (AI-generated from git log)
- Updated announcement banner in \`docs/overrides/main.html\`

## Review checklist
- [ ] Changelog entries are accurate and well-written
- [ ] No important changes are missing
- [ ] Banner version is correct

> Auto-generated by the prepare-release workflow using Claude." \
--base main \
--head "${{ steps.branch.outputs.name }}")
echo "pr_number=$(echo $PR_URL | grep -o '[0-9]*$')" >> "$GITHUB_OUTPUT"
echo "Created PR: $PR_URL"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

verify-docs-build:
name: Verify docs build
needs: prepare-changelog-and-banner
runs-on: ubuntu-latest

steps:
- name: Checkout PR branch
uses: actions/checkout@v6
with:
ref: ${{ needs.prepare-changelog-and-banner.outputs.branch }}

- name: Setup environment
uses: ./.github/setup-env
with:
python-version: "3.13"

- name: Build docs
run: uv run --group notebook --group docs mkdocs build

create-draft-release:
name: Create draft GitHub release
needs: [prepare-changelog-and-banner, verify-docs-build]
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Create draft release
run: |
gh release create "v${{ inputs.version }}" \
--draft \
--title "v${{ inputs.version }}" \
--generate-notes \
--target main
echo "Draft release created: https://github.com/${{ github.repository }}/releases"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
jobs:
run_tests:
runs-on: ubuntu-latest
timeout-minutes: 90
if: ${{ ! contains(github.event.head_commit.message, '[skip fast tests]') }}
env:
PYTENSOR_FLAGS: "blas__ldflags=-L/usr/lib/x86_64-linux-gnu -lblas -llapack"
Expand Down
Loading
Loading