This commit is contained in:
Christopher Schleiden
2023-04-05 15:17:12 -07:00
parent fb962e6c47
commit db3896d0aa
6 changed files with 102 additions and 8 deletions
+12 -1
View File
@@ -1,4 +1,4 @@
import {documentLinks, hover, validate, ValidationConfig} from "@actions/languageservice"; import {documentLinks, documentSymbols, hover, validate, ValidationConfig} from "@actions/languageservice";
import {registerLogger, setLogLevel} from "@actions/languageservice/log"; import {registerLogger, setLogLevel} from "@actions/languageservice/log";
import {clearCache, clearCacheEntry} from "@actions/languageservice/utils/workflow-cache"; import {clearCache, clearCacheEntry} from "@actions/languageservice/utils/workflow-cache";
import {Octokit} from "@octokit/rest"; import {Octokit} from "@octokit/rest";
@@ -7,6 +7,8 @@ import {
Connection, Connection,
DocumentLink, DocumentLink,
DocumentLinkParams, DocumentLinkParams,
DocumentSymbol,
DocumentSymbolParams,
ExecuteCommandParams, ExecuteCommandParams,
Hover, Hover,
HoverParams, HoverParams,
@@ -72,6 +74,10 @@ export function initConnection(connection: Connection) {
hoverProvider: true, hoverProvider: true,
documentLinkProvider: { documentLinkProvider: {
resolveProvider: false resolveProvider: false
},
documentSymbolProvider: {
label: "GitHub Actions",
workDoneProgress: false
} }
} }
}; };
@@ -158,6 +164,11 @@ export function initConnection(connection: Connection) {
return documentLinks(getDocument(documents, textDocument), repoContext?.workspaceUri); return documentLinks(getDocument(documents, textDocument), repoContext?.workspaceUri);
}); });
connection.onDocumentSymbol(async ({textDocument}: DocumentSymbolParams): Promise<DocumentSymbol[] | null> => {
const repoContext = repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri));
return documentSymbols(getDocument(documents, textDocument), repoContext?.workspaceUri);
});
// Make the text document manager listen on the connection // Make the text document manager listen on the connection
// for open, change and close text document events // for open, change and close text document events
documents.listen(connection); documents.listen(connection);
+70
View File
@@ -0,0 +1,70 @@
import {ErrorPolicy} from "@actions/workflow-parser/model/convert";
import {File} from "@actions/workflow-parser/workflows/file";
import {TextDocument} from "vscode-languageserver-textdocument";
import {DocumentSymbol, SymbolKind} from "vscode-languageserver-types";
import {mapRange} from "./utils/range";
import {fetchOrConvertWorkflowTemplate, fetchOrParseWorkflow} from "./utils/workflow-cache";
export async function documentSymbols(
document: TextDocument,
workspace: string | undefined
): Promise<DocumentSymbol[]> {
const file: File = {
name: document.uri,
content: document.getText()
};
const parsedWorkflow = fetchOrParseWorkflow(file, document.uri);
if (!parsedWorkflow?.value) {
return [];
}
const template = await fetchOrConvertWorkflowTemplate(
parsedWorkflow.context,
parsedWorkflow.value,
document.uri,
undefined,
{
errorPolicy: ErrorPolicy.TryConversion
}
);
if (!template) {
return [];
}
const symbols: DocumentSymbol[] = [];
const onSymbol = DocumentSymbol.create(
"`on` Triggers",
undefined,
SymbolKind.Key,
mapRange(template.events.range),
mapRange(template.events.range)
);
symbols.push(onSymbol);
const jobsSymbol = DocumentSymbol.create(
"Jobs",
undefined,
SymbolKind.Namespace,
mapRange(template.jobs?.[0].id.range),
mapRange(template.jobs?.[0].id.range),
[]
);
symbols.push(jobsSymbol);
for (const job of template.jobs || []) {
const jobSymbol = DocumentSymbol.create(
`Job ${job.name?.toDisplayString() || job.id?.toString()}`,
"detail",
SymbolKind.Class,
mapRange(job.id.range),
mapRange(job.id.range)
);
jobsSymbol.children!.push(jobSymbol);
}
return symbols;
}
+3 -2
View File
@@ -1,7 +1,8 @@
export {complete} from "./complete"; export {complete} from "./complete";
export {ContextProviderConfig} from "./context-providers/config"; export {ContextProviderConfig} from "./context-providers/config";
export {documentLinks} from "./document-links"; export {documentLinks} from "./document-links";
export {documentSymbols} from "./document-symbols";
export {hover} from "./hover"; export {hover} from "./hover";
export {Logger, LogLevel, registerLogger, setLogLevel} from "./log"; export {LogLevel, Logger, registerLogger, setLogLevel} from "./log";
export {validate, ValidationConfig, ActionsMetadataProvider} from "./validate"; export {ActionsMetadataProvider, ValidationConfig, validate} from "./validate";
export {ValueProviderConfig, ValueProviderKind} from "./value-providers/config"; export {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
+4 -2
View File
@@ -9,7 +9,7 @@ import {handleTemplateTokenErrors} from "./converter/handle-errors";
import {convertJobs} from "./converter/jobs"; import {convertJobs} from "./converter/jobs";
import {convertReferencedWorkflow} from "./converter/referencedWorkflow"; import {convertReferencedWorkflow} from "./converter/referencedWorkflow";
import {isReusableWorkflowJob} from "./type-guards"; import {isReusableWorkflowJob} from "./type-guards";
import {WorkflowTemplate} from "./workflow-template"; import {EventsConfig, WorkflowTemplate} from "./workflow-template";
export enum ErrorPolicy { export enum ErrorPolicy {
ReturnErrorsOnly, ReturnErrorsOnly,
@@ -73,7 +73,9 @@ export async function convertWorkflowTemplate(
switch (key.value) { switch (key.value) {
case "on": case "on":
result.events = handleTemplateTokenErrors(root, context, {}, () => convertOn(context, item.value)); result.events = handleTemplateTokenErrors(root, context, {range: item.key.range} as EventsConfig, () =>
convertOn(context, item.value)
);
break; break;
case "jobs": case "jobs":
+10 -3
View File
@@ -23,12 +23,15 @@ export function convertOn(context: TemplateContext, token: TemplateToken): Event
const event = token.assertString("on"); const event = token.assertString("on");
return { return {
range: token.range,
[event.value]: {} [event.value]: {}
} as EventsConfig; } as EventsConfig;
} }
if (isSequence(token)) { if (isSequence(token)) {
const result = {} as EventsConfig; const result = {
range: token.range
} as EventsConfig;
for (const item of token) { for (const item of token) {
const event = item.assertString("on"); const event = item.assertString("on");
@@ -39,7 +42,9 @@ export function convertOn(context: TemplateContext, token: TemplateToken): Event
} }
if (isMapping(token)) { if (isMapping(token)) {
const result = {} as EventsConfig; const result = {
range: token.range
} as EventsConfig;
for (const item of token) { for (const item of token) {
const eventKey = item.key.assertString("event name"); const eventKey = item.key.assertString("event name");
@@ -77,7 +82,9 @@ export function convertOn(context: TemplateContext, token: TemplateToken): Event
} }
context.error(token, "Invalid format for 'on'"); context.error(token, "Invalid format for 'on'");
return {}; return {
range: token.range
} as EventsConfig;
} }
function convertPatternFilter<T extends BranchFilterConfig & TagFilterConfig & PathFilterConfig>( function convertPatternFilter<T extends BranchFilterConfig & TagFilterConfig & PathFilterConfig>(
@@ -6,6 +6,7 @@ import {
StringToken, StringToken,
TemplateToken TemplateToken
} from "../templates/tokens"; } from "../templates/tokens";
import {TokenRange} from "../templates/tokens/token-range";
export type WorkflowTemplate = { export type WorkflowTemplate = {
events: EventsConfig; events: EventsConfig;
@@ -99,6 +100,8 @@ export type ActionStep = BaseStep & {
}; };
export type EventsConfig = { export type EventsConfig = {
range: TokenRange;
schedule?: ScheduleConfig[]; schedule?: ScheduleConfig[];
workflow_dispatch?: WorkflowDispatchConfig; workflow_dispatch?: WorkflowDispatchConfig;
workflow_call?: WorkflowCallConfig; workflow_call?: WorkflowCallConfig;