Compare commits

..

12 Commits

Author SHA1 Message Date
Henry Mercer 6a2acd17a0 Update update-release-branch.py to take token from stdin 2026-05-15 14:49:35 +01:00
Henry Mercer ddf64eab51 Read token from stdin in sync-checks.ts
Also allow specifying the token using an environment variable.
2026-05-15 14:33:26 +01:00
Michael B. Gale bbef5ff663 Merge pull request #3904 from github/mbg/esbuild/split-follow-up
Address review comments for #3899
2026-05-15 12:48:02 +00:00
Michael B. Gale 7187b6ecc7 Merge pull request #3906 from github/mergeback/v4.35.5-to-main-9e0d7b8d
Mergeback v4.35.5 refs/heads/releases/v4 into main
2026-05-15 11:50:42 +00:00
github-actions[bot] f1ce9f4421 Rebuild 2026-05-15 11:30:22 +00:00
github-actions[bot] 06c7e6fdd5 Update changelog and version after v4.35.5 2026-05-15 11:24:05 +00:00
Michael B. Gale 064674dfa3 Fix typo
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-15 11:35:47 +01:00
Michael B. Gale ab5047bf8f Add missing semicolons 2026-05-15 11:27:58 +01:00
Michael B. Gale 2320f9d058 "action" to "Action" in build.mjs 2026-05-15 11:26:51 +01:00
Michael B. Gale 46959216a2 Rename analyze-action-env.test.ts to analyze-action.test.ts 2026-05-15 11:25:12 +01:00
Michael B. Gale 9e1f914560 Merge analyze-action-input test into analyze-action-env file
The tests still can't run in parallel so I had to change `test` to `test.serial`, which caused a bunch of formatting changes.
2026-05-15 11:24:28 +01:00
Michael B. Gale db84cb5ccb Remove outdated comments for analyze-action tests 2026-05-15 11:22:17 +01:00
14 changed files with 295 additions and 201 deletions
+13 -8
View File
@@ -16,12 +16,23 @@ No user facing changes.
"""
# NB: This exact commit message is used to find commits for reverting during backports.
# Changing it requires a transition period where both old and new versions are supported.
# Changing it requires a transition period where both old and new versions are supported.
BACKPORT_COMMIT_MESSAGE = 'Update version and changelog for v'
# Name of the remote
ORIGIN = 'origin'
# Environment variables to check for a GitHub API token.
TOKEN_ENVIRONMENT_VARIABLES = ('GH_TOKEN', 'GITHUB_TOKEN')
# Gets a GitHub API token from one of the supported environment variables.
def get_github_token():
for variable_name in TOKEN_ENVIRONMENT_VARIABLES:
token = os.environ.get(variable_name, '').strip()
if token:
return token
raise Exception('Missing GitHub token. Set GITHUB_TOKEN or GH_TOKEN.')
# Runs git with the given args and returns the stdout.
# Raises an error if git does not exit successfully (unless passed
# allow_non_zero_exit_code=True).
@@ -270,12 +281,6 @@ def update_changelog(version):
def main():
parser = argparse.ArgumentParser('update-release-branch.py')
parser.add_argument(
'--github-token',
type=str,
required=True,
help='GitHub token, typically from GitHub Actions.'
)
parser.add_argument(
'--repository-nwo',
type=str,
@@ -313,7 +318,7 @@ def main():
target_branch = args.target_branch
is_primary_release = args.is_primary_release
repo = Github(args.github_token).get_repo(args.repository_nwo)
repo = Github(get_github_token()).get_repo(args.repository_nwo)
# the target branch will be of the form releases/vN, where N is the major version number
target_branch_major_version = target_branch.strip('releases/v')
+4 -2
View File
@@ -64,11 +64,12 @@ jobs:
- name: Update current release branch
if: github.event_name == 'workflow_dispatch'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo SOURCE_BRANCH=${REF_NAME}
echo TARGET_BRANCH=releases/${MAJOR_VERSION}
python .github/update-release-branch.py \
--github-token ${{ secrets.GITHUB_TOKEN }} \
--repository-nwo ${{ github.repository }} \
--source-branch '${{ env.REF_NAME }}' \
--target-branch 'releases/${{ env.MAJOR_VERSION }}' \
@@ -107,11 +108,12 @@ jobs:
- uses: ./.github/actions/release-initialise
- name: Update older release branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo SOURCE_BRANCH=${SOURCE_BRANCH}
echo TARGET_BRANCH=${TARGET_BRANCH}
python .github/update-release-branch.py \
--github-token ${{ secrets.GITHUB_TOKEN }} \
--repository-nwo ${{ github.repository }} \
--source-branch ${SOURCE_BRANCH} \
--target-branch ${TARGET_BRANCH} \
+4
View File
@@ -2,6 +2,10 @@
See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs.
## [UNRELEASED]
No user facing changes.
## 4.35.5 - 15 May 2026
- We have improved how the JavaScript bundles for the CodeQL Action are generated to avoid duplication across bundles and reduce the size of the repository by around 70%. This should have no effect on the runtime behaviour of the CodeQL Action. [#3899](https://github.com/github/codeql-action/pull/3899)
+1 -1
View File
@@ -71,7 +71,7 @@ Once the mergeback and backport pull request have been merged, the release is co
Since the `codeql-action` runs most of its testing through individual Actions workflows, there are over two hundred required jobs that need to pass in order for a PR to turn green. It would be too tedious to maintain that list manually. You can regenerate the set of required checks automatically by running the [sync-checks.ts](pr-checks/sync-checks.ts) script:
- At a minimum, you must provide an argument for the `--token` input. For example, `--token "$(gh auth token)"` to use the same token that `gh` uses. If no token is provided or the token has insufficient permissions, the script will fail.
- At a minimum, you must provide a token with permissions to update branch protection rules. For example, `gh auth token | pr-checks/sync-checks.ts --token-stdin` uses the same token that `gh` uses. You can also set the `GH_TOKEN` or `GITHUB_TOKEN` environment variable. If no token is provided or the token has insufficient permissions, the script will fail.
- By default, the script performs a dry run and outputs information about the changes it would make to the branch protection rules. To actually apply the changes, specify the `--apply` flag.
- If you run the script without any other arguments, it will retrieve the set of workflows that ran for the latest commit on `main`.
- You can specify a different git ref with the `--ref` input. You will likely want to use this if you have a PR that removes or adds PR checks. For example, `--ref "some/branch/name"` to use the HEAD of the `some/branch/name` branch.
+7 -7
View File
@@ -66,8 +66,8 @@ const onEndPlugin = {
const SHARED_ENTRYPOINT = "entry-points";
/**
* This plugin finds all source files that contain action entry points.
* It then generates the virtual `entry-points` module which imports all identifies files,
* This plugin finds all source files that contain Action entry points.
* It then generates the virtual `entry-points` module which imports all identified files,
* and re-exports their `runWrapper` functions with suitable aliases.
* A tiny stub file is emitted for each Action entrypoint. Each stub imports the shared bundle
* and calls the respective entry point.
@@ -83,7 +83,7 @@ const entryPointsPlugin = {
const toPascal = (s) =>
s.replace(/(^|-)([a-z0-9])/gi, (_, __, c) => c.toUpperCase());
// Find the source files containing action entry points.
// Find the source files containing Action entry points.
build.onStart(() => {
const actionFiles = globSync("src/*-action{,-post}.ts");
for (const actionFile of actionFiles) {
@@ -112,7 +112,7 @@ const entryPointsPlugin = {
return { path: SHARED_ENTRYPOINT, namespace };
});
// Generate the virtual `entry-points` file based on the actions we discovered.
// Generate the virtual `entry-points` file based on the Actions we discovered.
// Restrict using the namespace. The path filter does not need to discriminate any further.
build.onLoad({ filter: /.*/, namespace }, async () => {
const wrapperTemplatePath = "entry-wrapper.js.tpl";
@@ -127,7 +127,7 @@ const entryPointsPlugin = {
const imports = actionsSorted
.map(
(action) =>
`import * as ${action.pascalCaseName} from "./src/${basename(action.path)}"`,
`import * as ${action.pascalCaseName} from "./src/${basename(action.path)}";`,
)
.join("\n");
const wrappers = actionsSorted
@@ -143,7 +143,7 @@ const entryPointsPlugin = {
};
});
// Emit entry point stubs for each action using the entry template.
// Emit entry point stubs for each Action using the entry template.
build.onEnd(async (result) => {
// Read the entry point template.
const templatePath = "action-entry.js.tpl";
@@ -152,7 +152,7 @@ const entryPointsPlugin = {
const makeHeader = (sourceFile) =>
`// Automatically generated from '${templatePath}' for 'src/${basename(sourceFile)}'.\n\n`;
// Write entry point stubs for each action.
// Write entry point stubs for each Action.
for (const action of actions) {
await writeFile(
join(
+1 -1
View File
@@ -148304,7 +148304,7 @@ function getDiffRangesJsonFilePath() {
return path2.join(getTemporaryDirectory(), PR_DIFF_RANGE_JSON_FILENAME);
}
function getActionVersion() {
return "4.35.5";
return "4.35.6";
}
function getWorkflowEventName() {
return getRequiredEnvParam("GITHUB_EVENT_NAME");
+1 -1
View File
@@ -88509,7 +88509,7 @@ function getDiffRangesJsonFilePath() {
return path2.join(getTemporaryDirectory(), PR_DIFF_RANGE_JSON_FILENAME);
}
function getActionVersion() {
return "4.35.5";
return "4.35.6";
}
function getWorkflowEventName() {
return getRequiredEnvParam("GITHUB_EVENT_NAME");
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "4.35.5",
"version": "4.35.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "4.35.5",
"version": "4.35.6",
"license": "MIT",
"workspaces": [
"pr-checks"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "4.35.5",
"version": "4.35.6",
"private": true,
"description": "CodeQL action",
"scripts": {
+50 -1
View File
@@ -7,7 +7,13 @@ Tests for the sync-checks.ts script
import * as assert from "node:assert/strict";
import { describe, it } from "node:test";
import { CheckInfo, Exclusions, Options, removeExcluded } from "./sync-checks";
import {
CheckInfo,
Exclusions,
Options,
removeExcluded,
resolveToken,
} from "./sync-checks";
const defaultOptions: Options = {
apply: false,
@@ -58,3 +64,46 @@ describe("removeExcluded", async () => {
assert.deepEqual(retained, expectedExactMatches);
});
});
describe("resolveToken", async () => {
await it("reads the token from standard input", async () => {
const token = await resolveToken(
{ tokenStdin: true },
{ env: {}, readStdin: async () => " stdin-token\n" },
);
assert.equal(token, "stdin-token");
});
await it("reads the token from the GH_TOKEN environment variable", async () => {
const token = await resolveToken(
{},
{ env: { GH_TOKEN: "env-token" }, readStdin: async () => "" },
);
assert.equal(token, "env-token");
});
await it("reads the token from the GITHUB_TOKEN environment variable", async () => {
const token = await resolveToken(
{},
{ env: { GITHUB_TOKEN: "env-token" }, readStdin: async () => "" },
);
assert.equal(token, "env-token");
});
await it("rejects an empty standard input token", async () => {
await assert.rejects(
resolveToken(
{ tokenStdin: true },
{ env: {}, readStdin: async () => "\n" },
),
/No token received on standard input/,
);
});
await it("rejects missing token sources", async () => {
await assert.rejects(
resolveToken({}, { env: {}, readStdin: async () => "" }),
/Missing authentication token/,
);
});
});
+69 -9
View File
@@ -15,8 +15,8 @@ import {
/** Represents the command-line options. */
export interface Options {
/** The token to use to authenticate to the GitHub API. */
token?: string;
/** Whether to read the GitHub API token from standard input. */
tokenStdin?: boolean;
/** The git ref to use the checks for. */
ref?: string;
/** Whether to actually apply the changes or not. */
@@ -31,6 +31,65 @@ const codeqlActionRepo = {
repo: "codeql-action",
};
/** Environment variables to check for a GitHub API token. */
const TOKEN_ENVIRONMENT_VARIABLES = ["GH_TOKEN", "GITHUB_TOKEN"];
/** Represents the sources from which we can retrieve the GitHub API token. */
interface TokenSource {
/** Environment variables to inspect. */
env: NodeJS.ProcessEnv;
/** Reads a token from standard input. */
readStdin: () => Promise<string>;
}
/** Reads the GitHub API token from standard input. */
async function readTokenFromStdin(): Promise<string> {
let token = "";
process.stdin.setEncoding("utf8");
for await (const chunk of process.stdin) {
token += chunk;
}
return token.trim();
}
/** Gets a GitHub API token from one of the supported environment variables. */
function getTokenFromEnvironment(env: NodeJS.ProcessEnv): string | undefined {
for (const variableName of TOKEN_ENVIRONMENT_VARIABLES) {
const token = env[variableName]?.trim();
if (token) {
return token;
}
}
return undefined;
}
/** Gets the token to use to authenticate to the GitHub API. */
export async function resolveToken(
options: Pick<Options, "tokenStdin">,
tokenSource: TokenSource = {
env: process.env,
readStdin: readTokenFromStdin,
},
): Promise<string> {
if (options.tokenStdin) {
const token = (await tokenSource.readStdin()).trim();
if (token.length === 0) {
throw new Error("No token received on standard input.");
}
return token;
}
const environmentToken = getTokenFromEnvironment(tokenSource.env);
if (environmentToken !== undefined) {
return environmentToken;
}
throw new Error(
"Missing authentication token. Set GH_TOKEN/GITHUB_TOKEN or pipe a token " +
"to --token-stdin.",
);
}
/** Represents a configuration of which checks should not be set up as required checks. */
export interface Exclusions {
/** A list of strings that, if contained in a check name, are excluded. */
@@ -205,9 +264,10 @@ async function updateBranch(
async function main(): Promise<void> {
const { values: options } = parseArgs({
options: {
// The token to use to authenticate to the API.
token: {
type: "string",
// Read the token to use to authenticate to the API from standard input.
"token-stdin": {
type: "boolean",
default: false,
},
// The git ref for which to retrieve the check runs.
ref: {
@@ -228,16 +288,16 @@ async function main(): Promise<void> {
strict: true,
});
if (options.token === undefined) {
throw new Error("Missing --token");
}
const token = await resolveToken({
tokenStdin: options["token-stdin"],
});
console.info(
`Oldest supported major version is: ${OLDEST_SUPPORTED_MAJOR_VERSION}`,
);
// Initialise the API client.
const client = getApiClient(options.token);
const client = getApiClient(token);
// Find the check runs for the specified `ref` that we will later set as the required checks
// for the main and release branches.
-85
View File
@@ -1,85 +0,0 @@
import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import * as analyze from "./analyze";
import { runWrapper } from "./analyze-action";
import * as api from "./api-client";
import * as configUtils from "./config-utils";
import * as gitUtils from "./git-utils";
import * as statusReport from "./status-report";
import {
setupTests,
setupActionsVars,
mockFeatureFlagApiEndpoint,
} from "./testing-utils";
import * as util from "./util";
setupTests(test);
// This test needs to be in its own file so that ava would run it in its own
// nodejs process. The code being tested is in analyze-action.ts, which runs
// immediately on load. So the file needs to be loaded during part of the test,
// and that can happen only once per nodejs process. If multiple such tests are
// in the same test file, ava would run them in the same nodejs process, and all
// but the first test would fail.
test("analyze action with RAM & threads from environment variables", async (t) => {
// This test frequently times out on Windows with the default timeout, so we bump
// it a bit to 20s.
t.timeout(1000 * 20);
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
sinon
.stub(statusReport, "createStatusReportBase")
.resolves({} as statusReport.StatusReportBase);
sinon.stub(statusReport, "sendStatusReport").resolves();
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
const gitHubVersion: util.GitHubVersion = {
type: util.GitHubVariant.DOTCOM,
};
sinon.stub(configUtils, "getConfig").resolves({
gitHubVersion,
augmentationProperties: {},
languages: [],
packs: [],
trapCaches: {},
} as unknown as configUtils.Config);
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub.withArgs("token").returns("fake-token");
requiredInputStub.withArgs("upload-database").returns("false");
requiredInputStub.withArgs("output").returns("out");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("expect-error").returns("false");
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
mockFeatureFlagApiEndpoint(200, {});
// When there are no action inputs for RAM and threads, the action uses
// environment variables (passed down from the init action) to set RAM and
// threads usage.
process.env["CODEQL_THREADS"] = "-1";
process.env["CODEQL_RAM"] = "4992";
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
const runQueriesStub = sinon.stub(analyze, "runQueries");
await runWrapper();
t.assert(
runFinalizeStub.calledOnceWith(
sinon.match.any,
sinon.match.any,
"--threads=-1",
"--ram=4992",
),
);
t.assert(
runQueriesStub.calledOnceWith(
sinon.match.any,
"--ram=4992",
"--threads=-1",
),
);
});
});
-83
View File
@@ -1,83 +0,0 @@
import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import * as analyze from "./analyze";
import { runWrapper } from "./analyze-action";
import * as api from "./api-client";
import * as configUtils from "./config-utils";
import * as gitUtils from "./git-utils";
import * as statusReport from "./status-report";
import {
setupTests,
setupActionsVars,
mockFeatureFlagApiEndpoint,
} from "./testing-utils";
import * as util from "./util";
setupTests(test);
// This test needs to be in its own file so that ava would run it in its own
// nodejs process. The code being tested is in analyze-action.ts, which runs
// immediately on load. So the file needs to be loaded during part of the test,
// and that can happen only once per nodejs process. If multiple such tests are
// in the same test file, ava would run them in the same nodejs process, and all
// but the first test would fail.
test("analyze action with RAM & threads from action inputs", async (t) => {
t.timeout(1000 * 20);
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
sinon
.stub(statusReport, "createStatusReportBase")
.resolves({} as statusReport.StatusReportBase);
sinon.stub(statusReport, "sendStatusReport").resolves();
const gitHubVersion: util.GitHubVersion = {
type: util.GitHubVariant.DOTCOM,
};
sinon.stub(configUtils, "getConfig").resolves({
gitHubVersion,
augmentationProperties: {},
languages: [],
packs: [],
trapCaches: {},
} as unknown as configUtils.Config);
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub.withArgs("token").returns("fake-token");
requiredInputStub.withArgs("upload-database").returns("false");
requiredInputStub.withArgs("output").returns("out");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("expect-error").returns("false");
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
mockFeatureFlagApiEndpoint(200, {});
process.env["CODEQL_THREADS"] = "1";
process.env["CODEQL_RAM"] = "4992";
// Action inputs have precedence over environment variables.
optionalInputStub.withArgs("threads").returns("-1");
optionalInputStub.withArgs("ram").returns("3012");
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
const runQueriesStub = sinon.stub(analyze, "runQueries");
await runWrapper();
t.assert(
runFinalizeStub.calledOnceWith(
sinon.match.any,
sinon.match.any,
"--threads=-1",
"--ram=3012",
),
);
t.assert(
runQueriesStub.calledOnceWith(
sinon.match.any,
"--ram=3012",
"--threads=-1",
),
);
});
});
+142
View File
@@ -0,0 +1,142 @@
import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import * as analyze from "./analyze";
import { runWrapper } from "./analyze-action";
import * as api from "./api-client";
import * as configUtils from "./config-utils";
import * as gitUtils from "./git-utils";
import * as statusReport from "./status-report";
import {
setupTests,
setupActionsVars,
mockFeatureFlagApiEndpoint,
} from "./testing-utils";
import * as util from "./util";
setupTests(test);
test.serial(
"analyze action with RAM & threads from environment variables",
async (t) => {
// This test frequently times out on Windows with the default timeout, so we bump
// it a bit to 20s.
t.timeout(1000 * 20);
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
sinon
.stub(statusReport, "createStatusReportBase")
.resolves({} as statusReport.StatusReportBase);
sinon.stub(statusReport, "sendStatusReport").resolves();
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
const gitHubVersion: util.GitHubVersion = {
type: util.GitHubVariant.DOTCOM,
};
sinon.stub(configUtils, "getConfig").resolves({
gitHubVersion,
augmentationProperties: {},
languages: [],
packs: [],
trapCaches: {},
} as unknown as configUtils.Config);
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub.withArgs("token").returns("fake-token");
requiredInputStub.withArgs("upload-database").returns("false");
requiredInputStub.withArgs("output").returns("out");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("expect-error").returns("false");
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
mockFeatureFlagApiEndpoint(200, {});
// When there are no action inputs for RAM and threads, the action uses
// environment variables (passed down from the init action) to set RAM and
// threads usage.
process.env["CODEQL_THREADS"] = "-1";
process.env["CODEQL_RAM"] = "4992";
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
const runQueriesStub = sinon.stub(analyze, "runQueries");
await runWrapper();
t.assert(
runFinalizeStub.calledOnceWith(
sinon.match.any,
sinon.match.any,
"--threads=-1",
"--ram=4992",
),
);
t.assert(
runQueriesStub.calledOnceWith(
sinon.match.any,
"--ram=4992",
"--threads=-1",
),
);
});
},
);
test.serial(
"analyze action with RAM & threads from action inputs",
async (t) => {
t.timeout(1000 * 20);
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
sinon
.stub(statusReport, "createStatusReportBase")
.resolves({} as statusReport.StatusReportBase);
sinon.stub(statusReport, "sendStatusReport").resolves();
const gitHubVersion: util.GitHubVersion = {
type: util.GitHubVariant.DOTCOM,
};
sinon.stub(configUtils, "getConfig").resolves({
gitHubVersion,
augmentationProperties: {},
languages: [],
packs: [],
trapCaches: {},
} as unknown as configUtils.Config);
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub.withArgs("token").returns("fake-token");
requiredInputStub.withArgs("upload-database").returns("false");
requiredInputStub.withArgs("output").returns("out");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("expect-error").returns("false");
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
mockFeatureFlagApiEndpoint(200, {});
process.env["CODEQL_THREADS"] = "1";
process.env["CODEQL_RAM"] = "4992";
// Action inputs have precedence over environment variables.
optionalInputStub.withArgs("threads").returns("-1");
optionalInputStub.withArgs("ram").returns("3012");
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
const runQueriesStub = sinon.stub(analyze, "runQueries");
await runWrapper();
t.assert(
runFinalizeStub.calledOnceWith(
sinon.match.any,
sinon.match.any,
"--threads=-1",
"--ram=3012",
),
);
t.assert(
runQueriesStub.calledOnceWith(
sinon.match.any,
"--ram=3012",
"--threads=-1",
),
);
});
},
);