diff --git a/.github/prompts/classify-pr.prompt.yml b/.github/prompts/classify-pr.prompt.yml deleted file mode 100644 index 4ae0c75..0000000 --- a/.github/prompts/classify-pr.prompt.yml +++ /dev/null @@ -1,41 +0,0 @@ -messages: - - role: system - content: | - You classify pull requests for release note categorization. - 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. - Test-only changes that fix assertions for previously-wrong behavior - count as bug. - - enhancement: new API coverage, new SDK features, new configuration - options, new test coverage, generator/tooling improvements. - If only generated files changed with no bug claim, default to - enhancement. - - documentation: README, CONTRIBUTING, SECURITY, or other docs-only - changes with no runtime behavior change. SDK README updates that - accompany code changes don't count — label the code change. - - 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: 25 - temperature: 0 diff --git a/.github/prompts/detect-breaking.prompt.yml b/.github/prompts/detect-breaking.prompt.yml deleted file mode 100644 index 41252c6..0000000 --- a/.github/prompts/detect-breaking.prompt.yml +++ /dev/null @@ -1,36 +0,0 @@ -messages: - - role: system - content: | - You analyze Go library diffs for breaking changes to the public API. - A breaking change is: - - Removal or rename of an exported type, function, method, or constant - - Change to an exported function or method signature (parameters, return types) - - Removal of a package - - Breaking an interface contract (adding methods to an exported interface) - - Removal of exported struct fields - - NOT breaking: adding new exported types/functions/methods/constants, - adding new packages, internal refactors, test changes, documentation, - adding new struct fields, changes to unexported identifiers. - - Respond with a JSON object: - {"breaking": true/false, "items": ["description of each breaking change"]} -model: openai/gpt-4o-mini -responseFormat: json_schema -jsonSchema: |- - { - "name": "breaking_analysis", - "strict": true, - "schema": { - "type": "object", - "properties": { - "breaking": { "type": "boolean" }, - "items": { "type": "array", "items": { "type": "string" } } - }, - "required": ["breaking", "items"], - "additionalProperties": false - } - } -modelParameters: - maxCompletionTokens: 500 - temperature: 0 diff --git a/.github/prompts/summarize-changelog.prompt.yml b/.github/prompts/summarize-changelog.prompt.yml deleted file mode 100644 index bf9a7ba..0000000 --- a/.github/prompts/summarize-changelog.prompt.yml +++ /dev/null @@ -1,20 +0,0 @@ -messages: - - role: system - content: | - You write release summaries for a shared Go library. Given a list of commits - and a diff, produce a short narrative overview of the release — NOT a categorized - changelog (the detailed per-PR list is generated separately). - - Rules: - - Write 2-4 short paragraphs in plain prose, no bullet lists - - Lead with the most important change; group related changes naturally - - Flag any breaking changes prominently at the top with ⚠️ - - Use imperative voice ("Add", "Fix", not "Added", "Fixed") - - No commit hashes, no PR numbers, no author attributions - - No markdown headings — just paragraphs - - Do NOT wrap output in code fences - - Keep it under 15 lines -model: openai/gpt-4o -modelParameters: - maxCompletionTokens: 1500 - temperature: 0.2 diff --git a/.github/workflows/ai-labeler.yml b/.github/workflows/ai-labeler.yml deleted file mode 100644 index 1e8fbd9..0000000 --- a/.github/workflows/ai-labeler.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Classify PR - -on: - pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only calls reusable workflows, no PR code is checked out or executed - types: [opened, synchronize, reopened] - -concurrency: - group: classify-pr-${{ github.event.pull_request.number }} - cancel-in-progress: true - -permissions: {} - -jobs: - classify: - uses: basecamp/.github/.github/workflows/ai-classify-pr.yml@0f236fea0ac36da812ff7178af3af1b4ee686c3c - with: - prompt-file: .github/prompts/classify-pr.prompt.yml - labels: "bug,enhancement,documentation" - permissions: - contents: read - issues: write - models: read - pull-requests: write - - breaking: - uses: basecamp/.github/.github/workflows/ai-breaking-change.yml@0f236fea0ac36da812ff7178af3af1b4ee686c3c - with: - prompt-file: .github/prompts/detect-breaking.prompt.yml - file-patterns: | - credstore/*.go - editor/*.go - oauthcallback/*.go - output/*.go - pkce/*.go - profile/*.go - surface/*.go - permissions: - contents: read - issues: write - models: read - pull-requests: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b821df2..b4091f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,7 +84,6 @@ jobs: environment: release permissions: contents: write - models: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: @@ -101,77 +100,12 @@ jobs: exit 1 fi - - name: Build changelog context - run: | - PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") - DIFF_FILE=/tmp/diff.txt - if [ -z "$PREV_TAG" ]; then - COMMITS=$(git log --oneline --no-decorate) - git diff --stat 4b825dc642cb6eb9a060e54bf899d69f82a3ef17 HEAD > "$DIFF_FILE" - else - COMMITS=$(git log --oneline --no-decorate "${PREV_TAG}..HEAD") - git diff "${PREV_TAG}..HEAD" -- '*.go' 'go.mod' > "$DIFF_FILE" - fi - { - echo "Commits:" - echo "$COMMITS" - echo "" - echo "Diff summary:" - head -c 80000 "$DIFF_FILE" - } > /tmp/user-message.txt - # Splice into prompt YAML - python3 -c " - with open('.github/prompts/summarize-changelog.prompt.yml') as f: - lines = f.readlines() - with open('/tmp/user-message.txt') as f: - user_msg = f.read() - insert_at = len(lines) - for i, line in enumerate(lines): - if i == 0: continue - if line.strip() and not line[0].isspace(): - insert_at = i - break - entry = [' - role: user\n', ' content: |\n'] - for ln in user_msg.splitlines(): - entry.append(' ' + ln + '\n') - lines[insert_at:insert_at] = entry - with open('/tmp/prompt.yml', 'w') as f: - f.writelines(lines) - try: - import yaml - doc = yaml.safe_load(open('/tmp/prompt.yml')) - assert doc['messages'][-1]['role'] == 'user', 'prompt splice failed' - except ImportError: - pass - " - continue-on-error: true - - - name: Generate AI changelog - id: ai-changelog - uses: actions/ai-inference@e09e65981758de8b2fdab13c2bfb7c7d5493b0b6 # v2.0.7 - continue-on-error: true - with: - prompt-file: /tmp/prompt.yml - - name: Create GitHub Release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CHANGELOG_FILE: ${{ steps.ai-changelog.outputs.response-file }} TAG: ${{ github.ref_name }} run: | - NOTES="" - 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 + NOTES="### Install \`\`\` go get github.com/basecamp/cli@${TAG} diff --git a/prompts/seed-cli.md b/prompts/seed-cli.md index af02d56..487efff 100644 --- a/prompts/seed-cli.md +++ b/prompts/seed-cli.md @@ -31,13 +31,8 @@ You are creating a new Go CLI for a 37signals product using the seed templates. │ │ ├── test.yml │ │ ├── security.yml │ │ ├── release.yml - │ │ ├── ai-labeler.yml │ │ ├── dependabot-auto-merge.yml │ │ └── labeler.yml - │ ├── prompts/ - │ │ ├── classify-pr.prompt.yml - │ │ ├── detect-breaking.prompt.yml - │ │ └── summarize-changelog.prompt.yml │ ├── codeql/ │ │ └── codeql-config.yml │ ├── CODEOWNERS @@ -107,7 +102,6 @@ You are creating a new Go CLI for a 37signals product using the seed templates. - `seed/.github/workflows/test.yml` → `.github/workflows/test.yml` (update env vars, GOPRIVATE) - `seed/.github/workflows/security.yml` → `.github/workflows/security.yml` - `seed/.github/workflows/release.yml` → `.github/workflows/release.yml` (update env vars) - - `seed/.github/workflows/ai-labeler.yml` → `.github/workflows/ai-labeler.yml` - `seed/.github/workflows/dependabot-auto-merge.yml` → `.github/workflows/dependabot-auto-merge.yml` - `seed/.github/workflows/labeler.yml` → `.github/workflows/labeler.yml` - `seed/.github/dependabot.yml` → `.github/dependabot.yml` @@ -116,9 +110,6 @@ You are creating a new Go CLI for a 37signals product using the seed templates. - `seed/.github/release.yml` → `.github/release.yml` - `seed/.github/labeler.yml.tmpl` → `.github/labeler.yml` (customize label rules) - `seed/.github/codeql/codeql-config.yml` → `.github/codeql/codeql-config.yml` - - `seed/.github/prompts/classify-pr.prompt.yml` → `.github/prompts/classify-pr.prompt.yml` - - `seed/.github/prompts/detect-breaking.prompt.yml` → `.github/prompts/detect-breaking.prompt.yml` - - `seed/.github/prompts/summarize-changelog.prompt.yml` → `.github/prompts/summarize-changelog.prompt.yml` **Local dev config:** - `seed/.pre-commit-config.yaml.tmpl` → `.pre-commit-config.yaml` (fill in env var name) @@ -150,7 +141,6 @@ After the repo is pushed to GitHub: | Feature | What to configure | |---------|-------------------| | Private module access | `vars.RELEASE_CLIENT_ID` + `secrets.RELEASE_APP_PRIVATE_KEY` | - | AI changelog | `vars.ENABLE_AI_CHANGELOG=true` | | macOS notarization | 5 secrets in `release` environment | | Homebrew tap | `secrets.HOMEBREW_TAP_TOKEN` | | AUR publish | `secrets.AUR_SSH_KEY` | diff --git a/seed/.github/prompts/classify-pr.prompt.yml b/seed/.github/prompts/classify-pr.prompt.yml deleted file mode 100644 index 4ae0c75..0000000 --- a/seed/.github/prompts/classify-pr.prompt.yml +++ /dev/null @@ -1,41 +0,0 @@ -messages: - - role: system - content: | - You classify pull requests for release note categorization. - 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. - Test-only changes that fix assertions for previously-wrong behavior - count as bug. - - enhancement: new API coverage, new SDK features, new configuration - options, new test coverage, generator/tooling improvements. - If only generated files changed with no bug claim, default to - enhancement. - - documentation: README, CONTRIBUTING, SECURITY, or other docs-only - changes with no runtime behavior change. SDK README updates that - accompany code changes don't count — label the code change. - - 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: 25 - temperature: 0 diff --git a/seed/.github/prompts/detect-breaking.prompt.yml b/seed/.github/prompts/detect-breaking.prompt.yml deleted file mode 100644 index a6d5957..0000000 --- a/seed/.github/prompts/detect-breaking.prompt.yml +++ /dev/null @@ -1,34 +0,0 @@ -messages: - - role: system - content: | - You analyze CLI tool diffs for breaking changes. A breaking change is: - - Removal or rename of a CLI command or subcommand - - Removal or rename of a flag (--flag) - - Change in output format that would break scripts parsing the output - - Change in exit codes - - Removal of environment variable support - - NOT breaking: adding new commands, adding new flags, internal refactors, - test changes, documentation, adding new output fields. - - Respond with a JSON object: - {"breaking": true/false, "items": ["description of each breaking change"]} -model: openai/gpt-4o-mini -responseFormat: json_schema -jsonSchema: |- - { - "name": "breaking_analysis", - "strict": true, - "schema": { - "type": "object", - "properties": { - "breaking": { "type": "boolean" }, - "items": { "type": "array", "items": { "type": "string" } } - }, - "required": ["breaking", "items"], - "additionalProperties": false - } - } -modelParameters: - maxCompletionTokens: 500 - temperature: 0 diff --git a/seed/.github/prompts/summarize-changelog.prompt.yml b/seed/.github/prompts/summarize-changelog.prompt.yml deleted file mode 100644 index be7ef54..0000000 --- a/seed/.github/prompts/summarize-changelog.prompt.yml +++ /dev/null @@ -1,20 +0,0 @@ -messages: - - role: system - content: | - You write release summaries for a CLI tool. Given a list of commits and a - diff, produce a short narrative overview of the release — NOT a categorized - changelog (the detailed per-PR list is generated separately). - - Rules: - - Write 2-4 short paragraphs in plain prose, no bullet lists - - Lead with the most important change; group related changes naturally - - Flag any breaking changes prominently at the top with ⚠️ - - Use imperative voice ("Add", "Fix", not "Added", "Fixed") - - No commit hashes, no PR numbers, no author attributions - - No markdown headings — just paragraphs - - Do NOT wrap output in code fences - - Keep it under 15 lines -model: openai/gpt-4o -modelParameters: - maxCompletionTokens: 1500 - temperature: 0.2 diff --git a/seed/.github/workflows/ai-labeler.yml b/seed/.github/workflows/ai-labeler.yml deleted file mode 100644 index d4668b2..0000000 --- a/seed/.github/workflows/ai-labeler.yml +++ /dev/null @@ -1,241 +0,0 @@ -name: Classify PR - -on: - pull_request_target: # zizmor: ignore[dangerous-triggers] -- required for write access to PRs from forks; workflow only runs trusted actions and gh CLI commands, no PR code is checked out or executed - types: [opened, synchronize, reopened] - -concurrency: - group: classify-pr-${{ github.event.pull_request.number }} - cancel-in-progress: true - -permissions: {} - -jobs: - classify: - runs-on: ubuntu-latest - permissions: - contents: read - issues: write - models: read - pull-requests: write - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Build prompt - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR: ${{ github.event.pull_request.number }} - run: | - 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 - - # Compose user message - { - printf 'PR #%s: %s\n' "$PR" "$(cat /tmp/pr-title.txt)" - echo "" - cat /tmp/pr-body.txt - echo "" - echo "Diff (truncated):" - head -c 100000 /tmp/pr.diff - } > /tmp/user-message.txt - - # Build full prompt YAML: splice user message into the messages array - python3 -c " - with open('.github/prompts/classify-pr.prompt.yml') as f: - lines = f.readlines() - with open('/tmp/user-message.txt') as f: - user_msg = f.read() - - insert_at = len(lines) - for i, line in enumerate(lines): - if i == 0: - continue - if line.strip() and not line[0].isspace(): - insert_at = i - break - - entry = [' - role: user\n', ' content: |\n'] - for ln in user_msg.splitlines(): - entry.append(' ' + ln + '\n') - - lines[insert_at:insert_at] = entry - with open('/tmp/prompt.yml', 'w') as f: - f.writelines(lines) - - try: - import yaml - doc = yaml.safe_load(open('/tmp/prompt.yml')) - assert doc['messages'][-1]['role'] == 'user', 'prompt splice failed' - except ImportError: - pass - " - - - name: Classify - id: classify - uses: actions/ai-inference@e09e65981758de8b2fdab13c2bfb7c7d5493b0b6 # v2.0.7 - with: - prompt-file: /tmp/prompt.yml - - - name: Apply label - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - RESPONSE_FILE: ${{ steps.classify.outputs.response-file }} - PR: ${{ github.event.pull_request.number }} - run: | - 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 - 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 - gh pr edit "$PR" --remove-label "$L" 2>/dev/null || true - fi - done - if ! echo "$CURRENT" | grep -qx "$LABEL"; then - gh pr edit "$PR" --add-label "$LABEL" 2>/dev/null || true - fi - - breaking: - runs-on: ubuntu-latest - permissions: - contents: read - issues: write - models: read - pull-requests: write - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Build prompt - id: cmd-diff - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR: ${{ github.event.pull_request.number }} - run: | - # CLI command surface files - PATTERNS=( - "internal/commands/*.go" - "internal/cli/root.go" - ) - gh pr diff "$PR" > /tmp/full.diff - - # Filter diff to only command surface files - python3 -c " - import sys, re, fnmatch - diff = open('/tmp/full.diff').read() - patterns = sys.argv[1:] - sections = re.split(r'(?=^diff --git)', diff, flags=re.MULTILINE) - for s in sections: - m = re.match(r'diff --git a/(\S+)', s) - if m: - path = m.group(1) - if any(fnmatch.fnmatch(path, p) for p in patterns): - sys.stdout.write(s) - " "${PATTERNS[@]}" > /tmp/cmd.diff - - if [ ! -s /tmp/cmd.diff ]; then - echo "skip=true" >> "$GITHUB_OUTPUT" - else - TITLE=$(gh pr view "$PR" --json title --jq .title) - - { - printf 'PR #%s: %s\n' "$PR" "$TITLE" - echo "" - echo "Diff of CLI command surface files:" - head -c 100000 /tmp/cmd.diff - } > /tmp/user-message.txt - - python3 -c " - with open('.github/prompts/detect-breaking.prompt.yml') as f: - lines = f.readlines() - with open('/tmp/user-message.txt') as f: - user_msg = f.read() - - insert_at = len(lines) - for i, line in enumerate(lines): - if i == 0: - continue - if line.strip() and not line[0].isspace(): - insert_at = i - break - - entry = [' - role: user\n', ' content: |\n'] - for ln in user_msg.splitlines(): - entry.append(' ' + ln + '\n') - - lines[insert_at:insert_at] = entry - with open('/tmp/prompt.yml', 'w') as f: - f.writelines(lines) - - try: - import yaml - doc = yaml.safe_load(open('/tmp/prompt.yml')) - assert doc['messages'][-1]['role'] == 'user', 'prompt splice failed' - except ImportError: - pass - " - echo "skip=false" >> "$GITHUB_OUTPUT" - fi - - - name: Detect breaking changes - if: steps.cmd-diff.outputs.skip != 'true' - id: detect - uses: actions/ai-inference@e09e65981758de8b2fdab13c2bfb7c7d5493b0b6 # v2.0.7 - with: - prompt-file: /tmp/prompt.yml - - - name: Apply breaking label - 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: | - if [ -z "$RESPONSE_FILE" ] || [ ! -f "$RESPONSE_FILE" ]; then - echo "::warning::Model response file is missing; skipping breaking label." - exit 0 - fi - if ! jq empty "$RESPONSE_FILE" 2>/dev/null; then - echo "::warning::Model response is not valid JSON; skipping breaking label." - { - echo "## Breaking change detection failed" - echo "Model returned invalid JSON. Breaking label was **not** applied." - if [ -s "$RESPONSE_FILE" ]; then - echo '```' - cat "$RESPONSE_FILE" - echo '```' - fi - } >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi - BREAKING=$(jq -r '.breaking' "$RESPONSE_FILE") - - if [ "$BREAKING" = "true" ]; then - ITEMS=$(jq -r '.items[]' "$RESPONSE_FILE" | sed 's/^/- /') - gh label create breaking --color "B60205" 2>/dev/null || true - gh pr edit "$PR" --add-label "breaking" - - { - echo "**Potential breaking changes detected:**" - echo "" - echo "$ITEMS" - echo "" - echo "_Review carefully before merging. Consider a major version bump._" - } > /tmp/breaking-comment.md - - EXISTING=$(gh pr view "$PR" --json comments --jq '.comments[] | select(.body | startswith("**Potential breaking")) | .id' | head -1) - if [ -n "$EXISTING" ]; then - gh api graphql -f query="mutation { updateIssueComment(input: {id: \"$EXISTING\", body: $(jq -Rs . /tmp/breaking-comment.md)}) { issueComment { id } } }" - else - gh pr comment "$PR" --body-file /tmp/breaking-comment.md - fi - else - gh pr edit "$PR" --remove-label "breaking" 2>/dev/null || true - fi diff --git a/seed/.github/workflows/release.yml b/seed/.github/workflows/release.yml index 5013de0..e985827 100644 --- a/seed/.github/workflows/release.yml +++ b/seed/.github/workflows/release.yml @@ -131,7 +131,6 @@ jobs: contents: write id-token: write attestations: write - models: read env: HAS_MACOS_SIGNING: ${{ secrets.MACOS_SIGN_P12 && 'true' || '' }} HAS_AUR_KEY: ${{ secrets.AUR_SSH_KEY && 'true' || '' }} @@ -204,72 +203,6 @@ jobs: - name: Install Syft uses: anchore/sbom-action/download-syft@17ae1740179002c89186b61233e0f892c3118b11 # v0.23.0 - # Configure vars.ENABLE_AI_CHANGELOG=true plus models:read permission to enable AI changelog - - name: Build changelog context - if: vars.ENABLE_AI_CHANGELOG == 'true' - run: | - PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") - DIFF_FILE=/tmp/diff.txt - if [ -z "$PREV_TAG" ]; then - COMMITS=$(git log --oneline --no-decorate) - git diff --stat 4b825dc642cb6eb9a060e54bf899d69f82a3ef17 HEAD > "$DIFF_FILE" - else - COMMITS=$(git log --oneline --no-decorate "${PREV_TAG}..HEAD") - git diff "${PREV_TAG}..HEAD" -- '*.go' 'go.mod' > "$DIFF_FILE" - fi - { - echo "Commits:" - echo "$COMMITS" - echo "" - echo "Diff summary:" - head -c 80000 "$DIFF_FILE" - } > /tmp/user-message.txt - # Splice into prompt YAML - python3 -c " - with open('.github/prompts/summarize-changelog.prompt.yml') as f: - lines = f.readlines() - with open('/tmp/user-message.txt') as f: - user_msg = f.read() - insert_at = len(lines) - for i, line in enumerate(lines): - if i == 0: continue - if line.strip() and not line[0].isspace(): - insert_at = i - break - entry = [' - role: user\n', ' content: |\n'] - for ln in user_msg.splitlines(): - entry.append(' ' + ln + '\n') - lines[insert_at:insert_at] = entry - with open('/tmp/prompt.yml', 'w') as f: - f.writelines(lines) - try: - import yaml - doc = yaml.safe_load(open('/tmp/prompt.yml')) - assert doc['messages'][-1]['role'] == 'user', 'prompt splice failed' - except ImportError: - pass - " - continue-on-error: true - - - name: Generate AI changelog - if: vars.ENABLE_AI_CHANGELOG == 'true' - id: ai-changelog - uses: actions/ai-inference@e09e65981758de8b2fdab13c2bfb7c7d5493b0b6 # v2.0.7 - continue-on-error: true - with: - prompt-file: /tmp/prompt.yml - - - name: Set changelog path - id: changelog - if: vars.ENABLE_AI_CHANGELOG == 'true' - env: - RESPONSE_FILE: ${{ steps.ai-changelog.outputs.response-file }} - run: | - if [ -n "$RESPONSE_FILE" ] && [ -f "$RESPONSE_FILE" ]; then - sed -i '/^```\(markdown\)\?$/d' "$RESPONSE_FILE" - echo "file=$RESPONSE_FILE" >> "$GITHUB_OUTPUT" - fi - # Configure secrets.MACOS_SIGN_P12 (plus MACOS_SIGN_PASSWORD, MACOS_NOTARY_KEY, # MACOS_NOTARY_KEY_ID, MACOS_NOTARY_ISSUER_ID) to enable macOS notarization - name: Verify macOS signing secrets @@ -302,7 +235,6 @@ jobs: - name: Run GoReleaser env: - CHANGELOG_FILE: ${{ steps.changelog.outputs.file }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} HOMEBREW_TAP_TOKEN: ${{ steps.sdk-token.outputs.token }} MACOS_SIGN_P12: ${{ secrets.MACOS_SIGN_P12 }} @@ -310,13 +242,7 @@ jobs: MACOS_NOTARY_KEY: ${{ secrets.MACOS_NOTARY_KEY }} MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} - run: | - RELEASE_CHANGELOG="" - if [ -n "$CHANGELOG_FILE" ] && [ -f "$CHANGELOG_FILE" ]; then - RELEASE_CHANGELOG=$(cat "$CHANGELOG_FILE") - fi - export RELEASE_CHANGELOG - goreleaser release --clean + run: goreleaser release --clean - name: Attest build provenance uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2 diff --git a/seed/.goreleaser.yaml b/seed/.goreleaser.yaml index a332d63..ce9f7b9 100644 --- a/seed/.goreleaser.yaml +++ b/seed/.goreleaser.yaml @@ -65,10 +65,6 @@ release: prerelease: auto name_template: "{{ .ProjectName }} v{{ .Version }}" header: | - {{ if .Env.RELEASE_CHANGELOG }}{{ .Env.RELEASE_CHANGELOG }} - - --- - {{ end }} ### Install ``` diff --git a/seed/RELEASING.md.tmpl b/seed/RELEASING.md.tmpl index 1aba6bc..520e5e8 100644 --- a/seed/RELEASING.md.tmpl +++ b/seed/RELEASING.md.tmpl @@ -24,7 +24,7 @@ make release VERSION=0.1.0 DRY_RUN=1 - Builds binaries for all platforms (darwin, linux, windows, freebsd, openbsd x amd64/arm64) - Signs checksums with cosign (keyless via Sigstore OIDC) - Generates SBOM for supply chain transparency - - Optional: AI changelog, macOS notarization, Homebrew tap, AUR publish + - Optional: macOS notarization, Homebrew tap, AUR publish ## Versioning @@ -51,7 +51,6 @@ vars are added. | Security scan | always | none | on | | Test gate | always | none | on | | PGO profile | always (fallback) | none | on | -| AI changelog | `vars.ENABLE_AI_CHANGELOG == 'true'` | `models: read` permission | off | | macOS notarization | `secrets.MACOS_SIGN_P12 != ''` | 5 macOS secrets | off | | Homebrew tap | `secrets.HOMEBREW_TAP_TOKEN != ''` | `HOMEBREW_TAP_TOKEN` | off | | AUR publish | `secrets.AUR_SSH_KEY != ''` | `AUR_SSH_KEY` | off |