name: Linear Integration on: pull_request: types: [opened, closed, ready_for_review, reopened, synchronize] pull_request_review: types: [submitted] push: branches: [main, "feature/**", "bugfix/**", "task/**"] issues: types: [opened, closed, reopened] issue_comment: types: [created] env: NODE_VERSION: "18" jobs: extract-linear-id: name: Extract Linear Issue ID runs-on: ubuntu-latest outputs: issue-id: ${{ steps.extract.outputs.issue-id }} issue-found: ${{ steps.extract.outputs.issue-found }} steps: - name: Extract Linear Issue ID id: extract run: | ISSUE_ID="" ISSUE_FOUND="false" # PR 이벤트에서 Linear 이슈 ID 추출 if [[ "${{ github.event_name }}" == "pull_request" ]]; then # PR 제목과 본문에서 ZEL-XXX 형태 추출 TEXT="${{ github.event.pull_request.title }} ${{ github.event.pull_request.body }}" ISSUE_ID=$(echo "$TEXT" | grep -oE 'ZEL-[0-9]+' | head -1) # 브랜치명에서도 추출 시도 if [[ -z "$ISSUE_ID" ]]; then BRANCH="${{ github.event.pull_request.head.ref }}" ISSUE_ID=$(echo "$BRANCH" | grep -oE 'ZEL-[0-9]+' | head -1) fi # Push 이벤트에서 커밋 메시지 확인 elif [[ "${{ github.event_name }}" == "push" ]]; then # 최신 커밋 메시지에서 추출 COMMIT_MSG="${{ github.event.head_commit.message }}" ISSUE_ID=$(echo "$COMMIT_MSG" | grep -oE 'ZEL-[0-9]+' | head -1) # 이슈 이벤트에서 제목/본문 확인 elif [[ "${{ github.event_name }}" == "issues" ]]; then TEXT="${{ github.event.issue.title }} ${{ github.event.issue.body }}" ISSUE_ID=$(echo "$TEXT" | grep -oE 'ZEL-[0-9]+' | head -1) fi if [[ -n "$ISSUE_ID" ]]; then ISSUE_FOUND="true" echo "Found Linear issue: $ISSUE_ID" else echo "No Linear issue ID found" fi echo "issue-id=$ISSUE_ID" >> $GITHUB_OUTPUT echo "issue-found=$ISSUE_FOUND" >> $GITHUB_OUTPUT sync-pr-events: name: Sync Pull Request Events runs-on: ubuntu-latest needs: extract-linear-id if: github.event_name == 'pull_request' && needs.extract-linear-id.outputs.issue-found == 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Install dependencies run: | echo "Installing Node.js dependencies for Linear integration..." # npm 캐시는 이미 setup-node에서 처리됨 - name: Sync PR Status run: | # PR 머지 여부 확인 PR_MERGED="false" if [[ "${{ github.event.action }}" == "closed" && "${{ github.event.pull_request.merged }}" == "true" ]]; then PR_MERGED="true" fi echo "Syncing PR event:" echo " Issue ID: ${{ needs.extract-linear-id.outputs.issue-id }}" echo " Event: ${{ github.event_name }}" echo " Action: ${{ github.event.action }}" echo " PR URL: ${{ github.event.pull_request.html_url }}" echo " Author: ${{ github.event.pull_request.user.login }}" echo " Merged: $PR_MERGED" # Linear 동기화 실행 node scripts/linear-sync.cjs \ --issue-id="${{ needs.extract-linear-id.outputs.issue-id }}" \ --event="${{ github.event_name }}" \ --action="${{ github.event.action }}" \ --pr-url="${{ github.event.pull_request.html_url }}" \ --pr-author="${{ github.event.pull_request.user.login }}" \ --pr-merged="$PR_MERGED" env: LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} - name: Add PR Comment run: | echo "Adding comment to Linear issue:" echo " Issue ID: ${{ needs.extract-linear-id.outputs.issue-id }}" echo " Event: ${{ github.event_name }}" echo " Action: ${{ github.event.action }}" # Linear 코멘트 추가 node scripts/linear-comment.cjs \ --issue-id="${{ needs.extract-linear-id.outputs.issue-id }}" \ --event="${{ github.event_name }}" \ --action="${{ github.event.action }}" \ --pr-url="${{ github.event.pull_request.html_url }}" \ --pr-author="${{ github.event.pull_request.user.login }}" env: LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} sync-review-events: name: Sync Review Events runs-on: ubuntu-latest needs: extract-linear-id if: github.event_name == 'pull_request_review' && needs.extract-linear-id.outputs.issue-found == 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Sync Review Status run: | echo "Syncing review event:" echo " Issue ID: ${{ needs.extract-linear-id.outputs.issue-id }}" echo " Review State: ${{ github.event.review.state }}" echo " Reviewer: ${{ github.event.review.user.login }}" echo " PR URL: ${{ github.event.pull_request.html_url }}" # Linear 코멘트 추가 node scripts/linear-comment.cjs \ --issue-id="${{ needs.extract-linear-id.outputs.issue-id }}" \ --event="pull_request_review" \ --review-state="${{ github.event.review.state }}" \ --reviewer="${{ github.event.review.user.login }}" \ --pr-url="${{ github.event.pull_request.html_url }}" env: LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} sync-push-events: name: Sync Push Events runs-on: ubuntu-latest needs: extract-linear-id if: github.event_name == 'push' && needs.extract-linear-id.outputs.issue-found == 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Sync Commit Status run: | echo "Syncing push event:" echo " Issue ID: ${{ needs.extract-linear-id.outputs.issue-id }}" echo " Commit SHA: ${{ github.event.head_commit.id }}" echo " Commit Message: ${{ github.event.head_commit.message }}" echo " Author: ${{ github.event.head_commit.author.username }}" # Linear 동기화 및 코멘트 추가 node scripts/linear-sync.cjs \ --issue-id="${{ needs.extract-linear-id.outputs.issue-id }}" \ --event="push" \ --action="commit" node scripts/linear-comment.cjs \ --issue-id="${{ needs.extract-linear-id.outputs.issue-id }}" \ --event="push" \ --commit-sha="${{ github.event.head_commit.id }}" \ --commit-message="${{ github.event.head_commit.message }}" \ --pr-author="${{ github.event.head_commit.author.username }}" env: LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} sync-issue-events: name: Sync Issue Events runs-on: ubuntu-latest needs: extract-linear-id if: github.event_name == 'issues' && needs.extract-linear-id.outputs.issue-found == 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - name: Sync Issue Status run: | echo "Syncing issue event:" echo " Issue ID: ${{ needs.extract-linear-id.outputs.issue-id }}" echo " Action: ${{ github.event.action }}" echo " GitHub Issue: ${{ github.event.issue.html_url }}" # Linear 코멘트 추가 node scripts/linear-comment.cjs \ --issue-id="${{ needs.extract-linear-id.outputs.issue-id }}" \ --event="issue" \ --action="${{ github.event.action }}" \ --github-issue-url="${{ github.event.issue.html_url }}" env: LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }} notify-no-linear-id: name: Notify No Linear ID Found runs-on: ubuntu-latest needs: extract-linear-id if: needs.extract-linear-id.outputs.issue-found == 'false' steps: - name: Log Missing Linear ID run: | echo "⚠️ No Linear issue ID found in:" echo " Event: ${{ github.event_name }}" if [[ "${{ github.event_name }}" == "pull_request" ]]; then echo " PR Title: ${{ github.event.pull_request.title }}" echo " Branch: ${{ github.event.pull_request.head.ref }}" elif [[ "${{ github.event_name }}" == "push" ]]; then echo " Commit: ${{ github.event.head_commit.message }}" fi echo "" echo "Linear 이슈와 연결하려면 다음 형식을 사용하세요:" echo " - PR 제목: '[ZEL-123] 기능 구현'" echo " - 브랜치명: 'feature/ZEL-123-user-auth'" echo " - 커밋 메시지: 'feat: 로그인 기능 구현 [ZEL-123]'" summary: name: Linear Integration Summary runs-on: ubuntu-latest needs: [ extract-linear-id, sync-pr-events, sync-review-events, sync-push-events, sync-issue-events, ] if: always() steps: - name: Summary run: | echo "🔗 Linear Integration Summary" echo "==============================" echo "Event: ${{ github.event_name }}" echo "Linear Issue Found: ${{ needs.extract-linear-id.outputs.issue-found }}" if [[ "${{ needs.extract-linear-id.outputs.issue-found }}" == "true" ]]; then echo "Issue ID: ${{ needs.extract-linear-id.outputs.issue-id }}" echo "✅ Linear integration completed" else echo "❌ No Linear issue ID found" fi echo "" echo "Job Results:" echo " Extract ID: ${{ needs.extract-linear-id.result }}" echo " PR Sync: ${{ needs.sync-pr-events.result }}" echo " Review Sync: ${{ needs.sync-review-events.result }}" echo " Push Sync: ${{ needs.sync-push-events.result }}" echo " Issue Sync: ${{ needs.sync-issue-events.result }}"