Skip to content

Commit bfb514f

Browse files
committed
Add validation tests and CI job for webhook optimization
1 parent 07d923f commit bfb514f

File tree

6 files changed

+325
-138
lines changed

6 files changed

+325
-138
lines changed

.github/workflows/buildtest.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,31 @@ jobs:
6464
echo ""
6565
exit 1
6666
fi
67+
68+
validate-webhooks:
69+
runs-on: ubuntu-latest
70+
name: Validate webhook optimization
71+
72+
steps:
73+
- uses: actions/checkout@v4
74+
- name: Use Node.js 22.x
75+
uses: actions/setup-node@v4
76+
with:
77+
node-version: 22.x
78+
cache: 'npm'
79+
registry-url: 'https://npm.pkg.github.com'
80+
- run: npm ci
81+
env:
82+
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
83+
- name: Generate full webhooks file
84+
run: cd languageservice && npm run update-webhooks
85+
- name: Run optimization validation tests
86+
run: cd languageservice && npm test -- --testPathPattern=eventPayloads
87+
- name: Verify validation tests ran
88+
run: |
89+
if [ ! -f languageservice/src/context-providers/events/webhooks.full.validation-complete ]; then
90+
echo "ERROR: Validation tests did not run!"
91+
echo "The webhooks.full.validation-complete marker file was not created."
92+
exit 1
93+
fi
94+
echo "Validation tests completed at: $(cat languageservice/src/context-providers/events/webhooks.full.validation-complete)"

.gitignore

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ node_modules
77
# Minified JSON (generated at build time)
88
*.min.json
99

10-
# Intermediate JSON for size comparison (generated by update-webhooks --all)
11-
*.all.json
12-
*.drop.json
13-
*.strip.json
10+
# Full webhooks source (generated by update-webhooks, used for validation tests)
11+
*.full.json
12+
13+
# Validation marker (generated by tests)
14+
*.validation-complete

languageservice/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
"pretest": "npm run minify-json",
4444
"test": "NODE_OPTIONS=\"--experimental-vm-modules\" jest",
4545
"test-watch": "NODE_OPTIONS=\"--experimental-vm-modules\" jest --watch",
46-
"update-webhooks": "npx tsx script/webhooks/index.ts",
46+
"update-webhooks": "npx tsx script/webhooks/update-webhooks.ts",
4747
"watch": "tsc --build tsconfig.build.json --watch"
4848
},
4949
"dependencies": {
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Event filter lists for webhook processing.
3+
*
4+
* These lists categorize GitHub webhook events into those that are valid
5+
* workflow triggers (KEPT_EVENTS) and those that are not (DROPPED_EVENTS).
6+
*
7+
* When new events are added to the GitHub API, they must be added to one
8+
* of these lists. The update-webhooks script will fail if it encounters
9+
* an unknown event.
10+
*
11+
* See: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
12+
*/
13+
14+
/**
15+
* Events to drop - not valid workflow triggers (GitHub App or API-only events)
16+
*/
17+
export const DROPPED_EVENTS = new Set([
18+
"branch_protection_configuration",
19+
"code_scanning_alert",
20+
"commit_comment",
21+
"custom_property",
22+
"custom_property_values",
23+
"dependabot_alert",
24+
"deploy_key",
25+
"github_app_authorization",
26+
"installation",
27+
"installation_repositories",
28+
"installation_target",
29+
"marketplace_purchase",
30+
"member",
31+
"membership",
32+
"merge_group",
33+
"meta",
34+
"org_block",
35+
"organization",
36+
"package",
37+
"personal_access_token_request",
38+
"ping",
39+
"repository",
40+
"repository_advisory",
41+
"repository_ruleset",
42+
"secret_scanning_alert",
43+
"secret_scanning_alert_location",
44+
"security_advisory",
45+
"security_and_analysis",
46+
"sponsorship",
47+
"star",
48+
"team",
49+
"team_add"
50+
]);
51+
52+
/**
53+
* Events to keep - valid workflow triggers
54+
*/
55+
export const KEPT_EVENTS = new Set([
56+
"branch_protection_rule",
57+
"check_run",
58+
"check_suite",
59+
"create",
60+
"delete",
61+
"deployment",
62+
"deployment_status",
63+
"discussion",
64+
"discussion_comment",
65+
"fork",
66+
"gollum",
67+
"issue_comment",
68+
"issues",
69+
"label",
70+
"milestone",
71+
"page_build",
72+
"project",
73+
"project_card",
74+
"project_column",
75+
"projects_v2",
76+
"projects_v2_item",
77+
"public",
78+
"pull_request",
79+
"pull_request_review",
80+
"pull_request_review_comment",
81+
"pull_request_review_thread",
82+
"push",
83+
"registry_package",
84+
"release",
85+
"repository_dispatch",
86+
"repository_import",
87+
"repository_vulnerability_alert",
88+
"status",
89+
"watch",
90+
"workflow_dispatch",
91+
"workflow_job",
92+
"workflow_run"
93+
]);

languageservice/script/webhooks/index.ts renamed to languageservice/script/webhooks/update-webhooks.ts

Lines changed: 19 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -3,98 +3,12 @@ import Webhook from "./webhook.js";
33

44
import schemaImport from "rest-api-description/descriptions/api.github.com/dereferenced/api.github.com.deref.json";
55
import {deduplicateWebhooks} from "./deduplicate.js";
6+
import {DROPPED_EVENTS, KEPT_EVENTS} from "./event-filters.js";
67
const schema = schemaImport as any;
78

89
const OUTPUT_PATH = "./src/context-providers/events/webhooks.json";
910
const OBJECTS_PATH = "./src/context-providers/events/objects.json";
10-
const ALL_OUTPUT_PATH = "./src/context-providers/events/webhooks.all.json";
11-
const ALL_OBJECTS_PATH = "./src/context-providers/events/objects.all.json";
12-
const DROP_OUTPUT_PATH = "./src/context-providers/events/webhooks.drop.json";
13-
const DROP_OBJECTS_PATH = "./src/context-providers/events/objects.drop.json";
14-
const STRIP_OUTPUT_PATH = "./src/context-providers/events/webhooks.strip.json";
15-
const STRIP_OBJECTS_PATH = "./src/context-providers/events/objects.strip.json";
16-
17-
// Parse --all flag
18-
const generateAll = process.argv.includes("--all");
19-
20-
// Events to drop - not valid workflow triggers (GitHub App or API-only events)
21-
// See: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
22-
const DROPPED_EVENTS = new Set([
23-
"branch_protection_configuration",
24-
"code_scanning_alert",
25-
"commit_comment",
26-
"custom_property",
27-
"custom_property_values",
28-
"dependabot_alert",
29-
"deploy_key",
30-
"github_app_authorization",
31-
"installation",
32-
"installation_repositories",
33-
"installation_target",
34-
"marketplace_purchase",
35-
"member",
36-
"membership",
37-
"merge_group",
38-
"meta",
39-
"org_block",
40-
"organization",
41-
"package",
42-
"personal_access_token_request",
43-
"ping",
44-
"repository",
45-
"repository_advisory",
46-
"repository_ruleset",
47-
"secret_scanning_alert",
48-
"secret_scanning_alert_location",
49-
"security_advisory",
50-
"security_and_analysis",
51-
"sponsorship",
52-
"star",
53-
"team",
54-
"team_add"
55-
]);
56-
57-
// Events to keep - valid workflow triggers
58-
// See: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
59-
const KEPT_EVENTS = new Set([
60-
"branch_protection_rule",
61-
"check_run",
62-
"check_suite",
63-
"create",
64-
"delete",
65-
"deployment",
66-
"deployment_status",
67-
"discussion",
68-
"discussion_comment",
69-
"fork",
70-
"gollum",
71-
"issue_comment",
72-
"issues",
73-
"label",
74-
"milestone",
75-
"page_build",
76-
"project",
77-
"project_card",
78-
"project_column",
79-
"projects_v2",
80-
"projects_v2_item",
81-
"public",
82-
"pull_request",
83-
"pull_request_review",
84-
"pull_request_review_comment",
85-
"pull_request_review_thread",
86-
"push",
87-
"registry_package",
88-
"release",
89-
"repository_dispatch",
90-
"repository_import",
91-
"repository_vulnerability_alert",
92-
"status",
93-
"watch",
94-
"workflow_dispatch",
95-
"workflow_job",
96-
"workflow_run"
97-
]);
11+
const FULL_OUTPUT_PATH = "./src/context-providers/events/webhooks.full.json";
9812

9913
/**
10014
* Fields to strip from the JSON data.
@@ -234,6 +148,23 @@ if (unknownEvents.length > 0) {
234148
process.exit(1);
235149
}
236150

151+
// Build full webhooks (all events, no transformations) for validation tests
152+
const fullWebhooks: Record<string, Record<string, Webhook>> = {};
153+
for (const webhook of webhooks) {
154+
if (!webhook.action) webhook.action = "default";
155+
156+
if (fullWebhooks[webhook.category]) {
157+
fullWebhooks[webhook.category][webhook.action] = webhook;
158+
} else {
159+
fullWebhooks[webhook.category] = {};
160+
fullWebhooks[webhook.category][webhook.action] = webhook;
161+
}
162+
}
163+
164+
// Write full version (before any optimizations)
165+
await fs.writeFile(FULL_OUTPUT_PATH, JSON.stringify(fullWebhooks, null, 2));
166+
console.log(`Wrote ${FULL_OUTPUT_PATH} (${Object.keys(fullWebhooks).length} events, unoptimized)`);
167+
237168
// The category is the name of the webhook
238169
const categorizedWebhooks: Record<string, Record<string, Webhook>> = {};
239170
for (const webhook of webhooks) {
@@ -264,47 +195,3 @@ await fs.writeFile(OUTPUT_PATH, JSON.stringify(strippedWebhooks, null, 2));
264195

265196
console.log(`Wrote ${OUTPUT_PATH} (${Object.keys(strippedWebhooks).length} events)`);
266197
console.log(`Wrote ${OBJECTS_PATH} (${objectsArray.length} objects)`);
267-
268-
// Optionally generate intermediate versions for size comparison
269-
if (generateAll) {
270-
// Helper to deep clone
271-
function clone<T>(obj: T): T {
272-
return JSON.parse(JSON.stringify(obj));
273-
}
274-
275-
// Build full webhooks (no drop, no strip) from fresh data
276-
const fullWebhooks: Record<string, Record<string, any>> = {};
277-
for (const webhook of webhooks) {
278-
const w = clone(webhook);
279-
if (!w.action) w.action = "default";
280-
fullWebhooks[w.category] ||= {};
281-
fullWebhooks[w.category][w.action] = w;
282-
}
283-
284-
// Generate all version (no drop, no strip)
285-
const allWebhooks = clone(fullWebhooks);
286-
const allObjects = deduplicateWebhooks(allWebhooks);
287-
await fs.writeFile(ALL_OUTPUT_PATH, JSON.stringify(allWebhooks, null, 2));
288-
await fs.writeFile(ALL_OBJECTS_PATH, JSON.stringify(allObjects, null, 2));
289-
console.log(`Wrote ${ALL_OUTPUT_PATH} (${Object.keys(allWebhooks).length} events)`);
290-
console.log(`Wrote ${ALL_OBJECTS_PATH} (${allObjects.length} objects)`);
291-
292-
// Generate drop-only version (drop events, no strip)
293-
const dropWebhooks = clone(fullWebhooks);
294-
for (const event of DROPPED_EVENTS) {
295-
delete dropWebhooks[event];
296-
}
297-
const dropObjects = deduplicateWebhooks(dropWebhooks);
298-
await fs.writeFile(DROP_OUTPUT_PATH, JSON.stringify(dropWebhooks, null, 2));
299-
await fs.writeFile(DROP_OBJECTS_PATH, JSON.stringify(dropObjects, null, 2));
300-
console.log(`Wrote ${DROP_OUTPUT_PATH} (${Object.keys(dropWebhooks).length} events)`);
301-
console.log(`Wrote ${DROP_OBJECTS_PATH} (${dropObjects.length} objects)`);
302-
303-
// Generate strip-only version (strip fields, no drop)
304-
const stripWebhooks = stripFields(clone(fullWebhooks));
305-
const stripObjects = deduplicateWebhooks(stripWebhooks);
306-
await fs.writeFile(STRIP_OUTPUT_PATH, JSON.stringify(stripWebhooks, null, 2));
307-
await fs.writeFile(STRIP_OBJECTS_PATH, JSON.stringify(stripObjects, null, 2));
308-
console.log(`Wrote ${STRIP_OUTPUT_PATH} (${Object.keys(stripWebhooks).length} events)`);
309-
console.log(`Wrote ${STRIP_OBJECTS_PATH} (${stripObjects.length} objects)`);
310-
}

0 commit comments

Comments
 (0)