From 9d10de51c939cf5652df27056cf56ef6a21096eb Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Fri, 19 Dec 2025 19:22:01 +0900 Subject: [PATCH] feat(ci): implement automatic draft release management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add draft-release job in ci.yml that creates/updates draft release with tag 'next' and title 'Upcoming Changes 🍿' - Generate release notes based on commits since latest published release - Add step in publish.yml to delete draft release after successful publish - Follows indentcorp/backend pattern for automatic draft release management 🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode) --- .github/workflows/ci.yml | 58 +++++++++++++++++++++++++++++++++++ .github/workflows/publish.yml | 5 +++ 2 files changed, 63 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a189d5..9c0eca4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,3 +67,61 @@ jobs: run: | test -f dist/index.js || (echo "ERROR: dist/index.js not found!" && exit 1) test -f dist/index.d.ts || (echo "ERROR: dist/index.d.ts not found!" && exit 1) + + draft-release: + runs-on: ubuntu-latest + needs: [build] + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get latest published release tag + id: latest-release + run: | + LATEST_TAG=$(gh release list --exclude-drafts --exclude-pre-releases --limit 1 --json tagName --jq '.[0].tagName // empty') + echo "tag=${LATEST_TAG}" >> $GITHUB_OUTPUT + echo "Latest published release: ${LATEST_TAG:-none}" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Generate release notes + id: notes + run: | + if [ -n "${{ steps.latest-release.outputs.tag }}" ]; then + NOTES=$(gh api repos/${{ github.repository }}/releases/generate-notes \ + -f tag_name=next \ + -f previous_tag_name=${{ steps.latest-release.outputs.tag }} \ + --jq '.body') + else + NOTES="Initial release" + fi + echo "notes<> $GITHUB_OUTPUT + echo "$NOTES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create or update draft release + run: | + EXISTING_DRAFT=$(gh release list --json tagName,isDraft --jq '.[] | select(.isDraft == true and .tagName == "next") | .tagName') + + if [ -n "$EXISTING_DRAFT" ]; then + echo "Updating existing draft release..." + gh release edit next \ + --title "Upcoming Changes 🍿" \ + --notes "${{ steps.notes.outputs.notes }}" \ + --draft + else + echo "Creating new draft release..." + gh release create next \ + --title "Upcoming Changes 🍿" \ + --notes "${{ steps.notes.outputs.notes }}" \ + --draft \ + --target ${{ github.sha }} + fi + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6679ad2..751ca23 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -89,3 +89,8 @@ jobs: CI: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_CONFIG_PROVENANCE: true + + - name: Delete draft release + run: gh release delete next --yes 2>/dev/null || echo "No draft release to delete" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}