Skip to content

Commit 8507419

Browse files
authored
Add missing activity types for pull_request and pull_request_target (#242)
Fixes #51 Added the following activity types to pull_request and pull_request_target: - milestoned - demilestoned - enqueued - dequeued These types were missing from workflow-v1.0.json but are valid workflow triggers per GitHub docs. Also added schema-sync.test.ts to ensure activity types in workflow-v1.0.json stay in sync with webhooks.json. The test: - Checks both directions (webhooks→schema and schema→webhooks) - Has WEBHOOK_ONLY for types not valid as workflow triggers: - check_suite: requested, rerequested - registry_package: default - Has SCHEMA_ONLY for types valid in workflows but not in webhooks: - registry_package: updated - Has NAME_MAPPINGS for naming differences: - project_column: edited (webhook) ↔ updated (schema) - Provides actionable error messages when mismatches are found
1 parent 952dc89 commit 8507419

File tree

4 files changed

+258
-4
lines changed

4 files changed

+258
-4
lines changed

docs/json-data-files.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,50 @@ Only `name`, `description`, and `childParamsGroups` are kept — these are used
148148
To compare all fields vs stripped, run `npm run update-webhooks -- --all` and diff the `.all.json` files against the regular ones.
149149

150150
See `EVENT_ACTION_FIELDS` and `BODY_PARAM_FIELDS` in `script/webhooks/index.ts` to modify what gets stripped.
151+
152+
## Schema Synchronization
153+
154+
The `workflow-v1.0.json` schema defines which activity types are valid for each workflow trigger event. A test in `workflow-parser/src/schema-sync.test.ts` verifies these stay in sync with `webhooks.json`.
155+
156+
### When the Test Fails
157+
158+
If the schema-sync test fails, you'll see an error like:
159+
160+
```
161+
Event "pull_request" is missing activity type "new_activity" in workflow-v1.0.json
162+
```
163+
164+
**To resolve:**
165+
166+
1. Check [Events that trigger workflows](https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows) to verify the activity type is a valid workflow trigger:
167+
- Find the event section (e.g., "pull_request")
168+
- Look at the "Activity types" table — it lists which types can be used in `on.<event>.types`
169+
- If the type is listed there, it's a valid workflow trigger
170+
- If the type only appears in webhook docs but NOT in the workflow trigger docs, it's webhook-only
171+
172+
2. If it IS a valid workflow trigger:
173+
- Edit `workflow-parser/src/workflow-v1.0.json`
174+
- Find the `<event>-activity-type` definition (e.g., `pull-request-activity-type`)
175+
- Add the new activity type to `allowed-values`
176+
- Update the `description` in `<event>-activity` to list all types
177+
- Run `npm test` to regenerate the minified JSON
178+
179+
3. If it is NOT a valid workflow trigger (webhook-only):
180+
- Edit `workflow-parser/src/schema-sync.test.ts`
181+
- Add the type to `WEBHOOK_ONLY` for that event
182+
183+
### Known Discrepancies
184+
185+
The test tracks several types of known discrepancies:
186+
187+
| Category | Purpose | Example |
188+
|----------|---------|---------|
189+
| `WEBHOOK_ONLY` | Types in webhooks that aren't valid workflow triggers | `check_suite.requested` |
190+
| `SCHEMA_ONLY` | Types valid for workflows but missing from webhooks | `registry_package.updated` |
191+
| `NAME_MAPPINGS` | Different names for the same concept | `project_column`: webhook uses `edited`, schema uses `updated` |
192+
193+
### Bidirectional Checking
194+
195+
The test checks both directions:
196+
- **webhooks → schema**: Ensures all webhook activity types are in the schema (or listed in `WEBHOOK_ONLY`)
197+
- **schema → webhooks**: Ensures the schema doesn't have types that don't exist in webhooks (or listed in `SCHEMA_ONLY` or `NAME_MAPPINGS`)
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import * as fs from "fs";
2+
3+
/**
4+
* This test ensures that activity types in workflow-v1.0.json stay in sync with
5+
* the webhooks.json file from the languageservice package.
6+
*
7+
* When this test fails, it means new activity types were added to webhooks.json
8+
* that need to be handled. See docs/json-data-files.md for detailed instructions.
9+
*
10+
* Quick reference for fixing failures:
11+
* 1. Check https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows
12+
* Find the event and look at its "Activity types" table to see if the type is a valid workflow trigger.
13+
* 2. If the activity type IS a valid workflow trigger:
14+
* → Add it to the corresponding *-activity-type definition in workflow-v1.0.json
15+
* 3. If the activity type is webhook-only (not in workflow docs):
16+
* → Add it to the WEBHOOK_ONLY list below
17+
* 4. If there's a naming difference between webhook and schema:
18+
* → Add it to the NAME_MAPPINGS list below
19+
* 5. If the schema has a type not in webhooks.json:
20+
* → Add it to the SCHEMA_ONLY list below
21+
*/
22+
23+
describe("schema-sync", () => {
24+
// Activity types that exist in webhooks.json but are intentionally NOT
25+
// supported as workflow triggers. These will be ignored when checking
26+
// webhooks → schema direction.
27+
const WEBHOOK_ONLY: Record<string, string[]> = {
28+
// check_suite: requested and rerequested are webhook-only, not valid workflow triggers
29+
// See: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#check_suite
30+
check_suite: ["requested", "rerequested"],
31+
32+
// registry_package: "default" is a webhook concept, not a workflow trigger type
33+
registry_package: ["default"]
34+
};
35+
36+
// Activity types that exist in workflow schema but are intentionally NOT
37+
// in webhooks.json (schema-only types). These will be ignored when checking
38+
// schema → webhooks direction.
39+
const SCHEMA_ONLY: Record<string, string[]> = {
40+
// registry_package: "updated" is a valid workflow trigger per GitHub docs
41+
// but doesn't exist in webhooks.json (webhooks only has "published" and "default")
42+
// See: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#registry_package
43+
registry_package: ["updated"]
44+
};
45+
46+
// Known naming differences between webhooks.json and workflow-v1.0.json.
47+
// Key: event name, Value: { webhook: "webhookName", schema: "schemaName" }
48+
// These are treated as equivalent when comparing in both directions.
49+
const NAME_MAPPINGS: Record<string, Array<{webhook: string; schema: string}>> = {
50+
// project_column: webhooks.json uses "edited" but workflow triggers use "updated"
51+
// This is a known naming difference - they represent the same action
52+
project_column: [{webhook: "edited", schema: "updated"}]
53+
};
54+
55+
it("activity types in workflow-v1.0.json match webhooks.json", () => {
56+
// Load webhooks.json (relative path from the test runner CWD which is the package root)
57+
const webhooksPath = "../languageservice/src/context-providers/events/webhooks.json";
58+
const webhooks = JSON.parse(fs.readFileSync(webhooksPath, "utf-8")) as Record<string, Record<string, unknown>>;
59+
60+
// Load workflow-v1.0.json
61+
const schemaPath = "./src/workflow-v1.0.json";
62+
const schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8")) as {
63+
definitions: Record<string, {"allowed-values"?: string[]; description?: string}>;
64+
};
65+
66+
const mismatches: string[] = [];
67+
68+
// Build mapping helpers for each event
69+
const getWebhookToSchemaMapping = (eventName: string): Map<string, string> => {
70+
const map = new Map<string, string>();
71+
for (const mapping of NAME_MAPPINGS[eventName] || []) {
72+
map.set(mapping.webhook, mapping.schema);
73+
}
74+
return map;
75+
};
76+
77+
const getSchemaToWebhookMapping = (eventName: string): Map<string, string> => {
78+
const map = new Map<string, string>();
79+
for (const mapping of NAME_MAPPINGS[eventName] || []) {
80+
map.set(mapping.schema, mapping.webhook);
81+
}
82+
return map;
83+
};
84+
85+
// Check both directions for each event
86+
for (const [eventName, eventData] of Object.entries(webhooks)) {
87+
const webhookTypes = Object.keys(eventData);
88+
if (webhookTypes.length === 0) continue;
89+
90+
const schemaTypeName = `${eventName.replace(/_/g, "-")}-activity-type`;
91+
const schemaDef = schema.definitions[schemaTypeName];
92+
93+
// If there's no activity type definition in the schema, this event
94+
// doesn't support activity types in workflows (e.g., push, pull)
95+
if (!schemaDef || !schemaDef["allowed-values"]) continue;
96+
97+
const schemaTypes = new Set(schemaDef["allowed-values"]);
98+
const webhookOnly = new Set(WEBHOOK_ONLY[eventName] || []);
99+
const schemaOnly = new Set(SCHEMA_ONLY[eventName] || []);
100+
const webhookToSchema = getWebhookToSchemaMapping(eventName);
101+
const schemaToWebhook = getSchemaToWebhookMapping(eventName);
102+
103+
// Direction 1: webhooks → schema
104+
// Check that each webhook type exists in schema (or has a mapping, or is webhook-only)
105+
for (const webhookType of webhookTypes) {
106+
if (webhookOnly.has(webhookType)) continue;
107+
108+
const mappedSchemaType = webhookToSchema.get(webhookType);
109+
if (mappedSchemaType) {
110+
// Has a mapping - check the mapped name exists in schema
111+
if (!schemaTypes.has(mappedSchemaType)) {
112+
mismatches.push(
113+
`Event "${eventName}": webhook type "${webhookType}" maps to "${mappedSchemaType}" but "${mappedSchemaType}" not found in schema`
114+
);
115+
}
116+
} else {
117+
// No mapping - check the type exists directly
118+
if (!schemaTypes.has(webhookType)) {
119+
mismatches.push(
120+
`Event "${eventName}": missing activity type "${webhookType}" in workflow-v1.0.json (exists in webhooks.json)`
121+
);
122+
}
123+
}
124+
}
125+
126+
// Direction 2: schema → webhooks
127+
// Check that each schema type exists in webhooks (or has a mapping, or is schema-only)
128+
const webhookTypesSet = new Set(webhookTypes);
129+
for (const schemaType of schemaTypes) {
130+
if (schemaOnly.has(schemaType)) continue;
131+
132+
const mappedWebhookType = schemaToWebhook.get(schemaType);
133+
if (mappedWebhookType) {
134+
// Has a mapping - check the mapped name exists in webhooks
135+
if (!webhookTypesSet.has(mappedWebhookType)) {
136+
mismatches.push(
137+
`Event "${eventName}": schema type "${schemaType}" maps to "${mappedWebhookType}" but "${mappedWebhookType}" not found in webhooks.json`
138+
);
139+
}
140+
} else {
141+
// No mapping - check the type exists directly
142+
if (!webhookTypesSet.has(schemaType)) {
143+
mismatches.push(
144+
`Event "${eventName}": extra activity type "${schemaType}" in workflow-v1.0.json (not in webhooks.json)`
145+
);
146+
}
147+
}
148+
}
149+
150+
// Check that the description mentions all allowed values
151+
const activityDefName = `${eventName.replace(/_/g, "-")}-activity`;
152+
const activityDef = schema.definitions[activityDefName];
153+
if (activityDef?.description) {
154+
for (const schemaType of schemaTypes) {
155+
if (!activityDef.description.includes(`\`${schemaType}\``)) {
156+
mismatches.push(
157+
`Event "${eventName}": description in "${activityDefName}" is missing activity type \`${schemaType}\``
158+
);
159+
}
160+
}
161+
}
162+
}
163+
164+
if (mismatches.length > 0) {
165+
const errorMessage = [
166+
"Activity type mismatches found between webhooks.json and workflow-v1.0.json:",
167+
"",
168+
...mismatches,
169+
"",
170+
"To fix these mismatches:",
171+
"1. Check GitHub docs: https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows",
172+
"2. Verify the activity type is valid for workflow triggers",
173+
"3. Update the *-activity-type definition in workflow-parser/src/workflow-v1.0.json",
174+
"4. Update the description to list all supported activity types",
175+
"5. If there's a naming difference, add it to NAME_MAPPINGS in schema-sync.test.ts",
176+
"6. If the type is webhook-only, add it to WEBHOOK_ONLY",
177+
"7. If the type is schema-only, add it to SCHEMA_ONLY"
178+
].join("\n");
179+
180+
throw new Error(errorMessage);
181+
}
182+
});
183+
});

workflow-parser/src/workflow-v1.0.json

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@
856856
}
857857
},
858858
"pull-request-activity": {
859-
"description": "The types of pull request activity that trigger the workflow. Supported activity types: `assigned`, `unassigned`, `labeled`, `unlabeled`, `opened`, `edited`, `closed`, `reopened`, `synchronize`, `converted_to_draft`, `ready_for_review`, `locked`, `unlocked`, `review_requested`, `review_request_removed`, `auto_merge_enabled`, `auto_merge_disabled`.",
859+
"description": "The types of pull request activity that trigger the workflow. Supported activity types: `assigned`, `unassigned`, `labeled`, `unlabeled`, `opened`, `edited`, `closed`, `reopened`, `synchronize`, `converted_to_draft`, `locked`, `unlocked`, `enqueued`, `dequeued`, `milestoned`, `demilestoned`, `ready_for_review`, `review_requested`, `review_request_removed`, `auto_merge_enabled`, `auto_merge_disabled`.",
860860
"one-of": [
861861
"pull-request-activity-type",
862862
"pull-request-activity-types"
@@ -879,9 +879,13 @@
879879
"reopened",
880880
"synchronize",
881881
"converted_to_draft",
882-
"ready_for_review",
883882
"locked",
884883
"unlocked",
884+
"enqueued",
885+
"dequeued",
886+
"milestoned",
887+
"demilestoned",
888+
"ready_for_review",
885889
"review_requested",
886890
"review_request_removed",
887891
"auto_merge_enabled",
@@ -1004,7 +1008,7 @@
10041008
}
10051009
},
10061010
"pull-request-target-activity": {
1007-
"description": "The types of pull request activity that trigger the workflow. Supported activity types: `assigned`, `unassigned`, `labeled`, `unlabeled`, `opened`, `edited`, `closed`, `reopened`, `synchronize`, `converted_to_draft`, `ready_for_review`, `locked`, `unlocked`, `review_requested`, `review_request_removed`, `auto_merge_enabled`, `auto_merge_disabled`.",
1011+
"description": "The types of pull request activity that trigger the workflow. Supported activity types: `assigned`, `unassigned`, `labeled`, `unlabeled`, `opened`, `edited`, `closed`, `reopened`, `synchronize`, `converted_to_draft`, `locked`, `unlocked`, `enqueued`, `dequeued`, `milestoned`, `demilestoned`, `ready_for_review`, `review_requested`, `review_request_removed`, `auto_merge_enabled`, `auto_merge_disabled`.",
10081012
"one-of": [
10091013
"pull-request-target-activity-type",
10101014
"pull-request-target-activity-types"
@@ -1027,9 +1031,13 @@
10271031
"reopened",
10281032
"synchronize",
10291033
"converted_to_draft",
1030-
"ready_for_review",
10311034
"locked",
10321035
"unlocked",
1036+
"enqueued",
1037+
"dequeued",
1038+
"milestoned",
1039+
"demilestoned",
1040+
"ready_for_review",
10331041
"review_requested",
10341042
"review_request_removed",
10351043
"auto_merge_enabled",

workflow-parser/testdata/reader/events-mapping-all.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ on:
120120
- unassigned
121121
- labeled
122122
- unlabeled
123+
- milestoned
124+
- demilestoned
123125
- opened
124126
- edited
125127
- closed
@@ -129,6 +131,8 @@ on:
129131
- ready_for_review
130132
- locked
131133
- unlocked
134+
- enqueued
135+
- dequeued
132136
- review_requested
133137
- review_request_removed
134138
- auto_merge_enabled
@@ -160,6 +164,8 @@ on:
160164
- unassigned
161165
- labeled
162166
- unlabeled
167+
- milestoned
168+
- demilestoned
163169
- opened
164170
- edited
165171
- closed
@@ -169,6 +175,8 @@ on:
169175
- ready_for_review
170176
- locked
171177
- unlocked
178+
- enqueued
179+
- dequeued
172180
- review_requested
173181
- review_request_removed
174182
- auto_merge_enabled
@@ -386,6 +394,8 @@ jobs:
386394
"unassigned",
387395
"labeled",
388396
"unlabeled",
397+
"milestoned",
398+
"demilestoned",
389399
"opened",
390400
"edited",
391401
"closed",
@@ -395,6 +405,8 @@ jobs:
395405
"ready_for_review",
396406
"locked",
397407
"unlocked",
408+
"enqueued",
409+
"dequeued",
398410
"review_requested",
399411
"review_request_removed",
400412
"auto_merge_enabled",
@@ -441,6 +453,8 @@ jobs:
441453
"unassigned",
442454
"labeled",
443455
"unlabeled",
456+
"milestoned",
457+
"demilestoned",
444458
"opened",
445459
"edited",
446460
"closed",
@@ -450,6 +464,8 @@ jobs:
450464
"ready_for_review",
451465
"locked",
452466
"unlocked",
467+
"enqueued",
468+
"dequeued",
453469
"review_requested",
454470
"review_request_removed",
455471
"auto_merge_enabled",

0 commit comments

Comments
 (0)