Merge pull request #125 from github/joshmgross/file-provider
Add a `FileProvider` to `parseWorkflow`
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
@@ -53,13 +53,10 @@ describe("x-lang tests", () => {
|
||||
}
|
||||
|
||||
const parseResult = parseWorkflow(
|
||||
testFileName,
|
||||
[
|
||||
{
|
||||
name: testFileName,
|
||||
content: testInput
|
||||
}
|
||||
],
|
||||
{
|
||||
name: testFileName,
|
||||
content: testInput
|
||||
},
|
||||
nullTrace
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user