팀 파일명 규칙을 정하고 Python으로 검사하기
간단한 팀 파일명 규칙을 정하고 합성 폴더에서 검사한 뒤, 어떤 파일도 이름을 바꾸거나 삭제하지 않고 검토용 보고서를 작성합니다. 검사기는 구조 오류, 잘못된 날짜, 허용되지 않은 확장자를 구분할 수 있습니다.
원시 변경 메모를 변경 내용, 사용자 조치, 검증 단계가 구분된 변경 로그로 정리합니다. 합성 소프트웨어 업데이트 예제를 이용해 변경을 만든 사람이 아닌 동료에게도 유용한 릴리스 기록을 만드는 방법을 확인합니다.
이런 분께 맞아요변경 내용뿐 아니라 업데이트 후 독자가 무엇을 해야 하는지까지 명확하게 전달하는 릴리스 노트나 프로젝트 변경 로그가 필요한 팀을 위한 안내입니다.
변경 로그는 최소한 세 가지 실무 질문에 답해야 합니다. 무엇이 바뀌었는지, 독자가 무엇을 해야 하는지, 업데이트가 정상적으로 적용되었는지 어떻게 확인할지를 알려줘야 합니다. 구현 세부사항만 나열하면 내용 자체는 정확해도 다른 팀원이 실제로 조치해야 하는지 판단하기 어렵습니다.
이 예제에서는 세 가지 변경이 있는 작은 합성 릴리스를 사용합니다. 각 변경에는 영역, 사실적인 변경 설명, 필요한 조치가 있습니다. 별도의 검증 목록에서는 업데이트 후 무엇을 확인해야 하는지 정리합니다.
아래 릴리스 정보는 이 글을 위해 작성한 합성 데이터입니다. release_notes.json으로 저장하세요. 가상의 CSV export 도구 버전 1.4.0에 대한 변경을 설명합니다.
{
"version": "1.4.0",
"date": "2026-09-20",
"changes": [
{
"area": "Export path",
"change": "Default CSV export folder changed from reports/ to outputs/reports/.",
"action": "Update scripts or shortcuts that expect reports/."
},
{
"area": "Config key",
"change": "Configuration key report_dir was renamed to output_dir.",
"action": "Rename report_dir to output_dir before the next run."
},
{
"area": "Validation",
"change": "Empty customer_id values now stop export instead of being written as blank cells.",
"action": "Fix blank customer_id values before rerunning failed exports."
}
],
"checks": [
"Confirm a test export appears under outputs/reports/.",
"Confirm the configuration uses output_dir.",
"Confirm a row with a blank customer_id stops with a validation error."
]
}
변경은 정확히 3개이고 필요한 조치도 3개이며 검증 항목도 3개입니다. 합성 예제이므로 경로, 설정 이름, 동작은 실제 제품에 대한 사실이 아니라 설명을 위한 예시입니다.
변경 로그는 버전과 날짜로 시작합니다. 변경 설명은 사실적으로 유지하고, 필요한 조치는 직접 실행할 수 있는 문장으로 작성해야 합니다. 검증 단계는 별도로 분리하여 설정 작업과 업데이트 후 확인 작업을 구분합니다.
Version 1.4.0 - 2026-09-20
What changed
- Export path: Default CSV export folder changed from reports/ to outputs/reports/.
- Config key: Configuration key report_dir was renamed to output_dir.
- Validation: Empty customer_id values now stop export instead of being written as blank cells.
What you need to do
- Update scripts or shortcuts that expect reports/.
- Rename report_dir to output_dir before the next run.
- Fix blank customer_id values before rerunning failed exports.
Check after updating
- Confirm a test export appears under outputs/reports/.
- Confirm the configuration uses output_dir.
- Confirm a row with a blank customer_id stops with a validation error.
예상 변경 로그에는 버전과 날짜가 있는 한 줄, 섹션 제목 3개, bullet 9개가 있습니다. 변경 3개, 조치 3개, 검증 3개입니다. 필요한 조치가 변경 설명 문단 속에 숨겨져 있지 않습니다.
다음 스크립트를 useful_changelog.py로 저장하세요. 합성 JSON을 검증하고 변경 로그 텍스트를 만든 뒤 예상 섹션과 bullet 수를 확인합니다. 결과는 새 출력 폴더에 저장하며 원본 JSON은 읽기만 합니다.
import json
from pathlib import Path
SOURCE = Path("release_notes.json")
OUTPUT_DIR = Path("outputs") / "useful_changelog_result"
OUTPUT = OUTPUT_DIR / "CHANGELOG_ENTRY.txt"
def require_text(value, name):
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{name} must be a non-empty string.")
return value.strip()
def main() -> None:
if not SOURCE.is_file():
raise FileNotFoundError(f"Source file not found: {SOURCE}")
if OUTPUT_DIR.exists():
raise FileExistsError(f"Output folder already exists: {OUTPUT_DIR}")
with SOURCE.open("r", encoding="utf-8") as stream:
data = json.load(stream)
version = require_text(data.get("version"), "version")
date = require_text(data.get("date"), "date")
changes = data.get("changes")
checks = data.get("checks")
if not isinstance(changes, list) or not changes:
raise ValueError("changes must be a non-empty list.")
if not isinstance(checks, list) or not checks:
raise ValueError("checks must be a non-empty list.")
change_lines = []
action_lines = []
for index, item in enumerate(changes, start=1):
if not isinstance(item, dict):
raise ValueError(f"Change {index} must be an object.")
area = require_text(item.get("area"), f"change {index} area")
change = require_text(item.get("change"), f"change {index} description")
action = require_text(item.get("action"), f"change {index} action")
change_lines.append(f"- {area}: {change}")
action_lines.append(f"- {action}")
check_lines = [f"- {require_text(value, 'check')}" for value in checks]
lines = [
f"Version {version} - {date}",
"",
"What changed",
*change_lines,
"",
"What you need to do",
*action_lines,
"",
"Check after updating",
*check_lines,
]
text = "\n".join(lines) + "\n"
if text.count("\nWhat changed\n") != 1:
raise RuntimeError("Missing What changed section.")
if text.count("\nWhat you need to do\n") != 1:
raise RuntimeError("Missing action section.")
if text.count("\nCheck after updating\n") != 1:
raise RuntimeError("Missing verification section.")
bullet_count = sum(line.startswith("- ") for line in lines)
expected_bullets = len(changes) * 2 + len(checks)
if bullet_count != expected_bullets:
raise RuntimeError("Unexpected bullet count.")
OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
OUTPUT_DIR.mkdir()
with OUTPUT.open("x", encoding="utf-8") as stream:
stream.write(text)
print(f"Changes: {len(changes)}.")
print(f"Required actions: {len(action_lines)}.")
print(f"Verification checks: {len(checks)}.")
print(f"Total bullets: {bullet_count}.")
print(f"Output: {OUTPUT.as_posix()}")
if __name__ == "__main__":
main()
이 합성 릴리스에서는 변경 3개, 필요한 조치 3개, 검증 항목 3개, bullet 9개가 보고되어야 합니다. 아래 콘솔 출력은 손으로 도출한 예상값이며 실제 실행 로그가 아닙니다.
Changes: 3.
Required actions: 3.
Verification checks: 3.
Total bullets: 9.
Output: outputs/useful_changelog_result/CHANGELOG_ENTRY.txt| 약한 변경 로그 문장 | 빠진 정보 |
|---|---|
| Updated export logic | 어떤 동작이 바뀌었고 독자가 조치해야 하는지 알 수 없습니다. |
| Fixed configuration | 어떤 설정 키가 영향을 받았고 무엇으로 바꿔야 하는지 없습니다. |
| Improved validation | 새로운 실패 조건과 사용자에게 미치는 영향이 불분명합니다. |
| Various bug fixes | 영향, 범위, 확인 방법이 없습니다. |
| Please update accordingly | 실행하거나 검증할 수 있을 정도로 구체적인 조치가 아닙니다. |
독자가 issue tracker, commit, 채팅 기록을 다시 찾아 변경 내용을 재구성하게 만들지 마세요. 경로, 키, 명령, 파일 형식, 필수 입력이 바뀌었다면 이전 동작과 새 동작을 직접 적는 편이 좋습니다.
변경 로그는 기술 문서, migration guide, 시험 결과, 버전 관리 이력을 대신하지 않습니다. 복잡한 변경은 이런 자료의 링크가 필요할 수 있지만, 변경 로그 자체에도 영향과 즉시 필요한 조치를 요약해야 합니다.
모든 내부 refactor를 변경 로그에 적을 필요는 없습니다. 독자의 동작, 인터페이스, 의존성, 필수 입력, 출력, 설정, 업무 절차가 바뀌지 않는다면 세부 구현 기록은 다른 위치가 더 적절할 수 있습니다.
큰 릴리스에서는 관련 변경을 영역별로 묶고 필수 조치와 선택적 권장 사항을 구분하세요. 문서 오류를 수정하는 경우가 아니라면 과거 변경 로그를 다시 써서 이력을 바꾸기보다 기존 기록을 보존하는 편이 좋습니다.
2026-09-20 · 예제 수동 검토 · 대상: Python 3.12 · 표준 라이브러리: json, pathlib · 실행하지 않음
설명과 예제는 직접 작성했습니다. 관련 동작과 개념은 아래 공식 자료에서 확인할 수 있습니다.