チーム業務・コラボレーション

何が変わり、何をすべきかが伝わる changelog entry を書く

生の release notes を、変更内容、必要な user actions、verification steps に分けた changelog entry に変換します。合成の software update を使い、変更を行っていない人にも役立つ release note の作り方を示します。

目次を表示

この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 English

対象読者何が変わったかだけでなく、読者が次に何をすべきかまで伝える release notes や project changelogs を必要とするチーム向けのガイドです。

準備するもの
  • Python 3.12 と、そのバージョンを起動できるターミナルコマンド。
  • UTF-8 JSON と text files を保存できるテキストエディタ。
  • スクリプトが outputs の下に新しいフォルダを作成できる作業フォルダ。
  • 必要なのは Python 標準ライブラリのみです: json, pathlib.

01変更内容と読者の action を分ける

changelog entry は少なくとも3つの実務的な質問に答える必要があります: 何が変わったか、読者は何をする必要があるか、update が正しく動作したことをどう確認するか。implementation details の一覧が正確でも、他の team member に action が必要かどうか伝わらない場合があります。

このチュートリアルでは、3つの changes を含む小さな合成 release を使用します。各 change には area、事実に基づく description、required action があります。別の verification list で、更新後に何を確認するかを示します。

02合成の raw release notes を作成する

以下の release information は合成データであり、この記事のために作成したものです。release_notes.json として保存してください。架空の CSV export tool の version 1.4.0 を説明しています。

json
{
  "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."
  ]
}

changes は正確に3件、required actions は3件、verification checks は3件あります。この例は合成なので、paths, configuration names, behaviors は実在製品に関する事実ではなく、デモ用の値です。

03想定される changelog entry を手作業で作成する

entry は version と date から始めます。change descriptions は事実に基づいたままにします。required actions は直接的な instructions とし、verification は別にして、読者が configuration work と post-update checks を区別できるようにします。

text
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.

想定 entry には heading line が1行、section headings が3つ、bullet lines が9行あります: changes 3件、actions 3件、checks 3件です。change を説明する paragraph の中に action を隠しません。

04changelog entry を生成して検証する

次のスクリプトを useful_changelog.py として保存してください。合成 JSON を検証し、changelog text を作成し、想定される section と bullet counts を確認して、新しい output folder に結果を書き込みます。元の JSON file は読み取り専用です。

python
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()

05想定結果を確認する

この合成 release では、スクリプトは changes 3件、required actions 3件、verification checks 3件、bullet lines 9行を報告するはずです。以下の想定 console output は手作業で導出したもので、execution log ではありません。

text
Changes: 3.
Required actions: 3.
Verification checks: 3.
Total bullets: 9.
Output: outputs/useful_changelog_result/CHANGELOG_ENTRY.txt
  • 各 change が What changed の下に1回ずつ表示されていることを確認します。
  • すべての change に対応する instruction が What you need to do の下にあることを確認します。
  • verification steps が required actions と分離されていることを確認します。
  • paths と configuration names が合成 source notes から正確にコピーされていることを確認します。
  • OUTPUT_DIR を変更せずにスクリプトを再実行します。以前の entry を置き換えるのではなく FileExistsError で停止するはずです。

06技術的には正しいが役に立たない changelog entry を見分ける

弱い changelog text不足していること
Updated export logicどの behavior が変わったのか、action が必要なのか読者には分かりません。
Fixed configuration影響する key と必要な replacement が特定されていません。
Improved validation新しい failure condition と users への影響が不明確です。
Various bug fixesimpact, scope, required checks に関する情報がありません。
Please update accordinglyaction が曖昧すぎて、実行も検証もできません。

読者に issue trackers, commits, chat history から変更内容を再構成させないでください。update により path, key, command, file format, required input が変わる場合は、old behavior と new behavior を直接記載します。

07changelog を user-visible consequences に限定する

changelog entry は technical documentation, migration instructions, test evidence, version control history の代わりにはなりません。複雑な変更ではそれらへの links が必要になる場合がありますが、それでも changelog では consequence と immediate action を要約する必要があります。

すべての internal refactor に changelog entry が必要なわけではありません。behavior, interfaces, dependencies, required inputs, outputs, configuration, workflow が読者にとって変わらない場合、詳細な implementation notes は別の場所に置く方が適切です。

より大きな releases では、関連する changes を area ごとにまとめ、required actions と optional recommendations を区別します。documented error を修正し、その correction を明確に記録できる場合を除き、過去の changelog entries を書き換えず保持してください。

実行・検証の記録

2026-09-20 · 手作業で確認した例 · 対象: Python 3.12 · 標準ライブラリ: json, pathlib · 未実行

  • 合成 changes 3件、それぞれに対応する required actions 3件、verification checks 3件を手作業で数えました。
  • 3つの named sections を持つ想定 changelog entry を手作業で導出しました。
  • 想定合計を 9 bullet lines: 3 changes + 3 actions + 3 checks と計算しました。
  • 合成の old and new export paths が reports/ と outputs/reports/ であり、configuration names が report_dir と output_dir であることを確認しました。
  • required text validation, section checks, bullet-count validation, output collision protection, source JSON の保持についてスクリプトを確認しました。
  • 想定される console output を手作業で導出しました。
検証範囲の限界
  • この回答の作成者はコードを実行しておらず、changelog file は作成していません。
  • version, paths, configuration keys, validation behavior は合成例であり、実在する製品について説明するものではありません。
  • スクリプトは structure を検証しますが、人が書いた change description が完全または正確かどうかは判断できません。
  • 公式ドキュメントの URL は既知のドキュメント所在地に基づいて記載していますが、ライブでは確認していません。

サイト全体の執筆・検証方針

参考資料

説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。