generated from gc/template-java-maven
- Spring Boot 3.2.1 백엔드 (com.gcsc.connection, 포트 8042, context /snp-connection) - React 19 + TypeScript + Vite 7 + Tailwind CSS 4 프론트엔드 - frontend-maven-plugin 통합 빌드 설정 - 팀 워크플로우 v1.6.1 동기화 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
280 lines
9.8 KiB
Markdown
280 lines
9.8 KiB
Markdown
---
|
|
name: mr
|
|
description: 커밋 + 푸시 + Gitea MR을 한 번에 생성합니다
|
|
user-invokable: true
|
|
argument-hint: "[target-branch: develop|main] (기본: develop)"
|
|
---
|
|
|
|
현재 브랜치의 변경 사항을 커밋+푸시하고, Gitea에 MR을 생성합니다.
|
|
타겟 브랜치: $ARGUMENTS (기본: develop)
|
|
|
|
## 수행 단계
|
|
|
|
### 0. 권한 확인
|
|
|
|
```bash
|
|
# GITEA_TOKEN 확인
|
|
if [ -z "$GITEA_TOKEN" ]; then
|
|
echo "GITEA_TOKEN이 필요합니다. Gitea → Settings → Applications에서 생성하세요"
|
|
exit 1
|
|
fi
|
|
|
|
# Gitea API로 리포 권한 조회
|
|
REMOTE_URL=$(git remote get-url origin)
|
|
GITEA_HOST=$(echo "$REMOTE_URL" | sed -E 's|^https?://([^/]+)/.*|\1|')
|
|
REPO_PATH=$(echo "$REMOTE_URL" | grep -oE '[^/]+/[^/]+\.git$' | sed 's/.git$//')
|
|
PERMISSIONS=$(curl -sf "https://${GITEA_HOST}/api/v1/repos/${REPO_PATH}" \
|
|
-H "Authorization: token ${GITEA_TOKEN}")
|
|
CAN_PUSH=$(echo "$PERMISSIONS" | python3 -c "import sys,json; print(json.load(sys.stdin)['permissions']['push'])")
|
|
```
|
|
|
|
- `CAN_PUSH`가 `False`이면: "MR 생성 권한이 필요합니다. 프로젝트 관리자에게 요청하세요." 안내 후 종료
|
|
|
|
### 0.5. 팀 워크플로우 최신화 확인
|
|
|
|
`.claude/workflow-version.json`이 존재하지 않으면 이 단계를 건너뛴다 (팀 프로젝트가 아닌 경우).
|
|
|
|
```bash
|
|
# 로컬 설정 읽기
|
|
GITEA_URL=$(python3 -c "import json; print(json.load(open('.claude/workflow-version.json')).get('gitea_url', 'https://gitea.gc-si.dev'))" 2>/dev/null)
|
|
PROJECT_TYPE=$(python3 -c "import json; print(json.load(open('.claude/workflow-version.json')).get('project_type', ''))" 2>/dev/null)
|
|
CUSTOM_PRECOMMIT=$(python3 -c "import json; print(json.load(open('.claude/workflow-version.json')).get('custom_pre_commit', False))" 2>/dev/null)
|
|
|
|
# 서버 해시 조회 (custom_pre_commit이면 pre-commit 제외 해시 사용)
|
|
SERVER_VER=$(curl -sf --max-time 5 "${GITEA_URL}/gc/template-common/raw/branch/develop/workflow-version.json")
|
|
if [ "$CUSTOM_PRECOMMIT" = "True" ]; then
|
|
SERVER_HASH=$(echo "$SERVER_VER" | python3 -c "import sys,json; print(json.load(sys.stdin).get('content_hashes_custom_precommit',{}).get('${PROJECT_TYPE}',''))" 2>/dev/null)
|
|
else
|
|
SERVER_HASH=$(echo "$SERVER_VER" | python3 -c "import sys,json; print(json.load(sys.stdin).get('content_hashes',{}).get('${PROJECT_TYPE}',''))" 2>/dev/null)
|
|
fi
|
|
|
|
# 로컬 해시 계산 (custom_pre_commit이면 .githooks/pre-commit 제외)
|
|
if [ "$CUSTOM_PRECOMMIT" = "True" ]; then
|
|
LOCAL_HASH=$(find .claude/rules .claude/agents .claude/scripts .githooks \
|
|
.claude/skills/push .claude/skills/mr .claude/skills/create-mr \
|
|
.claude/skills/release .claude/skills/version .claude/skills/fix-issue \
|
|
-type f ! -path '.githooks/pre-commit' 2>/dev/null | sort | xargs cat 2>/dev/null | shasum -a 256 | cut -d' ' -f1)
|
|
else
|
|
LOCAL_HASH=$(find .claude/rules .claude/agents .claude/scripts .githooks \
|
|
.claude/skills/push .claude/skills/mr .claude/skills/create-mr \
|
|
.claude/skills/release .claude/skills/version .claude/skills/fix-issue \
|
|
-type f 2>/dev/null | sort | xargs cat 2>/dev/null | shasum -a 256 | cut -d' ' -f1)
|
|
fi
|
|
```
|
|
|
|
**비교 결과 처리**:
|
|
- **서버 조회 실패** (`SERVER_HASH` 비어있음): "⚠️ 서버 연결 불가, 워크플로우 체크를 건너뜁니다" 경고 후 다음 단계 진행
|
|
- **일치** (`LOCAL_HASH == SERVER_HASH`): 다음 단계 진행
|
|
- **불일치**: "⚠️ 팀 워크플로우가 최신이 아닙니다. 동기화를 실행합니다..." 출력 → **sync-team-workflow 절차를 자동 실행** → 완료 후 원래 작업 계속
|
|
|
|
### 1. 사전 검증
|
|
|
|
```bash
|
|
# 현재 브랜치 확인 (main/develop이면 중단)
|
|
BRANCH=$(git branch --show-current)
|
|
```
|
|
|
|
- 현재 브랜치가 `main` 또는 `develop`이면: "feature 브랜치에서 실행해주세요" 안내 후 종료
|
|
|
|
### 2. 커밋 + 푸시 (변경 사항이 있을 때만)
|
|
|
|
```bash
|
|
git status --short
|
|
```
|
|
|
|
**커밋되지 않은 변경이 있으면**:
|
|
- 변경 범위(파일 목록, 추가/수정/삭제) 요약 표시
|
|
- Conventional Commits 형식 커밋 메시지 자동 생성
|
|
- **사용자 확인** (AskUserQuestion): 커밋 메시지 수락/수정/취소
|
|
- 수락 시: `git add -A` → `git commit` → `git push`
|
|
|
|
**변경이 없으면**:
|
|
- 이미 커밋된 내용으로 MR 생성 진행
|
|
- 리모트에 push되지 않은 커밋이 있으면 `git push`
|
|
|
|
### 3. MR 대상 브랜치 결정
|
|
|
|
타겟 브랜치 후보를 분석하여 표시:
|
|
|
|
```bash
|
|
# develop과의 차이
|
|
git log develop..HEAD --oneline 2>/dev/null
|
|
# main과의 차이
|
|
git log main..HEAD --oneline 2>/dev/null
|
|
```
|
|
|
|
**사용자 확인** (AskUserQuestion):
|
|
- **질문**: "MR 타겟 브랜치를 선택하세요"
|
|
- 옵션 1: develop (추천, N건 커밋 차이)
|
|
- 옵션 2: main (N건 커밋 차이)
|
|
- 옵션 3: 취소
|
|
|
|
인자($ARGUMENTS)로 브랜치가 지정되었으면 확인 없이 바로 진행.
|
|
|
|
### 4. RELEASE-NOTES.md 갱신 (develop 대상 MR일 때만)
|
|
|
|
타겟이 `develop`일 때 릴리즈 노트를 자동 갱신한다.
|
|
|
|
**4-1. 커밋 분석**
|
|
|
|
```bash
|
|
# develop 대비 현재 브랜치의 커밋 목록 (Conventional Commits 파싱)
|
|
git log develop..HEAD --format="%s"
|
|
```
|
|
|
|
모든 커밋 타입을 타입별 섹션으로 분류:
|
|
|
|
| 타입 | 섹션 |
|
|
|------|------|
|
|
| feat | 추가 |
|
|
| fix | 수정 |
|
|
| refactor, perf | 변경 |
|
|
| docs | 문서 |
|
|
| test | 테스트 |
|
|
| style, chore, ci | 기타 |
|
|
|
|
- 커밋 메시지에서 이슈 번호를 자동 추출하여 `(#번호)` 형태로 연결
|
|
- 커밋 메시지의 scope는 제거하고, 설명부만 사람이 읽기 좋은 형태로 변환
|
|
- 예: `feat(auth): 로그인 검증 로직 추가` → `- 로그인 검증 로직 추가`
|
|
|
|
**4-2. RELEASE-NOTES.md 갱신**
|
|
|
|
`docs/RELEASE-NOTES.md` 파일이 없으면 새로 생성:
|
|
|
|
```markdown
|
|
# Release Notes
|
|
|
|
이 문서는 [Keep a Changelog](https://keepachangelog.com/ko/1.0.0/) 형식을 따릅니다.
|
|
|
|
## [Unreleased]
|
|
```
|
|
|
|
기존 파일이 있으면 `[Unreleased]` 섹션에 항목을 추가한다.
|
|
이미 같은 내용이 있으면 중복 추가하지 않는다.
|
|
|
|
**4-3. 사용자 첨삭 확인**
|
|
|
|
사용자에게 릴리즈 노트 초안을 표시하고 **AskUserQuestion**으로 확인:
|
|
- **질문**: "릴리즈 노트 초안입니다. 수정할 내용이 있으면 알려주세요."
|
|
- 옵션 1: 이대로 진행 (추천)
|
|
- 옵션 2: 수정 (Other 입력)
|
|
- 옵션 3: 릴리즈 노트 생략
|
|
|
|
사용자가 수정 사항을 입력하면 반영 후 커밋.
|
|
생략을 선택하면 릴리즈 노트 변경 없이 MR 생성 진행.
|
|
|
|
**4-4. 추가 커밋 + 푸시**
|
|
|
|
릴리즈 노트 변경이 있으면:
|
|
```bash
|
|
git add docs/RELEASE-NOTES.md
|
|
git commit -m "docs: 릴리즈 노트 업데이트"
|
|
git push
|
|
```
|
|
|
|
### 5. MR 정보 구성
|
|
|
|
```bash
|
|
# 커밋 목록
|
|
git log {target}..HEAD --oneline
|
|
# 변경 파일 통계
|
|
git diff {target}..HEAD --stat
|
|
```
|
|
|
|
- **제목**: 커밋이 1개면 커밋 메시지 사용, 여러 개면 브랜치명에서 추출
|
|
- `feature/ISSUE-42-user-login` → `feat: ISSUE-42 user-login`
|
|
- `bugfix/fix-timeout` → `fix: fix-timeout`
|
|
- **본문**:
|
|
```markdown
|
|
## 변경 사항
|
|
- (커밋 목록 기반 자동 생성)
|
|
|
|
## 관련 이슈
|
|
- closes #이슈번호 (브랜치명에서 추출, 없으면 생략)
|
|
|
|
## 테스트
|
|
- [ ] 빌드 성공 확인
|
|
- [ ] 기존 테스트 통과
|
|
```
|
|
|
|
### 6. Gitea API로 MR 생성
|
|
|
|
```bash
|
|
curl -X POST "https://{host}/api/v1/repos/{owner}/{repo}/pulls" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"title": "MR 제목",
|
|
"body": "MR 본문",
|
|
"head": "현재브랜치",
|
|
"base": "타겟브랜치"
|
|
}'
|
|
```
|
|
|
|
### 7. PR 승인 + 머지 (선택)
|
|
|
|
**사용자 확인** (AskUserQuestion):
|
|
- **질문**: "MR을 어떻게 처리하시겠습니까?"
|
|
- 옵션 1: 리뷰 대기 (추천) — MR만 생성, 리뷰어 지정 후 수동 머지
|
|
- 옵션 2: 승인 + 머지 — claude-bot으로 즉시 승인하고 머지
|
|
|
|
**승인 + 머지 선택 시**:
|
|
|
|
```bash
|
|
# CLAUDE_BOT_TOKEN 확인
|
|
if [ -z "$CLAUDE_BOT_TOKEN" ]; then
|
|
echo "CLAUDE_BOT_TOKEN이 설정되지 않아 자동 승인이 불가합니다. MR만 생성합니다."
|
|
# MR URL 출력 후 종료
|
|
fi
|
|
|
|
# 1. claude-bot이 PR 리뷰 승인
|
|
curl -X POST "https://{host}/api/v1/repos/{owner}/{repo}/pulls/{pr_number}/reviews" \
|
|
-H "Authorization: token ${CLAUDE_BOT_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"event": "APPROVED", "body": "MR 승인 (via /mr skill)"}'
|
|
|
|
# 2. 머지 실행
|
|
curl -X POST "https://{host}/api/v1/repos/{owner}/{repo}/pulls/{pr_number}/merge" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"Do": "merge", "merge_message_field": "MR 제목", "delete_branch_after_merge": true}'
|
|
```
|
|
|
|
⚠️ `delete_branch_after_merge: true` — feature 브랜치는 머지 후 삭제한다 (develop/main과 달리).
|
|
|
|
### 8. 결과 출력
|
|
|
|
**승인 + 머지한 경우**:
|
|
```
|
|
✅ MR 머지 완료
|
|
브랜치: feature/my-branch → develop
|
|
MR: https://gitea.gc-si.dev/gc/my-project/pulls/42
|
|
커밋: 3건, 파일: 5개 변경
|
|
릴리즈 노트: docs/RELEASE-NOTES.md [Unreleased] 갱신됨
|
|
PR 승인: claude-bot ✅
|
|
머지: 완료 ✅
|
|
브랜치 삭제: feature/my-branch ✅
|
|
```
|
|
|
|
**리뷰 대기 선택 시**:
|
|
```
|
|
✅ MR 생성 완료
|
|
브랜치: feature/my-branch → develop
|
|
MR: https://gitea.gc-si.dev/gc/my-project/pulls/42
|
|
커밋: 3건, 파일: 5개 변경
|
|
릴리즈 노트: docs/RELEASE-NOTES.md [Unreleased] 갱신됨
|
|
|
|
다음 단계: 리뷰어 지정 → 승인 대기 → 머지
|
|
```
|
|
|
|
## 필요 환경변수
|
|
|
|
- `GITEA_TOKEN`: Gitea API 접근 토큰
|
|
- 없으면: "Gitea 토큰이 필요합니다. Settings → Applications에서 생성하세요" 안내
|
|
- `CLAUDE_BOT_TOKEN`: claude-bot PR 승인용 토큰 (선택, 없으면 자동 승인 건너뜀)
|
|
|
|
## 기존 /create-mr과의 차이
|
|
|
|
- `/mr`: 커밋+푸시 + 릴리즈 노트 포함, 빠른 실행 (일상적 사용)
|
|
- `/create-mr`: MR 생성만, 세부 옵션 지원 (상세 제어)
|