Skip to content

Commit 5e7beb4

Browse files
committed
Add PR check to make sure all commands are registered somewhere
1 parent 66a2b23 commit 5e7beb4

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

azure-pipeline.pr.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ jobs:
1515
- script: npm run lint
1616
displayName: Run lint
1717

18+
- script: yarn run check:commands
19+
displayName: Verify command registrations
20+
1821
- script: yarn run test
1922
displayName: Run test suite
2023
env:

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4317,6 +4317,7 @@
43174317
"watch": "webpack --watch --mode development --env esbuild",
43184318
"watch:web": "webpack --watch --mode development --config-name extension:webworker --config-name webviews",
43194319
"hygiene": "node ./build/hygiene.js",
4320+
"check:commands": "node scripts/check-commands.js",
43204321
"prepare": "husky install",
43214322
"update:codicons": "npx ts-node --project tsconfig.scripts.json build/update-codicons.ts"
43224323
},

scripts/check-commands.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
/*
7+
* Verifies that every command declared in package.json under contributes.commands
8+
* has a corresponding vscode.commands.registerCommand('<commandId>' ...) call in the source.
9+
* Exits with non-zero status if any are missing.
10+
*/
11+
12+
const fs = require('fs');
13+
const path = require('path');
14+
const glob = require('glob');
15+
16+
function readJson(filePath) {
17+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
18+
}
19+
20+
function getDeclaredCommands(pkg) {
21+
const contributes = pkg.contributes || {};
22+
const commands = contributes.commands || [];
23+
const ids = [];
24+
for (const cmd of commands) {
25+
if (cmd && typeof cmd.command === 'string') {
26+
ids.push(cmd.command);
27+
}
28+
}
29+
return ids;
30+
}
31+
32+
function getRegisteredCommands(workspaceRoot) {
33+
const files = glob.sync('src/**/*.ts', { cwd: workspaceRoot, ignore: ['**/node_modules/**', '**/dist/**', '**/out/**'] });
34+
const registered = new Set();
35+
const regex = /vscode\.commands\.(registerCommand|registerDiffInformationCommand)\s*\(\s*[']([^'\n]+)[']/g;
36+
for (const rel of files) {
37+
const full = path.join(workspaceRoot, rel);
38+
let content;
39+
try {
40+
content = fs.readFileSync(full, 'utf8');
41+
} catch {
42+
continue;
43+
}
44+
let match;
45+
while ((match = regex.exec(content)) !== null) {
46+
registered.add(match[2]);
47+
}
48+
}
49+
return registered;
50+
}
51+
52+
function main() {
53+
const workspaceRoot = path.resolve(__dirname, '..');
54+
const pkgPath = path.join(workspaceRoot, 'package.json');
55+
const pkg = readJson(pkgPath);
56+
const declared = getDeclaredCommands(pkg);
57+
const registered = getRegisteredCommands(workspaceRoot);
58+
59+
const missing = declared.filter(id => !registered.has(id));
60+
61+
if (missing.length) {
62+
console.error('ERROR: The following commands are declared in package.json but not registered:');
63+
for (const m of missing) {
64+
console.error(' - ' + m);
65+
}
66+
console.error('\nAdd a corresponding vscode.commands.registerCommand("<id>", ...) call.');
67+
process.exit(1);
68+
} else {
69+
console.log('All declared commands are registered.');
70+
}
71+
}
72+
73+
main();

0 commit comments

Comments
 (0)