Merge pull request #42 from github/joshmgross/matrix-context-completion
Support `matrix` context auto-completion
This commit is contained in:
@@ -374,10 +374,9 @@ jobs:
|
||||
|
||||
expect(result.map(x => x.label)).toContain("strategy");
|
||||
});
|
||||
});
|
||||
|
||||
it("includes expected keys", async () => {
|
||||
const input = `
|
||||
it("includes expected keys", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
@@ -390,10 +389,173 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: npm test > test-job-\${{ strategy.| }}.txt
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual(["fail-fast", "job-index", "job-total", "max-parallel"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("matrix context", () => {
|
||||
it("matrix is not suggested when outside of a matrix job", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: npm test > test-job-\${{ | }}.txt
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual(["fail-fast", "job-index", "job-total", "max-parallel"]);
|
||||
expect(result.map(x => x.label)).not.toContain("strategy");
|
||||
});
|
||||
|
||||
it("matrix is suggested within a matrix job", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
test-group: [1, 2]
|
||||
node: [14, 16]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: npm test > test-job-\${{ | }}.txt
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toContain("strategy");
|
||||
});
|
||||
|
||||
it("basic matrix job", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: \${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
node: [14, 16]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: \${{ matrix.| }}
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual(["node", "os"]);
|
||||
});
|
||||
|
||||
it("matrix with include", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
fruit: [apple, pear]
|
||||
animal: [cat, dog]
|
||||
include:
|
||||
- color: green
|
||||
- color: pink
|
||||
animal: cat
|
||||
- fruit: apple
|
||||
shape: circle
|
||||
- fruit: banana
|
||||
- fruit: banana
|
||||
animal: cat
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: \${{ matrix.| }}
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual(["animal", "color", "fruit", "shape"]);
|
||||
});
|
||||
|
||||
it("matrix from expression", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix: \${{ fromJSON('{"color":["green","blue"]}') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: \${{ matrix.| }}
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual([]);
|
||||
});
|
||||
|
||||
it("matrix with include expression", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: \${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
fruit: [apple, pear]
|
||||
animal: [cat, dog]
|
||||
include: \${{ fromJSON('{"color":"green"}') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: \${{ matrix.| }}
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual([]);
|
||||
});
|
||||
|
||||
it("matrix with expression in property", async () => {
|
||||
const input = `
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
color: \${{ fromJSON('["green","blue"]') }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: \${{ matrix.| }}
|
||||
`;
|
||||
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual(["color"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,9 +2,10 @@ import {data} from "@github/actions-expressions";
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
import {ContextProviderConfig} from "./config";
|
||||
import {getInputsContext} from "./inputs";
|
||||
import {getMatrixContext} from "./matrix";
|
||||
import {getNeedsContext} from "./needs";
|
||||
import {getStepsContext} from "./steps";
|
||||
import {allowStrategyContext, getStrategyContext} from "./strategy";
|
||||
import {getStrategyContext} from "./strategy";
|
||||
|
||||
export async function getContext(
|
||||
names: string[],
|
||||
@@ -55,6 +56,9 @@ async function getDefaultContext(name: string, workflowContext: WorkflowContext)
|
||||
|
||||
case "strategy":
|
||||
return getStrategyContext(workflowContext);
|
||||
|
||||
case "matrix":
|
||||
return getMatrixContext(workflowContext);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
@@ -72,9 +76,14 @@ function objectToDictionary(object: {[key: string]: string}): data.Dictionary {
|
||||
function filterContextNames(contextNames: string[], workflowContext: WorkflowContext): string[] {
|
||||
return contextNames.filter(name => {
|
||||
switch (name) {
|
||||
case "matrix":
|
||||
case "strategy":
|
||||
return allowStrategyContext(workflowContext);
|
||||
return hasStrategy(workflowContext);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function hasStrategy(workflowContext: WorkflowContext): boolean {
|
||||
return workflowContext.job?.strategy !== undefined;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
import {data} from "@github/actions-expressions";
|
||||
import {Job} from "@github/actions-workflow-parser/model/workflow-template";
|
||||
import {BasicExpressionToken} from "@github/actions-workflow-parser/templates/tokens/basic-expression-token";
|
||||
import {ExpressionToken} from "@github/actions-workflow-parser/templates/tokens/expression-token";
|
||||
import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token";
|
||||
import {SequenceToken} from "@github/actions-workflow-parser/templates/tokens/sequence-token";
|
||||
import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token";
|
||||
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token";
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
import {getMatrixContext} from "./matrix";
|
||||
|
||||
type MatrixMap = {
|
||||
[key: string]: Array<string> | Array<{[key: string]: string}>;
|
||||
};
|
||||
|
||||
function createMatrix(map: MatrixMap): WorkflowContext {
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
strategy.add(stringToToken("matrix"), mapToToken(map));
|
||||
return contextFromStrategy(strategy);
|
||||
}
|
||||
|
||||
function mapToToken(map: MatrixMap) {
|
||||
const token = new MappingToken(undefined, undefined, undefined);
|
||||
for (const key in map) {
|
||||
const arr = map[key];
|
||||
const seqToken = new SequenceToken(undefined, undefined, undefined);
|
||||
for (const item of arr) {
|
||||
if (typeof item === "string") {
|
||||
seqToken.add(new StringToken(undefined, undefined, item, undefined));
|
||||
} else {
|
||||
const mapToken = new MappingToken(undefined, undefined, undefined);
|
||||
for (const key in item) {
|
||||
mapToken.add(stringToToken(key), stringToToken(item[key]));
|
||||
}
|
||||
seqToken.add(mapToken);
|
||||
}
|
||||
}
|
||||
token.add(stringToToken(key), seqToken);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
function stringToToken(value: string) {
|
||||
return new StringToken(undefined, undefined, value, undefined);
|
||||
}
|
||||
|
||||
function expressionToToken(expr: string) {
|
||||
return new BasicExpressionToken(undefined, undefined, expr, undefined, undefined);
|
||||
}
|
||||
|
||||
function contextFromStrategy(strategy?: TemplateToken) {
|
||||
return {
|
||||
job: {
|
||||
strategy: strategy
|
||||
}
|
||||
} as WorkflowContext;
|
||||
}
|
||||
|
||||
describe("matrix context", () => {
|
||||
describe("invalid workflow context", () => {
|
||||
it("job not defined", () => {
|
||||
const workflowContext = {} as WorkflowContext;
|
||||
expect(workflowContext.job).toBeUndefined();
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("strategy not defined", () => {
|
||||
const job = {} as Job;
|
||||
const workflowContext = {job} as WorkflowContext;
|
||||
expect(workflowContext.job!.strategy).toBeUndefined();
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("strategy is not a mapping token", () => {
|
||||
const workflowContext = contextFromStrategy(stringToToken("hello"));
|
||||
expect(workflowContext.job!.strategy).toBeDefined();
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("matrix is not defined", () => {
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("matrix is not a mapping token", () => {
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
strategy.add(stringToToken("matrix"), stringToToken("hello"));
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("empty matrix", () => {
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
strategy.add(stringToToken("matrix"), new MappingToken(undefined, undefined, undefined));
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
});
|
||||
|
||||
describe("matrix with expressions", () => {
|
||||
it("matrix from expression", () => {
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
strategy.add(stringToToken("matrix"), expressionToToken("${{ fromJSON(needs.job1.outputs.matrix) }}"));
|
||||
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
const context = getMatrixContext(workflowContext);
|
||||
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("matrix with include expression", () => {
|
||||
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);
|
||||
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
|
||||
it("matrix with expression within property", () => {
|
||||
const version = expressionToToken("${{ github.event.client_payload.versions }}");
|
||||
|
||||
const matrix = new MappingToken(undefined, undefined, undefined);
|
||||
matrix.add(stringToToken("version"), version);
|
||||
|
||||
const strategy = new MappingToken(undefined, undefined, undefined);
|
||||
strategy.add(stringToToken("matrix"), matrix);
|
||||
|
||||
const workflowContext = contextFromStrategy(strategy);
|
||||
const context = getMatrixContext(workflowContext);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary({
|
||||
key: "version",
|
||||
value: new data.Null()
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("valid matrices", () => {
|
||||
it("basic matrix", () => {
|
||||
const workflowContext = createMatrix({os: ["ubuntu-latest", "windows-latest"]});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary({
|
||||
key: "os",
|
||||
value: new data.Array(new data.StringData("ubuntu-latest"), new data.StringData("windows-latest"))
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("matrix with multiple properties", () => {
|
||||
const workflowContext = createMatrix({
|
||||
os: ["ubuntu-latest", "windows-latest"],
|
||||
node: ["12", "14"]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
{
|
||||
key: "os",
|
||||
value: new data.Array(new data.StringData("ubuntu-latest"), new data.StringData("windows-latest"))
|
||||
},
|
||||
{
|
||||
key: "node",
|
||||
value: new data.Array(new data.StringData("12"), new data.StringData("14"))
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("matrix with include", () => {
|
||||
const workflowContext = createMatrix({
|
||||
os: ["ubuntu-latest", "windows-latest"],
|
||||
node: ["12", "14"],
|
||||
include: [
|
||||
{
|
||||
os: "macos-latest",
|
||||
node: "12"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
{
|
||||
key: "os",
|
||||
value: new data.Array(
|
||||
new data.StringData("ubuntu-latest"),
|
||||
new data.StringData("windows-latest"),
|
||||
new data.StringData("macos-latest")
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "node",
|
||||
value: new data.Array(new data.StringData("12"), new data.StringData("14"))
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("matrix with only include", () => {
|
||||
const workflowContext = createMatrix({
|
||||
include: [
|
||||
{
|
||||
site: "production",
|
||||
datacenter: "site-a"
|
||||
},
|
||||
{
|
||||
site: "staging",
|
||||
datacenter: "site-b"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
{
|
||||
key: "site",
|
||||
value: new data.Array(new data.StringData("production"), new data.StringData("staging"))
|
||||
},
|
||||
{
|
||||
key: "datacenter",
|
||||
value: new data.Array(new data.StringData("site-a"), new data.StringData("site-b"))
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("matrix with exclude", () => {
|
||||
const workflowContext = createMatrix({
|
||||
os: ["macos-latest", "windows-latest"],
|
||||
node: ["12", "14", "16"],
|
||||
environment: ["staging", "production"],
|
||||
exclude: [
|
||||
{
|
||||
os: "macos-latest",
|
||||
node: "12",
|
||||
environment: "production"
|
||||
},
|
||||
{
|
||||
os: "windows-latest",
|
||||
node: "16"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
|
||||
expect(context).toEqual(
|
||||
new data.Dictionary(
|
||||
{
|
||||
key: "os",
|
||||
value: new data.Array(new data.StringData("macos-latest"), new data.StringData("windows-latest"))
|
||||
},
|
||||
{
|
||||
key: "node",
|
||||
value: new data.Array(new data.StringData("12"), new data.StringData("14"), new data.StringData("16"))
|
||||
},
|
||||
{
|
||||
key: "environment",
|
||||
value: new data.Array(new data.StringData("staging"), new data.StringData("production"))
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("matrix with only exclude", () => {
|
||||
const workflowContext = createMatrix({
|
||||
exclude: [
|
||||
{
|
||||
os: "macos-latest",
|
||||
node: "12",
|
||||
environment: "production"
|
||||
},
|
||||
{
|
||||
os: "windows-latest",
|
||||
node: "16"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const context = getMatrixContext(workflowContext);
|
||||
|
||||
expect(context).toEqual(new data.Dictionary());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,184 @@
|
||||
import {data} from "@github/actions-expressions";
|
||||
import {isBasicExpression, isMapping, isSequence, isString} from "@github/actions-workflow-parser";
|
||||
import {KeyValuePair} from "@github/actions-workflow-parser/templates/tokens/key-value-pair";
|
||||
import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token";
|
||||
import {SequenceToken} from "@github/actions-workflow-parser/templates/tokens/sequence-token";
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
|
||||
export function getMatrixContext(workflowContext: WorkflowContext): data.Dictionary {
|
||||
// https://docs.github.com/en/actions/learn-github-actions/contexts#matrix-context
|
||||
const strategy = workflowContext.job?.strategy;
|
||||
if (!strategy || !isMapping(strategy)) {
|
||||
return new data.Dictionary();
|
||||
}
|
||||
|
||||
const matrix = strategy.find("matrix");
|
||||
if (!matrix || !isMapping(matrix)) {
|
||||
// Matrix could be an expression, so there's no context we can provide
|
||||
return new data.Dictionary();
|
||||
}
|
||||
|
||||
const properties = matrixProperties(matrix);
|
||||
if (!properties) {
|
||||
// Matrix included an expression, so there's no context we can provide
|
||||
return new data.Dictionary();
|
||||
}
|
||||
|
||||
const d = new data.Dictionary();
|
||||
for (const [key, value] of properties) {
|
||||
if (value === undefined) {
|
||||
d.add(key, new data.Null());
|
||||
continue;
|
||||
}
|
||||
|
||||
const a = new data.Array();
|
||||
for (const v of value) {
|
||||
a.add(new data.StringData(v));
|
||||
}
|
||||
d.add(key, a);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix
|
||||
* A matrix property can come from:
|
||||
* - An explicit matrix property key
|
||||
* - A configuration included via the "include" property
|
||||
*
|
||||
* By definition, "exclude" can't add new keys to the matrix.
|
||||
* Additionally, "include" and "exclude are not properties of the matrix
|
||||
* If the matrix or "include" is an expression, we can't know the keys
|
||||
*
|
||||
* Examples:
|
||||
* 1. Basic matrix
|
||||
* matrix:
|
||||
* version: [10, 12, 14]
|
||||
* os: [ubuntu-latest, windows-latest]
|
||||
*
|
||||
* Keys: version, os
|
||||
*
|
||||
* 2. Matrix with "include"
|
||||
* matrix:
|
||||
* version: [10, 12, 14]
|
||||
* os: [ubuntu-latest, windows-latest]
|
||||
* include:
|
||||
* - version: 10
|
||||
* os: macos-latest
|
||||
*
|
||||
* Keys: version, os
|
||||
*
|
||||
* 3. Matrix with new properties in "include"
|
||||
* matrix:
|
||||
* include:
|
||||
* - site: "production"
|
||||
* datacenter: "site-a"
|
||||
* - site: "staging"
|
||||
* datacenter: "site-b"
|
||||
*
|
||||
* Keys: site, datacenter
|
||||
*
|
||||
* 4. Matrix with "exclude"
|
||||
* matrix:
|
||||
* os: [macos-latest, windows-latest]
|
||||
* version: [12, 14, 16]
|
||||
* environment: [staging, production]
|
||||
* exclude:
|
||||
* - os: macos-latest
|
||||
* version: 12
|
||||
* environment: production
|
||||
* - os: windows-latest
|
||||
* version: 16
|
||||
*
|
||||
* Keys: os, version, environment
|
||||
*/
|
||||
function matrixProperties(matrix: MappingToken): Map<string, Set<string> | undefined> | undefined {
|
||||
const properties = new Map<string, Set<string> | undefined>();
|
||||
|
||||
let include: SequenceToken | undefined;
|
||||
|
||||
for (let i = 0; i < matrix.count; i++) {
|
||||
const pair = matrix.get(i);
|
||||
if (!isString(pair.key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const key = pair.key.value;
|
||||
switch (key) {
|
||||
case "include":
|
||||
// If "include" is an expression, we can't know the properties of the matrix
|
||||
if (isBasicExpression(pair.value) || !isSequence(pair.value)) {
|
||||
return;
|
||||
}
|
||||
include = pair.value;
|
||||
break;
|
||||
|
||||
case "exclude":
|
||||
break;
|
||||
default:
|
||||
if (!isSequence(pair.value)) {
|
||||
properties.set(key, undefined);
|
||||
continue;
|
||||
}
|
||||
|
||||
const values = new Set<string>();
|
||||
for (let j = 0; j < pair.value.count; j++) {
|
||||
const value = pair.value.get(j);
|
||||
// The parser should coerce matrix values to strings, ignore expressions
|
||||
if (isString(value)) {
|
||||
values.add(value.value);
|
||||
}
|
||||
}
|
||||
|
||||
properties.set(key, values);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (include) {
|
||||
for (let i = 0; i < include.count; i++) {
|
||||
const item = include.get(i);
|
||||
if (!isMapping(item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let j = 0; j < item.count; j++) {
|
||||
const pair = item.get(j);
|
||||
addValueToProperties(properties, pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
function addValueToProperties(properties: Map<string, Set<string> | undefined>, pair: KeyValuePair): void {
|
||||
if (!isString(pair.key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = pair.key.value;
|
||||
const value = isString(pair.value) ? pair.value.value : undefined;
|
||||
if (!properties.has(key)) {
|
||||
if (value === undefined) {
|
||||
properties.set(key, undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
properties.set(key, new Set<string>([value]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const property = properties.get(key);
|
||||
if (property !== undefined) {
|
||||
property.add(value);
|
||||
return;
|
||||
}
|
||||
|
||||
properties.set(key, new Set<string>([value]));
|
||||
}
|
||||
@@ -38,7 +38,3 @@ export function getStrategyContext(workflowContext: WorkflowContext): data.Dicti
|
||||
|
||||
return strategyContext;
|
||||
}
|
||||
|
||||
export function allowStrategyContext(workflowContext: WorkflowContext): boolean {
|
||||
return workflowContext.job?.strategy !== undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user