Merge branch 'main' into elbrenn/called-secret-complete

This commit is contained in:
Beth Brennan
2023-03-07 16:44:25 -05:00
committed by GitHub
21 changed files with 363 additions and 133 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "browser-playground", "name": "browser-playground",
"version": "0.1.157", "version": "0.1.159",
"description": "", "description": "",
"private": true, "private": true,
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@github/actions-languageserver": "^0.1.157", "@github/actions-languageserver": "^0.1.159",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2", "monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "^4.0.3", "monaco-languageclient": "^4.0.3",
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@github/actions-expressions", "name": "@github/actions-expressions",
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"source": "./src/index.ts", "source": "./src/index.ts",
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@github/actions-languageserver", "name": "@github/actions-languageserver",
"version": "0.1.157", "version": "0.1.159",
"description": "Language server for GitHub Actions", "description": "Language server for GitHub Actions",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@@ -38,8 +38,8 @@
"watch": "tsc --build tsconfig.build.json --watch" "watch": "tsc --build tsconfig.build.json --watch"
}, },
"dependencies": { "dependencies": {
"@github/actions-languageservice": "^0.1.157", "@github/actions-languageservice": "^0.1.159",
"@github/actions-workflow-parser": "^0.1.157", "@github/actions-workflow-parser": "^0.1.159",
"@octokit/rest": "^19.0.7", "@octokit/rest": "^19.0.7",
"vscode-languageserver": "^8.0.2", "vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.7", "vscode-languageserver-textdocument": "^1.0.7",
+49 -45
View File
@@ -6,6 +6,7 @@ import {isMapping, isString} from "@github/actions-workflow-parser";
import {Octokit} from "@octokit/rest"; import {Octokit} from "@octokit/rest";
import {RepositoryContext} from "../initializationOptions"; import {RepositoryContext} from "../initializationOptions";
import {TTLCache} from "../utils/cache"; import {TTLCache} from "../utils/cache";
import {getRepoPermission} from "../utils/repo-permission";
export async function getSecrets( export async function getSecrets(
workflowContext: WorkflowContext, workflowContext: WorkflowContext,
@@ -15,6 +16,13 @@ export async function getSecrets(
defaultContext: DescriptionDictionary | undefined, defaultContext: DescriptionDictionary | undefined,
mode: Mode mode: Mode
): Promise<DescriptionDictionary> { ): Promise<DescriptionDictionary> {
const permission = await getRepoPermission(octokit, cache, repo);
if (permission === "none") {
const secretsContext = defaultContext || new DescriptionDictionary();
secretsContext.complete = false;
return secretsContext;
}
let environmentName: string | undefined; let environmentName: string | undefined;
if (workflowContext?.job?.environment) { if (workflowContext?.job?.environment) {
if (isString(workflowContext.job.environment)) { if (isString(workflowContext.job.environment)) {
@@ -41,54 +49,50 @@ export async function getSecrets(
} }
} }
try { const secrets = await getRemoteSecrets(octokit, cache, repo, environmentName);
const secrets = await getRemoteSecrets(octokit, cache, repo, environmentName);
// Build combined map of secrets
const secretsMap = new Map<
string,
{
key: string;
value: data.StringData;
description?: string;
}
>();
secrets.orgSecrets.forEach(secret => // Build combined map of secrets
secretsMap.set(secret.value.toLowerCase(), { const secretsMap = new Map<
key: secret.value, string,
value: new data.StringData("***"), {
description: "Organization secret" key: string;
}) value: data.StringData;
); description?: string;
// Override org secrets with repo secrets
secrets.repoSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
value: new data.StringData("***"),
description: "Repository secret"
})
);
// Override repo secrets with environment secrets (if defined)
secrets.environmentSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
value: new data.StringData("***"),
description: `Secret for environment \`${environmentName}\``
})
);
// Sort secrets by key and add to context
Array.from(secretsMap.values())
.sort((a, b) => a.key.localeCompare(b.key))
.forEach(secret => secretsContext?.add(secret.key, secret.value, secret.description));
} catch (e: any) {
if (e.status === 403 || e.status === 404) {
secretsContext.complete = false;
} }
} >();
secrets.orgSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
value: new data.StringData("***"),
description: "Organization secret"
})
);
// Override org secrets with repo secrets
secrets.repoSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
value: new data.StringData("***"),
description: "Repository secret"
})
);
// Override repo secrets with environment secrets (if defined)
secrets.environmentSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
value: new data.StringData("***"),
description: `Secret for environment \`${environmentName}\``
})
);
// Sort secrets by key and add to context
Array.from(secretsMap.values())
.sort((a, b) => a.key.localeCompare(b.key))
.forEach(secret => secretsContext?.add(secret.key, secret.value, secret.description));
return secretsContext; return secretsContext;
} }
@@ -6,6 +6,7 @@ import {Pair} from "@github/actions-expressions/data/expressiondata";
import {RepositoryContext} from "../initializationOptions"; import {RepositoryContext} from "../initializationOptions";
import {StringData} from "@github/actions-expressions/data/index"; import {StringData} from "@github/actions-expressions/data/index";
import {TTLCache} from "../utils/cache"; import {TTLCache} from "../utils/cache";
import {getRepoPermission} from "../utils/repo-permission";
export async function getVariables( export async function getVariables(
workflowContext: WorkflowContext, workflowContext: WorkflowContext,
@@ -14,6 +15,13 @@ export async function getVariables(
repo: RepositoryContext, repo: RepositoryContext,
defaultContext: DescriptionDictionary | undefined defaultContext: DescriptionDictionary | undefined
): Promise<DescriptionDictionary | undefined> { ): Promise<DescriptionDictionary | undefined> {
const permission = await getRepoPermission(octokit, cache, repo);
if (permission === "none") {
const secretsContext = defaultContext || new DescriptionDictionary();
secretsContext.complete = false;
return secretsContext;
}
let environmentName: string | undefined; let environmentName: string | undefined;
if (workflowContext?.job?.environment) { if (workflowContext?.job?.environment) {
if (isString(workflowContext.job.environment)) { if (isString(workflowContext.job.environment)) {
@@ -31,54 +39,49 @@ export async function getVariables(
} }
const variablesContext = defaultContext || new DescriptionDictionary(); const variablesContext = defaultContext || new DescriptionDictionary();
try { const variables = await getRemoteVariables(octokit, cache, repo, environmentName);
const variables = await getRemoteVariables(octokit, cache, repo, environmentName);
// Build combined map of variables // Build combined map of variables
const variablesMap = new Map< const variablesMap = new Map<
string, string,
{ {
key: string; key: string;
value: data.StringData; value: data.StringData;
description?: string; description?: string;
}
>();
variables.organizationVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Organization variable`
})
);
// Override org variables with repo variables
variables.repoVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Repository variable`
})
);
// Override repo variables with environment veriables (if defined)
variables.environmentVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName}\``
})
);
// Sort variables by key and add to context
Array.from(variablesMap.values())
.sort((a, b) => a.key.localeCompare(b.key))
.forEach(variable => variablesContext?.add(variable.key, variable.value, variable.description));
} catch (e: any) {
if (e.status === 403 || e.status === 404) {
variablesContext.complete = false;
} }
} >();
variables.organizationVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Organization variable`
})
);
// Override org variables with repo variables
variables.repoVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Repository variable`
})
);
// Override repo variables with environment veriables (if defined)
variables.environmentVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName}\``
})
);
// Sort variables by key and add to context
Array.from(variablesMap.values())
.sort((a, b) => a.key.localeCompare(b.key))
.forEach(variable => variablesContext?.add(variable.key, variable.value, variable.description));
return variablesContext; return variablesContext;
} }
@@ -0,0 +1,46 @@
import {error} from "@github/actions-languageservice/log";
import {Octokit} from "@octokit/rest";
import {RepositoryContext} from "../initializationOptions";
import {TTLCache} from "./cache";
import {getUsername} from "./username";
export type RepoPermission = "admin" | "write" | "read" | "none";
export async function getRepoPermission(
octokit: Octokit,
cache: TTLCache,
repo: RepositoryContext
): Promise<RepoPermission> {
const username = await getUsername(octokit, cache);
const permission = await cache.get(`${repo.owner}/${repo.name}/${username}/permission`, undefined, () =>
fetchRepoPermission(octokit, repo, username)
);
switch (permission) {
case "admin":
case "write":
case "read":
case "none":
return permission;
default:
error(`Unknown permission: ${permission}`);
return "none";
}
}
async function fetchRepoPermission(octokit: Octokit, repo: RepositoryContext, username: string): Promise<string> {
try {
const res = await octokit.request("GET /repos/{owner}/{repo}/collaborators/{username}/permission", {
owner: repo.owner,
repo: repo.name,
username: username
});
const permission = res.data?.permission;
return permission;
} catch (e: any) {
if (e.status === 404 || e.status === 403) {
return "none";
}
throw e;
}
}
+16
View File
@@ -0,0 +1,16 @@
import {Octokit} from "@octokit/rest";
import {TTLCache} from "./cache";
export async function getUsername(octokit: Octokit, cache: TTLCache): Promise<string> {
return await cache.get(`/username`, undefined, () => fetchUsername(octokit));
}
async function fetchUsername(octokit: Octokit): Promise<string> {
try {
const username = await octokit.request("GET /user").then(res => res.data.login);
return username;
} catch (e) {
console.log("Failure to retrieve username: ", e);
throw e;
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "@github/actions-languageservice", "name": "@github/actions-languageservice",
"version": "0.1.157", "version": "0.1.159",
"description": "Language service for GitHub Actions", "description": "Language service for GitHub Actions",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
@@ -39,8 +39,8 @@
"watch": "tsc --build tsconfig.build.json --watch" "watch": "tsc --build tsconfig.build.json --watch"
}, },
"dependencies": { "dependencies": {
"@github/actions-expressions": "^0.1.157", "@github/actions-expressions": "^0.1.159",
"@github/actions-workflow-parser": "^0.1.157", "@github/actions-workflow-parser": "^0.1.159",
"vscode-languageserver-textdocument": "^1.0.7", "vscode-languageserver-textdocument": "^1.0.7",
"vscode-languageserver-types": "^3.17.2", "vscode-languageserver-types": "^3.17.2",
"yaml": "^2.1.1" "yaml": "^2.1.1"
@@ -5,7 +5,7 @@ import {testFileProvider} from "./test-utils/test-file-provider";
function mapResult(result: CompletionItem[]) { function mapResult(result: CompletionItem[]) {
return result.map(x => { return result.map(x => {
return {label: x.label, description: (x.documentation as MarkupContent).value}; return {label: x.label, description: (x.documentation as MarkupContent)?.value};
}); });
} }
@@ -24,6 +24,9 @@ jobs:
expect(result).not.toBeUndefined(); expect(result).not.toBeUndefined();
expect(mapResult(result)).toEqual([ expect(mapResult(result)).toEqual([
{
label: "key"
},
{ {
label: "name", label: "name",
description: "An optional name" description: "An optional name"
@@ -50,10 +53,77 @@ jobs:
expect(result).not.toBeUndefined(); expect(result).not.toBeUndefined();
expect(mapResult(result)).toEqual([ expect(mapResult(result)).toEqual([
{
label: "key"
},
{ {
label: "name", label: "name",
description: "An optional name" description: "An optional name"
} }
]); ]);
}); });
it("completes job secrets", async () => {
const input = `
on: push
jobs:
build:
uses: ./reusable-workflow-with-inputs.yaml
secrets:
|
`;
const result = await complete(...getPositionFromCursor(input), {fileProvider: testFileProvider});
expect(result).not.toBeUndefined();
// includes inherit since no secrets have been passed in
expect(mapResult(result)).toEqual([
{
label: "envPAT",
description: "A secret for the environment"
},
{
label: "inherit"
},
{
label: "serverPAT"
}
]);
});
it("completes inherit secrets", async () => {
const input = `
on: push
jobs:
build:
uses: ./reusable-workflow-with-inputs.yaml
secrets: |
`;
const result = await complete(...getPositionFromCursor(input), {fileProvider: testFileProvider});
expect(result).not.toBeUndefined();
expect(mapResult(result)).toContainEqual({label: "inherit"});
});
it("filters existing secrets", async () => {
const input = `
on: push
jobs:
build:
uses: ./reusable-workflow-with-inputs.yaml
secrets:
envPAT: "myPAT"
|
`;
const result = await complete(...getPositionFromCursor(input), {fileProvider: testFileProvider});
expect(result).not.toBeUndefined();
expect(mapResult(result)).toEqual([
{
label: "serverPAT"
}
]);
});
}); });
+5 -5
View File
@@ -27,7 +27,7 @@ import {findToken} from "./utils/find-token";
import {guessIndentation} from "./utils/indentation-guesser"; import {guessIndentation} from "./utils/indentation-guesser";
import {mapRange} from "./utils/range"; import {mapRange} from "./utils/range";
import {getRelCharOffset} from "./utils/rel-char-pos"; import {getRelCharOffset} from "./utils/rel-char-pos";
import {transform} from "./utils/transform"; import {isPlaceholder, transform} from "./utils/transform";
import {Value, ValueProviderConfig} from "./value-providers/config"; import {Value, ValueProviderConfig} from "./value-providers/config";
import {defaultValueProviders} from "./value-providers/default"; import {defaultValueProviders} from "./value-providers/default";
import {definitionValues} from "./value-providers/definition"; import {definitionValues} from "./value-providers/definition";
@@ -160,7 +160,7 @@ async function getValues(
const customValueProvider = const customValueProvider =
valueProviderToken?.definition?.key && valueProviderConfig?.[valueProviderToken.definition.key]; valueProviderToken?.definition?.key && valueProviderConfig?.[valueProviderToken.definition.key];
if (customValueProvider) { if (customValueProvider) {
const customValues = await customValueProvider.get(workflowContext); const customValues = await customValueProvider.get(workflowContext, existingValues);
if (customValues) { if (customValues) {
return filterAndSortCompletionOptions(customValues, existingValues); return filterAndSortCompletionOptions(customValues, existingValues);
} }
@@ -169,7 +169,7 @@ async function getValues(
const defaultValueProvider = const defaultValueProvider =
valueProviderToken?.definition?.key && defaultValueProviders[valueProviderToken.definition.key]; valueProviderToken?.definition?.key && defaultValueProviders[valueProviderToken.definition.key];
if (defaultValueProvider) { if (defaultValueProvider) {
const values = await defaultValueProvider.get(workflowContext); const values = await defaultValueProvider.get(workflowContext, existingValues);
return filterAndSortCompletionOptions(values, existingValues); return filterAndSortCompletionOptions(values, existingValues);
} }
@@ -209,8 +209,8 @@ export function getExistingValues(token: TemplateToken | null, parent: TemplateT
const mapKeys = new Set<string>(); const mapKeys = new Set<string>();
const mapToken = parent as MappingToken; const mapToken = parent as MappingToken;
for (const {key} of mapToken) { for (const {key, value} of mapToken) {
if (isString(key)) { if (isString(key) && !isPlaceholder(key, value)) {
mapKeys.add(key.value); mapKeys.add(key.value);
} }
} }
@@ -59,6 +59,13 @@ on:
description: 'An optional name' description: 'An optional name'
required: false required: false
type: string type: string
key:
type: string
secrets:
envPAT:
required: true
description: 'A secret for the environment'
serverPAT:
jobs: jobs:
build: build:
+12
View File
@@ -1,3 +1,6 @@
import {isString} from "@github/actions-workflow-parser";
import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token";
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token";
import {Position, TextDocument} from "vscode-languageserver-textdocument"; import {Position, TextDocument} from "vscode-languageserver-textdocument";
import {Range} from "vscode-languageserver-types"; import {Range} from "vscode-languageserver-types";
@@ -72,3 +75,12 @@ export function transform(doc: TextDocument, pos: Position): [TextDocument, Posi
return [newDoc, newDoc.positionAt(offset)]; return [newDoc, newDoc.positionAt(offset)];
} }
// Detect placeholder key and value added by transform
export function isPlaceholder(key: StringToken, value: TemplateToken) {
if (key.value === PLACEHOLDER_KEY && isString(value) && value.value == "") {
return true;
}
return false;
}
@@ -98,6 +98,8 @@ on: push
jobs: jobs:
build: build:
uses: ./reusable-workflow-with-inputs.yaml uses: ./reusable-workflow-with-inputs.yaml
secrets:
envPAT: pat
`; `;
const result = await validate(createDocument("wf.yaml", input), { const result = await validate(createDocument("wf.yaml", input), {
fileProvider: testFileProvider fileProvider: testFileProvider
@@ -129,6 +131,8 @@ jobs:
uses: ./reusable-workflow-with-inputs.yaml uses: ./reusable-workflow-with-inputs.yaml
with: with:
username: monalisa username: monalisa
secrets:
envPAT: pat
`; `;
const result = await validate(createDocument("wf.yaml", input), { const result = await validate(createDocument("wf.yaml", input), {
fileProvider: testFileProvider fileProvider: testFileProvider
@@ -21,7 +21,7 @@ export enum ValueProviderKind {
export type ValueProvider = { export type ValueProvider = {
kind: ValueProviderKind; kind: ValueProviderKind;
get: (context: WorkflowContext) => Promise<Value[]>; get: (context: WorkflowContext, existingValues?: Set<string>) => Promise<Value[]>;
}; };
export interface ValueProviderConfig { export interface ValueProviderConfig {
@@ -2,6 +2,7 @@ import {WorkflowContext} from "../context/workflow-context";
import {ValueProviderConfig, ValueProviderKind} from "./config"; import {ValueProviderConfig, ValueProviderKind} from "./config";
import {needs} from "./needs"; import {needs} from "./needs";
import {reusableJobInputs} from "./reusable-job-inputs"; import {reusableJobInputs} from "./reusable-job-inputs";
import {reusableJobSecrets} from "./reusable-job-secrets";
import {stringsToValues} from "./strings-to-values"; import {stringsToValues} from "./strings-to-values";
export const DEFAULT_RUNNER_LABELS = [ export const DEFAULT_RUNNER_LABELS = [
@@ -28,6 +29,10 @@ export const defaultValueProviders: ValueProviderConfig = {
kind: ValueProviderKind.AllowedValues, kind: ValueProviderKind.AllowedValues,
get: async context => reusableJobInputs(context) get: async context => reusableJobInputs(context)
}, },
"workflow-job-secrets": {
kind: ValueProviderKind.SuggestedValues,
get: async (context, existingValues) => reusableJobSecrets(context, existingValues)
},
"runs-on": { "runs-on": {
kind: ValueProviderKind.SuggestedValues, kind: ValueProviderKind.SuggestedValues,
get: async (_: WorkflowContext) => stringsToValues(DEFAULT_RUNNER_LABELS) get: async (_: WorkflowContext) => stringsToValues(DEFAULT_RUNNER_LABELS)
@@ -19,7 +19,8 @@ export function reusableJobInputs(context: WorkflowContext): Value[] {
values.push({ values.push({
label: key.value, label: key.value,
description: inputDescription(value) description: inputDescription(value),
insertText: `${key.value}: `
}); });
} }
@@ -0,0 +1,53 @@
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token";
import {isMapping, isString} from "@github/actions-workflow-parser/templates/tokens/type-guards";
import {WorkflowContext} from "../context/workflow-context";
import {Value} from "./config";
export function reusableJobSecrets(context: WorkflowContext, existingValues?: Set<string>): Value[] {
if (!context.reusableWorkflowJob) {
return [];
}
const values: Value[] = [];
const inheritSecrets = context.reusableWorkflowJob["inherit-secrets"];
if (inheritSecrets) {
return values;
}
// Suggest inherit if no other secrets have been set
if (!existingValues || existingValues.size === 0) {
values.push({
label: "inherit"
});
}
if (context.reusableWorkflowJob?.["secret-definitions"]) {
for (const {key, value} of context.reusableWorkflowJob["secret-definitions"]) {
if (!isString(key)) {
continue;
}
values.push({
label: key.value,
description: secretDescription(value),
insertText: `${key.value}: `
});
}
}
return values;
}
function secretDescription(secretDef: TemplateToken): string | undefined {
if (!isMapping(secretDef)) {
return "";
}
const descriptionToken = secretDef.find("description");
if (!descriptionToken || !isString(descriptionToken)) {
return "";
}
return descriptionToken.value;
}
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"$schema": "node_modules/lerna/schemas/lerna-schema.json", "$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": true, "useWorkspaces": true,
"version": "0.1.157" "version": "0.1.159"
} }
+17 -17
View File
@@ -111,10 +111,10 @@
} }
}, },
"browser-playground": { "browser-playground": {
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@github/actions-languageserver": "^0.1.157", "@github/actions-languageserver": "^0.1.159",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2", "monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "^4.0.3", "monaco-languageclient": "^4.0.3",
@@ -135,7 +135,7 @@
}, },
"expressions": { "expressions": {
"name": "@github/actions-expressions", "name": "@github/actions-expressions",
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@types/jest": "^29.0.3", "@types/jest": "^29.0.3",
@@ -151,11 +151,11 @@
}, },
"languageserver": { "languageserver": {
"name": "@github/actions-languageserver", "name": "@github/actions-languageserver",
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@github/actions-languageservice": "^0.1.157", "@github/actions-languageservice": "^0.1.159",
"@github/actions-workflow-parser": "^0.1.157", "@github/actions-workflow-parser": "^0.1.159",
"@octokit/rest": "^19.0.7", "@octokit/rest": "^19.0.7",
"vscode-languageserver": "^8.0.2", "vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.7", "vscode-languageserver-textdocument": "^1.0.7",
@@ -176,11 +176,11 @@
}, },
"languageservice": { "languageservice": {
"name": "@github/actions-languageservice", "name": "@github/actions-languageservice",
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@github/actions-expressions": "^0.1.157", "@github/actions-expressions": "^0.1.159",
"@github/actions-workflow-parser": "^0.1.157", "@github/actions-workflow-parser": "^0.1.159",
"vscode-languageserver-textdocument": "^1.0.7", "vscode-languageserver-textdocument": "^1.0.7",
"vscode-languageserver-types": "^3.17.2", "vscode-languageserver-types": "^3.17.2",
"yaml": "^2.1.1" "yaml": "^2.1.1"
@@ -14265,10 +14265,10 @@
}, },
"workflow-parser": { "workflow-parser": {
"name": "@github/actions-workflow-parser", "name": "@github/actions-workflow-parser",
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@github/actions-expressions": "^0.1.157", "@github/actions-expressions": "^0.1.159",
"cronstrue": "^2.21.0", "cronstrue": "^2.21.0",
"yaml": "^2.0.0-8" "yaml": "^2.0.0-8"
}, },
@@ -14827,8 +14827,8 @@
"@github/actions-languageserver": { "@github/actions-languageserver": {
"version": "file:languageserver", "version": "file:languageserver",
"requires": { "requires": {
"@github/actions-languageservice": "^0.1.157", "@github/actions-languageservice": "^0.1.159",
"@github/actions-workflow-parser": "^0.1.157", "@github/actions-workflow-parser": "^0.1.159",
"@octokit/rest": "^19.0.7", "@octokit/rest": "^19.0.7",
"@types/jest": "^29.0.3", "@types/jest": "^29.0.3",
"fetch-mock": "^9.11.0", "fetch-mock": "^9.11.0",
@@ -14845,8 +14845,8 @@
"@github/actions-languageservice": { "@github/actions-languageservice": {
"version": "file:languageservice", "version": "file:languageservice",
"requires": { "requires": {
"@github/actions-expressions": "^0.1.157", "@github/actions-expressions": "^0.1.159",
"@github/actions-workflow-parser": "^0.1.157", "@github/actions-workflow-parser": "^0.1.159",
"@types/jest": "^29.0.3", "@types/jest": "^29.0.3",
"jest": "^29.0.3", "jest": "^29.0.3",
"prettier": "^2.8.3", "prettier": "^2.8.3",
@@ -14863,7 +14863,7 @@
"@github/actions-workflow-parser": { "@github/actions-workflow-parser": {
"version": "file:workflow-parser", "version": "file:workflow-parser",
"requires": { "requires": {
"@github/actions-expressions": "^0.1.157", "@github/actions-expressions": "^0.1.159",
"@types/jest": "^29.0.3", "@types/jest": "^29.0.3",
"@typescript-eslint/eslint-plugin": "^5.40.0", "@typescript-eslint/eslint-plugin": "^5.40.0",
"@typescript-eslint/parser": "^5.40.0", "@typescript-eslint/parser": "^5.40.0",
@@ -17857,7 +17857,7 @@
"browser-playground": { "browser-playground": {
"version": "file:browser-playground", "version": "file:browser-playground",
"requires": { "requires": {
"@github/actions-languageserver": "^0.1.157", "@github/actions-languageserver": "^0.1.159",
"css-loader": "^6.7.2", "css-loader": "^6.7.2",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2", "monaco-editor-workers": "^0.34.2",
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@github/actions-workflow-parser", "name": "@github/actions-workflow-parser",
"version": "0.1.157", "version": "0.1.159",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
"source": "./src/index.ts", "source": "./src/index.ts",
@@ -40,7 +40,7 @@
"watch": "tsc --build tsconfig.build.json --watch" "watch": "tsc --build tsconfig.build.json --watch"
}, },
"dependencies": { "dependencies": {
"@github/actions-expressions": "^0.1.157", "@github/actions-expressions": "^0.1.159",
"cronstrue": "^2.21.0", "cronstrue": "^2.21.0",
"yaml": "^2.0.0-8" "yaml": "^2.0.0-8"
}, },
+14 -5
View File
@@ -1,6 +1,6 @@
import {TemplateContext} from "../../templates/template-context"; import {TemplateContext} from "../../templates/template-context";
import {BasicExpressionToken, MappingToken, ScalarToken, StringToken, TemplateToken} from "../../templates/tokens"; import {BasicExpressionToken, MappingToken, ScalarToken, StringToken, TemplateToken} from "../../templates/tokens";
import {isSequence, isString} from "../../templates/tokens/type-guards"; import {isMapping, isSequence, isString} from "../../templates/tokens/type-guards";
import {Step, WorkflowJob} from "../workflow-template"; import {Step, WorkflowJob} from "../workflow-template";
import {convertConcurrency} from "./concurrency"; import {convertConcurrency} from "./concurrency";
import {convertToJobContainer, convertToJobServices} from "./container"; import {convertToJobContainer, convertToJobServices} from "./container";
@@ -38,7 +38,9 @@ export function convertJob(context: TemplateContext, jobKey: StringToken, token:
break; break;
case "env": case "env":
env = item.value.assertMapping("job env"); handleTemplateTokenErrors(item.value, context, undefined, () => {
env = item.value.assertMapping("job env");
});
break; break;
case "environment": case "environment":
@@ -69,7 +71,9 @@ export function convertJob(context: TemplateContext, jobKey: StringToken, token:
} }
case "outputs": case "outputs":
outputs = item.value.assertMapping("job outputs"); handleTemplateTokenErrors(item.value, context, undefined, () => {
outputs = item.value.assertMapping("job outputs");
});
break; break;
case "runs-on": case "runs-on":
@@ -95,14 +99,19 @@ export function convertJob(context: TemplateContext, jobKey: StringToken, token:
break; break;
case "with": case "with":
workflowJobInputs = item.value.assertMapping("uses-with value"); handleTemplateTokenErrors(item.value, context, undefined, () => {
workflowJobInputs = item.value.assertMapping("uses-with value");
});
break; break;
case "secrets": case "secrets":
if (isString(item.value) && item.value.value === "inherit") { if (isString(item.value) && item.value.value === "inherit") {
inheritSecrets = true; inheritSecrets = true;
} else { } else {
workflowJobSecrets = item.value.assertMapping("uses-secrets value"); handleTemplateTokenErrors(item.value, context, undefined, () => {
workflowJobSecrets = item.value.assertMapping("uses-secrets value");
});
} }
break;
} }
} }