Skip to content

Changelog Draft

Changelog Draft #28

name: Changelog Draft
on:
schedule:
- cron: '0 13 * * 5'
- cron: '0 14 * * 5'
workflow_dispatch:
inputs:
since:
description: Optional ISO timestamp/date lower bound
required: false
type: string
until:
description: Optional ISO timestamp/date upper bound
required: false
type: string
bootstrap_since:
description: Optional lower bound used to cap automatic lookback
required: false
type: string
open_pr:
description: Open a draft PR after generating the changelog
required: false
default: true
type: boolean
permissions:
contents: write
pull-requests: write
jobs:
generate-changelog:
runs-on: ubuntu-latest
steps:
- name: Skip scheduled run if a changelog draft PR is already open
id: gate
shell: bash
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
should_run=true
# Scheduled runs are idempotent rather than time-gated: GitHub's
# scheduler can delay a cron by an hour or more, so we can't rely on
# the wall-clock execution time. Two crons fire each Friday (one per
# DST offset) for redundancy; whichever runs first does the work, and
# any later run skips once a draft PR exists. Manual dispatch always
# runs so drafts can be regenerated on demand.
if [ "${{ github.event_name }}" = "schedule" ]; then
open_drafts="$(gh pr list \
--repo "$GITHUB_REPOSITORY" \
--state open \
--json headRefName \
--jq '[.[] | select(.headRefName | startswith("automation/changelog-"))] | length')"
if [ "$open_drafts" != "0" ]; then
echo "Found $open_drafts open changelog draft PR(s); skipping."
should_run=false
fi
fi
echo "should_run=$should_run" >> "$GITHUB_OUTPUT"
- name: Checkout code
if: steps.gate.outputs.should_run == 'true'
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Bun
if: steps.gate.outputs.should_run == 'true'
uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- name: Install dependencies
if: steps.gate.outputs.should_run == 'true'
run: bun install --frozen-lockfile
- name: Generate changelog draft
if: steps.gate.outputs.should_run == 'true'
id: generate
env:
CHANGELOG_GITHUB_TOKEN: ${{ secrets.CHANGELOG_GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
CHANGELOG_SINCE: ${{ inputs.since }}
CHANGELOG_UNTIL: ${{ inputs.until }}
CHANGELOG_BOOTSTRAP_SINCE: ${{ inputs.bootstrap_since || vars.CHANGELOG_BOOTSTRAP_SINCE }}
run: bun run generate-changelog-draft
- name: Run link validation
if: steps.gate.outputs.should_run == 'true' && steps.generate.outputs.has_changes == 'true'
run: bun run validate-links
- name: Upload generated draft artifacts
if: steps.gate.outputs.should_run == 'true' && steps.generate.outputs.has_changes == 'true'
uses: actions/upload-artifact@v4
with:
name: changelog-draft-${{ github.run_id }}
path: |
${{ steps.generate.outputs.draft_path }}
${{ steps.generate.outputs.pr_body_path }}
- name: Create draft pull request
if: steps.gate.outputs.should_run == 'true' && steps.generate.outputs.has_changes == 'true' && (github.event_name != 'workflow_dispatch' || inputs.open_pr)
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.CHANGELOG_GITHUB_TOKEN != '' && secrets.CHANGELOG_GITHUB_TOKEN || github.token }}
base: main
branch: ${{ steps.generate.outputs.branch_name }}
delete-branch: true
title: ${{ steps.generate.outputs.pr_title }}
commit-message: ${{ steps.generate.outputs.commit_message }}
body-path: ${{ steps.generate.outputs.pr_body_path }}
draft: true
add-paths: |
content/docs/changelog/**
public/changelog/llms.txt