DMF_Crawler/docs/ops/05-release-and-versioning.md
Yun Chan 56a6e2da93 chore: 저장소 구조 정리 및 문서화, 첫 커밋
- src/dist 산출물 분리 원칙 정리(.gitignore, .gitattributes)
- 루트 및 주요 폴더(config/scripts/prompts/tests/src, 런타임 폴더 5종)에
  안내용 README.md 추가
- CHANGELOG.md, LICENSE, docs/ops/05-release-and-versioning.md 추가
- docs/README.md 문서 지도 갱신
2026-09-04 09:25:44 +09:00

4.9 KiB

05. 릴리스와 버전 관리

이 문서는 버전 번호·git 태그·릴리스 절차의 정본이다. "몇 버전을 언제 어떻게 배포하는가"는 여기서 결정한다. 배포판을 실제로 만드는 절차(원드라이브 zip 등 수동 전달)의 실측 로그는 docs/HANDOFF.md에 있다.

1. 버전 번호 — Semantic Versioning

pyproject.toml[project].version이 유일한 버전 정본이다. 형식은 MAJOR.MINOR.PATCH.

자리 올리는 경우
MAJOR 설정 파일 스키마·CLI 인자·DB 스키마 등 하위 호환을 깨는 변경
MINOR 하위 호환을 유지하며 기능을 추가(새 시트, 새 알림 채널, 새 CLI 서브커맨드 등)
PATCH 버그 수정, 문서 정리, 리팩터링 등 사용자에게 보이는 동작 변화가 없는 변경

0.y.z 동안은(1.0.0 이전) 아직 안정 API 이전이므로 MINOR도 하위 호환을 깰 수 있다.

2. 릴리스 절차

1. CHANGELOG.md의 [Unreleased] 섹션을 확정 버전으로 승격
   - 헤더를 `## [X.Y.Z] - YYYY-MM-DD`로 바꾼다
   - 문서 하단 비교 링크(compare/... , releases/tag/...)를 갱신한다
2. pyproject.toml의 version = "X.Y.Z" 를 갱신
3. 필수 smoke 실행 (AGENTS.md §3)
   .\.venv\Scripts\python.exe -m compileall -q src tests
   .\.venv\Scripts\python.exe -m dmf_crawler --help
   .\.venv\Scripts\python.exe -m dmf_crawler doctor --json
   .\.venv\Scripts\python.exe -m pytest tests -q
4. (선택) 배포용 빌드 산출물 생성 — §3 참고
5. 커밋: "release: vX.Y.Z"
6. 태그: git tag -a vX.Y.Z -m "vX.Y.Z"
7. 푸시: git push origin main --follow-tags
8. git.chanpaca.net 웹에서 Releases → 해당 태그로 릴리스 노트 작성
   (본문은 CHANGELOG.md의 해당 버전 섹션을 그대로 옮긴다)

태그 이름은 항상 v 접두어를 붙인다(v0.1.0, v1.2.0). pyproject.toml의 버전 문자열에는 v를 붙이지 않는다.

3. 빌드 산출물 (dist/) — src/와의 구분

이 저장소는 소스와 빌드 산출물을 엄격히 분리한다.

디렉터리 내용 git 추적 여부
src/dmf_crawler/ 사람이 직접 편집하는 유일한 소스. 여기가 정본이다 추적함
dist/ python -m build 등이 만들어내는 sdist(.tar.gz)·wheel(.whl) 추적 안 함(.gitignore)
build/ setuptools가 빌드 중 쓰는 임시 작업 디렉터리 추적 안 함
*.egg-info/ 패키지 메타데이터 캐시 추적 안 함

dist/항상 src/에서 재생성 가능해야 한다. dist/ 안의 파일을 손으로 고쳐서는 안 된다 (고칠 게 있으면 src/를 고치고 다시 빌드한다). 그래서 저장소에 커밋하지 않는다 — 커밋하면 "소스와 다른 빌드 산출물이 정본 행세를 하는" 사고가 난다.

빌드 확인 절차:

.\.venv\Scripts\python.exe -m pip install --upgrade build
.\.venv\Scripts\python.exe -m build            # dist/dmf_crawler-X.Y.Z-py3-none-any.whl + .tar.gz 생성
.\.venv\Scripts\python.exe -m pip install --force-reinstall dist\dmf_crawler-*.whl
.\.venv\Scripts\python.exe -m dmf_crawler --help

이 프로그램은 PyPI에 올리지 않는다(pyproject.tomlPrivate :: Do Not Upload 분류자). dist/의 wheel은 다른 PC에 수동 배포할 때만 쓴다. 일반 사용자 배포는 bootstrap.cmd + 저장소 zip 방식을 쓴다(§4).

4. 최종 사용자 배포판 (zip)

이 프로그램은 개발자가 아닌 사용자가 쓴다(AGENTS.md, README.md 참고). PyPI/wheel 설치가 아니라 저장소를 그대로 zip으로 압축해 전달하는 방식을 쓴다. 실제 배포 사례와 포함/제외 감사 체크리스트는 docs/HANDOFF.md의 "릴리즈 배포본 생성 완료" 절을 참고한다.

핵심 원칙만 요약한다:

  • 포함: bootstrap.cmd, README.md, LICENSE, pyproject.toml, src/, config/, scripts/, prompts/, docs/(필요한 만큼).
  • 제외: .venv/, data/, logs/, reports/, backup/, state/, tests/, __pycache__/, *.pyc, *.lnk, config.local.toml, service_key*, *oauth-token*.
  • 압축 해제 후 bootstrap.cmd가 정상 동작하는지 새 폴더에서 재현 검증한다.

5. 원격 저장소

정본 원격은 git.chanpaca.net(공개 저장소, Forgejo)이다.

git remote -v
# origin  ssh://git@git.chanpaca.net:2222/yunchan/DMF_Crawler.git

이 저장소는 **공개(public)**다. 그래서 커밋 전 다음을 반드시 확인한다(AGENTS.md §6와 동일):

  • API 키·OAuth 토큰·웹훅 URL·비밀번호가 코드·설정·로그·문서 어디에도 평문으로 없는가
  • config/config.local.toml, *.sqlite3, data/, logs/, reports/, backup/, state/.gitignore로 실제로 제외되는가 (git status 로 커밋 전 매번 확인)
  • 실제 수집 데이터(엑셀·DB)가 우연히 스테이징되지 않았는가