Skip to content

Commit 230b94d

Browse files
idycursoragent
andcommitted
ci: generate release notes from grouped diffs
Direct-commit releases need AI-generated notes that summarize git diffs instead of PR metadata, so the release workflow now builds grouped change inputs before producing final notes. - Replace Copilot PR-based release notes with multi-step GitHub Models inference - Generate per-group diff summaries before a final release note synthesis step - Document the new diff-based release note flow in the README Generated with [Cursor](https://cursor.sh/) Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 3b2ba3e commit 230b94d

2 files changed

Lines changed: 145 additions & 27 deletions

File tree

.github/workflows/release.yml

Lines changed: 141 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ on:
77

88
permissions:
99
contents: write
10-
pull-requests: read
10+
models: read
11+
12+
env:
13+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
1114

1215
concurrency:
1316
group: release-${{ github.ref_name }}
@@ -23,7 +26,7 @@ jobs:
2326
build_number: ${{ steps.meta.outputs.build_number }}
2427
sources_hash: ${{ steps.meta.outputs.sources_hash }}
2528
steps:
26-
- uses: actions/checkout@v4
29+
- uses: actions/checkout@v6
2730

2831
- id: meta
2932
shell: bash
@@ -67,7 +70,7 @@ jobs:
6770
- target: x86_64-linux-gnu
6871
mcpu: baseline
6972
steps:
70-
- uses: actions/checkout@v4
73+
- uses: actions/checkout@v6
7174

7275
- name: Cache downloaded sources
7376
uses: actions/cache@v4
@@ -138,10 +141,8 @@ jobs:
138141
- prepare
139142
- build
140143
runs-on: ubuntu-24.04
141-
env:
142-
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
143144
steps:
144-
- uses: actions/checkout@v4
145+
- uses: actions/checkout@v6
145146
with:
146147
fetch-depth: 0
147148

@@ -168,31 +169,149 @@ jobs:
168169
169170
printf 'base_ref=%s\n' "$previous" >>"$GITHUB_OUTPUT"
170171
171-
- name: Validate Copilot release notes inputs
172+
- name: Validate release notes inputs
172173
shell: bash
173174
run: |
174175
set -euo pipefail
175176
176-
if [[ -z "$COPILOT_GITHUB_TOKEN" ]]; then
177-
printf '::error::COPILOT_GITHUB_TOKEN secret is required for release notes\n'
178-
exit 1
179-
fi
180-
181177
if [[ -z "${{ steps.previous-tag.outputs.base_ref }}" ]]; then
182-
printf '::error::Previous v<version>-rN tag is required for Copilot release notes base-ref\n'
178+
printf '::error::Previous v<version>-rN tag is required for release notes base-ref\n'
183179
exit 1
184180
fi
185181
186-
- name: Generate Copilot release notes
187-
id: copilot-notes
188-
uses: github/copilot-release-notes@main
182+
- name: Prepare grouped release note inputs
183+
shell: bash
184+
run: |
185+
set -euo pipefail
186+
187+
base_ref="${{ steps.previous-tag.outputs.base_ref }}"
188+
head_ref="${{ needs.prepare.outputs.tag }}"
189+
context_dir="dist/release-context"
190+
mkdir -p "$context_dir"
191+
192+
git log --no-merges --format='- %s (%h)' "$base_ref..$head_ref" >"$context_dir/commits.md"
193+
git diff --name-status "$base_ref..$head_ref" >"$context_dir/files.txt"
194+
git diff --stat "$base_ref..$head_ref" >"$context_dir/diff-stat.txt"
195+
196+
write_group_prompt() {
197+
local group="$1"
198+
local title="$2"
199+
shift 2
200+
local prompt="$context_dir/${group}.prompt.md"
201+
local diff_file="$context_dir/${group}.diff"
202+
203+
git diff --unified=20 "$base_ref..$head_ref" -- "$@" >"$diff_file" || true
204+
205+
{
206+
printf 'You are preparing one section of release notes for esp-zig-bootstrap.\n'
207+
printf 'Summarize only user-relevant changes in this group. Ignore noisy mechanical patch context unless it changes behavior.\n'
208+
printf 'Use concise markdown bullets. Do not mention files that did not change.\n\n'
209+
printf 'Release range: `%s..%s`\n' "$base_ref" "$head_ref"
210+
printf 'Group: %s\n\n' "$title"
211+
printf 'Changed files in this group:\n'
212+
git diff --name-status "$base_ref..$head_ref" -- "$@" || true
213+
printf '\nOverall commit log:\n'
214+
cat "$context_dir/commits.md"
215+
printf '\nDiff for this group, truncated if necessary:\n'
216+
python3 -c 'import pathlib, sys; data = pathlib.Path(sys.argv[1]).read_text(errors="replace"); limit = 120000; sys.stdout.write(data if len(data) <= limit else data[:limit] + "\n\n[diff truncated]\n")' "$diff_file"
217+
} >"$prompt"
218+
}
219+
220+
write_group_prompt ci-release "CI and release automation" \
221+
.github/workflows/release.yml release.sh
222+
write_group_prompt docs "Documentation" \
223+
README.md AGENTS.md RELEASE.md 0.16.0/README.md 0.16.0/regression/README.md
224+
write_group_prompt version-inputs "Version inputs and bootstrap support" \
225+
.gitignore bootstrap.sh 0.16.0/.gitignore 0.16.0/llvm-project 0.16.0/zig-bootstrap
226+
write_group_prompt xtensa-patches "Xtensa downstream patch set" \
227+
0.16.0/patches
228+
write_group_prompt regression-tests "Xtensa regression tests" \
229+
0.16.0/regression/run.sh 0.16.0/regression/cases
230+
231+
- name: Summarize CI and release changes
232+
id: notes-ci-release
233+
uses: actions/ai-inference@v1
234+
with:
235+
prompt-file: dist/release-context/ci-release.prompt.md
236+
model: openai/gpt-4o
237+
max-completion-tokens: 700
238+
239+
- name: Summarize documentation changes
240+
id: notes-docs
241+
uses: actions/ai-inference@v1
242+
with:
243+
prompt-file: dist/release-context/docs.prompt.md
244+
model: openai/gpt-4o
245+
max-completion-tokens: 700
246+
247+
- name: Summarize version input changes
248+
id: notes-version-inputs
249+
uses: actions/ai-inference@v1
250+
with:
251+
prompt-file: dist/release-context/version-inputs.prompt.md
252+
model: openai/gpt-4o
253+
max-completion-tokens: 700
254+
255+
- name: Summarize Xtensa patch changes
256+
id: notes-xtensa-patches
257+
uses: actions/ai-inference@v1
258+
with:
259+
prompt-file: dist/release-context/xtensa-patches.prompt.md
260+
model: openai/gpt-4o
261+
max-completion-tokens: 900
262+
263+
- name: Summarize regression test changes
264+
id: notes-regression-tests
265+
uses: actions/ai-inference@v1
266+
with:
267+
prompt-file: dist/release-context/regression-tests.prompt.md
268+
model: openai/gpt-4o
269+
max-completion-tokens: 700
270+
271+
- name: Prepare final release notes prompt
272+
shell: bash
273+
run: |
274+
set -euo pipefail
275+
276+
{
277+
printf 'You are writing final release notes for esp-zig-bootstrap.\n'
278+
printf 'Turn the grouped summaries into concise user-facing markdown.\n'
279+
printf 'Keep meaningful technical details, but remove duplication and internal workflow noise.\n'
280+
printf 'Use these sections exactly: "## Highlights", "## Changes", "## Notes".\n'
281+
printf 'Do not include artifacts; they are appended separately.\n\n'
282+
printf 'Release: `%s`\n' "${{ needs.prepare.outputs.tag }}"
283+
printf 'Source commit: `%s`\n\n' "$GITHUB_SHA"
284+
printf 'Commit log:\n'
285+
cat dist/release-context/commits.md
286+
printf '\nChanged files:\n'
287+
cat dist/release-context/files.txt
288+
printf '\nDiff stat:\n'
289+
cat dist/release-context/diff-stat.txt
290+
printf '\n\nGrouped AI summaries:\n\n'
291+
printf '### CI and release automation\n'
292+
cat "${{ steps.notes-ci-release.outputs.response-file }}"
293+
printf '\n\n### Documentation\n'
294+
cat "${{ steps.notes-docs.outputs.response-file }}"
295+
printf '\n\n### Version inputs and bootstrap support\n'
296+
cat "${{ steps.notes-version-inputs.outputs.response-file }}"
297+
printf '\n\n### Xtensa downstream patch set\n'
298+
cat "${{ steps.notes-xtensa-patches.outputs.response-file }}"
299+
printf '\n\n### Xtensa regression tests\n'
300+
cat "${{ steps.notes-regression-tests.outputs.response-file }}"
301+
printf '\n'
302+
} >dist/release-context/final.prompt.md
303+
304+
- name: Generate final release notes
305+
id: final-notes
306+
uses: actions/ai-inference@v1
189307
with:
190-
base-ref: ${{ steps.previous-tag.outputs.base_ref }}
191-
head-ref: ${{ needs.prepare.outputs.tag }}
308+
prompt-file: dist/release-context/final.prompt.md
309+
model: openai/gpt-4o
310+
max-completion-tokens: 1400
192311

193312
- name: Prepare release payload
194313
env:
195-
COPILOT_RELEASE_NOTES: ${{ steps.copilot-notes.outputs.release-notes }}
314+
FINAL_RELEASE_NOTES_FILE: ${{ steps.final-notes.outputs.response-file }}
196315
shell: bash
197316
run: |
198317
set -euo pipefail
@@ -209,16 +328,15 @@ jobs:
209328
sha256sum *.tar.xz >SHA256SUMS
210329
)
211330
212-
if [[ -z "$COPILOT_RELEASE_NOTES" ]]; then
213-
printf '::error::Copilot release notes output is empty\n'
331+
if [[ ! -s "$FINAL_RELEASE_NOTES_FILE" ]]; then
332+
printf '::error::AI release notes output is empty\n'
214333
exit 1
215334
fi
216335
217336
{
218337
printf 'Automated release for `%s`.\n\n' "${{ needs.prepare.outputs.tag }}"
219338
printf 'Source commit: `%s`\n\n' "$GITHUB_SHA"
220-
printf '## Changes\n\n'
221-
printf '%s\n' "$COPILOT_RELEASE_NOTES"
339+
cat "$FINAL_RELEASE_NOTES_FILE"
222340
printf '\n\n## Artifacts\n\n'
223341
for artifact in "${artifacts[@]}"; do
224342
printf -- '- `%s`\n' "$(basename "$artifact")"

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ produce multiple cross-compiled distributions. Individual target failures do not
8181
block the release; the final GitHub Release includes only successfully built
8282
artifacts.
8383

84-
Release notes are generated with `github/copilot-release-notes`. The repository
85-
must have a `COPILOT_GITHUB_TOKEN` secret with `Copilot Requests: Read`
86-
permission, and the tag must have a previous `v<version>-rN` tag to use as the
87-
release notes base ref.
84+
Release notes are generated with GitHub Models through `actions/ai-inference`.
85+
The workflow summarizes grouped file diffs first, then asks the model to combine
86+
those summaries into final release notes. The tag must have a previous
87+
`v<version>-rN` tag to use as the release notes base ref.
8888

8989
To refresh an existing release, delete and recreate the tag:
9090

0 commit comments

Comments
 (0)