@avi2dg/checks 0.67.0 → 0.68.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/CHANGELOG.md +16 -0
- package/commitlint.config.ts +17 -0
- package/docs/configs/commit-messages.md +16 -1
- package/docs/design.md +1 -1
- package/docs/gates/checks-ci-wiring.md +3 -2
- package/package.json +1 -1
- package/src/delivery/bun-pin.ts +9 -10
- package/src/delivery/runner-pick.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
Every release of `@avi2dg/checks`, newest first, written by the release from its conventional commits.
|
|
4
4
|
|
|
5
|
+
## 0.68.1
|
|
6
|
+
|
|
7
|
+
Released 2026-11-06.
|
|
8
|
+
|
|
9
|
+
### Fixes
|
|
10
|
+
|
|
11
|
+
- **commitlint:** accept Dependabot titles that open with Bump or Update [#50](https://github.com/avi2d/checks/pull/50)
|
|
12
|
+
|
|
13
|
+
## 0.68.0
|
|
14
|
+
|
|
15
|
+
Released 2026-11-06.
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- **ci-wiring:** accept short shared refs for runner pick and setup [#49](https://github.com/avi2d/checks/pull/49)
|
|
20
|
+
|
|
5
21
|
## 0.67.0
|
|
6
22
|
|
|
7
23
|
Released 2026-11-06.
|
package/commitlint.config.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
// subject-case cannot be relaxed for one author, so every rule skips the title shapes Dependabot writes.
|
|
2
|
+
const token = String.raw`\S*[^\s.]`;
|
|
3
|
+
const directory = String.raw`in \/\S*[^\s.]`;
|
|
4
|
+
const group = String.raw`[\w.-]+`;
|
|
5
|
+
const single = String.raw`[Bb]ump ${token} from ${token} to ${token}(?: ${directory})?`;
|
|
6
|
+
const bumpTo = String.raw`[Bb]ump ${token} to ${token}`;
|
|
7
|
+
const joint = String.raw`[Bb]ump ${token}(?:, ${token})* and ${token}`;
|
|
8
|
+
const byName = String.raw`[Bb]ump ${token}(?: ${directory}| across (?:[2-9]|[1-9]\d+) directories)`;
|
|
9
|
+
const requirementVersion = String.raw`(?:[~^<>=!]+ )?${token}(?:, (?:[~^<>=!]+ )?${token})*`;
|
|
10
|
+
const requirement = String.raw`[Uu]pdate ${token} requirement (?:from ${requirementVersion} )?to ${requirementVersion}`;
|
|
11
|
+
const inGroup = String.raw`[Bb]ump ${token} from ${token} to ${token} in the ${group} group(?: across \d+ director(?:y|ies))?`;
|
|
12
|
+
const groupWithUpdates = String.raw`[Bb]ump the ${group} group(?: ${directory}| across \d+ director(?:y|ies))? with \d+ updates?`;
|
|
13
|
+
const dependabot = new RegExp(
|
|
14
|
+
String.raw`^build\(deps(?:-dev)?\): (?:${single}|${bumpTo}|${joint}|${byName}|${requirement}|${inGroup}|${groupWithUpdates})(?: \(#\d+\))?$`,
|
|
15
|
+
);
|
|
16
|
+
|
|
1
17
|
export default {
|
|
2
18
|
extends: ["@commitlint/config-conventional"],
|
|
19
|
+
ignores: [(message: string) => dependabot.test(message)],
|
|
3
20
|
};
|
|
@@ -11,6 +11,21 @@ The shared commitlint config holds each pull request title to the conventional c
|
|
|
11
11
|
Commits follow `@commitlint/config-conventional`, shared from `node_modules/@avi2dg/checks/commitlint.config.ts`.
|
|
12
12
|
It arrives with the kit, since `@commitlint/cli` and `@commitlint/config-conventional` are dependencies, not peers.
|
|
13
13
|
|
|
14
|
+
A Dependabot title can capitalise `Bump` or `Update` after its prefix, which subject-case forbids.
|
|
15
|
+
So the config skips every rule for a one-line title in one of the shapes Dependabot writes, whoever wrote it:
|
|
16
|
+
|
|
17
|
+
- `build(deps)` or `build(deps-dev)`, then `Bump` or `bump`, then `X from A to B` with an optional `in /dir`, or `X and Y`, or `X, Y and Z`, or `X across N directories` with two or more, or `X in /dir`.
|
|
18
|
+
- `build(deps)` or `build(deps-dev)`, then `Bump` or `bump`, then `the G group`, optionally `in /dir` or `across N directory or directories`, then `with N update` or `with N updates`.
|
|
19
|
+
- `build(deps)` or `build(deps-dev)`, then `Bump` or `bump`, then `X from A to B in the G group`, optionally `across N directory or directories`.
|
|
20
|
+
- `build(deps)` or `build(deps-dev)`, then `Bump` or `bump`, then `X to V`, when the previous version is unknown.
|
|
21
|
+
- `build(deps)` or `build(deps-dev)`, then `Update` or `update`, then `X requirement`, then `from A` when the old requirement is known, then `to B`.
|
|
22
|
+
A requirement may carry an operator such as `~> 1.4.0`, and several may be listed with commas, such as `^0.20, ^0.21`.
|
|
23
|
+
|
|
24
|
+
The title may end with the pull request number, such as ` (#123)`.
|
|
25
|
+
A body keeps every rule.
|
|
26
|
+
Every rule applies to any other title, including a hand-written title that uses a Dependabot prefix and verb but none of these shapes.
|
|
27
|
+
`chore` is not in the list because no avi2d repository's Dependabot config writes it.
|
|
28
|
+
|
|
14
29
|
## Workflow
|
|
15
30
|
|
|
16
31
|
The lint runs in CI on pull requests, because `jj` never fires a git hook.
|
|
@@ -25,7 +40,7 @@ The title lint runs before the docs-only filter, so a change to top-level Markdo
|
|
|
25
40
|
It lints the pull request title, or the head subject when no open pull request heads the dispatched branch.
|
|
26
41
|
The title is the enforced subject because a squash merge uses it as the main commit subject, and otherwise per-commit messages are not linted.
|
|
27
42
|
GitHub appends the pull request number to the squashed subject, so the bin lints the title with ` (#0000)` attached.
|
|
28
|
-
The header length limit applies to the landed subject, not the bare title.
|
|
43
|
+
The header length limit applies to the landed subject, not the bare title, for any title the config does not skip.
|
|
29
44
|
The bin moves the git comment character off `#`, so a title starting with `#` is linted like any other.
|
|
30
45
|
The `ci` job also triggers on `workflow_dispatch`, as [checks-release-pr](../gates/checks-release-pr.md) and [checks-release-push](../gates/checks-release-push.md) say.
|
|
31
46
|
GitHub holds the `pull_request` runs of a release pull request the workflow token opens until a maintainer approves them.
|
package/docs/design.md
CHANGED
|
@@ -190,7 +190,7 @@ Commits merged after the bump wait for the next release.
|
|
|
190
190
|
Releases come from the version bumps across all of `HEAD`'s ancestry, not from tags.
|
|
191
191
|
So a checkout without tags, a fork, and a branch that merged `main` in all write the same file when no release was reverted.
|
|
192
192
|
A section keeps the date it was written, because the squash merge that lands the release commit may fall on another day.
|
|
193
|
-
Entries come from commit subjects,
|
|
193
|
+
Entries come from commit subjects, the squash-merged pull request titles commitlint holds to the conventional format, except the Dependabot shapes [The commit message lint](configs/commit-messages.md) names.
|
|
194
194
|
A commit body holds the branch's own messages, and nothing lints it, so no entry comes from a body.
|
|
195
195
|
The changelog arrives in the release commit, and no workflow pushes to a branch a person works on.
|
|
196
196
|
|
|
@@ -69,7 +69,8 @@ A job on `push` or another trigger no fork reaches may still name self-hosted la
|
|
|
69
69
|
In a private repository each mutation job carries exactly the labels the consumer declares in `package.json` under `checks.mutationRunner`.
|
|
70
70
|
Every other job there carries exactly the hosted-default expression, or exactly one of the label sets the consumer declares under `checks.selfHostedRunners`.
|
|
71
71
|
A job there also carries `runs-on: ${{ needs.<job>.outputs.runs-on }}` when the same workflow needs that job and that job calls the runner pick.
|
|
72
|
-
The pick is the repository file `runner.yml` under `.github/workflows/` or `avi2d/workflows/.github/workflows/runner.yml` at a
|
|
72
|
+
The pick is the repository file `runner.yml` under `.github/workflows/` or `avi2d/workflows/.github/workflows/runner.yml` at a full SHA or at a version tag, `v<major>` or `v<major>.<minor>.<patch>`.
|
|
73
|
+
A branch name or a missing ref is not the pick.
|
|
73
74
|
A public repository still refuses that expression on a job a fork can reach.
|
|
74
75
|
The resolved label cannot be shown to be a hosted runner before the run.
|
|
75
76
|
A repository without those declarations fails each job they would pin until it declares them.
|
|
@@ -94,7 +95,7 @@ The fleet version is the version the kit ships in its own `.bun-version`.
|
|
|
94
95
|
The step fails the check when the version is missing or differs from the fleet bun version.
|
|
95
96
|
A range fails because it differs from the fleet version.
|
|
96
97
|
A version built from an expression fails because it cannot be shown equal before the run.
|
|
97
|
-
A step that uses `avi2d/workflows/actions/setup
|
|
98
|
+
A step that uses `avi2d/workflows/setup` or `avi2d/workflows/actions/setup`, at any ref or none, reads `.bun-version`.
|
|
98
99
|
The step fails the check when `.bun-version` is missing or differs from the fleet bun version.
|
|
99
100
|
This rule skips a repository with no setup-bun step and no shared setup step.
|
|
100
101
|
A kit release that moves the fleet version turns each consumer red until its pin follows.
|
package/package.json
CHANGED
package/src/delivery/bun-pin.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type BunPinFault = {
|
|
|
17
17
|
|
|
18
18
|
const SETUP_BUN = /^oven-sh\/setup-bun(?:@(?<ref>.*))?$/i;
|
|
19
19
|
const V2_REF = /^v2(?:\.\d+){0,2}$/;
|
|
20
|
-
const SHARED_SETUP = /^avi2d\/workflows\/actions\/setup(
|
|
20
|
+
const SHARED_SETUP = /^avi2d\/workflows\/(?:actions\/)?setup(?:@.*)?$/i;
|
|
21
21
|
const SETUP_VERSION_FILE = ".bun-version";
|
|
22
22
|
|
|
23
23
|
function setupBunRef(uses: unknown): string | undefined {
|
|
@@ -25,9 +25,9 @@ function setupBunRef(uses: unknown): string | undefined {
|
|
|
25
25
|
return match === null ? undefined : (match.groups?.["ref"] ?? "");
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function
|
|
29
|
-
const
|
|
30
|
-
return
|
|
28
|
+
function sharedSetupUses(uses: unknown): string | undefined {
|
|
29
|
+
const text = typeof uses === "string" ? uses.trim() : "";
|
|
30
|
+
return SHARED_SETUP.test(text) ? text : undefined;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function isExpression(value: string): boolean {
|
|
@@ -113,9 +113,8 @@ function unknownRefFault(ref: string): string {
|
|
|
113
113
|
return `uses oven-sh/setup-bun at ${ref === "" ? "no ref" : ref}, but the check knows only setup-bun v2's version resolution, so the step must use oven-sh/setup-bun@v2`;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
function sharedSetupFault(policy: BunPinPolicy,
|
|
116
|
+
function sharedSetupFault(policy: BunPinPolicy, uses: string): string | undefined {
|
|
117
117
|
const version = nonEmpty(policy.files.get(SETUP_VERSION_FILE));
|
|
118
|
-
const uses = ref === "" ? "avi2d/workflows/actions/setup" : `avi2d/workflows/actions/setup@${ref}`;
|
|
119
118
|
if (version === undefined) {
|
|
120
119
|
return `uses ${uses}, which reads ${SETUP_VERSION_FILE}, but the repository holds no ${SETUP_VERSION_FILE} file, want ${policy.fleet}`;
|
|
121
120
|
}
|
|
@@ -137,9 +136,9 @@ export function findBunPinFaults(policy: BunPinPolicy, workflows: readonly Workf
|
|
|
137
136
|
const fault = V2_REF.test(ref) ? bunPinFault(policy, step) : unknownRefFault(ref);
|
|
138
137
|
return fault === undefined ? [] : atStep(fault);
|
|
139
138
|
}
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
const fault = sharedSetupFault(policy,
|
|
139
|
+
const sharedUses = sharedSetupUses(step["uses"]);
|
|
140
|
+
if (sharedUses === undefined) return [];
|
|
141
|
+
const fault = sharedSetupFault(policy, sharedUses);
|
|
143
142
|
return fault === undefined ? [] : atStep(fault);
|
|
144
143
|
});
|
|
145
144
|
});
|
|
@@ -165,7 +164,7 @@ function versionFileKeys(job: Readonly<Record<string, unknown>>): readonly strin
|
|
|
165
164
|
|
|
166
165
|
function usesSharedSetup(job: Readonly<Record<string, unknown>>): boolean {
|
|
167
166
|
const steps = Array.isArray(job["steps"]) ? job["steps"] : [];
|
|
168
|
-
return steps.some((step) => isRecord(step) &&
|
|
167
|
+
return steps.some((step) => isRecord(step) && sharedSetupUses(step["uses"]) !== undefined);
|
|
169
168
|
}
|
|
170
169
|
|
|
171
170
|
function wantedBunPinFiles(workflows: readonly Workflow[]): ReadonlySet<string> {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { names, type Workflow } from "./workflow-references.ts";
|
|
2
2
|
|
|
3
3
|
const NEEDS_RUNS_ON = /^\$\{\{\s*needs\.([\w-]+)\.outputs\.runs-on\s*\}\}$/i;
|
|
4
|
-
const SHARED_RUNNER = /^
|
|
4
|
+
const SHARED_RUNNER = /^[Aa][Vv][Ii]2[Dd]\/[Ww][Oo][Rr][Kk][Ff][Ll][Oo][Ww][Ss]\/\.github\/workflows\/runner\.yml@(?:[0-9a-fA-F]{40}|v\d+(?:\.\d+\.\d+)?)$/;
|
|
5
5
|
const LOCAL_RUNNER = ".github/workflows/runner.yml";
|
|
6
6
|
|
|
7
7
|
function callsRunnerPick(uses: unknown, workflows: readonly Workflow[]): boolean {
|