commitfmt-darwin-x64 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +114 -56
  2. package/commitfmt +0 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -19,22 +19,39 @@
19
19
  </a>
20
20
  </p>
21
21
 
22
- It's not a linter. At least not a complete replacement for [commitlint](https://commitlint.js.org), because commitfmt can't prevent you from writing a body or force you to write a description in uppercase (I don't know why you might want to do that), but it will help keep git history clean and readable.
22
+ commitfmt is an opinionated formatter and configurable linter for Git commit messages. Designed primarily for use in a Git `prepare-commit-msg` hook, it helps keep commit history clean and readable.
23
23
 
24
- By design, commitfmt runs on the `prepare-commit-msg` hook and formats the message according to git standards and [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) in particular.
24
+ ## Quick start
25
+
26
+ The example below installs commitfmt as a local npm development dependency. See [Installation](#installation) for standalone and Python alternatives.
27
+
28
+ ```bash
29
+ npm install --save-dev commitfmt
30
+ ```
31
+
32
+ Try the default formatting mode:
33
+
34
+ ```bash
35
+ printf '%s\n' "feat ( parser ) : add new option." | npm exec -- commitfmt
36
+ # feat(parser): add new option
37
+ ```
38
+
39
+ Then add `npm exec -- commitfmt` to a Git `prepare-commit-msg` hook using one of the [hook examples](#hook). No configuration is required for formatting. To enforce project-specific rules, add a [configuration file](#configuration) to the repository root.
40
+
41
+ See [Modes](#modes) for the difference between formatting a message, linting a message, and checking commit history.
25
42
 
26
43
  ## Features
27
44
 
28
45
  ### Formatting
29
46
 
30
- commitfmt by default transforms a message like this:
47
+ By default, commitfmt transforms a message like this:
31
48
 
32
49
  ```
33
50
  feat ( scope , scope ) : add new feature.
34
51
  body description
35
52
  ```
36
53
 
37
- into well-formatted message:
54
+ into a well-formatted message:
38
55
 
39
56
  ```
40
57
  feat(scope, scope): add new feature
@@ -44,9 +61,9 @@ body description
44
61
 
45
62
  ### Linting
46
63
 
47
- commitfmt can check that developers follow the rules set by the project.
64
+ commitfmt can enforce project-specific commit rules.
48
65
 
49
- For example, check that only allowed types and scopes are used. To do this, add the following to the <nobr>[configuration file](#configuration)</nobr>:
66
+ For example, to restrict commit types and scopes, add the following to the [configuration file](#configuration):
50
67
 
51
68
  ```toml
52
69
  [lint.header]
@@ -62,22 +79,24 @@ exists = ["Issue-ID", "Authored-By"]
62
79
 
63
80
  ### Performance
64
81
 
65
- commitfmt is very fast because its code is written in Rust with memory consumption and performance in mind. It's about 18x faster than commitlint.
82
+ commitfmt is designed for low-overhead local hooks. The [comparison benchmark](docs/benchmark.md) records mean latency and throughput for commitfmt and commitlint when checking the current commit and a 10-commit history range.
66
83
 
67
- It natively supports following platforms:
84
+ ## Installation
68
85
 
69
- | OS | Architecture |
70
- | --- | --- |
71
- | macOS | x86_64, arm64 |
72
- | Windows | x86_64, i686 |
73
- | Linux | x86_64, i686, arm64 |
86
+ Prebuilt binaries are available for the following platforms and installation methods:
74
87
 
75
- ## Installation
88
+ | OS | Installation script | npm or pip |
89
+ | --- | --- | --- |
90
+ | macOS | x64, arm64 | x64, arm64 |
91
+ | Windows | x64, x86, arm64 | x64, arm64 |
92
+ | Linux | x64, x86, arm64 | x64, arm64 |
76
93
 
77
94
  ### Script
78
95
 
79
96
  You can use a simple [script](https://github.com/mishamyrt/commitfmt/blob/refs/heads/main/scripts/install.sh) to install commitfmt.
80
- It will download the latest version of the binary and install it to the system.
97
+ It downloads and installs the latest prebuilt binary.
98
+
99
+ The installer requires Bash, `curl` or `wget`, and the appropriate archive tools: `tar` on macOS and Linux, with `xz` or `unxz` as a fallback, or `unzip` on Windows. On Windows, run it from Git Bash, MSYS2, or Cygwin. The binary is installed in `/usr/local/bin` when that directory is writable; otherwise, it is installed in `~/.local/bin`.
81
100
 
82
101
  ```bash
83
102
  # Install latest version
@@ -110,9 +129,9 @@ pip install commitfmt
110
129
 
111
130
  ## Hook
112
131
 
113
- After installing the package, you need to add a hook to the `prepare-commit-msg` event. You can use any hook manager.
132
+ After installing commitfmt, add a Git `prepare-commit-msg` hook. You can configure it manually or use any hook manager.
114
133
 
115
- > **Important:** if you are using a pnpm, yarn or any other package manager, you need to run `pnpm commitfmt`, `yarn commitfmt`, etc. instead of `commitfmt`.
134
+ > **Command used in hooks:** the examples below assume an installation made with the script or pip and use the direct `commitfmt` command. For a local Node.js development dependency, replace it with `pnpm exec commitfmt`, `npm exec -- commitfmt`, or `yarn exec commitfmt`.
116
135
 
117
136
  ### Script
118
137
 
@@ -130,13 +149,17 @@ Add to your `lefthook.yml` file:
130
149
 
131
150
  ```yaml
132
151
  prepare-commit-msg:
133
- - name: format commit message
134
- run: commitfmt
152
+ jobs:
153
+ - name: format commit message
154
+ run: commitfmt
155
+ args: ""
135
156
  ```
136
157
 
158
+ `args` is intentionally empty: Lefthook otherwise forwards Git hook arguments, while commitfmt locates Git's `COMMIT_EDITMSG` itself.
159
+
137
160
  ### [Husky](https://github.com/typicode/husky)
138
161
 
139
- Add to your `.husky` folder `prepare-commit-msg` file with the following content:
162
+ Create `.husky/prepare-commit-msg` with the following content:
140
163
 
141
164
  ```bash
142
165
  #!/bin/sh
@@ -145,29 +168,29 @@ commitfmt
145
168
 
146
169
  ## Configuration
147
170
 
148
- In commitfmt, you cannot customize basic formatting rules such as extra spaces removal.
149
-
150
- It is an opinionated formatter and the author has established best practices that should not harm anyone.
171
+ Core formatting behavior, such as removing extra whitespace, is intentionally not configurable. This keeps formatted commit messages consistent and predictable across a project. Project-specific constraints can be configured using the lint rules below.
151
172
 
152
173
  ### Linting
153
174
 
154
- Most of the linting rules are disabled by default. Default config contains 2 rules as they can be safely auto-fixed:
175
+ Most linting rules are disabled by default. Two rules are enabled because the formatter can fix them safely:
155
176
 
156
177
  ```toml
157
178
  [lint.header]
158
- description-full-stop = true
179
+ description-full-stop = true # Remove trailing periods from header descriptions
159
180
 
160
181
  [lint.footer]
161
- breaking-exclamation = true
182
+ breaking-exclamation = true # Add ! for BREAKING CHANGE or BREAKING-CHANGE
162
183
  ```
163
184
 
164
- To enable more rules, create a `commitfmt.toml` or (`.commitfmt.toml`) file in the root of your project. Available lint rules can be found in the [rules.md](https://github.com/mishamyrt/commitfmt/blob/main/crates/commitfmt-linter/docs/rules.md) file.
185
+ Breaking-change footer keys are case-sensitive. commitfmt recognizes `BREAKING CHANGE` and `BREAKING-CHANGE`; `BREAKING CHANGES` is not supported.
165
186
 
166
- If there is a problem with an enabled rule and it cannot be automatically fixed, the commit process will be aborted.
187
+ To enable more rules, create a `.commitfmt.toml` or `commitfmt.toml` file in the root of your Git repository. commitfmt loads the configuration from the repository root even when it is run from a subdirectory. If both files exist, `.commitfmt.toml` takes precedence. Available lint rules can be found in the [rules.md](https://github.com/mishamyrt/commitfmt/blob/main/crates/commitfmt-linter/docs/rules.md) file.
188
+
189
+ In the default formatting mode, safe fixes are applied automatically. The command fails on violations that cannot be fixed; when used as a hook, this aborts the commit. In `--lint` mode, the message is never modified and any violation causes a non-zero exit code.
167
190
 
168
191
  #### Unsafe fixes
169
192
 
170
- Some rules may be fixed, but in certain contexts this fix may not be what is desired. For example, adding a full stop to the end of body will be useful in most cases, if there is a log at the end of the message, the period may distort it. You can see which rules have unsafe patches in the same `rules.md` file mentioned above.
193
+ Some rules have fixes that may be undesirable in certain contexts. For example, adding a period to the end of a body may distort an embedded log. Rules with unsafe fixes are marked in the same `rules.md` file.
171
194
 
172
195
  To enable unsafe fixes, add the following to your config file:
173
196
 
@@ -178,13 +201,20 @@ unsafe-fixes = true
178
201
 
179
202
  ### Extending
180
203
 
181
- You can extend the configuration of the parent project by adding the `extends` key to your config file:
204
+ To reuse another configuration, add `extends` with a path relative to the current configuration file:
182
205
 
183
206
  ```toml
184
207
  extends = "node_modules/commitfmt-config-standard/commitfmt.toml"
185
208
  ```
186
209
 
187
- Extension is only possible for the current configuration. If the current configuration extends another configuration, which in turn extends a third configuration, commitfmt will throw an error when trying to load such a configuration.
210
+ Only one inheritance level is supported. If the referenced configuration also contains `extends`, commitfmt returns an error.
211
+
212
+ Configuration inheritance uses a shallow merge:
213
+
214
+ - top-level parser options from the current file override inherited values
215
+ - redefining `[lint.header]`, `[lint.body]`, or `[lint.footer]` replaces the entire inherited group; groups omitted from the current file remain inherited
216
+ - `[lint]` options from the current file replace inherited `[lint]` options, so repeat `unsafe-fixes = true` when the current file defines lint settings and still needs unsafe fixes
217
+ - additional footers from the current file are appended after inherited footers
188
218
 
189
219
  ### Parser Configuration
190
220
 
@@ -208,7 +238,7 @@ By default, commitfmt uses git's `core.commentChar` or `core.commentString` conf
208
238
  comment-symbol = "//"
209
239
  ```
210
240
 
211
- Lines starting with the comment symbol will be ignored during parsing.
241
+ Comment lines immediately after the header and at the end of the commit message are ignored during parsing. Comment lines elsewhere are preserved as message content, and the header is always parsed as content.
212
242
 
213
243
  ### Additional footers
214
244
 
@@ -231,10 +261,12 @@ You can use shell commands to dynamically generate footer values:
231
261
  ```toml
232
262
  [[additional-footers]]
233
263
  key = "Authored-By"
234
- value = "{{ echo $USER }}"
264
+ value = "{{ printf %s \"$USER\" }}"
235
265
  ```
236
266
 
237
- Inside the template expression you can use any shell command available in the `PATH`.
267
+ Commands are executed with `sh -c`. The `sh` executable and any external commands must be available through `PATH`; shell built-ins such as `printf` require no separate executable. A non-zero exit code aborts formatting, and trailing line endings are removed from standard output before it is used as the footer value.
268
+
269
+ > **Security:** shell templates execute arbitrary commands. Use configuration files only from trusted sources.
238
270
 
239
271
  #### Branch value pattern
240
272
 
@@ -243,13 +275,13 @@ You can also add the ticket number from the task tracker to the footer if it is
243
275
  ```toml
244
276
  [[additional-footers]]
245
277
  key = "Ticket-ID"
246
- branch-pattern = "(?:.*)/(?<TICKET_ID>[A-Z0-9-]+)/?(?:.*)"
278
+ branch-pattern = "^(?:[^/]+/)*(?<TICKET_ID>[A-Z][A-Z0-9]*-[0-9]+)(?:/.*)?$"
247
279
  value = "${{ TICKET_ID }}"
248
280
  ```
249
281
 
250
282
  For example, if your branch name is `feature/CC-123/add-new-feature` or `feature/CC-123`, the `Ticket-ID` footer will be added to the commit message with the value `CC-123`.
251
283
 
252
- If the ticket number is not found in the branch name, footer will be skipped.
284
+ The named capture is available to the value template as `TICKET_ID`. If the current branch is unavailable or does not match the pattern, the footer is skipped.
253
285
 
254
286
  Branch patterns use the [regex-lite syntax](https://docs.rs/regex-lite/latest/regex_lite/#syntax).
255
287
  Unicode character classes and Unicode-aware case folding are not supported.
@@ -258,34 +290,34 @@ Unicode character classes and Unicode-aware case folding are not supported.
258
290
 
259
291
  Examples of patterns for branch names in git flow format:
260
292
 
261
- - Jira/YouTrack: `(?:.*)/(?<TICKET_ID>[A-Z0-9-]+)/?(?:.*)`
293
+ - Jira/YouTrack: `^(?:[^/]+/)*(?<TICKET_ID>[A-Z][A-Z0-9]*-[0-9]+)(?:/.*)?$`
262
294
  - `feature/CFMT-123`
263
295
  - `feature/CFMT-123/add-new-feature`
264
- - GitHub: `(?:.*)/(?<ISSUE_ID>[0-9-]+)/?(?:.*)`
296
+ - GitHub: `^(?:[^/]+/)*(?<ISSUE_ID>[0-9]+)(?:/.*)?$`
265
297
  - `feature/123`
266
298
  - `feature/123/add-new-feature`
267
299
 
268
300
  #### On conflict
269
301
 
270
- If the footer already exists in the commit message, you can specify what to do with it. By default, the footer will be skipped.
302
+ If the message already contains a footer with the same key, `on-conflict` determines whether commitfmt adds the configured footer. The existing footer is never removed.
271
303
 
272
304
  ```toml
273
305
  [[additional-footers]]
274
306
  key = "Ticket-ID"
275
- branch-pattern = "(?:.*)/(?<TICKET_ID>[A-Z0-9-]+)/?(?:.*)"
307
+ branch-pattern = "^(?:[^/]+/)*(?<TICKET_ID>[A-Z][A-Z0-9]*-[0-9]+)(?:/.*)?$"
276
308
  value = "${{ TICKET_ID }}"
277
- on-conflict = "error" # optional. default: skip. available: skip, append, error
309
+ on-conflict = "error" # optional; default: skip
278
310
  ```
279
311
 
280
312
  Available options:
281
313
 
282
- - `skip` - skip the footer if it already exists
283
- - `append` - append the footer to the end of the footer list
284
- - `error` - abort the commit
314
+ - `skip` keep the existing footer and do not add the configured one (default)
315
+ - `append` keep the existing footer and add the configured one at the end
316
+ - `error` return an error without writing the formatted message; when running as a hook, this aborts the commit
285
317
 
286
318
  #### Footer formatting
287
319
 
288
- You can customize how footers are formatted using `separator` and `alignment` options:
320
+ You can customize how footers are formatted using `separator` and `alignment`. The separator must be a single character.
289
321
 
290
322
  ```toml
291
323
  [[additional-footers]]
@@ -297,8 +329,8 @@ alignment = "right"
297
329
 
298
330
  Available alignment options:
299
331
 
300
- - `left` - align separator to the left (default)
301
- - `right` - align separator to the right
332
+ - `left` no space before the separator and one after it (default): `Ticket-ID# CFMT-123`
333
+ - `right` one space before the separator and none after it: `Ticket-ID #CFMT-123`
302
334
 
303
335
  ### Recipe
304
336
 
@@ -321,28 +353,54 @@ case = "upper-first"
321
353
  breaking-exclamation = true
322
354
  ```
323
355
 
324
- ## Testing
356
+ ## Modes
357
+
358
+ ### Formatting mode
325
359
 
326
- To test the configuration and the work of commitfmt, run the following command:
360
+ Formatting is the default mode. commitfmt normalizes the message structure and applies fixes from enabled rules. Safe fixes are always applied; unsafe fixes are applied only when [`unsafe-fixes`](#unsafe-fixes) is enabled. An unfixable violation returns a non-zero exit status and prevents the formatted message from being written.
361
+
362
+ When a message is supplied through standard input, `commitfmt` formats it and writes the result to standard output:
327
363
 
328
364
  ```bash
329
- echo "chore ( test ) : test commit" | commitfmt
365
+ printf '%s\n' "chore ( test ) : test commit." | commitfmt
366
+ # chore(test): test commit
367
+
330
368
  # or
331
- cat commit_text.txt | commitfmt
369
+ commitfmt < commit_text.txt
370
+ ```
371
+
372
+ The command exits with a non-zero status if configuration loading, parsing, or an unfixable rule fails.
373
+
374
+ When run without redirected standard input during an active Git commit, as in a `prepare-commit-msg` hook, commitfmt reads and updates Git's `COMMIT_EDITMSG` file instead of writing the formatted message to standard output.
375
+
376
+ ### Lint mode
377
+
378
+ Use `--lint` to check a message without modifying it or applying available fixes:
379
+
380
+ ```bash
381
+ printf '%s\n' "chore(test): test commit" | commitfmt --lint
332
382
  ```
333
383
 
334
- ## History testing
384
+ A valid message produces no output and exits with status 0. Any violation produces a report and a non-zero exit status. When used in a hook, lint mode checks `COMMIT_EDITMSG` but never rewrites it.
335
385
 
336
- To test the history of commits, run the following command:
386
+ ### History mode
387
+
388
+ Use `--from` to lint a Git commit range:
337
389
 
338
390
  ```bash
339
391
  commitfmt --from HEAD~20
340
392
  # or
341
- commitfmt --from 1234567890 --to 1234567890
393
+ commitfmt --from v1.1.0 --to HEAD
342
394
  ```
343
395
 
396
+ The lower boundary is excluded. `--to` defaults to `HEAD` and can only be used together with `--from`. History mode never modifies existing commits and always lints messages, so `--lint` is unnecessary and ignored.
397
+
344
398
  ## Ignoring commits
345
399
 
346
- commitfmt ignores commit messages that start with `Merge` or `Revert` to avoid breaking standard git processes.
400
+ commitfmt skips messages whose text starts with the exact, case-sensitive prefix `Merge` or `Revert`. This avoids rewriting Git-generated merge and revert messages.
401
+
402
+ The check is based only on the message text, not commit metadata: `merge`, `revert:`, and other differently cased prefixes are not skipped, while any custom message starting with `Merge` or `Revert` is skipped. This applies both when formatting a single message and when linting history.
403
+
404
+ ## License
347
405
 
348
- This happens both when formatting a single commit and when linting a history.
406
+ [MIT](./LICENSE).
package/commitfmt CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commitfmt-darwin-x64",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Utility for formatting and verifying the commit message.",
5
5
  "preferUnplugged": false,
6
6
  "repository": {