Ensure existing context errors don't prevent parsing workflows
This commit is contained in:
@@ -5,6 +5,7 @@ import {ContextProviderConfig} from "./context-providers/config";
|
|||||||
import {registerLogger} from "./log";
|
import {registerLogger} from "./log";
|
||||||
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
||||||
import {TestLogger} from "./test-utils/logger";
|
import {TestLogger} from "./test-utils/logger";
|
||||||
|
import {testFileProvider} from "./test-utils/test-file-provider";
|
||||||
|
|
||||||
const contextProviderConfig: ContextProviderConfig = {
|
const contextProviderConfig: ContextProviderConfig = {
|
||||||
getContext: async (context: string) => {
|
getContext: async (context: string) => {
|
||||||
@@ -1130,4 +1131,24 @@ jobs:
|
|||||||
|
|
||||||
expect(result.find(x => x.label === "toJson")!.insertText).toBe("toJson");
|
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"]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ export function parseWorkflow(entryFile: File, contextOrTrace: TraceWriter | Tem
|
|||||||
: new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), contextOrTrace);
|
: new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), contextOrTrace);
|
||||||
|
|
||||||
const fileId = context.getFileId(entryFile.name);
|
const fileId = context.getFileId(entryFile.name);
|
||||||
const reader = new YamlObjectReader(context, fileId, entryFile.content);
|
const reader = new YamlObjectReader(fileId, entryFile.content);
|
||||||
if (context.errors.count > 0) {
|
if (reader.errors.length > 0) {
|
||||||
// The file is not valid YAML, template errors could be misleading
|
// 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 {
|
return {
|
||||||
context,
|
context,
|
||||||
value: undefined
|
value: undefined
|
||||||
|
|||||||
@@ -68,11 +68,11 @@ it("YAML errors include range information", () => {
|
|||||||
|
|
||||||
const context = new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), nullTrace);
|
const context = new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), nullTrace);
|
||||||
const fileId = context.getFileId("test.yaml");
|
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({
|
expect(error.range).toEqual({
|
||||||
start: {line: 7, column: 38},
|
start: {line: 7, column: 38},
|
||||||
end: {line: 7, column: 63}
|
end: {line: 7, column: 63}
|
||||||
|
|||||||
@@ -15,20 +15,27 @@ import {
|
|||||||
} from "../templates/tokens/index";
|
} from "../templates/tokens/index";
|
||||||
import {Position, TokenRange} from "../templates/tokens/token-range";
|
import {Position, TokenRange} from "../templates/tokens/token-range";
|
||||||
|
|
||||||
|
export type YamlError = {
|
||||||
|
message: string;
|
||||||
|
range: TokenRange | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
export class YamlObjectReader implements ObjectReader {
|
export class YamlObjectReader implements ObjectReader {
|
||||||
private readonly _generator: Generator<ParseEvent>;
|
private readonly _generator: Generator<ParseEvent>;
|
||||||
private _current!: IteratorResult<ParseEvent>;
|
private _current!: IteratorResult<ParseEvent>;
|
||||||
private fileId?: number;
|
private fileId?: number;
|
||||||
private lineCounter = new LineCounter();
|
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, {
|
const doc = parseDocument(content, {
|
||||||
lineCounter: this.lineCounter,
|
lineCounter: this.lineCounter,
|
||||||
keepSourceTokens: true,
|
keepSourceTokens: true,
|
||||||
uniqueKeys: false // Uniqueness is validated by the template reader
|
uniqueKeys: false // Uniqueness is validated by the template reader
|
||||||
});
|
});
|
||||||
for (const err of doc.errors) {
|
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._generator = this.getNodes(doc);
|
||||||
this.fileId = fileId;
|
this.fileId = fileId;
|
||||||
|
|||||||
Reference in New Issue
Block a user