Merge branch 'main' into joshmgross/schema-function-descriptions

This commit is contained in:
Josh Gross
2023-03-20 18:58:10 -04:00
committed by GitHub
23 changed files with 1741 additions and 233 deletions
+35
View File
@@ -0,0 +1,35 @@
---
name: Bug report
about: Report a bug or unexpected behavior while using Actions Language Services
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. With this workflow '...'
2. Do this '...'
3. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Package/Area**
- [ ] Expressions
- [ ] Workflow Parser
- [ ] Language Service
- [ ] Language Server
**Package Version**
`v1.x.y`
**Additional context**
Add any other context about the problem here.
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Ask a question or provide feedback about the Actions Language Services
about: For general Q&A and feedback, see the Discussions tab.
url: https://github.com/actions/languageservices/discussions
- name: Ask a question or provide feedback about GitHub Actions
about: Please check out the GitHub community forum for discussions about GitHub Actions
url: https://github.com/orgs/community/discussions/categories/actions
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for Actions Language Services
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Additional context**
Add any other context or screenshots about the feature request here.
+1
View File
@@ -23,4 +23,5 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: npm run format-check -ws
- run: npm run build -ws
- run: npm run lint -ws
- run: npm test -ws
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "browser-playground",
"version": "0.1.177",
"version": "0.1.179",
"description": "",
"private": true,
"main": "index.js",
"type": "module",
"dependencies": {
"@github/actions-languageserver": "^0.1.177",
"@github/actions-languageserver": "^0.1.179",
"monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "^4.0.3",
+1
View File
@@ -1,3 +1,4 @@
/* eslint-disable */
import * as monaco from "monaco-editor";
import {CloseAction, ErrorAction, MessageTransports, MonacoLanguageClient, MonacoServices} from "monaco-languageclient";
+6 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-expressions",
"version": "0.1.177",
"version": "0.1.179",
"license": "MIT",
"type": "module",
"source": "./src/index.ts",
@@ -46,6 +46,11 @@
],
"devDependencies": {
"@types/jest": "^29.0.3",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.0.3",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
+8 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-languageserver",
"version": "0.1.177",
"version": "0.1.179",
"description": "Language server for GitHub Actions",
"license": "MIT",
"type": "module",
@@ -40,8 +40,8 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"dependencies": {
"@github/actions-languageservice": "^0.1.177",
"@github/actions-workflow-parser": "^0.1.177",
"@github/actions-languageservice": "^0.1.179",
"@github/actions-workflow-parser": "^0.1.179",
"@octokit/rest": "^19.0.7",
"@octokit/types": "^9.0.0",
"vscode-languageserver": "^8.0.2",
@@ -56,6 +56,11 @@
],
"devDependencies": {
"@types/jest": "^29.0.3",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"fetch-mock": "^9.11.0",
"jest": "^29.0.3",
"prettier": "^2.8.3",
+8 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-languageservice",
"version": "0.1.177",
"version": "0.1.179",
"description": "Language service for GitHub Actions",
"license": "MIT",
"type": "module",
@@ -41,8 +41,8 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"dependencies": {
"@github/actions-expressions": "^0.1.177",
"@github/actions-workflow-parser": "^0.1.177",
"@github/actions-expressions": "^0.1.179",
"@github/actions-workflow-parser": "^0.1.179",
"vscode-languageserver-textdocument": "^1.0.7",
"vscode-languageserver-types": "^3.17.2",
"vscode-uri": "^3.0.7",
@@ -57,6 +57,11 @@
"types": "./dist/index.d.ts",
"devDependencies": {
"@types/jest": "^29.0.3",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"eslint": "^8.36.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.0.3",
"prettier": "^2.8.3",
"rest-api-description": "github:github/rest-api-description",
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import {data, DescriptionDictionary} from "@github/actions-expressions";
import {CompletionItem, CompletionItemKind} from "vscode-languageserver-types";
import {complete, getExpressionInput} from "./complete";
@@ -9,17 +10,19 @@ import {testFileProvider} from "./test-utils/test-file-provider";
import {clearCache} from "./utils/workflow-cache";
const contextProviderConfig: ContextProviderConfig = {
getContext: async (context: string) => {
getContext: (context: string) => {
switch (context) {
case "github":
return new DescriptionDictionary({
key: "event",
value: new data.StringData("push"),
description: "The event that triggered the workflow"
});
return Promise.resolve(
new DescriptionDictionary({
key: "event",
value: new data.StringData("push"),
description: "The event that triggered the workflow"
})
);
}
return undefined;
return Promise.resolve(undefined);
}
};
+7 -3
View File
@@ -225,6 +225,10 @@ function getExpressionCompletionItems(
context: DescriptionDictionary,
pos: Position
): CompletionItem[] {
if (!token.range) {
return [];
}
let currentInput = "";
if (isBasicExpression(token)) {
@@ -234,15 +238,15 @@ function getExpressionCompletionItems(
currentInput = stringToken.source || stringToken.value;
}
const relCharOffset = getRelCharOffset(token.range!, currentInput, pos);
const relCharOffset = getRelCharOffset(token.range, currentInput, pos);
const expressionInput = (getExpressionInput(currentInput, relCharOffset) || "").trim();
try {
return completeExpression(expressionInput, context, [], validatorFunctions).map(item =>
mapExpressionCompletionItem(item, currentInput[relCharOffset])
);
} catch (e: any) {
error(`Error while completing expression: '${e?.message || "<no details>"}'`);
} catch (e) {
error(`Error while completing expression: '${(e as Error)?.message || "<no details>"}'`);
return [];
}
}
@@ -73,10 +73,10 @@ type DeduplicatedWebhooks = {
};
};
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */
const dedupedWebhookPayloads: DeduplicatedWebhooks = webhooks as any;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const objects: Param[] = webhookObjects as any;
/* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */
// Hydrated webhook payloads
const webhookPayloads: Webhooks = {};
+18 -16
View File
@@ -9,28 +9,30 @@ import {TestLogger} from "./test-utils/logger";
import {clearCache} from "./utils/workflow-cache";
const contextProviderConfig: ContextProviderConfig = {
getContext: async (context: string) => {
getContext: (context: string) => {
switch (context) {
case "github":
return new DescriptionDictionary(
{
key: "event",
value: new data.StringData("push"),
description: "The event that triggered the workflow"
},
{
key: "test",
value: new DescriptionDictionary({
key: "name",
return Promise.resolve(
new DescriptionDictionary(
{
key: "event",
value: new data.StringData("push"),
description: "Name for the test"
}),
description: "Test dictionary"
}
description: "The event that triggered the workflow"
},
{
key: "test",
value: new DescriptionDictionary({
key: "name",
value: new data.StringData("push"),
description: "Name for the test"
}),
description: "Test dictionary"
}
)
);
}
return undefined;
return Promise.resolve(undefined);
}
};
+3 -3
View File
@@ -1,5 +1,4 @@
import {isString} from "@github/actions-workflow-parser";
import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token";
import {DescriptionProvider, hover, HoverConfig} from "./hover";
import {getPositionFromCursor} from "./test-utils/cursor-position";
import {testFileProvider} from "./test-utils/test-file-provider";
@@ -8,15 +7,16 @@ import {clearCache} from "./utils/workflow-cache";
export function testHoverConfig(tokenValue: string, tokenKey: string, description?: string) {
return {
descriptionProvider: {
getDescription: async (_, token, __) => {
getDescription: (_, token) => {
if (!isString(token)) {
throw new Error("Test provider only supports string tokens");
}
expect(token.value).toEqual(tokenValue);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
expect(token.definition!.key).toEqual(tokenKey);
return description;
return Promise.resolve(description);
}
} satisfies DescriptionProvider,
fileProvider: testFileProvider
+3 -2
View File
@@ -160,7 +160,8 @@ async function getDescription(
function isCronMappingValue(tokenResult: TokenResult): boolean {
return (
tokenResult.parent?.definition?.key === "cron-mapping" &&
isString(tokenResult.token!) &&
!!tokenResult.token &&
isString(tokenResult.token) &&
tokenResult.token.value !== "cron"
);
}
@@ -211,7 +212,7 @@ function expressionHover(
};
} catch (e) {
// Hovering over an invalid expression should not cause an error here
info(`Encountered error trying to calculate expression hover: ${e}`);
info(`Encountered error trying to calculate expression hover: ${(e as Error).message}`);
return null;
}
}
+2 -6
View File
@@ -1,7 +1,3 @@
import {TraceWriter} from "@github/actions-workflow-parser/templates/trace-writer";
import {NoOperationTraceWriter} from "@github/actions-workflow-parser/templates/trace-writer";
export const nullTrace: TraceWriter = {
info: x => {},
verbose: x => {},
error: x => {}
};
export const nullTrace = new NoOperationTraceWriter();
+4 -4
View File
@@ -14,7 +14,7 @@ beforeEach(() => {
});
const validationConfig: ValidationConfig = {
fetchActionMetadata: async (ref: ActionReference) => {
fetchActionMetadata: (ref: ActionReference) => {
let metadata: ActionMetadata | undefined = undefined;
switch (ref.owner + "/" + ref.name + "@" + ref.ref) {
case "actions/checkout@v3":
@@ -82,7 +82,7 @@ const validationConfig: ValidationConfig = {
description: "An action with no inputs"
};
}
return metadata;
return Promise.resolve(metadata);
}
};
@@ -326,8 +326,8 @@ jobs:
config.valueProviderConfig = {
"step-with": {
kind: ValueProviderKind.AllowedValues,
get: async () => {
return [{label: "repository", description: "Repository name with owner."}];
get: () => {
return Promise.resolve([{label: "repository", description: "Repository name with owner."}]);
}
}
};
@@ -1,4 +1,4 @@
import {data, DescriptionDictionary} from "@github/actions-expressions/.";
import {DescriptionDictionary} from "@github/actions-expressions/.";
import {DiagnosticSeverity} from "vscode-languageserver-types";
import {ContextProviderConfig} from "./context-providers/config";
import {registerLogger} from "./log";
@@ -48,15 +48,16 @@ jobs:
it("partial skip access invalid context on incomplete", async () => {
const contextProviderConfig: ContextProviderConfig = {
getContext: async (context: string) => {
getContext: (context: string) => {
switch (context) {
case "secrets":
case "secrets": {
const dict = new DescriptionDictionary();
dict.complete = false;
return dict;
return Promise.resolve(dict);
}
}
return undefined;
return Promise.resolve(undefined);
}
};
+3 -3
View File
@@ -3,7 +3,7 @@ import {createDocument} from "./test-utils/document";
import {validate} from "./validate";
import {defaultValueProviders} from "./value-providers/default";
import {clearCache} from "./utils/workflow-cache";
import {ValueProvider, ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
beforeEach(() => {
clearCache();
@@ -249,7 +249,7 @@ jobs:
const valueProviderConfig: ValueProviderConfig = {
"job-environment": {
kind: ValueProviderKind.AllowedValues,
get: async () => [{label: "test"}],
get: () => Promise.resolve([{label: "test"}]),
caseInsensitive: false
}
};
@@ -286,7 +286,7 @@ jobs:
const valueProviderConfig: ValueProviderConfig = {
"job-environment": {
kind: ValueProviderKind.AllowedValues,
get: async () => [{label: "test"}],
get: () => Promise.resolve([{label: "test"}]),
caseInsensitive: true
}
};
+11 -10
View File
@@ -23,6 +23,7 @@ import {validateAction} from "./validate-action";
import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
import {defaultValueProviders} from "./value-providers/default";
import {fetchOrParseWorkflow, fetchOrConvertWorkflowTemplate} from "./utils/workflow-cache";
import {TokenRange} from "@github/actions-workflow-parser/templates/tokens/token-range";
export type ValidationConfig = {
valueProviderConfig?: ValueProviderConfig;
@@ -72,7 +73,7 @@ export async function validate(textDocument: TextDocument, config?: ValidationCo
});
}
} catch (e) {
error(`Unhandled error while validating: ${e}`);
error(`Unhandled error while validating: ${(e as Error).message}`);
}
return diagnostics;
@@ -92,18 +93,18 @@ async function additionalValidations(
const validationDefinition = validationToken.definition;
// If this is an expression, validate it
if (isBasicExpression(token)) {
if (isBasicExpression(token) && token.range) {
await validateExpression(
diagnostics,
token,
validationToken.definitionInfo?.allowedContext || [],
config?.contextProviderConfig,
getProviderContext(documentUri, template, root, token)
getProviderContext(documentUri, template, root, token.range)
);
}
if (token.definition?.key === "regular-step") {
const context = getProviderContext(documentUri, template, root, token);
if (token.definition?.key === "regular-step" && token.range) {
const context = getProviderContext(documentUri, template, root, token.range);
await validateAction(diagnostics, token, context.step, config);
}
@@ -129,7 +130,7 @@ async function additionalValidations(
}
if (valueProvider) {
const customValues = await valueProvider.get(getProviderContext(documentUri, template, root, token));
const customValues = await valueProvider.get(getProviderContext(documentUri, template, root, token.range));
const caseInsensitive = valueProvider.caseInsensitive ?? false;
const customValuesMap = new Set(customValues.map(x => (caseInsensitive ? x.label.toLowerCase() : x.label)));
@@ -161,12 +162,12 @@ function getProviderContext(
documentUri: URI,
template: WorkflowTemplate,
root: TemplateToken,
token: TemplateToken
tokenRange: TokenRange
): WorkflowContext {
const {parent, path} = findToken(
const {path} = findToken(
{
line: token.range!.start.line - 1,
character: token.range!.start.column - 1
line: tokenRange.start.line - 1,
character: tokenRange.start.column - 1
},
root
);
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": true,
"version": "0.1.177"
"version": "0.1.179"
}
+1578 -157
View File
File diff suppressed because it is too large Load Diff
+7 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-workflow-parser",
"version": "0.1.177",
"version": "0.1.179",
"license": "MIT",
"type": "module",
"source": "./src/index.ts",
@@ -40,7 +40,7 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"dependencies": {
"@github/actions-expressions": "^0.1.177",
"@github/actions-expressions": "^0.1.179",
"cronstrue": "^2.21.0",
"yaml": "^2.0.0-8"
},
@@ -52,9 +52,11 @@
],
"devDependencies": {
"@types/jest": "^29.0.3",
"@typescript-eslint/eslint-plugin": "^5.40.0",
"@typescript-eslint/parser": "^5.40.0",
"eslint": "7.32.0",
"@typescript-eslint/eslint-plugin": "^5.56.0",
"@typescript-eslint/parser": "^5.56.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.0.3",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",