🚀 Deploy 20260111-v0.1.1 #4
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
| # =================================================================== | |
| # 범용 프로젝트 자동 체인지로그 관리 워크플로우 | |
| # =================================================================== | |
| # | |
| # 이 워크플로우는 deploy 브랜치로 PR이 생성될 때 CodeRabbit AI의 리뷰를 | |
| # 자동으로 감지하고 파싱하여 CHANGELOG.json과 CHANGELOG.md를 업데이트합니다. | |
| # | |
| # 작동 방식: | |
| # 1. deploy 브랜치로 PR 생성 시 트리거 | |
| # 2. PR 제목을 즉시 🚀 Deploy 형식으로 변경 | |
| # 3. CodeRabbit Summary 요청 후 최대 10분 대기 | |
| # 4. Summary 내용을 파싱하여 CHANGELOG 파일들 업데이트 | |
| # 5. PR 자동 머지 후 배포 트리거 | |
| # | |
| # API Rate Limit 참고: | |
| # - GITHUB_TOKEN: 1,000 요청/시간/레포 (Actions 내) | |
| # - PAT: 5,000 요청/시간/계정 | |
| # - 이 워크플로우 예상 사용량: ~130회/실행 | |
| # | |
| # =================================================================== | |
| name: AUTO UPDATE PROJECT CHANGELOG | |
| on: | |
| pull_request_target: | |
| types: [opened] | |
| branches: ["deploy"] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| jobs: | |
| # Job 1: CodeRabbit Summary 감지 및 파싱 | |
| detect-and-parse: | |
| name: CodeRabbit Summary 감지 및 파싱 | |
| runs-on: ubuntu-latest | |
| outputs: | |
| summary_found: ${{ steps.detect_summary.outputs.summary_found }} | |
| version: ${{ steps.get_version.outputs.version }} | |
| project_type: ${{ steps.get_version.outputs.project_type }} | |
| steps: | |
| - name: PR 본문 초기화 | |
| run: | | |
| PR_NUMBER=${{ github.event.pull_request.number }} | |
| echo "🗑️ PR #$PR_NUMBER 본문 초기화 중..." | |
| curl -s -H "Authorization: token ${{ secrets._GITHUB_PAT_TOKEN }}" \ | |
| -H "Content-Type: application/json" \ | |
| -X PATCH \ | |
| -d '{"body": ""}' \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}" | |
| echo "✅ PR 본문 초기화 완료" | |
| - name: 저장소 체크아웃 | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| fetch-depth: 0 | |
| ref: ${{ github.event.repository.default_branch || 'main' }} | |
| - name: 버전 스크립트 권한 설정 | |
| run: | | |
| if [ -f ".github/scripts/version_manager.sh" ]; then | |
| chmod +x .github/scripts/version_manager.sh | |
| echo "✅ 버전 스크립트 권한 설정 완료" | |
| fi | |
| - name: 버전 정보 확인 | |
| id: get_version | |
| run: | | |
| VERSION="1.0.0" | |
| PROJECT_TYPE="unknown" | |
| # 버전 스크립트 사용 | |
| if [ -f ".github/scripts/version_manager.sh" ]; then | |
| VERSION=$(./.github/scripts/version_manager.sh get | tail -n 1) | |
| elif [ -f "version.yml" ]; then | |
| VERSION=$(grep "^version:" version.yml | sed 's/version: *"\([^"]*\)".*/\1/') | |
| # 폴백: 프로젝트 타입별 버전 파일 | |
| elif [ -f "build.gradle" ]; then | |
| VERSION=$(grep "version = '" build.gradle | sed "s/version = '//" | sed "s/'//") | |
| PROJECT_TYPE="spring" | |
| elif [ -f "pubspec.yaml" ]; then | |
| VERSION=$(grep "^version:" pubspec.yaml | sed 's/version: *\([0-9.]*\).*/\1/') | |
| PROJECT_TYPE="flutter" | |
| elif [ -f "package.json" ]; then | |
| VERSION=$(jq -r '.version' package.json) | |
| PROJECT_TYPE="node" | |
| elif [ -f "pyproject.toml" ]; then | |
| VERSION=$(grep "^version = " pyproject.toml | sed 's/version = *"\([^"]*\)".*/\1/') | |
| PROJECT_TYPE="python" | |
| fi | |
| # version.yml에서 프로젝트 타입 확인 | |
| if [ -f "version.yml" ] && [ "$PROJECT_TYPE" = "unknown" ]; then | |
| PROJECT_TYPE=$(grep "^project_type:" version.yml | sed 's/project_type: *"\([^"]*\)".*/\1/' || echo "unknown") | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "project_type=$PROJECT_TYPE" >> $GITHUB_OUTPUT | |
| echo "✅ 버전: $VERSION, 프로젝트 타입: $PROJECT_TYPE" | |
| - name: PR 제목 즉시 변경 | |
| run: | | |
| PR_NUMBER=${{ github.event.pull_request.number }} | |
| VERSION="${{ steps.get_version.outputs.version }}" | |
| TODAY=$(date '+%Y%m%d') | |
| NEW_TITLE="🚀 Deploy ${TODAY}-v${VERSION}" | |
| curl -s -H "Authorization: token ${{ secrets._GITHUB_PAT_TOKEN }}" \ | |
| -H "Content-Type: application/json" \ | |
| -X PATCH \ | |
| -d "{\"title\": \"${NEW_TITLE}\"}" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}" | |
| echo "✅ PR 제목 변경 완료: $NEW_TITLE" | |
| - name: CodeRabbit Summary 요청 | |
| run: | | |
| PR_NUMBER=${{ github.event.pull_request.number }} | |
| curl -s -H "Authorization: token ${{ secrets._GITHUB_PAT_TOKEN }}" \ | |
| -H "Content-Type: application/json" \ | |
| -X POST \ | |
| -d '{"body": "@coderabbitai summary"}' \ | |
| "https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" | |
| echo "✅ CodeRabbit Summary 요청 완료" | |
| - name: CodeRabbit Summary 감지 (폴링) | |
| id: detect_summary | |
| run: | | |
| PR_NUMBER="${{ github.event.pull_request.number }}" | |
| MAX_ATTEMPTS=120 # 10분 = 120 * 5초 | |
| ATTEMPT=0 | |
| echo "🔍 PR #$PR_NUMBER에서 CodeRabbit Summary 감지 시작..." | |
| echo "⏰ 최대 대기 시간: 10분 (5초마다 체크)" | |
| while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do | |
| ATTEMPT=$((ATTEMPT + 1)) | |
| echo "[$ATTEMPT/$MAX_ATTEMPTS] Summary 확인 중... ($(date '+%H:%M:%S'))" | |
| # JSON API로 PR body 가져오기 (Public/Private 동일하게 동작) | |
| PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| "https://api.github.com/repos/${{ github.repository }}/pulls/${PR_NUMBER}" | \ | |
| jq -r '.body // ""') | |
| # 본문이 비어있는지 확인 | |
| if [ -z "$PR_BODY" ] || [ "$PR_BODY" = "null" ]; then | |
| echo "⏳ PR 본문이 비어있습니다" | |
| elif echo "$PR_BODY" | grep -q "Summary by CodeRabbit"; then | |
| echo "✅ CodeRabbit Summary 발견!" | |
| echo "$PR_BODY" > pr_body.md | |
| echo "summary_found=true" >> $GITHUB_OUTPUT | |
| break | |
| else | |
| echo "⏳ CodeRabbit Summary 아직 없음" | |
| fi | |
| if [ $ATTEMPT -lt $MAX_ATTEMPTS ]; then | |
| sleep 5 | |
| fi | |
| done | |
| if [ $ATTEMPT -eq $MAX_ATTEMPTS ]; then | |
| echo "⚠️ 10분 대기 후에도 Summary를 찾을 수 없습니다" | |
| echo "summary_found=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Summary 파일 업로드 | |
| if: steps.detect_summary.outputs.summary_found == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pr-content | |
| path: pr_body.md | |
| retention-days: 1 | |
| # Job 2: CHANGELOG 업데이트 | |
| update-changelog: | |
| name: CHANGELOG 업데이트 | |
| runs-on: ubuntu-latest | |
| needs: detect-and-parse | |
| if: needs.detect-and-parse.outputs.summary_found == 'true' | |
| steps: | |
| - name: 저장소 체크아웃 | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| fetch-depth: 0 | |
| ref: ${{ github.event.repository.default_branch || 'main' }} | |
| - name: Git 설정 | |
| run: | | |
| DEFAULT_BRANCH="${{ github.event.repository.default_branch || 'main' }}" | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| git pull origin $DEFAULT_BRANCH | |
| - name: Summary 파일 다운로드 | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: pr-content | |
| - name: CHANGELOG 업데이트 | |
| run: | | |
| PR_NUMBER="${{ github.event.pull_request.number }}" | |
| VERSION="${{ needs.detect-and-parse.outputs.version }}" | |
| PROJECT_TYPE="${{ needs.detect-and-parse.outputs.project_type }}" | |
| TODAY=$(date '+%Y-%m-%d') | |
| TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%SZ') | |
| echo "📝 CHANGELOG 업데이트 시작..." | |
| echo "📋 프로젝트: $PROJECT_TYPE v$VERSION" | |
| # Python 스크립트 실행 권한 설정 | |
| if [ -f ".github/scripts/changelog_manager.py" ]; then | |
| chmod +x .github/scripts/changelog_manager.py | |
| else | |
| echo "❌ changelog_manager.py를 찾을 수 없습니다" | |
| exit 1 | |
| fi | |
| # 환경 변수 설정 후 Python 스크립트 실행 | |
| export VERSION="$VERSION" | |
| export PROJECT_TYPE="$PROJECT_TYPE" | |
| export TODAY="$TODAY" | |
| export PR_NUMBER="$PR_NUMBER" | |
| export TIMESTAMP="$TIMESTAMP" | |
| python3 .github/scripts/changelog_manager.py update-from-summary | |
| echo "📄 CHANGELOG.md 재생성 중..." | |
| python3 .github/scripts/changelog_manager.py generate-md | |
| - name: 변경사항 커밋 및 푸시 | |
| run: | | |
| DEFAULT_BRANCH="${{ github.event.repository.default_branch || 'main' }}" | |
| git add CHANGELOG.json CHANGELOG.md | |
| if git diff --staged --quiet; then | |
| echo "📝 변경사항이 없습니다" | |
| else | |
| REPO_NAME=$(basename "${{ github.repository }}") | |
| VERSION="${{ needs.detect-and-parse.outputs.version }}" | |
| git commit -m "$REPO_NAME 버전 관리 : docs : v$VERSION 릴리즈 문서 업데이트 (PR #${{ github.event.pull_request.number }})" | |
| # Race Condition 방지: pull-rebase 후 push (최대 3회 재시도) | |
| MAX_RETRIES=3 | |
| RETRY_COUNT=0 | |
| PUSH_SUCCESS=false | |
| while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| echo "🔄 Push 시도 $RETRY_COUNT/$MAX_RETRIES..." | |
| if git push origin HEAD:$DEFAULT_BRANCH; then | |
| PUSH_SUCCESS=true | |
| echo "✅ 변경사항 커밋 완료" | |
| break | |
| else | |
| echo "⚠️ Push 실패, remote 변경사항 동기화 중..." | |
| if git pull --rebase origin $DEFAULT_BRANCH; then | |
| echo "✅ Rebase 성공, 다시 push 시도..." | |
| else | |
| echo "❌ Rebase 실패, 충돌 해결 필요" | |
| git rebase --abort 2>/dev/null || true | |
| exit 1 | |
| fi | |
| fi | |
| done | |
| if [ "$PUSH_SUCCESS" = false ]; then | |
| echo "❌ $MAX_RETRIES회 시도 후에도 push 실패" | |
| exit 1 | |
| fi | |
| fi | |
| - name: 임시 파일 정리 | |
| run: rm -f pr_body.md | |
| # Job 3: PR 머지 및 배포 트리거 | |
| merge-and-deploy: | |
| name: PR 머지 및 배포 트리거 | |
| runs-on: ubuntu-latest | |
| needs: [detect-and-parse, update-changelog] | |
| if: needs.detect-and-parse.outputs.summary_found == 'true' | |
| steps: | |
| - name: 저장소 체크아웃 | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets._GITHUB_PAT_TOKEN }} | |
| fetch-depth: 0 | |
| - name: Git 설정 | |
| run: | | |
| git config --local user.email "action@github.com" | |
| git config --local user.name "GitHub Action" | |
| - name: PR 브랜치 최신화 | |
| env: | |
| GH_TOKEN: ${{ secrets._GITHUB_PAT_TOKEN }} | |
| run: | | |
| PR_HEAD=$(gh pr view ${{ github.event.pull_request.number }} --json headRefName -q .headRefName) | |
| PR_BASE=$(gh pr view ${{ github.event.pull_request.number }} --json baseRefName -q .baseRefName) | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "📋 PR 정보:" | |
| echo " • HEAD 브랜치: $PR_HEAD" | |
| echo " • BASE 브랜치: $PR_BASE" | |
| echo " • 목표: $PR_BASE 브랜치에 $PR_HEAD의 변경사항을 머지" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| # 원격 브랜치 최신화 | |
| echo "🔄 원격 브랜치 최신화 중..." | |
| git fetch origin $PR_HEAD | |
| git fetch origin $PR_BASE | |
| # BASE 브랜치(deploy)로 체크아웃 | |
| echo "📦 $PR_BASE 브랜치로 체크아웃 중..." | |
| git checkout $PR_BASE | |
| git pull origin $PR_BASE | |
| # HEAD 브랜치(main)의 최신 변경사항 다시 가져오기 (race condition 방지) | |
| echo "🔄 $PR_HEAD 브랜치의 최신 변경사항 가져오는 중..." | |
| git fetch origin $PR_HEAD | |
| # HEAD 브랜치(main)의 변경사항을 BASE(deploy)에 머지 | |
| echo "🔀 $PR_HEAD의 변경사항을 $PR_BASE에 머지 중..." | |
| if git merge --no-edit origin/$PR_HEAD; then | |
| echo "✅ 머지 성공" | |
| else | |
| echo "⚠️ 머지 충돌 발생" | |
| echo "충돌 파일:" | |
| git diff --name-only --diff-filter=U || true | |
| echo "❌ 머지 충돌로 인해 실패했습니다. 수동으로 해결 후 다시 시도하세요." | |
| exit 1 | |
| fi | |
| # deploy 브랜치에 푸시 (다른 워크플로우 트리거) | |
| # Race Condition 방지: pull-rebase 후 push (최대 3회 재시도) | |
| echo "🚀 $PR_BASE 브랜치에 푸시 중..." | |
| MAX_RETRIES=3 | |
| RETRY_COUNT=0 | |
| PUSH_SUCCESS=false | |
| while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do | |
| RETRY_COUNT=$((RETRY_COUNT + 1)) | |
| echo "🔄 Push 시도 $RETRY_COUNT/$MAX_RETRIES..." | |
| if git push origin $PR_BASE; then | |
| PUSH_SUCCESS=true | |
| echo "✅ $PR_BASE 브랜치에 푸시 완료 (배포 워크플로우 트리거됨)" | |
| break | |
| else | |
| echo "⚠️ Push 실패, remote 변경사항 동기화 중..." | |
| if git pull --rebase origin $PR_BASE; then | |
| echo "✅ Rebase 성공, 다시 push 시도..." | |
| else | |
| echo "❌ Rebase 실패, 충돌 해결 필요" | |
| git rebase --abort 2>/dev/null || true | |
| exit 1 | |
| fi | |
| fi | |
| done | |
| if [ "$PUSH_SUCCESS" = false ]; then | |
| echo "❌ $MAX_RETRIES회 시도 후에도 push 실패" | |
| exit 1 | |
| fi | |
| - name: 자동 PR Merge | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| PR_NUMBER=${{ github.event.pull_request.number }} | |
| # PAT 토큰 존재 여부 확인 | |
| if [ -z "${{ secrets._GITHUB_PAT_TOKEN }}" ]; then | |
| PAT_AVAILABLE="false" | |
| else | |
| PAT_AVAILABLE="true" | |
| fi | |
| # PR 상태 확인 | |
| PR_STATE=$(gh pr view $PR_NUMBER --json state,mergeable -q '.state + "," + (.mergeable | tostring)') | |
| PR_STATE_VALUE=$(echo "$PR_STATE" | cut -d',' -f1) | |
| PR_MERGEABLE=$(echo "$PR_STATE" | cut -d',' -f2) | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "📋 PR 상태 확인:" | |
| echo " • 상태: $PR_STATE_VALUE" | |
| echo " • 병합 가능: $PR_MERGEABLE" | |
| echo " • PAT 토큰 사용 가능: $PAT_AVAILABLE" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| if [ "$PR_STATE_VALUE" = "CLOSED" ] || [ "$PR_STATE_VALUE" = "MERGED" ]; then | |
| echo "✅ PR이 이미 닫혔거나 병합되었습니다" | |
| exit 0 | |
| fi | |
| if [ "$PR_MERGEABLE" != "true" ]; then | |
| echo "⚠️ PR을 GitHub API로 병합할 수 없습니다" | |
| echo "💡 이미 'PR 브랜치 최신화' 단계에서 변경사항이 deploy 브랜치에 적용되었습니다" | |
| echo "📝 PR 상태를 업데이트합니다..." | |
| # PR에 댓글 추가 | |
| export GH_TOKEN=${{ secrets.GITHUB_TOKEN }} | |
| gh pr comment $PR_NUMBER --body "✅ 변경사항이 자동으로 deploy 브랜치에 적용되었습니다. PR을 수동으로 닫아주세요." | |
| echo "✅ PR 상태 업데이트 완료" | |
| exit 0 | |
| fi | |
| # 머지 성공 여부 추적 변수 | |
| MERGE_SUCCESS="false" | |
| # 1차 시도: GITHUB_TOKEN으로 머지 시도 (--admin 없이) | |
| echo "" | |
| echo "🔀 1차 시도: GITHUB_TOKEN으로 PR 병합 중..." | |
| export GH_TOKEN=${{ secrets.GITHUB_TOKEN }} | |
| MERGE_OUTPUT=$(gh pr merge $PR_NUMBER --merge --delete-branch=false 2>&1) | |
| MERGE_EXIT_CODE=$? | |
| if [ $MERGE_EXIT_CODE -eq 0 ] && echo "$MERGE_OUTPUT" | grep -q "merged\|Merged"; then | |
| echo "✅ GITHUB_TOKEN으로 PR 병합 성공" | |
| MERGE_SUCCESS="true" | |
| else | |
| echo "⚠️ GITHUB_TOKEN으로 병합 실패" | |
| echo " 출력: $MERGE_OUTPUT" | |
| # PR 상태 재확인 (다른 프로세스가 머지했을 수 있음) | |
| PR_STATE_CHECK=$(gh pr view $PR_NUMBER --json state -q .state) | |
| if [ "$PR_STATE_CHECK" = "MERGED" ]; then | |
| echo "✅ PR이 이미 머지되었습니다" | |
| MERGE_SUCCESS="true" | |
| fi | |
| fi | |
| # 2차 시도: PAT 토큰으로 재시도 (--admin 플래그 사용) | |
| if [ "$MERGE_SUCCESS" = "false" ] && [ "$PAT_AVAILABLE" = "true" ]; then | |
| echo "" | |
| echo "🔀 2차 시도: PAT 토큰으로 PR 병합 중 (--admin 플래그 사용)..." | |
| export GH_TOKEN=${{ secrets._GITHUB_PAT_TOKEN }} | |
| MERGE_OUTPUT=$(gh pr merge $PR_NUMBER --merge --admin --delete-branch=false 2>&1) | |
| MERGE_EXIT_CODE=$? | |
| if [ $MERGE_EXIT_CODE -eq 0 ] && echo "$MERGE_OUTPUT" | grep -q "merged\|Merged"; then | |
| echo "✅ PAT 토큰으로 PR 병합 성공" | |
| MERGE_SUCCESS="true" | |
| else | |
| echo "❌ PAT 토큰으로도 병합 실패" | |
| echo " 출력: $MERGE_OUTPUT" | |
| # PR 상태 재확인 | |
| PR_STATE_CHECK=$(gh pr view $PR_NUMBER --json state -q .state) | |
| if [ "$PR_STATE_CHECK" = "MERGED" ]; then | |
| echo "✅ PR이 이미 머지되었습니다" | |
| MERGE_SUCCESS="true" | |
| fi | |
| fi | |
| fi | |
| # 최종 실패 처리 | |
| if [ "$MERGE_SUCCESS" = "false" ]; then | |
| echo "" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "❌ PR 자동 병합 실패" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| if [ "$PAT_AVAILABLE" = "false" ]; then | |
| echo "" | |
| echo "⚠️ PAT 토큰이 설정되어 있지 않습니다." | |
| echo "" | |
| echo "📋 해결 방법:" | |
| echo "1. GitHub에서 Personal Access Token 생성" | |
| echo " - https://github.com/settings/tokens" | |
| echo " - 권한: repo (전체 권한)" | |
| echo "" | |
| echo "2. Repository Secrets에 등록" | |
| echo " - Settings > Secrets and variables > Actions" | |
| echo " - New repository secret" | |
| echo " - Name: _GITHUB_PAT_TOKEN" | |
| echo " - Value: 생성한 토큰" | |
| echo "" | |
| echo "또는" | |
| echo "" | |
| echo "3. Branch Protection Rules 조정" | |
| echo " - Settings > Branches > Branch protection rules" | |
| echo " - 'Allow specified actors to bypass required pull requests'" | |
| echo " - GitHub Actions bot을 예외로 추가" | |
| echo "" | |
| else | |
| echo "" | |
| echo "⚠️ GITHUB_TOKEN과 PAT 토큰 모두로 병합에 실패했습니다." | |
| echo "" | |
| echo "📋 가능한 원인:" | |
| echo "1. Branch Protection Rules가 너무 엄격함" | |
| echo "2. PR에 충돌이 있음" | |
| echo "3. 필수 상태 체크가 통과하지 않음" | |
| echo "4. 필수 리뷰 승인이 없음" | |
| echo "" | |
| fi | |
| # PR에 댓글 추가 | |
| export GH_TOKEN=${{ secrets.GITHUB_TOKEN }} | |
| ERROR_COMMENT="❌ 자동 병합 실패. 수동으로 병합해주세요." | |
| if [ "$PAT_AVAILABLE" = "false" ]; then | |
| ERROR_COMMENT="❌ 자동 병합 실패: PAT 토큰이 설정되어 있지 않습니다. Settings > Secrets에 \`_GITHUB_PAT_TOKEN\`을 등록하거나 Branch Protection Rules에서 GitHub Actions bot을 예외로 추가해주세요." | |
| fi | |
| gh pr comment $PR_NUMBER --body "$ERROR_COMMENT" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "✅ PR 자동 병합 완료" | |
| - name: 배포 완료 알림 | |
| run: | | |
| echo "🎉 체인지로그 업데이트 및 배포 트리거 완료!" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" | |
| echo "📋 배포 정보:" | |
| echo " • 버전: ${{ needs.detect-and-parse.outputs.version }}" | |
| echo " • 프로젝트: ${{ needs.detect-and-parse.outputs.project_type }}" | |
| echo " • PR: #${{ github.event.pull_request.number }}" | |
| echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" |