Scheduled Release #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Scheduled Release | |
| # Automated release pipeline for gptme. | |
| # - Runs twice weekly (Mon + Thu at noon UTC) to create dev pre-releases | |
| # - Can be manually triggered for dev, patch, or minor releases | |
| # - Dev releases use `.devYYYYMMDD` suffix and are marked as pre-releases | |
| # - All releases get structured changelogs via build_changelog.py | |
| # (dev: since last tag, stable: since last stable release) | |
| # | |
| # Scripts shared with `make release` / `make release-dev`: | |
| # - scripts/bump_version.sh — version bump, commit, tag | |
| # - scripts/publish_release.sh — push, GH release, PyPI publish | |
| on: | |
| schedule: | |
| # Twice weekly: Monday and Thursday at 12:00 UTC | |
| - cron: '0 12 * * 1,4' | |
| workflow_dispatch: | |
| inputs: | |
| release_type: | |
| description: 'Release type' | |
| required: true | |
| default: 'dev' | |
| type: choice | |
| options: | |
| - dev # Development pre-release (.devYYYYMMDD) | |
| - patch # Stable patch release (x.y.Z+1) | |
| - minor # Stable minor release (x.Y+1.0) | |
| permissions: | |
| contents: write | |
| actions: read | |
| concurrency: | |
| group: scheduled-release | |
| cancel-in-progress: false | |
| jobs: | |
| check: | |
| name: Pre-flight checks | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for changes and CI status | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| # Find last stable release tag (no pre-release suffix) | |
| LAST_STABLE=$(git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1) | |
| # Find last tag of any kind | |
| LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| COMMITS_SINCE_TAG=0 | |
| if [ -n "$LAST_TAG" ]; then | |
| COMMITS_SINCE_TAG=$(git rev-list "${LAST_TAG}..HEAD" --count) | |
| fi | |
| echo "last_stable=$LAST_STABLE" >> "$GITHUB_OUTPUT" | |
| echo "last_tag=$LAST_TAG" >> "$GITHUB_OUTPUT" | |
| echo "commits=$COMMITS_SINCE_TAG" >> "$GITHUB_OUTPUT" | |
| echo "Last stable: $LAST_STABLE | Last tag: $LAST_TAG | Commits since tag: $COMMITS_SINCE_TAG" | |
| # Skip if no new commits | |
| if [ "$COMMITS_SINCE_TAG" -eq 0 ]; then | |
| echo "No new commits since $LAST_TAG — skipping release." | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Verify CI is green on HEAD | |
| HEAD_SHA=$(git rev-parse HEAD) | |
| echo "Checking CI status for $HEAD_SHA..." | |
| # Check combined commit status (covers both status checks and check runs) | |
| # Use check-runs API which covers GitHub Actions | |
| CONCLUSION=$(gh api "repos/${{ github.repository }}/commits/${HEAD_SHA}/check-suites" \ | |
| --jq '[.check_suites[] | select(.app.slug == "github-actions")] | map(.conclusion) | unique | .[]' 2>/dev/null || echo "unknown") | |
| echo "CI conclusions: $CONCLUSION" | |
| # If any suite is still running or has failed, skip | |
| if echo "$CONCLUSION" | grep -qE "failure|action_required|timed_out"; then | |
| echo "CI has failures on HEAD — skipping release." | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if echo "$CONCLUSION" | grep -qE "null|pending"; then | |
| echo "CI is still running on HEAD — skipping release." | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Require explicit success — skip if unknown or empty (API failure) | |
| if [ -z "$CONCLUSION" ] || [ "$CONCLUSION" = "unknown" ]; then | |
| echo "CI status unavailable on HEAD — skipping release." | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if ! echo "$CONCLUSION" | grep -q "success"; then | |
| echo "No successful CI checks found on HEAD — skipping release." | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "should_release=true" >> "$GITHUB_OUTPUT" | |
| release: | |
| name: Create release | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: master | |
| fetch-depth: 0 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| - name: Install poetry | |
| run: pipx install poetry | |
| - name: Bump version | |
| id: version | |
| run: | | |
| TYPE="${{ github.event.inputs.release_type || 'dev' }}" | |
| bash scripts/bump_version.sh --type "$TYPE" | |
| - name: Generate changelog | |
| run: | | |
| # Download the shared changelog generator (same as `make dist/CHANGELOG.md`) | |
| wget -q -O scripts/build_changelog.py \ | |
| https://raw.githubusercontent.com/ActivityWatch/activitywatch/master/scripts/build_changelog.py | |
| chmod +x scripts/build_changelog.py | |
| pip install -q requests | |
| TAG="${{ steps.version.outputs.tag }}" | |
| PRERELEASE="${{ steps.version.outputs.prerelease }}" | |
| # Use appropriate range: dev→since last tag, stable→since last stable | |
| if [ "$PRERELEASE" = "true" ]; then | |
| SINCE="${{ steps.version.outputs.last_tag }}" | |
| else | |
| SINCE="${{ steps.version.outputs.last_stable }}" | |
| fi | |
| echo "Generating changelog: ${SINCE}...${TAG}" | |
| python3 scripts/build_changelog.py \ | |
| --range "${SINCE}...${TAG}" \ | |
| --project-title gptme \ | |
| --org gptme \ | |
| --repo gptme \ | |
| --output /tmp/changelog.md \ | |
| --add-version-header | |
| echo "--- Generated changelog preview ---" | |
| head -50 /tmp/changelog.md | |
| - name: Publish release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} | |
| run: | | |
| bash scripts/publish_release.sh --publish-pypi --notes-file /tmp/changelog.md |