Skip to content

fix(changelog): restore cwd-relative resolution for --file-name CLI arg - #1987

Open
bearomorphism wants to merge 2 commits into
commitizen-tools:masterfrom
bearomorphism:fix/1411-relative-path-resolution
Open

fix(changelog): restore cwd-relative resolution for --file-name CLI arg#1987
bearomorphism wants to merge 2 commits into
commitizen-tools:masterfrom
bearomorphism:fix/1411-relative-path-resolution

Conversation

@bearomorphism

Copy link
Copy Markdown
Collaborator

Description

Why

Fixes #1411 — relative paths work differently with newer versions.

The user reported that after upgrading to v4.6.3, the following command stopped working as expected:

# run from a Sphinx docs subdirectory
cz -n cz_customize changelog --file-name=changelog/file

Before v4.6.3: the file was created at <cwd>/changelog/file (relative to the directory where cz was invoked — standard CLI behaviour).
After v4.6.3: the file is created at <project_root>/changelog/file (relative to the config file's directory), ignoring cwd.

What changed

Source Before v4.6.3 After v4.6.3 (broken) After this PR (fixed)
--file-name CLI arg relative to cwd relative to config dir relative to cwd
changelog_file config setting relative to cwd relative to config dir relative to config dir

PR #1391 (v4.6.3) fixed a real bug — cz bump --changelog from a subdirectory was writing the changelog relative to the subdirectory instead of the project root. However, it applied the config-dir anchor to both sources: the config-file changelog_file setting AND the CLI --file-name argument. This over-correction broke existing setups that relied on --file-name being cwd-relative.

How it works

commitizen/commands/changelog.py: The __init__ method now distinguishes between the two sources:

  • arguments.get("file_name") (CLI arg) → used as-is, relative to cwd
  • config.settings.get("changelog_file") (config setting) → resolved relative to config.path.parent

commitizen/commands/bump.py: When Bump invokes Changelog, it previously always forwarded file_name (even when the value came from config). It now only forwards file_name if it was explicitly provided via CLI (--file-name). Without a forwarded file_name, Changelog falls through to its own config lookup and applies the correct config-dir anchor.

Backward compatibility

  • Users who relied on --file-name being resolved relative to cwd: behaviour restored to pre-v4.6.3.
  • Users who relied on changelog_file in config being resolved relative to the config dir: no change, the PR fix: cz bump subdir #1391 behaviour is preserved.
  • Users who ran cz bump --changelog without --file-name from a subdirectory: no change, the changelog still goes to the project root (the PR fix: cz bump subdir #1391 fix is preserved).

Checklist

Was generative AI tooling used to co-author this PR?

  • Yes (GitHub Copilot CLI)

Code Changes

  • Add test cases to all the changes you introduce
  • Run uv run poe all locally to ensure this change passes linter check and tests
  • Manually test the changes:
    • Verify the feature/bug fix works as expected in real-world scenarios
    • Test edge cases and error conditions
    • Ensure backward compatibility is maintained
  • Update the documentation for the changes

Expected Behavior

cz changelog --file-name=changelog/CHANGES.md run from any working directory should write the changelog to <cwd>/changelog/CHANGES.md.

changelog_file = "CHANGELOG.md" in pyproject.toml should write the changelog to <project_root>/CHANGELOG.md, regardless of the working directory.

Steps to Test This Pull Request

# Setup
git init /tmp/test-cz && cd /tmp/test-cz
git commit --allow-empty -m "feat: initial"
cat > pyproject.toml << 'EOF'
[tool.commitizen]
version = "0.1.0"
changelog_file = "CHANGELOG.md"
EOF

# 1. Verify: cz changelog --file-name from a subdir uses cwd
mkdir -p subdir && cd subdir
cz changelog --file-name=mychangelog.md --dry-run
# Should show changelog content without creating /tmp/test-cz/mychangelog.md

# 2. Verify: cz bump --changelog writes to project root even from subdir
cd /tmp/test-cz/subdir
git commit --allow-empty -m "feat: a feature"
cz bump --changelog --dry-run
# Changelog should go to /tmp/test-cz/CHANGELOG.md, NOT /tmp/test-cz/subdir/CHANGELOG.md

Additional Context

bearomorphism and others added 2 commits May 9, 2026 22:25
Closes commitizen-tools#1331

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When --file-name is passed on the command line, the path should be
interpreted relative to the current working directory, as is standard
for CLI tools.  When changelog_file is read from the configuration
file it should be anchored to the config file's directory so the
result is stable regardless of where cz is invoked.

PR commitizen-tools#1391 / v4.6.3 inadvertently applied the config-dir anchor to
BOTH sources, breaking setups where users specify a cwd-relative path
via --file-name (e.g. from a Sphinx docs subdirectory).

Changes:
- commitizen/commands/changelog.py: distinguish args-provided
  file_name (cwd-relative) from config-provided changelog_file
  (config-dir-relative)
- commitizen/commands/bump.py: only forward file_name to Changelog
  when it was explicitly supplied via CLI; otherwise let Changelog
  perform its own config lookup so the anchor logic is applied correctly
- tests/test_changelog.py: replace the PR-commitizen-tools#1391 test with a
  parametrised regression test covering all four combinations
- docs/commands/changelog.md: document the two resolution strategies

Fixes commitizen-tools#1411

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@codecov

codecov Bot commented May 9, 2026

Copy link
Copy Markdown

⚠️ JUnit XML file not found

The CLI was unable to find any JUnit XML files to upload.
For more help, visit our troubleshooting guide.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restores pre-v4.6.3 behavior for cz changelog --file-name by making CLI-provided paths resolve relative to the current working directory, while preserving config-provided changelog_file resolution relative to the config file directory. It also introduces a new cz dump-config command with docs/tests.

Changes:

  • Fix changelog output path resolution by distinguishing CLI --file-name vs config changelog_file sources.
  • Adjust cz bump --changelog to only forward file_name to Changelog when explicitly provided via CLI.
  • Add a new cz dump-config command, along with documentation and tests.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
commitizen/commands/changelog.py Implements source-aware path resolution for changelog output filename.
commitizen/commands/bump.py Ensures Bump only forwards CLI --file-name, letting Changelog resolve config-relative paths.
tests/test_changelog.py Updates/extends tests to validate the new filename resolution behavior.
docs/commands/changelog.md Documents the CLI-vs-config relative path behavior.
commitizen/commands/dump_config.py Adds the DumpConfig command implementation.
commitizen/commands/__init__.py Exposes DumpConfig in the commands package.
commitizen/cli.py Registers the new dump-config subcommand and help text.
tests/commands/test_dump_config_command.py Adds tests for dump-config output formats.
tests/commands/test_common_command.py Includes dump-config in the common --help regression tests.
tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_10_dump_config_.txt Adds help output snapshot for dump-config (Py 3.10).
tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_11_dump_config_.txt Adds help output snapshot for dump-config (Py 3.11).
tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_12_dump_config_.txt Adds help output snapshot for dump-config (Py 3.12).
tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_13_dump_config_.txt Adds help output snapshot for dump-config (Py 3.13).
tests/commands/test_common_command/test_command_shows_description_when_use_help_option_py_3_14_dump_config_.txt Adds help output snapshot for dump-config (Py 3.14).
docs/commands/dump_config.md Adds documentation for the new dump-config command.
mkdocs.yml Adds the new dump-config docs page to navigation and plugin config.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +39 to +46
{"tool": {"commitizen": settings}},
default_flow_style=False,
allow_unicode=True,
)
)
else:
out.write(
json.dumps({"tool": {"commitizen": settings}}, indent=2, default=str)
Comment thread commitizen/cli.py
Comment on lines +200 to +213
{
"name": "dump-config",
"description": "Output the current commitizen configuration",
"help": "Output the current commitizen configuration.",
"func": commands.DumpConfig,
"arguments": [
{
"name": ["--format", "-f"],
"choices": ["toml", "yaml", "json"],
"default": "toml",
"help": "Output format (default: toml).",
}
],
},
Comment on lines +33 to +44
assert "tool" in data
assert "commitizen" in data["tool"]
assert data["tool"]["commitizen"]["name"] == "cz_conventional_commits"


def test_dump_config_json(config, capsys):
DumpConfig(config, {"format": "json"})()
out, _ = capsys.readouterr()
data = json.loads(out)
assert "tool" in data
assert "commitizen" in data["tool"]
assert data["tool"]["commitizen"]["name"] == "cz_conventional_commits"
Comment on lines +1 to +16
# dump-config

Output the current commitizen configuration (defaults merged with any project overrides) so you can paste it directly into a configuration file as a starting point.

## Usage

```
cz dump-config [--format {toml,yaml,json}]
```

## Options

| Option | Description |
|---|---|
| `--format`, `-f` | Output format: `toml` (default), `yaml`, or `json` |

@Manny7717 Manny7717 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified: the changelog fix is correct; one scope concern before merge

The fix (a7da2ca) — verified locally, regression-proven:

  • Changelog.__init__ now distinguishes CLI-provided --file-name (kept as-is, cwd-relative) from config-provided changelog_file (anchored to the config file's directory); Bump forwards file_name to Changelog only when it came from the CLI. Matches the pre-4.6.3 contract from #1411 and keeps the #1391 config-dir fix for the config path.
  • New parametrized test_changelog_file_name_resolution: 4/4 pass on head; 2/4 FAIL on master (the two CLI-arg cases get config-dir-anchored, e.g. changelog/CHANGES.rst/my/project/changelog/CHANGES.rst) — clean regression proof.
  • End-to-end repro of the #1411 scenario: from a docs/ subdir, cz changelog --file-name=changelog/new.md writes to <cwd>/changelog/new.md; config-only changelog_file writes to <root>/CHANGELOG.md. Both correct.
  • tests/test_changelog.py + tests/commands/test_bump_command.py: 199 passed. ruff check/format clean, mypy clean on the 3 touched source files.

Scope concern (3f891ed): the PR bundles an unrelated feature — feat: cz dump-config (12 files, +219: new command + docs + 5 tests, all verified passing 5/5) — into a bugfix PR whose title and body only describe the changelog fix. Per the repo's contribution rules the commit type controls release impact: squash-merging this as fix(changelog): would ship a new user-facing feature in a patch release, and splitting it would let the fix land fast while the feature gets its own review/release cycle. Recommend splitting the dump-config commit into its own PR and keeping a7da2ca alone here.

Fix itself: no blockers. Happy to re-approve once scoped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment