GitHub Projects Sync Wizard 상세 가이드
GitHub Projects Status와 Issue Label 간 양방향 실시간 동기화를 설정하는 완전 가이드입니다.
목차
개요
문제점
GitHub Actions는 projects_v2_item 이벤트를 트리거로 지원하지 않습니다.
# ❌ 이 코드는 작동하지 않음
on:
projects_v2_item:
types: [edited]이로 인해 Projects Board에서 Status를 변경해도 Issue Label이 자동으로 동기화되지 않습니다.
해결책
Cloudflare Workers를 사용하여 GitHub Organization Webhook을 직접 수신하고 처리합니다.
| 동기화 방향 | 담당 | 트리거 |
|---|---|---|
| Label → Status | GitHub Actions | Issue Label 변경 |
| Status → Label | Cloudflare Worker | Projects Status 변경 |
아키텍처
전체 흐름
┌─────────────────────────────────────────────────────────────────────┐
│ GitHub Projects Board │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌───────┐│
│ │ 작업전 │ → │ 작업중 │ → │ 피드백 │ → │담당자확인│ → │작업완료││
│ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └───────┘│
│ │ │
│ │ 카드 드래그 (Status 변경) │
└──────────────────────┼──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────┐
│ GitHub Organization Webhook │
│ Event: projects_v2_item │
│ Action: edited │
└──────────────────────────────────────────────────────────────────────┘
│
│ HTTPS POST (with X-Hub-Signature-256)
▼
┌──────────────────────────────────────────────────────────────────────┐
│ Cloudflare Worker (Edge) │
│ │
│ 처리 순서: │
│ 1. Webhook Secret 검증 (HMAC-SHA256) │
│ 2. 이벤트 필터링 (projects_v2_item + edited만 처리) │
│ 3. GraphQL API로 현재 Status 조회 │
│ 4. REST API로 Issue Label 동기화 │
└──────────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────────┐
│ GitHub Issue │
│ Labels: [enhancement] [작업 중] ← 자동으로 변경됨! │
└──────────────────────────────────────────────────────────────────────┘양방향 동기화
┌─────────────┐ ┌─────────────┐
│ Issue Label │ ◀───────────────────────▶ │ Projects │
│ │ 항상 동기화됨 │ Status │
└──────┬──────┘ └──────┬──────┘
│ │
│ Label 변경 시 │ Status 변경 시
▼ ▼
┌─────────────┐ ┌─────────────┐
│ GitHub │ │ Cloudflare │
│ Actions │ │ Worker │
└─────────────┘ └─────────────┘마법사 사용법 (4단계 간소화)
Step 1: 마법사에서 정보 입력
.github/util/common/projects-sync-wizard/projects-sync-wizard.html 파일을 브라우저에서 열고:
GitHub Projects URL 입력:
https://github.com/orgs/YOUR-ORG/projects/1URL을 입력하면 Organization Name과 Project Number가 자동으로 추출됩니다.
Worker 이름 설정 (기본값:
github-projects-sync-worker)- 배포 시 이름이 충돌하면 스크립트에서 새 이름을 입력할 수 있습니다.
Status Labels 확인/커스텀 (issue-labels.yml 기본값 제공)
- 작업전, 작업중, 담당자확인, 피드백, 작업완료, 보류, 취소
- 중요: Label 이름은 GitHub Projects의 Status 컬럼 이름과 정확히 일치해야 합니다.
Webhook Secret (자동 생성)
"Worker 파일 ZIP 다운로드" 클릭
Step 2: 스크립트 한 번 실행
# ZIP 압축 해제 후 폴더로 이동
cd github-projects-sync-worker
# Mac/Linux
./projects-sync-worker-setup.sh
# Windows PowerShell
.\projects-sync-worker-setup.ps1스크립트가 자동으로 처리하는 작업:
- npm 의존성 설치 (SSL 오류 자동 대응)
- Cloudflare 로그인 (브라우저 자동 오픈)
- Worker 배포 (이름 충돌 시 재입력 가능)
- GITHUB_TOKEN 입력 받기
- WEBHOOK_SECRET 자동 설정
- Worker URL 출력
Step 3: GitHub Webhook 수동 설정
- Organization Settings → Webhooks 이동
https://github.com/organizations/YOUR-ORG/settings/hooks - "Add webhook" 클릭
- 설정 입력:
- Payload URL: 스크립트에서 출력된 Worker URL
- Content type:
application/json - Secret: config.json의 webhookSecret 값
- Events: "Let me select individual events" → "Project v2 items" 체크
- "Add webhook" 클릭
Step 4: 테스트
- GitHub Projects Board에서 Issue 카드를 다른 Status 컬럼으로 이동
- Issue 페이지에서 Label이 자동으로 변경되는지 확인
- 문제 발생 시 Worker 로그 확인:
npx wrangler tail
수동 설정 방법
마법사 없이 직접 설정하는 방법입니다.
Cloudflare Worker 수동 설정
1. wrangler.toml 생성
name = "github-projects-sync-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[vars]
PROJECT_NUMBER = "1"
STATUS_FIELD = "Status"
STATUS_LABELS = '["작업전","작업중","담당자확인","피드백","작업완료","보류","취소"]'
ORG_NAME = "YOUR-ORG"2. Secrets 설정
npx wrangler secret put GITHUB_TOKEN
# GitHub PAT 입력 (repo, project 권한)
npx wrangler secret put WEBHOOK_SECRET
# 임의의 비밀키 입력 (예: openssl rand -hex 32)GitHub Actions 워크플로우
PROJECT-COMMON-PROJECTS-SYNC-MANAGER.yaml 파일의 환경 변수를 수정합니다:
env:
STATUS_LABELS: '["작업전", "작업중", "담당자확인", "피드백", "작업완료", "보류", "취소"]'
PROJECT_NUMBER: '1'
ORG_NAME: 'YOUR-ORG'트러블슈팅
SSL 오류 (UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
원인: 회사/학교 네트워크 프록시 또는 보안 소프트웨어
해결:
# npm install 시
npm config set strict-ssl false
npm install
npm config set strict-ssl true
# wrangler 명령어 시
export NODE_TLS_REJECT_UNAUTHORIZED=0 # Mac/Linux
$env:NODE_TLS_REJECT_UNAUTHORIZED=0 # Windows PowerShellCloudflare 이메일 인증 오류
에러: You need to verify your email address to use Workers. [code: 10034]
해결:
- Cloudflare 대시보드 접속
- 상단 이메일 인증 배너 확인
- 이메일 확인하여 인증 링크 클릭
서브도메인 충돌
에러: Subdomain is unavailable, please try a different subdomain
해결: 다른 서브도메인 이름 사용 (예: my-org-sync, project-sync 등)
Webhook 401 에러
원인: Webhook Secret 불일치
해결:
- GitHub Webhook 설정에서 Secret 확인
- Cloudflare Worker의 WEBHOOK_SECRET과 동일한지 확인
- 불일치 시 둘 다 동일한 값으로 재설정
npx wrangler secret put WEBHOOK_SECRETLabel이 동기화되지 않음
체크리스트:
- Worker 로그 확인:
npx wrangler tail - Webhook Delivery 확인: Organization Settings → Webhooks → Recent Deliveries
- Issue가 해당 Project에 연결되어 있는지 확인
- Label이 프로젝트의 Status 컬럼 이름과 정확히 일치하는지 확인
유지보수
GitHub PAT 만료 시
cd github-projects-sync-worker
export NODE_TLS_REJECT_UNAUTHORIZED=0
npx wrangler secret put GITHUB_TOKEN
# 새 토큰 입력Status Label 추가/변경 시
wrangler.toml의STATUS_LABELS수정- Worker 재배포
npx wrangler deploy- GitHub Actions 워크플로우의
STATUS_LABELS도 동일하게 수정
Worker 코드 업데이트
cd github-projects-sync-worker
export NODE_TLS_REJECT_UNAUTHORIZED=0
npx wrangler deployWorker 로그 확인
npx wrangler tailFAQ
Q: 비용이 드나요?
A: Cloudflare Workers Free Tier로 완전 무료입니다.
- 일일 요청 100,000건
- 일반적인 사용량은 100건 미만
Q: Organization이 아닌 개인 저장소에서 사용할 수 있나요?
A: 아니요, GitHub Projects V2는 Organization 레벨에서만 Webhook을 지원합니다. 개인 저장소의 Projects는 이 방법으로 동기화할 수 없습니다.
Q: 여러 프로젝트에서 사용할 수 있나요?
A: 프로젝트마다 별도의 Worker를 배포하거나, Worker 코드를 수정하여 여러 프로젝트를 처리하도록 확장할 수 있습니다.
Q: 무한 루프가 발생하나요?
A: 아니요, Worker 코드에 무한 루프 방지 로직이 포함되어 있습니다. 이미 동일한 Label이 있으면 업데이트를 스킵합니다.
Q: PR에도 적용되나요?
A: 네, Worker 코드는 Issue와 Pull Request 모두 지원합니다.
관련 파일
| 파일 | 설명 |
|---|---|
.github/util/common/projects-sync-wizard/ | 마법사 UI 폴더 |
.github/workflows/PROJECT-COMMON-PROJECTS-SYNC-MANAGER.yaml | Label → Status 동기화 |
버전 히스토리
| 버전 | 날짜 | 변경사항 |
|---|---|---|
| 2.0.0 | 2026-01-21 | 4단계 간소화, 원클릭 설치 스크립트 추가 |
| 1.0.0 | 2026-01-21 | 초기 릴리즈 |