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
21 changes: 19 additions & 2 deletions .github/prompts/classify-pr.prompt.yml
Review prompt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ messages:
- role: system
content: |
You classify pull requests for release note categorization.
Respond with exactly one word: bug, enhancement, or documentation.
Respond with JSON: {"label": "bug"}, {"label": "enhancement"}, or {"label": "documentation"}.

- bug: corrects wrong behavior, broken defaults, incorrect error codes,
retry/backoff defects, auth handling bugs, compatibility regressions.
Expand All @@ -19,6 +19,23 @@ messages:
When a PR mixes categories: bug > enhancement > documentation.
Prefer diff evidence over the PR title.
model: openai/gpt-4o-mini
responseFormat: json_schema
jsonSchema: |-
{
"name": "classification",
"strict": true,
"schema": {
"type": "object",
"properties": {
"label": {
"type": "string",
"enum": ["bug", "enhancement", "documentation"]
}
},
"required": ["label"],
"additionalProperties": false
}
}
modelParameters:
maxCompletionTokens: 10
maxCompletionTokens: 25
temperature: 0
14 changes: 8 additions & 6 deletions .github/workflows/ai-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
- name: Build prompt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }}
run: |
PR=${{ github.event.pull_request.number }}
gh pr diff "$PR" > /tmp/pr.diff
gh pr view "$PR" --json title --jq .title > /tmp/pr-title.txt
gh pr view "$PR" --json body --jq '.body // ""' > /tmp/pr-body.txt
Expand Down Expand Up @@ -79,13 +79,15 @@ jobs:
- name: Apply label
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RESPONSE_FILE: ${{ steps.classify.outputs.response-file }}
PR: ${{ github.event.pull_request.number }}
run: |
LABEL=$(echo "${{ steps.classify.outputs.response }}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
LABEL=$(jq -r '.label // empty' "$RESPONSE_FILE" 2>/dev/null || cat "$RESPONSE_FILE")
LABEL=$(printf '%s' "$LABEL" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
case "$LABEL" in
bug|enhancement|documentation) ;;
*) echo "Unexpected: $LABEL — skipping"; exit 0 ;;
esac
PR=${{ github.event.pull_request.number }}
CURRENT=$(gh pr view "$PR" --json labels --jq '.labels[].name')
for L in bug enhancement documentation; do
if [ "$L" != "$LABEL" ] && echo "$CURRENT" | grep -qx "$L"; then
Expand All @@ -105,8 +107,8 @@ jobs:
id: api-diff
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }}
run: |
PR=${{ github.event.pull_request.number }}
gh pr diff "$PR" > /tmp/full.diff

# Filter diff to exported Go library files (not tests, seed, or non-package dirs)
Expand Down Expand Up @@ -178,8 +180,9 @@ jobs:
if: steps.api-diff.outputs.skip != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RESPONSE_FILE: ${{ steps.detect.outputs.response-file }}
PR: ${{ github.event.pull_request.number }}
run: |
RESPONSE_FILE="${{ steps.detect.outputs.response-file }}"
if [ -z "$RESPONSE_FILE" ] || [ ! -f "$RESPONSE_FILE" ]; then
echo "::warning::Model response file is missing; skipping breaking label."
exit 0
Expand All @@ -198,7 +201,6 @@ jobs:
exit 0
fi
BREAKING=$(jq -r '.breaking' "$RESPONSE_FILE")
PR=${{ github.event.pull_request.number }}

if [ "$BREAKING" = "true" ]; then
ITEMS=$(jq -r '.items[]' "$RESPONSE_FILE" | sed 's/^/- /')
Expand Down
45 changes: 21 additions & 24 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ jobs:
security:
name: Security
uses: ./.github/workflows/security.yml
secrets: inherit

test:
name: Test gate
Expand Down Expand Up @@ -63,9 +62,11 @@ jobs:
govulncheck ./...

- name: Verify tag is on main
env:
COMMIT_SHA: ${{ github.sha }}
run: |
git fetch origin main
if ! git merge-base --is-ancestor "${{ github.sha }}" origin/main; then
if ! git merge-base --is-ancestor "$COMMIT_SHA" origin/main; then
echo "Error: tag is not on the main branch"
exit 1
fi
Expand All @@ -83,9 +84,11 @@ jobs:
fetch-depth: 0

- name: Verify tag is on main
env:
COMMIT_SHA: ${{ github.sha }}
run: |
git fetch origin main
if ! git merge-base --is-ancestor "${{ github.sha }}" origin/main; then
if ! git merge-base --is-ancestor "$COMMIT_SHA" origin/main; then
echo "Error: tag is not on the main branch"
exit 1
fi
Expand Down Expand Up @@ -142,35 +145,23 @@ jobs:
with:
prompt-file: /tmp/prompt.yml

- name: Set changelog env
run: |
RESPONSE_FILE="${{ steps.ai-changelog.outputs.response-file }}"
if [ -n "$RESPONSE_FILE" ] && [ -f "$RESPONSE_FILE" ]; then
# Strip markdown code fences that AI models wrap around responses
sed -i '/^```\(markdown\)\?$/d' "$RESPONSE_FILE"
DELIM="CHANGELOG_DELIM_$(openssl rand -hex 8)"
{
echo "RELEASE_CHANGELOG<<${DELIM}"
cat "$RESPONSE_FILE"
echo ""
echo "${DELIM}"
} >> $GITHUB_ENV
else
echo "RELEASE_CHANGELOG=" >> $GITHUB_ENV
fi

- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CHANGELOG_FILE: ${{ steps.ai-changelog.outputs.response-file }}
TAG: ${{ github.ref_name }}
run: |
TAG="${{ github.ref_name }}"
NOTES=""
if [ -n "$RELEASE_CHANGELOG" ]; then
NOTES="${RELEASE_CHANGELOG}
if [ -n "$CHANGELOG_FILE" ] && [ -f "$CHANGELOG_FILE" ]; then
sed -i '/^```\(markdown\)\?$/d' "$CHANGELOG_FILE"
CHANGELOG=$(cat "$CHANGELOG_FILE")
if [ -n "$CHANGELOG" ]; then
NOTES="${CHANGELOG}

---

"
fi
fi
NOTES="${NOTES}### Install

Expand All @@ -197,6 +188,7 @@ jobs:
if: vars.SKILLS_APP_ID != ''
continue-on-error: true
timeout-minutes: 5
environment: release
concurrency:
group: sync-skills
cancel-in-progress: false
Expand Down Expand Up @@ -232,4 +224,9 @@ jobs:

- name: Sync skills
if: steps.check.outputs.ready == 'true'
run: CLI_NAME=cli SKILLS_TOKEN=${{ steps.skills-token.outputs.token }} RELEASE_TAG=${{ github.ref_name }} SOURCE_SHA=${{ github.sha }} scripts/sync-skills.sh
env:
CLI_NAME: cli
SKILLS_TOKEN: ${{ steps.skills-token.outputs.token }}
RELEASE_TAG: ${{ github.ref_name }}
SOURCE_SHA: ${{ github.sha }}
run: scripts/sync-skills.sh
21 changes: 19 additions & 2 deletions seed/.github/prompts/classify-pr.prompt.yml
Review prompt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ messages:
- role: system
content: |
You classify pull requests for release note categorization.
Respond with exactly one word: bug, enhancement, or documentation.
Respond with JSON: {"label": "bug"}, {"label": "enhancement"}, or {"label": "documentation"}.

- bug: corrects wrong behavior, broken defaults, incorrect error codes,
retry/backoff defects, auth handling bugs, compatibility regressions.
Expand All @@ -19,6 +19,23 @@ messages:
When a PR mixes categories: bug > enhancement > documentation.
Prefer diff evidence over the PR title.
model: openai/gpt-4o-mini
responseFormat: json_schema
jsonSchema: |-
{
"name": "classification",
"strict": true,
"schema": {
"type": "object",
"properties": {
"label": {
"type": "string",
"enum": ["bug", "enhancement", "documentation"]
}
},
"required": ["label"],
"additionalProperties": false
}
}
modelParameters:
maxCompletionTokens: 10
maxCompletionTokens: 25
temperature: 0
15 changes: 8 additions & 7 deletions seed/.github/workflows/ai-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ jobs:
- name: Build prompt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }}
run: |
PR=${{ github.event.pull_request.number }}
gh pr diff "$PR" > /tmp/pr.diff
gh pr view "$PR" --json title --jq .title > /tmp/pr-title.txt
gh pr view "$PR" --json body --jq '.body // ""' > /tmp/pr-body.txt
Expand Down Expand Up @@ -79,13 +79,15 @@ jobs:
- name: Apply label
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RESPONSE_FILE: ${{ steps.classify.outputs.response-file }}
PR: ${{ github.event.pull_request.number }}
run: |
LABEL=$(echo "${{ steps.classify.outputs.response }}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
LABEL=$(jq -r '.label // empty' "$RESPONSE_FILE" 2>/dev/null || cat "$RESPONSE_FILE")
LABEL=$(printf '%s' "$LABEL" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
case "$LABEL" in
bug|enhancement|documentation) ;;
*) echo "Unexpected: $LABEL — skipping"; exit 0 ;;
esac
PR=${{ github.event.pull_request.number }}
CURRENT=$(gh pr view "$PR" --json labels --jq '.labels[].name')
for L in bug enhancement documentation; do
if [ "$L" != "$LABEL" ] && echo "$CURRENT" | grep -qx "$L"; then
Expand All @@ -105,9 +107,8 @@ jobs:
id: cmd-diff
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR: ${{ github.event.pull_request.number }}
run: |
PR=${{ github.event.pull_request.number }}

# CLI command surface files
PATTERNS=(
"internal/commands/*.go"
Expand Down Expand Up @@ -184,8 +185,9 @@ jobs:
if: steps.cmd-diff.outputs.skip != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RESPONSE_FILE: ${{ steps.detect.outputs.response-file }}
PR: ${{ github.event.pull_request.number }}
run: |
RESPONSE_FILE="${{ steps.detect.outputs.response-file }}"
if [ -z "$RESPONSE_FILE" ] || [ ! -f "$RESPONSE_FILE" ]; then
echo "::warning::Model response file is missing; skipping breaking label."
exit 0
Expand All @@ -204,7 +206,6 @@ jobs:
exit 0
fi
BREAKING=$(jq -r '.breaking' "$RESPONSE_FILE")
PR=${{ github.event.pull_request.number }}

if [ "$BREAKING" = "true" ]; then
ITEMS=$(jq -r '.items[]' "$RESPONSE_FILE" | sed 's/^/- /')
Expand Down
Loading
Loading