Merge pull request #188 from github/joshmgross/lint-language-server
Lint the language server package
This commit is contained in:
@@ -43,6 +43,7 @@
|
||||
"@github/actions-languageservice": "^0.1.169",
|
||||
"@github/actions-workflow-parser": "^0.1.169",
|
||||
"@octokit/rest": "^19.0.7",
|
||||
"@octokit/types": "^9.0.0",
|
||||
"vscode-languageserver": "^8.0.2",
|
||||
"vscode-languageserver-textdocument": "^1.0.7",
|
||||
"yaml": "^2.1.3"
|
||||
|
||||
@@ -84,7 +84,7 @@ export async function getSecrets(
|
||||
secretsMap.set(secret.value.toLowerCase(), {
|
||||
key: secret.value,
|
||||
value: new data.StringData("***"),
|
||||
description: `Secret for environment \`${environmentName}\``
|
||||
description: `Secret for environment \`${environmentName || ""}\``
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ export async function getStepsContext(
|
||||
const stepContext = new DescriptionDictionary();
|
||||
for (const {key, value, description} of defaultStepContext.pairs()) {
|
||||
switch (key) {
|
||||
case "outputs":
|
||||
case "outputs": {
|
||||
const outputs = await getActionOutputs(octokit, cache, action);
|
||||
if (!outputs) {
|
||||
stepContext.add(key, value, description);
|
||||
@@ -63,6 +63,7 @@ export async function getStepsContext(
|
||||
}
|
||||
stepContext.add("outputs", outputsDict);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
stepContext.add(key, value, description);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export async function getVariables(
|
||||
variablesMap.set(variable.key.toLowerCase(), {
|
||||
key: variable.key,
|
||||
value: new data.StringData(variable.value.coerceString()),
|
||||
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName}\``
|
||||
description: `${variable.value.coerceString()} - Variable for environment \`${environmentName || ""}\``
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ async function getDescription(mock: fetchMock.FetchMockSandbox) {
|
||||
}
|
||||
}),
|
||||
new TTLCache(),
|
||||
workflowContext.step!
|
||||
workflowContext.step! // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ async function getDescription(input: string, mock: fetchMock.FetchMockSandbox) {
|
||||
}
|
||||
}),
|
||||
new TTLCache(),
|
||||
workflowContext.step!,
|
||||
workflowContext.step!, // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||
new StringToken(undefined, undefined, input, undefined)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
import {WorkflowContext} from "@github/actions-languageservice/context/workflow-context";
|
||||
import {convertWorkflowTemplate, parseWorkflow, TraceWriter} from "@github/actions-workflow-parser";
|
||||
import {convertWorkflowTemplate, NoOperationTraceWriter, parseWorkflow} from "@github/actions-workflow-parser";
|
||||
import {isJob} from "@github/actions-workflow-parser/model/type-guards";
|
||||
|
||||
const nullTrace: TraceWriter = {
|
||||
info: x => {},
|
||||
verbose: x => {},
|
||||
error: x => {}
|
||||
};
|
||||
|
||||
export async function createWorkflowContext(
|
||||
workflow: string,
|
||||
job?: string,
|
||||
stepIndex?: number
|
||||
): Promise<WorkflowContext> {
|
||||
const parsed = parseWorkflow({name: "test.yaml", content: workflow}, nullTrace);
|
||||
const parsed = parseWorkflow({name: "test.yaml", content: workflow}, new NoOperationTraceWriter());
|
||||
if (!parsed.value) {
|
||||
throw new Error("Failed to parse workflow");
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {error} from "@github/actions-languageservice/log";
|
||||
import {Octokit, RestEndpointMethodTypes} from "@octokit/rest";
|
||||
import {parse} from "yaml";
|
||||
import {TTLCache} from "./cache";
|
||||
import {errorMessage, errorStatus} from "./error";
|
||||
|
||||
export async function fetchActionMetadata(
|
||||
client: Octokit,
|
||||
@@ -17,15 +18,15 @@ export async function fetchActionMetadata(
|
||||
}
|
||||
|
||||
// https://docs.github.com/actions/creating-actions/metadata-syntax-for-github-actions
|
||||
return parse(metadata);
|
||||
return parse(metadata) as ActionMetadata;
|
||||
}
|
||||
|
||||
async function getActionMetadata(client: Octokit, action: ActionReference): Promise<string | undefined> {
|
||||
let resp: RestEndpointMethodTypes["repos"]["getContent"]["response"];
|
||||
try {
|
||||
resp = await fetchAction(client, action);
|
||||
} catch (e: any) {
|
||||
error(`Failed to fetch action metadata for ${actionIdentifier(action)}: '${e?.message || "<no details>"}'`);
|
||||
} catch (e) {
|
||||
error(`Failed to fetch action metadata for ${actionIdentifier(action)}: '${errorMessage(e)}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,9 +51,9 @@ async function fetchAction(client: Octokit, action: ActionReference) {
|
||||
ref: action.ref,
|
||||
path: action.path ? `${action.path}/action.yml` : "action.yml"
|
||||
});
|
||||
} catch (e: any) {
|
||||
} catch (e) {
|
||||
// If action.yml doesn't exist, try action.yaml
|
||||
if (e.status === 404) {
|
||||
if (errorStatus(e) === 404) {
|
||||
return await client.repos.getContent({
|
||||
owner: action.owner,
|
||||
repo: action.name,
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import {RequestError} from "@octokit/types";
|
||||
|
||||
export function errorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
if (typeof error === "string") {
|
||||
return error;
|
||||
}
|
||||
|
||||
if ("name" in (error as RequestError)) {
|
||||
return (error as RequestError).name;
|
||||
}
|
||||
|
||||
const status = errorStatus(error);
|
||||
if (status) {
|
||||
return `HTTP ${status}`;
|
||||
}
|
||||
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
export function errorStatus(error: unknown): number | undefined {
|
||||
if ("status" in (error as RequestError)) {
|
||||
return (error as RequestError).status;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import {Octokit} from "@octokit/rest";
|
||||
import {RepositoryContext} from "../initializationOptions";
|
||||
import {TTLCache} from "./cache";
|
||||
import {getUsername} from "./username";
|
||||
import {errorStatus} from "./error";
|
||||
|
||||
export type RepoPermission = "admin" | "write" | "read" | "none";
|
||||
|
||||
@@ -37,8 +38,9 @@ async function fetchRepoPermission(octokit: Octokit, repo: RepositoryContext, us
|
||||
});
|
||||
const permission = res.data?.permission;
|
||||
return permission;
|
||||
} catch (e: any) {
|
||||
if (e.status === 404 || e.status === 403) {
|
||||
} catch (e) {
|
||||
const status = errorStatus(e);
|
||||
if (status === 404 || status === 403) {
|
||||
return "none";
|
||||
}
|
||||
throw e;
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Value} from "@github/actions-languageservice/value-providers/config";
|
||||
import {DEFAULT_RUNNER_LABELS} from "@github/actions-languageservice/value-providers/default";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
import {errorMessage} from "../utils/error";
|
||||
|
||||
// Limitation: getRunnerLabels returns default hosted labels and labels for repository self-hosted runners.
|
||||
// It doesn't return labels for organization runners visible to the repository.
|
||||
@@ -35,7 +36,7 @@ async function fetchRunnerLabels(client: Octokit, owner: string, name: string):
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log(`Failure to retrieve runner labels: ${e}`);
|
||||
log(`Failure to retrieve runner labels: ${errorMessage(e)}`);
|
||||
}
|
||||
|
||||
return labels;
|
||||
|
||||
Reference in New Issue
Block a user