@avi2dg/checks 0.68.1 → 0.69.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.
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.69.0
6
+
7
+ Released 2026-11-06.
8
+
9
+ ### Features
10
+
11
+ - export git, main, test and test-report helpers [#57](https://github.com/avi2d/checks/pull/57)
12
+
13
+ ## 0.68.2
14
+
15
+ Released 2026-11-06.
16
+
17
+ ### Fixes
18
+
19
+ - **commit-identity:** accept Dependabot bot identity on Dependabot titles [#53](https://github.com/avi2d/checks/pull/53)
20
+
5
21
  ## 0.68.1
6
22
 
7
23
  Released 2026-11-06.
@@ -14,7 +14,9 @@ const dependabot = new RegExp(
14
14
  String.raw`^build\(deps(?:-dev)?\): (?:${single}|${bumpTo}|${joint}|${byName}|${requirement}|${inGroup}|${groupWithUpdates})(?: \(#\d+\))?$`,
15
15
  );
16
16
 
17
+ export const isDependabotTitle = (title: string): boolean => dependabot.test(title);
18
+
17
19
  export default {
18
20
  extends: ["@commitlint/config-conventional"],
19
- ignores: [(message: string) => dependabot.test(message)],
21
+ ignores: [isDependabotTitle],
20
22
  };
package/docs/design.md CHANGED
@@ -84,12 +84,13 @@ Nothing would then say which gate a helper serves.
84
84
  A mutation runner's default scope covers `src/`, so the kit's own Stryker run mutates its source with no `mutate` list.
85
85
  The testing directory is named `testing` rather than `tests`, because a `src/tests/` beside the root `tests/` would read as a second suite.
86
86
 
87
- Eight `exports` keys name a path the file does not sit at, because consumers resolve them by that name.
87
+ Twelve `exports` keys name a path the file does not sit at, because consumers resolve them by that name.
88
88
  `@avi2dg/checks/scripts/test-skips.ts`, `@avi2dg/checks/scripts/comment-matchers.ts` and `@avi2dg/checks/scripts/prose-matchers.ts` point at their files under `src/`.
89
89
  `@avi2dg/checks/browser-hooks.ts` points at `src/quality/browser/hooks.ts`, whose types a product's browser hooks import.
90
90
  `@avi2dg/checks/browser-checks.json` points at `src/quality/browser/browser-checks.json`, the starter a product copies.
91
91
  `@avi2dg/checks/screen-sizes.ts` points at `src/quality/browser/screen-sizes.ts`, whose sizes a product imports.
92
92
  `@avi2dg/checks/block-screens.ts` points at `src/testing/block-screens.ts`, whose screenshot suite a product's pixel tests call.
93
+ `@avi2dg/checks/core/git.ts`, `@avi2dg/checks/core/main.ts`, `@avi2dg/checks/testing/test.ts` and `@avi2dg/checks/testing/test-report.ts` point at their files under `src/`, whose git, entry-point, test-report and skip-judging helpers a repository's own test runner script builds on.
93
94
  `@avi2dg/checks/templates/*` points at `dist/templates/`.
94
95
  A path read without the resolver, such as `node_modules/@avi2dg/checks/scripts/test-skips.ts`, does not exist.
95
96
 
@@ -17,6 +17,11 @@ The same author on a commit with any other committer must match the allowed name
17
17
  `github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>` is allowed as author only of a commit whose subject is `chore: release <version>`, with or without the pull request number a squash merge adds.
18
18
  GitHub attributes the release commit [checks-release-pr](checks-release-pr.md) or [checks-release-push](checks-release-push.md) makes to that bot, since each commits through the workflow token.
19
19
  Such a commit may carry a `Co-authored-by` trailer naming that bot, since GitHub adds one to some squash merges of a pull request the bot opened, and every other trailer is refused.
20
+ A Dependabot-titled commit may carry a `Co-authored-by` trailer naming `dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>`, since GitHub adds one when the owner squash-merges a pull request the bot opened, and every other trailer is refused.
21
+ `dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>` is allowed as author only of a commit whose subject is a Dependabot title [the commit message lint](../configs/commit-messages.md) exempts, with or without the pull request number a squash merge adds.
22
+ Dependabot writes that commit itself, and GitHub commits it as `GitHub <noreply@github.com>`, which the gate already allows as committer.
23
+ This identity matches by name and email, even on a commit GitHub made, so the Dependabot address under another name is refused.
24
+ Its `Signed-off-by` trailer is not a `Co-authored-by` trailer, so the gate does not read it.
20
25
 
21
26
  ## What it reads
22
27
 
@@ -52,6 +57,9 @@ commit-identity: 1 of 1 commit(s) in HEAD carry a foreign identity:
52
57
  79fa94f9f027 feat: foreign
53
58
  author someone <someone@example.com>
54
59
  allowed: Repo Owner <owner@example.com>
60
+ allowed as committer only: GitHub <noreply@github.com>, which also lets an allowed email author under any name
61
+ allowed as release author only: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
62
+ allowed as Dependabot author only, on a Dependabot title: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
55
63
  ```
56
64
 
57
65
  ## When it runs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avi2dg/checks",
3
- "version": "0.68.1",
3
+ "version": "0.69.0",
4
4
  "description": "Deterministic checks shared across a set of TypeScript repositories",
5
5
  "author": {
6
6
  "name": "avi2d",
@@ -152,6 +152,10 @@
152
152
  "./browser-checks.json": "./src/quality/browser/browser-checks.json",
153
153
  "./screen-sizes.ts": "./src/quality/browser/screen-sizes.ts",
154
154
  "./block-screens.ts": "./src/testing/block-screens.ts",
155
+ "./core/git.ts": "./src/core/git.ts",
156
+ "./core/main.ts": "./src/core/main.ts",
157
+ "./testing/test-report.ts": "./src/testing/test-report.ts",
158
+ "./testing/test.ts": "./src/testing/test.ts",
155
159
  "./oxlint": {
156
160
  "types": "./dist/presets/oxlint.d.ts",
157
161
  "default": "./dist/presets/oxlint.js"
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env bun
2
2
  import { Console, Effect, FileSystem, Path, Schema } from "effect";
3
+ import { isDependabotTitle } from "../../commitlint.config.ts";
3
4
  import { releasedVersionOf } from "./release.ts";
4
5
  import { git, refArgs } from "../core/git.ts";
5
6
  import { runMain } from "../core/main.ts";
@@ -23,11 +24,13 @@ const SQUASH_COMMITTER: Identity = { name: "GitHub", email: "noreply@github.com"
23
24
  // GitHub may also name that bot as co-author when it squashes the pull request the bot opened.
24
25
  const RELEASE_AUTHOR: Identity = { name: "github-actions[bot]", email: "41898282+github-actions[bot]@users.noreply.github.com" };
25
26
 
27
+ const DEPENDABOT_AUTHOR: Identity = { name: "dependabot[bot]", email: "49699333+dependabot[bot]@users.noreply.github.com" };
28
+
26
29
  const CO_AUTHOR = /^co-authored-by:\s*(.*?)\s*<([^<>]*)>\s*$/i;
27
30
 
28
- function namesReleaseAuthor(trailer: string): boolean {
31
+ function namesCoAuthor(identity: Identity, trailer: string): boolean {
29
32
  const [, name, email = ""] = CO_AUTHOR.exec(trailer) ?? [];
30
- return name !== undefined && allows([RELEASE_AUTHOR], { name, email });
33
+ return name !== undefined && allows([identity], { name, email });
31
34
  }
32
35
 
33
36
  // git's own trailer parser, so only the trailer block counts and prose never does.
@@ -130,14 +133,19 @@ function inspect(commit: Commit, allowed: readonly Identity[]): Offence | undefi
130
133
  const release = releasedVersionOf(commit.subject) !== undefined;
131
134
  const authors = release ? [...allowed, RELEASE_AUTHOR] : allowed;
132
135
  const madeByGitHub = allows([SQUASH_COMMITTER], commit.committer);
133
- if (!(madeByGitHub ? allowsEmail(authors, commit.author) : allows(authors, commit.author))) {
136
+ const authored = madeByGitHub ? allowsEmail(authors, commit.author) : allows(authors, commit.author);
137
+ // Outside the author list, which a GitHub-made commit matches by email alone and so would take any name on the bot's address.
138
+ const dependabotTitle = isDependabotTitle(commit.subject);
139
+ const dependabot = dependabotTitle && allows([DEPENDABOT_AUTHOR], commit.author);
140
+ if (!authored && !dependabot) {
134
141
  reasons.push(`author ${render(commit.author)}`);
135
142
  }
136
143
  if (!allows([...allowed, SQUASH_COMMITTER], commit.committer)) {
137
144
  reasons.push(`committer ${render(commit.committer)}`);
138
145
  }
139
146
  for (const trailer of commit.coAuthoredBy) {
140
- if (release && namesReleaseAuthor(trailer)) continue;
147
+ if (release && namesCoAuthor(RELEASE_AUTHOR, trailer)) continue;
148
+ if (dependabotTitle && namesCoAuthor(DEPENDABOT_AUTHOR, trailer)) continue;
141
149
  reasons.push(`trailer ${trailer}`);
142
150
  }
143
151
  return reasons.length === 0 ? undefined : { commit, reasons };
@@ -167,6 +175,7 @@ const check = Effect.gen(function* () {
167
175
  lines.push(` allowed: ${allowed.map(render).join(", ")}`);
168
176
  lines.push(` allowed as committer only: ${render(SQUASH_COMMITTER)}, which also lets an allowed email author under any name`);
169
177
  lines.push(` allowed as release author only: ${render(RELEASE_AUTHOR)}`);
178
+ lines.push(` allowed as Dependabot author only, on a Dependabot title: ${render(DEPENDABOT_AUTHOR)}`);
170
179
  yield* Console.error(lines.join("\n"));
171
180
  return false;
172
181
  }