czg — Wizard interactivo de commits
Qué es
czg (cz-git) es un wizard de línea de comandos que guía al desarrollador a través de la creación de un mensaje de commit siguiendo el estándar Conventional Commits. En lugar de escribir el mensaje manualmente, el dev responde una serie de preguntas y czg construye el mensaje correctamente formateado.
En Wiedii, bun commit es el alias estándar que invoca czg.
Por qué lo usamos en Wiedii
- Elimina el margen de error humano en el formato de commits —
feat(auth): add OAuth2 loginsiempre va a estar bien escrito - Guía a devs nuevos que aún no tienen memorizado el formato Conventional Commits
- Se integra con commitlint — el hook
commit-msgvalida que el mensaje generado cumple las reglas, cerrando el ciclo - Velocidad — czg es significativamente más rápido que alternativas como
commitizenconcz-conventional-changelog
Instalación
czg va como devDependency en el package.json de cada repo. No se instala globalmente.
bun add -d czg cz-git @commitlint/cli @commitlint/config-conventional
{
"type": "module",
"scripts": {
"commit": "bun --bun git-czg"
},
"devDependencies": {
"@commitlint/cli": "21.0.1",
"@commitlint/config-conventional": "21.0.1",
"cz-git": "^1.13.1",
"czg": "^1.12.0"
},
"engines": {
"bun": "1.3.14",
"node": "Please use Bun instead of Node to install dependencies",
"npm": "Please use Bun instead of NPM to install dependencies",
"pnpm": "Please use Bun instead of PNPM to install dependencies",
"yarn": "Please use Bun instead of Yarn to install dependencies"
}
}
czgvscz-git—cz-gites dependencia transitiva deczg, pero se declara explícitamente porquecommitlint.config.jsla importa directamente (import { defineConfig } from 'cz-git').commitizenno se usa — en Wiedii solo se invocabun commit→czg.
"type": "module"— todos los repos nuevos en Wiedii usan ESM. El archivo de configuracióncommitlint.config.jsusaimport/export defaulten lugar derequire/module.exports.
bun --bun git-czg—bun --bunfuerza el runtime de Bun (más rápido que Node).git-czges el binario que instala czg; también habilitagit czgcomo subcomando de git.
engines— patrón Wiedii: mensajes de error en los campos de versión de otros package managers hace explícito que solo se usa Bun.
Uso
# Flujo estándar — siempre
git add .
bun commit # ejecuta: bun --bun git-czg → abre el wizard interactivo
El wizard hace las siguientes preguntas en orden:
- Tipo —
feat,fix,docs,style,refactor,perf,test,build,ci,chore,revert - Scope (opcional) — el módulo o área afectada, ej.
auth,api,ui - Título — descripción corta en imperativo, sin mayúscula inicial, sin punto final
- Cuerpo (opcional) — descripción larga con contexto adicional
- Breaking change — si es un cambio que rompe compatibilidad
- Issues relacionados (opcional) — referencia a issues de GitLab ej.
#42
El resultado es un mensaje como:
feat(auth): add OAuth2 login with GitLab provider
Implements OAuth2 flow using GitLab as identity provider.
Replaces the previous username/password form.
BREAKING CHANGE: removes /api/login endpoint
Closes #42
Configuración estándar en Wiedii
// commitlint.config.js — ESM (requiere "type": "module" en package.json)
import { defineConfig } from 'cz-git'
export default defineConfig({
extends: ['@commitlint/config-conventional'],
rules: {
'subject-case': [2, 'always', 'lower-case'],
'subject-full-stop': [2, 'never', '.'],
'header-max-length': [2, 'always', 100],
},
prompt: {
messages: {
type: "Select the type of change that you're committing:",
scope: 'Denote the SCOPE of this change (optional):',
customScope: 'Denote the SCOPE of this change:',
subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
breaking: 'List any BREAKING CHANGES (optional). Use "|" to break new line:\n',
footerPrefixesSelect: 'Select the ISSUES type of change (optional):',
customFooterPrefix: 'Input ISSUES prefix:',
footer: 'List any ISSUES by this change. E.g.: #31, #34:\n',
confirmCommit: 'Are you sure you want to proceed with the commit above?',
},
types: [
{ value: 'feat', name: 'feat: ✨ A new feature', emoji: '✨' },
{ value: 'fix', name: 'fix: 🐛 A bug fix', emoji: '🐛' },
{ value: 'docs', name: 'docs: 📝 Documentation only changes', emoji: '📝' },
{ value: 'style', name: 'style: 💄 Changes that do not affect the meaning of the code', emoji: '💄' },
{ value: 'refactor', name: 'refactor: ♻️ A code change that neither fixes a bug nor adds a feature', emoji: '♻️' },
{ value: 'perf', name: 'perf: ⚡️ A code change that improves performance', emoji: '⚡️' },
{ value: 'test', name: 'test: ✅ Adding missing tests or correcting existing tests', emoji: '✅' },
{ value: 'build', name: 'build: 📦️ Changes that affect the build system or external dependencies', emoji: '📦️' },
{ value: 'ci', name: 'ci: 🎡 Changes to CI configuration files and scripts', emoji: '🎡' },
{ value: 'chore', name: "chore: 🔨 Other changes that don't modify src or test files", emoji: '🔨' },
{ value: 'revert', name: 'revert: ⏪️ Reverts a previous commit', emoji: '⏪️' },
],
useEmoji: true,
emojiAlign: 'center',
scopes: [],
allowCustomScopes: true,
allowEmptyScopes: true,
customScopesAlign: 'bottom',
customScopesAlias: 'custom',
emptyScopesAlias: 'empty',
enableMultipleScopes: true,
scopeEnumSeparator: ',',
upperCaseSubject: false,
markBreakingChangeMode: false,
allowBreakingChanges: ['feat', 'fix'],
maxHeaderLength: 100,
maxSubjectLength: 100,
breaklineNumber: 100,
breaklineChar: '|',
skipQuestions: [],
issuePrefixes: [
{ value: 'closed', name: 'closed: ISSUES has been processed' },
{ value: 'Fixes', name: 'Fixes: 🐛 Fixes an open ISSUE' },
{ value: 'Ref', name: 'Ref: 🔗 Related ISSUES' },
],
emptyIssuePrefixAlias: 'skip',
customIssuePrefixAlias: 'custom',
allowCustomIssuePrefix: true,
allowEmptyIssuePrefix: true,
confirmColorize: true,
defaultBody: '',
defaultIssues: '',
defaultScope: '',
defaultSubject: '',
},
})
changelog.config.js
Archivo separado de commitlint.config.js. Lo consume conventional-changelog / Nx Release para generar CHANGELOG.md. Define los scopes del proyecto y el límite de longitud del mensaje.
// changelog.config.js — ESM
// Sobreescribe 'scopes' con los paquetes reales del repo
export default {
scopes: [], // ← completar con los módulos del proyecto
maxMessageLength: 100,
}
scopesdebe reflejar exactamente los mismos valores definidos encommitlint.config.js→rules['scope-enum']cuando el proyecto tiene scopes fijos.
Integración con lefthook
El hook commit-msg valida el mensaje generado por czg antes de completar el commit:
# lefthook.yaml
commit-msg:
parallel: false
jobs:
- run: mise trust
- run: mise install --yes
commands:
commitlint:
priority: 1
run: mise exec -- bun commitlint --config commitlint.config.js --edit "$1"
Si el mensaje no cumple las reglas de commitlint.config.js, el commit se rechaza con un mensaje de error claro.
Troubleshooting rápido
bun commit abre el wizard pero el commit falla con error de commitlint:
# Verificar que commitlint.config.js existe en la raíz del repo
ls commitlint.config.js
# Probar commitlint manualmente
bun commitlint --from HEAD~1
El wizard no muestra los tipos personalizados:
# Verificar que commitlint.config.js exporta el bloque `prompt`
# y que czg y cz-git están en devDependencies, no en dependencies
cat package.json | grep -E "czg|cz-git"
bun commit no encuentra czg:
# Verificar que está instalado
bun install
ls node_modules/.bin/czg
Referencias
- Documentación oficial czg
- Conventional Commits spec
- commits — política completa de mensajes de commit en Wiedii
- lefthook — el hook
commit-msgvalida el mensaje generado por czg - bun —
bun commites el alias estándar para invocar czg