mirror of
https://github.com/github/codeql-action.git
synced 2026-10-10 04:35:26 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4e9b269fe | ||
|
|
6e7fe2e990 | ||
|
|
fa56eef12f | ||
|
|
71f2680f85 | ||
|
|
3b399fec34 | ||
|
|
5532d8e11e | ||
|
|
68f5b579fa | ||
|
|
45cda5b577 | ||
|
|
e57c0e65dd | ||
|
|
1ced68ed2f | ||
|
|
13b1321685 | ||
|
|
cc826bb8e3 | ||
|
|
40d76bc727 | ||
|
|
bd97dda6bf | ||
|
|
d6196d8703 | ||
|
|
3acc10a2ce | ||
|
|
2a935ca93d | ||
|
|
5aa5056e2d | ||
|
|
ea60dc6408 | ||
|
|
ce3f825b1d | ||
|
|
38fee79b02 | ||
|
|
ebd711ff66 | ||
|
|
75ea4cb2e4 | ||
|
|
59ff83ecef | ||
|
|
1728f0c676 | ||
|
|
63c5299790 | ||
|
|
39f1b3fa8d | ||
|
|
d5b1e793ce |
@@ -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.38.3 - 08 Oct 2026
|
||||
|
||||
- _Upcoming breaking change_: CodeQL version 2.21.2 and earlier were discontinued on 24 September 2026 alongside GitHub Enterprise Server 3.17, and will be unsupported by the next minor release of the CodeQL Action. Added a deprecation warning for customers using these versions of CodeQL. [#4188](https://github.com/github/codeql-action/pull/4188)
|
||||
|
||||
@@ -53,6 +53,7 @@ Here are a few things you can do that will increase the likelihood of your pull
|
||||
- Write tests.
|
||||
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
|
||||
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
||||
- For user-facing changes, add a change-note file. See [unreleased-change-notes/README.md](unreleased-change-notes/README.md).
|
||||
|
||||
## Releasing (write access required)
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import pkg from "./package.json" with { type: "json" };
|
||||
|
||||
globalThis.__CODEQL_ACTION_VERSION__ = pkg.version;
|
||||
globalThis.__CODEQL_ACTION_TEST_ENV__ = "unit-test";
|
||||
|
||||
@@ -78,7 +78,7 @@ const UPLOAD_LIB_SRC = "./src/upload-lib";
|
||||
*
|
||||
* The virtual module additionally re-exports `upload-lib` under the `uploadLib` namespace so that
|
||||
* external consumers can access it via the small `lib/upload-lib.js` stub emitted below.
|
||||
*
|
||||
*
|
||||
* A tiny stub file is emitted for each Action entrypoint, and one for `upload-lib`. Each stub
|
||||
* imports the shared bundle and calls/re-exports from the respective entry point.
|
||||
*
|
||||
@@ -212,6 +212,7 @@ const context = await esbuild.context({
|
||||
target: ["node20"],
|
||||
define: {
|
||||
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),
|
||||
__CODEQL_ACTION_TEST_ENV__: JSON.stringify(""),
|
||||
},
|
||||
metafile: true,
|
||||
});
|
||||
|
||||
@@ -140,6 +140,17 @@ export default [
|
||||
"no-async-foreach/no-async-foreach": "error",
|
||||
"no-sequences": "error",
|
||||
"no-shadow": "off",
|
||||
|
||||
// A basic check that we don't use `exportVariable` from `@actions/core`.
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
selector: "MemberExpression[property.name='exportVariable']",
|
||||
message:
|
||||
"Use the `export` method of an `Env` instance or `exportEnvVar` from `environment.ts` instead.",
|
||||
},
|
||||
],
|
||||
|
||||
// This is overly restrictive with unsetting `EnvVar`s
|
||||
"@typescript-eslint/no-dynamic-delete": "off",
|
||||
"@typescript-eslint/no-shadow": "error",
|
||||
@@ -157,6 +168,15 @@ export default [
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["src/environment.ts"],
|
||||
|
||||
// We allow `exportVariable` from `@actions/core` to be used in this file
|
||||
// since it defines the wrapper around it that other modules use.
|
||||
rules: {
|
||||
"no-restricted-syntax": "off",
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["**/*.ts", "**/*.js"],
|
||||
|
||||
|
||||
950
lib/entry-points.js
generated
950
lib/entry-points.js
generated
File diff suppressed because it is too large
Load Diff
14
package-lock.json
generated
14
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.38.3",
|
||||
"version": "4.38.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codeql",
|
||||
"version": "4.38.3",
|
||||
"version": "4.38.4",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"pr-checks"
|
||||
@@ -58,7 +58,7 @@
|
||||
"eslint-import-resolver-typescript": "^4.4.5",
|
||||
"eslint-plugin-github": "^6.1.2",
|
||||
"eslint-plugin-import-x": "^4.17.1",
|
||||
"eslint-plugin-jsdoc": "^64.5.4",
|
||||
"eslint-plugin-jsdoc": "^65.0.1",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^13.0.6",
|
||||
"globals": "^17.12.0",
|
||||
@@ -5381,15 +5381,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jsdoc": {
|
||||
"version": "64.5.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-64.5.4.tgz",
|
||||
"integrity": "sha512-xfRhXPSSWT612muJ6XTvxuVJ8zYHv99qNgBqPVqF28aSqoy4s4XbSkrWXnYA2hl5ejC02yEpk6fqkj3BmJ6Xbg==",
|
||||
"version": "65.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-65.0.1.tgz",
|
||||
"integrity": "sha512-7IvB+ZS71WCw5tGKh6f6D5k55qtXKdrGTnIpQTBKWdpyZ5IfhGHfh0i6ArWlCJ4JEtz22YRk5Bqu1MvbOlpMKQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@es-joy/jsdoccomment": "~0.98.0",
|
||||
"@es-joy/resolve.exports": "1.2.0",
|
||||
"@typescript-eslint/utils": "^8.70.0",
|
||||
"@typescript-eslint/utils": "^8.70.1",
|
||||
"are-docs-informative": "^0.1.1",
|
||||
"comment-parser": "1.4.9",
|
||||
"debug": "^4.4.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.38.3",
|
||||
"version": "4.38.4",
|
||||
"private": true,
|
||||
"description": "CodeQL action",
|
||||
"scripts": {
|
||||
@@ -66,7 +66,7 @@
|
||||
"eslint-import-resolver-typescript": "^4.4.5",
|
||||
"eslint-plugin-github": "^6.1.2",
|
||||
"eslint-plugin-import-x": "^4.17.1",
|
||||
"eslint-plugin-jsdoc": "^64.5.4",
|
||||
"eslint-plugin-jsdoc": "^65.0.1",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^13.0.6",
|
||||
"globals": "^17.12.0",
|
||||
|
||||
@@ -154,26 +154,6 @@ await describe("isValidChangenoteFile", async () => {
|
||||
assert.equal(isValidChangenoteFile("non-existent-file.md"), false);
|
||||
});
|
||||
|
||||
await it("rejects invalid filename", async () => {
|
||||
await withTmpFile(
|
||||
"fix-bug.md",
|
||||
"---\ncategory: fix\n---\n- Fixed a bug\n",
|
||||
(filePath) => {
|
||||
assert.equal(isValidChangenoteFile(filePath), false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
await it("rejects missing frontmatter", async () => {
|
||||
await withTmpFile(
|
||||
"2026-01-01-fix-bug.md",
|
||||
"- Fixed a bug\n",
|
||||
(filePath) => {
|
||||
assert.equal(isValidChangenoteFile(filePath), false);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
await it("rejects invalid Markdown", async () => {
|
||||
await withTmpFile(
|
||||
"2026-01-01-fix-bug.md",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
|
||||
import { matter } from "lite-matter";
|
||||
import type { List, ListItem } from "mdast";
|
||||
@@ -95,21 +94,7 @@ export function isValidChangenoteFile(filename: string): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { data: frontmatter, content } = matter(fileData);
|
||||
|
||||
if (!isValidChangenoteFilename(path.basename(filename))) {
|
||||
isValid = false;
|
||||
console.error(
|
||||
`${filename}: invalid filename; must match pattern YYYY-MM-DD-id.md`,
|
||||
);
|
||||
}
|
||||
if (!hasValidChangenoteCategory(frontmatter)) {
|
||||
isValid = false;
|
||||
const categories = Object.keys(VALID_CHANGE_NOTE_CATEGORIES).join(", ");
|
||||
console.error(
|
||||
`${filename}: invalid category; must be one of: ${categories}`,
|
||||
);
|
||||
}
|
||||
const { content } = matter(fileData);
|
||||
if (!isValidChangenoteContent(content)) {
|
||||
isValid = false;
|
||||
console.error(
|
||||
|
||||
@@ -28,12 +28,12 @@ interface ChangenoteFile {
|
||||
|
||||
/**
|
||||
* Returns the absolute file paths of all files in
|
||||
* {@link CHANGENOTES_DIR} (except ".gitkeep").
|
||||
* {@link CHANGENOTES_DIR} (except ".gitkeep" and "README.md").
|
||||
* */
|
||||
function listUnreleasedChangenoteDir(): string[] {
|
||||
return fs
|
||||
.readdirSync(CHANGENOTES_DIR)
|
||||
.filter((name) => name !== ".gitkeep")
|
||||
.filter((name) => ![".gitkeep", "README.md"].includes(name))
|
||||
.map((name) => path.join(CHANGENOTES_DIR, name));
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ predicate isSafeForDefaultSetup(string envVar) {
|
||||
"GITHUB_BASE_REF", "GITHUB_EVENT_NAME", "GITHUB_JOB", "GITHUB_RUN_ATTEMPT", "GITHUB_RUN_ID",
|
||||
"GITHUB_SHA", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_TOKEN", "GITHUB_WORKFLOW",
|
||||
"GITHUB_WORKSPACE", "GOFLAGS", "ImageVersion", "JAVA_TOOL_OPTIONS", "RUNNER_ARCH",
|
||||
"RUNNER_ENVIRONMENT", "RUNNER_NAME", "RUNNER_OS", "RUNNER_TEMP", "RUNNER_TOOL_CACHE"
|
||||
"RUNNER_ENVIRONMENT", "RUNNER_NAME", "RUNNER_OS", "RUNNER_TEMP", "RUNNER_TOOL_CACHE",
|
||||
"NODE_ENV"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,29 @@ export interface FeatureState {
|
||||
/** Identifies a type of state an Action may have. */
|
||||
export type StateFeature = keyof FeatureState;
|
||||
|
||||
/**
|
||||
* The `Env` feature implies the availability of the `ReadOnlyEnv` feature.
|
||||
*
|
||||
* If `T` is `Env`, this returns `Env | ReadOnlyEnv`.
|
||||
* Otherwise, it is the identity and returns T.
|
||||
*/
|
||||
type ImpliedFeatures<T extends StateFeature> = T extends "Env"
|
||||
? "Env" | "ReadOnlyEnv"
|
||||
: T;
|
||||
|
||||
/**
|
||||
* Given an object type `Obj`, this tries to lookup a corresponding `StateFeature`
|
||||
* to which the object type belongs in `FeatureState`. Resolves to `never` if there
|
||||
* is no match.
|
||||
*/
|
||||
type FeatureNameFor<Obj extends object> = {
|
||||
[K in StateFeature]: [Obj] extends [FeatureState[K]]
|
||||
? [FeatureState[K]] extends [Obj]
|
||||
? K
|
||||
: never
|
||||
: never;
|
||||
}[StateFeature];
|
||||
|
||||
/** Constructs the intersection of all state types identifies by `Fs`. */
|
||||
export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends []
|
||||
? Record<never, never>
|
||||
@@ -66,8 +89,54 @@ export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends []
|
||||
? FeatureState[Head] & FieldsOf<Tail>
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Symbol used for a field in `ActionState` that carries the type array of state features.
|
||||
* This is a Symbol so that it doesn't clash with any property names we might want to have.
|
||||
*/
|
||||
const stateFeatures = Symbol();
|
||||
|
||||
/** Describes the state of an Action that has access to the state corresponding to `Fs`. */
|
||||
export type ActionState<Fs extends readonly StateFeature[]> = FieldsOf<Fs>;
|
||||
export type ActionState<Fs extends readonly StateFeature[]> = FieldsOf<Fs> & {
|
||||
/**
|
||||
* When given a chance, TypeScript will simplify an `ActionState<Fs>` type as much as possible,
|
||||
* which results in a concrete object type that doesn't mention `Fs`.
|
||||
*
|
||||
* That causes problems for functions which accept `ActionState<Fs>` values, but need to know the
|
||||
* feature keys `Fs`. This property here explicitly captures `Fs` in the concrete object type
|
||||
* that results from simplifying `ActionState<Fs>`.
|
||||
*
|
||||
* This is a function rather than a field, because we want to be able to provide values of type
|
||||
* `ActionState<Fs>` to functions expecting `ActionState<As>` where `As` is a subset of `Fs`.
|
||||
*
|
||||
* Since function types are contravariant in the types of their parameters, using a function
|
||||
* type here allows that to happen.
|
||||
*
|
||||
* Because the field is optional, we don't have to explicitly provide a value
|
||||
* for it anywhere while the type is still inferred.
|
||||
*
|
||||
* `Fs[number]` returns the union of all features in `Fs`. We wrap it in `ImpliedFeatures`
|
||||
* so that `Env` is expanded into `Env | ReadOnlyEnv`, allowing functions that expect the
|
||||
* `ReadOnlyEnv` feature to be provided with an `ActionState` that has the `Env` feature
|
||||
* without requiring this to be made explicit.
|
||||
*/
|
||||
readonly [stateFeatures]?: (ts: ImpliedFeatures<Fs[number]>) => void;
|
||||
};
|
||||
|
||||
/** Extends `state` with an `extra` feature. */
|
||||
export function extendActionState<
|
||||
// In first position, so that it can be explicitly provided if `FeatureNameFor`
|
||||
// should not work on `extra`.
|
||||
F extends StateFeature,
|
||||
Fs extends readonly StateFeature[],
|
||||
E extends FeatureState[F],
|
||||
>(
|
||||
state: ActionState<Fs>,
|
||||
extra: E,
|
||||
): ActionState<[...Fs, FeatureNameFor<E> & F]> {
|
||||
return { ...state, ...extra } as unknown as ActionState<
|
||||
[...Fs, FeatureNameFor<E> & F]
|
||||
>;
|
||||
}
|
||||
|
||||
/** The type of an Action's main entry point. This is a function that is provided
|
||||
* with a basic `ActionState` object with features that are always available.
|
||||
|
||||
@@ -30,7 +30,6 @@ declare const __CODEQL_ACTION_VERSION__: string;
|
||||
export interface ActionsEnv {
|
||||
getRequiredInput: (name: string) => string;
|
||||
getOptionalInput: (name: string) => string | undefined;
|
||||
exportVariable: (name: string, value: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +39,6 @@ export function getActionsEnv(): ActionsEnv {
|
||||
return {
|
||||
getRequiredInput,
|
||||
getOptionalInput,
|
||||
exportVariable: core.exportVariable,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -214,9 +214,10 @@ async function runAutobuildIfLegacyGoWorkflow(config: Config, logger: Logger) {
|
||||
|
||||
async function run({
|
||||
startedAt,
|
||||
env,
|
||||
logger,
|
||||
actions,
|
||||
}: ActionState<["Base", "Logger", "Actions"]>) {
|
||||
}: ActionState<["Base", "Env", "Logger", "Actions"]>) {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
|
||||
@@ -287,7 +288,7 @@ async function run({
|
||||
|
||||
const apiDetails = getApiDetails();
|
||||
const outputDir = actionsUtil.getRequiredInput("output");
|
||||
core.exportVariable(EnvVar.SARIF_RESULTS_OUTPUT_DIR, outputDir);
|
||||
env.export(EnvVar.SARIF_RESULTS_OUTPUT_DIR, outputDir);
|
||||
const threads = util.getThreadsFlag(
|
||||
actionsUtil.getOptionalInput("threads") || process.env["CODEQL_THREADS"],
|
||||
logger,
|
||||
@@ -456,7 +457,7 @@ async function run({
|
||||
`expect-error input was set to true but no error was thrown.`,
|
||||
);
|
||||
}
|
||||
core.exportVariable(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||
env.export(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||
} catch (unwrappedError) {
|
||||
const error = util.wrapError(unwrappedError);
|
||||
if (
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
ReadOnlyEnv,
|
||||
RegistryProxyVars,
|
||||
getEnv,
|
||||
exportEnvVar,
|
||||
} from "./environment";
|
||||
import { Logger } from "./logging";
|
||||
import { getRepositoryNwo, RepositoryNwo } from "./repository";
|
||||
@@ -316,7 +317,7 @@ export async function getAnalysisKey(): Promise<string> {
|
||||
const jobName = getRequiredEnvParam("GITHUB_JOB");
|
||||
|
||||
analysisKey = `${workflowPath}:${jobName}`;
|
||||
core.exportVariable(EnvVar.ANALYSIS_KEY, analysisKey);
|
||||
exportEnvVar(EnvVar.ANALYSIS_KEY, analysisKey);
|
||||
return analysisKey;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,11 @@ async function sendCompletedStatusReport(
|
||||
}
|
||||
}
|
||||
|
||||
async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
|
||||
async function run({
|
||||
startedAt,
|
||||
env,
|
||||
logger,
|
||||
}: ActionState<["Base", "Env", "Logger"]>) {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
|
||||
@@ -135,7 +139,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
|
||||
return;
|
||||
}
|
||||
|
||||
core.exportVariable(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||
env.export(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||
|
||||
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import { getTemporaryDirectory, getWorkflowEventName } from "./actions-util";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { CodeQL, getCodeQL } from "./codeql";
|
||||
import * as configUtils from "./config-utils";
|
||||
import { DocUrl } from "./doc-url";
|
||||
import { ActionsEnvVars, EnvVar } from "./environment";
|
||||
import { ActionsEnvVars, EnvVar, exportEnvVar } from "./environment";
|
||||
import { Feature, featureConfig, initFeatures } from "./feature-flags";
|
||||
import { BuiltInLanguage, Language } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
@@ -136,16 +134,16 @@ export async function setupCppAutobuild(codeql: CodeQL, logger: Logger) {
|
||||
: ""
|
||||
}`,
|
||||
);
|
||||
core.exportVariable(envVar, "false");
|
||||
exportEnvVar(envVar, "false");
|
||||
} else {
|
||||
logger.info(
|
||||
`Enabling ${featureName}. This can be disabled by setting the ${envVar} environment variable to 'false'. See ${DocUrl.DEFINE_ENV_VARIABLES} for more information.`,
|
||||
);
|
||||
core.exportVariable(envVar, "true");
|
||||
exportEnvVar(envVar, "true");
|
||||
}
|
||||
} else {
|
||||
logger.info(`Disabling ${featureName}.`);
|
||||
core.exportVariable(envVar, "false");
|
||||
exportEnvVar(envVar, "false");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +163,7 @@ export async function runAutobuild(
|
||||
await codeQL.runAutobuild(config, language);
|
||||
}
|
||||
if (language === BuiltInLanguage.go) {
|
||||
core.exportVariable(EnvVar.DID_AUTOBUILD_GOLANG, "true");
|
||||
exportEnvVar(EnvVar.DID_AUTOBUILD_GOLANG, "true");
|
||||
}
|
||||
logger.endGroup();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import type { VersionInfo } from "./cli/types";
|
||||
import { CliError, wrapCliConfigurationError } from "./cli-errors";
|
||||
import { appendExtraQueryExclusions, type Config } from "./config-utils";
|
||||
import { DocUrl } from "./doc-url";
|
||||
import { EnvVar, getEnv } from "./environment";
|
||||
import { EnvVar, getEnv, exportEnvVar } from "./environment";
|
||||
import {
|
||||
CodeQLDefaultVersionInfo,
|
||||
Feature,
|
||||
@@ -1054,7 +1054,7 @@ async function getCodeQLForCmd(
|
||||
}' by 'github/codeql-action/*@v${getActionVersion()}' in your code scanning workflow to ` +
|
||||
"continue using this version of the CodeQL Action.",
|
||||
);
|
||||
core.exportVariable(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
|
||||
exportEnvVar(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
|
||||
}
|
||||
return codeql;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { performance } from "perf_hooks";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
import { ActionState } from "./action-common";
|
||||
@@ -46,7 +45,7 @@ import {
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { EnvVar, exportEnvVar } from "./environment";
|
||||
import * as errorMessages from "./error-messages";
|
||||
import { Feature, FeatureEnablement, FeatureWithoutCLI } from "./feature-flags";
|
||||
import {
|
||||
@@ -965,10 +964,10 @@ async function setCppTrapCachingEnvironmentVariables(
|
||||
);
|
||||
} else if (config.trapCaches[BuiltInLanguage.cpp]) {
|
||||
logger.info("Enabling TRAP caching for C/C++.");
|
||||
core.exportVariable(envVar, "true");
|
||||
exportEnvVar(envVar, "true");
|
||||
} else {
|
||||
logger.debug(`Disabling TRAP caching for C/C++.`);
|
||||
core.exportVariable(envVar, "false");
|
||||
exportEnvVar(envVar, "false");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { dbIsFinalized } from "./analyze";
|
||||
import { scanArtifactsForTokens } from "./artifact-scanner";
|
||||
import { type CodeQL } from "./codeql";
|
||||
import { Config } from "./config-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { EnvVar, exportEnvVar } from "./environment";
|
||||
import * as json from "./json";
|
||||
import { Language } from "./languages";
|
||||
import { Logger, withGroup } from "./logging";
|
||||
@@ -330,7 +330,7 @@ export async function uploadArtifacts(
|
||||
// some issues early.
|
||||
if (isInTestMode()) {
|
||||
await scanArtifactsForTokens(toUpload, logger);
|
||||
core.exportVariable("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
|
||||
exportEnvVar("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
|
||||
}
|
||||
|
||||
const suffix = getArtifactSuffix(getOptionalInput("matrix"));
|
||||
|
||||
12
src/environment.test.ts
Normal file
12
src/environment.test.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import test from "ava";
|
||||
|
||||
import { Env, ReadOnlyEnv } from "./environment";
|
||||
import { getTestEnv, setupTests } from "./testing-utils";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test("isTestingEnv() is true", (t) => {
|
||||
t.true(new ReadOnlyEnv(process.env).isTestingEnv());
|
||||
t.true(new Env(process.env).isTestingEnv());
|
||||
t.true(getTestEnv().isTestingEnv());
|
||||
});
|
||||
@@ -1,3 +1,10 @@
|
||||
import * as core from "@actions/core";
|
||||
|
||||
/**
|
||||
* This constant is set in `ava.setup.mjs` for tests.
|
||||
*/
|
||||
declare const __CODEQL_ACTION_TEST_ENV__: string | undefined;
|
||||
|
||||
/**
|
||||
* Environment variables used by Default Setup to communicate the private registry proxy configuration.
|
||||
*/
|
||||
@@ -211,8 +218,20 @@ export enum ActionsEnvVars {
|
||||
RUNNER_TOOL_CACHE = "RUNNER_TOOL_CACHE",
|
||||
}
|
||||
|
||||
/** Environment variables which are not specific to CodeQL. */
|
||||
export enum SystemEnvVar {
|
||||
/**
|
||||
* Used by Node and related tools to indicate what kind of environment we are running in.
|
||||
*/
|
||||
NODE_ENV = "NODE_ENV",
|
||||
}
|
||||
|
||||
/** A type representing all known environment variables. */
|
||||
export type KnownEnvVar = EnvVar | ActionsEnvVars | RegistryProxyVars;
|
||||
export type KnownEnvVar =
|
||||
| EnvVar
|
||||
| ActionsEnvVars
|
||||
| RegistryProxyVars
|
||||
| SystemEnvVar;
|
||||
|
||||
/**
|
||||
* Gets an environment variable, but throws an error if it is not set.
|
||||
@@ -289,6 +308,26 @@ export class ReadOnlyEnv<T extends string | undefined = string | undefined> {
|
||||
public entries(): Array<[string, T]> {
|
||||
return Object.entries(this.vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether we should skip uploads of
|
||||
* all kinds (SARIF results, status reports, DBs, ...).
|
||||
*
|
||||
* This is not guaranteed to be set in all test environments.
|
||||
*/
|
||||
public isSkippingUploadsInTests(): boolean {
|
||||
return this.getOptional(EnvVar.TEST_MODE) === "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicative of whether we are in a testing environment
|
||||
* by testing whether the value of the `NODE_ENV` variable is "test".
|
||||
* This is expected to be the case if e.g. `ava` is running the tests
|
||||
* or if this instance was constructed by `getTestEnv`.
|
||||
*/
|
||||
public isTestingEnv(): boolean {
|
||||
return __CODEQL_ACTION_TEST_ENV__ === "unit-test";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,6 +346,26 @@ export class Env<
|
||||
this.changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around `core.exportVariable` which does not call `core.exportVariable`
|
||||
* when running unit tests. This is important, because otherwise `core.exportVariable`
|
||||
* sets environment variables for other steps in a workflow when we run unit tests in CI.
|
||||
*
|
||||
* @param name The name of the environment variable to set and export.
|
||||
* @param val The value to set and export for the environment variable.
|
||||
*/
|
||||
public export(name: string, val: T): void {
|
||||
// Setting the environment variable for this instance is always OK, including
|
||||
// in tests, since we use fresh `Env` instances whenever needed. This allows
|
||||
// tests to pass that rely on that part of the `core.exportVariable` behaviour.
|
||||
this.set(name, val);
|
||||
|
||||
// Call `core.exportVariable` whenever we are not in a test environment.
|
||||
if (!this.isTestingEnv()) {
|
||||
core.exportVariable(name, val);
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets a value indicating whether `set` was called at least once. */
|
||||
public hasChanged(): boolean {
|
||||
return this.changed;
|
||||
@@ -317,3 +376,34 @@ export class Env<
|
||||
export function getEnv(env: NodeJS.ProcessEnv = process.env): Env {
|
||||
return new Env(env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are in test mode. This is used by CodeQL Action PR checks.
|
||||
*
|
||||
* In test mode, we skip several uploads (SARIF results, status reports, DBs, ...).
|
||||
*
|
||||
* @deprecated
|
||||
* The purpose of this function is ambiguous. Use `isSkippingUploadsInTests` on
|
||||
* a `ReadOnlyEnv` instance instead for equivalent behaviour. Use `isTestingEnv`
|
||||
* to determine if we are running in a unit test.
|
||||
*/
|
||||
export function isInTestMode(): boolean {
|
||||
return getEnv().isSkippingUploadsInTests();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around `core.exportVariable` which does not call `core.exportVariable`
|
||||
* when running unit tests. This is important, because otherwise `core.exportVariable`
|
||||
* sets environment variables for other steps in a workflow when we run unit tests in CI.
|
||||
*
|
||||
* @deprecated Use `export` on an `Env` instance instead.
|
||||
*/
|
||||
export function exportEnvVar(name: string, val: any): void {
|
||||
const env = getEnv();
|
||||
|
||||
if (typeof val === "string") {
|
||||
env.export(name, val);
|
||||
} else {
|
||||
env.export(name, JSON.stringify(val));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
DependencyCachingUsageReport,
|
||||
getDependencyCacheUsage,
|
||||
} from "./dependency-caching";
|
||||
import { EnvVar, getEnv } from "./environment";
|
||||
import { EnvVar, getEnv, exportEnvVar } from "./environment";
|
||||
import { initFeatures } from "./feature-flags";
|
||||
import * as gitUtils from "./git-utils";
|
||||
import * as initActionPostHelper from "./init-action-post-helper";
|
||||
@@ -166,7 +166,7 @@ function getFinalJobStatus(config: Config | undefined): JobStatus {
|
||||
let jobStatus: JobStatus;
|
||||
|
||||
if (process.env[EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] === "true") {
|
||||
core.exportVariable(EnvVar.JOB_STATUS, JobStatus.SuccessStatus);
|
||||
exportEnvVar(EnvVar.JOB_STATUS, JobStatus.SuccessStatus);
|
||||
jobStatus = JobStatus.SuccessStatus;
|
||||
} else if (config !== undefined) {
|
||||
// - We have computed a CodeQL config
|
||||
@@ -191,7 +191,7 @@ function getFinalJobStatus(config: Config | undefined): JobStatus {
|
||||
|
||||
// This shouldn't be necessary, but in the odd case that we run more than one
|
||||
// `init` post step, ensure the job status is consistent between them.
|
||||
core.exportVariable(EnvVar.JOB_STATUS, jobStatus);
|
||||
exportEnvVar(EnvVar.JOB_STATUS, jobStatus);
|
||||
return jobStatus;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,12 @@ import * as core from "@actions/core";
|
||||
import * as io from "@actions/io";
|
||||
import * as semver from "semver";
|
||||
|
||||
import { Action, ActionState, runInActions } from "./action-common";
|
||||
import {
|
||||
Action,
|
||||
ActionState,
|
||||
extendActionState,
|
||||
runInActions,
|
||||
} from "./action-common";
|
||||
import {
|
||||
FileCmdNotFoundError,
|
||||
getActionVersion,
|
||||
@@ -93,7 +98,6 @@ import {
|
||||
checkActionVersion,
|
||||
getErrorMessage,
|
||||
BuildMode,
|
||||
getOptionalEnvVar,
|
||||
} from "./util";
|
||||
import { checkWorkflow } from "./workflow";
|
||||
|
||||
@@ -253,7 +257,7 @@ async function run(
|
||||
);
|
||||
const repositoryProperties = repositoryPropertiesResult.orElse({});
|
||||
|
||||
core.exportVariable(EnvVar.INIT_ACTION_HAS_RUN, "true");
|
||||
actionState.env.export(EnvVar.INIT_ACTION_HAS_RUN, "true");
|
||||
|
||||
// path.resolve() respects the intended semantics of source-root. If
|
||||
// source-root is relative, it is relative to the GITHUB_WORKSPACE. If
|
||||
@@ -278,7 +282,9 @@ async function run(
|
||||
}
|
||||
|
||||
// Compute the value of the `config-file` input.
|
||||
const actionStateWithFeatures = { ...actionState, features };
|
||||
const actionStateWithFeatures = extendActionState(actionState, {
|
||||
features,
|
||||
});
|
||||
configFile = await getConfigFileInput(
|
||||
actionStateWithFeatures,
|
||||
repositoryProperties,
|
||||
@@ -369,7 +375,7 @@ async function run(
|
||||
);
|
||||
}
|
||||
if (semver.lt(actualVer, publicPreview)) {
|
||||
core.exportVariable(EnvVar.EXPERIMENTAL_FEATURES, "true");
|
||||
actionState.env.export(EnvVar.EXPERIMENTAL_FEATURES, "true");
|
||||
logger.info("Experimental Rust analysis enabled");
|
||||
}
|
||||
}
|
||||
@@ -517,9 +523,9 @@ async function run(
|
||||
}
|
||||
|
||||
// Forward Go flags
|
||||
const goFlags = process.env["GOFLAGS"];
|
||||
const goFlags = actionState.env.getOptional("GOFLAGS");
|
||||
if (goFlags) {
|
||||
core.exportVariable("GOFLAGS", goFlags);
|
||||
actionState.env.export("GOFLAGS", goFlags);
|
||||
core.warning(
|
||||
"Passing the GOFLAGS env parameter to the init action is deprecated. Please move this to the analyze action.",
|
||||
);
|
||||
@@ -565,7 +571,7 @@ async function run(
|
||||
|
||||
// Store the original location of our wrapper script somewhere where we can
|
||||
// later retrieve it from and cross-check that it hasn't been changed.
|
||||
core.exportVariable(EnvVar.GO_BINARY_LOCATION, goWrapperPath);
|
||||
actionState.env.export(EnvVar.GO_BINARY_LOCATION, goWrapperPath);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Analyzing Go on Linux, but failed to install wrapper script. Tracing custom builds may fail: ${e}`,
|
||||
@@ -574,7 +580,7 @@ async function run(
|
||||
} else {
|
||||
// Store the location of the original Go binary, so we can check that no setup tasks were performed after the
|
||||
// `init` Action ran.
|
||||
core.exportVariable(EnvVar.GO_BINARY_LOCATION, goBinaryPath);
|
||||
actionState.env.export(EnvVar.GO_BINARY_LOCATION, goBinaryPath);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
@@ -609,12 +615,12 @@ async function run(
|
||||
// threads it would ask extractors to use. See help text for the "--ram" and "--threads"
|
||||
// options at https://codeql.github.com/docs/codeql-cli/manual/database-trace-command/
|
||||
// for details.
|
||||
core.exportVariable(
|
||||
actionState.env.export(
|
||||
"CODEQL_RAM",
|
||||
process.env["CODEQL_RAM"] ||
|
||||
getCodeQLMemoryLimit(getOptionalInput("ram"), logger).toString(),
|
||||
);
|
||||
core.exportVariable(
|
||||
actionState.env.export(
|
||||
"CODEQL_THREADS",
|
||||
process.env["CODEQL_THREADS"] ||
|
||||
getThreadsFlagValue(getOptionalInput("threads"), logger).toString(),
|
||||
@@ -622,12 +628,15 @@ async function run(
|
||||
|
||||
// Disable Kotlin extractor if feature flag set
|
||||
if (await features.getValue(Feature.DisableKotlinAnalysisEnabled)) {
|
||||
core.exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
|
||||
actionState.env.export(
|
||||
"CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN",
|
||||
"true",
|
||||
);
|
||||
}
|
||||
|
||||
// Emergency override to force the CodeQL CLI back to the JGit-based Git backend.
|
||||
if (await features.getValue(Feature.ForceJGit)) {
|
||||
core.exportVariable("CODEQL_GIT_BACKEND", "jgit");
|
||||
actionState.env.export("CODEQL_GIT_BACKEND", "jgit");
|
||||
}
|
||||
|
||||
const kotlinLimitVar =
|
||||
@@ -636,7 +645,7 @@ async function run(
|
||||
(await codeQlVersionAtLeast(codeql, "2.20.3")) &&
|
||||
!(await codeQlVersionAtLeast(codeql, "2.20.4"))
|
||||
) {
|
||||
core.exportVariable(kotlinLimitVar, "2.1.20");
|
||||
actionState.env.export(kotlinLimitVar, "2.1.20");
|
||||
}
|
||||
|
||||
// Restore dependency cache(s), if they exist.
|
||||
@@ -685,7 +694,7 @@ async function run(
|
||||
config.buildMode === BuildMode.None &&
|
||||
config.languages.includes(BuiltInLanguage.java)
|
||||
) {
|
||||
core.exportVariable(
|
||||
actionState.env.export(
|
||||
EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS,
|
||||
"true",
|
||||
);
|
||||
@@ -743,7 +752,7 @@ async function run(
|
||||
const tracerConfig = await getCombinedTracerConfig(logger, codeql, config);
|
||||
if (tracerConfig !== undefined) {
|
||||
for (const [key, value] of Object.entries(tracerConfig.env)) {
|
||||
core.exportVariable(key, value);
|
||||
actionState.env.export(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,10 +760,10 @@ async function run(
|
||||
if (await features.getValue(Feature.JavaNetworkDebugging)) {
|
||||
// Get the existing value of `JAVA_TOOL_OPTIONS`, if any.
|
||||
const existingJavaToolOptions =
|
||||
getOptionalEnvVar(JavaEnvVars.JAVA_TOOL_OPTIONS) || "";
|
||||
actionState.env.getOptional(JavaEnvVars.JAVA_TOOL_OPTIONS) ?? "";
|
||||
|
||||
// Add the network debugging options.
|
||||
core.exportVariable(
|
||||
actionState.env.export(
|
||||
JavaEnvVars.JAVA_TOOL_OPTIONS,
|
||||
`${existingJavaToolOptions} -Djavax.net.debug=all`,
|
||||
);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import * as fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as github from "@actions/github";
|
||||
import test, { ExecutionContext } from "ava";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { createStubCodeQL } from "./codeql";
|
||||
import { ActionsEnvVars } from "./environment";
|
||||
import * as environment from "./environment";
|
||||
import { Feature } from "./feature-flags";
|
||||
import {
|
||||
checkPacksForOverlayCompatibility,
|
||||
@@ -85,7 +84,7 @@ for (const { runnerEnv, ErrorConstructor, message } of [
|
||||
`cleanupDatabaseClusterDirectory throws a ${ErrorConstructor.name} when cleanup fails on ${runnerEnv} runner`,
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir: string) => {
|
||||
process.env[ActionsEnvVars.RUNNER_ENVIRONMENT] = runnerEnv;
|
||||
process.env[environment.ActionsEnvVars.RUNNER_ENVIRONMENT] = runnerEnv;
|
||||
|
||||
const dbLocation = path.resolve(tmpDir, "dbs");
|
||||
fs.mkdirSync(dbLocation, { recursive: true });
|
||||
@@ -546,7 +545,7 @@ test.serial(
|
||||
test.serial(
|
||||
"file coverage deprecation warning for org-owned repo with default setup recommends repo property",
|
||||
(t) => {
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
||||
github.context.payload = {
|
||||
repository: {
|
||||
@@ -566,14 +565,14 @@ test.serial(
|
||||
'with the name `github-codeql-file-coverage-on-prs` and the type "True/false", then set this property to ' +
|
||||
"`true` in the repository's settings.",
|
||||
);
|
||||
t.true(exportVariableStub.calledOnce);
|
||||
t.true(exportEnvVarStub.calledOnce);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"file coverage deprecation warning for org-owned repo with advanced setup recommends env var and repo property",
|
||||
(t) => {
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
||||
github.context.payload = {
|
||||
repository: {
|
||||
@@ -594,14 +593,14 @@ test.serial(
|
||||
'with the name `github-codeql-file-coverage-on-prs` and the type "True/false", then set this property to ' +
|
||||
"`true` in the repository's settings.",
|
||||
);
|
||||
t.true(exportVariableStub.calledOnce);
|
||||
t.true(exportEnvVarStub.calledOnce);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"file coverage deprecation warning for user-owned repo with default setup recommends advanced setup",
|
||||
(t) => {
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
||||
github.context.payload = {
|
||||
repository: {
|
||||
@@ -620,14 +619,14 @@ test.serial(
|
||||
"To opt out of this change, switch to an advanced setup workflow and " +
|
||||
"set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true`.",
|
||||
);
|
||||
t.true(exportVariableStub.calledOnce);
|
||||
t.true(exportEnvVarStub.calledOnce);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"file coverage deprecation warning for user-owned repo with advanced setup recommends env var",
|
||||
(t) => {
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
||||
github.context.payload = {
|
||||
repository: {
|
||||
@@ -645,14 +644,14 @@ test.serial(
|
||||
"to improve analysis performance. File coverage information will still be computed on non-PR analyses.\n\n" +
|
||||
"To opt out of this change, set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true`.",
|
||||
);
|
||||
t.true(exportVariableStub.calledOnce);
|
||||
t.true(exportEnvVarStub.calledOnce);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"file coverage deprecation warning for unknown owner type with default setup recommends advanced setup",
|
||||
(t) => {
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
||||
github.context.payload = { repository: undefined };
|
||||
const messages: LoggedMessage[] = [];
|
||||
@@ -666,14 +665,14 @@ test.serial(
|
||||
"To opt out of this change, switch to an advanced setup workflow and " +
|
||||
"set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true`.",
|
||||
);
|
||||
t.true(exportVariableStub.calledOnce);
|
||||
t.true(exportEnvVarStub.calledOnce);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"file coverage deprecation warning for unknown owner type with advanced setup recommends env var",
|
||||
(t) => {
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
||||
github.context.payload = { repository: undefined };
|
||||
const messages: LoggedMessage[] = [];
|
||||
@@ -686,7 +685,7 @@ test.serial(
|
||||
"to improve analysis performance. File coverage information will still be computed on non-PR analyses.\n\n" +
|
||||
"To opt out of this change, set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true`.",
|
||||
);
|
||||
t.true(exportVariableStub.calledOnce);
|
||||
t.true(exportEnvVarStub.calledOnce);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -695,10 +694,10 @@ test.serial(
|
||||
(t) => {
|
||||
process.env["CODEQL_ACTION_DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION"] =
|
||||
"true";
|
||||
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||
const exportEnvVarStub = sinon.stub(environment, "exportEnvVar");
|
||||
const messages: LoggedMessage[] = [];
|
||||
logFileCoverageOnPrsDeprecationWarning(getRecordingLogger(messages));
|
||||
t.is(messages.length, 0);
|
||||
t.true(exportVariableStub.notCalled);
|
||||
t.true(exportEnvVarStub.notCalled);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||
import * as github from "@actions/github";
|
||||
import * as io from "@actions/io";
|
||||
@@ -17,7 +16,7 @@ import {
|
||||
import { GitHubApiDetails } from "./api-client";
|
||||
import { CodeQL, setupCodeQL } from "./codeql";
|
||||
import * as configUtils from "./config-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { EnvVar, exportEnvVar } from "./environment";
|
||||
import {
|
||||
CodeQLDefaultVersionInfo,
|
||||
Feature,
|
||||
@@ -411,5 +410,5 @@ export function logFileCoverageOnPrsDeprecationWarning(logger: Logger): void {
|
||||
}
|
||||
|
||||
logger.warning(message);
|
||||
core.exportVariable(EnvVar.DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION, "true");
|
||||
exportEnvVar(EnvVar.DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION, "true");
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import * as sinon from "sinon";
|
||||
import * as actionsUtil from "../actions-util";
|
||||
import * as apiClient from "../api-client";
|
||||
import type { ResolveDatabaseOutput } from "../codeql";
|
||||
import * as environment from "../environment";
|
||||
import * as gitUtils from "../git-utils";
|
||||
import { BuiltInLanguage } from "../languages";
|
||||
import { getRunnerLogger } from "../logging";
|
||||
@@ -82,7 +83,7 @@ const testDownloadOverlayBaseDatabaseFromCache = makeMacro({
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
|
||||
sinon.stub(utils, "isInTestMode").returns(testCase.isInTestMode);
|
||||
sinon.stub(environment, "isInTestMode").returns(testCase.isInTestMode);
|
||||
|
||||
if (testCase.restoreCacheResult instanceof Error) {
|
||||
sinon
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import { Action, ActionState, runInActions } from "./action-common";
|
||||
import {
|
||||
Action,
|
||||
ActionState,
|
||||
extendActionState,
|
||||
runInActions,
|
||||
} from "./action-common";
|
||||
import {
|
||||
getActionVersion,
|
||||
getOptionalInput,
|
||||
@@ -131,7 +136,9 @@ async function run(
|
||||
);
|
||||
const repositoryProperties = repositoryPropertiesResult.orElse({});
|
||||
|
||||
const actionStateWithFeatures = { ...actionState, features };
|
||||
const actionStateWithFeatures = extendActionState(actionState, {
|
||||
features,
|
||||
});
|
||||
|
||||
const statusReportBase = await createStatusReportBase(
|
||||
ActionName.SetupCodeQL,
|
||||
@@ -184,7 +191,7 @@ async function run(
|
||||
core.setOutput("codeql-path", codeql.getPath());
|
||||
core.setOutput("codeql-version", (await codeql.getVersion()).version);
|
||||
|
||||
core.exportVariable(EnvVar.SETUP_CODEQL_ACTION_HAS_RUN, "true");
|
||||
actionState.env.export(EnvVar.SETUP_CODEQL_ACTION_HAS_RUN, "true");
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
core.setFailed(error.message);
|
||||
|
||||
@@ -3,7 +3,6 @@ import { OutgoingHttpHeaders } from "http";
|
||||
import * as path from "path";
|
||||
import { performance } from "perf_hooks";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
import { default as deepEqual } from "fast-deep-equal";
|
||||
import * as semver from "semver";
|
||||
@@ -29,7 +28,7 @@ import {
|
||||
makeDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import { EnvVar, getEnv } from "./environment";
|
||||
import { EnvVar, exportEnvVar, getEnv } from "./environment";
|
||||
import {
|
||||
CODEQL_VERSION_ZSTD_BUNDLE,
|
||||
CodeQLDefaultVersionInfo,
|
||||
@@ -1071,7 +1070,7 @@ export async function setupCodeQLBundle(
|
||||
|
||||
// Record that this job now has a copy of the CodeQL tools, so that a later step doesn't delete
|
||||
// the toolcache out from under the path we are about to return.
|
||||
core.exportVariable(EnvVar.HAS_SET_UP_CODEQL, "true");
|
||||
exportEnvVar(EnvVar.HAS_SET_UP_CODEQL, "true");
|
||||
|
||||
return {
|
||||
codeqlFolder,
|
||||
|
||||
@@ -3,7 +3,12 @@ import * as path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import { Action, ActionState, runInActions } from "./action-common";
|
||||
import {
|
||||
Action,
|
||||
ActionState,
|
||||
extendActionState,
|
||||
runInActions,
|
||||
} from "./action-common";
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
@@ -98,7 +103,8 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
|
||||
};
|
||||
|
||||
// Start the Proxy
|
||||
const proxyBin = await getProxyBinaryPath({ ...action, features });
|
||||
const actionWithFeatures = extendActionState(action, { features });
|
||||
const proxyBin = await getProxyBinaryPath(actionWithFeatures);
|
||||
const proxyInfo = await startProxy(
|
||||
proxyBin,
|
||||
proxyConfig,
|
||||
|
||||
@@ -23,7 +23,13 @@ import type { ComputedInput, InputName } from "./config/inputs";
|
||||
import { parseRegistriesWithoutCredentials } from "./config/pack-registries";
|
||||
import type { DependencyCacheRestoreStatusReport } from "./dependency-caching";
|
||||
import { DocUrl } from "./doc-url";
|
||||
import { EnvVar, getEnv, ReadOnlyEnv, RegistryProxyVars } from "./environment";
|
||||
import {
|
||||
EnvVar,
|
||||
getEnv,
|
||||
ReadOnlyEnv,
|
||||
RegistryProxyVars,
|
||||
exportEnvVar,
|
||||
} from "./environment";
|
||||
import { getRef } from "./git-utils";
|
||||
import * as json from "./json";
|
||||
import type { Logger } from "./logging";
|
||||
@@ -71,9 +77,7 @@ export function getDisplayActionName(actionName: ActionName): string {
|
||||
* environment and returns it.
|
||||
* If a new UUID is generated, it is also exported as an environment variable.
|
||||
*/
|
||||
export function getJobUUID(
|
||||
action: ActionState<["Logger", "ReadOnlyEnv", "Actions"]>,
|
||||
) {
|
||||
export function getJobUUID(action: ActionState<["Logger", "Env", "Actions"]>) {
|
||||
// Check if we already have a UUID for the analysis and return it if so.
|
||||
const existingJobRunUuid = action.env.getOptional(EnvVar.JOB_RUN_UUID);
|
||||
|
||||
@@ -86,7 +90,7 @@ export function getJobUUID(
|
||||
const jobRunUuid = uuid.v4();
|
||||
action.logger.info(`Job run UUID is ${jobRunUuid}.`);
|
||||
|
||||
action.actions.exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
|
||||
action.env.export(EnvVar.JOB_RUN_UUID, jobRunUuid);
|
||||
return jobRunUuid;
|
||||
}
|
||||
|
||||
@@ -268,12 +272,12 @@ export function getJobStatusDisplayName(status: JobStatus): string {
|
||||
*/
|
||||
function setJobStatusIfUnsuccessful(actionStatus: ActionStatus) {
|
||||
if (actionStatus === "user-error") {
|
||||
core.exportVariable(
|
||||
exportEnvVar(
|
||||
EnvVar.JOB_STATUS,
|
||||
process.env[EnvVar.JOB_STATUS] ?? JobStatus.ConfigErrorStatus,
|
||||
);
|
||||
} else if (actionStatus === "failure" || actionStatus === "aborted") {
|
||||
core.exportVariable(
|
||||
exportEnvVar(
|
||||
EnvVar.JOB_STATUS,
|
||||
process.env[EnvVar.JOB_STATUS] ?? JobStatus.FailureStatus,
|
||||
);
|
||||
@@ -376,7 +380,7 @@ export async function createStatusReportBase(
|
||||
let workflowStartedAt = process.env[EnvVar.WORKFLOW_STARTED_AT];
|
||||
if (workflowStartedAt === undefined) {
|
||||
workflowStartedAt = actionStartedAt.toISOString();
|
||||
core.exportVariable(EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt);
|
||||
exportEnvVar(EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt);
|
||||
}
|
||||
const runnerOs = getRequiredEnvParam("RUNNER_OS");
|
||||
const codeQlCliVersion = getCachedCodeQlVersion(
|
||||
@@ -388,7 +392,7 @@ export async function createStatusReportBase(
|
||||
// re-export the testing environment variable so that it is available to subsequent steps,
|
||||
// even if it was only set for this step
|
||||
if (testingEnvironment) {
|
||||
core.exportVariable(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
|
||||
exportEnvVar(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
|
||||
}
|
||||
const isSteadyStateDefaultSetupRun =
|
||||
process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true";
|
||||
|
||||
@@ -202,10 +202,6 @@ class TestActionsEnv implements ActionsEnv {
|
||||
public getOptionalInput(_name: string): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public exportVariable(name: string, value: string): void {
|
||||
this.env.set(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,7 +14,7 @@ import { getGitHubVersion, wrapApiConfigurationError } from "./api-client";
|
||||
import { CodeQL, getCodeQL } from "./codeql";
|
||||
import { getConfig } from "./config-utils";
|
||||
import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { EnvVar, exportEnvVar } from "./environment";
|
||||
import { FeatureEnablement } from "./feature-flags";
|
||||
import * as fingerprints from "./fingerprints";
|
||||
import * as gitUtils from "./git-utils";
|
||||
@@ -126,7 +126,7 @@ async function combineSarifFilesUsingCLI(
|
||||
logger.warning(
|
||||
`Uploading multiple SARIF runs with the same category is deprecated ${deprecationWarningMessage}. Please update your workflow to upload a single run per category. ${deprecationMoreInformationMessage}`,
|
||||
);
|
||||
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
|
||||
exportEnvVar("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
|
||||
}
|
||||
|
||||
// If not, use the naive method of combining the files.
|
||||
@@ -1032,7 +1032,7 @@ export function validateUniqueCategory(
|
||||
`Category: (${id ? id : "none"}) Tool: (${tool ? tool : "none"})`,
|
||||
);
|
||||
}
|
||||
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
|
||||
exportEnvVar(sentinelEnvVar, sentinelEnvVar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
39
src/util.ts
39
src/util.ts
@@ -14,13 +14,23 @@ import * as apiCompatibility from "./api-compatibility.json";
|
||||
import type { CodeQL } from "./codeql";
|
||||
import type { Pack } from "./config/db-config";
|
||||
import type { Config } from "./config-utils";
|
||||
import { EnvVar, getRequiredEnvParam } from "./environment";
|
||||
import {
|
||||
EnvVar,
|
||||
getRequiredEnvParam,
|
||||
isInTestMode,
|
||||
exportEnvVar,
|
||||
} from "./environment";
|
||||
import * as json from "./json";
|
||||
import { Language } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
|
||||
// Re-export for backwards compatibility to avoid updating a lot of imports elsewhere.
|
||||
export { getRequiredEnvParam, getOptionalEnvVar, getEnv } from "./environment";
|
||||
export {
|
||||
getRequiredEnvParam,
|
||||
getOptionalEnvVar,
|
||||
getEnv,
|
||||
isInTestMode,
|
||||
} from "./environment";
|
||||
|
||||
/**
|
||||
* The name of the file containing the base database OIDs, as stored in the
|
||||
@@ -542,7 +552,7 @@ export function checkGitHubVersionInRange(
|
||||
);
|
||||
}
|
||||
hasBeenWarnedAboutVersion = true;
|
||||
core.exportVariable(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true);
|
||||
exportEnvVar(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true);
|
||||
}
|
||||
|
||||
export enum DisallowedAPIVersionReason {
|
||||
@@ -586,11 +596,11 @@ export function assertNever(value: never): never {
|
||||
* knowing what version of CodeQL we're running.
|
||||
*/
|
||||
export function initializeEnvironment(version: string) {
|
||||
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||
core.exportVariable(EnvVar.FEATURE_SANDWICH, "false");
|
||||
core.exportVariable(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||
core.exportVariable(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||
core.exportVariable(EnvVar.VERSION, version);
|
||||
exportEnvVar(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||
exportEnvVar(EnvVar.FEATURE_SANDWICH, "false");
|
||||
exportEnvVar(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||
exportEnvVar(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||
exportEnvVar(EnvVar.VERSION, version);
|
||||
}
|
||||
|
||||
export class HTTPError extends Error {
|
||||
@@ -711,15 +721,6 @@ export function isGoodVersion(versionSpec: string) {
|
||||
return !BROKEN_VERSIONS.includes(versionSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we are in test mode. This is used by CodeQL Action PR checks.
|
||||
*
|
||||
* In test mode, we skip several uploads (SARIF results, status reports, DBs, ...).
|
||||
*/
|
||||
export function isInTestMode(): boolean {
|
||||
return process.env[EnvVar.TEST_MODE] === "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether we specifically want to skip uploading SARIF files.
|
||||
*/
|
||||
@@ -948,7 +949,7 @@ export async function checkDiskUsage(
|
||||
} else {
|
||||
logger.debug(message);
|
||||
}
|
||||
core.exportVariable(EnvVar.HAS_WARNED_ABOUT_DISK_SPACE, "true");
|
||||
exportEnvVar(EnvVar.HAS_WARNED_ABOUT_DISK_SPACE, "true");
|
||||
}
|
||||
return {
|
||||
numAvailableBytes: diskUsage.bavail * blockSizeInBytes,
|
||||
@@ -997,7 +998,7 @@ export function checkActionVersion(
|
||||
"https://github.blog/changelog/2025-10-28-upcoming-deprecation-of-codeql-action-v3/",
|
||||
);
|
||||
// set LOG_VERSION_DEPRECATION env var to prevent the warning from being logged multiple times
|
||||
core.exportVariable(EnvVar.LOG_VERSION_DEPRECATION, "true");
|
||||
exportEnvVar(EnvVar.LOG_VERSION_DEPRECATION, "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
unreleased-change-notes/README.md
Normal file
24
unreleased-change-notes/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
## Change notes
|
||||
|
||||
Change-notes are Markdown files used to document user-facing changes. When making a change that affects users, create a Markdown file here that describes the change. During the next release, the change-note files in `unreleased-change-notes/` will automatically be added to `CHANGELOG.md`.
|
||||
|
||||
### Change-note file format
|
||||
|
||||
Change-note files must follow a certain format so that they can be automatically validated and processed. Failure to follow the format will result in a failed PR check.
|
||||
|
||||
You may validate your change-note file locally by running `npx tsx pr-checks/changenotes.ts validate`. This command will scan all change-note files in `unreleased-change-notes/` and report any errors.
|
||||
|
||||
|
||||
#### Body
|
||||
|
||||
The body of the change-note file must:
|
||||
|
||||
- Be written in valid [GitHub-Flavored Markdown](https://github.github.com/gfm/).
|
||||
- Be structured as a single unordered Markdown list with hyphen (`-`) bullets. Each list item should describe a single change. If there are multiple changes, use multiple list items.
|
||||
|
||||
### Example change-note file
|
||||
|
||||
```
|
||||
- Fixed a bug where a network error while streaming the download of the CodeQL bundle could terminate the `init` Action instead of falling back to downloading the bundle before extracting it. [#4061](https://github.com/github/codeql-action/pull/4061)
|
||||
- Fix incorrect minimum required Git version for [improved incremental analysis](https://github.com/github/roadmap/issues/1158): it should have been 2.36.0, not 2.11.0. [#3781](https://github.com/github/codeql-action/pull/3781)
|
||||
```
|
||||
Reference in New Issue
Block a user