main → dev 브랜치 통합 #26
Workflow file for this run
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
| name: PR Issue Status Sync | |
| on: | |
| pull_request: | |
| types: [opened, closed] | |
| jobs: | |
| sync-status: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Update Linked Issue Status in Project | |
| env: | |
| GH_TOKEN: ${{ secrets.PROJECT_TOKEN }} | |
| PR_BODY: ${{ github.event.pull_request.body }} | |
| PR_MERGED: ${{ github.event.pull_request.merged }} | |
| run: | | |
| # PR 본문에서 연결된 이슈 번호 파싱 (Closes #X, Fixes #X 등) | |
| ISSUE_NUMS=$(echo "$PR_BODY" | grep -ioE "(close[sd]?|fix(e[sd])?|resolve[sd]?)\s*#[0-9]+" | grep -oE "[0-9]+" || true) | |
| if [[ -z "$ISSUE_NUMS" ]]; then | |
| echo "No linked issues found" | |
| exit 0 | |
| fi | |
| # 상태 결정 | |
| if [[ "${{ github.event.action }}" == "opened" ]]; then | |
| TARGET_STATUS="In Review" | |
| elif [[ "$PR_MERGED" == "true" ]]; then | |
| TARGET_STATUS="Done" | |
| else | |
| echo "PR closed without merge, skipping" | |
| exit 0 | |
| fi | |
| # 프로젝트 ID 및 Status 필드 조회 | |
| PROJECT_ID=$(gh api graphql -f query='{ | |
| organization(login: "depromeet") { | |
| projectV2(number: 99) { id } | |
| } | |
| }' --jq '.data.organization.projectV2.id') | |
| STATUS_FIELD=$(gh api graphql -f query='{ | |
| organization(login: "depromeet") { | |
| projectV2(number: 99) { | |
| fields(first: 30) { | |
| nodes { | |
| ... on ProjectV2SingleSelectField { | |
| id name options { id name } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }' --jq '.data.organization.projectV2.fields.nodes[] | select(.name == "Status")') | |
| FIELD_ID=$(echo "$STATUS_FIELD" | jq -r '.id') | |
| OPTION_ID=$(echo "$STATUS_FIELD" | jq -r --arg s "$TARGET_STATUS" '.options[] | select(.name == $s) | .id') | |
| if [[ -z "$OPTION_ID" ]]; then | |
| echo "Status option '$TARGET_STATUS' not found in project. Please create it." | |
| exit 0 | |
| fi | |
| for ISSUE_NUM in $ISSUE_NUMS; do | |
| # 이슈에 연결된 ProjectV2 item 중 대상 프로젝트(ID 일치)만 선택 | |
| ITEM_ID=$(gh api graphql \ | |
| -f query='query($owner:String!,$repo:String!,$num:Int!){ | |
| repository(owner:$owner,name:$repo){ | |
| issue(number:$num){ | |
| projectItems(first:20){ nodes { id project { id } } } | |
| } | |
| } | |
| }' \ | |
| -F owner=depromeet -F repo=18th-team3-server -F num="$ISSUE_NUM" \ | |
| --jq --arg pid "$PROJECT_ID" '.data.repository.issue.projectItems.nodes[] | select(.project.id == $pid) | .id') | |
| if [[ -n "$ITEM_ID" ]]; then | |
| gh api graphql \ | |
| -f query='mutation($pid:ID!,$iid:ID!,$fid:ID!,$oid:String!) { | |
| updateProjectV2ItemFieldValue(input:{projectId:$pid,itemId:$iid,fieldId:$fid,value:{singleSelectOptionId:$oid}}) { | |
| projectV2Item { id } | |
| } | |
| }' \ | |
| -f pid="$PROJECT_ID" -f iid="$ITEM_ID" -f fid="$FIELD_ID" -f oid="$OPTION_ID" | |
| echo "Issue #$ISSUE_NUM → $TARGET_STATUS" | |
| fi | |
| done |