Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ee228549a | ||
|
|
45a665690b | ||
|
|
0a9f420c96 |
+1
-1
@@ -1 +1 @@
|
|||||||
* @actions/actions-workflow-development-reviewers
|
* @actions/actions-experience
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
name: Create release PR
|
name: Create release PR
|
||||||
|
|
||||||
run-name: Create release PR for new ${{ github.event.inputs.version }} version
|
run-name: Create release PR for v${{ github.event.inputs.version }}
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
required: true
|
required: true
|
||||||
type: choice
|
description: "Version to bump `package.json` to (format: x.y.z)"
|
||||||
description: "What type of release is this"
|
|
||||||
options:
|
|
||||||
- "major"
|
|
||||||
- "minor"
|
|
||||||
- "patch"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-release-pr:
|
create-release-pr:
|
||||||
@@ -36,27 +31,21 @@ jobs:
|
|||||||
git config --global user.email "[email protected]"
|
git config --global user.email "[email protected]"
|
||||||
git config --global user.name "GitHub Actions"
|
git config --global user.name "GitHub Actions"
|
||||||
|
|
||||||
NEW_VERSION=$(./script/workflows/increment-version.sh ${{ inputs.version }})
|
git checkout -b release/${{ inputs.version }}
|
||||||
|
|
||||||
git checkout -b release/$NEW_VERSION
|
npx lerna version ${{ inputs.version }} --yes --no-push --no-git-tag-version --force-publish
|
||||||
|
|
||||||
npx lerna version $NEW_VERSION --yes --no-push --no-git-tag-version --force-publish
|
|
||||||
|
|
||||||
git add **/package.json package-lock.json lerna.json
|
git add **/package.json package-lock.json lerna.json
|
||||||
git commit -m "Release extension version $NEW_VERSION"
|
git commit -m "Release extension version ${{ inputs.version }}"
|
||||||
|
|
||||||
git push --set-upstream origin release/$NEW_VERSION
|
git push --set-upstream origin release/${{ inputs.version }}
|
||||||
|
|
||||||
echo "new_version=$NEW_VERSION" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Create PR
|
- name: Create PR
|
||||||
run: |
|
run: |
|
||||||
LAST_PR=$(gh pr list --repo ${{ github.repository }} --limit 1 --state merged --search "Release version" --json number | jq -r '.[0].number')
|
|
||||||
./script/workflows/generate-release-notes.sh $LAST_PR ${{ env.new_version }}
|
|
||||||
gh pr create \
|
gh pr create \
|
||||||
--title "Release version ${{ env.new_version }}" \
|
--title "Release version ${{ inputs.version }}" \
|
||||||
--body-file releasenotes.md \
|
--body "Release version ${{ inputs.version }}" \
|
||||||
--base main \
|
--base main \
|
||||||
--head release/${{ env.new_version }}
|
--head release/${{ inputs.version }}
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
*/node_modules
|
*/node_modules
|
||||||
*/dist
|
*/dist
|
||||||
lerna-debug.log
|
|
||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
+1
-9
@@ -8,8 +8,6 @@ Hi there! We're thrilled that you'd like to contribute to this project. Your hel
|
|||||||
|
|
||||||
We accept pull requests for bug fixes and features where we've discussed the approach in an issue and given the go-ahead for a community member to work on it. We'd also love to hear about ideas for new features as issues.
|
We accept pull requests for bug fixes and features where we've discussed the approach in an issue and given the go-ahead for a community member to work on it. We'd also love to hear about ideas for new features as issues.
|
||||||
|
|
||||||
We track issues on our project board [here](https://github.com/orgs/github/projects/9557/views/1).
|
|
||||||
|
|
||||||
Please do:
|
Please do:
|
||||||
|
|
||||||
* Check existing issues to verify that the [bug][bug issues] or [feature request][feature request issues] has not already been submitted.
|
* Check existing issues to verify that the [bug][bug issues] or [feature request][feature request issues] has not already been submitted.
|
||||||
@@ -23,7 +21,7 @@ Please avoid:
|
|||||||
|
|
||||||
* Opening pull requests for issues marked `needs-design`, `needs-investigation`, or `blocked`.
|
* Opening pull requests for issues marked `needs-design`, `needs-investigation`, or `blocked`.
|
||||||
|
|
||||||
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
|
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE.md).
|
||||||
|
|
||||||
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
|
Please note that this project is released with a [Contributor Code of Conduct][code-of-conduct]. By participating in this project you agree to abide by its terms.
|
||||||
|
|
||||||
@@ -63,9 +61,3 @@ Please also look at the `README.md` files for each package for additional notes
|
|||||||
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
|
||||||
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
- [Using Pull Requests](https://help.github.com/articles/about-pull-requests/)
|
||||||
- [GitHub Help](https://help.github.com)
|
- [GitHub Help](https://help.github.com)
|
||||||
|
|
||||||
|
|
||||||
[bug issues]: https://github.com/actions/languageservices/labels/bug
|
|
||||||
[feature request issues]: https://github.com/actions/languageservices/labels/enhancement
|
|
||||||
[hw]: https://github.com/actions/languageservices/labels/help%20wanted
|
|
||||||
[gfi]: https://github.com/actions/languageservices/labels/good%20first%20issue
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/expressions",
|
"name": "@actions/expressions",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"source": "./src/index.ts",
|
"source": "./src/index.ts",
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class Evaluator implements ExprVisitor<data.ExpressionData> {
|
|||||||
return this.eval(this.n);
|
return this.eval(this.n);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected eval(n: Expr): data.ExpressionData {
|
private eval(n: Expr): data.ExpressionData {
|
||||||
return n.accept(this);
|
return n.accept(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/languageserver",
|
"name": "@actions/languageserver",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"description": "Language server for GitHub Actions",
|
"description": "Language server for GitHub Actions",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -43,8 +43,8 @@
|
|||||||
"watch": "tsc --build tsconfig.build.json --watch"
|
"watch": "tsc --build tsconfig.build.json --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/languageservice": "^0.3.9",
|
"@actions/languageservice": "^0.3.1",
|
||||||
"@actions/workflow-parser": "^0.3.9",
|
"@actions/workflow-parser": "^0.3.1",
|
||||||
"@octokit/rest": "^19.0.7",
|
"@octokit/rest": "^19.0.7",
|
||||||
"@octokit/types": "^9.0.0",
|
"@octokit/types": "^9.0.0",
|
||||||
"vscode-languageserver": "^8.0.2",
|
"vscode-languageserver": "^8.0.2",
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import {Octokit} from "@octokit/rest";
|
import {Octokit} from "@octokit/rest";
|
||||||
|
|
||||||
export function getClient(token: string, userAgent?: string, apiUrl?: string): Octokit {
|
export function getClient(token: string, userAgent?: string): Octokit {
|
||||||
return new Octokit({
|
return new Octokit({
|
||||||
auth: token,
|
auth: token,
|
||||||
userAgent: userAgent || `GitHub Actions Language Server`,
|
userAgent: userAgent || `GitHub Actions Language Server`
|
||||||
baseUrl: apiUrl
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export function initConnection(connection: Connection) {
|
|||||||
const options = params.initializationOptions as InitializationOptions;
|
const options = params.initializationOptions as InitializationOptions;
|
||||||
|
|
||||||
if (options.sessionToken) {
|
if (options.sessionToken) {
|
||||||
client = getClient(options.sessionToken, options.userAgent, options.gitHubApiUrl);
|
client = getClient(options.sessionToken, options.userAgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.repos) {
|
if (options.repos) {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ export async function getSecrets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const eventsConfig = workflowContext?.template?.events;
|
const eventsConfig = workflowContext?.template?.events;
|
||||||
|
|
||||||
if (eventsConfig?.workflow_call) {
|
if (eventsConfig?.workflow_call) {
|
||||||
// Unpredictable secrets may be passed in via a workflow_call trigger
|
// Unpredictable secrets may be passed in via a workflow_call trigger
|
||||||
secretsContext.complete = false;
|
secretsContext.complete = false;
|
||||||
@@ -39,7 +38,6 @@ export async function getSecrets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
||||||
environmentName = workflowContext.job.environment.value;
|
environmentName = workflowContext.job.environment.value;
|
||||||
@@ -48,17 +46,10 @@ export async function getSecrets(
|
|||||||
if (isString(x.key) && x.key.value === "name") {
|
if (isString(x.key) && x.key.value === "name") {
|
||||||
if (isString(x.value)) {
|
if (isString(x.value)) {
|
||||||
environmentName = x.value.value;
|
environmentName = x.value.value;
|
||||||
} else {
|
|
||||||
// this means we have a dynamic enviornment, in those situations we
|
|
||||||
// want to make sure we skip doing secret validation
|
|
||||||
secretsContext.complete = false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// if the expression is something like environment: ${{ ... }} then we want to skip validation
|
|
||||||
secretsContext.complete = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ import {data, DescriptionDictionary} from "@actions/expressions";
|
|||||||
import {Pair} from "@actions/expressions/data/expressiondata";
|
import {Pair} from "@actions/expressions/data/expressiondata";
|
||||||
import {StringData} from "@actions/expressions/data/index";
|
import {StringData} from "@actions/expressions/data/index";
|
||||||
import {WorkflowContext} from "@actions/languageservice/context/workflow-context";
|
import {WorkflowContext} from "@actions/languageservice/context/workflow-context";
|
||||||
import {log, warn} from "@actions/languageservice/log";
|
import {warn} from "@actions/languageservice/log";
|
||||||
import {isMapping, isString} from "@actions/workflow-parser";
|
import {isMapping, isString} from "@actions/workflow-parser";
|
||||||
import {Octokit} from "@octokit/rest";
|
import {Octokit} from "@octokit/rest";
|
||||||
import {RequestError} from "@octokit/request-error";
|
|
||||||
|
|
||||||
import {RepositoryContext} from "../initializationOptions";
|
import {RepositoryContext} from "../initializationOptions";
|
||||||
import {TTLCache} from "../utils/cache";
|
import {TTLCache} from "../utils/cache";
|
||||||
@@ -43,58 +42,50 @@ 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 =>
|
variables.organizationVariables.forEach(variable =>
|
||||||
variablesMap.set(variable.key.toLowerCase(), {
|
variablesMap.set(variable.key.toLowerCase(), {
|
||||||
key: variable.key,
|
key: variable.key,
|
||||||
value: new data.StringData(variable.value.coerceString()),
|
value: new data.StringData(variable.value.coerceString()),
|
||||||
description: `${variable.value.coerceString()} - Organization variable`
|
description: `${variable.value.coerceString()} - Organization variable`
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Override org variables with repo variables
|
// Override org variables with repo variables
|
||||||
variables.repoVariables.forEach(variable =>
|
variables.repoVariables.forEach(variable =>
|
||||||
variablesMap.set(variable.key.toLowerCase(), {
|
variablesMap.set(variable.key.toLowerCase(), {
|
||||||
key: variable.key,
|
key: variable.key,
|
||||||
value: new data.StringData(variable.value.coerceString()),
|
value: new data.StringData(variable.value.coerceString()),
|
||||||
description: `${variable.value.coerceString()} - Repository variable`
|
description: `${variable.value.coerceString()} - Repository variable`
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Override repo variables with environment veriables (if defined)
|
// Override repo variables with environment veriables (if defined)
|
||||||
variables.environmentVariables.forEach(variable =>
|
variables.environmentVariables.forEach(variable =>
|
||||||
variablesMap.set(variable.key.toLowerCase(), {
|
variablesMap.set(variable.key.toLowerCase(), {
|
||||||
key: variable.key,
|
key: variable.key,
|
||||||
value: new data.StringData(variable.value.coerceString()),
|
value: new data.StringData(variable.value.coerceString()),
|
||||||
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName || ""}\``
|
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName || ""}\``
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// Sort variables by key and add to context
|
// Sort variables by key and add to context
|
||||||
Array.from(variablesMap.values())
|
Array.from(variablesMap.values())
|
||||||
.sort((a, b) => a.key.localeCompare(b.key))
|
.sort((a, b) => a.key.localeCompare(b.key))
|
||||||
.forEach(variable => variablesContext?.add(variable.key, variable.value, variable.description));
|
.forEach(variable => variablesContext?.add(variable.key, variable.value, variable.description));
|
||||||
|
|
||||||
return variablesContext;
|
return variablesContext;
|
||||||
} catch (e) {
|
|
||||||
if (!(e instanceof RequestError)) throw e;
|
|
||||||
if (e.name == "HttpError" && e.status == 404) {
|
|
||||||
log("Failure to request variables. Ignore if you're using GitHub Enterprise Server below version 3.8");
|
|
||||||
return variablesContext;
|
|
||||||
} else throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRemoteVariables(
|
export async function getRemoteVariables(
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import {File} from "@actions/workflow-parser/workflows/file";
|
|||||||
import {FileProvider} from "@actions/workflow-parser/workflows/file-provider";
|
import {FileProvider} from "@actions/workflow-parser/workflows/file-provider";
|
||||||
import {fileIdentifier} from "@actions/workflow-parser/workflows/file-reference";
|
import {fileIdentifier} from "@actions/workflow-parser/workflows/file-reference";
|
||||||
import {Octokit} from "@octokit/rest";
|
import {Octokit} from "@octokit/rest";
|
||||||
|
import path from "path";
|
||||||
import {TTLCache} from "./utils/cache";
|
import {TTLCache} from "./utils/cache";
|
||||||
import vscodeURI from "vscode-uri/lib/umd";
|
|
||||||
|
|
||||||
export function getFileProvider(
|
export function getFileProvider(
|
||||||
client: Octokit | undefined,
|
client: Octokit | undefined,
|
||||||
@@ -31,10 +31,7 @@ export function getFileProvider(
|
|||||||
throw new Error("Local file references are not supported with this configuration");
|
throw new Error("Local file references are not supported with this configuration");
|
||||||
}
|
}
|
||||||
|
|
||||||
const workspaceURI = vscodeURI.URI.parse(workspace);
|
const file = await readFile(path.join(workspace, ref.path));
|
||||||
const refURI = vscodeURI.Utils.joinPath(workspaceURI, ref.path);
|
|
||||||
const file = await readFile(refURI.toString());
|
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new Error(`File not found: ${ref.path}`);
|
throw new Error(`File not found: ${ref.path}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ export interface InitializationOptions {
|
|||||||
* Desired log level
|
* Desired log level
|
||||||
*/
|
*/
|
||||||
logLevel?: LogLevel;
|
logLevel?: LogLevel;
|
||||||
|
|
||||||
/**
|
|
||||||
* If a GitHub Enterprise Server should be used, the URL of the API endpoint, eg "https://ghe.my-company.com/api/v3"
|
|
||||||
*/
|
|
||||||
gitHubApiUrl?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RepositoryContext {
|
export interface RepositoryContext {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/languageservice",
|
"name": "@actions/languageservice",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"description": "Language service for GitHub Actions",
|
"description": "Language service for GitHub Actions",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
"watch": "tsc --build tsconfig.build.json --watch"
|
"watch": "tsc --build tsconfig.build.json --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/expressions": "^0.3.9",
|
"@actions/expressions": "^0.3.1",
|
||||||
"@actions/workflow-parser": "^0.3.9",
|
"@actions/workflow-parser": "^0.3.1",
|
||||||
"vscode-languageserver-textdocument": "^1.0.7",
|
"vscode-languageserver-textdocument": "^1.0.7",
|
||||||
"vscode-languageserver-types": "^3.17.2",
|
"vscode-languageserver-types": "^3.17.2",
|
||||||
"vscode-uri": "^3.0.7",
|
"vscode-uri": "^3.0.7",
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import {complete} from "./complete";
|
|||||||
import {registerLogger} from "./log";
|
import {registerLogger} from "./log";
|
||||||
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
||||||
import {TestLogger} from "./test-utils/logger";
|
import {TestLogger} from "./test-utils/logger";
|
||||||
import {clearCache} from "./utils/workflow-cache";
|
|
||||||
import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
|
import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
|
||||||
|
import {clearCache} from "./utils/workflow-cache";
|
||||||
|
|
||||||
registerLogger(new TestLogger());
|
registerLogger(new TestLogger());
|
||||||
|
|
||||||
@@ -406,7 +406,7 @@ jobs:
|
|||||||
expect(result.map(e => e.label)).toContain("runs-on");
|
expect(result.map(e => e.label)).toContain("runs-on");
|
||||||
|
|
||||||
const textEdit = result.filter(e => e.label === "runs-on")[0].textEdit as TextEdit;
|
const textEdit = result.filter(e => e.label === "runs-on")[0].textEdit as TextEdit;
|
||||||
expect(textEdit.newText).toEqual("runs-on: ");
|
expect(textEdit.newText).toEqual("runs-on");
|
||||||
expect(textEdit.range).toEqual({
|
expect(textEdit.range).toEqual({
|
||||||
start: {line: 3, character: 4},
|
start: {line: 3, character: 4},
|
||||||
end: {line: 3, character: 10}
|
end: {line: 3, character: 10}
|
||||||
@@ -421,7 +421,7 @@ jobs:
|
|||||||
expect(result.map(e => e.label)).toContain("runs-on");
|
expect(result.map(e => e.label)).toContain("runs-on");
|
||||||
|
|
||||||
const textEdit = result.filter(e => e.label === "runs-on")[0].textEdit as TextEdit;
|
const textEdit = result.filter(e => e.label === "runs-on")[0].textEdit as TextEdit;
|
||||||
expect(textEdit.newText).toEqual("runs-on: ");
|
expect(textEdit.newText).toEqual("runs-on");
|
||||||
expect(textEdit.range).toEqual({
|
expect(textEdit.range).toEqual({
|
||||||
start: {line: 3, character: 4},
|
start: {line: 3, character: 4},
|
||||||
end: {line: 3, character: 4}
|
end: {line: 3, character: 4}
|
||||||
@@ -448,7 +448,7 @@ jobs:
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// One-of
|
// One-of
|
||||||
expect(result.filter(x => x.label === "concurrency").map(x => x.textEdit?.newText)).toEqual(["concurrency: "]);
|
expect(result.filter(x => x.label === "concurrency").map(x => x.textEdit?.newText)).toEqual(["concurrency"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("custom indentation", async () => {
|
it("custom indentation", async () => {
|
||||||
@@ -471,50 +471,7 @@ jobs:
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// One-of
|
// One-of
|
||||||
expect(result.filter(x => x.label === "concurrency").map(x => x.textEdit?.newText)).toEqual(["concurrency: "]);
|
expect(result.filter(x => x.label === "concurrency").map(x => x.textEdit?.newText)).toEqual(["concurrency"]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("adds a new line and indentation for mapping keys when the key is given", async () => {
|
|
||||||
const input = "concurrency: |";
|
|
||||||
|
|
||||||
const result = await complete(...getPositionFromCursor(input));
|
|
||||||
|
|
||||||
expect(result.filter(x => x.label === "cancel-in-progress").map(x => x.textEdit?.newText)).toEqual([
|
|
||||||
"\n cancel-in-progress: "
|
|
||||||
]);
|
|
||||||
expect(result.filter(x => x.label === "group").map(x => x.textEdit?.newText)).toEqual(["\n group: "]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not add new line if no key in line", async () => {
|
|
||||||
const input = "run-n|";
|
|
||||||
|
|
||||||
const result = await complete(...getPositionFromCursor(input));
|
|
||||||
|
|
||||||
expect(result.filter(x => x.label === "run-name").map(x => x.textEdit?.newText)).toEqual(["run-name: "]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds new line for nested mapping", async () => {
|
|
||||||
const input = "on:\n workflow_dispatch: in|";
|
|
||||||
|
|
||||||
const result = await complete(...getPositionFromCursor(input));
|
|
||||||
|
|
||||||
expect(result.filter(x => x.label === "inputs").map(x => x.textEdit?.newText)).toEqual(["\n inputs:\n "]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds : for one-of", async () => {
|
|
||||||
const input = "on:\n check_run:\n ty|";
|
|
||||||
|
|
||||||
const result = await complete(...getPositionFromCursor(input));
|
|
||||||
|
|
||||||
expect(result.filter(x => x.label === "types").map(x => x.textEdit?.newText)).toEqual(["types: "]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not add : for one-of in key mode", async () => {
|
|
||||||
const input = "on:\n check_run: ty|";
|
|
||||||
|
|
||||||
const result = await complete(...getPositionFromCursor(input));
|
|
||||||
|
|
||||||
expect(result.filter(x => x.label === "types").map(x => x.textEdit?.newText)).toEqual(["types"]);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import {isPlaceholder, transform} from "./utils/transform";
|
|||||||
import {fetchOrConvertWorkflowTemplate, fetchOrParseWorkflow} from "./utils/workflow-cache";
|
import {fetchOrConvertWorkflowTemplate, fetchOrParseWorkflow} from "./utils/workflow-cache";
|
||||||
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 {DefinitionValueMode, definitionValues} from "./value-providers/definition";
|
import {definitionValues} from "./value-providers/definition";
|
||||||
|
|
||||||
export function getExpressionInput(input: string, pos: number): string {
|
export function getExpressionInput(input: string, pos: number): string {
|
||||||
// Find start marker around the cursor position
|
// Find start marker around the cursor position
|
||||||
@@ -180,7 +180,7 @@ async function getValues(
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const values = definitionValues(def, indentation, keyToken ? DefinitionValueMode.Key : DefinitionValueMode.Parent);
|
const values = definitionValues(def, indentation);
|
||||||
return filterAndSortCompletionOptions(values, existingValues);
|
return filterAndSortCompletionOptions(values, existingValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {getEventPayload, getSupportedEventTypes} from "./events/eventPayloads";
|
|||||||
import {getInputsContext} from "./inputs";
|
import {getInputsContext} from "./inputs";
|
||||||
|
|
||||||
export function getGithubContext(workflowContext: WorkflowContext, mode: Mode): DescriptionDictionary {
|
export function getGithubContext(workflowContext: WorkflowContext, mode: Mode): DescriptionDictionary {
|
||||||
// https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
|
// https://docs.github.com/en/actions/learn-github-actions/contexts#github-cwontext
|
||||||
const keys = [
|
const keys = [
|
||||||
"action",
|
"action",
|
||||||
"action_path",
|
"action_path",
|
||||||
@@ -16,7 +16,6 @@ export function getGithubContext(workflowContext: WorkflowContext, mode: Mode):
|
|||||||
"action_repository",
|
"action_repository",
|
||||||
"action_status",
|
"action_status",
|
||||||
"actor",
|
"actor",
|
||||||
"actor_id",
|
|
||||||
"api_url",
|
"api_url",
|
||||||
"base_ref",
|
"base_ref",
|
||||||
"env",
|
"env",
|
||||||
@@ -26,16 +25,13 @@ export function getGithubContext(workflowContext: WorkflowContext, mode: Mode):
|
|||||||
"graphql_url",
|
"graphql_url",
|
||||||
"head_ref",
|
"head_ref",
|
||||||
"job",
|
"job",
|
||||||
"job_workflow_sha",
|
|
||||||
"path",
|
|
||||||
"ref",
|
"ref",
|
||||||
"ref_name",
|
"ref_name",
|
||||||
"ref_protected",
|
"ref_protected",
|
||||||
"ref_type",
|
"ref_type",
|
||||||
|
"path",
|
||||||
"repository",
|
"repository",
|
||||||
"repository_id",
|
|
||||||
"repository_owner",
|
"repository_owner",
|
||||||
"repository_owner_id",
|
|
||||||
"repositoryUrl",
|
"repositoryUrl",
|
||||||
"retention_days",
|
"retention_days",
|
||||||
"run_id",
|
"run_id",
|
||||||
@@ -47,8 +43,6 @@ export function getGithubContext(workflowContext: WorkflowContext, mode: Mode):
|
|||||||
"token",
|
"token",
|
||||||
"triggering_actor",
|
"triggering_actor",
|
||||||
"workflow",
|
"workflow",
|
||||||
"workflow_ref",
|
|
||||||
"workflow_sha",
|
|
||||||
"workspace"
|
"workspace"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import {data, isDescriptionDictionary} from "@actions/expressions";
|
|
||||||
import {isDictionary} from "@actions/expressions/data/dictionary";
|
|
||||||
import {ExpressionData, Pair} from "@actions/expressions/data/expressiondata";
|
|
||||||
|
|
||||||
export class AccessError extends Error {
|
|
||||||
constructor(message: string, public readonly keyName: string) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ErrorDictionary extends data.Dictionary {
|
|
||||||
constructor(...pairs: Pair[]) {
|
|
||||||
super(...pairs);
|
|
||||||
}
|
|
||||||
public complete = true;
|
|
||||||
|
|
||||||
get(key: string): ExpressionData | undefined {
|
|
||||||
const value = super.get(key);
|
|
||||||
if (value) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.complete) {
|
|
||||||
throw new AccessError(`Invalid context access: ${key}`, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function wrapDictionary(d: data.Dictionary): ErrorDictionary {
|
|
||||||
const e = new ErrorDictionary();
|
|
||||||
if (isDescriptionDictionary(d)) {
|
|
||||||
e.complete = d.complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const {key, value} of d.pairs()) {
|
|
||||||
if (isDictionary(value)) {
|
|
||||||
e.add(key, wrapDictionary(value));
|
|
||||||
} else {
|
|
||||||
e.add(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
import {Evaluator, ExpressionEvaluationError, data} from "@actions/expressions";
|
|
||||||
import {Expr, Logical} from "@actions/expressions/ast";
|
|
||||||
import {ExpressionData} from "@actions/expressions/data/expressiondata";
|
|
||||||
import {TokenType} from "@actions/expressions/lexer";
|
|
||||||
import {falsy, truthy} from "@actions/expressions/result";
|
|
||||||
import {AccessError} from "./error-dictionary";
|
|
||||||
|
|
||||||
export type ValidationError = {
|
|
||||||
message: string;
|
|
||||||
severity: "error" | "warning";
|
|
||||||
};
|
|
||||||
|
|
||||||
export class ValidationEvaluator extends Evaluator {
|
|
||||||
public readonly errors: ValidationError[] = [];
|
|
||||||
|
|
||||||
public validate() {
|
|
||||||
super.evaluate();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override eval(n: Expr): ExpressionData {
|
|
||||||
try {
|
|
||||||
return super.eval(n);
|
|
||||||
} catch (e) {
|
|
||||||
// Record error
|
|
||||||
if (e instanceof AccessError) {
|
|
||||||
this.errors.push({
|
|
||||||
message: `Context access might be invalid: ${e.keyName}`,
|
|
||||||
severity: "warning"
|
|
||||||
});
|
|
||||||
} else if (e instanceof ExpressionEvaluationError) {
|
|
||||||
this.errors.push({
|
|
||||||
message: `Expression might be invalid: ${e.message}`,
|
|
||||||
severity: "error"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return null but continue with the validation
|
|
||||||
return new data.Null();
|
|
||||||
}
|
|
||||||
|
|
||||||
override visitLogical(logical: Logical): ExpressionData {
|
|
||||||
let result: data.ExpressionData | undefined;
|
|
||||||
|
|
||||||
for (const arg of logical.args) {
|
|
||||||
const r = this.eval(arg);
|
|
||||||
|
|
||||||
// Simulate short-circuit behavior but continue to evalute all arguments for validation purposes
|
|
||||||
if (
|
|
||||||
!result &&
|
|
||||||
((logical.operator.type === TokenType.AND && falsy(r)) || (logical.operator.type === TokenType.OR && truthy(r)))
|
|
||||||
) {
|
|
||||||
result = r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// result is always assigned before we return here
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
||||||
return result!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
import {Lexer, Parser} from "@actions/expressions";
|
||||||
|
import {Dictionary} from "@actions/expressions/data/dictionary";
|
||||||
|
import {StringData} from "@actions/expressions/data/string";
|
||||||
|
import {splitAllowedContext} from "@actions/workflow-parser/templates/allowed-context";
|
||||||
|
import {ValidationVisitor} from "./visitor";
|
||||||
|
|
||||||
|
const testContext = new Dictionary({
|
||||||
|
key: "github",
|
||||||
|
value: new Dictionary(
|
||||||
|
{
|
||||||
|
key: "event",
|
||||||
|
value: new StringData("push")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "repo",
|
||||||
|
value: new Dictionary({
|
||||||
|
key: "name",
|
||||||
|
value: new StringData("test")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
function useVisitor(expression: string, allowedContext: string[]): any[] {
|
||||||
|
const {namedContexts, functions} = splitAllowedContext(allowedContext);
|
||||||
|
|
||||||
|
const l = new Lexer(expression);
|
||||||
|
const lr = l.lex();
|
||||||
|
|
||||||
|
const p = new Parser(lr.tokens, namedContexts, functions);
|
||||||
|
const expr = p.parse();
|
||||||
|
|
||||||
|
const e = new ValidationVisitor(expr, testContext);
|
||||||
|
e.validate();
|
||||||
|
|
||||||
|
return e.errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("validation visitor", () => {
|
||||||
|
it("invalid context access", () => {
|
||||||
|
expect(useVisitor("github.foo", ["github"])).toEqual([
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: foo",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
column: 10,
|
||||||
|
line: 0
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
column: 0,
|
||||||
|
line: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: "warning"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("invalid context access as index", () => {
|
||||||
|
expect(useVisitor("github[github.foo]", ["github"])).toEqual([
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: foo",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
column: 17,
|
||||||
|
line: 0
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
column: 7,
|
||||||
|
line: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: "warning"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("invalid nested context access", () => {
|
||||||
|
expect(useVisitor("github.repo.name", ["github"])).toEqual([
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: name",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
column: 16,
|
||||||
|
line: 0
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
column: 0,
|
||||||
|
line: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: "warning"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("invalid context accesses", () => {
|
||||||
|
expect(useVisitor("github.foo || github.foo.bar", ["github"])).toEqual([
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: foo",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
column: 10,
|
||||||
|
line: 0
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
column: 0,
|
||||||
|
line: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: "warning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: "Context access might be invalid: bar",
|
||||||
|
range: {
|
||||||
|
end: {
|
||||||
|
column: 28,
|
||||||
|
line: 0
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
column: 14,
|
||||||
|
line: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
severity: "warning"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
import {DescriptionDictionary} from "@actions/expressions";
|
||||||
|
import {
|
||||||
|
Binary,
|
||||||
|
ContextAccess,
|
||||||
|
Expr,
|
||||||
|
ExprVisitor,
|
||||||
|
FunctionCall,
|
||||||
|
Grouping,
|
||||||
|
IndexAccess,
|
||||||
|
Literal,
|
||||||
|
Logical,
|
||||||
|
Unary
|
||||||
|
} from "@actions/expressions/ast";
|
||||||
|
import {Dictionary} from "@actions/expressions/data/dictionary";
|
||||||
|
import {ExpressionData} from "@actions/expressions/data/expressiondata";
|
||||||
|
import {Range} from "@actions/expressions/lexer";
|
||||||
|
|
||||||
|
export type ValidationError = {
|
||||||
|
range: Range;
|
||||||
|
message: string;
|
||||||
|
severity: "error" | "warning";
|
||||||
|
};
|
||||||
|
|
||||||
|
export class ValidationVisitor implements ExprVisitor<void> {
|
||||||
|
public readonly errors: ValidationError[] = [];
|
||||||
|
|
||||||
|
constructor(private expr: Expr, private context: Dictionary) {}
|
||||||
|
|
||||||
|
validate(): void {
|
||||||
|
this._validate(this.expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _validate(expr: Expr) {
|
||||||
|
expr.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitLiteral() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
visitUnary(unary: Unary) {
|
||||||
|
this._validate(unary.expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitBinary(binary: Binary) {
|
||||||
|
this._validate(binary.left);
|
||||||
|
this._validate(binary.right);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitLogical(logical: Logical) {
|
||||||
|
for (const arg of logical.args) {
|
||||||
|
this._validate(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitGrouping(grouping: Grouping) {
|
||||||
|
this._validate(grouping.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitContextAccess(contextAccess: ContextAccess) {
|
||||||
|
const contextName = contextAccess.name.lexeme;
|
||||||
|
if (this.context.get(contextName) === undefined) {
|
||||||
|
this.errors.push({
|
||||||
|
message: `Context access might be invalid: ${contextName}`,
|
||||||
|
range: contextAccess.name.range,
|
||||||
|
severity: "error"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitIndexAccess(indexAccess: IndexAccess) {
|
||||||
|
let contextAccess: ContextAccess | undefined;
|
||||||
|
|
||||||
|
const s: ExpressionData[] = [];
|
||||||
|
let i: Expr = indexAccess;
|
||||||
|
while (i) {
|
||||||
|
if (i instanceof IndexAccess) {
|
||||||
|
if (!(i.index instanceof Literal)) {
|
||||||
|
// Not a literal, validate independently
|
||||||
|
this._validate(i.index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.push(i.index.literal);
|
||||||
|
i = i.expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i instanceof ContextAccess) {
|
||||||
|
contextAccess = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!contextAccess) {
|
||||||
|
// Context not found, should not happen, ignore in this case
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextName = contextAccess.name.lexeme;
|
||||||
|
let contextValue = this.context.get(contextName);
|
||||||
|
if (contextValue === undefined || !(contextValue instanceof Dictionary)) {
|
||||||
|
const contextName = contextAccess.name.lexeme;
|
||||||
|
if (this.context.get(contextName) === undefined) {
|
||||||
|
this.errors.push({
|
||||||
|
message: `Context access might be invalid: ${contextName}`,
|
||||||
|
range: contextAccess.name.range,
|
||||||
|
severity: "warning"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (s.length > 0) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const idx = s.pop()!;
|
||||||
|
|
||||||
|
const key = idx.coerceString();
|
||||||
|
const v: ExpressionData | undefined = contextValue.get(key);
|
||||||
|
if (v === undefined) {
|
||||||
|
if (contextValue instanceof DescriptionDictionary && !contextValue.complete) {
|
||||||
|
// If the context dictionary is not complete, we cannot validate the expression
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.errors.push({
|
||||||
|
range: {
|
||||||
|
start: contextAccess.name.range.start,
|
||||||
|
end: (indexAccess.index as Literal).token.range.end
|
||||||
|
},
|
||||||
|
message: `Context access might be invalid: ${key}`,
|
||||||
|
severity: "warning"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(v instanceof Dictionary)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
contextValue = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
visitFunctionCall(functionCall: FunctionCall) {
|
||||||
|
for (const arg of functionCall.args) {
|
||||||
|
this._validate(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import {DescriptionDictionary} from "@actions/expressions/.";
|
import {DescriptionDictionary} from "@actions/expressions";
|
||||||
import {DiagnosticSeverity} from "vscode-languageserver-types";
|
import {DiagnosticSeverity} from "vscode-languageserver-types";
|
||||||
import {ContextProviderConfig} from "./context-providers/config";
|
import {ContextProviderConfig} from "./context-providers/config";
|
||||||
import {registerLogger} from "./log";
|
import {registerLogger} from "./log";
|
||||||
@@ -46,52 +46,6 @@ jobs:
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("access invalid context field in short-circuited expression", async () => {
|
|
||||||
const result = await validate(
|
|
||||||
createDocument(
|
|
||||||
"wf.yaml",
|
|
||||||
`on: push
|
|
||||||
run-name: name-\${{ github.does-not-exist || github.does-not-exist2 }}
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- run: echo`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result).toEqual([
|
|
||||||
{
|
|
||||||
message: "Context access might be invalid: does-not-exist",
|
|
||||||
range: {
|
|
||||||
end: {
|
|
||||||
character: 69,
|
|
||||||
line: 1
|
|
||||||
},
|
|
||||||
start: {
|
|
||||||
character: 15,
|
|
||||||
line: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
severity: DiagnosticSeverity.Warning
|
|
||||||
},
|
|
||||||
{
|
|
||||||
message: "Context access might be invalid: does-not-exist2",
|
|
||||||
range: {
|
|
||||||
end: {
|
|
||||||
character: 69,
|
|
||||||
line: 1
|
|
||||||
},
|
|
||||||
start: {
|
|
||||||
character: 15,
|
|
||||||
line: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
severity: DiagnosticSeverity.Warning
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("partial skip access invalid context on incomplete", async () => {
|
it("partial skip access invalid context on incomplete", async () => {
|
||||||
const contextProviderConfig: ContextProviderConfig = {
|
const contextProviderConfig: ContextProviderConfig = {
|
||||||
getContext: (context: string) => {
|
getContext: (context: string) => {
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ import {ActionMetadata, ActionReference} from "./action";
|
|||||||
import {ContextProviderConfig} from "./context-providers/config";
|
import {ContextProviderConfig} from "./context-providers/config";
|
||||||
import {Mode, getContext} from "./context-providers/default";
|
import {Mode, getContext} from "./context-providers/default";
|
||||||
import {WorkflowContext, getWorkflowContext} from "./context/workflow-context";
|
import {WorkflowContext, getWorkflowContext} from "./context/workflow-context";
|
||||||
import {wrapDictionary} from "./expression-validation/error-dictionary";
|
import {ValidationVisitor} from "./expression-validation/visitor";
|
||||||
import {ValidationEvaluator} from "./expression-validation/evaluator";
|
|
||||||
import {validatorFunctions} from "./expression-validation/functions";
|
|
||||||
import {error} from "./log";
|
import {error} from "./log";
|
||||||
import {findToken} from "./utils/find-token";
|
import {findToken} from "./utils/find-token";
|
||||||
import {mapRange} from "./utils/range";
|
import {mapRange} from "./utils/range";
|
||||||
@@ -205,7 +203,7 @@ async function validateExpression(
|
|||||||
|
|
||||||
const context = await getContext(namedContexts, contextProviderConfig, workflowContext, Mode.Validation);
|
const context = await getContext(namedContexts, contextProviderConfig, workflowContext, Mode.Validation);
|
||||||
|
|
||||||
const e = new ValidationEvaluator(expr, wrapDictionary(context), validatorFunctions);
|
const e = new ValidationVisitor(expr, context);
|
||||||
e.validate();
|
e.validate();
|
||||||
|
|
||||||
diagnostics.push(
|
diagnostics.push(
|
||||||
|
|||||||
@@ -9,30 +9,15 @@ import {getWorkflowSchema} from "@actions/workflow-parser/workflows/workflow-sch
|
|||||||
import {Value} from "./config";
|
import {Value} from "./config";
|
||||||
import {stringsToValues} from "./strings-to-values";
|
import {stringsToValues} from "./strings-to-values";
|
||||||
|
|
||||||
export enum DefinitionValueMode {
|
export function definitionValues(def: Definition, indentation: string): Value[] {
|
||||||
/**
|
|
||||||
* We're getting completion options for a parent token
|
|
||||||
* foo:
|
|
||||||
* ba|
|
|
||||||
*/
|
|
||||||
Parent,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We're getting completion options for a key token. For example:
|
|
||||||
* foo: |
|
|
||||||
*/
|
|
||||||
Key
|
|
||||||
}
|
|
||||||
|
|
||||||
export function definitionValues(def: Definition, indentation: string, mode: DefinitionValueMode): Value[] {
|
|
||||||
const schema = getWorkflowSchema();
|
const schema = getWorkflowSchema();
|
||||||
|
|
||||||
if (def instanceof MappingDefinition) {
|
if (def instanceof MappingDefinition) {
|
||||||
return mappingValues(def, schema.definitions, indentation, mode);
|
return mappingValues(def, schema.definitions, indentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def instanceof OneOfDefinition) {
|
if (def instanceof OneOfDefinition) {
|
||||||
return oneOfValues(def, schema.definitions, indentation, mode);
|
return oneOfValues(def, schema.definitions, indentation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def instanceof BooleanDefinition) {
|
if (def instanceof BooleanDefinition) {
|
||||||
@@ -51,7 +36,7 @@ export function definitionValues(def: Definition, indentation: string, mode: Def
|
|||||||
if (def instanceof SequenceDefinition) {
|
if (def instanceof SequenceDefinition) {
|
||||||
const itemDef = schema.getDefinition(def.itemType);
|
const itemDef = schema.getDefinition(def.itemType);
|
||||||
if (itemDef) {
|
if (itemDef) {
|
||||||
return definitionValues(itemDef, indentation, mode);
|
return definitionValues(itemDef, indentation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,8 +46,7 @@ export function definitionValues(def: Definition, indentation: string, mode: Def
|
|||||||
function mappingValues(
|
function mappingValues(
|
||||||
mappingDefinition: MappingDefinition,
|
mappingDefinition: MappingDefinition,
|
||||||
definitions: {[key: string]: Definition},
|
definitions: {[key: string]: Definition},
|
||||||
indentation: string,
|
indentation: string
|
||||||
mode: DefinitionValueMode
|
|
||||||
): Value[] {
|
): Value[] {
|
||||||
const properties: Value[] = [];
|
const properties: Value[] = [];
|
||||||
for (const [key, value] of Object.entries(mappingDefinition.properties)) {
|
for (const [key, value] of Object.entries(mappingDefinition.properties)) {
|
||||||
@@ -76,36 +60,15 @@ function mappingValues(
|
|||||||
if (typeDef) {
|
if (typeDef) {
|
||||||
switch (typeDef.definitionType) {
|
switch (typeDef.definitionType) {
|
||||||
case DefinitionType.Sequence:
|
case DefinitionType.Sequence:
|
||||||
if (mode == DefinitionValueMode.Key) {
|
insertText = `${key}:\n${indentation}- `;
|
||||||
insertText = `\n${indentation}${key}:\n${indentation}${indentation}- `;
|
|
||||||
} else {
|
|
||||||
insertText = `${key}:\n${indentation}- `;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DefinitionType.Mapping:
|
case DefinitionType.Mapping:
|
||||||
if (mode == DefinitionValueMode.Key) {
|
insertText = `${key}:\n${indentation}`;
|
||||||
insertText = `\n${indentation}${key}:\n${indentation}${indentation}`;
|
|
||||||
} else {
|
|
||||||
insertText = `${key}:\n${indentation}`;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DefinitionType.OneOf:
|
case DefinitionType.OneOf:
|
||||||
if (mode == DefinitionValueMode.Parent) {
|
// No special insertText in this case
|
||||||
insertText = `${key}: `;
|
|
||||||
} else {
|
|
||||||
// No special insertText in this case
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DefinitionType.String:
|
|
||||||
case DefinitionType.Boolean:
|
|
||||||
if (mode == DefinitionValueMode.Key) {
|
|
||||||
insertText = `\n${indentation}${key}: `;
|
|
||||||
} else {
|
|
||||||
insertText = `${key}: `;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -126,12 +89,11 @@ function mappingValues(
|
|||||||
function oneOfValues(
|
function oneOfValues(
|
||||||
oneOfDefinition: OneOfDefinition,
|
oneOfDefinition: OneOfDefinition,
|
||||||
definitions: {[key: string]: Definition},
|
definitions: {[key: string]: Definition},
|
||||||
indentation: string,
|
indentation: string
|
||||||
mode: DefinitionValueMode
|
|
||||||
): Value[] {
|
): Value[] {
|
||||||
const values: Value[] = [];
|
const values: Value[] = [];
|
||||||
for (const key of oneOfDefinition.oneOf) {
|
for (const key of oneOfDefinition.oneOf) {
|
||||||
values.push(...definitionValues(definitions[key], indentation, mode));
|
values.push(...definitionValues(definitions[key], indentation));
|
||||||
}
|
}
|
||||||
return distinctValues(values);
|
return distinctValues(values);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-7
@@ -1,10 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"packages": [
|
"useWorkspaces": true,
|
||||||
"expressions",
|
"version": "0.3.1"
|
||||||
"workflow-parser",
|
|
||||||
"languageservice",
|
|
||||||
"languageserver"
|
|
||||||
],
|
|
||||||
"version": "0.3.9"
|
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+71
-163
@@ -135,7 +135,7 @@
|
|||||||
},
|
},
|
||||||
"expressions": {
|
"expressions": {
|
||||||
"name": "@actions/expressions",
|
"name": "@actions/expressions",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.0.3",
|
"@types/jest": "^29.0.3",
|
||||||
@@ -395,11 +395,11 @@
|
|||||||
},
|
},
|
||||||
"languageserver": {
|
"languageserver": {
|
||||||
"name": "@actions/languageserver",
|
"name": "@actions/languageserver",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/languageservice": "^0.3.9",
|
"@actions/languageservice": "^0.3.1",
|
||||||
"@actions/workflow-parser": "^0.3.9",
|
"@actions/workflow-parser": "^0.3.1",
|
||||||
"@octokit/rest": "^19.0.7",
|
"@octokit/rest": "^19.0.7",
|
||||||
"@octokit/types": "^9.0.0",
|
"@octokit/types": "^9.0.0",
|
||||||
"vscode-languageserver": "^8.0.2",
|
"vscode-languageserver": "^8.0.2",
|
||||||
@@ -678,11 +678,11 @@
|
|||||||
},
|
},
|
||||||
"languageservice": {
|
"languageservice": {
|
||||||
"name": "@actions/languageservice",
|
"name": "@actions/languageservice",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/expressions": "^0.3.9",
|
"@actions/expressions": "^0.3.1",
|
||||||
"@actions/workflow-parser": "^0.3.9",
|
"@actions/workflow-parser": "^0.3.1",
|
||||||
"vscode-languageserver-textdocument": "^1.0.7",
|
"vscode-languageserver-textdocument": "^1.0.7",
|
||||||
"vscode-languageserver-types": "^3.17.2",
|
"vscode-languageserver-types": "^3.17.2",
|
||||||
"vscode-uri": "^3.0.7",
|
"vscode-uri": "^3.0.7",
|
||||||
@@ -975,89 +975,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.22.13",
|
"version": "7.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
|
||||||
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/highlight": "^7.22.13",
|
"@babel/highlight": "^7.18.6"
|
||||||
"chalk": "^2.4.2"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame/node_modules/ansi-styles": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"color-convert": "^1.9.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame/node_modules/chalk": {
|
|
||||||
"version": "2.4.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
|
||||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"ansi-styles": "^3.2.1",
|
|
||||||
"escape-string-regexp": "^1.0.5",
|
|
||||||
"supports-color": "^5.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame/node_modules/color-convert": {
|
|
||||||
"version": "1.9.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
|
||||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"color-name": "1.1.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame/node_modules/color-name": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
|
|
||||||
"version": "1.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
|
||||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame/node_modules/has-flag": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/code-frame/node_modules/supports-color": {
|
|
||||||
"version": "5.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
|
||||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"has-flag": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.20.1",
|
"version": "7.20.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@@ -1101,14 +1028,12 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.23.0",
|
"version": "7.20.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
|
|
||||||
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.23.0",
|
"@babel/types": "^7.20.2",
|
||||||
"@jridgewell/gen-mapping": "^0.3.2",
|
"@jridgewell/gen-mapping": "^0.3.2",
|
||||||
"@jridgewell/trace-mapping": "^0.3.17",
|
|
||||||
"jsesc": "^2.5.1"
|
"jsesc": "^2.5.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1146,34 +1071,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-environment-visitor": {
|
"node_modules/@babel/helper-environment-visitor": {
|
||||||
"version": "7.22.20",
|
"version": "7.18.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
|
|
||||||
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-function-name": {
|
"node_modules/@babel/helper-function-name": {
|
||||||
"version": "7.23.0",
|
"version": "7.19.0",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
|
|
||||||
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.22.15",
|
"@babel/template": "^7.18.10",
|
||||||
"@babel/types": "^7.23.0"
|
"@babel/types": "^7.19.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-hoist-variables": {
|
"node_modules/@babel/helper-hoist-variables": {
|
||||||
"version": "7.22.5",
|
"version": "7.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
|
|
||||||
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.22.5"
|
"@babel/types": "^7.18.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@@ -1228,31 +1150,28 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-split-export-declaration": {
|
"node_modules/@babel/helper-split-export-declaration": {
|
||||||
"version": "7.22.6",
|
"version": "7.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
|
|
||||||
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.22.5"
|
"@babel/types": "^7.18.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.22.5",
|
"version": "7.19.4",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
|
|
||||||
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.22.20",
|
"version": "7.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
|
|
||||||
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
@@ -1279,13 +1198,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/highlight": {
|
"node_modules/@babel/highlight": {
|
||||||
"version": "7.22.20",
|
"version": "7.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
|
|
||||||
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.22.20",
|
"@babel/helper-validator-identifier": "^7.18.6",
|
||||||
"chalk": "^2.4.2",
|
"chalk": "^2.0.0",
|
||||||
"js-tokens": "^4.0.0"
|
"js-tokens": "^4.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1357,10 +1275,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.23.0",
|
"version": "7.20.3",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
|
||||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
},
|
},
|
||||||
@@ -1543,33 +1460,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.22.15",
|
"version": "7.18.10",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
|
|
||||||
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.22.13",
|
"@babel/code-frame": "^7.18.6",
|
||||||
"@babel/parser": "^7.22.15",
|
"@babel/parser": "^7.18.10",
|
||||||
"@babel/types": "^7.22.15"
|
"@babel/types": "^7.18.10"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.23.2",
|
"version": "7.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
|
||||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.22.13",
|
"@babel/code-frame": "^7.18.6",
|
||||||
"@babel/generator": "^7.23.0",
|
"@babel/generator": "^7.20.1",
|
||||||
"@babel/helper-environment-visitor": "^7.22.20",
|
"@babel/helper-environment-visitor": "^7.18.9",
|
||||||
"@babel/helper-function-name": "^7.23.0",
|
"@babel/helper-function-name": "^7.19.0",
|
||||||
"@babel/helper-hoist-variables": "^7.22.5",
|
"@babel/helper-hoist-variables": "^7.18.6",
|
||||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
"@babel/helper-split-export-declaration": "^7.18.6",
|
||||||
"@babel/parser": "^7.23.0",
|
"@babel/parser": "^7.20.1",
|
||||||
"@babel/types": "^7.23.0",
|
"@babel/types": "^7.20.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"globals": "^11.1.0"
|
"globals": "^11.1.0"
|
||||||
},
|
},
|
||||||
@@ -1578,13 +1493,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.23.0",
|
"version": "7.20.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
|
|
||||||
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.22.5",
|
"@babel/helper-string-parser": "^7.19.4",
|
||||||
"@babel/helper-validator-identifier": "^7.22.20",
|
"@babel/helper-validator-identifier": "^7.19.1",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4474,12 +4388,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.6.7",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
|
|
||||||
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.4",
|
"follow-redirects": "^1.15.0",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
@@ -6279,9 +6192,7 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.15.5",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
|
||||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -6289,6 +6200,7 @@
|
|||||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
},
|
},
|
||||||
@@ -6740,10 +6652,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/http-cache-semantics": {
|
"node_modules/http-cache-semantics": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
|
"dev": true,
|
||||||
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
|
"license": "BSD-2-Clause"
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/http-proxy-agent": {
|
"node_modules/http-proxy-agent": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
@@ -7025,10 +6936,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ip": {
|
"node_modules/ip": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
|
"dev": true,
|
||||||
"integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==",
|
"license": "MIT"
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
@@ -11559,10 +11469,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/word-wrap": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
|
|
||||||
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -11758,9 +11667,8 @@
|
|||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.2.2",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
"license": "ISC",
|
||||||
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
@@ -11811,10 +11719,10 @@
|
|||||||
},
|
},
|
||||||
"workflow-parser": {
|
"workflow-parser": {
|
||||||
"name": "@actions/workflow-parser",
|
"name": "@actions/workflow-parser",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/expressions": "^0.3.9",
|
"@actions/expressions": "^0.3.1",
|
||||||
"cronstrue": "^2.21.0",
|
"cronstrue": "^2.21.0",
|
||||||
"yaml": "^2.0.0-8"
|
"yaml": "^2.0.0-8"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Release 0.3.5
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# this script is used to generate release notes for a given release
|
|
||||||
# first argument is the pull request id for the last release
|
|
||||||
# the second is the new release number
|
|
||||||
|
|
||||||
# the script then grabs every pull request merged since that pull request
|
|
||||||
# and outputs a string of release notes
|
|
||||||
|
|
||||||
# get the new release number
|
|
||||||
NEW_RELEASE=$2
|
|
||||||
|
|
||||||
echo "Generating release notes for $NEW_RELEASE"
|
|
||||||
|
|
||||||
# get the last release pull request id
|
|
||||||
LAST_RELEASE_PR=$1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#get when the last release was merged
|
|
||||||
LAST_RELEASE_MERGED_AT=$(gh pr view $LAST_RELEASE_PR --repo actions/languageservices --json mergedAt | jq -r '.mergedAt')
|
|
||||||
|
|
||||||
CHANGELIST=$(gh pr list --repo actions/languageservices --base main --state merged --json title --search "merged:>$LAST_RELEASE_MERGED_AT -label:no-release")
|
|
||||||
|
|
||||||
# store the release notes in a variable so we can use it later
|
|
||||||
|
|
||||||
echo "Release $NEW_RELEASE" >> releasenotes.md
|
|
||||||
|
|
||||||
echo $CHANGELIST | jq -r '.[].title' | while read line; do
|
|
||||||
echo " - $line" >> releasenotes.md
|
|
||||||
done
|
|
||||||
|
|
||||||
echo " "
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
VERSION=$(cat lerna.json | jq -r '.version')
|
|
||||||
|
|
||||||
MAJOR=$(echo $VERSION | cut -d. -f1)
|
|
||||||
MINOR=$(echo $VERSION | cut -d. -f2)
|
|
||||||
PATCH=$(echo $VERSION | cut -d. -f3)
|
|
||||||
|
|
||||||
if [ "$1" == "major" ]; then
|
|
||||||
MAJOR=$((MAJOR+1))
|
|
||||||
MINOR=0
|
|
||||||
PATCH=0
|
|
||||||
elif [ "$1" == "minor" ]; then
|
|
||||||
MINOR=$((MINOR+1))
|
|
||||||
PATCH=0
|
|
||||||
elif [ "$1" == "patch" ]; then
|
|
||||||
PATCH=$((PATCH+1))
|
|
||||||
else
|
|
||||||
echo "Invalid version type. Use 'major', 'minor' or 'patch'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
NEW_VERSION="$MAJOR.$MINOR.$PATCH"
|
|
||||||
echo $NEW_VERSION
|
|
||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
`convertWorkflowTemplate` then takes that intermediate representation and converts it to a [`WorkflowTemplate`](./src/model/workflow-template.ts) object, which is a more convenient representation for working with workflows.
|
`convertWorkflowTemplate` then takes that intermediate representation and converts it to a [`WorkflowTemplate`](./src/workflow-template.ts) object, which is a more convenient representation for working with workflows.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const workflowTemplate = await convertWorkflowTemplate(result.context, result.value);
|
const workflowTemplate = await convertWorkflowTemplate(result.context, result.value);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actions/workflow-parser",
|
"name": "@actions/workflow-parser",
|
||||||
"version": "0.3.9",
|
"version": "0.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"source": "./src/index.ts",
|
"source": "./src/index.ts",
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"watch": "tsc --build tsconfig.build.json --watch"
|
"watch": "tsc --build tsconfig.build.json --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/expressions": "^0.3.9",
|
"@actions/expressions": "^0.3.1",
|
||||||
"cronstrue": "^2.21.0",
|
"cronstrue": "^2.21.0",
|
||||||
"yaml": "^2.0.0-8"
|
"yaml": "^2.0.0-8"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -59,24 +59,17 @@ export function convertOn(context: TemplateContext, token: TemplateToken): Event
|
|||||||
|
|
||||||
// All other events are defined as mappings. During schema validation we already ensure that events
|
// All other events are defined as mappings. During schema validation we already ensure that events
|
||||||
// receive only known keys, so here we can focus on the values and whether they are valid.
|
// receive only known keys, so here we can focus on the values and whether they are valid.
|
||||||
|
|
||||||
const eventToken = item.value.assertMapping(`event ${eventName}`);
|
const eventToken = item.value.assertMapping(`event ${eventName}`);
|
||||||
if (eventName === "workflow_call") {
|
|
||||||
result.workflow_call = convertEventWorkflowCall(context, eventToken);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventName === "workflow_dispatch") {
|
|
||||||
result.workflow_dispatch = convertEventWorkflowDispatchInputs(context, eventToken);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result[eventName] = {
|
result[eventName] = {
|
||||||
...convertPatternFilter("branches", eventToken),
|
...convertPatternFilter("branches", eventToken),
|
||||||
...convertPatternFilter("tags", eventToken),
|
...convertPatternFilter("tags", eventToken),
|
||||||
...convertPatternFilter("paths", eventToken),
|
...convertPatternFilter("paths", eventToken),
|
||||||
...convertFilter("types", eventToken),
|
...convertFilter("types", eventToken),
|
||||||
...convertFilter("workflows", eventToken)
|
...convertFilter("workflows", eventToken),
|
||||||
|
// workflow_call and workflow_dispatch share input parsing
|
||||||
|
...convertEventWorkflowDispatchInputs(context, eventToken),
|
||||||
|
...convertEventWorkflowCall(context, eventToken)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ function convertStep(context: TemplateContext, idBuilder: IdBuilder, step: Templ
|
|||||||
let id: StringToken | undefined;
|
let id: StringToken | undefined;
|
||||||
let name: ScalarToken | undefined;
|
let name: ScalarToken | undefined;
|
||||||
let uses: StringToken | undefined;
|
let uses: StringToken | undefined;
|
||||||
let continueOnError: boolean | ScalarToken | undefined;
|
let continueOnError: boolean | undefined;
|
||||||
let env: MappingToken | undefined;
|
let env: MappingToken | undefined;
|
||||||
const ifCondition = new BasicExpressionToken(undefined, undefined, "success()", undefined, undefined, undefined);
|
const ifCondition = new BasicExpressionToken(undefined, undefined, "success()", undefined, undefined, undefined);
|
||||||
for (const item of mapping) {
|
for (const item of mapping) {
|
||||||
@@ -78,11 +78,7 @@ function convertStep(context: TemplateContext, idBuilder: IdBuilder, step: Templ
|
|||||||
env = item.value.assertMapping("step env");
|
env = item.value.assertMapping("step env");
|
||||||
break;
|
break;
|
||||||
case "continue-on-error":
|
case "continue-on-error":
|
||||||
if (!item.value.isExpression) {
|
continueOnError = item.value.assertBoolean("steps item continue-on-error").value;
|
||||||
continueOnError = item.value.assertBoolean("steps item continue-on-error").value;
|
|
||||||
} else {
|
|
||||||
continueOnError = item.value.assertScalar("steps item continue-on-error");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import {TemplateContext} from "../../templates/template-context";
|
import {TemplateContext} from "../../templates/template-context";
|
||||||
import {MappingToken, TemplateToken} from "../../templates/tokens";
|
import {MappingToken, TemplateToken} from "../../templates/tokens";
|
||||||
import {isMapping} from "../../templates/tokens/type-guards";
|
import {isMapping} from "../../templates/tokens/type-guards";
|
||||||
import {SecretConfig, WorkflowCallConfig, InputConfig, InputType} from "../workflow-template";
|
import {SecretConfig, WorkflowCallConfig} from "../workflow-template";
|
||||||
import {convertStringList} from "./string-list";
|
|
||||||
import {ScalarToken} from "../../templates/tokens/scalar-token";
|
|
||||||
|
|
||||||
export function convertEventWorkflowCall(context: TemplateContext, token: MappingToken): WorkflowCallConfig {
|
export function convertEventWorkflowCall(context: TemplateContext, token: MappingToken): WorkflowCallConfig {
|
||||||
const result: WorkflowCallConfig = {};
|
const result: WorkflowCallConfig = {};
|
||||||
@@ -13,7 +11,7 @@ export function convertEventWorkflowCall(context: TemplateContext, token: Mappin
|
|||||||
|
|
||||||
switch (key.value) {
|
switch (key.value) {
|
||||||
case "inputs":
|
case "inputs":
|
||||||
result.inputs = convertWorkflowInputs(context, item.value.assertMapping("workflow dispatch inputs"));
|
// Ignore, these are handled by convertEventWorkflowDispatchInputs
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "secrets":
|
case "secrets":
|
||||||
@@ -29,94 +27,6 @@ export function convertEventWorkflowCall(context: TemplateContext, token: Mappin
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertWorkflowInputs(
|
|
||||||
context: TemplateContext,
|
|
||||||
token: MappingToken
|
|
||||||
): {
|
|
||||||
[inputName: string]: InputConfig;
|
|
||||||
} {
|
|
||||||
const result: {[inputName: string]: InputConfig} = {};
|
|
||||||
|
|
||||||
for (const item of token) {
|
|
||||||
const inputName = item.key.assertString("input name");
|
|
||||||
const inputMapping = item.value.assertMapping("input configuration");
|
|
||||||
|
|
||||||
result[inputName.value] = convertWorkflowInput(context, inputMapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertWorkflowInput(context: TemplateContext, token: MappingToken): InputConfig {
|
|
||||||
const result: InputConfig = {
|
|
||||||
type: InputType.string // Default to string
|
|
||||||
};
|
|
||||||
|
|
||||||
let defaultValue: undefined | ScalarToken;
|
|
||||||
|
|
||||||
for (const item of token) {
|
|
||||||
const key = item.key.assertString("workflow dispatch input key");
|
|
||||||
|
|
||||||
switch (key.value) {
|
|
||||||
case "description":
|
|
||||||
result.description = item.value.assertString("input description").value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "required":
|
|
||||||
result.required = item.value.assertBoolean("input required").value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "default":
|
|
||||||
defaultValue = item.value.assertScalar("input default");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "type":
|
|
||||||
result.type = InputType[item.value.assertString("input type").value as keyof typeof InputType];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "options":
|
|
||||||
result.options = convertStringList("input options", item.value.assertSequence("input options"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
context.error(item.key, `Invalid key '${key.value}'`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate default value
|
|
||||||
if (defaultValue !== undefined && !defaultValue.isExpression) {
|
|
||||||
try {
|
|
||||||
switch (result.type) {
|
|
||||||
case InputType.boolean:
|
|
||||||
result.default = defaultValue.assertBoolean("input default").value;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case InputType.string:
|
|
||||||
case InputType.choice:
|
|
||||||
case InputType.environment:
|
|
||||||
result.default = defaultValue.assertString("input default").value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
context.error(defaultValue, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate `options` for `choice` type
|
|
||||||
if (result.type === InputType.choice) {
|
|
||||||
if (result.options === undefined || result.options.length === 0) {
|
|
||||||
context.error(token, "Missing 'options' for choice input");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (result.options !== undefined) {
|
|
||||||
context.error(token, "Input type is not 'choice', but 'options' is defined");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function convertWorkflowCallSecrets(
|
function convertWorkflowCallSecrets(
|
||||||
context: TemplateContext,
|
context: TemplateContext,
|
||||||
token: MappingToken
|
token: MappingToken
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ type BaseStep = {
|
|||||||
id: string;
|
id: string;
|
||||||
name?: ScalarToken;
|
name?: ScalarToken;
|
||||||
if: BasicExpressionToken;
|
if: BasicExpressionToken;
|
||||||
"continue-on-error"?: boolean | ScalarToken;
|
"continue-on-error"?: boolean;
|
||||||
env?: MappingToken;
|
env?: MappingToken;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ export type WorkflowDispatchConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type WorkflowCallConfig = {
|
export type WorkflowCallConfig = {
|
||||||
inputs?: {[inputName: string]: InputConfig & {default?: string | boolean | number | ScalarToken}};
|
inputs?: {[inputName: string]: InputConfig};
|
||||||
secrets?: {[secretName: string]: SecretConfig};
|
secrets?: {[secretName: string]: SecretConfig};
|
||||||
// TODO - these are supported in C# and Go but not in TS yet
|
// TODO - these are supported in C# and Go but not in TS yet
|
||||||
// outputs: { [outputName: string]: OutputConfig }
|
// outputs: { [outputName: string]: OutputConfig }
|
||||||
|
|||||||
@@ -576,9 +576,7 @@
|
|||||||
"merge-group-mapping": {
|
"merge-group-mapping": {
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"types": "merge-group-activity",
|
"types": "merge-group-activity"
|
||||||
"branches": "event-branches",
|
|
||||||
"branches-ignore": "event-branches-ignore"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1183,7 +1181,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"workflow-run-activity": {
|
"workflow-run-activity": {
|
||||||
"description": "The types of workflow run activity that trigger the workflow. Supported activity types: `completed`, `requested`, `in_progress`.",
|
"description": "The types of workflow run activity that trigger the workflow. Suupported activity types: `completed`, `requested`, `in_progress`.",
|
||||||
"one-of": [
|
"one-of": [
|
||||||
"workflow-run-activity-type",
|
"workflow-run-activity-type",
|
||||||
"workflow-run-activity-types"
|
"workflow-run-activity-types"
|
||||||
@@ -2489,7 +2487,7 @@
|
|||||||
"string": {
|
"string": {
|
||||||
"require-non-empty": true
|
"require-non-empty": true
|
||||||
},
|
},
|
||||||
"description": "Use `shell` to override the default shell settings in the runner's operating system. You can use built-in shell keywords, or you can define a custom set of shell options. The shell command that is run internally executes a temporary file that contains the commands specified in `run`."
|
"description": "Use `shell` to override the default shell settings in the runner's operating system. You can use built-in shell keywords, or you can define a custom set of shell options. The shell command that is run internally executes a temporary file that contains the comands specified in `run`."
|
||||||
},
|
},
|
||||||
"working-directory": {
|
"working-directory": {
|
||||||
"string": {
|
"string": {
|
||||||
|
|||||||
+1
-14
@@ -72,13 +72,7 @@ on:
|
|||||||
- edited
|
- edited
|
||||||
- deleted
|
- deleted
|
||||||
merge_group:
|
merge_group:
|
||||||
branches:
|
types: checks_requested
|
||||||
- master
|
|
||||||
- main
|
|
||||||
branches-ignore:
|
|
||||||
- develop
|
|
||||||
types:
|
|
||||||
- checks_requested
|
|
||||||
milestone:
|
milestone:
|
||||||
types:
|
types:
|
||||||
- created
|
- created
|
||||||
@@ -319,13 +313,6 @@ jobs:
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"merge_group": {
|
"merge_group": {
|
||||||
"branches": [
|
|
||||||
"master",
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"branches-ignore": [
|
|
||||||
"develop"
|
|
||||||
],
|
|
||||||
"types": [
|
"types": [
|
||||||
"checks_requested"
|
"checks_requested"
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user