Wrap fetchActionsMetadata in provider checking sessionToken

This commit is contained in:
Beth Brennan
2023-03-27 14:00:58 -04:00
parent 9c4b8a4c1c
commit 50f9c04a91
6 changed files with 105 additions and 76 deletions
+2 -8
View File
@@ -26,7 +26,7 @@ import {getFileProvider} from "./file-provider";
import {InitializationOptions, RepositoryContext} from "./initializationOptions"; import {InitializationOptions, RepositoryContext} from "./initializationOptions";
import {onCompletion} from "./on-completion"; import {onCompletion} from "./on-completion";
import {ReadFileRequest, Requests} from "./request"; import {ReadFileRequest, Requests} from "./request";
import {fetchActionMetadata} from "./utils/action-metadata"; import {getActionsMetadataProvider} from "./utils/action-metadata";
import {TTLCache} from "./utils/cache"; import {TTLCache} from "./utils/cache";
import {timeOperation} from "./utils/timer"; import {timeOperation} from "./utils/timer";
import {valueProviders} from "./value-providers"; import {valueProviders} from "./value-providers";
@@ -108,13 +108,7 @@ export function initConnection(connection: Connection) {
const config: ValidationConfig = { const config: ValidationConfig = {
valueProviderConfig: valueProviders(client, repoContext, cache), valueProviderConfig: valueProviders(client, repoContext, cache),
contextProviderConfig: contextProviders(client, repoContext, cache), contextProviderConfig: contextProviders(client, repoContext, cache),
fetchActionMetadata: async action => { actionsMetadataProvider: getActionsMetadataProvider(client, cache),
if (client) {
return await fetchActionMetadata(client, cache, action);
}
return undefined;
},
fileProvider: getFileProvider(client, cache, repoContext?.workspaceUri, async path => { fileProvider: getFileProvider(client, cache, repoContext?.workspaceUri, async path => {
return await connection.sendRequest(Requests.ReadFile, {path} satisfies ReadFileRequest); return await connection.sendRequest(Requests.ReadFile, {path} satisfies ReadFileRequest);
}) })
@@ -1,10 +1,24 @@
import {actionIdentifier, ActionMetadata, ActionReference} from "@actions/languageservice/action"; import {actionIdentifier, ActionMetadata, ActionReference} from "@actions/languageservice/action";
import {ActionsMetadataProvider} from "@actions/languageservice";
import {error} from "@actions/languageservice/log"; import {error} from "@actions/languageservice/log";
import {Octokit, RestEndpointMethodTypes} from "@octokit/rest"; import {Octokit, RestEndpointMethodTypes} from "@octokit/rest";
import {parse} from "yaml"; import {parse} from "yaml";
import {TTLCache} from "./cache"; import {TTLCache} from "./cache";
import {errorMessage, errorStatus} from "./error"; import {errorMessage, errorStatus} from "./error";
export function getActionsMetadataProvider(
client: Octokit | undefined,
cache: TTLCache
): ActionsMetadataProvider | undefined {
if (!client) {
return undefined;
}
return {
fetchActionMetadata: async action => fetchActionMetadata(client, cache, action)
};
}
export async function fetchActionMetadata( export async function fetchActionMetadata(
client: Octokit, client: Octokit,
cache: TTLCache, cache: TTLCache,
+1 -1
View File
@@ -3,5 +3,5 @@ export {ContextProviderConfig} from "./context-providers/config";
export {documentLinks} from "./document-links"; export {documentLinks} from "./document-links";
export {hover} from "./hover"; export {hover} from "./hover";
export {Logger, LogLevel, registerLogger, setLogLevel} from "./log"; export {Logger, LogLevel, registerLogger, setLogLevel} from "./log";
export {validate, ValidationConfig} from "./validate"; export {validate, ValidationConfig, ActionsMetadataProvider} from "./validate";
export {ValueProviderConfig, ValueProviderKind} from "./value-providers/config"; export {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
+2 -2
View File
@@ -14,7 +14,7 @@ export async function validateAction(
step: Step | undefined, step: Step | undefined,
config: ValidationConfig | undefined config: ValidationConfig | undefined
): Promise<void> { ): Promise<void> {
if (!isMapping(stepToken) || !step || !isActionStep(step) || !config?.fetchActionMetadata) { if (!isMapping(stepToken) || !step || !isActionStep(step) || !config?.actionsMetadataProvider) {
return; return;
} }
@@ -23,7 +23,7 @@ export async function validateAction(
return; return;
} }
const actionMetadata = await config.fetchActionMetadata(action); const actionMetadata = await config.actionsMetadataProvider.fetchActionMetadata(action);
if (actionMetadata === undefined) { if (actionMetadata === undefined) {
diagnostics.push({ diagnostics.push({
severity: DiagnosticSeverity.Error, severity: DiagnosticSeverity.Error,
+81 -64
View File
@@ -14,75 +14,77 @@ beforeEach(() => {
}); });
const validationConfig: ValidationConfig = { const validationConfig: ValidationConfig = {
fetchActionMetadata: (ref: ActionReference) => { actionsMetadataProvider: {
let metadata: ActionMetadata | undefined = undefined; fetchActionMetadata: (ref: ActionReference) => {
switch (ref.owner + "/" + ref.name + "@" + ref.ref) { let metadata: ActionMetadata | undefined = undefined;
case "actions/checkout@v3": switch (ref.owner + "/" + ref.name + "@" + ref.ref) {
metadata = { case "actions/checkout@v3":
name: "Checkout", metadata = {
description: "Checkout a Git repository at a particular version", name: "Checkout",
inputs: { description: "Checkout a Git repository at a particular version",
repository: { inputs: {
description: "Repository name with owner", repository: {
default: "${{ github.repository }}" description: "Repository name with owner",
default: "${{ github.repository }}"
}
} }
} };
}; break;
break; case "actions/setup-node@v1":
case "actions/setup-node@v1": metadata = {
metadata = { name: "Setup Node.js environment",
name: "Setup Node.js environment", description:
description: "Setup a Node.js environment by adding problem matchers and optionally downloading and adding it to the PATH.",
"Setup a Node.js environment by adding problem matchers and optionally downloading and adding it to the PATH.", inputs: {
inputs: { version: {
version: { description: "Deprecated. Use node-version instead. Will not be supported after October 1, 2019",
description: "Deprecated. Use node-version instead. Will not be supported after October 1, 2019", deprecationMessage:
deprecationMessage: "The version property will not be supported after October 1, 2019. Use node-version instead"
"The version property will not be supported after October 1, 2019. Use node-version instead" }
} }
} };
}; break;
break; case "actions/deploy-pages@main":
case "actions/deploy-pages@main": metadata = {
metadata = { name: "Deploy GitHub Pages site",
name: "Deploy GitHub Pages site", description: "A GitHub Action to deploy an artifact as a GitHub Pages site",
description: "A GitHub Action to deploy an artifact as a GitHub Pages site", inputs: {
inputs: { token: {
token: { required: true,
required: true, description: "token to use",
description: "token to use", default: "${{ github.token }}"
default: "${{ github.token }}" }
} }
} };
}; break;
break; case "actions/cache@v1":
case "actions/cache@v1": metadata = {
metadata = { name: "Cache",
name: "Cache", description: "Cache artifacts like dependencies and build outputs to improve workflow execution time",
description: "Cache artifacts like dependencies and build outputs to improve workflow execution time", inputs: {
inputs: { path: {
path: { description: "A directory to store and save the cache",
description: "A directory to store and save the cache", required: true
required: true },
}, key: {
key: { description: "An explicit key for restoring and saving the cache",
description: "An explicit key for restoring and saving the cache", required: true
required: true },
}, "restore-keys": {
"restore-keys": { description: "An ordered list of keys to use for restoring the cache if no cache hit occurred for key",
description: "An ordered list of keys to use for restoring the cache if no cache hit occurred for key", required: false
required: false }
} }
} };
}; break;
break; case "actions/action-no-input@v1":
case "actions/action-no-input@v1": metadata = {
metadata = { name: "Action with no inputs",
name: "Action with no inputs", description: "An action with no inputs"
description: "An action with no inputs" };
}; }
return Promise.resolve(metadata);
} }
return Promise.resolve(metadata);
} }
}; };
@@ -101,6 +103,21 @@ jobs:
expect(result).toEqual([]); expect(result).toEqual([]);
}); });
it("no actionsMetadataProvider", async () => {
const input = `
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/does-not-exist@v3
`;
const config: ValidationConfig = {};
const result = await validate(createDocument("wf.yaml", input), config);
expect(result).toEqual([]);
});
it("action does not exist", async () => { it("action does not exist", async () => {
const input = ` const input = `
on: push on: push
+5 -1
View File
@@ -28,10 +28,14 @@ import {defaultValueProviders} from "./value-providers/default";
export type ValidationConfig = { export type ValidationConfig = {
valueProviderConfig?: ValueProviderConfig; valueProviderConfig?: ValueProviderConfig;
contextProviderConfig?: ContextProviderConfig; contextProviderConfig?: ContextProviderConfig;
fetchActionMetadata?(action: ActionReference): Promise<ActionMetadata | undefined>; actionsMetadataProvider?: ActionsMetadataProvider;
fileProvider?: FileProvider; fileProvider?: FileProvider;
}; };
export type ActionsMetadataProvider = {
fetchActionMetadata(action: ActionReference): Promise<ActionMetadata | undefined>;
};
/** /**
* Validates a workflow file * Validates a workflow file
* *