Skip to content

Commit 2ee2631

Browse files
authored
ci: add release-please automation (#278)
1 parent 7c7d47e commit 2ee2631

14 files changed

Lines changed: 2798 additions & 8 deletions

.github/workflows/release-notes.yaml

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
name: Release Notes
22

33
on:
4+
workflow_dispatch:
5+
inputs:
6+
tag:
7+
description: Release tag to write notes for (for example, v0.4.0)
8+
required: true
9+
type: string
410
release:
511
types:
612
- published
@@ -12,16 +18,26 @@ jobs:
1218
release-notes:
1319
name: release-notes
1420
runs-on: ubuntu-latest
21+
env:
22+
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.release.tag_name }}
1523
steps:
1624
- name: Validate release inputs
1725
env:
1826
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
19-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20-
RELEASE_TAG: ${{ github.event.release.tag_name }}
27+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
28+
COMMUNIQUE_MODEL: ${{ vars.COMMUNIQUE_MODEL }}
29+
GITHUB_TOKEN: ${{ github.token }}
2130
run: |
2231
set -euo pipefail
2332
24-
: "${ANTHROPIC_API_KEY:?ANTHROPIC_API_KEY secret is required}"
33+
if [[ -z "${ANTHROPIC_API_KEY:-}" && -z "${OPENAI_API_KEY:-}" ]]; then
34+
echo "ANTHROPIC_API_KEY or OPENAI_API_KEY is required to generate release notes with Communique." >&2
35+
exit 1
36+
fi
37+
if [[ -z "${ANTHROPIC_API_KEY:-}" && -z "${COMMUNIQUE_MODEL:-}" ]]; then
38+
echo "Set COMMUNIQUE_MODEL when using OPENAI_API_KEY so Communique can select an OpenAI-compatible model." >&2
39+
exit 1
40+
fi
2541
: "${GITHUB_TOKEN:?GITHUB_TOKEN is required}"
2642
: "${RELEASE_TAG:?release tag is required}"
2743
@@ -36,6 +52,7 @@ jobs:
3652
- name: Checkout
3753
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3854
with:
55+
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.event.release.tag_name }}
3956
fetch-depth: 0
4057
fetch-tags: true
4158
persist-credentials: false
@@ -50,8 +67,6 @@ jobs:
5067
cache: false
5168

5269
- name: Resolve previous release ref
53-
env:
54-
RELEASE_TAG: ${{ github.event.release.tag_name }}
5570
run: |
5671
set -euo pipefail
5772
@@ -71,12 +86,19 @@ jobs:
7186
- name: Generate GitHub release notes
7287
env:
7388
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
74-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
75-
RELEASE_TAG: ${{ github.event.release.tag_name }}
89+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
90+
COMMUNIQUE_MODEL: ${{ vars.COMMUNIQUE_MODEL }}
91+
GITHUB_TOKEN: ${{ github.token }}
7692
run: |
7793
set -euo pipefail
7894
7995
: "${PREVIOUS_RELEASE_REF:?previous release ref is required}"
8096
97+
communique_args=()
98+
if [[ -n "${COMMUNIQUE_MODEL:-}" ]]; then
99+
communique_args+=(--model "$COMMUNIQUE_MODEL")
100+
fi
101+
81102
communique generate "$RELEASE_TAG" "$PREVIOUS_RELEASE_REF" \
82-
--github-release --repo "${{ github.repository }}"
103+
--github-release --repo "${{ github.repository }}" \
104+
"${communique_args[@]}"
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Release Please
2+
3+
# Maintains the single release PR (VERSION bump + Communique-written
4+
# CHANGELOG section) and, when that PR merges, creates the tag + GitHub Release.
5+
# The stock release-please action cannot register a custom changelog generator,
6+
# so this workflow runs scripts/release-please-runner.js against the
7+
# release-please library and registers Communique there.
8+
on:
9+
workflow_dispatch:
10+
push:
11+
branches:
12+
- main
13+
14+
concurrency:
15+
group: release-please-main
16+
cancel-in-progress: false
17+
18+
permissions:
19+
contents: read
20+
21+
env:
22+
RELEASE_PLEASE_TARGET_BRANCH: main
23+
24+
jobs:
25+
release-please:
26+
runs-on: ubuntu-latest
27+
timeout-minutes: 20
28+
permissions:
29+
contents: write
30+
issues: write
31+
pull-requests: write
32+
outputs:
33+
prs_created: ${{ steps.release_please.outputs.prs_created }}
34+
pr_branches: ${{ steps.release_please.outputs.pr_branches }}
35+
releases_created: ${{ steps.release_please.outputs.releases_created }}
36+
release_tags: ${{ steps.release_please.outputs.release_tags }}
37+
steps:
38+
- name: Check out main
39+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
40+
with:
41+
ref: ${{ env.RELEASE_PLEASE_TARGET_BRANCH }}
42+
fetch-depth: 0
43+
persist-credentials: false
44+
45+
# Install only the tools this release workflow needs. cache: false avoids
46+
# persisting tool downloads on a workflow that has write permissions and
47+
# release-note LLM secrets.
48+
- name: Set up mise
49+
uses: jdx/mise-action@1648a7812b9aeae629881980618f079932869151 # v4.0.1
50+
with:
51+
install_args: node communique
52+
cache: false
53+
54+
- name: Install locked Release Please dependency
55+
env:
56+
NPM_CONFIG_IGNORE_SCRIPTS: "true"
57+
run: npm ci --prefix scripts
58+
59+
- name: Run release-please with Communique notes
60+
id: release_please
61+
env:
62+
GITHUB_TOKEN: ${{ github.token }}
63+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
64+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
65+
COMMUNIQUE_MODEL: ${{ vars.COMMUNIQUE_MODEL }}
66+
run: |
67+
set -euo pipefail
68+
./scripts/run-release-please.sh
69+
70+
# Releases created with the workflow token do not trigger the
71+
# `release: published` workflow, so dispatch the Communique release-note
72+
# rewrite explicitly for each tag the runner created.
73+
dispatch-release-notes:
74+
runs-on: ubuntu-latest
75+
needs: release-please
76+
if: ${{ always() && !cancelled() && needs.release-please.outputs.releases_created == 'true' }}
77+
permissions:
78+
actions: write
79+
contents: read
80+
steps:
81+
- name: Dispatch Communique release notes for created releases
82+
env:
83+
GH_TOKEN: ${{ github.token }}
84+
RELEASE_TAGS: ${{ needs.release-please.outputs.release_tags }}
85+
run: |
86+
set -euo pipefail
87+
read -ra tags <<< "$RELEASE_TAGS"
88+
for tag in "${tags[@]}"; do
89+
gh workflow run release-notes.yaml --ref "$tag" --field "tag=$tag"
90+
done
91+
92+
# Branch pushes made with the workflow token do not trigger `pull_request`
93+
# workflows, so dispatch checks explicitly against the release PR branch head.
94+
dispatch-checks:
95+
runs-on: ubuntu-latest
96+
needs: release-please
97+
if: ${{ always() && !cancelled() && needs.release-please.outputs.prs_created == 'true' }}
98+
permissions:
99+
actions: write
100+
contents: read
101+
steps:
102+
- name: Dispatch checks onto the release PR branch
103+
env:
104+
GH_TOKEN: ${{ github.token }}
105+
PR_BRANCHES: ${{ needs.release-please.outputs.pr_branches }}
106+
run: |
107+
set -euo pipefail
108+
read -ra branches <<< "$PR_BRANCHES"
109+
for branch in "${branches[@]}"; do
110+
gh workflow run test.yml --ref "$branch"
111+
done

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: Tests
22

33
on:
4+
workflow_dispatch:
45
push:
56
branches: [main]
67
pull_request:

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ luac.out
66
*.zip
77
*.tar.gz
88

9+
# Node release tooling dependencies
10+
/scripts/node_modules/
11+
912
# Project-local Lua rock tree built by `mise run setup`
1013
/.luarocks/
1114

.release-please-manifest.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
".": "0.3.0"
3+
}

DEVELOPMENT.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,24 @@ mise run check
102102
mise run format
103103
```
104104

105+
## Release Automation
106+
107+
Releases are managed by Release Please. After feature and fix PRs land on `main`, the `Release Please` workflow opens or updates a single release PR that bumps `VERSION`, updates `.release-please-manifest.json`, and rewrites the next `CHANGELOG.md` entry with Communique-generated notes. Merging that release PR creates the `v<version>` tag and GitHub Release, then dispatches the `Release Notes` workflow to rewrite the GitHub Release body with Communique's GitHub-release format.
108+
109+
Release notes require either `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`; when using OpenAI-compatible credentials, set `COMMUNIQUE_MODEL` so Communique knows which model to call. The pinned Communique Linux binary currently requires a glibc 2.39-compatible environment (for example Ubuntu 24.04 or the GitHub-hosted `ubuntu-latest` runner); on older Linux hosts, run the dry-run in a newer container or runner.
110+
111+
To dogfood release automation without mutating GitHub, install the pinned tools from `mise.toml`, install the locked Release Please dependency graph under `scripts/`, and run the runner in dry-run mode against a branch that already contains the release config:
112+
113+
```bash
114+
mise install
115+
NPM_CONFIG_IGNORE_SCRIPTS=true npm ci --prefix scripts
116+
GITHUB_TOKEN=... \
117+
GITHUB_REPOSITORY=coder/claudecode.nvim \
118+
RELEASE_PLEASE_TARGET_BRANCH=your-branch \
119+
ANTHROPIC_API_KEY=... \
120+
./scripts/run-release-please.sh --dry-run
121+
```
122+
105123
## Implementation Guidelines
106124

107125
1. **Error Handling**

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.3.0

communique.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,16 @@ Primary readers are Neovim users and plugin integrators, not the plugin's own ma
99
system_extra = """
1010
Write direct, practical release notes for Neovim users and integrators.
1111
Lead with what changed and why it matters.
12+
Use plain Markdown with no emoji.
1213
Group changes into clear sections (for example Features, Fixes, Breaking Changes) and keep them concise.
1314
Avoid marketing language.
1415
Provide concrete migration guidance when configuration options, commands, or MCP tool behavior changed.
16+
Do not mention version-only release preparation commits unless they affect users.
1517
Do not invent changes that are not supported by the commits, pull requests, or diffs.
1618
"""
1719

1820
[defaults]
1921
model = "claude-opus-4-8"
22+
repo = "coder/claudecode.nvim"
23+
verify_links = true
24+
match_style = true

release-please-config.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"packages": {
3+
".": {
4+
"release-type": "simple",
5+
"changelog-type": "communique",
6+
"changelog-path": "CHANGELOG.md",
7+
"version-file": "VERSION",
8+
"include-component-in-tag": false,
9+
"include-v-in-tag": true,
10+
"bump-minor-pre-major": true,
11+
"pull-request-title-pattern": "chore(release): ${version}",
12+
"pull-request-header": "The next claudecode.nvim release. Merging this PR creates the release tag and GitHub Release, then starts Communique GitHub Release note generation.",
13+
"pull-request-footer": "Maintained by the release-please workflow. CHANGELOG.md and the release PR body are regenerated by Communique on every push to main, so manual edits to this PR are overwritten."
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)