Support partial matrix context completion
This commit is contained in:
@@ -532,7 +532,7 @@ jobs:
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual([]);
|
||||
expect(result.map(x => x.label)).toEqual(["animal", "fruit"]);
|
||||
});
|
||||
|
||||
it("matrix with expression in property", async () => {
|
||||
|
||||
@@ -85,7 +85,7 @@ export async function complete(
|
||||
const expressionInput = (getExpressionInput(currentInput, relCharPos) || "").trim();
|
||||
|
||||
const allowedContext = getAllowedContext(token, parent);
|
||||
const context = await getContext(allowedContext, contextProviderConfig, workflowContext);
|
||||
const context = await getContext(allowedContext, contextProviderConfig, workflowContext, true);
|
||||
|
||||
return completeExpression(expressionInput, context, []);
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@ export type ContextValue = data.Dictionary | data.Null;
|
||||
export async function getContext(
|
||||
names: string[],
|
||||
config: ContextProviderConfig | undefined,
|
||||
workflowContext: WorkflowContext
|
||||
workflowContext: WorkflowContext,
|
||||
allowPartialContext: boolean = false
|
||||
): Promise<data.Dictionary> {
|
||||
const context = new data.Dictionary();
|
||||
|
||||
const filteredNames = filterContextNames(names, workflowContext);
|
||||
for (const contextName of filteredNames) {
|
||||
let value = (await getDefaultContext(contextName, workflowContext)) || new data.Dictionary();
|
||||
let value = getDefaultContext(contextName, workflowContext, allowPartialContext) || new data.Dictionary();
|
||||
if (value.kind === Kind.Null) {
|
||||
context.add(contextName, value);
|
||||
continue;
|
||||
@@ -35,7 +36,11 @@ export async function getContext(
|
||||
return context;
|
||||
}
|
||||
|
||||
async function getDefaultContext(name: string, workflowContext: WorkflowContext): Promise<ContextValue | undefined> {
|
||||
function getDefaultContext(
|
||||
name: string,
|
||||
workflowContext: WorkflowContext,
|
||||
allowPartialContext: boolean
|
||||
): ContextValue | undefined {
|
||||
switch (name) {
|
||||
case "runner":
|
||||
return objectToDictionary({
|
||||
@@ -62,7 +67,7 @@ async function getDefaultContext(name: string, workflowContext: WorkflowContext)
|
||||
return getStrategyContext(workflowContext);
|
||||
|
||||
case "matrix":
|
||||
return getMatrixContext(workflowContext);
|
||||
return getMatrixContext(workflowContext, allowPartialContext);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
@@ -62,7 +62,7 @@ describe("matrix context", () => {
|
||||
const workflowContext = {} as WorkflowContext;
|
||||
expect(workflowContext.job).toBeUndefined();
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@ describe("matrix context", () => {
|
||||
const workflowContext = {job} as WorkflowContext;
|
||||
expect(workflowContext.job!.strategy).toBeUndefined();
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ describe("matrix context", () => {
|
||||
const workflowContext = contextFromStrategy(stringToToken("hello"));
|
||||
expect(workflowContext.job!.strategy).toBeDefined();
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ describe("matrix context", () => {
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(new data.Null());
|
||||
});
|
||||
|
||||
@@ -96,7 +96,7 @@ describe("matrix context", () => {
|
||||
strategy.add(stringToToken("matrix"), stringToToken("hello"));
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(new data.Null());
|
||||
});
|
||||
|
||||
@@ -105,7 +105,7 @@ describe("matrix context", () => {
|
||||
strategy.add(stringToToken("matrix"), new MappingToken(undefined, undefined, undefined));
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
});
|
||||
@@ -116,7 +116,7 @@ describe("matrix context", () => {
|
||||
strategy.add(stringToToken("matrix"), expressionToToken("${{ fromJSON(needs.job1.outputs.matrix) }}"));
|
||||
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(new data.Null());
|
||||
});
|
||||
@@ -136,11 +136,37 @@ describe("matrix context", () => {
|
||||
strategy.add(stringToToken("matrix"), matrix);
|
||||
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(new data.Null());
|
||||
});
|
||||
|
||||
it("matrix with include expression and partial context allowed", () => {
|
||||
const include = expressionToToken("${{ fromJSON(needs.job1.outputs.matrix) }}");
|
||||
|
||||
const nodeSequence = new SequenceToken(undefined, undefined, undefined);
|
||||
nodeSequence.add(stringToToken("12"));
|
||||
nodeSequence.add(stringToToken("14"));
|
||||
|
||||
const matrix = new MappingToken(undefined, undefined, undefined);
|
||||
matrix.add(stringToToken("node"), nodeSequence);
|
||||
matrix.add(stringToToken("include"), include);
|
||||
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
strategy.add(stringToToken("matrix"), matrix);
|
||||
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext, true);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary({
|
||||
key: "node",
|
||||
value: new data.Array(new data.StringData("12"), new data.StringData("14"))
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("matrix with expression within property", () => {
|
||||
const version = expressionToToken("${{ github.event.client_payload.versions }}");
|
||||
|
||||
@@ -151,7 +177,7 @@ describe("matrix context", () => {
|
||||
strategy.add(stringToToken("matrix"), matrix);
|
||||
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary({
|
||||
@@ -166,7 +192,7 @@ describe("matrix context", () => {
|
||||
it("basic matrix", () => {
|
||||
const workflowContext = createMatrix({os: ["ubuntu-latest", "windows-latest"]});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary({
|
||||
key: "os",
|
||||
@@ -181,7 +207,7 @@ describe("matrix context", () => {
|
||||
node: ["12", "14"]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
{
|
||||
@@ -208,7 +234,7 @@ describe("matrix context", () => {
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
@@ -242,7 +268,7 @@ describe("matrix context", () => {
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
@@ -276,7 +302,7 @@ describe("matrix context", () => {
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
@@ -311,7 +337,7 @@ describe("matrix context", () => {
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
const context = getMatrixContext(workflowContext, false);
|
||||
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ import {SequenceToken} from "@github/actions-workflow-parser/templates/tokens/se
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
import {ContextValue} from "./default";
|
||||
|
||||
export function getMatrixContext(workflowContext: WorkflowContext): ContextValue {
|
||||
export function getMatrixContext(workflowContext: WorkflowContext, allowPartialContext: boolean): ContextValue {
|
||||
// https://docs.github.com/en/actions/learn-github-actions/contexts#matrix-context
|
||||
const strategy = workflowContext.job?.strategy;
|
||||
if (!strategy || !isMapping(strategy)) {
|
||||
@@ -19,7 +19,7 @@ export function getMatrixContext(workflowContext: WorkflowContext): ContextValue
|
||||
return new data.Null();
|
||||
}
|
||||
|
||||
const properties = matrixProperties(matrix);
|
||||
const properties = matrixProperties(matrix, allowPartialContext);
|
||||
if (!properties) {
|
||||
// Matrix included an expression, so there's no context we can provide
|
||||
return new data.Null();
|
||||
@@ -94,7 +94,10 @@ export function getMatrixContext(workflowContext: WorkflowContext): ContextValue
|
||||
*
|
||||
* Keys: os, version, environment
|
||||
*/
|
||||
function matrixProperties(matrix: MappingToken): Map<string, Set<string> | undefined> | undefined {
|
||||
function matrixProperties(
|
||||
matrix: MappingToken,
|
||||
allowPartialContext: boolean
|
||||
): Map<string, Set<string> | undefined> | undefined {
|
||||
const properties = new Map<string, Set<string> | undefined>();
|
||||
|
||||
let include: SequenceToken | undefined;
|
||||
@@ -108,9 +111,13 @@ function matrixProperties(matrix: MappingToken): Map<string, Set<string> | undef
|
||||
const key = pair.key.value;
|
||||
switch (key) {
|
||||
case "include":
|
||||
// If "include" is an expression, we can't know the properties of the matrix
|
||||
// If "include" is an expression, we can't know the full properties of the matrix
|
||||
if (isBasicExpression(pair.value) || !isSequence(pair.value)) {
|
||||
return;
|
||||
if (!allowPartialContext) {
|
||||
return;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
include = pair.value;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user