From dc441ad55f75eae1a546e26ff5e2b8a28a9cedc3 Mon Sep 17 00:00:00 2001 From: Sephiroth Date: Tue, 24 Feb 2026 16:09:39 +0000 Subject: [PATCH] refactor: switch release flow to PR-based approach - create-release.ts now creates release/v{version} branch and PR instead of pushing to main - Workflow auto-creates version tag on main push when tag doesn't exist - Tag push or auto-tag triggers build and release as before --- .github/workflows/slv-remote-build.yml | 57 ++++++++++++++++++++++++-- scripts/create-release.ts | 57 ++++++++++++++++++++------ 2 files changed, 97 insertions(+), 17 deletions(-) diff --git a/.github/workflows/slv-remote-build.yml b/.github/workflows/slv-remote-build.yml index 99df788..521f4fd 100644 --- a/.github/workflows/slv-remote-build.yml +++ b/.github/workflows/slv-remote-build.yml @@ -15,9 +15,47 @@ on: default: "0.6.0" jobs: + check-version-tag: + name: Check and Create Version Tag + if: github.ref == 'refs/heads/main' && github.event_name == 'push' + runs-on: ubuntu-latest + permissions: + contents: write + outputs: + tag_created: ${{ steps.check_tag.outputs.tag_created }} + version: ${{ steps.check_tag.outputs.version }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check and create version tag + id: check_tag + run: | + VERSION=$(grep -oP "VERSION = '\K[0-9]+\.[0-9]+\.[0-9]+" cmn/constants/version.ts) + echo "version=$VERSION" >> $GITHUB_OUTPUT + if ! git tag -l "v$VERSION" | grep -q .; then + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag "v$VERSION" + git push origin "v$VERSION" + echo "tag_created=true" >> $GITHUB_OUTPUT + echo "Created tag v$VERSION" + else + echo "tag_created=false" >> $GITHUB_OUTPUT + echo "Tag v$VERSION already exists" + fi + build-mac: name: Build macOS Binary - if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + needs: [check-version-tag] + if: | + always() && ( + startsWith(github.ref, 'refs/tags/v') || + github.event_name == 'workflow_dispatch' || + (needs.check-version-tag.result == 'success' && needs.check-version-tag.outputs.tag_created == 'true') + ) runs-on: macos-latest steps: - name: Checkout code @@ -110,7 +148,15 @@ jobs: needs: - test - build-mac - if: success() && (startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') + - check-version-tag + if: | + always() && + needs.test.result == 'success' && + needs.build-mac.result == 'success' && ( + startsWith(github.ref, 'refs/tags/v') || + github.event_name == 'workflow_dispatch' || + (needs.check-version-tag.result == 'success' && needs.check-version-tag.outputs.tag_created == 'true') + ) runs-on: [self-hosted] permissions: contents: write @@ -156,11 +202,13 @@ jobs: python -m pip install --upgrade pip pip install ansible - - name: Extract version from tag or input + - name: Extract version from tag, input, or version file id: get_version run: | if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV + elif [[ "${{ needs.check-version-tag.outputs.tag_created }}" == "true" ]]; then + echo "VERSION=${{ needs.check-version-tag.outputs.version }}" >> $GITHUB_ENV else echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV fi @@ -213,8 +261,9 @@ jobs: - name: Create GitHub Release uses: softprops/action-gh-release@v1 - if: startsWith(github.ref, 'refs/tags/v') + if: startsWith(github.ref, 'refs/tags/v') || needs.check-version-tag.outputs.tag_created == 'true' with: + tag_name: v${{ env.VERSION }} files: | dist/slv-x86_64-unknown-linux-gnu-exe.tar.gz dist/slv-x86_64-apple-darwin-exe.tar.gz diff --git a/scripts/create-release.ts b/scripts/create-release.ts index d52c7a7..e2c906a 100644 --- a/scripts/create-release.ts +++ b/scripts/create-release.ts @@ -68,19 +68,50 @@ async function createRelease() { await spawnSync(`git commit -m "Release v${newVersion}"`) console.log('✅ Changes committed') - // 4. Create a tag - console.log(`Creating tag v${newVersion}...`) - await spawnSync(`git tag v${newVersion}`) - console.log(`✅ Tag v${newVersion} created`) - - // 5. Push the changes and tag - console.log('Pushing changes and tag...') - await spawnSync('git push origin main') - await spawnSync(`git push origin v${newVersion}`) - console.log('✅ Changes and tag pushed') - - console.log(`\n✅ Release v${newVersion} created successfully!`) - console.log('GitHub Actions will now build and publish the release.') + // 4. Create release branch and push + const branchName = `release/v${newVersion}` + console.log(`Creating branch ${branchName}...`) + await spawnSync(`git checkout -b ${branchName}`) + console.log(`✅ Branch ${branchName} created`) + + console.log(`Pushing branch ${branchName}...`) + await spawnSync(`git push origin ${branchName}`) + console.log(`✅ Branch ${branchName} pushed`) + + // 5. Create Pull Request via GitHub API + console.log('Creating Pull Request...') + const ghToken = Deno.env.get('GITHUB_TOKEN') || '' + if (!ghToken) { + console.error('Error: GITHUB_TOKEN environment variable is required for PR creation') + Deno.exit(1) + } + + const prBody = `## Release v${newVersion}\n\nThis PR updates the version to v${newVersion}.\n\nWhen merged, GitHub Actions will automatically create the \`v${newVersion}\` tag and trigger the build & release process.` + + const prResponse = await fetch('https://api.github.com/repos/ValidatorsDAO/slv/pulls', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${ghToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + title: `Release v${newVersion}`, + body: prBody, + head: branchName, + base: 'main', + }), + }) + + const prData = await prResponse.json() + if (prResponse.ok) { + console.log(`✅ Pull Request created: ${prData.html_url}`) + } else { + console.error(`Error creating PR: ${JSON.stringify(prData)}`) + Deno.exit(1) + } + + console.log(`\n✅ Release v${newVersion} PR created successfully!`) + console.log('Once the PR is merged, GitHub Actions will automatically tag and release.') } // Run the release function