From e1d2b7fbb51efbb6288dcb9914af7df0bcdffcb2 Mon Sep 17 00:00:00 2001 From: manNomi Date: Mon, 24 Aug 2026 23:09:50 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=9A=20ci:=20=EB=8C=80=ED=95=99=20SSG?= =?UTF-8?q?=20=EC=9E=AC=EB=B0=B0=ED=8F=AC=20CD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/university-web-redeploy.yml | 139 ++++++++++++++++++ docs/university-multizone-deployment.md | 17 +++ 2 files changed, 156 insertions(+) create mode 100644 .github/workflows/university-web-redeploy.yml diff --git a/.github/workflows/university-web-redeploy.yml b/.github/workflows/university-web-redeploy.yml new file mode 100644 index 00000000..10b77935 --- /dev/null +++ b/.github/workflows/university-web-redeploy.yml @@ -0,0 +1,139 @@ +name: Redeploy University Web + +on: + workflow_dispatch: + inputs: + reason: + description: "Reason for rebuilding university SSG pages" + required: false + default: "University API data updated" + type: string + repository_dispatch: + types: [university-data-updated] + +permissions: + contents: read + +concurrency: + group: university-web-production-redeploy + cancel-in-progress: false + +jobs: + redeploy: + name: Redeploy university web production + runs-on: ubuntu-latest + timeout-minutes: 20 + environment: + name: Production – solid-connect-university-web + url: ${{ steps.deploy.outputs.deployment_url }} + env: + VERCEL_PROJECT_NAME: solid-connect-university-web + VERCEL_RELEASE_BRANCH: release-university + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + REDEPLOY_REASON: ${{ github.event.inputs.reason || github.event.client_payload.reason || 'University API data updated' }} + steps: + - name: Checkout university release branch + uses: actions/checkout@v4 + with: + ref: release-university + fetch-depth: 1 + + - name: Validate Vercel credentials + run: | + set -euo pipefail + + if [ -z "$VERCEL_ORG_ID" ] || [ -z "$VERCEL_TOKEN" ]; then + echo "VERCEL_ORG_ID and VERCEL_TOKEN secrets are required." >&2 + exit 1 + fi + + - name: Trigger fresh production deployment + id: deploy + env: + REPOSITORY_ID: ${{ github.event.repository.id }} + run: | + set -euo pipefail + + RELEASE_SHA=$(git rev-parse HEAD) + REQUEST_BODY=$(jq -n \ + --arg name "$VERCEL_PROJECT_NAME" \ + --arg ref "$VERCEL_RELEASE_BRANCH" \ + --arg sha "$RELEASE_SHA" \ + --argjson repoId "$REPOSITORY_ID" \ + '{ + name: $name, + gitSource: { + type: "github", + repoId: $repoId, + ref: $ref, + sha: $sha + }, + target: "production" + }') + + HTTP_STATUS=$(curl --silent --show-error \ + --output deployment.json \ + --write-out "%{http_code}" \ + --request POST \ + --header "Authorization: Bearer $VERCEL_TOKEN" \ + --header "Content-Type: application/json" \ + --data "$REQUEST_BODY" \ + "https://api.vercel.com/v13/deployments?teamId=$VERCEL_ORG_ID&forceNew=1") + + if [[ ! "$HTTP_STATUS" =~ ^2 ]]; then + jq -r '.error.message // "Vercel deployment request failed."' deployment.json >&2 + exit 1 + fi + + DEPLOYMENT_ID=$(jq -r '.id // empty' deployment.json) + DEPLOYMENT_HOST=$(jq -r '.url // empty' deployment.json) + + if [ -z "$DEPLOYMENT_ID" ] || [ -z "$DEPLOYMENT_HOST" ]; then + echo "Vercel response did not include a deployment ID and URL." >&2 + exit 1 + fi + + { + echo "deployment_id=$DEPLOYMENT_ID" + echo "deployment_url=https://$DEPLOYMENT_HOST" + } >> "$GITHUB_OUTPUT" + + { + echo "## University Web redeploy" + echo "- Reason: $REDEPLOY_REASON" + echo "- Source branch: $VERCEL_RELEASE_BRANCH" + echo "- Source commit: $RELEASE_SHA" + echo "- Deployment: https://$DEPLOYMENT_HOST" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Wait for deployment + env: + DEPLOYMENT_ID: ${{ steps.deploy.outputs.deployment_id }} + run: | + set -euo pipefail + + for attempt in $(seq 1 90); do + RESPONSE=$(curl --fail-with-body --silent --show-error \ + --header "Authorization: Bearer $VERCEL_TOKEN" \ + "https://api.vercel.com/v13/deployments/$DEPLOYMENT_ID?teamId=$VERCEL_ORG_ID") + STATE=$(jq -r '.readyState // "UNKNOWN"' <<< "$RESPONSE") + + echo "Deployment state: $STATE" + + case "$STATE" in + READY) + echo "- Result: READY" >> "$GITHUB_STEP_SUMMARY" + exit 0 + ;; + ERROR|CANCELED) + echo "- Result: $STATE" >> "$GITHUB_STEP_SUMMARY" + exit 1 + ;; + esac + + sleep 10 + done + + echo "Vercel deployment did not finish within 15 minutes." >&2 + exit 1 diff --git a/docs/university-multizone-deployment.md b/docs/university-multizone-deployment.md index f84ca338..114e26f2 100644 --- a/docs/university-multizone-deployment.md +++ b/docs/university-multizone-deployment.md @@ -92,6 +92,23 @@ production university web project의 `NEXT_PUBLIC_WEB_URL`은 실제 사용자 NEXT_PUBLIC_WEB_URL=https://www.solid-connection.com ``` +## SSG 데이터 재배포 + +대학 API 데이터만 변경된 경우에는 Git 변경이 없어도 `Redeploy University Web` workflow를 실행한다. 이 workflow는 `release-university`의 현재 소스를 사용해 university web production을 새로 빌드한다. 동일한 커밋의 기존 배포를 재사용하지 않으므로 빌드 시점의 최신 API 데이터가 SSG 페이지에 반영된다. + +GitHub Actions 화면에서 수동으로 실행할 수 있다. API 데이터 갱신 작업에서 자동 호출하려면 repository dispatch event type을 `university-data-updated`로 전송한다. 선택적으로 `client_payload.reason`에 갱신 이유를 넣을 수 있다. + +```json +{ + "event_type": "university-data-updated", + "client_payload": { + "reason": "대학 API 초기 데이터 입력 완료" + } +} +``` + +workflow는 저장소의 `VERCEL_TOKEN`과 `VERCEL_ORG_ID` secret을 사용한다. 대상 프로젝트는 `solid-connect-university-web`으로 고정하며 다른 web과 admin 프로젝트는 재배포하지 않는다. + ## Local Development 터미널 두 개에서 실행한다.