From e94aa64c2231df25007e588a9c6ca03cad60f98c Mon Sep 17 00:00:00 2001 From: Zhaofeng Chen Date: Fri, 30 Jan 2026 12:47:31 +0000 Subject: [PATCH] ci: add manual deployment action --- .github/workflows/README.md | 91 +++++++++++-------- .../promote-staging-to-production.yml | 85 +++++++++++++++++ README.md | 18 ++-- 3 files changed, 144 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/promote-staging-to-production.yml diff --git a/.github/workflows/README.md b/.github/workflows/README.md index b9b196fa6f..534c6a9766 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -6,18 +6,32 @@ This document describes the CI/CD architecture for the Apache Teaclave website. ``` .github/workflows/ -├── _reusable-build.yml # [Reusable] Shared build logic for Docker + website -├── pr-validation.yml # PR validation workflow (read-only) -├── deploy-staging.yml # Deployment workflow for staging -└── README.md # This file +├── _reusable-build.yml # [Reusable] Shared build logic for Docker + website +├── pr-validation.yml # PR validation workflow (read-only) +├── deploy-staging.yml # Deploys build to asf-staging branch +├── promote-staging-to-production.yml # [Manual] Replaces asf-site with asf-staging +└── README.md # This file ``` ### Naming Convention - **`pr-*.yml`** - PR validation workflows (read-only permissions) - **`deploy-*.yml`** - Deployment workflows (write permissions) +- **`promote-*.yml`** - Manual promotion workflows (e.g. staging → production) - **`_reusable-*.yml`** - Reusable workflows (called by others, underscore prefix) +## 🌐 Website Update Flow + +1. **PR merged** (or push to `master`) → **Deploy Staging** runs → build is deployed to the **asf-staging** branch. Staging site is updated. +2. **Verify** → Visit the staging website and confirm everything looks correct. +3. **Promote to production** → Go to **Actions** → **"Promote Staging to Production"** → **Run workflow**. This replaces the **asf-site** branch with the content of **asf-staging**, updating the final live website. + +| Step | What happens | +|------|----------------| +| Merge / push to master | `deploy-staging.yml` → `asf-staging` updated | +| Manual check | You verify the staging site | +| Manual trigger | `promote-staging-to-production.yml` → `asf-site` = `asf-staging` | + ## 🏗️ Architecture Overview ### Design Principles @@ -31,40 +45,37 @@ This document describes the CI/CD architecture for the Apache Teaclave website. ### Architecture Diagram ``` -┌─────────────────────────────────────────────────────────────────┐ -│ GitHub Repository Events │ -│ │ -│ Pull Request Push to master Manual Trigger │ -│ │ │ │ │ -│ ▼ ▼ ▼ │ -│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │pr-validation│ │deploy- │ │deploy- │ │ -│ │.yml │ │staging.yml │ │staging.yml │ │ -│ └────┬────────┘ └──────┬───────┘ └──────┬───────┘ │ -│ │ │ │ │ -│ │ ┌────────────┴──────────────────────┘ │ -│ │ │ │ -│ ▼ ▼ │ -│ ┌────────────────────────────────────────────────┐ │ -│ │ _reusable-build.yml (Shared Logic) │ │ -│ │ │ │ -│ │ ┌──────────────────┐ ┌────────────────────┐ │ │ -│ │ │ build-docker- │─▶│ build-website │ │ │ -│ │ │ image │ │ │ │ │ -│ │ └──────────────────┘ └────────────────────┘ │ │ -│ │ │ │ -│ │ Outputs: │ │ -│ │ - docker-artifact-name │ │ -│ │ - build-artifact-name │ │ -│ └─────────────────┬────────────────┬─────────────┘ │ -│ │ │ │ -│ ┌────────────┘ └────────────┐ │ -│ ▼ ▼ │ -│ ┌─────────┐ ┌──────────────┐ │ -│ │validate │ │deploy-staging│ │ -│ │ │ │ │ │ -│ └─────────┘ └──────────────┘ │ -│ │ -│ Result: ✓ PR Check Result: ✓ Deployed │ -└─────────────────────────────────────────────────────────────────┘ +┌─────────────────────────────────────────────────────────────────────────┐ +│ GitHub Repository Events │ +│ │ +│ Pull Request Push to master Manual Trigger │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────────┐ │ +│ │pr-validation│ │deploy- │ │promote-staging-to- │ │ +│ │.yml │ │staging.yml │ │production.yml │ │ +│ └────┬────────┘ └──────┬───────┘ │ (manual only) │ │ +│ │ │ └──────────┬─────────────┘ │ +│ │ │ │ │ +│ ▼ ▼ │ │ +│ ┌────────────────────────────────────────┐ │ │ +│ │ _reusable-build.yml (Shared Logic) │ │ │ +│ │ build-docker-image → build-website │ │ │ +│ └────────────────────┬───────────────────┘ │ │ +│ │ │ │ +│ ┌────────────────┴────────────────┐ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ validate│ │deploy-staging│ │ promote │ │ +│ └─────────┘ └──────┬───────┘ │ (asf-staging│ │ +│ │ │ │ → asf-site)│ │ +│ │ ▼ └──────┬───────┘ │ +│ │ asf-staging │ │ +│ │ (staging site) ▼ │ +│ │ │ asf-site │ +│ │ │ (live site) │ +│ │ │ │ +│ ▼ └──► Verify staging, then run │ +│ Result: ✓ PR Check "Promote Staging to Production" │ +└─────────────────────────────────────────────────────────────────────────┘ ``` diff --git a/.github/workflows/promote-staging-to-production.yml b/.github/workflows/promote-staging-to-production.yml new file mode 100644 index 0000000000..a81e88a71a --- /dev/null +++ b/.github/workflows/promote-staging-to-production.yml @@ -0,0 +1,85 @@ +# Promote Staging to Production +# +# Manual-only workflow: after verifying the staging site, run this to replace +# the production branch (asf-site) with the content of asf-staging. +# +# Flow: +# 1. PR merged → deploy-staging.yml runs → asf-staging updated +# 2. Visit staging website, verify it looks correct +# 3. Go to Actions → "Promote Staging to Production" → Run workflow +# 4. asf-site is replaced with asf-staging → final website updated + +name: Promote Staging to Production + +on: + workflow_dispatch: + +# Permissions to push to the production branch +permissions: + contents: write + +# Prevent concurrent promotions +concurrency: + group: promote-staging-to-production + cancel-in-progress: false + +jobs: + promote: + name: Replace asf-site with asf-staging + runs-on: ubuntu-22.04 + timeout-minutes: 10 + environment: + name: production + url: https://teaclave.apache.org + + steps: + - name: Checkout repository + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + persist-credentials: false + + - name: Fetch asf-staging + run: | + git fetch origin asf-staging + if ! git rev-parse --verify origin/asf-staging >/dev/null 2>&1; then + echo "Error: Branch asf-staging not found. Run deploy-staging first." + exit 1 + fi + echo "asf-staging is at: $(git rev-parse origin/asf-staging)" + + - name: Replace asf-site with asf-staging + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_REPOSITORY: ${{ github.repository }} + run: | + set -euo pipefail + + cleanup() { + git config --local --unset-all http.https://github.com/.extraheader 2>/dev/null || true + } + trap cleanup EXIT INT TERM + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git config --local http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n x-access-token:${GITHUB_TOKEN} | base64)" + + # Push asf-staging to asf-site (replace production with staging content) + git push https://github.com/${GITHUB_REPOSITORY}.git origin/asf-staging:asf-site --force + + echo "✅ Production branch (asf-site) updated with content from asf-staging" + + - name: Promotion Summary + run: | + echo "### ✅ Production Updated" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "The **asf-site** branch has been replaced with the content of **asf-staging**." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "#### Details" >> $GITHUB_STEP_SUMMARY + echo "- **Source:** \`asf-staging\`" >> $GITHUB_STEP_SUMMARY + echo "- **Target:** \`asf-site\` (production)" >> $GITHUB_STEP_SUMMARY + echo "- **Triggered by:** @${{ github.actor }}" >> $GITHUB_STEP_SUMMARY + echo "- **Timestamp:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "The live website will reflect the new content shortly." >> $GITHUB_STEP_SUMMARY diff --git a/README.md b/README.md index f47478bc9c..57ded93888 100644 --- a/README.md +++ b/README.md @@ -18,19 +18,17 @@ The official website for Apache Teaclave™, generated with the Docusaurus stati make build ``` -### Deployment +### Deployment (CI/CD) -To deploy the generated site to the staging and production environments: +Deployment is handled by GitHub Actions: -```bash -# Deploy to staging -ghp-import --no-history --force site/build/ -b asf-staging -git push -f asf-staging +1. **Merge a PR** (or push to `master`) → the **Deploy Staging** workflow runs and updates the **asf-staging** branch. +2. **Verify** the staging site. +3. **Promote to production** → In the repo, go to **Actions** → **"Promote Staging to Production"** → **Run workflow**. This updates **asf-site** with the content of **asf-staging**. -# Deploy to production -ghp-import --no-history --force site/build/ -b asf-site -git push -f asf-site -``` +For workflow details and architecture, see [.github/workflows/README.md](.github/workflows/README.md). + +Manual deployment from a local build (e.g. `make staging` / `make site` in `site/`) is still supported; see `site/Makefile`. ### Website URLs