diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml new file mode 100644 index 0000000..8846ffc --- /dev/null +++ b/.github/workflows/deploy-preview.yml @@ -0,0 +1,100 @@ +name: PR Preview + +on: + pull_request: + types: [opened, synchronize, reopened, closed] + +concurrency: + group: pr-preview-${{ github.event.number }} + cancel-in-progress: true + +jobs: + deploy: + if: github.event.action != 'closed' + name: Deploy preview + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + environment: + name: pr-preview-${{ github.event.number }} + url: https://getbms.github.io/bms/pr-${{ github.event.number }}/ + + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # actions/checkout@v4.2.2 + with: + persist-credentials: false + + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # subosito/flutter-action@v2 + with: + flutter-version: '3.44.2' + channel: stable + cache: true + + - run: flutter pub get + + - run: dart run build_runner build --delete-conflicting-outputs + + - run: flutter build web --release --base-href /bms/pr-${{ github.event.number }}/ + + - uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build/web + destination_dir: pr-${{ github.event.number }} + keep_files: true + + - name: Post preview URL comment + uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # actions/github-script@v7 + with: + script: | + const prNumber = ${{ github.event.number }}; + const sha = '${{ github.sha }}'.slice(0, 7); + const url = `https://getbms.github.io/bms/pr-${prNumber}/`; + const marker = ''; + const body = `${marker}\n### Preview deployed\n\n| | |\n|---|---|\n| **URL** | ${url} |\n| **Commit** | \`${sha}\` |\n| **Status** | Live |\n\nUpdates automatically on every push.`; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + + const existing = comments.find(c => c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + body, + }); + } + + cleanup: + if: github.event.action == 'closed' + name: Remove preview + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # actions/checkout@v4.2.2 + with: + ref: gh-pages + + - name: Delete PR preview directory + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + if [ -d "pr-${{ github.event.number }}" ]; then + git rm -rf pr-${{ github.event.number }} + git commit -m "cleanup: remove PR ${{ github.event.number }} preview" + git push + fi diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..32a5648 --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,55 @@ +name: Deploy to Production + +on: + # Auto-triggers only when staging completes successfully + workflow_run: + workflows: ["Deploy to Staging"] + types: [completed] + branches: [master] + # Keep manual trigger as fallback + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: deploy-prod + cancel-in-progress: true + +jobs: + deploy: + name: Deploy production + runs-on: ubuntu-latest + # Skip if triggered by workflow_run and staging did not succeed + if: > + github.event_name == 'workflow_dispatch' || + github.event.workflow_run.conclusion == 'success' + environment: + name: production + url: https://getbms.github.io/bms/ + + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # actions/checkout@v4.2.2 + with: + # When triggered by workflow_run, deploy the exact commit staging used + ref: ${{ github.event.workflow_run.head_sha || github.sha }} + persist-credentials: false + + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # subosito/flutter-action@v2 + with: + flutter-version: '3.44.2' + channel: stable + cache: true + + - run: flutter pub get + + - run: dart run build_runner build --delete-conflicting-outputs + + - run: flutter build web --release --base-href /bms/ + + - uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build/web + keep_files: true + commit_message: 'deploy: production @ ${{ github.event.workflow_run.head_sha || github.sha }}' diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml new file mode 100644 index 0000000..9311b4e --- /dev/null +++ b/.github/workflows/deploy-staging.yml @@ -0,0 +1,58 @@ +name: Deploy to Staging + +on: + # Auto-triggers when a PR is merged to master + push: + branches: [master] + # Keep manual trigger as fallback for re-runs or hotfixes + workflow_dispatch: + inputs: + ref: + description: 'Branch or tag to deploy (default: master)' + required: false + default: 'master' + +permissions: + contents: write + +concurrency: + group: deploy-staging + cancel-in-progress: true + +jobs: + deploy: + name: Deploy staging + runs-on: ubuntu-latest + environment: + name: staging + url: https://getbms.github.io/bms/staging/ + + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # actions/checkout@v4.2.2 + with: + ref: ${{ inputs.ref || github.sha }} + persist-credentials: false + + - name: Capture deployed SHA + id: head + run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # subosito/flutter-action@v2 + with: + flutter-version: '3.44.2' + channel: stable + cache: true + + - run: flutter pub get + + - run: dart run build_runner build --delete-conflicting-outputs + + - run: flutter build web --release --base-href /bms/staging/ + + - uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build/web + destination_dir: staging + keep_files: true + commit_message: 'deploy: staging @ ${{ steps.head.outputs.sha }}'