ci(whatsnew): generate release highlights via GitHub Models
Activate the What's New highlights step that condenses each release's Features into <=8 short bullets and injects a <!-- whatsnew --> block the app reads (utils/whatsNew.parseWhatsNew), with a deterministic fallback. Runs as a needs: job inside the release-please workflows rather than on a standalone release: published trigger, because release-please creates the release with GITHUB_TOKEN and GitHub never starts new workflow runs from token-generated events -- a standalone trigger would never fire. Shared as a reusable workflow_call so the stable and beta channels stay in sync. Best-effort: continue-on-error + fallback mean it can never break a release. Requires GitHub Models enabled for the org; until then the fallback is used.
This commit is contained in:
@@ -35,3 +35,16 @@ jobs:
|
|||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "Docker images will be built and tagged with this beta version." >> $GITHUB_STEP_SUMMARY
|
echo "Docker images will be built and tagged with this beta version." >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Best-effort "What's New" highlights on the freshly-created release. Runs in
|
||||||
|
# this same workflow run (not a `release:` trigger) because release-please
|
||||||
|
# creates the release with GITHUB_TOKEN, which never starts new workflow runs.
|
||||||
|
whatsnew:
|
||||||
|
needs: release-please
|
||||||
|
if: ${{ needs.release-please.outputs.release_created }}
|
||||||
|
permissions:
|
||||||
|
contents: write # edit the release body
|
||||||
|
models: read # GitHub Models (free tier)
|
||||||
|
uses: ./.github/workflows/whatsnew-highlights.yml
|
||||||
|
with:
|
||||||
|
tag: ${{ needs.release-please.outputs.tag_name }}
|
||||||
|
|
||||||
|
|||||||
@@ -34,3 +34,16 @@ jobs:
|
|||||||
echo "" >> $GITHUB_STEP_SUMMARY
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
echo "Docker images will be built and tagged with this version." >> $GITHUB_STEP_SUMMARY
|
echo "Docker images will be built and tagged with this version." >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Best-effort "What's New" highlights on the freshly-created release. Runs in
|
||||||
|
# this same workflow run (not a `release:` trigger) because release-please
|
||||||
|
# creates the release with GITHUB_TOKEN, which never starts new workflow runs.
|
||||||
|
whatsnew:
|
||||||
|
needs: release-please
|
||||||
|
if: ${{ needs.release-please.outputs.release_created }}
|
||||||
|
permissions:
|
||||||
|
contents: write # edit the release body
|
||||||
|
models: read # GitHub Models (free tier)
|
||||||
|
uses: ./.github/workflows/whatsnew-highlights.yml
|
||||||
|
with:
|
||||||
|
tag: ${{ needs.release-please.outputs.tag_name }}
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,48 @@
|
|||||||
# What's New highlights — GitHub Models release step
|
# What's New highlights — GitHub Models release step (reusable)
|
||||||
#
|
#
|
||||||
# DRAFT — move this into `.github/workflows/` on the repo that publishes the
|
# Called by the release-please workflows AFTER a release is created
|
||||||
# canonical releases the app reads (PicPeak/picpeak). It is kept under docs/
|
# (release-please.yml for `stable`, release-please-beta.yml for `main`). It runs
|
||||||
# here so it does NOT auto-run on the fork.
|
# as a job in the SAME workflow run rather than on its own `release: published`
|
||||||
|
# trigger, because release-please creates the release with the default
|
||||||
|
# GITHUB_TOKEN and GitHub does not start new workflow runs from token-generated
|
||||||
|
# events — a standalone `release:` workflow would simply never fire.
|
||||||
#
|
#
|
||||||
# What it does: when a release is published (release-please), it condenses that
|
# What it does: condenses the new release's "### Features" into <=8 short
|
||||||
# release's "### Features" into <=8 short bullets via GitHub Models (free tier,
|
# bullets via GitHub Models (free tier, `models: read`) and injects a
|
||||||
# `models: read`) and injects a `<!-- whatsnew -->` block at the top of the
|
# `<!-- whatsnew -->` block at the top of the release notes. The app reads that
|
||||||
# release notes. The picpeak app reads that block (utils/whatsNew.parseWhatsNew),
|
# block (backend utils/whatsNew.parseWhatsNew) and falls back to the raw
|
||||||
# and falls back to the raw Features list for releases without it — so this is
|
# Features list for releases without it — so this is purely a quality upgrade,
|
||||||
# purely a quality upgrade, never a hard dependency.
|
# never a hard dependency. Failure is isolated by `continue-on-error` + the
|
||||||
|
# deterministic fallback below, so it can never break a release.
|
||||||
|
#
|
||||||
|
# Requires GitHub Models to be enabled for the PicPeak org (owner setting).
|
||||||
|
# Until then the AI step returns nothing and the deterministic fallback is used.
|
||||||
#
|
#
|
||||||
# Validated end-to-end on a fork (extract -> openai/gpt-4o-mini -> inject into
|
# Validated end-to-end on a fork (extract -> openai/gpt-4o-mini -> inject into
|
||||||
# real release notes; app parseWhatsNew() reads the block back). The one thing
|
# real release notes; app parseWhatsNew() reads the block back).
|
||||||
# that can't be checked from a fork: GitHub Models must be enabled for the
|
|
||||||
# PicPeak ORG (owner setting). Failure is isolated anyway by `continue-on-error`
|
|
||||||
# + the deterministic fallback below, so it can never break a release.
|
|
||||||
|
|
||||||
name: What's New highlights
|
name: What's New highlights
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
workflow_call:
|
||||||
types: [published]
|
inputs:
|
||||||
|
tag:
|
||||||
permissions:
|
description: Release tag to annotate (e.g. v2.3.0)
|
||||||
contents: write # to edit the release body
|
required: true
|
||||||
models: read # GitHub Models (free tier)
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
highlights:
|
highlights:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # to edit the release body
|
||||||
|
models: read # GitHub Models (free tier)
|
||||||
steps:
|
steps:
|
||||||
- name: Extract Features from the published release
|
- name: Extract Features from the published release
|
||||||
id: feat
|
id: feat
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
TAG: ${{ inputs.tag }}
|
||||||
run: |
|
run: |
|
||||||
BODY=$(gh release view "$TAG" --json body -q .body)
|
BODY=$(gh release view "$TAG" --json body -q .body)
|
||||||
FEATURES=$(printf '%s\n' "$BODY" | awk '/^#{2,4} +Features/{f=1;next} /^#{1,4} +\S/{f=0} f')
|
FEATURES=$(printf '%s\n' "$BODY" | awk '/^#{2,4} +Features/{f=1;next} /^#{1,4} +\S/{f=0} f')
|
||||||
@@ -60,12 +67,12 @@ jobs:
|
|||||||
continue-on-error: true # never let highlights break a release
|
continue-on-error: true # never let highlights break a release
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
TAG: ${{ github.event.release.tag_name }}
|
TAG: ${{ inputs.tag }}
|
||||||
AI: ${{ steps.ai.outputs.response }}
|
AI: ${{ steps.ai.outputs.response }}
|
||||||
FEATURES: ${{ steps.feat.outputs.features }}
|
FEATURES: ${{ steps.feat.outputs.features }}
|
||||||
run: |
|
run: |
|
||||||
BULLETS="$AI"
|
BULLETS="$AI"
|
||||||
# Deterministic fallback if the model returned nothing.
|
# Deterministic fallback if the model returned nothing (e.g. Models not yet enabled).
|
||||||
if [ -z "$BULLETS" ]; then
|
if [ -z "$BULLETS" ]; then
|
||||||
BULLETS=$(printf '%s\n' "$FEATURES" | head -8 \
|
BULLETS=$(printf '%s\n' "$FEATURES" | head -8 \
|
||||||
| sed -E 's/^\* \*\*[^:]+:\*\* */- /; s/ \(\[[^]]*\]\([^)]*\)\)//g')
|
| sed -E 's/^\* \*\*[^:]+:\*\* */- /; s/ \(\[[^]]*\]\([^)]*\)\)//g')
|
||||||
Reference in New Issue
Block a user