Skip to content

Commit 38fa046

Browse files
committed
ci(danger): map root files into explicit scopes
1 parent 216f4ea commit 38fa046

File tree

5 files changed

+84
-14
lines changed

5 files changed

+84
-14
lines changed

util/danger/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ This directory contains the Danger.js rules and fixtures used in CI to add scope
1515
npm --prefix util/danger ci # install dev deps (without touching the repo root)
1616
npm --prefix util/danger test # run Vitest unit tests for rule logic
1717
npm --prefix util/danger run danger:local # print the fixture report from util/danger/fixtures/sample-pr.json
18+
npm --prefix util/danger run danger:scope-map # emit JSON mapping every tracked file to its Danger scope
1819
npm --prefix util/danger run danger:ci # run Danger in CI mode (requires GitHub PR context)
1920
```
2021

@@ -31,7 +32,7 @@ npm --prefix util/danger run danger:ci # run Danger in CI mode (requires Git
3132

3233
- Scopes reflect the MrDocs tree: `source`, `tests`, `golden-tests`, `docs`, `ci`, `build`, `tooling`, `third-party`, `other`.
3334
- Conventional commit types allowed: `feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert`.
34-
- Non-test commit size warning triggers around 800 lines of churn (tests and golden fixtures ignored).
35+
- Non-test commit size notice triggers at 2000 lines of churn (tests and golden fixtures ignored) and is informational.
3536

3637
## Updating rules
3738

util/danger/list-scopes.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//
2+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
// Copyright (c) 2025 Alan de Freitas ([email protected])
7+
//
8+
// Official repository: https://github.com/cppalliance/mrdocs
9+
//
10+
/**
11+
* Utility script to map every tracked file to the scope Danger uses.
12+
* Useful for spotting files that fall into the "other" bucket.
13+
*
14+
* Usage:
15+
* npm --prefix util/danger run danger:scope-map > scope-map.json
16+
*/
17+
18+
import { execSync } from "node:child_process";
19+
import path from "node:path";
20+
import { classifyScope, scopeDisplayOrder, type ScopeKey } from "./logic";
21+
22+
function initBuckets(): Record<ScopeKey, string[]> {
23+
const buckets = {} as Record<ScopeKey, string[]>;
24+
for (const scope of scopeDisplayOrder) {
25+
buckets[scope] = [];
26+
}
27+
return buckets;
28+
}
29+
30+
function main(): void {
31+
const repoRoot = path.resolve(__dirname, "../..");
32+
const output: Record<ScopeKey, string[]> = initBuckets();
33+
34+
const files = execSync("git ls-files", { cwd: repoRoot })
35+
.toString()
36+
.split("\n")
37+
.map((line) => line.trim())
38+
.filter(Boolean);
39+
40+
for (const file of files) {
41+
const scope = classifyScope(file);
42+
// Keep ordering stable to make diffs easy to read.
43+
output[scope].push(file);
44+
}
45+
46+
for (const scope of scopeDisplayOrder) {
47+
output[scope].sort();
48+
}
49+
50+
const counts = Object.fromEntries(scopeDisplayOrder.map((scope) => [scope, output[scope].length]));
51+
52+
const result = {
53+
counts,
54+
files: output,
55+
};
56+
57+
// Pretty-print so it can be inspected or diffed easily.
58+
console.log(JSON.stringify(result, null, 2));
59+
}
60+
61+
main();

util/danger/logic.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,19 @@ describe("summarizeScopes", () => {
4141
{ filename: "src/test/file.cpp", additions: 5, deletions: 1 },
4242
{ filename: "test-files/golden-tests/out.xml", additions: 100, deletions: 0 },
4343
{ filename: "docs/index.adoc", additions: 4, deletions: 0 },
44+
{ filename: "SourceFileNames.cpp", additions: 1, deletions: 0 },
45+
{ filename: ".clang-format", additions: 0, deletions: 0 },
46+
{ filename: ".gitignore", additions: 0, deletions: 0 },
47+
{ filename: "LICENSE.txt", additions: 0, deletions: 0 },
4448
]);
4549

46-
expect(report.totals.source.files).toBe(1);
50+
expect(report.totals.source.files).toBe(2);
4751
expect(report.totals.tests.files).toBe(1);
4852
expect(report.totals["golden-tests"].files).toBe(1);
4953
expect(report.totals.docs.files).toBe(1);
50-
expect(report.overall.files).toBe(4);
54+
expect(report.totals.tooling.files).toBe(1);
55+
expect(report.totals.ci.files).toBe(2);
56+
expect(report.overall.files).toBe(8);
5157
});
5258
});
5359

util/danger/logic.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
/**
1111
* Semantic areas of the repository used to group diff churn in reports and rules.
1212
*/
13-
type ScopeKey =
13+
export type ScopeKey =
1414
| "golden-tests"
1515
| "tests"
1616
| "source"
@@ -185,10 +185,10 @@ const scopeRules: ScopeRule[] = [
185185
},
186186
{
187187
scope: "source",
188-
patterns: [/^src\//i, /^include\//i, /^examples\//i, /^share\//i],
188+
patterns: [/^src\//i, /^include\//i, /^examples\//i, /^share\//i, /^SourceFileNames\.cpp$/i],
189189
},
190190
{ scope: "docs", patterns: [/^docs\//i, /^README\.adoc$/i, /^Doxyfile/i] },
191-
{ scope: "ci", patterns: [/^\.github\//, /^\.roadmap\//] },
191+
{ scope: "ci", patterns: [/^\.github\//, /^\.roadmap\//, /^\.gitignore$/i, /^\.gitattributes$/i, /^LICENSE\.txt$/i] },
192192
{
193193
scope: "build",
194194
patterns: [
@@ -203,6 +203,7 @@ const scopeRules: ScopeRule[] = [
203203
],
204204
},
205205
{ scope: "tooling", patterns: [/^tools\//i, /^util\/(?!danger\/)/i] },
206+
{ scope: "tooling", patterns: [/^\.clang-format$/i] },
206207
{ scope: "ci", patterns: [/^util\/danger\//i, /^\.github\//, /^\.roadmap\//] },
207208
{ scope: "third-party", patterns: [/^third-party\//i] },
208209
];
@@ -221,7 +222,7 @@ function normalizePath(path: string): string {
221222
* @param path raw file path from GitHub.
222223
* @returns matched ScopeKey or "other" if no rules match.
223224
*/
224-
function getScope(path: string): ScopeKey {
225+
export function classifyScope(path: string): ScopeKey {
225226
const normalized = normalizePath(path);
226227
for (const rule of scopeRules) {
227228
if (rule.patterns.some((pattern) => pattern.test(normalized))) {
@@ -311,7 +312,7 @@ export function summarizeScopes(files: FileChange[]): ScopeReport {
311312
const fileSummaries: FileSummary[] = [];
312313

313314
for (const file of files) {
314-
const scope = getScope(file.filename);
315+
const scope = classifyScope(file.filename);
315316
totals[scope].files += 1;
316317
totals[scope].additions += file.additions || 0;
317318
totals[scope].deletions += file.deletions || 0;
@@ -453,7 +454,7 @@ export function commitSizeInfos(commits: CommitInfo[]): string[] {
453454

454455
let churn = 0;
455456
for (const file of commit.files) {
456-
const scope = getScope(file.filename);
457+
const scope = classifyScope(file.filename);
457458
if (scope !== "source") {
458459
continue;
459460
}

util/danger/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
"engines": {
77
"node": ">=18"
88
},
9-
"scripts": {
10-
"test": "vitest run",
11-
"danger:ci": "danger ci --dangerfile dangerfile.ts",
12-
"danger:local": "ts-node --project tsconfig.json run-local.ts"
13-
},
9+
"scripts": {
10+
"test": "vitest run",
11+
"danger:ci": "danger ci --dangerfile dangerfile.ts",
12+
"danger:local": "ts-node --project tsconfig.json run-local.ts",
13+
"danger:scope-map": "ts-node --project tsconfig.json list-scopes.ts"
14+
},
1415
"devDependencies": {
1516
"@types/node": "^20.14.2",
1617
"danger": "^12.3.1",

0 commit comments

Comments
 (0)