@rheged-studio/commitlint-config 1.0.1
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.
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/package.json +121 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Rob Easthope
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# @acme-skunkworks/commitlint-config
|
|
2
|
+
|
|
3
|
+
Shared [commitlint](https://commitlint.js.org) configuration for Rheged Studio packages.
|
|
4
|
+
|
|
5
|
+
It **single-sources** the estate's allowed [Conventional Commit](https://www.conventionalcommits.org) types into one published package, consumed by both layers of the commit gate so the ruleset can never drift between them:
|
|
6
|
+
|
|
7
|
+
- the reusable CI workflow (`reusable-validate-commits.yml`) that validates a PR's `base..head` commit range, and
|
|
8
|
+
- the local husky `pre-push` hook that runs the same range check before a push ever reaches CI.
|
|
9
|
+
|
|
10
|
+
It extends [`@commitlint/config-conventional`](https://www.npmjs.com/package/@commitlint/config-conventional) and retains all of its defaults — only the list of allowed commit types is pinned to the estate's set.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pnpm add -D @acme-skunkworks/commitlint-config @commitlint/cli
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`@commitlint/config-conventional` is a runtime dependency of this package, so installing this config pulls it in automatically — you do not need to add it yourself.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Point your commitlint config at this package:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// commitlint.config.mjs
|
|
26
|
+
export default {
|
|
27
|
+
extends: ["@acme-skunkworks/commitlint-config"],
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The example uses `.mjs` so the `export default` works regardless of the consuming project's module type. In an ESM project (`"type": "module"`) a plain `commitlint.config.js` works too; in a CommonJS project use `.mjs` (as above) or `module.exports` in a `.js`/`.cjs` file.
|
|
32
|
+
|
|
33
|
+
Then validate a commit-message range — exactly what the CI workflow and the pre-push hook do:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
# lint every commit on the branch that isn't on the base
|
|
37
|
+
pnpm exec commitlint --from "origin/main" --to "HEAD"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Allowed commit types
|
|
41
|
+
|
|
42
|
+
The `type-enum` rule is set explicitly and is aligned to the estate's release-please bump rules:
|
|
43
|
+
|
|
44
|
+
| Type | Release bump | Notes |
|
|
45
|
+
| ---------- | ------------ | -------------------------------------- |
|
|
46
|
+
| `feat` | minor | A new feature |
|
|
47
|
+
| `fix` | patch | A bug fix |
|
|
48
|
+
| `perf` | patch | A performance improvement |
|
|
49
|
+
| `revert` | patch | Reverts a previous commit |
|
|
50
|
+
| `chore` | none | Tooling / housekeeping |
|
|
51
|
+
| `docs` | none | Documentation only |
|
|
52
|
+
| `ci` | none | CI configuration and pipelines |
|
|
53
|
+
| `build` | none | Build system or external dependencies |
|
|
54
|
+
| `refactor` | none | Neither fixes a bug nor adds a feature |
|
|
55
|
+
| `test` | none | Adding or correcting tests |
|
|
56
|
+
| `style` | none | Formatting; no code-behaviour change |
|
|
57
|
+
|
|
58
|
+
A `!` marker or a `BREAKING CHANGE:` footer promotes any type to a **major** bump.
|
|
59
|
+
|
|
60
|
+
Everything else is inherited from `@commitlint/config-conventional` unchanged, including:
|
|
61
|
+
|
|
62
|
+
- a non-empty commit type and subject,
|
|
63
|
+
- the header max-length limit, and
|
|
64
|
+
- `defaultIgnores` — merge (`Merge …`), revert (`Revert …`), `fixup!` and `squash!` messages are skipped automatically, so this config never needs to blanket-ignore them by author identity.
|
|
65
|
+
|
|
66
|
+
## Bot-authored commits
|
|
67
|
+
|
|
68
|
+
**There is no identity denylist.** Bots are validated exactly like everyone else — the config has no `ignores` entry, and none should be added. Every automated commit producer in the estate already emits a Conventional subject, verified against this ruleset:
|
|
69
|
+
|
|
70
|
+
| Producer | Subject |
|
|
71
|
+
| ------------------------------- | ------------------------------------------------- |
|
|
72
|
+
| Dependabot (`github-actions`) | `ci(deps): bump the actions group with 3 updates` |
|
|
73
|
+
| Dependabot (npm) | `chore(deps): …` / `chore(deps-dev): …` |
|
|
74
|
+
| release-please | `chore: release main` |
|
|
75
|
+
| `reusable-changelog-enrich.yml` | `chore(changelog): enrich post-merge metadata` |
|
|
76
|
+
|
|
77
|
+
Dependabot's subjects come from a `commit-message` template in each repo's `.github/dependabot.yml`, which sets `prefix` (plus `prefix-development` for the npm ecosystem) and `include: scope`. Without that template Dependabot falls back to inferring a prefix from recent commit history — which may yield a Conventional subject, but is not guaranteed to, and can leave a bare `Bump …` that would fail the gate. The explicit template is what makes the output deterministic, which is why it is a prerequisite for making the gate a required check rather than an optional nicety ([A-980](https://linear.app/rheged-studio/issue/A-980)).
|
|
78
|
+
|
|
79
|
+
Two inherited rules are worth knowing when reading a bot commit:
|
|
80
|
+
|
|
81
|
+
- **`header-max-length` (100) is the one real ceiling.** This is why Dependabot bumps are grouped — a grouped subject stays short (`bump the actions group with 3 updates`), whereas an ungrouped multi-package subject can run past 100 characters and fail.
|
|
82
|
+
- **`body-max-line-length` (100) ignores unbreakable lines.** Dependabot bodies contain compare URLs well over 100 characters; those pass, because the rule only trips on over-long lines that could have been wrapped. A long prose line still fails.
|
|
83
|
+
|
|
84
|
+
Should a bot ever need an exception, prefer fixing its commit template. A per-identity `ignores` entry is a documented last resort, not a first move.
|
|
85
|
+
|
|
86
|
+
## Versioning: float on latest
|
|
87
|
+
|
|
88
|
+
The gate is designed to track this config's **latest published version** rather than pinning it, mirroring how the estate floats on its shared GitHub workflows (`@v1`). The reusable CI workflow installs the config fresh on each run, so a caret range with no committed lockfile resolves to the latest published version — a ruleset change reaches the gate on its next run, with no per-repo bump PR.
|
|
89
|
+
|
|
90
|
+
Where a consumer instead commits a lockfile (for example the local pre-push hook running in a repo that pins its dev-dependencies), the resolved version stays put until it is updated: the package is Dependabot-versioned like the estate's other shared packages, so those consumers get update PRs. The trade-off is deliberate — because a ruleset change reaches the floating consumers immediately, edits must be made carefully.
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
pnpm install
|
|
96
|
+
pnpm build # tsc → dist/ (the published artifact)
|
|
97
|
+
pnpm test # vitest — behavioural tests over the resolved ruleset
|
|
98
|
+
pnpm tsc # type-check
|
|
99
|
+
pnpm lint # eslint
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The ruleset itself is `src/index.ts`; `src/index.test.ts` exercises the _effective_ config by resolving `extends` through `@commitlint/load` and linting sample messages with `@commitlint/lint`.
|
|
103
|
+
|
|
104
|
+
## Licence
|
|
105
|
+
|
|
106
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { UserConfig } from "@commitlint/types";
|
|
2
|
+
/**
|
|
3
|
+
* `@acme-skunkworks/commitlint-config` — the estate's shared commitlint ruleset.
|
|
4
|
+
*
|
|
5
|
+
* It single-sources the allowed Conventional-Commit types into one published
|
|
6
|
+
* package so that both consumers of the commit gate — the reusable CI workflow
|
|
7
|
+
* (`reusable-validate-commits.yml`) and the local husky `pre-push` range check —
|
|
8
|
+
* float on the *same* list with zero drift (A-823 / A-979).
|
|
9
|
+
*
|
|
10
|
+
* The config extends `@commitlint/config-conventional` and deliberately retains
|
|
11
|
+
* all of its defaults (header max length, non-empty type/subject, and the
|
|
12
|
+
* `defaultIgnores` for `Merge …` / `Revert …` / `fixup!` / `squash!` messages).
|
|
13
|
+
* Only `type-enum` is overridden.
|
|
14
|
+
*
|
|
15
|
+
* `type-enum` is set *explicitly* — even though the list currently mirrors
|
|
16
|
+
* config-conventional's own default — so that an upstream change to
|
|
17
|
+
* config-conventional's default type set can never silently move the estate's
|
|
18
|
+
* gate. The list is aligned to the release-please bump rules: `feat` → minor;
|
|
19
|
+
* `fix`/`perf`/`revert` → patch; the remaining types cut no release.
|
|
20
|
+
*/
|
|
21
|
+
declare const config: UserConfig;
|
|
22
|
+
export default config;
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,QAAA,MAAM,MAAM,EAAE,UAqBb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@acme-skunkworks/commitlint-config` — the estate's shared commitlint ruleset.
|
|
3
|
+
*
|
|
4
|
+
* It single-sources the allowed Conventional-Commit types into one published
|
|
5
|
+
* package so that both consumers of the commit gate — the reusable CI workflow
|
|
6
|
+
* (`reusable-validate-commits.yml`) and the local husky `pre-push` range check —
|
|
7
|
+
* float on the *same* list with zero drift (A-823 / A-979).
|
|
8
|
+
*
|
|
9
|
+
* The config extends `@commitlint/config-conventional` and deliberately retains
|
|
10
|
+
* all of its defaults (header max length, non-empty type/subject, and the
|
|
11
|
+
* `defaultIgnores` for `Merge …` / `Revert …` / `fixup!` / `squash!` messages).
|
|
12
|
+
* Only `type-enum` is overridden.
|
|
13
|
+
*
|
|
14
|
+
* `type-enum` is set *explicitly* — even though the list currently mirrors
|
|
15
|
+
* config-conventional's own default — so that an upstream change to
|
|
16
|
+
* config-conventional's default type set can never silently move the estate's
|
|
17
|
+
* gate. The list is aligned to the release-please bump rules: `feat` → minor;
|
|
18
|
+
* `fix`/`perf`/`revert` → patch; the remaining types cut no release.
|
|
19
|
+
*/
|
|
20
|
+
const config = {
|
|
21
|
+
extends: ["@commitlint/config-conventional"],
|
|
22
|
+
rules: {
|
|
23
|
+
"type-enum": [
|
|
24
|
+
2, // error
|
|
25
|
+
"always",
|
|
26
|
+
[
|
|
27
|
+
"feat",
|
|
28
|
+
"fix",
|
|
29
|
+
"perf",
|
|
30
|
+
"revert",
|
|
31
|
+
"chore",
|
|
32
|
+
"docs",
|
|
33
|
+
"ci",
|
|
34
|
+
"build",
|
|
35
|
+
"refactor",
|
|
36
|
+
"test",
|
|
37
|
+
"style",
|
|
38
|
+
],
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
export default config;
|
package/package.json
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rheged-studio/commitlint-config",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Shared commitlint configuration for ACME Skunkworks packages.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"commitlint",
|
|
7
|
+
"conventional-commits",
|
|
8
|
+
"config",
|
|
9
|
+
"rheged-studio"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://github.com/rheged-studio/commitlint-config#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/rheged-studio/commitlint-config/issues"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/rheged-studio/commitlint-config.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": {
|
|
21
|
+
"name": "Rob Easthope",
|
|
22
|
+
"url": "https://github.com/RobEasthope"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js",
|
|
29
|
+
"default": "./dist/index.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"act:ci": "act pull_request -W .github/workflows/ci.yml --eventpath .github/act-events/pull_request.json",
|
|
40
|
+
"act:list": "act --list",
|
|
41
|
+
"act:release:dry": "act push -W .github/workflows/pkg-release.yml",
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"ci:list": "gh run list --limit 10",
|
|
44
|
+
"ci:view": "gh run view",
|
|
45
|
+
"ci:watch": "gh run watch $(gh run list -L 1 --json databaseId -q '.[0].databaseId // empty')",
|
|
46
|
+
"clean": "rimraf node_modules dist",
|
|
47
|
+
"format": "prettier --write .",
|
|
48
|
+
"lint": "eslint 'src/**/*.ts' --cache --cache-location ./.eslintcache",
|
|
49
|
+
"lint:fix": "eslint 'src/**/*.ts' --fix --cache --cache-location ./.eslintcache",
|
|
50
|
+
"lint:md": "markdownlint-cli2 '**/*.{md,mdx}' '!**/node_modules/**' '!**/dist/**' '!**/.turbo/**' '!**/.astro/**' '!**/.claude/skills/**' '!**/.agents/skills/**' '!AGENTS.md'",
|
|
51
|
+
"lint:md:fix": "markdownlint-cli2 --fix '**/*.{md,mdx}' '!**/node_modules/**' '!**/dist/**' '!**/.turbo/**' '!**/.astro/**' '!**/.claude/skills/**' '!**/.agents/skills/**' '!AGENTS.md'",
|
|
52
|
+
"lint:sh": "bash -c 'if command -v shellcheck >/dev/null 2>&1; then shellcheck infrastructure/scripts/*.sh .husky/pre-commit .husky/pre-push .husky/commit-msg; elif [ \"$(uname -s)\" = \"Darwin\" ]; then echo \"⚠️ shellcheck not installed — skipping. Install: brew install shellcheck\"; else echo \"⚠️ shellcheck not installed — skipping. Install: apt-get install shellcheck\"; fi'",
|
|
53
|
+
"lint:workflows": "actionlint",
|
|
54
|
+
"lint:yaml": "yamllint .",
|
|
55
|
+
"prepare": "husky",
|
|
56
|
+
"prepublishOnly": "pnpm run build",
|
|
57
|
+
"release:manual": "pnpm run build && npm publish --access public --provenance=false",
|
|
58
|
+
"release:manual:dry": "pnpm run build && npm publish --access public --provenance=false --dry-run",
|
|
59
|
+
"sort-pkg-json": "sort-package-json",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:sh": "bash -c 'if command -v bats >/dev/null 2>&1; then bats infrastructure/tests/*.bats; elif [ \"$(uname -s)\" = \"Darwin\" ]; then echo \"⚠️ bats not installed — skipping. Install: brew install bats-core\"; else echo \"⚠️ bats not installed — skipping. Install: apt-get install bats\"; fi'",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"tsc": "tsc --noEmit && tsc -p tsconfig.tools.json",
|
|
64
|
+
"validate:changelog": "pnpm exec changelog-core validate"
|
|
65
|
+
},
|
|
66
|
+
"lint-staged": {
|
|
67
|
+
"**/*": [
|
|
68
|
+
"prettier --write --ignore-unknown"
|
|
69
|
+
],
|
|
70
|
+
"**/*.{ts,tsx,js,mjs,cjs}": [
|
|
71
|
+
"bash -c 'pnpm exec eslint --fix --cache --cache-location ./.eslintcache \"$@\" || true' --"
|
|
72
|
+
],
|
|
73
|
+
"**/package.json": [
|
|
74
|
+
"bash -c 'sort-package-json \"$@\" || true' --",
|
|
75
|
+
"bash -c 'pnpm exec eslint --fix --cache --cache-location ./.eslintcache \"$@\" || true' --"
|
|
76
|
+
],
|
|
77
|
+
"**/*.{md,mdx}": [
|
|
78
|
+
"bash -c 'markdownlint-cli2 --fix --config ./.markdownlint-cli2.jsonc \"$@\" || true' --"
|
|
79
|
+
],
|
|
80
|
+
"**/*.{yml,yaml}": [
|
|
81
|
+
"bash -c 'if command -v yamllint >/dev/null 2>&1; then yamllint \"$@\"; elif [ \"$(uname -s)\" = \"Darwin\" ]; then echo \"⚠️ yamllint not installed — skipping. Install with: brew install yamllint\"; else echo \"⚠️ yamllint not installed — skipping. Install with: pip install --user yamllint==1.37.1\"; fi' --"
|
|
82
|
+
],
|
|
83
|
+
".github/workflows/*.{yml,yaml}": [
|
|
84
|
+
"bash -c 'if command -v actionlint >/dev/null 2>&1; then actionlint \"$@\"; elif [ \"$(uname -s)\" = \"Darwin\" ]; then echo \"⚠️ actionlint not installed — skipping. Install with: brew install actionlint\"; else echo \"⚠️ actionlint not installed — skipping. Install via: bash <(curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/v1.7.5/scripts/download-actionlint.bash)\"; fi' --"
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
"dependencies": {
|
|
88
|
+
"@commitlint/config-conventional": "^21.2.0",
|
|
89
|
+
"@commitlint/types": "^21.2.0"
|
|
90
|
+
},
|
|
91
|
+
"devDependencies": {
|
|
92
|
+
"@acme-skunkworks/changelog-core": "^1.1.1",
|
|
93
|
+
"@acme-skunkworks/eslint-config": "^1.1.3",
|
|
94
|
+
"@acme-skunkworks/markdownlint-config": "^3.0.0",
|
|
95
|
+
"@commitlint/cli": "^21.2.1",
|
|
96
|
+
"@commitlint/lint": "^21.2.0",
|
|
97
|
+
"@commitlint/load": "^21.2.0",
|
|
98
|
+
"@types/node": "^25.6.0",
|
|
99
|
+
"bats": "1.13.0",
|
|
100
|
+
"eslint": "^9.0.0",
|
|
101
|
+
"husky": "^9.1.7",
|
|
102
|
+
"jiti": "^2.7.0",
|
|
103
|
+
"lint-staged": "^16.3.2",
|
|
104
|
+
"markdownlint-cli2": "^0.18.1",
|
|
105
|
+
"prettier": "^3.0.0",
|
|
106
|
+
"prettier-plugin-tailwindcss": "^0.8.0",
|
|
107
|
+
"rimraf": "^6.0.1",
|
|
108
|
+
"sort-package-json": "^3.6.1",
|
|
109
|
+
"tsx": "^4.21.1",
|
|
110
|
+
"typescript": "^6.0.3",
|
|
111
|
+
"vitest": "^4.1.6"
|
|
112
|
+
},
|
|
113
|
+
"packageManager": "pnpm@10.33.0",
|
|
114
|
+
"engines": {
|
|
115
|
+
"node": ">=22"
|
|
116
|
+
},
|
|
117
|
+
"publishConfig": {
|
|
118
|
+
"access": "public",
|
|
119
|
+
"provenance": true
|
|
120
|
+
}
|
|
121
|
+
}
|