Skip to content

Commit 8aedf1e

Browse files
committed
folder structure validator
1 parent 444bbb2 commit 8aedf1e

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env node
2+
3+
const { execSync } = require('child_process');
4+
5+
const allowedCategories = new Set([
6+
'Core ServiceNow APIs',
7+
'Server-Side Components',
8+
'Client-Side Components',
9+
'Modern Development',
10+
'Integration',
11+
'Specialized Areas'
12+
]);
13+
14+
function resolveDiffRange() {
15+
if (process.argv[2]) {
16+
return process.argv[2];
17+
}
18+
19+
const inCI = process.env.GITHUB_ACTIONS === 'true';
20+
if (!inCI) {
21+
return 'origin/main...HEAD';
22+
}
23+
24+
const base = process.env.GITHUB_BASE_REF ? `origin/${process.env.GITHUB_BASE_REF}` : 'origin/main';
25+
const head = process.env.GITHUB_SHA || 'HEAD';
26+
return `${base}...${head}`;
27+
}
28+
29+
function getChangedFiles(diffRange) {
30+
let output;
31+
try {
32+
output = execSync(`git diff --name-only --diff-filter=ACMR ${diffRange}`, {
33+
encoding: 'utf8',
34+
stdio: ['ignore', 'pipe', 'pipe']
35+
});
36+
} catch (error) {
37+
console.error('Failed to collect changed files. Ensure the base branch is fetched.');
38+
console.error(error.stderr?.toString() || error.message);
39+
process.exit(1);
40+
}
41+
42+
return output
43+
.split('\n')
44+
.map((line) => line.trim())
45+
.filter(Boolean);
46+
}
47+
48+
function validateFilePath(filePath) {
49+
const normalized = filePath.replace(/\\/g, '/');
50+
const segments = normalized.split('/');
51+
52+
if (!allowedCategories.has(segments[0])) {
53+
return null;
54+
}
55+
56+
// Files must live under: Category/Subcategory/SpecificUseCase/<file>
57+
if (segments.length < 4) {
58+
return `Move '${normalized}' under a valid folder hierarchy (Category/Subcategory/Use-Case/your-file). Files directly inside '${segments[0]}' or its subcategories are not allowed.`;
59+
}
60+
61+
return null;
62+
}
63+
64+
function main() {
65+
const diffRange = resolveDiffRange();
66+
const changedFiles = getChangedFiles(diffRange);
67+
68+
if (changedFiles.length === 0) {
69+
console.log('No relevant file changes detected.');
70+
return;
71+
}
72+
73+
const problems = [];
74+
75+
for (const filePath of changedFiles) {
76+
const issue = validateFilePath(filePath);
77+
if (issue) {
78+
problems.push(issue);
79+
}
80+
}
81+
82+
if (problems.length > 0) {
83+
console.error('Folder structure violations found:');
84+
for (const msg of problems) {
85+
console.error(` - ${msg}`);
86+
}
87+
process.exit(1);
88+
}
89+
90+
console.log('Folder structure looks good.');
91+
}
92+
93+
main();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Validate Folder Structure
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
8+
concurrency:
9+
group: folder-structure-${{ github.head_ref || github.run_id }}
10+
cancel-in-progress: true
11+
12+
jobs:
13+
structure:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Use Node.js 18
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: 18
25+
26+
- name: Validate folder layout
27+
run: node .github/scripts/validate-structure.js

0 commit comments

Comments
 (0)