Merge branch 'main' into mario-campos/cache-cli-resolve-langs

# Conflicts:
#	lib/entry-points.js
#	src/codeql.ts
#	src/environment.ts
#	src/status-report.ts
This commit is contained in:
Mario Campos
2026-07-09 15:02:03 -05:00
126 changed files with 18417 additions and 16116 deletions

View File

@@ -10,6 +10,7 @@ import test, {
import nock from "nock";
import * as sinon from "sinon";
import { ActionState, StateFeature } from "./action-common";
import { ActionsEnv, getActionVersion } from "./actions-util";
import { AnalysisKind } from "./analyses";
import * as apiClient from "./api-client";
@@ -20,6 +21,7 @@ import { resetCachedCommandOutputs } from "./cli/output-cache";
import * as codeql from "./codeql";
import { Config } from "./config-utils";
import * as defaults from "./defaults.json";
import { Env, ActionsEnvVars } from "./environment";
import {
CodeQLDefaultVersionInfo,
Feature,
@@ -28,9 +30,11 @@ 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,
getEnv,
GitHubVariant,
GitHubVersion,
HTTPError,
@@ -173,6 +177,11 @@ export function makeMacro<Args extends unknown[]>(
return wrapper;
}
export function getTestEnv(): Env {
const testEnv: NodeJS.ProcessEnv = {};
return getEnv(testEnv);
}
/**
* Gets an `ActionsEnv` instance for use in tests.
*/
@@ -182,6 +191,116 @@ export function getTestActionsEnv(): ActionsEnv {
};
}
/** For testing purposes, we make all available state features accessible in `TestEnv`. */
type AllState = ["Logger", "Env", "Actions", "FeatureFlags"];
/** Initialise a fresh `ActionState<AllState>` value. */
export function initAllState(
overrides?: Partial<ActionState<AllState>>,
): ActionState<AllState> {
return {
name: ActionName.Init,
startedAt: new Date(),
logger: new RecordingLogger(),
env: getTestEnv(),
actions: getTestActionsEnv(),
features: createFeatures([]),
...overrides,
};
}
/**
* Wraps a function that accepts an `ActionState` for testing in different environments.
*/
export class TestEnv<
Args extends readonly any[],
R,
Fs extends ReadonlyArray<AllState[number]>,
> {
private readonly fn: (state: ActionState<Fs>, ...args: Args) => R;
private args?: Args;
private logger: RecordingLogger;
private state: ActionState<AllState>;
constructor(
fn: (state: ActionState<Fs>, ...args: Args) => R,
cloneFrom?: TestEnv<Args, R, Fs>,
) {
this.fn = fn;
this.args = cloneFrom?.args;
this.logger = new RecordingLogger();
this.state =
cloneFrom !== undefined
? { ...cloneFrom.state, logger: this.logger }
: initAllState({ logger: this.logger });
}
private clone(): TestEnv<Args, R, Fs> {
return new TestEnv(this.fn, this);
}
public getLogger(): RecordingLogger {
return this.logger;
}
public getState(): ActionState<AllState> {
return this.state;
}
public getArgs(): Args | undefined {
return this.args;
}
public withArgs(...args: Args) {
const result = this.clone();
result.args = args;
return result;
}
public withFeatures(enabled: Feature[]): TestEnv<Args, R, Fs> {
const result = this.clone();
result.state.features = createFeatures(enabled);
return result;
}
public withEnv(env: Env): TestEnv<Args, R, Fs> {
const result = this.clone();
result.state.env = env;
return result;
}
public withActions(actions: ActionsEnv): TestEnv<Args, R, Fs> {
const result = this.clone();
result.state.actions = actions;
return result;
}
call(): R {
if (!this.args) {
throw new Error("Trying to call function in TestEnv without arguments.");
}
return this.fn(this.state as unknown as ActionState<Fs>, ...this.args);
}
public passes<T>(
assertion: (makeCall: () => R) => T | Promise<T>,
): T | Promise<T> {
return assertion(() => {
const result = this.call();
return result;
});
}
}
/** Utility function to construct a `TestEnv`. */
export function callee<
Args extends readonly any[],
R,
Fs extends readonly StateFeature[],
>(fn: (state: ActionState<Fs>, ...args: Args) => R): TestEnv<Args, R, Fs> {
return new TestEnv(fn);
}
/**
* Default values for environment variables typically set in an Actions
* environment. Tests can override individual variables by passing them in the
@@ -201,7 +320,7 @@ export const DEFAULT_ACTIONS_VARS = {
GITHUB_WORKFLOW: "test-workflow",
RUNNER_NAME: "my-runner",
RUNNER_OS: "Linux",
} as const satisfies Record<string, string>;
} as const satisfies Partial<Record<ActionsEnvVars, string>>;
/** Partial mappings from GitHub Actions environment variables to values. */
export type ActionVarOverrides = Partial<
@@ -213,11 +332,15 @@ export type ActionVarOverrides = Partial<
* excluding some that are expected to be set to paths. See `setupActionsVars`.
*
* @param overrides Overrides for the defaults.
* @param env The environment to set the variables for.
*/
export function setupBaseActionsVars(overrides?: ActionVarOverrides) {
export function setupBaseActionsVars(
overrides?: ActionVarOverrides,
env: Env = getEnv(),
) {
const vars = { ...DEFAULT_ACTIONS_VARS, ...overrides };
for (const [key, value] of Object.entries(vars)) {
process.env[key] = value;
env.set(key, value);
}
}