Skip to content

release: v2.2.0 - change @Last modified by only when the file's content… - #129

Merged
cldmv-bot[bot] merged 5 commits into
masterfrom
next
Oct 4, 2026
Merged

cldmv-bot[bot] merged 5 commits into
masterfrom
next

Conversation

@cldmv-bot

@cldmv-bot cldmv-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

@cldmv/fix-headers v2.2.0 Changelog

Release Date: October 2026
Release Type: Minor
Branch: release/2.2.0


Overview

Version 2.2.0 changes what @Last modified by means. It now names whoever last edited the file's content, the part of the file outside the header, instead of whoever last ran fix-headers. A run that only rewrites a header (a date format conversion, a corrected @Project, new spacing or margin) keeps the recorded editor, so running the tool never claims other people's files. @Author was already the original author and stays that way unless forceAuthorUpdate is set.

No option was removed, the fixHeaders API and the header format are unchanged, and @Last modified time is still restamped whenever a header is rewritten. See the upgrade notes for the one behaviour change that can show up in an existing setup.


✨ Features

@Last modified by follows content edits, not header rewrites (#128, closes #127)

Before, any run that changed a header could write the identity detected for that run into @Last modified by, and with forceLastModifiedAuthorUpdate it did so on every file. With a shared config that forces the author fields, whoever ran the tool became the last editor of every file it touched, including files they never opened.

fix-headers now decides whether a file's content was edited by comparing it with the file at git HEAD. The header is taken out of both versions, along with the blank lines after it, and what is left is compared:

File Content edited? @Author @Last modified by @Last modified time
Tracked, body the same as at HEAD, header rewritten no kept kept now
Tracked, body differs from HEAD yes kept run identity now
Not in HEAD (new, untracked or ignored, or no commits yet) yes kept (filled when missing) run identity now
Outside a git work tree, header rewritten cannot tell, treated as no kept kept now
Header already current, content not edited no unchanged unchanged unchanged
  • Header-only rewrites keep the recorded editor. The date format (normalizeDateFormat), an epoch repair, @Date (fixCreatedDate), a time zone conversion, the frame, spacing and margin, and the @Project, @Filename and @Copyright values all rewrite the header without changing who last edited the file. @Last modified time still moves, because the header did.
  • A content edit makes the run's identity the last editor. That is the identity detected for the run (authorName / authorEmail, or git as described under useGpgSignerAuthor). A missing field is filled with it in every case, and a file with no header gets it in both fields. Adding a header to a committed file is not a content edit, so a later header-only run by someone else keeps whoever was recorded then.
  • A repeat edit by the editor already recorded is stamped once. When the body differs from HEAD and the recorded time is older than the file's last commit, the edit has not been stamped yet, so @Last modified time is restamped even though the editor is unchanged. Once stamped, the time is newer than the last commit and running fix-headers again changes nothing until the next commit.
  • forceLastModifiedAuthorUpdate keeps its meaning (write the run identity as @Last modified by on every file, edited or not), and forceAuthorUpdate still replaces an existing @Author / @Email. With content-edit detection, forceLastModifiedAuthorUpdate is no longer needed for normal use, and the README says so. The --help text for both force flags is reworded to match what they do.
  • The issues result follows the same rule. The lastModifiedByName / lastModifiedByEmail entries appear only when the value that would be written really differs from the existing header, which now depends on whether the content was edited.

The check compares the working tree with HEAD, so run fix-headers before committing (a pre-commit hook, or npm run fix:headers before git commit). Content committed without a run is not detected later, because by then the body matches HEAD. The README gains an Author and last modified section with the same table and rules.

🧪 Tests

  • New suite tests/last-modified-content-edit.test.vitest.mjs covers header-only rewrites that keep the editor, body edits that take the run identity, @Author preserved for a different runner, forceAuthorUpdate still replacing it, untracked and new files, files outside a git work tree, and the one-time restamp of a repeat edit. tests/core-edge.test.vitest.mjs and tests/sample-output.test.vitest.mjs are updated for the new issues output. Coverage stays at 100%.

📚 Documentation

🔧 Dependencies

No dependency updates. ignore, the only runtime dependency, is unchanged.


Upgrade notes

  • No breaking changes: no option was removed and the API is unchanged.
  • @Last modified by can differ from before after a run. A header-only rewrite no longer writes the run's identity into it, and a content edit now does. A config that sets forceLastModifiedAuthorUpdate keeps the old behaviour (the run identity on every file) and can drop that option once its files carry the right editor.
  • Run the tool before you commit. The edit check reads the working tree against HEAD, so a hook or script that runs fix-headers after the commit will see an unchanged body and keep the recorded editor.
  • Outside a git work tree nothing is detected as an edit, so recorded editors are kept and only @Last modified time moves when a header is rewritten.
  • Preview the effect on your project with --dry-run --diff --verbose.
👥 Contributors

coverage

Metric Coverage
Statements 100.0%
Branches 100.0%
Functions 100.0%
Lines 100.0%

Avg: 100.0% · e643b86 · Node lts/*

Co-authored-by: Shinrai Shinrai@users.noreply.github.com

Shinrai and others added 3 commits October 3, 2026 22:51
@last modified by now records whoever last edited the file's content
(everything outside the header), not whoever last ran fix-headers. The
content counts as edited when the file's body, with the header taken out,
differs from its body at git HEAD, or when HEAD does not have the file
(new, untracked or ignored). Header rewrites fix-headers makes on its own
(date format, epoch repair, fixCreatedDate, time zone conversion, frame,
spacing, margin, @Project/@Filename/@copyright) still restamp
@last modified time but keep the recorded editor. Outside a git work tree
content edits cannot be detected and the recorded editor is kept.

A content edit by the editor already recorded is restamped once when the
recorded time is older than the file's last commit, so repeat edits move
the time without making re-runs churn.

@Author/@Email stay the original author unless forceAuthorUpdate is set.
forceLastModifiedAuthorUpdate keeps its previous meaning (write the run
identity on every file) and is documented as not needed for normal use.

Closes #127
@cldmv-bot cldmv-bot Bot added ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: minor This release adds new functionality in a backwards-compatible way type: feature Implements new functionality — a PR or issue that adds a feature labels Oct 4, 2026
@cldmv-bot

cldmv-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor Author

🔒 Dependency Review

  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses
  • ✅ 0 denied package(s)
  • ✅ 0 package(s) with OpenSSF Scorecard score < 3

Full job summary

@cldmv-bot cldmv-bot Bot added area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure type: dependencies Relates to dependency updates, version bumps, or package management type: documentation Relates to docs, README updates, guides, or inline code comments labels Oct 4, 2026
@cldmv-bot

cldmv-bot Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

📦 Bundle size unchanged

File Raw Δ Raw Gzipped Δ Gzipped
bin/fix-headers.mjs 51.8 kB +472 B (+0.9%) 17.6 kB +360 B
dist/index.cjs 1.6 kB — 940 B —
dist/index.mjs 42.6 kB +438 B (+1.0%) 14.7 kB +330 B
Total 96.0 kB +910 B 33.2 kB +690 B

📊 Generated by bundle-size. Brotli sizes also measured but omitted from the table for brevity.

Shinrai and others added 2 commits October 3, 2026 23:12
Add docs/changelog/v2/v2.2.0.md for the @last modified by content-edit change (#128) and promote v2.2.0 to Latest in the README, moving v2.1.4 into Recent Releases.
@cldmv-bot
cldmv-bot Bot merged commit fc1f59b into master Oct 4, 2026
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: minor This release adds new functionality in a backwards-compatible way type: dependencies Relates to dependency updates, version bumps, or package management type: documentation Relates to docs, README updates, guides, or inline code comments type: feature Implements new functionality — a PR or issue that adds a feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Header-only rewrites must not touch @Last modified by/time; @Author is never changed unless forced

1 participant