From 378d2ab7996ecb4ccc836f3fb6d4d5663b706a76 Mon Sep 17 00:00:00 2001 From: Josh Gross Date: Fri, 20 Jan 2023 18:38:56 -0500 Subject: [PATCH 1/2] Support `client_payload` for `repository_dispatch` events --- .../src/context-providers/github.ts | 17 +++++++++++++---- .../src/validate.expressions.test.ts | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/actions-languageservice/src/context-providers/github.ts b/actions-languageservice/src/context-providers/github.ts index 14a9e69..1b14af2 100644 --- a/actions-languageservice/src/context-providers/github.ts +++ b/actions-languageservice/src/context-providers/github.ts @@ -89,17 +89,26 @@ function getEventContext(workflowContext: WorkflowContext): ExpressionData { for (const e of events) { const payload = eventPayloads[e]; if (payload) { - merge(d, payload); + const anyKeys = ANY_KEYS[e] || []; + merge(d, payload, anyKeys); } } return d; } -function merge(d: data.Dictionary, toAdd: Object): data.Dictionary { +// These events have a top-level object that can be any type +const ANY_KEYS: Record = { + repository_dispatch: ["client_payload"] +}; + +function merge(d: data.Dictionary, toAdd: Object, anyKeys: string[]): data.Dictionary { for (const [key, value] of Object.entries(toAdd)) { - if (value && typeof value === "object" && !d.get(key)) { - d.add(key, merge(new data.Dictionary(), value)); + if (anyKeys.includes(key)) { + d.add(key, new data.Null()); + } else if (value && typeof value === "object" && !d.get(key)) { + // Only use anyKeys for the top-level object + d.add(key, merge(new data.Dictionary(), value, [])); } else { d.add(key, new data.Null()); } diff --git a/actions-languageservice/src/validate.expressions.test.ts b/actions-languageservice/src/validate.expressions.test.ts index 85e0a4f..9d05070 100644 --- a/actions-languageservice/src/validate.expressions.test.ts +++ b/actions-languageservice/src/validate.expressions.test.ts @@ -1236,5 +1236,23 @@ jobs: } ]); }); + + it("allows any property in client_payload", async () => { + const input = ` +on: + repository_dispatch: + types: [test] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - run: echo \${{ github.event.client_payload.anything }} + - run: echo \${{ github.event.client_payload.branch }}` + + const result = await validate(createDocument("wf.yaml", input)); + + expect(result).toEqual([]); + }); }); }); From e8bf17771ce4048f046caf48e4ff3791bb9c27cd Mon Sep 17 00:00:00 2001 From: Josh Gross Date: Mon, 23 Jan 2023 11:35:09 -0500 Subject: [PATCH 2/2] Allow `{}` to represent any value in event payloads --- .../events/repository_dispatch.json | 5 +--- .../src/context-providers/github.ts | 24 +++++++++---------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/actions-languageservice/src/context-providers/events/repository_dispatch.json b/actions-languageservice/src/context-providers/events/repository_dispatch.json index fd32d52..0f3c2b4 100644 --- a/actions-languageservice/src/context-providers/events/repository_dispatch.json +++ b/actions-languageservice/src/context-providers/events/repository_dispatch.json @@ -1,10 +1,7 @@ { "action": "on-demand-test", "branch": "master", - "client_payload": { - "unit": false, - "integration": true - }, + "client_payload": {}, "repository": { "id": 17273051, "node_id": "MDEwOlJlcG9zaXRvcnkxNzI3MzA1MQ==", diff --git a/actions-languageservice/src/context-providers/github.ts b/actions-languageservice/src/context-providers/github.ts index 1b14af2..af43d20 100644 --- a/actions-languageservice/src/context-providers/github.ts +++ b/actions-languageservice/src/context-providers/github.ts @@ -89,26 +89,24 @@ function getEventContext(workflowContext: WorkflowContext): ExpressionData { for (const e of events) { const payload = eventPayloads[e]; if (payload) { - const anyKeys = ANY_KEYS[e] || []; - merge(d, payload, anyKeys); + merge(d, payload); } } return d; } -// These events have a top-level object that can be any type -const ANY_KEYS: Record = { - repository_dispatch: ["client_payload"] -}; - -function merge(d: data.Dictionary, toAdd: Object, anyKeys: string[]): data.Dictionary { +function merge(d: data.Dictionary, toAdd: Object): data.Dictionary { for (const [key, value] of Object.entries(toAdd)) { - if (anyKeys.includes(key)) { - d.add(key, new data.Null()); - } else if (value && typeof value === "object" && !d.get(key)) { - // Only use anyKeys for the top-level object - d.add(key, merge(new data.Dictionary(), value, [])); + if (value && typeof value === "object" && !d.get(key)) { + + if (!Array.isArray(value) && Object.entries(value).length === 0) { + // Allow an empty object to be any value + d.add(key, new data.Null()); + continue; + } + + d.add(key, merge(new data.Dictionary(), value)); } else { d.add(key, new data.Null()); }