From e25500b8e41f6b10d86ec7e1959fbcbb1432a1f9 Mon Sep 17 00:00:00 2001 From: Josh Gross Date: Thu, 9 Feb 2023 18:50:05 -0500 Subject: [PATCH] Ensure existing context errors don't prevent parsing workflows --- .../src/complete.expressions.test.ts | 21 +++++++++++++++++++ .../src/workflows/workflow-parser.ts | 7 +++++-- .../src/workflows/yaml-object-reader.test.ts | 6 +++--- .../src/workflows/yaml-object-reader.ts | 11 ++++++++-- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/actions-languageservice/src/complete.expressions.test.ts b/actions-languageservice/src/complete.expressions.test.ts index f7130e7..d0dfdee 100644 --- a/actions-languageservice/src/complete.expressions.test.ts +++ b/actions-languageservice/src/complete.expressions.test.ts @@ -5,6 +5,7 @@ import {ContextProviderConfig} from "./context-providers/config"; import {registerLogger} from "./log"; import {getPositionFromCursor} from "./test-utils/cursor-position"; import {TestLogger} from "./test-utils/logger"; +import {testFileProvider} from "./test-utils/test-file-provider"; const contextProviderConfig: ContextProviderConfig = { getContext: async (context: string) => { @@ -1130,4 +1131,24 @@ jobs: expect(result.find(x => x.label === "toJson")!.insertText).toBe("toJson"); }); + + it("Parsing errors don't prevent reusable workflows from being loaded", async () => { + const input = ` +on: push +jobs: + a: + uses: ./reusable-workflow-with-outputs.yaml + b: + needs: [a] + runs-on: ubuntu-latest + steps: + - run: echo "hello \${{ needs.a.outputs.| }}" +`; + const result = await complete(...getPositionFromCursor(input), { + contextProviderConfig, + fileProvider: testFileProvider + }); + + expect(result.map(x => x.label)).toEqual(["build_id"]); + }); }); diff --git a/actions-workflow-parser/src/workflows/workflow-parser.ts b/actions-workflow-parser/src/workflows/workflow-parser.ts index ef32027..1710a3e 100644 --- a/actions-workflow-parser/src/workflows/workflow-parser.ts +++ b/actions-workflow-parser/src/workflows/workflow-parser.ts @@ -20,9 +20,12 @@ export function parseWorkflow(entryFile: File, contextOrTrace: TraceWriter | Tem : new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), contextOrTrace); const fileId = context.getFileId(entryFile.name); - const reader = new YamlObjectReader(context, fileId, entryFile.content); - if (context.errors.count > 0) { + const reader = new YamlObjectReader(fileId, entryFile.content); + if (reader.errors.length > 0) { // The file is not valid YAML, template errors could be misleading + for (const err of reader.errors) { + context.error(fileId, err.message, err.range); + } return { context, value: undefined diff --git a/actions-workflow-parser/src/workflows/yaml-object-reader.test.ts b/actions-workflow-parser/src/workflows/yaml-object-reader.test.ts index d4d4aac..9b767ef 100644 --- a/actions-workflow-parser/src/workflows/yaml-object-reader.test.ts +++ b/actions-workflow-parser/src/workflows/yaml-object-reader.test.ts @@ -68,11 +68,11 @@ it("YAML errors include range information", () => { const context = new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), nullTrace); const fileId = context.getFileId("test.yaml"); - new YamlObjectReader(context, fileId, content); + const reader = new YamlObjectReader(fileId, content); - expect(context.errors.count).toBe(1); + expect(reader.errors.length).toBe(1); - const error = context.errors.getErrors()[0]; + const error = reader.errors[0]; expect(error.range).toEqual({ start: {line: 7, column: 38}, end: {line: 7, column: 63} diff --git a/actions-workflow-parser/src/workflows/yaml-object-reader.ts b/actions-workflow-parser/src/workflows/yaml-object-reader.ts index d64c4c5..7b72c8a 100644 --- a/actions-workflow-parser/src/workflows/yaml-object-reader.ts +++ b/actions-workflow-parser/src/workflows/yaml-object-reader.ts @@ -15,20 +15,27 @@ import { } from "../templates/tokens/index"; import {Position, TokenRange} from "../templates/tokens/token-range"; +export type YamlError = { + message: string; + range: TokenRange | undefined; +}; + export class YamlObjectReader implements ObjectReader { private readonly _generator: Generator; private _current!: IteratorResult; private fileId?: number; private lineCounter = new LineCounter(); - constructor(context: TemplateContext, fileId: number | undefined, content: string) { + public errors: YamlError[] = []; + + constructor(fileId: number | undefined, content: string) { const doc = parseDocument(content, { lineCounter: this.lineCounter, keepSourceTokens: true, uniqueKeys: false // Uniqueness is validated by the template reader }); for (const err of doc.errors) { - context.error(fileId, err.message, rangeFromLinePos(err.linePos)); + this.errors.push({message: err.message, range: rangeFromLinePos(err.linePos)}); } this._generator = this.getNodes(doc); this.fileId = fileId;