diff --git a/.github/workflows/deploy-stage.yml b/.github/workflows/deploy-stage.yml deleted file mode 100644 index 4ca30ba1..00000000 --- a/.github/workflows/deploy-stage.yml +++ /dev/null @@ -1,212 +0,0 @@ -name: Stage Deployment - -on: - push: - branches: [main] - -jobs: - detect-changes: - name: Detect Changes - runs-on: ubuntu-latest - outputs: - web: ${{ steps.filter.outputs.web }} - admin: ${{ steps.filter.outputs.admin }} - shared: ${{ steps.filter.outputs.shared }} - root: ${{ steps.filter.outputs.root }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Check changed files - uses: dorny/paths-filter@v3 - id: filter - with: - filters: | - web: - - 'apps/web/**' - admin: - - 'apps/admin/**' - shared: - - 'packages/**' - root: - - 'package.json' - - 'pnpm-lock.yaml' - - 'pnpm-workspace.yaml' - - 'turbo.json' - - '.github/workflows/**' - - deploy-web-stage: - name: Deploy Web (Stage) - runs-on: ubuntu-latest - needs: detect-changes - if: needs.detect-changes.outputs.web == 'true' || needs.detect-changes.outputs.shared == 'true' || needs.detect-changes.outputs.root == 'true' - env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_WEB_STAGE }} - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v3 - with: - version: 9 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "22.x" - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Install Vercel CLI - run: pnpm add --global vercel@latest - - - name: Turbo cached build (web) - run: pnpm turbo run build --filter=@solid-connect/web - - - name: Prepare Vercel project metadata (web) - run: | - rm -rf .vercel - mkdir -p .vercel-ci - working-directory: apps/web - - - name: Pull Vercel environment (web stage) - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee .vercel-ci/pull.log - working-directory: apps/web - - - name: Build prebuilt artifacts (web stage) - run: vercel build --yes --target=preview --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee .vercel-ci/build.log - working-directory: apps/web - - - name: Verify prebuilt artifacts (web) - run: | - test -f .vercel/output/config.json - test -d .vercel/output/functions - working-directory: apps/web - - - name: Deploy prebuilt artifacts (web stage) - id: deploy_web - run: | - set -euo pipefail - vercel deploy --prebuilt --target=preview --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee .vercel-ci/deploy.log - URL=$(grep -Eo 'https://[^ ]+\.vercel\.app' .vercel-ci/deploy.log | head -n 1) - if [ -z "$URL" ]; then - echo "Failed to parse deployment URL from Vercel output" >&2 - exit 1 - fi - echo "url=$URL" >> "$GITHUB_OUTPUT" - { - echo "## Web Stage Deployment" - echo "- Status: success" - echo "- URL: $URL" - } >> "$GITHUB_STEP_SUMMARY" - working-directory: apps/web - - - name: Append failure summary (web stage) - if: failure() - run: | - { - echo "## Web Stage Deployment Failed" - echo "- Inspect artifact: web-stage-vercel-logs" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Upload Vercel logs (web stage) - if: always() - uses: actions/upload-artifact@v4 - with: - name: web-stage-vercel-logs - path: apps/web/.vercel-ci/*.log - if-no-files-found: ignore - - deploy-admin-stage: - name: Deploy Admin (Stage) - runs-on: ubuntu-latest - needs: detect-changes - if: needs.detect-changes.outputs.admin == 'true' || needs.detect-changes.outputs.shared == 'true' || needs.detect-changes.outputs.root == 'true' - env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_ADMIN_STAGE }} - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Install pnpm - uses: pnpm/action-setup@v3 - with: - version: 9 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "22.x" - cache: "pnpm" - - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Install Vercel CLI - run: pnpm add --global vercel@latest - - - name: Turbo cached build (admin) - run: pnpm turbo run build --filter=@solid-connect/admin - - - name: Prepare Vercel project metadata (admin) - run: | - rm -rf .vercel - mkdir -p .vercel-ci - working-directory: apps/admin - - - name: Pull Vercel environment (admin stage) - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee .vercel-ci/pull.log - working-directory: apps/admin - - - name: Build prebuilt artifacts (admin stage) - run: vercel build --yes --target=preview --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee .vercel-ci/build.log - working-directory: apps/admin - - - name: Verify prebuilt artifacts (admin) - run: | - test -f .vercel/output/config.json - test -d .vercel/output/functions - working-directory: apps/admin - - - name: Deploy prebuilt artifacts (admin stage) - id: deploy_admin - run: | - set -euo pipefail - vercel deploy --prebuilt --target=preview --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee .vercel-ci/deploy.log - URL=$(grep -Eo 'https://[^ ]+\.vercel\.app' .vercel-ci/deploy.log | head -n 1) - if [ -z "$URL" ]; then - echo "Failed to parse deployment URL from Vercel output" >&2 - exit 1 - fi - echo "url=$URL" >> "$GITHUB_OUTPUT" - { - echo "## Admin Stage Deployment" - echo "- Status: success" - echo "- URL: $URL" - } >> "$GITHUB_STEP_SUMMARY" - working-directory: apps/admin - - - name: Append failure summary (admin stage) - if: failure() - run: | - { - echo "## Admin Stage Deployment Failed" - echo "- Inspect artifact: admin-stage-vercel-logs" - } >> "$GITHUB_STEP_SUMMARY" - - - name: Upload Vercel logs (admin stage) - if: always() - uses: actions/upload-artifact@v4 - with: - name: admin-stage-vercel-logs - path: apps/admin/.vercel-ci/*.log - if-no-files-found: ignore diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 295a78b7..eeda3ad2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,20 @@ -name: Promote Main to Release +name: Promote Main to Release Branches permissions: contents: write on: workflow_dispatch: + inputs: + target: + description: "Promote target" + required: true + default: "both" + type: choice + options: + - both + - web + - admin jobs: generate_tag: @@ -30,7 +40,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} promote_release_branch: - name: Promote main -> release + name: Promote main -> release branch(es) runs-on: ubuntu-latest needs: create_release steps: @@ -39,53 +49,72 @@ jobs: with: fetch-depth: 0 - - name: Promote main branch to release branch + - name: Promote main branch to selected release branch(es) run: | set -euo pipefail git fetch origin main - git fetch origin release || true - MAIN_SHA=$(git rev-parse origin/main) - if git show-ref --verify --quiet refs/remotes/origin/release; then - RELEASE_SHA=$(git rev-parse origin/release) - else - RELEASE_SHA="" - fi + TARGET="${{ github.event.inputs.target }}" - if [ -z "$RELEASE_SHA" ]; then - git push origin origin/main:refs/heads/release - { - echo "## Release Promotion" - echo "- Status: success (release branch created)" - echo "- Promoted main SHA: $MAIN_SHA" - echo "- Target branch: release" - echo "- Note: Vercel production deploy is triggered by release branch update" - } >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi + case "$TARGET" in + web) + RELEASE_BRANCHES="release-web" + ;; + admin) + RELEASE_BRANCHES="release-admin" + ;; + both) + RELEASE_BRANCHES="release-web release-admin" + ;; + *) + echo "Unsupported target: $TARGET" >&2 + exit 1 + ;; + esac - if [ "$MAIN_SHA" = "$RELEASE_SHA" ]; then - { - echo "## Release Promotion" - echo "- Status: skipped (release is already up to date)" - echo "- main: $MAIN_SHA" - } >> "$GITHUB_STEP_SUMMARY" - exit 0 - fi + { + echo "## Release Promotion" + echo "- Selected target: $TARGET" + echo "- Promoted main SHA: $MAIN_SHA" + } >> "$GITHUB_STEP_SUMMARY" - if ! git merge-base --is-ancestor origin/release origin/main; then - echo "release branch is not an ancestor of main. Resolve release history before promotion." >&2 - exit 1 - fi + for BRANCH in $RELEASE_BRANCHES; do + git fetch origin "$BRANCH" || true - git push origin origin/main:refs/heads/release + if git show-ref --verify --quiet "refs/remotes/origin/$BRANCH"; then + RELEASE_SHA=$(git rev-parse "origin/$BRANCH") + else + RELEASE_SHA="" + fi + + if [ -z "$RELEASE_SHA" ]; then + git push origin origin/main:"refs/heads/$BRANCH" + { + echo "- $BRANCH: created from main" + } >> "$GITHUB_STEP_SUMMARY" + continue + fi + + if [ "$MAIN_SHA" = "$RELEASE_SHA" ]; then + { + echo "- $BRANCH: already up to date" + } >> "$GITHUB_STEP_SUMMARY" + continue + fi + + if ! git merge-base --is-ancestor "origin/$BRANCH" origin/main; then + echo "$BRANCH is not an ancestor of main. Resolve release history before promotion." >&2 + exit 1 + fi + + git push origin origin/main:"refs/heads/$BRANCH" + { + echo "- $BRANCH: updated" + } >> "$GITHUB_STEP_SUMMARY" + done { - echo "## Release Promotion" - echo "- Status: success" - echo "- Promoted main SHA: $MAIN_SHA" - echo "- Target branch: release" - echo "- Note: Vercel production deploy is triggered by release branch update" + echo "- Note: Vercel production deploy is triggered by corresponding release branch update" } >> "$GITHUB_STEP_SUMMARY" diff --git a/turbo.json b/turbo.json index 49171f7d..f2f03b7e 100644 --- a/turbo.json +++ b/turbo.json @@ -4,7 +4,7 @@ "tasks": { "build": { "dependsOn": ["^build"], - "outputs": ["dist/**", ".output/**", ".vercel/output/**"], + "outputs": ["dist/**", ".output/**"], "env": ["NODE_ENV", "NEXT_PUBLIC_*"] }, "@solid-connect/web#build": {