chore: promote main (i.e. staging) to production #281
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
| # Manual Release Workflow (Orchestrator) | |
| # | |
| # This workflow orchestrates both web and desktop releases when triggered. | |
| # It runs semantic-release once and then calls both release workflows. | |
| # | |
| # Role in release workflow: | |
| # - Triggered by push to release branch or manual dispatch | |
| # - Creates GitHub releases with semantic versioning once | |
| # - Calls release-web.yaml for web deployment on ref==release | |
| # - Syncs release version to main branch if ref==release | |
| # - Calls release-desktop.yaml for desktop app builds on ref==release | |
| # - Coordinates both releases to use same version | |
| name: Release | |
| on: | |
| push: | |
| branches: | |
| - release | |
| - main | |
| paths-ignore: | |
| - 'docs/**' | |
| - '**.md' | |
| - '.vscode/**' | |
| workflow_dispatch: | |
| env: | |
| # Define whether this is a production release (release branch) | |
| IS_PRODUCTION_RELEASE: ${{ github.ref_name == 'release' }} | |
| concurrency: orchestrate-release | |
| jobs: | |
| ci: | |
| name: CI | |
| uses: makerxstudio/shared-config/.github/workflows/node-ci.yml@main | |
| with: | |
| working-directory: . | |
| node-version: 20.x | |
| audit-script: npm run audit | |
| compile-script: npm run check-types | |
| test-script: npm run test | |
| pre-test-script: | | |
| pipx install algokit | |
| algokit localnet start | |
| npx --yes wait-on tcp:4001 -t 30000 | |
| build-and-release: | |
| name: Build and Create Release | |
| needs: [ci] | |
| runs-on: ubuntu-latest | |
| outputs: | |
| release-version: ${{ steps.generate-release-version.outputs.release-version }} | |
| release-tag: ${{ steps.generate-release-version.outputs.release-tag }} | |
| release-id: ${{ steps.generate-release-version.outputs.release-id }} | |
| crabnebula-release-id: ${{ steps.get-crabnebula-release-id.outputs.release-id }} | |
| steps: | |
| - name: Generate bot token | |
| uses: actions/create-github-app-token@v1 | |
| id: app_token | |
| with: | |
| app-id: ${{ secrets.BOT_ID }} | |
| private-key: ${{ secrets.BOT_SK }} | |
| - uses: actions/checkout@v4 | |
| with: | |
| token: ${{ steps.app_token.outputs.token }} | |
| fetch-depth: 0 | |
| - name: Setup node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| registry-url: 'https://npm.pkg.github.com' | |
| scope: '@algorandfoundation' | |
| cache: 'npm' | |
| - name: Install npm dependencies | |
| run: npm ci --ignore-scripts | |
| env: | |
| NODE_AUTH_TOKEN: ${{ steps.app_token.outputs.token }} | |
| # Let scripts run without the token | |
| - run: npm rebuild | |
| - name: Validate CrabNebula API key | |
| id: validate-cn-api | |
| uses: crabnebula-dev/[email protected] | |
| with: | |
| command: release list ${{ secrets.CN_ORG_NAME }}/${{ secrets.CN_APP_NAME }} --limit 1 | |
| api-key: ${{ secrets.CN_API_KEY }} | |
| continue-on-error: false | |
| - name: Generate release version | |
| uses: ./.github/actions/generate-release-version | |
| id: generate-release-version | |
| with: | |
| # Use bot token for semantic-release operations | |
| github-token: ${{ steps.app_token.outputs.token }} | |
| node-version: 20 | |
| - name: Create .env file with production values | |
| if: env.IS_PRODUCTION_RELEASE == 'true' | |
| run: | | |
| cat > .env << EOF | |
| VITE_DISPENSER_AUTH0_DOMAIN=dispenser-prod.eu.auth0.com | |
| VITE_DISPENSER_AUTH0_CLIENT_ID=Cg13HjvSV45pMme4dnK9yVJde8tVeDaM | |
| VITE_DISPENSER_AUTH0_AUDIENCE=api-prod-dispenser-user | |
| VITE_TESTNET_DISPENSER_API_URL=https://api.dispenser.algorandfoundation.tools | |
| VITE_TESTNET_DISPENSER_ADDRESS=Z5GPJQCHVU54C2I4FLYNE2XHRQRL5OV2GPJQKXJFMW34CRIN2KRQFXF7DI | |
| EOF | |
| - name: Create .env file with dev values | |
| if: env.IS_PRODUCTION_RELEASE != 'true' | |
| run: cp .env.sample .env | |
| - name: Build application | |
| run: npm run build | |
| - name: Upload app build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: app-build | |
| path: dist/ | |
| retention-days: 1 | |
| - name: Validate release outputs | |
| run: | | |
| echo "generate-release-version outputs:" | |
| echo "release-version: ${{ steps.generate-release-version.outputs.release-version }}" | |
| echo "release-tag: ${{ steps.generate-release-version.outputs.release-tag }}" | |
| echo "release-notes: ${{ steps.generate-release-version.outputs.release-notes }}" | |
| echo "release-channel: ${{ steps.generate-release-version.outputs.release-channel }}" | |
| # Validate required outputs | |
| if [ -z "${{ steps.generate-release-version.outputs.release-version }}" ]; then | |
| echo "❌ Error: release-version is empty" | |
| exit 1 | |
| fi | |
| if [ -z "${{ steps.generate-release-version.outputs.release-tag }}" ]; then | |
| echo "❌ Error: release-tag is empty" | |
| exit 1 | |
| fi | |
| echo "✅ All required release outputs are present" | |
| - name: Create draft CrabNebula release | |
| uses: crabnebula-dev/[email protected] | |
| id: create-crabnebula-release | |
| if: env.IS_PRODUCTION_RELEASE == 'true' | |
| with: | |
| command: release draft ${{ secrets.CN_ORG_NAME }}/${{ secrets.CN_APP_NAME }} ${{ steps.generate-release-version.outputs.release-version }} ${{ env.IS_PRODUCTION_RELEASE != 'true' && '--channel beta' || '' }} | |
| api-key: ${{ secrets.CN_API_KEY }} | |
| - name: Get CrabNebula release ID | |
| id: get-crabnebula-release-id | |
| if: env.IS_PRODUCTION_RELEASE == 'true' | |
| run: echo "release-id=${{ fromJson(steps.create-crabnebula-release.outputs.stdout).id }}" >> $GITHUB_OUTPUT | |
| sync-release-to-main: | |
| name: Sync Release Version to Main | |
| runs-on: ubuntu-latest | |
| needs: [build-and-release] | |
| if: github.ref_name == 'release' | |
| steps: | |
| - name: Generate bot token | |
| uses: actions/create-github-app-token@v1 | |
| id: app_token | |
| with: | |
| app-id: ${{ secrets.BOT_ID }} | |
| private-key: ${{ secrets.BOT_SK }} | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ steps.app_token.outputs.token }} | |
| - name: Set Git user as GitHub actions | |
| run: git config --global user.email "179917785+engineering-ci[bot]@users.noreply.github.com" && git config --global user.name "engineering-ci[bot]" | |
| - name: Sync stable release back to main | |
| run: | | |
| VERSION="${{ needs.build-and-release.outputs.release-version }}" | |
| TAG="${{ needs.build-and-release.outputs.release-tag }}" | |
| echo "Syncing release version $VERSION (tag: $TAG) back to main..." | |
| # Get the latest state of both branches | |
| git fetch origin | |
| git checkout release | |
| git pull origin release | |
| # Switch to main and merge the release commit | |
| git checkout main | |
| git pull origin main | |
| # Find the commit that has the version tag | |
| RELEASE_COMMIT=$(git rev-list -n 1 $TAG) | |
| echo "Release commit: $RELEASE_COMMIT" | |
| # Cherry-pick the release commit into main (without merge history) | |
| # Use -X theirs to automatically resolve conflicts in favor of the release branch | |
| git cherry-pick $RELEASE_COMMIT --no-commit -X theirs | |
| git commit -m "chore: sync stable release $VERSION to main [skip ci] | |
| This commit syncs the stable release version back to main branch | |
| to ensure the next beta cycle starts from the correct version base. | |
| Release: $VERSION | |
| Tag: $TAG" | |
| # Create the same tag on main branch (force move if it exists) | |
| git tag -f $TAG | |
| # Push the updated main branch and tags | |
| git push origin main | |
| git push origin $TAG -f | |
| echo "✅ Successfully synced $VERSION to main branch" | |
| release-web: | |
| name: Release Web | |
| needs: [build-and-release] | |
| if: github.ref_name == 'release' | |
| uses: ./.github/workflows/release-web.yaml | |
| with: | |
| version: ${{ needs.build-and-release.outputs.release-version }} | |
| secrets: inherit | |
| release-desktop: | |
| name: Release Desktop | |
| needs: [build-and-release] | |
| if: github.ref_name == 'release' | |
| uses: ./.github/workflows/release-desktop.yaml | |
| with: | |
| version: ${{ needs.build-and-release.outputs.release-version }} | |
| production-release: ${{ github.ref_name == 'release' }} | |
| release-tag: ${{ needs.build-and-release.outputs.release-tag }} | |
| crabnebula-release-id: ${{ needs.build-and-release.outputs.crabnebula-release-id }} | |
| secrets: inherit |