Trabajo en equipo y colaboración

Escribir una entrada de changelog que explique qué cambió y qué hacer

Convierte notas de versión sin procesar en una entrada de changelog que separe los cambios de las acciones necesarias del usuario y de los pasos de verificación. Una actualización sintética de software muestra cómo hacer que una nota de versión sea útil para alguien que no realizó el cambio.

Ver el índice

La traducción se ha realizado con IA. Comprueba el código, las unidades y los valores junto con el original. La revisión por hablantes nativos de cada idioma aún no se ha completado. English

Para quién esEsta guía está dirigida a equipos que necesitan notas de versión o changelogs de proyecto que expliquen tanto qué cambió como qué deben hacer los lectores a continuación.

Preparación
  • Python 3.12 y un comando de terminal que inicie esa versión.
  • Un editor de texto que pueda guardar archivos JSON y text files en UTF-8.
  • Una carpeta de trabajo donde el script pueda crear una nueva carpeta dentro de outputs.
  • Solo se requiere la biblioteca estándar de Python: json y pathlib.

01Separar el cambio de la acción del lector

Una entrada de changelog debe responder al menos tres preguntas prácticas: qué cambió, qué debe hacer el lector y cómo puede comprobar que la actualización funcionó. Una lista de implementation details puede ser correcta y, aun así, dejar a otro miembro del equipo sin saber si debe realizar alguna acción.

Este tutorial utiliza una pequeña release sintética con tres changes. Cada change tiene un area, una description factual y una required action. Una verification list separada indica al lector qué debe comprobar después de actualizar.

02Crear notas de versión sintéticas sin procesar

La siguiente release information es sintética y fue creada específicamente para este artículo. Guárdala como release_notes.json. Describe la version 1.4.0 de una herramienta ficticia de exportación CSV.

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

Hay exactamente 3 changes, 3 required actions y 3 verification checks. Como el ejemplo es sintético, estos paths, configuration names y behaviors son valores de demostración, no hechos sobre un producto real.

03Determinar manualmente la entrada de changelog esperada

La entrada debe comenzar con la version y la date. Las change descriptions deben mantenerse factuales. Las required actions deben utilizar instructions directas, y la verification debe ir separada para que los lectores distingan el trabajo de configuration de los 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.

La entrada esperada contiene una heading line, tres section headings y nueve bullet lines: tres changes, tres actions y tres checks. Ninguna action queda oculta dentro de un párrafo que describe el change.

04Generar y validar la entrada de changelog

Guarda el script siguiente como useful_changelog.py. Valida el JSON sintético, crea el changelog text, comprueba las section y bullet counts esperadas y escribe el resultado en una nueva output folder. El JSON original solo se lee.

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

05Comprobar el resultado esperado

Para esta release sintética, el script debería informar de tres changes, tres required actions, tres verification checks y nueve bullet lines. La salida de consola esperada que aparece a continuación se obtuvo manualmente y no es un execution log.

text
Changes: 3.
Required actions: 3.
Verification checks: 3.
Total bullets: 9.
Output: outputs/useful_changelog_result/CHANGELOG_ENTRY.txt
  • Confirma que cada change aparezca una vez bajo What changed.
  • Confirma que cada change tenga una instruction correspondiente bajo What you need to do.
  • Confirma que los verification steps estén separados de las required actions.
  • Confirma que los paths y configuration names se copien exactamente de las synthetic source notes.
  • Ejecuta el script de nuevo sin cambiar OUTPUT_DIR. Debería detenerse con FileExistsError en lugar de sustituir la entrada anterior.

06Reconocer entradas de changelog técnicamente correctas pero poco útiles

Texto débil de changelogQué falta
Updated export logicLos lectores no saben qué behavior cambió ni si deben actuar.
Fixed configurationNo se identifican la key afectada ni el replacement necesario.
Improved validationLa nueva failure condition y su efecto sobre los users no están claros.
Various bug fixesNo hay información sobre impact, scope ni required checks.
Please update accordinglyLa action es demasiado vaga para ejecutarla o verificarla.

Evita obligar al lector a reconstruir el cambio a partir de issue trackers, commits o chat history. Si una actualización cambia un path, key, command, file format o required input, indica directamente el old y el new behavior.

07Mantener el changelog limitado a consecuencias visibles para el usuario

Una entrada de changelog no sustituye technical documentation, migration instructions, test evidence ni version control history. Los changes complejos pueden necesitar links a esos materiales, pero el changelog debe seguir resumiendo la consequence y la immediate action.

No todo internal refactor necesita una entrada de changelog. Si behavior, interfaces, dependencies, required inputs, outputs, configuration o workflow no cambian para el lector, las implementation notes detalladas pueden pertenecer a otro lugar.

Para releases más grandes, agrupa los changes relacionados por area y distingue required actions de optional recommendations. Conserva las entradas antiguas del changelog en lugar de reescribir la historia, salvo que estés corrigiendo un documented error y puedas registrar claramente esa correction.

Registro de ejecución y verificación

2026-09-20 · ejemplo revisado manualmente · objetivo: Python 3.12 · biblioteca estándar: json, pathlib · sin ejecución

  • Se contaron manualmente 3 synthetic changes, 3 corresponding required actions y 3 verification checks.
  • Se obtuvo manualmente la entrada de changelog esperada con tres named sections.
  • Se calculó el total esperado como 9 bullet lines: 3 changes + 3 actions + 3 checks.
  • Se comprobó que los synthetic old and new export paths sean reports/ y outputs/reports/ y que los configuration names sean report_dir y output_dir.
  • Se revisó el script para required text validation, section checks, bullet-count validation, output collision protection y conservación del source JSON.
  • Se obtuvo manualmente la salida de consola esperada.
Límites de la verificación
  • El código no fue ejecutado por el autor de esta respuesta; no se creó ningún changelog file.
  • La version, los paths, las configuration keys y el validation behavior son ejemplos sintéticos y no describen un producto real.
  • El script valida la structure, pero no puede determinar si una change description escrita por una persona es completa o exacta.
  • Las URL de la documentación oficial se proporcionaron a partir de ubicaciones de documentación conocidas, pero no se comprobaron en línea.

Criterios de redacción y verificación de todo el sitio

Fuentes de referencia

Las explicaciones y los ejemplos son de elaboración propia. Puedes consultar los comportamientos y conceptos relacionados en las siguientes fuentes oficiales.