Add common entry point

This commit is contained in:
Michael B. Gale
2026-07-01 17:45:56 +01:00
parent b009eac559
commit 9c16c3b47b
2 changed files with 54 additions and 7 deletions

View File

@@ -1,7 +1,19 @@
import { ActionsEnv } from "./actions-util";
import * as core from "@actions/core";
import { ActionsEnv, getActionsEnv } from "./actions-util";
import { Env } from "./environment";
import { FeatureEnablement } from "./feature-flags";
import { Logger } from "./logging";
import { getActionsLogger, Logger } from "./logging";
import { ActionName, sendUnhandledErrorStatusReport } from "./status-report";
import { getEnv, getErrorMessage } from "./util";
/** Common state that is always available in `ActionState`. */
export interface BaseState {
/** The name of the Action. */
name: ActionName;
/** When the Action was started. */
startedAt: Date;
}
/** Describes different state features that an Action may have. */
export interface FeatureState {
@@ -27,10 +39,8 @@ export interface FeatureState {
export type StateFeature = keyof FeatureState;
/** Constructs the union of all state types identifies by `Fs`. */
export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends [
infer Head extends StateFeature,
]
? FeatureState[Head]
export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends []
? BaseState
: Fs extends [
infer Head extends StateFeature,
...infer Tail extends StateFeature[],
@@ -40,3 +50,37 @@ export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends [
/** Describes the state of an Action that has access to the state corresponding to `Fs`. */
export type ActionState<Fs extends readonly StateFeature[]> = FieldsOf<Fs>;
/** The type of an Action's main entry point. */
export type ActionMain = (
state: ActionState<["Logger", "Env", "Actions"]>,
) => Promise<void>;
/** A specification for a CodeQL Action step. */
export interface Action {
/** The name of the Action. */
name: ActionName;
/** The entry point for the Action. */
run: ActionMain;
}
/** A generic entry point that sets up the environment for the `action` and runs it. */
export async function runInActions(action: Action) {
const startedAt = new Date();
const logger = getActionsLogger();
const env = getEnv();
const actionsEnv = getActionsEnv();
try {
await action.run({
name: action.name,
startedAt,
logger,
env,
actions: actionsEnv,
});
} catch (error) {
core.setFailed(`${action.name} action failed: ${getErrorMessage(error)}`);
await sendUnhandledErrorStatusReport(action.name, startedAt, error, logger);
}
}

View File

@@ -33,6 +33,7 @@ import {
} from "./feature-flags";
import { Logger } from "./logging";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
import { ActionName } from "./status-report";
import {
DEFAULT_DEBUG_ARTIFACT_NAME,
DEFAULT_DEBUG_DATABASE_NAME,
@@ -221,6 +222,8 @@ export class TestEnv<
cloneFrom !== undefined
? { ...cloneFrom.state }
: {
name: ActionName.Init,
startedAt: new Date(),
logger: new RecordingLogger(),
env: getTestEnv(),
actions: getActionsEnv(),
@@ -272,7 +275,7 @@ export class TestEnv<
if (!this.args) {
throw new Error("Trying to call function in TestEnv without arguments.");
}
return this.fn(this.state as ActionState<Fs>, ...this.args);
return this.fn(this.state as unknown as ActionState<Fs>, ...this.args);
}
public passes<T>(