Merge pull request #125 from github/joshmgross/file-provider

Add a `FileProvider` to `parseWorkflow`
This commit is contained in:
Josh Gross
2023-02-06 17:10:46 -05:00
committed by GitHub
19 changed files with 96 additions and 161 deletions
@@ -9,7 +9,7 @@ const nullTrace: TraceWriter = {
};
export function createWorkflowContext(workflow: string, job?: string, stepIndex?: number): WorkflowContext {
const parsed = parseWorkflow("test.yaml", [{name: "test.yaml", content: workflow}], nullTrace);
const parsed = parseWorkflow({name: "test.yaml", content: workflow}, nullTrace);
if (!parsed.value) {
throw new Error("Failed to parse workflow");
}
+1 -1
View File
@@ -65,7 +65,7 @@ export async function complete(
name: textDocument.uri,
content: newDoc.getText()
};
const result = parseWorkflow(file.name, [file], nullTrace);
const result = parseWorkflow(file, nullTrace);
if (!result.value) {
return [];
}
@@ -8,13 +8,10 @@ import {getWorkflowContext, WorkflowContext} from "./workflow-context";
function testGetWorkflowContext(input: string): WorkflowContext {
const [textDocument, pos] = getPositionFromCursor(input);
const result = parseWorkflow(
"wf.yaml",
[
{
content: textDocument.getText(),
name: "wf.yaml"
}
],
{
content: textDocument.getText(),
name: "wf.yaml"
},
nullTrace
);
@@ -14,7 +14,7 @@ export async function documentLinks(document: TextDocument): Promise<DocumentLin
content: document.getText()
};
const result = parseWorkflow(file.name, [file], nullTrace);
const result = parseWorkflow(file, nullTrace);
if (!result.value) {
return [];
}
@@ -78,7 +78,7 @@ function testMapToExpressionPos(input: string) {
name: td.uri,
content: td.getText()
};
const result = parseWorkflow(file.name, [file], nullTrace);
const result = parseWorkflow(file, nullTrace);
if (!result.value) {
throw new Error("Invalid workflow");
}
@@ -105,7 +105,7 @@ async function hoverExpression(input: string) {
name: td.uri,
content: td.getText()
};
const result = parseWorkflow(file.name, [file], nullTrace);
const result = parseWorkflow(file, nullTrace);
if (!result.value) {
return undefined;
}
+1 -1
View File
@@ -37,7 +37,7 @@ export async function hover(document: TextDocument, position: Position, config?:
name: document.uri,
content: document.getText()
};
const result = parseWorkflow(file.name, [file], nullTrace);
const result = parseWorkflow(file, nullTrace);
if (!result.value) {
return null;
}
@@ -27,13 +27,10 @@ function testFindToken(input: string): {
} {
const [textDocument, pos] = getPositionFromCursor(input);
const result = parseWorkflow(
"wf.yaml",
[
{
content: textDocument.getText(),
name: "wf.yaml"
}
],
{
content: textDocument.getText(),
name: "wf.yaml"
},
nullTrace
);
+1 -1
View File
@@ -56,7 +56,7 @@ export async function validate(
const diagnostics: Diagnostic[] = [];
try {
const result: ParseWorkflowResult = parseWorkflow(file.name, [file], nullTrace);
const result: ParseWorkflowResult = parseWorkflow(file, nullTrace);
if (result.value) {
// Errors will be updated in the context. Attempt to do the conversion anyway in order to give the user more information
const template = convertWorkflowTemplate(result.context, result.value, ErrorPolicy.TryConversion);
@@ -1,5 +0,0 @@
import {File} from "@github/actions-workflow-parser/workflows/file";
export type WorkflowProvider = {
getWorkflow: (name: string) => Promise<File | undefined>;
};
+20 -35
View File
@@ -6,19 +6,16 @@ import {parseWorkflow} from "./workflows/workflow-parser";
describe("Workflow Expression Parsing", () => {
it("preserves original expressions when building format", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: `on: push
{
name: "test.yaml",
content: `on: push
run-name: Test \${{ github.event_name }} \${{ github.ref }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo 'hello'`
}
],
},
nullTrace
);
@@ -44,11 +41,9 @@ jobs:
it("preserves original expressions when building format for multi-line strings", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: `on: push
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
@@ -56,8 +51,7 @@ jobs:
- run: |
echo \${{ github.event_name }}
echo 'hello' \${{github.ref }}`
}
],
},
nullTrace
);
@@ -109,11 +103,9 @@ jobs:
it("return errors and string token with preserved expressions for (multiple) expression errors", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: `on: push
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
@@ -121,8 +113,7 @@ jobs:
- run: |
echo \${{ abc }}
echo 'hello' \${{ gith }}`
}
],
},
nullTrace
);
@@ -147,11 +138,9 @@ jobs:
it("reports all errors for multi-line expressions at the correct locations", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: `on: push
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
@@ -159,8 +148,7 @@ jobs:
- run: |
echo \${{ fromJSON2('test') }}
echo 'hello' \${{ toJSON2(inputs.test) }}`
}
],
},
nullTrace
);
@@ -186,19 +174,16 @@ jobs:
it("parses isExpression strings into expression tokens", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: `on: push
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- run: echo 'hello'`
}
],
},
nullTrace
);
+17 -29
View File
@@ -5,13 +5,10 @@ import {parseWorkflow} from "./workflows/workflow-parser";
describe("parseWorkflow", () => {
it("parses valid workflow", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: "on: push\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - run: echo 'hello'"
}
],
{
name: "test.yaml",
content: "on: push\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - run: echo 'hello'"
},
nullTrace
);
@@ -20,13 +17,10 @@ describe("parseWorkflow", () => {
it("contains range for error", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: "on: push\njobs:\n build:\n steps:\n - run: echo 'hello'"
}
],
{
name: "test.yaml",
content: "on: push\njobs:\n build:\n steps:\n - run: echo 'hello'"
},
nullTrace
);
@@ -40,19 +34,16 @@ describe("parseWorkflow", () => {
it("error range for expression is constrained to scalar node", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: `on: push
{
name: "test.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: \${{ github.event = 12 }}
run: echo 'hello'`
}
],
},
nullTrace
);
@@ -71,14 +62,11 @@ jobs:
it("tokens contain descriptions", () => {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content:
"on: push\nname: hello\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - run: echo 'hello'"
}
],
{
name: "test.yaml",
content:
"on: push\nname: hello\njobs:\n build:\n runs-on: ubuntu-latest\n steps:\n - run: echo 'hello'"
},
nullTrace
);
@@ -9,16 +9,13 @@ function serializeTemplate(template: unknown): unknown {
describe("convertWorkflowTemplate", () => {
it("converts workflow with one job", () => {
const result = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on: push
{
name: "wf.yaml",
content: `on: push
jobs:
build:
runs-on: ubuntu-latest`
}
],
},
nullTrace
);
@@ -48,11 +45,9 @@ jobs:
it("converts workflow if expressions", () => {
const result = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on: push
{
name: "wf.yaml",
content: `on: push
jobs:
build:
if: \${{ true }}
@@ -60,8 +55,7 @@ jobs:
deploy:
if: true
runs-on: ubuntu-latest`
}
],
},
nullTrace
);
@@ -100,17 +94,14 @@ jobs:
it("converts workflow with empty needs", () => {
const result = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on: push
{
name: "wf.yaml",
content: `on: push
jobs:
build:
needs: # comment to preserve whitespace in test
runs-on: ubuntu-latest`
}
],
},
nullTrace
);
@@ -145,11 +136,9 @@ jobs:
it("converts workflow with needs errors", () => {
const result = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on: push
{
name: "wf.yaml",
content: `on: push
jobs:
job1:
needs: [unknown-job, job3]
@@ -159,8 +148,7 @@ jobs:
job3:
needs: job1
runs-on: ubuntu-latest`
}
],
},
nullTrace
);
@@ -225,11 +213,9 @@ jobs:
it("converts workflow with invalid on", () => {
const result = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on:
{
name: "wf.yaml",
content: `on:
workflow_dispatch:
inputs:
test:
@@ -239,8 +225,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- run: echo hello`
}
],
},
nullTrace
);
@@ -288,15 +273,12 @@ jobs:
it("converts workflow with invalid jobs", () => {
const result = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on: push
{
name: "wf.yaml",
content: `on: push
jobs:
build:`
}
],
},
nullTrace
);
@@ -6,13 +6,10 @@ import {TemplateToken} from "./template-token";
describe("traverse", () => {
it("returns parent token and key", () => {
const workflow = parseWorkflow(
"wf.yaml",
[
{
name: "wf.yaml",
content: `on: push`
}
],
{
name: "wf.yaml",
content: `on: push`
},
nullTrace
);
@@ -0,0 +1,3 @@
export interface FileProvider {
getFileContent(path: string): Promise<File>;
}
@@ -11,7 +11,7 @@ jobs:
- name: 'Hello \${{ fromJSON('test') == inputs.name }}'
run: echo Hello, world!`;
const result = parseWorkflow("main.yaml", [{name: "main.yaml", content: content}], nullTrace);
const result = parseWorkflow({name: "main.yaml", content: content}, nullTrace);
expect(result.context.errors.count).toBe(1);
expect(result.value).toBeUndefined();
@@ -3,6 +3,7 @@ import * as templateReader from "../templates/template-reader";
import {TemplateToken} from "../templates/tokens/template-token";
import {TraceWriter} from "../templates/trace-writer";
import {File} from "./file";
import {FileProvider} from "./file-provider";
import {WORKFLOW_ROOT} from "./workflow-constants";
import {getWorkflowSchema} from "./workflow-schema";
import {YamlObjectReader} from "./yaml-object-reader";
@@ -11,15 +12,11 @@ export interface ParseWorkflowResult {
value: TemplateToken | undefined;
}
export function parseWorkflow(entryFileName: string, files: File[], trace: TraceWriter): ParseWorkflowResult {
export function parseWorkflow(entryFile: File, trace: TraceWriter, fileProvider?: FileProvider): ParseWorkflowResult {
const context = new TemplateContext(new TemplateValidationErrors(), getWorkflowSchema(), trace);
// Add file ids
files.forEach(x => context.getFileId(x.name));
const fileId = context.getFileId(entryFileName);
const fileContent = files[fileId - 1].content;
const reader = new YamlObjectReader(context, fileId, fileContent);
const fileId = context.getFileId(entryFile.name);
const reader = new YamlObjectReader(context, fileId, entryFile.content);
if (context.errors.count > 0) {
// The file is not valid YAML, template errors could be misleading
return {
@@ -81,13 +81,10 @@ it("YAML errors include range information", () => {
function parseAsWorkflow(content: string): TemplateToken | undefined {
const result = parseWorkflow(
"test.yaml",
[
{
name: "test.yaml",
content: content
}
],
{
name: "test.yaml",
content: content
},
nullTrace
);
+4 -7
View File
@@ -53,13 +53,10 @@ describe("x-lang tests", () => {
}
const parseResult = parseWorkflow(
testFileName,
[
{
name: testFileName,
content: testInput
}
],
{
name: testFileName,
content: testInput
},
nullTrace
);