mirror of
https://github.com/github/codeql-action.git
synced 2026-06-04 04:44:50 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 699d8f2cc5 |
+32
-112
@@ -33,10 +33,6 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
|
|
||||||
concurrency:
|
|
||||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
|
||||||
group: pr-checks-unit-tests-${{ github.ref }}-${{ github.event_name }}-${{ matrix.os }}-node${{ matrix['node-version'] }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Prepare git (Windows)
|
- name: Prepare git (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
@@ -75,21 +71,22 @@ jobs:
|
|||||||
sarif_file: eslint.sarif
|
sarif_file: eslint.sarif
|
||||||
category: eslint
|
category: eslint
|
||||||
|
|
||||||
# These checks do not need to be run as part of the same matrix that we use for the `unit-tests`
|
# Verifying the PR checks are up-to-date requires Node 24. The PR checks are not dependent
|
||||||
# job.
|
# on the main codebase and therefore do not need to be run as part of the same matrix that
|
||||||
other-checks:
|
# we use for the `unit-tests` job.
|
||||||
name: Other checks
|
verify-pr-checks:
|
||||||
|
name: Verify PR checks
|
||||||
if: github.triggering_actor != 'dependabot[bot]'
|
if: github.triggering_actor != 'dependabot[bot]'
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
|
|
||||||
concurrency:
|
|
||||||
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
|
|
||||||
group: pr-checks-pr-checks-${{ github.ref }}-${{ github.event_name }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Prepare git (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: git config --global core.autocrlf false
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
@@ -100,22 +97,34 @@ jobs:
|
|||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
id: install-deps
|
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Verify PR checks up to date
|
- name: Verify PR checks up to date
|
||||||
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
|
if: always()
|
||||||
run: .github/workflows/script/verify-pr-checks.sh
|
run: .github/workflows/script/verify-pr-checks.sh
|
||||||
|
|
||||||
- name: Run pr-checks tests
|
- name: Run pr-checks tests
|
||||||
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
|
if: always()
|
||||||
working-directory: pr-checks
|
working-directory: pr-checks
|
||||||
run: npx tsx --test
|
run: npx tsx --test
|
||||||
|
|
||||||
- name: Verify all Actions use the same Node version
|
check-node-version:
|
||||||
id: head-version
|
if: github.triggering_actor != 'dependabot[bot]'
|
||||||
|
name: Check Action Node versions
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 45
|
||||||
|
env:
|
||||||
|
BASE_REF: ${{ github.base_ref }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
- id: head-version
|
||||||
|
name: Verify all Actions use the same Node version
|
||||||
run: |
|
run: |
|
||||||
NODE_VERSION=$(find . -path "*/node_modules" -prune -o -name "action.yml" -exec yq -o=json '.runs.using' {} \; | jq -rs '[.[] | select(. != null and startswith("node"))] | unique | .[]')
|
NODE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
|
||||||
echo "NODE_VERSION: ${NODE_VERSION}"
|
echo "NODE_VERSION: ${NODE_VERSION}"
|
||||||
if [[ $(echo "$NODE_VERSION" | wc -l) -gt 1 ]]; then
|
if [[ $(echo "$NODE_VERSION" | wc -l) -gt 1 ]]; then
|
||||||
echo "::error::More than one node version used in 'action.yml' files."
|
echo "::error::More than one node version used in 'action.yml' files."
|
||||||
@@ -123,111 +132,22 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
|
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Fetch base commit
|
- id: checkout-base
|
||||||
id: fetch-base
|
name: 'Backport: Check out base ref'
|
||||||
# Forks and Dependabot PRs don't have permission to write comments, so skip the repo size
|
|
||||||
# check in those cases.
|
|
||||||
if: >-
|
|
||||||
github.event_name == 'pull_request' &&
|
|
||||||
github.event.pull_request.head.repo.full_name == github.repository &&
|
|
||||||
github.event.pull_request.user.login != 'dependabot[bot]'
|
|
||||||
env:
|
|
||||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
||||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
# Compare against the merge base so the size delta reflects only the commits actually
|
|
||||||
# added by this PR, ignoring any changes that have landed on the base branch since the
|
|
||||||
# PR branched off.
|
|
||||||
merge_base=$(gh api "repos/$GITHUB_REPOSITORY/compare/$BASE_SHA...$HEAD_SHA" --jq '.merge_base_commit.sha')
|
|
||||||
echo "merge_base=$merge_base" >> "$GITHUB_OUTPUT"
|
|
||||||
git fetch --no-tags --depth=1 origin "$merge_base" "$HEAD_SHA"
|
|
||||||
|
|
||||||
- name: Check repo size
|
|
||||||
if: steps.fetch-base.outcome == 'success'
|
|
||||||
working-directory: pr-checks
|
|
||||||
env:
|
|
||||||
BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
||||||
BASE_SHA: ${{ steps.fetch-base.outputs.merge_base }}
|
|
||||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
||||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
||||||
run: npx tsx check-repo-size.ts --output-dir "$RUNNER_TEMP/repo-size"
|
|
||||||
|
|
||||||
- name: Upload repo size comment
|
|
||||||
if: steps.fetch-base.outcome == 'success'
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: repo-size-comment
|
|
||||||
path: ${{ runner.temp }}/repo-size/
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
- name: 'Backport: Check out base ref'
|
|
||||||
id: checkout-base
|
|
||||||
if: ${{ startsWith(github.head_ref, 'backport-') }}
|
if: ${{ startsWith(github.head_ref, 'backport-') }}
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.base_ref }}
|
ref: ${{ env.BASE_REF }}
|
||||||
|
|
||||||
- name: 'Backport: Verify Node versions unchanged'
|
- name: 'Backport: Verify Node versions unchanged'
|
||||||
if: steps.checkout-base.outcome == 'success'
|
if: steps.checkout-base.outcome == 'success'
|
||||||
env:
|
env:
|
||||||
HEAD_VERSION: ${{ steps.head-version.outputs.node_version }}
|
HEAD_VERSION: ${{ steps.head-version.outputs.node_version }}
|
||||||
run: |
|
run: |
|
||||||
BASE_VERSION=$(find . -path "*/node_modules" -prune -o -name "action.yml" -exec yq -o=json '.runs.using' {} \; | jq -rs '[.[] | select(. != null and startswith("node"))] | unique | .[]')
|
BASE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
|
||||||
echo "HEAD_VERSION: ${HEAD_VERSION}"
|
echo "HEAD_VERSION: ${HEAD_VERSION}"
|
||||||
echo "BASE_VERSION: ${BASE_VERSION}"
|
echo "BASE_VERSION: ${BASE_VERSION}"
|
||||||
if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then
|
if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then
|
||||||
echo "::error::Cannot change the Node version of an Action in a backport PR."
|
echo "::error::Cannot change the Node version of an Action in a backport PR."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
post-repo-size-comment:
|
|
||||||
name: Post repo size comment
|
|
||||||
needs: other-checks
|
|
||||||
# Keep write permissions isolated from the job that checks out and tests PR code. This job only
|
|
||||||
# posts the candidate comment body produced by the read-only `pr-checks` job.
|
|
||||||
if: >-
|
|
||||||
github.event_name == 'pull_request' &&
|
|
||||||
github.event.pull_request.head.repo.full_name == github.repository &&
|
|
||||||
github.event.pull_request.user.login != 'dependabot[bot]' &&
|
|
||||||
needs.other-checks.result == 'success'
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: write
|
|
||||||
runs-on: ubuntu-slim
|
|
||||||
timeout-minutes: 10
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
cancel-in-progress: true
|
|
||||||
group: check-repo-size-${{ github.event.pull_request.number }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Download repo size comment
|
|
||||||
uses: actions/download-artifact@v8
|
|
||||||
with:
|
|
||||||
name: repo-size-comment
|
|
||||||
path: repo-size-comment
|
|
||||||
|
|
||||||
- name: Post repo size comment
|
|
||||||
env:
|
|
||||||
COMMENT_MARKER: "<!-- repo-size-diff-bot -->"
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
|
||||||
run: |
|
|
||||||
significant=$(jq -r '.significant' repo-size-comment/metadata.json)
|
|
||||||
comment_id=$(
|
|
||||||
gh api "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \
|
|
||||||
--paginate \
|
|
||||||
--jq ".[] | select(.body | contains(\"$COMMENT_MARKER\")) | .id" \
|
|
||||||
| head -n 1
|
|
||||||
)
|
|
||||||
|
|
||||||
if [[ -n "$comment_id" ]]; then
|
|
||||||
echo "Updating existing comment $comment_id."
|
|
||||||
gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$comment_id" --field body=@repo-size-comment/body.md
|
|
||||||
elif [[ "$significant" == "true" ]]; then
|
|
||||||
echo "Creating new repo size comment."
|
|
||||||
gh api --method POST "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" --field body=@repo-size-comment/body.md
|
|
||||||
else
|
|
||||||
echo "Skipping repo size comment because the delta is below the threshold and no sticky comment exists."
|
|
||||||
fi
|
|
||||||
|
|||||||
@@ -4,13 +4,8 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
|||||||
|
|
||||||
## [UNRELEASED]
|
## [UNRELEASED]
|
||||||
|
|
||||||
No user facing changes.
|
|
||||||
|
|
||||||
## 4.36.0 - 22 May 2026
|
|
||||||
|
|
||||||
- _Breaking change_: Bump the minimum required CodeQL bundle version to 2.19.4. [#3894](https://github.com/github/codeql-action/pull/3894)
|
- _Breaking change_: Bump the minimum required CodeQL bundle version to 2.19.4. [#3894](https://github.com/github/codeql-action/pull/3894)
|
||||||
- Add support for SHA-256 Git object IDs. [#3893](https://github.com/github/codeql-action/pull/3893)
|
- Add support for SHA-256 Git object IDs. [#3893](https://github.com/github/codeql-action/pull/3893)
|
||||||
- Update default CodeQL bundle version to [2.25.5](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.5). [#3926](https://github.com/github/codeql-action/pull/3926)
|
|
||||||
|
|
||||||
## 4.35.5 - 15 May 2026
|
## 4.35.5 - 15 May 2026
|
||||||
|
|
||||||
|
|||||||
@@ -140,18 +140,6 @@ export default [
|
|||||||
"no-async-foreach/no-async-foreach": "error",
|
"no-async-foreach/no-async-foreach": "error",
|
||||||
"no-sequences": "error",
|
"no-sequences": "error",
|
||||||
"no-shadow": "off",
|
"no-shadow": "off",
|
||||||
|
|
||||||
// A basic check that we don't use `exportVariable` from `@actions/core`. This rule depends on
|
|
||||||
// the module being imported as `core`, but that is a good enough check for us.
|
|
||||||
"no-restricted-syntax": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
selector:
|
|
||||||
"MemberExpression[object.name='core'][property.name='exportVariable']",
|
|
||||||
message: "Use `exportVariable` from `environment.ts` instead.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
// This is overly restrictive with unsetting `EnvVar`s
|
// This is overly restrictive with unsetting `EnvVar`s
|
||||||
"@typescript-eslint/no-dynamic-delete": "off",
|
"@typescript-eslint/no-dynamic-delete": "off",
|
||||||
"@typescript-eslint/no-shadow": "error",
|
"@typescript-eslint/no-shadow": "error",
|
||||||
@@ -169,15 +157,6 @@ 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"],
|
files: ["**/*.ts", "**/*.js"],
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"bundleVersion": "codeql-bundle-v2.25.5",
|
"bundleVersion": "codeql-bundle-v2.25.4",
|
||||||
"cliVersion": "2.25.5",
|
"cliVersion": "2.25.4",
|
||||||
"priorBundleVersion": "codeql-bundle-v2.25.4",
|
"priorBundleVersion": "codeql-bundle-v2.25.3",
|
||||||
"priorCliVersion": "2.25.4"
|
"priorCliVersion": "2.25.3"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+494
-453
File diff suppressed because it is too large
Load Diff
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "4.36.1",
|
"version": "4.36.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "4.36.1",
|
"version": "4.36.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"pr-checks"
|
"pr-checks"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "4.36.1",
|
"version": "4.36.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "CodeQL action",
|
"description": "CodeQL action",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,259 +0,0 @@
|
|||||||
#!/usr/bin/env npx tsx
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tests for check-repo-size.ts.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import * as assert from "node:assert/strict";
|
|
||||||
import { execFileSync } from "node:child_process";
|
|
||||||
import { randomBytes } from "node:crypto";
|
|
||||||
import * as fs from "node:fs";
|
|
||||||
import * as os from "node:os";
|
|
||||||
import * as path from "node:path";
|
|
||||||
import { afterEach, beforeEach, describe, it } from "node:test";
|
|
||||||
|
|
||||||
import {
|
|
||||||
COMMENT_MARKER,
|
|
||||||
DEFAULT_BASE_REF,
|
|
||||||
buildCommentBody,
|
|
||||||
formatBytes,
|
|
||||||
formatPercent,
|
|
||||||
isDeltaSignificant,
|
|
||||||
measureArchiveSize,
|
|
||||||
readArgs,
|
|
||||||
} from "./check-repo-size";
|
|
||||||
|
|
||||||
describe("formatBytes", async () => {
|
|
||||||
const cases: Array<[number, boolean, string]> = [
|
|
||||||
// Unsigned values, including sub-KiB amounts which round to 0.00.
|
|
||||||
[0, false, "0.00 KiB"],
|
|
||||||
[512, false, "0.50 KiB"],
|
|
||||||
[1024, false, "1.00 KiB"],
|
|
||||||
[1024 * 1024, false, "1024.00 KiB"],
|
|
||||||
[2 * 1024 * 1024, false, "2048.00 KiB"],
|
|
||||||
// Negative values always use a leading minus.
|
|
||||||
[-2 * 1024 * 1024, false, "-2048.00 KiB"],
|
|
||||||
// signed=true prepends a + to non-negative values.
|
|
||||||
[0, true, "+0.00 KiB"],
|
|
||||||
[2 * 1024 * 1024, true, "+2048.00 KiB"],
|
|
||||||
[-2 * 1024 * 1024, true, "-2048.00 KiB"],
|
|
||||||
];
|
|
||||||
for (const [bytes, signed, expected] of cases) {
|
|
||||||
await it(`formats ${bytes} (signed=${signed}) as ${expected}`, () => {
|
|
||||||
assert.equal(formatBytes(bytes, signed), expected);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("formatPercent", async () => {
|
|
||||||
await it("formats positive fractions with a leading +", () => {
|
|
||||||
assert.equal(formatPercent(0.1), "+10.00%");
|
|
||||||
assert.equal(formatPercent(0.0123), "+1.23%");
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("formats negative fractions with a leading -", () => {
|
|
||||||
assert.equal(formatPercent(-0.1), "-10.00%");
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("formats zero without a sign", () => {
|
|
||||||
assert.equal(formatPercent(0), "0.00%");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("isDeltaSignificant", async () => {
|
|
||||||
const cases: Array<[number, number, number, boolean]> = [
|
|
||||||
// At and above threshold (both signs).
|
|
||||||
[100, 1000, 0.1, true],
|
|
||||||
[101, 1000, 0.1, true],
|
|
||||||
[-100, 1000, 0.1, true],
|
|
||||||
// Below threshold (both signs, plus exact zero).
|
|
||||||
[99, 1000, 0.1, false],
|
|
||||||
[-99, 1000, 0.1, false],
|
|
||||||
[0, 1000, 0.1, false],
|
|
||||||
];
|
|
||||||
for (const [delta, base, fraction, expected] of cases) {
|
|
||||||
await it(`returns ${expected} for delta=${delta}, base=${base}, fraction=${fraction}`, () => {
|
|
||||||
assert.equal(isDeltaSignificant(delta, base, fraction), expected);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("buildCommentBody", async () => {
|
|
||||||
await it("includes the marker, the base/PR/delta rows, and the run URL", () => {
|
|
||||||
const body = buildCommentBody({
|
|
||||||
baseRef: "main",
|
|
||||||
baseSize: 2_000_000,
|
|
||||||
prSize: 2_300_000,
|
|
||||||
runUrl: "https://example.test/run",
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.match(body, new RegExp(`^${escapeRegExp(COMMENT_MARKER)}`));
|
|
||||||
assert.match(body, /Base \(`main`\) \| 1953\.13 KiB \(2000000 bytes\)/);
|
|
||||||
assert.match(body, /This PR \| 2246\.09 KiB \(2300000 bytes\)/);
|
|
||||||
assert.match(
|
|
||||||
body,
|
|
||||||
/\*\*Delta\*\* \| \*\*\+292\.97 KiB \(\+300000 bytes, \+15\.00%\)\*\*/,
|
|
||||||
);
|
|
||||||
assert.match(body, /\[workflow run\]\(https:\/\/example\.test\/run\)/);
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("formats negative deltas with a leading minus and omits the run URL when missing", () => {
|
|
||||||
const body = buildCommentBody({
|
|
||||||
baseRef: "main",
|
|
||||||
baseSize: 2_000_000,
|
|
||||||
prSize: 1_800_000,
|
|
||||||
});
|
|
||||||
assert.match(
|
|
||||||
body,
|
|
||||||
/\*\*Delta\*\* \| \*\*-195\.31 KiB \(-200000 bytes, -10\.00%\)\*\*/,
|
|
||||||
);
|
|
||||||
assert.doesNotMatch(body, /workflow run/);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("readArgs", async () => {
|
|
||||||
await it("defaults the base ref and head commit for local runs", () => {
|
|
||||||
const originalEnv = process.env;
|
|
||||||
const originalArgv = process.argv;
|
|
||||||
|
|
||||||
try {
|
|
||||||
process.env = {};
|
|
||||||
process.argv = ["node", "check-repo-size.ts", "--output-dir", "/tmp/out"];
|
|
||||||
|
|
||||||
const args = readArgs();
|
|
||||||
|
|
||||||
assert.equal(args.baseRef, DEFAULT_BASE_REF);
|
|
||||||
assert.equal(args.baseCommitish, `origin/${DEFAULT_BASE_REF}`);
|
|
||||||
assert.equal(args.headCommitish, "HEAD");
|
|
||||||
assert.equal(args.outputDir, "/tmp/out");
|
|
||||||
assert.equal(args.runUrl, undefined);
|
|
||||||
} finally {
|
|
||||||
process.env = originalEnv;
|
|
||||||
process.argv = originalArgv;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("uses the base and head SHAs when provided by the workflow", () => {
|
|
||||||
const originalEnv = process.env;
|
|
||||||
const originalArgv = process.argv;
|
|
||||||
|
|
||||||
try {
|
|
||||||
process.env = {
|
|
||||||
BASE_REF: "main",
|
|
||||||
BASE_SHA: "abc123",
|
|
||||||
HEAD_SHA: "def456",
|
|
||||||
RUN_URL: "https://example.test/run",
|
|
||||||
};
|
|
||||||
process.argv = ["node", "check-repo-size.ts", "--output-dir", "/tmp/out"];
|
|
||||||
|
|
||||||
const args = readArgs();
|
|
||||||
|
|
||||||
assert.equal(args.baseRef, "main");
|
|
||||||
assert.equal(args.baseCommitish, "abc123");
|
|
||||||
assert.equal(args.headCommitish, "def456");
|
|
||||||
assert.equal(args.outputDir, "/tmp/out");
|
|
||||||
assert.equal(args.runUrl, "https://example.test/run");
|
|
||||||
} finally {
|
|
||||||
process.env = originalEnv;
|
|
||||||
process.argv = originalArgv;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("throws when --output-dir is missing", () => {
|
|
||||||
const originalEnv = process.env;
|
|
||||||
const originalArgv = process.argv;
|
|
||||||
|
|
||||||
try {
|
|
||||||
process.env = {};
|
|
||||||
process.argv = ["node", "check-repo-size.ts"];
|
|
||||||
assert.throws(() => readArgs(), /--output-dir is required/);
|
|
||||||
} finally {
|
|
||||||
process.env = originalEnv;
|
|
||||||
process.argv = originalArgv;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let repoDir: string;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
repoDir = fs.mkdtempSync(path.join(os.tmpdir(), "check-repo-size-test-"));
|
|
||||||
execFileSync("git", ["init", "--initial-branch=main", "-q"], {
|
|
||||||
cwd: repoDir,
|
|
||||||
});
|
|
||||||
execFileSync("git", ["config", "user.email", "test@example.test"], {
|
|
||||||
cwd: repoDir,
|
|
||||||
});
|
|
||||||
execFileSync("git", ["config", "user.name", "Test"], { cwd: repoDir });
|
|
||||||
execFileSync("git", ["config", "commit.gpgsign", "false"], { cwd: repoDir });
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
fs.rmSync(repoDir, { recursive: true, force: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
function commit(name: string, content: string, message: string) {
|
|
||||||
fs.writeFileSync(path.join(repoDir, name), content);
|
|
||||||
execFileSync("git", ["add", name], { cwd: repoDir });
|
|
||||||
execFileSync("git", ["commit", "-q", "-m", message], { cwd: repoDir });
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("measureArchiveSize", async () => {
|
|
||||||
await it("returns a positive byte count for a non-empty repo", async () => {
|
|
||||||
commit("a.txt", "hello world\n", "first");
|
|
||||||
const size = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
assert.ok(size > 0, `expected size > 0, got ${size}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("returns the same size on repeated runs (deterministic)", async () => {
|
|
||||||
commit("a.txt", "hello world\n", "first");
|
|
||||||
const a = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
const b = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
assert.equal(a, b);
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("returns a larger size when more content is added", async () => {
|
|
||||||
commit("a.txt", "hello world\n", "first");
|
|
||||||
const small = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
|
|
||||||
// Use random bytes so the new content is incompressible and the archive
|
|
||||||
// is guaranteed to grow even after gzip.
|
|
||||||
commit("b.bin", randomBytes(8192).toString("base64"), "second");
|
|
||||||
const big = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
assert.ok(
|
|
||||||
big > small,
|
|
||||||
`expected ${big} > ${small} after adding more content`,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("ignores untracked files (e.g. node_modules)", async () => {
|
|
||||||
commit("a.txt", "hello\n", "first");
|
|
||||||
commit(".gitignore", "node_modules/\n", "ignore node_modules");
|
|
||||||
const sizeBefore = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
|
|
||||||
fs.mkdirSync(path.join(repoDir, "node_modules"));
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(repoDir, "node_modules", "huge.bin"),
|
|
||||||
"x".repeat(1_000_000),
|
|
||||||
);
|
|
||||||
|
|
||||||
const sizeAfter = await measureArchiveSize("HEAD", repoDir);
|
|
||||||
assert.equal(
|
|
||||||
sizeAfter,
|
|
||||||
sizeBefore,
|
|
||||||
"untracked node_modules should not affect the archive size",
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
await it("rejects when the ref does not exist", async () => {
|
|
||||||
commit("a.txt", "hello\n", "first");
|
|
||||||
await assert.rejects(
|
|
||||||
() => measureArchiveSize("does-not-exist", repoDir),
|
|
||||||
/git archive does-not-exist exited with code/,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
function escapeRegExp(s: string): string {
|
|
||||||
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
||||||
}
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
#!/usr/bin/env npx tsx
|
|
||||||
|
|
||||||
/*
|
|
||||||
Measures the difference in the `.tar.gz`'d checkout size of the repo between the PR head and the PR
|
|
||||||
base. This size is relevant because it corresponds to the duration of the "Download action
|
|
||||||
repository" step that happens at the start of every job that uses this Action.
|
|
||||||
|
|
||||||
Writes the candidate sticky-comment body and a small metadata file to `--output-dir`. A separate
|
|
||||||
workflow job consumes those artifacts and decides whether to create or update a PR comment.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { spawn } from "node:child_process";
|
|
||||||
import * as fs from "node:fs";
|
|
||||||
import * as path from "node:path";
|
|
||||||
import { parseArgs } from "node:util";
|
|
||||||
|
|
||||||
import { REPO_ROOT } from "./config";
|
|
||||||
|
|
||||||
/** Hidden marker used to find the existing sticky comment on a PR. */
|
|
||||||
export const COMMENT_MARKER = "<!-- repo-size-diff-bot -->";
|
|
||||||
|
|
||||||
export const DEFAULT_BASE_REF = "main";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fraction of the base archive size at which a delta is considered significant enough to warrant
|
|
||||||
* a new sticky comment. We always update an existing comment regardless, so the comment stays in
|
|
||||||
* sync as the diff evolves.
|
|
||||||
*/
|
|
||||||
export const SIGNIFICANT_DELTA_FRACTION = 0.1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stream `git archive --format=tar.gz <ref>` and count the compressed bytes.
|
|
||||||
*
|
|
||||||
* `git archive` only includes tracked files, so untracked directories like `node_modules` and
|
|
||||||
* `build` aren't counted in the size downloaded when starting up a CodeQL job.
|
|
||||||
*/
|
|
||||||
export async function measureArchiveSize(
|
|
||||||
ref: string,
|
|
||||||
cwd: string,
|
|
||||||
): Promise<number> {
|
|
||||||
const git = spawn("git", ["archive", "--format=tar.gz", ref], { cwd });
|
|
||||||
|
|
||||||
let stderr = "";
|
|
||||||
git.stderr.on("data", (chunk: Buffer) => {
|
|
||||||
stderr += chunk.toString();
|
|
||||||
});
|
|
||||||
|
|
||||||
let size = 0;
|
|
||||||
git.stdout.on("data", (chunk: Buffer) => {
|
|
||||||
size += chunk.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
const exitCode = await new Promise<number>((resolve, reject) => {
|
|
||||||
git.on("error", reject);
|
|
||||||
git.on("close", resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exitCode !== 0) {
|
|
||||||
throw new Error(
|
|
||||||
`git archive ${ref} exited with code ${exitCode}: ${stderr.trim()}`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a byte count as KiB. If `signed` is true, a leading `+` is prepended for non-negative
|
|
||||||
* values so gains and losses are visually distinct.
|
|
||||||
*/
|
|
||||||
export function formatBytes(bytes: number, signed = false): string {
|
|
||||||
const sign = bytes < 0 ? "-" : signed ? "+" : "";
|
|
||||||
const kib = Math.abs(bytes) / 1024;
|
|
||||||
return `${sign}${kib.toFixed(2)} KiB`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Format a fraction as a signed percentage with 2 decimal places. */
|
|
||||||
export function formatPercent(fraction: number): string {
|
|
||||||
const pct = fraction * 100;
|
|
||||||
const sign = pct > 0 ? "+" : "";
|
|
||||||
return `${sign}${pct.toFixed(2)}%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommentBodyOptions {
|
|
||||||
baseRef: string;
|
|
||||||
baseSize: number;
|
|
||||||
prSize: number;
|
|
||||||
/** Optional URL of the workflow run, included in the comment footer. */
|
|
||||||
runUrl?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildCommentBody(opts: CommentBodyOptions): string {
|
|
||||||
const { baseRef, baseSize, prSize, runUrl } = opts;
|
|
||||||
const delta = prSize - baseSize;
|
|
||||||
const signedDelta = delta >= 0 ? `+${delta}` : `${delta}`;
|
|
||||||
const runUrlLine = runUrl
|
|
||||||
? ` See the [workflow run](${runUrl}) for details.`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
return [
|
|
||||||
COMMENT_MARKER,
|
|
||||||
"### Repository checkout size",
|
|
||||||
"",
|
|
||||||
"| | Compressed archive size |",
|
|
||||||
"|---|---|",
|
|
||||||
`| Base (\`${baseRef}\`) | ${formatBytes(baseSize)} (${baseSize} bytes) |`,
|
|
||||||
`| This PR | ${formatBytes(prSize)} (${prSize} bytes) |`,
|
|
||||||
`| **Delta** | **${formatBytes(delta, true)} (${signedDelta} bytes, ${formatPercent(delta / baseSize)})** |`,
|
|
||||||
"",
|
|
||||||
"Sizes are measured by streaming `git archive --format=tar.gz <ref>`, " +
|
|
||||||
"which includes tracked files and excludes untracked files such as " +
|
|
||||||
"`node_modules`. The compressed checkout is " +
|
|
||||||
"downloaded by every consumer of this Action, so changes here directly " +
|
|
||||||
`affect Action download time.${runUrlLine}`,
|
|
||||||
].join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true when the absolute delta is at least `fraction` of the base size. Both increases and
|
|
||||||
* decreases are considered significant, so we report wins as well as losses.
|
|
||||||
*/
|
|
||||||
export function isDeltaSignificant(
|
|
||||||
delta: number,
|
|
||||||
baseSize: number,
|
|
||||||
fraction: number,
|
|
||||||
): boolean {
|
|
||||||
return Math.abs(delta) >= baseSize * fraction;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MainArgs {
|
|
||||||
/** Base ref of the PR. Defaults to `main`. Used as the label in the PR comment. */
|
|
||||||
baseRef: string;
|
|
||||||
/** Base commit-ish to archive. Defaults to `origin/<baseRef>` for local runs. */
|
|
||||||
baseCommitish: string;
|
|
||||||
/** Head commit-ish to archive. Defaults to `HEAD` for local runs. */
|
|
||||||
headCommitish: string;
|
|
||||||
/** Optional URL of the workflow run, surfaced in the comment footer. */
|
|
||||||
runUrl?: string;
|
|
||||||
/** Directory where `body.md` and `metadata.json` are written. */
|
|
||||||
outputDir: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function readArgs(): MainArgs {
|
|
||||||
const { values } = parseArgs({
|
|
||||||
options: {
|
|
||||||
"output-dir": { type: "string" },
|
|
||||||
},
|
|
||||||
strict: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const outputDir = values["output-dir"];
|
|
||||||
if (!outputDir) {
|
|
||||||
throw new Error("--output-dir is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseRef = process.env.BASE_REF ?? DEFAULT_BASE_REF;
|
|
||||||
const baseCommitish = process.env.BASE_SHA ?? `origin/${baseRef}`;
|
|
||||||
const headCommitish = process.env.HEAD_SHA ?? "HEAD";
|
|
||||||
|
|
||||||
return {
|
|
||||||
baseRef,
|
|
||||||
baseCommitish,
|
|
||||||
headCommitish,
|
|
||||||
runUrl: process.env.RUN_URL,
|
|
||||||
outputDir,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main(): Promise<number> {
|
|
||||||
const args = readArgs();
|
|
||||||
|
|
||||||
console.log(`Measuring base archive size for ${args.baseCommitish}...`);
|
|
||||||
const baseSize = await measureArchiveSize(args.baseCommitish, REPO_ROOT);
|
|
||||||
console.log(` ${baseSize} bytes`);
|
|
||||||
|
|
||||||
console.log(`Measuring PR archive size for ${args.headCommitish}...`);
|
|
||||||
const prSize = await measureArchiveSize(args.headCommitish, REPO_ROOT);
|
|
||||||
console.log(` ${prSize} bytes`);
|
|
||||||
|
|
||||||
const delta = prSize - baseSize;
|
|
||||||
const significant = isDeltaSignificant(
|
|
||||||
delta,
|
|
||||||
baseSize,
|
|
||||||
SIGNIFICANT_DELTA_FRACTION,
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
`Delta: ${delta} bytes (significant=${significant}, threshold=${(
|
|
||||||
SIGNIFICANT_DELTA_FRACTION * 100
|
|
||||||
).toFixed(2)}%)`,
|
|
||||||
);
|
|
||||||
|
|
||||||
const body = buildCommentBody({
|
|
||||||
baseRef: args.baseRef,
|
|
||||||
baseSize,
|
|
||||||
prSize,
|
|
||||||
runUrl: args.runUrl,
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.mkdirSync(args.outputDir, { recursive: true });
|
|
||||||
fs.writeFileSync(path.join(args.outputDir, "body.md"), body);
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.join(args.outputDir, "metadata.json"),
|
|
||||||
`${JSON.stringify(
|
|
||||||
{ significant, baseRef: args.baseRef, baseSize, prSize, delta },
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
)}\n`,
|
|
||||||
);
|
|
||||||
console.log(`Wrote body.md and metadata.json to ${args.outputDir}.`);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
try {
|
|
||||||
process.exit(await main());
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err instanceof Error ? err.message : String(err));
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (require.main === module) {
|
|
||||||
void run();
|
|
||||||
}
|
|
||||||
+2
-5
@@ -6,17 +6,14 @@ export const OLDEST_SUPPORTED_MAJOR_VERSION = 3;
|
|||||||
/** The `pr-checks` directory. */
|
/** The `pr-checks` directory. */
|
||||||
export const PR_CHECKS_DIR = __dirname;
|
export const PR_CHECKS_DIR = __dirname;
|
||||||
|
|
||||||
/** The repository root. */
|
|
||||||
export const REPO_ROOT = path.join(PR_CHECKS_DIR, "..");
|
|
||||||
|
|
||||||
/** The path of the file configuring which checks shouldn't be required. */
|
/** The path of the file configuring which checks shouldn't be required. */
|
||||||
export const PR_CHECK_EXCLUDED_FILE = path.join(PR_CHECKS_DIR, "excluded.yml");
|
export const PR_CHECK_EXCLUDED_FILE = path.join(PR_CHECKS_DIR, "excluded.yml");
|
||||||
|
|
||||||
/** The path to the esbuild metadata file. */
|
/** The path to the esbuild metadata file. */
|
||||||
export const BUNDLE_METADATA_FILE = path.join(REPO_ROOT, "meta.json");
|
export const BUNDLE_METADATA_FILE = path.join(PR_CHECKS_DIR, "..", "meta.json");
|
||||||
|
|
||||||
/** The `src` directory. */
|
/** The `src` directory. */
|
||||||
const SOURCE_ROOT = path.join(REPO_ROOT, "src");
|
const SOURCE_ROOT = path.join(PR_CHECKS_DIR, "..", "src");
|
||||||
|
|
||||||
/** The path to the built-in languages file. */
|
/** The path to the built-in languages file. */
|
||||||
export const BUILTIN_LANGUAGES_FILE = path.join(
|
export const BUILTIN_LANGUAGES_FILE = path.join(
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
# PR checks to exclude from required checks
|
# PR checks to exclude from required checks
|
||||||
contains:
|
contains:
|
||||||
- "ESLint"
|
|
||||||
- "https://"
|
- "https://"
|
||||||
- "test-setup-python-scripts"
|
|
||||||
- "update"
|
|
||||||
- "Update"
|
- "Update"
|
||||||
|
- "ESLint"
|
||||||
|
- "update"
|
||||||
|
- "test-setup-python-scripts"
|
||||||
is:
|
is:
|
||||||
- "Agent"
|
|
||||||
- "check-expected-release-files"
|
|
||||||
- "Cleanup artifacts"
|
|
||||||
- "CodeQL"
|
- "CodeQL"
|
||||||
- "Dependabot"
|
- "Dependabot"
|
||||||
- "Label PR with size"
|
- "check-expected-release-files"
|
||||||
- "Post repo size comment"
|
- "Agent"
|
||||||
|
- "Cleanup artifacts"
|
||||||
- "Prepare"
|
- "Prepare"
|
||||||
- "Upload results"
|
- "Upload results"
|
||||||
|
- "Label PR with size"
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ predicate isSafeForDefaultSetup(string envVar) {
|
|||||||
"GITHUB_BASE_REF", "GITHUB_EVENT_NAME", "GITHUB_JOB", "GITHUB_RUN_ATTEMPT", "GITHUB_RUN_ID",
|
"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_SHA", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_TOKEN", "GITHUB_WORKFLOW",
|
||||||
"GITHUB_WORKSPACE", "GOFLAGS", "ImageVersion", "JAVA_TOOL_OPTIONS", "RUNNER_ARCH",
|
"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"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +43,6 @@ predicate envVarRead(DataFlow::Node node, string envVar) {
|
|||||||
from DataFlow::Node read, string envVar
|
from DataFlow::Node read, string envVar
|
||||||
where
|
where
|
||||||
envVarRead(read, envVar) and
|
envVarRead(read, envVar) and
|
||||||
read.getFile().getRelativePath().matches("src/%") and
|
|
||||||
not read.getFile().getBaseName().matches("%.test.ts") and
|
not read.getFile().getBaseName().matches("%.test.ts") and
|
||||||
not isSafeForDefaultSetup(envVar)
|
not isSafeForDefaultSetup(envVar)
|
||||||
select read,
|
select read,
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export async function runWrapper() {
|
|||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
if (config !== undefined) {
|
if (config !== undefined) {
|
||||||
const codeql = await getCodeQL(config.codeQLCmd);
|
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
const version = await codeql.getVersion();
|
const version = await codeql.getVersion();
|
||||||
await debugArtifacts.uploadCombinedSarifArtifacts(
|
await debugArtifacts.uploadCombinedSarifArtifacts(
|
||||||
logger,
|
logger,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import {
|
|||||||
DependencyCacheUploadStatusReport,
|
DependencyCacheUploadStatusReport,
|
||||||
uploadDependencyCaches,
|
uploadDependencyCaches,
|
||||||
} from "./dependency-caching";
|
} from "./dependency-caching";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { initFeatures } from "./feature-flags";
|
import { initFeatures } from "./feature-flags";
|
||||||
import { BuiltInLanguage } from "./languages";
|
import { BuiltInLanguage } from "./languages";
|
||||||
import { getActionsLogger, Logger } from "./logging";
|
import { getActionsLogger, Logger } from "./logging";
|
||||||
@@ -256,7 +256,7 @@ async function run(startedAt: Date) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeql = await getCodeQL(config.codeQLCmd);
|
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
|
|
||||||
if (hasBadExpectErrorInput()) {
|
if (hasBadExpectErrorInput()) {
|
||||||
throw new util.ConfigurationError(
|
throw new util.ConfigurationError(
|
||||||
@@ -284,7 +284,7 @@ async function run(startedAt: Date) {
|
|||||||
|
|
||||||
const apiDetails = getApiDetails();
|
const apiDetails = getApiDetails();
|
||||||
const outputDir = actionsUtil.getRequiredInput("output");
|
const outputDir = actionsUtil.getRequiredInput("output");
|
||||||
exportVariable(EnvVar.SARIF_RESULTS_OUTPUT_DIR, outputDir);
|
core.exportVariable(EnvVar.SARIF_RESULTS_OUTPUT_DIR, outputDir);
|
||||||
const threads = util.getThreadsFlag(
|
const threads = util.getThreadsFlag(
|
||||||
actionsUtil.getOptionalInput("threads") || process.env["CODEQL_THREADS"],
|
actionsUtil.getOptionalInput("threads") || process.env["CODEQL_THREADS"],
|
||||||
logger,
|
logger,
|
||||||
@@ -444,7 +444,7 @@ async function run(startedAt: Date) {
|
|||||||
`expect-error input was set to true but no error was thrown.`,
|
`expect-error input was set to true but no error was thrown.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
exportVariable(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
|
core.exportVariable(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||||
} catch (unwrappedError) {
|
} catch (unwrappedError) {
|
||||||
const error = util.wrapError(unwrappedError);
|
const error = util.wrapError(unwrappedError);
|
||||||
if (
|
if (
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@ import * as githubUtils from "@actions/github/lib/utils";
|
|||||||
import * as retry from "@octokit/plugin-retry";
|
import * as retry from "@octokit/plugin-retry";
|
||||||
|
|
||||||
import { getActionVersion, getRequiredInput } from "./actions-util";
|
import { getActionVersion, getRequiredInput } from "./actions-util";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { Logger } from "./logging";
|
import { Logger } from "./logging";
|
||||||
import { getRepositoryNwo, RepositoryNwo } from "./repository";
|
import { getRepositoryNwo, RepositoryNwo } from "./repository";
|
||||||
import {
|
import {
|
||||||
@@ -216,7 +216,7 @@ export async function getAnalysisKey(): Promise<string> {
|
|||||||
const jobName = getRequiredEnvParam("GITHUB_JOB");
|
const jobName = getRequiredEnvParam("GITHUB_JOB");
|
||||||
|
|
||||||
analysisKey = `${workflowPath}:${jobName}`;
|
analysisKey = `${workflowPath}:${jobName}`;
|
||||||
exportVariable(EnvVar.ANALYSIS_KEY, analysisKey);
|
core.exportVariable(EnvVar.ANALYSIS_KEY, analysisKey);
|
||||||
return analysisKey;
|
return analysisKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { getGitHubVersion } from "./api-client";
|
|||||||
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
|
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
|
||||||
import { getCodeQL } from "./codeql";
|
import { getCodeQL } from "./codeql";
|
||||||
import { Config, getConfig } from "./config-utils";
|
import { Config, getConfig } from "./config-utils";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { Language } from "./languages";
|
import { Language } from "./languages";
|
||||||
import { Logger, getActionsLogger } from "./logging";
|
import { Logger, getActionsLogger } from "./logging";
|
||||||
import {
|
import {
|
||||||
@@ -101,7 +101,7 @@ async function run(startedAt: Date) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const codeql = await getCodeQL(config.codeQLCmd);
|
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
|
|
||||||
languages = await determineAutobuildLanguages(codeql, config, logger);
|
languages = await determineAutobuildLanguages(codeql, config, logger);
|
||||||
if (languages !== undefined) {
|
if (languages !== undefined) {
|
||||||
@@ -137,7 +137,7 @@ async function run(startedAt: Date) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
exportVariable(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
|
core.exportVariable(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||||
|
|
||||||
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
|
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -1,9 +1,11 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
import { getTemporaryDirectory, getWorkflowEventName } from "./actions-util";
|
import { getTemporaryDirectory, getWorkflowEventName } from "./actions-util";
|
||||||
import { getGitHubVersion } from "./api-client";
|
import { getGitHubVersion } from "./api-client";
|
||||||
import { CodeQL, getCodeQL } from "./codeql";
|
import { CodeQL, getCodeQL } from "./codeql";
|
||||||
import * as configUtils from "./config-utils";
|
import * as configUtils from "./config-utils";
|
||||||
import { DocUrl } from "./doc-url";
|
import { DocUrl } from "./doc-url";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { Feature, featureConfig, initFeatures } from "./feature-flags";
|
import { Feature, featureConfig, initFeatures } from "./feature-flags";
|
||||||
import { BuiltInLanguage, Language } from "./languages";
|
import { BuiltInLanguage, Language } from "./languages";
|
||||||
import { Logger } from "./logging";
|
import { Logger } from "./logging";
|
||||||
@@ -134,16 +136,16 @@ export async function setupCppAutobuild(codeql: CodeQL, logger: Logger) {
|
|||||||
: ""
|
: ""
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
exportVariable(envVar, "false");
|
core.exportVariable(envVar, "false");
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
`Enabling ${featureName}. This can be disabled by setting the ${envVar} environment variable to 'false'. See ${DocUrl.DEFINE_ENV_VARIABLES} for more information.`,
|
`Enabling ${featureName}. This can be disabled by setting the ${envVar} environment variable to 'false'. See ${DocUrl.DEFINE_ENV_VARIABLES} for more information.`,
|
||||||
);
|
);
|
||||||
exportVariable(envVar, "true");
|
core.exportVariable(envVar, "true");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.info(`Disabling ${featureName}.`);
|
logger.info(`Disabling ${featureName}.`);
|
||||||
exportVariable(envVar, "false");
|
core.exportVariable(envVar, "false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +155,7 @@ export async function runAutobuild(
|
|||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
logger.startGroup(`Attempting to automatically build ${language} code`);
|
logger.startGroup(`Attempting to automatically build ${language} code`);
|
||||||
const codeQL = await getCodeQL(config.codeQLCmd);
|
const codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
if (language === BuiltInLanguage.cpp) {
|
if (language === BuiltInLanguage.cpp) {
|
||||||
await setupCppAutobuild(codeQL, logger);
|
await setupCppAutobuild(codeQL, logger);
|
||||||
}
|
}
|
||||||
@@ -163,7 +165,7 @@ export async function runAutobuild(
|
|||||||
await codeQL.runAutobuild(config, language);
|
await codeQL.runAutobuild(config, language);
|
||||||
}
|
}
|
||||||
if (language === BuiltInLanguage.go) {
|
if (language === BuiltInLanguage.go) {
|
||||||
exportVariable(EnvVar.DID_AUTOBUILD_GOLANG, "true");
|
core.exportVariable(EnvVar.DID_AUTOBUILD_GOLANG, "true");
|
||||||
}
|
}
|
||||||
logger.endGroup();
|
logger.endGroup();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
import { ExecOptions } from "@actions/exec";
|
import { ExecOptions } from "@actions/exec";
|
||||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||||
@@ -123,6 +124,166 @@ async function stubCodeql(): Promise<codeql.CodeQL> {
|
|||||||
return codeqlObject;
|
return codeqlObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stubSuccessfulToolRunner(
|
||||||
|
stdoutForArgs: (args: string[]) => string | undefined,
|
||||||
|
): sinon.SinonStub<any[], toolrunner.ToolRunner> {
|
||||||
|
const runnerConstructorStub = sinon.stub(
|
||||||
|
toolrunner,
|
||||||
|
"ToolRunner",
|
||||||
|
) as sinon.SinonStub<any[], toolrunner.ToolRunner>;
|
||||||
|
|
||||||
|
runnerConstructorStub.callsFake((_cmd, args, options: ExecOptions) => {
|
||||||
|
return {
|
||||||
|
exec: async () => {
|
||||||
|
const stdout = stdoutForArgs(args as string[]);
|
||||||
|
if (stdout !== undefined) {
|
||||||
|
options.listeners?.stdout?.(Buffer.from(stdout));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
} as toolrunner.ToolRunner;
|
||||||
|
});
|
||||||
|
|
||||||
|
return runnerConstructorStub;
|
||||||
|
}
|
||||||
|
|
||||||
|
test.serial("getVersion and printVersion share cached version", async (t) => {
|
||||||
|
const version = { version: "2.30.0" };
|
||||||
|
let versionCalls = 0;
|
||||||
|
stubSuccessfulToolRunner((args) => {
|
||||||
|
if (args.join(" ") === "version --format=json") {
|
||||||
|
versionCalls++;
|
||||||
|
return JSON.stringify(version);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
|
||||||
|
t.deepEqual(await codeqlObject.getVersion(), version);
|
||||||
|
await codeqlObject.printVersion();
|
||||||
|
|
||||||
|
t.is(versionCalls, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial(
|
||||||
|
"betterResolveLanguages caches only the unfiltered result",
|
||||||
|
async (t) => {
|
||||||
|
const unfilteredLanguages = {
|
||||||
|
aliases: { typescript: BuiltInLanguage.javascript },
|
||||||
|
extractors: {
|
||||||
|
html: [{ extractor_root: "/html" }],
|
||||||
|
javascript: [{ extractor_root: "/javascript" }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const filteredLanguages = {
|
||||||
|
aliases: { typescript: BuiltInLanguage.javascript },
|
||||||
|
extractors: {
|
||||||
|
javascript: [{ extractor_root: "/javascript" }],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let unfilteredCalls = 0;
|
||||||
|
let filteredCalls = 0;
|
||||||
|
stubSuccessfulToolRunner((args) => {
|
||||||
|
if (args[0] === "resolve" && args[1] === "languages") {
|
||||||
|
if (args.includes("--filter-to-languages-with-queries")) {
|
||||||
|
filteredCalls++;
|
||||||
|
return JSON.stringify(filteredLanguages);
|
||||||
|
}
|
||||||
|
unfilteredCalls++;
|
||||||
|
return JSON.stringify(unfilteredLanguages);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
|
||||||
|
t.deepEqual(
|
||||||
|
await codeqlObject.betterResolveLanguages(),
|
||||||
|
unfilteredLanguages,
|
||||||
|
);
|
||||||
|
t.deepEqual(
|
||||||
|
await codeqlObject.betterResolveLanguages(),
|
||||||
|
unfilteredLanguages,
|
||||||
|
);
|
||||||
|
t.deepEqual(
|
||||||
|
await codeqlObject.betterResolveLanguages({
|
||||||
|
filterToLanguagesWithQueries: true,
|
||||||
|
}),
|
||||||
|
filteredLanguages,
|
||||||
|
);
|
||||||
|
t.deepEqual(
|
||||||
|
await codeqlObject.betterResolveLanguages({
|
||||||
|
filterToLanguagesWithQueries: true,
|
||||||
|
}),
|
||||||
|
filteredLanguages,
|
||||||
|
);
|
||||||
|
|
||||||
|
// The unfiltered result is cached after the first call; the filtered
|
||||||
|
// variant is not cached because nothing reuses it.
|
||||||
|
t.is(unfilteredCalls, 1);
|
||||||
|
t.is(filteredCalls, 2);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test.serial("resolveExtractor caches its result per language", async (t) => {
|
||||||
|
await util.withTmpDir(async (tempDir) => {
|
||||||
|
const extractorRoot = path.join(tempDir, "javascript");
|
||||||
|
fs.mkdirSync(path.join(extractorRoot, "tools"), { recursive: true });
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.join(extractorRoot, "tools", "tracing-config.lua"),
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
|
||||||
|
let resolveExtractorCalls = 0;
|
||||||
|
stubSuccessfulToolRunner((args) => {
|
||||||
|
if (args[0] === "resolve" && args[1] === "extractor") {
|
||||||
|
resolveExtractorCalls++;
|
||||||
|
return JSON.stringify(extractorRoot);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
|
||||||
|
t.is(
|
||||||
|
await codeqlObject.resolveExtractor(BuiltInLanguage.javascript),
|
||||||
|
extractorRoot,
|
||||||
|
);
|
||||||
|
t.is(
|
||||||
|
await codeqlObject.resolveExtractor(BuiltInLanguage.javascript),
|
||||||
|
extractorRoot,
|
||||||
|
);
|
||||||
|
t.true(await codeqlObject.isTracedLanguage(BuiltInLanguage.javascript));
|
||||||
|
t.is(resolveExtractorCalls, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.serial(
|
||||||
|
"hydrateCliMetadata seeds the cache from persisted metadata",
|
||||||
|
async (t) => {
|
||||||
|
let cliCalls = 0;
|
||||||
|
stubSuccessfulToolRunner((_args) => {
|
||||||
|
cliCalls++;
|
||||||
|
return "{}";
|
||||||
|
});
|
||||||
|
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
|
||||||
|
codeqlObject.hydrateCliMetadata({
|
||||||
|
codeQLCmd: "codeql-for-testing",
|
||||||
|
extractorPaths: { javascript: "/javascript" },
|
||||||
|
});
|
||||||
|
|
||||||
|
t.is(
|
||||||
|
await codeqlObject.resolveExtractor(BuiltInLanguage.javascript),
|
||||||
|
"/javascript",
|
||||||
|
);
|
||||||
|
t.is(cliCalls, 0);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test.serial(
|
test.serial(
|
||||||
"downloads and caches explicitly requested bundles that aren't in the toolcache",
|
"downloads and caches explicitly requested bundles that aren't in the toolcache",
|
||||||
async (t) => {
|
async (t) => {
|
||||||
|
|||||||
+89
-15
@@ -15,7 +15,7 @@ import * as api from "./api-client";
|
|||||||
import { CliError, wrapCliConfigurationError } from "./cli-errors";
|
import { CliError, wrapCliConfigurationError } from "./cli-errors";
|
||||||
import { appendExtraQueryExclusions, type Config } from "./config-utils";
|
import { appendExtraQueryExclusions, type Config } from "./config-utils";
|
||||||
import { DocUrl } from "./doc-url";
|
import { DocUrl } from "./doc-url";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import {
|
import {
|
||||||
CodeQLDefaultVersionInfo,
|
CodeQLDefaultVersionInfo,
|
||||||
Feature,
|
Feature,
|
||||||
@@ -218,6 +218,10 @@ export interface CodeQL {
|
|||||||
outputFile: string,
|
outputFile: string,
|
||||||
options: { mergeRunsFromEqualCategory?: boolean },
|
options: { mergeRunsFromEqualCategory?: boolean },
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
|
/** Return cacheable metadata gathered from the CodeQL CLI. */
|
||||||
|
getCliMetadata(): CodeQLCliMetadata;
|
||||||
|
/** Hydrate the CodeQL wrapper with cacheable metadata gathered earlier in the job. */
|
||||||
|
hydrateCliMetadata(metadata: CodeQLCliMetadata | undefined): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VersionInfo {
|
export interface VersionInfo {
|
||||||
@@ -247,12 +251,10 @@ export interface BetterResolveLanguagesOutput {
|
|||||||
[alias: string]: string;
|
[alias: string]: string;
|
||||||
};
|
};
|
||||||
extractors: {
|
extractors: {
|
||||||
[language: string]: [
|
[language: string]: Array<{
|
||||||
{
|
extractor_root: string;
|
||||||
extractor_root: string;
|
extractor_options?: any;
|
||||||
extractor_options?: any;
|
}>;
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,6 +266,11 @@ export interface ResolveBuildEnvironmentOutput {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CodeQLCliMetadata {
|
||||||
|
codeQLCmd: string;
|
||||||
|
extractorPaths?: { [language: string]: string };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
|
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
|
||||||
*/
|
*/
|
||||||
@@ -392,9 +399,14 @@ export async function setupCodeQL(
|
|||||||
/**
|
/**
|
||||||
* Use the CodeQL executable located at the given path.
|
* Use the CodeQL executable located at the given path.
|
||||||
*/
|
*/
|
||||||
export async function getCodeQL(cmd: string): Promise<CodeQL> {
|
export async function getCodeQL(
|
||||||
|
cmd: string,
|
||||||
|
cliMetadata?: CodeQLCliMetadata,
|
||||||
|
): Promise<CodeQL> {
|
||||||
if (cachedCodeQL === undefined) {
|
if (cachedCodeQL === undefined) {
|
||||||
cachedCodeQL = await getCodeQLForCmd(cmd, true);
|
cachedCodeQL = await getCodeQLForCmd(cmd, true, cliMetadata);
|
||||||
|
} else {
|
||||||
|
cachedCodeQL.hydrateCliMetadata(cliMetadata);
|
||||||
}
|
}
|
||||||
return cachedCodeQL;
|
return cachedCodeQL;
|
||||||
}
|
}
|
||||||
@@ -492,6 +504,14 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
|
|||||||
),
|
),
|
||||||
resolveDatabase: resolveFunction(partialCodeql, "resolveDatabase"),
|
resolveDatabase: resolveFunction(partialCodeql, "resolveDatabase"),
|
||||||
mergeResults: resolveFunction(partialCodeql, "mergeResults"),
|
mergeResults: resolveFunction(partialCodeql, "mergeResults"),
|
||||||
|
getCliMetadata: resolveFunction(partialCodeql, "getCliMetadata", () => ({
|
||||||
|
codeQLCmd: partialCodeql.getPath?.() ?? "/tmp/dummy-path",
|
||||||
|
})),
|
||||||
|
hydrateCliMetadata: resolveFunction(
|
||||||
|
partialCodeql,
|
||||||
|
"hydrateCliMetadata",
|
||||||
|
() => {},
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,6 +526,12 @@ export async function getCodeQLForTesting(
|
|||||||
return getCodeQLForCmd(cmd, false);
|
return getCodeQLForCmd(cmd, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cacheCodeQlVersionForStatusReports(versionInfo: VersionInfo): void {
|
||||||
|
if (util.getCachedCodeQlVersion() === undefined) {
|
||||||
|
util.cacheCodeQlVersion(versionInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a CodeQL object for CodeQL CLI access.
|
* Return a CodeQL object for CodeQL CLI access.
|
||||||
*
|
*
|
||||||
@@ -517,13 +543,24 @@ export async function getCodeQLForTesting(
|
|||||||
async function getCodeQLForCmd(
|
async function getCodeQLForCmd(
|
||||||
cmd: string,
|
cmd: string,
|
||||||
checkVersion: boolean,
|
checkVersion: boolean,
|
||||||
|
initialCliMetadata?: CodeQLCliMetadata,
|
||||||
): Promise<CodeQL> {
|
): Promise<CodeQL> {
|
||||||
|
// Metadata persisted across the init/autobuild/analyze steps. Only extractor
|
||||||
|
// paths are reused by a later step, so that's all this holds.
|
||||||
|
const cliMetadata: CodeQLCliMetadata = { codeQLCmd: cmd };
|
||||||
|
// In-process-only caches. These aren't persisted because no later step reuses
|
||||||
|
// them: the CLI version always matches across steps, and `resolve languages`
|
||||||
|
// is only re-read within a single step.
|
||||||
|
let cachedVersion: VersionInfo | undefined;
|
||||||
|
let cachedUnfilteredBetterResolveLanguages:
|
||||||
|
| BetterResolveLanguagesOutput
|
||||||
|
| undefined;
|
||||||
const codeql: CodeQL = {
|
const codeql: CodeQL = {
|
||||||
getPath() {
|
getPath() {
|
||||||
return cmd;
|
return cmd;
|
||||||
},
|
},
|
||||||
async getVersion() {
|
async getVersion() {
|
||||||
let result = util.getCachedCodeQlVersion();
|
let result = cachedVersion;
|
||||||
if (result === undefined) {
|
if (result === undefined) {
|
||||||
const output = await runCli(cmd, ["version", "--format=json"], {
|
const output = await runCli(cmd, ["version", "--format=json"], {
|
||||||
noStreamStdout: true,
|
noStreamStdout: true,
|
||||||
@@ -535,12 +572,15 @@ async function getCodeQLForCmd(
|
|||||||
`Invalid JSON output from \`version --format=json\`: ${output}`,
|
`Invalid JSON output from \`version --format=json\`: ${output}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
util.cacheCodeQlVersion(result);
|
cachedVersion = result;
|
||||||
}
|
}
|
||||||
|
cacheCodeQlVersionForStatusReports(result);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
async printVersion() {
|
async printVersion() {
|
||||||
await runCli(cmd, ["version", "--format=json"]);
|
const version = await this.getVersion();
|
||||||
|
process.stdout.write(`[command]${cmd} version --format=json\n`);
|
||||||
|
process.stdout.write(`${JSON.stringify(version)}\n`);
|
||||||
},
|
},
|
||||||
async supportsFeature(feature: ToolsFeature) {
|
async supportsFeature(feature: ToolsFeature) {
|
||||||
return isSupportedToolsFeature(await this.getVersion(), feature);
|
return isSupportedToolsFeature(await this.getVersion(), feature);
|
||||||
@@ -758,6 +798,13 @@ async function getCodeQLForCmd(
|
|||||||
filterToLanguagesWithQueries: boolean;
|
filterToLanguagesWithQueries: boolean;
|
||||||
} = { filterToLanguagesWithQueries: false },
|
} = { filterToLanguagesWithQueries: false },
|
||||||
) {
|
) {
|
||||||
|
if (
|
||||||
|
!filterToLanguagesWithQueries &&
|
||||||
|
cachedUnfilteredBetterResolveLanguages
|
||||||
|
) {
|
||||||
|
return cachedUnfilteredBetterResolveLanguages;
|
||||||
|
}
|
||||||
|
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
"resolve",
|
"resolve",
|
||||||
"languages",
|
"languages",
|
||||||
@@ -772,7 +819,11 @@ async function getCodeQLForCmd(
|
|||||||
const output = await runCli(cmd, codeqlArgs);
|
const output = await runCli(cmd, codeqlArgs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return JSON.parse(output) as BetterResolveLanguagesOutput;
|
const result = JSON.parse(output) as BetterResolveLanguagesOutput;
|
||||||
|
if (!filterToLanguagesWithQueries) {
|
||||||
|
cachedUnfilteredBetterResolveLanguages = result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`,
|
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`,
|
||||||
@@ -968,6 +1019,11 @@ async function getCodeQLForCmd(
|
|||||||
await new toolrunner.ToolRunner(cmd, args).exec();
|
await new toolrunner.ToolRunner(cmd, args).exec();
|
||||||
},
|
},
|
||||||
async resolveExtractor(language: Language): Promise<string> {
|
async resolveExtractor(language: Language): Promise<string> {
|
||||||
|
const cachedExtractorPath = cliMetadata.extractorPaths?.[language];
|
||||||
|
if (cachedExtractorPath !== undefined) {
|
||||||
|
return cachedExtractorPath;
|
||||||
|
}
|
||||||
|
|
||||||
// Request it using `format=json` so we don't need to strip the trailing new line generated by
|
// Request it using `format=json` so we don't need to strip the trailing new line generated by
|
||||||
// the CLI.
|
// the CLI.
|
||||||
let extractorPath = "";
|
let extractorPath = "";
|
||||||
@@ -993,7 +1049,10 @@ async function getCodeQLForCmd(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
).exec();
|
).exec();
|
||||||
return JSON.parse(extractorPath) as string;
|
const resolvedExtractorPath = JSON.parse(extractorPath) as string;
|
||||||
|
cliMetadata.extractorPaths ??= {};
|
||||||
|
cliMetadata.extractorPaths[language] = resolvedExtractorPath;
|
||||||
|
return resolvedExtractorPath;
|
||||||
},
|
},
|
||||||
async resolveQueriesStartingPacks(queries: string[]): Promise<string[]> {
|
async resolveQueriesStartingPacks(queries: string[]): Promise<string[]> {
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
@@ -1058,7 +1117,22 @@ async function getCodeQLForCmd(
|
|||||||
|
|
||||||
await runCli(cmd, args);
|
await runCli(cmd, args);
|
||||||
},
|
},
|
||||||
|
getCliMetadata() {
|
||||||
|
return cliMetadata;
|
||||||
|
},
|
||||||
|
hydrateCliMetadata(metadata: CodeQLCliMetadata | undefined): void {
|
||||||
|
if (metadata?.codeQLCmd !== cliMetadata.codeQLCmd) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cliMetadata.extractorPaths = {
|
||||||
|
...metadata.extractorPaths,
|
||||||
|
...cliMetadata.extractorPaths,
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
// Seed the cache with any metadata persisted by an earlier step.
|
||||||
|
codeql.hydrateCliMetadata(initialCliMetadata);
|
||||||
// To ensure that status reports include the CodeQL CLI version wherever
|
// To ensure that status reports include the CodeQL CLI version wherever
|
||||||
// possible, we want to call getVersion(), which populates the version value
|
// possible, we want to call getVersion(), which populates the version value
|
||||||
// used by status reporting, at the earliest opportunity. But invoking
|
// used by status reporting, at the earliest opportunity. But invoking
|
||||||
@@ -1096,7 +1170,7 @@ async function getCodeQLForCmd(
|
|||||||
}' by 'github/codeql-action/*@v${getActionVersion()}' in your code scanning workflow to ` +
|
}' by 'github/codeql-action/*@v${getActionVersion()}' in your code scanning workflow to ` +
|
||||||
"continue using this version of the CodeQL Action.",
|
"continue using this version of the CodeQL Action.",
|
||||||
);
|
);
|
||||||
exportVariable(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
|
core.exportVariable(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
|
||||||
}
|
}
|
||||||
return codeql;
|
return codeql;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -2,6 +2,7 @@ import * as fs from "fs";
|
|||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { performance } from "perf_hooks";
|
import { performance } from "perf_hooks";
|
||||||
|
|
||||||
|
import * as core from "@actions/core";
|
||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -18,7 +19,7 @@ import {
|
|||||||
} from "./analyses";
|
} from "./analyses";
|
||||||
import * as api from "./api-client";
|
import * as api from "./api-client";
|
||||||
import { CachingKind, getCachingKind } from "./caching-utils";
|
import { CachingKind, getCachingKind } from "./caching-utils";
|
||||||
import { type CodeQL } from "./codeql";
|
import { type CodeQL, type CodeQLCliMetadata } from "./codeql";
|
||||||
import {
|
import {
|
||||||
calculateAugmentation,
|
calculateAugmentation,
|
||||||
ExcludeQueryFilter,
|
ExcludeQueryFilter,
|
||||||
@@ -31,7 +32,7 @@ import {
|
|||||||
makeTelemetryDiagnostic,
|
makeTelemetryDiagnostic,
|
||||||
} from "./diagnostics";
|
} from "./diagnostics";
|
||||||
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import * as errorMessages from "./error-messages";
|
import * as errorMessages from "./error-messages";
|
||||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||||
import {
|
import {
|
||||||
@@ -176,6 +177,10 @@ export interface Config {
|
|||||||
* Path of the CodeQL executable.
|
* Path of the CodeQL executable.
|
||||||
*/
|
*/
|
||||||
codeQLCmd: string;
|
codeQLCmd: string;
|
||||||
|
/**
|
||||||
|
* Cacheable metadata gathered from the CodeQL CLI while initializing the workflow.
|
||||||
|
*/
|
||||||
|
codeQLMetadata?: CodeQLCliMetadata;
|
||||||
/**
|
/**
|
||||||
* Version of GitHub we are talking to.
|
* Version of GitHub we are talking to.
|
||||||
*/
|
*/
|
||||||
@@ -560,6 +565,7 @@ export async function initActionState(
|
|||||||
computedConfig,
|
computedConfig,
|
||||||
tempDir,
|
tempDir,
|
||||||
codeQLCmd: codeql.getPath(),
|
codeQLCmd: codeql.getPath(),
|
||||||
|
codeQLMetadata: codeql.getCliMetadata(),
|
||||||
gitHubVersion: githubVersion,
|
gitHubVersion: githubVersion,
|
||||||
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
|
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
|
||||||
debugMode,
|
debugMode,
|
||||||
@@ -1044,10 +1050,10 @@ async function setCppTrapCachingEnvironmentVariables(
|
|||||||
);
|
);
|
||||||
} else if (config.trapCaches[BuiltInLanguage.cpp]) {
|
} else if (config.trapCaches[BuiltInLanguage.cpp]) {
|
||||||
logger.info("Enabling TRAP caching for C/C++.");
|
logger.info("Enabling TRAP caching for C/C++.");
|
||||||
exportVariable(envVar, "true");
|
core.exportVariable(envVar, "true");
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`Disabling TRAP caching for C/C++.`);
|
logger.debug(`Disabling TRAP caching for C/C++.`);
|
||||||
exportVariable(envVar, "false");
|
core.exportVariable(envVar, "false");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { dbIsFinalized } from "./analyze";
|
|||||||
import { scanArtifactsForTokens } from "./artifact-scanner";
|
import { scanArtifactsForTokens } from "./artifact-scanner";
|
||||||
import { type CodeQL } from "./codeql";
|
import { type CodeQL } from "./codeql";
|
||||||
import { Config } from "./config-utils";
|
import { Config } from "./config-utils";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import * as json from "./json";
|
import * as json from "./json";
|
||||||
import { Language } from "./languages";
|
import { Language } from "./languages";
|
||||||
import { Logger, withGroup } from "./logging";
|
import { Logger, withGroup } from "./logging";
|
||||||
@@ -330,7 +330,7 @@ export async function uploadArtifacts(
|
|||||||
// some issues early.
|
// some issues early.
|
||||||
if (isInTestMode()) {
|
if (isInTestMode()) {
|
||||||
await scanArtifactsForTokens(toUpload, logger);
|
await scanArtifactsForTokens(toUpload, logger);
|
||||||
exportVariable("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
|
core.exportVariable("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
const suffix = getArtifactSuffix(getOptionalInput("matrix"));
|
const suffix = getArtifactSuffix(getOptionalInput("matrix"));
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"bundleVersion": "codeql-bundle-v2.25.5",
|
"bundleVersion": "codeql-bundle-v2.25.4",
|
||||||
"cliVersion": "2.25.5",
|
"cliVersion": "2.25.4",
|
||||||
"priorBundleVersion": "codeql-bundle-v2.25.4",
|
"priorBundleVersion": "codeql-bundle-v2.25.3",
|
||||||
"priorCliVersion": "2.25.4"
|
"priorCliVersion": "2.25.3"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Environment variables used by the CodeQL Action.
|
* Environment variables used by the CodeQL Action.
|
||||||
*
|
*
|
||||||
@@ -156,29 +154,3 @@ export enum EnvVar {
|
|||||||
/** Used by Code Scanning Risk Assessment to communicate the assessment ID to the CodeQL Action. */
|
/** Used by Code Scanning Risk Assessment to communicate the assessment ID to the CodeQL Action. */
|
||||||
RISK_ASSESSMENT_ID = "CODEQL_ACTION_RISK_ASSESSMENT_ID",
|
RISK_ASSESSMENT_ID = "CODEQL_ACTION_RISK_ASSESSMENT_ID",
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
export function exportVariable(name: string, val: any): void {
|
|
||||||
if (process.env["NODE_ENV"] === "test") {
|
|
||||||
// Setting the environment variable for the current process is OK since we reset
|
|
||||||
// those at the end of each test. This allows tests to pass that rely on that
|
|
||||||
// part of the `core.exportVariable` behaviour.
|
|
||||||
process.env[name] = val;
|
|
||||||
} else {
|
|
||||||
// Call `core.exportVariable` whenever we are not in a test environment.
|
|
||||||
core.exportVariable(name, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ async function generateFailedSarif(
|
|||||||
sarifFile?: string,
|
sarifFile?: string,
|
||||||
) {
|
) {
|
||||||
const databasePath = config.dbLocation;
|
const databasePath = config.dbLocation;
|
||||||
const codeql = await getCodeQL(config.codeQLCmd);
|
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
|
|
||||||
// Set the filename for the SARIF file if not already set.
|
// Set the filename for the SARIF file if not already set.
|
||||||
if (sarifFile === undefined) {
|
if (sarifFile === undefined) {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
DependencyCachingUsageReport,
|
DependencyCachingUsageReport,
|
||||||
getDependencyCacheUsage,
|
getDependencyCacheUsage,
|
||||||
} from "./dependency-caching";
|
} from "./dependency-caching";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { initFeatures } from "./feature-flags";
|
import { initFeatures } from "./feature-flags";
|
||||||
import * as gitUtils from "./git-utils";
|
import * as gitUtils from "./git-utils";
|
||||||
import * as initActionPostHelper from "./init-action-post-helper";
|
import * as initActionPostHelper from "./init-action-post-helper";
|
||||||
@@ -75,7 +75,7 @@ async function run(startedAt: Date) {
|
|||||||
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any.",
|
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any.",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const codeql = await getCodeQL(config.codeQLCmd);
|
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
|
|
||||||
uploadFailedSarifResult = await initActionPostHelper.uploadFailureInfo(
|
uploadFailedSarifResult = await initActionPostHelper.uploadFailureInfo(
|
||||||
debugArtifacts.tryUploadAllAvailableDebugArtifacts,
|
debugArtifacts.tryUploadAllAvailableDebugArtifacts,
|
||||||
@@ -157,7 +157,7 @@ function getFinalJobStatus(config: Config | undefined): JobStatus {
|
|||||||
let jobStatus: JobStatus;
|
let jobStatus: JobStatus;
|
||||||
|
|
||||||
if (process.env[EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] === "true") {
|
if (process.env[EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] === "true") {
|
||||||
exportVariable(EnvVar.JOB_STATUS, JobStatus.SuccessStatus);
|
core.exportVariable(EnvVar.JOB_STATUS, JobStatus.SuccessStatus);
|
||||||
jobStatus = JobStatus.SuccessStatus;
|
jobStatus = JobStatus.SuccessStatus;
|
||||||
} else if (config !== undefined) {
|
} else if (config !== undefined) {
|
||||||
// - We have computed a CodeQL config
|
// - We have computed a CodeQL config
|
||||||
@@ -182,7 +182,7 @@ function getFinalJobStatus(config: Config | undefined): JobStatus {
|
|||||||
|
|
||||||
// This shouldn't be necessary, but in the odd case that we run more than one
|
// 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.
|
// `init` post step, ensure the job status is consistent between them.
|
||||||
exportVariable(EnvVar.JOB_STATUS, jobStatus);
|
core.exportVariable(EnvVar.JOB_STATUS, jobStatus);
|
||||||
return jobStatus;
|
return jobStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-14
@@ -37,7 +37,7 @@ import {
|
|||||||
makeDiagnostic,
|
makeDiagnostic,
|
||||||
makeTelemetryDiagnostic,
|
makeTelemetryDiagnostic,
|
||||||
} from "./diagnostics";
|
} from "./diagnostics";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
||||||
import {
|
import {
|
||||||
loadPropertiesFromApi,
|
loadPropertiesFromApi,
|
||||||
@@ -255,9 +255,9 @@ async function run(startedAt: Date) {
|
|||||||
// Create a unique identifier for this run.
|
// Create a unique identifier for this run.
|
||||||
const jobRunUuid = uuidV4();
|
const jobRunUuid = uuidV4();
|
||||||
logger.info(`Job run UUID is ${jobRunUuid}.`);
|
logger.info(`Job run UUID is ${jobRunUuid}.`);
|
||||||
exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
|
core.exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
|
||||||
|
|
||||||
exportVariable(EnvVar.INIT_ACTION_HAS_RUN, "true");
|
core.exportVariable(EnvVar.INIT_ACTION_HAS_RUN, "true");
|
||||||
|
|
||||||
configFile = getOptionalInput("config-file");
|
configFile = getOptionalInput("config-file");
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ async function run(startedAt: Date) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (semver.lt(actualVer, publicPreview)) {
|
if (semver.lt(actualVer, publicPreview)) {
|
||||||
exportVariable(EnvVar.EXPERIMENTAL_FEATURES, "true");
|
core.exportVariable(EnvVar.EXPERIMENTAL_FEATURES, "true");
|
||||||
logger.info("Experimental Rust analysis enabled");
|
logger.info("Experimental Rust analysis enabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -508,7 +508,7 @@ async function run(startedAt: Date) {
|
|||||||
// Forward Go flags
|
// Forward Go flags
|
||||||
const goFlags = process.env["GOFLAGS"];
|
const goFlags = process.env["GOFLAGS"];
|
||||||
if (goFlags) {
|
if (goFlags) {
|
||||||
exportVariable("GOFLAGS", goFlags);
|
core.exportVariable("GOFLAGS", goFlags);
|
||||||
core.warning(
|
core.warning(
|
||||||
"Passing the GOFLAGS env parameter to the init action is deprecated. Please move this to the analyze action.",
|
"Passing the GOFLAGS env parameter to the init action is deprecated. Please move this to the analyze action.",
|
||||||
);
|
);
|
||||||
@@ -554,7 +554,7 @@ async function run(startedAt: Date) {
|
|||||||
|
|
||||||
// Store the original location of our wrapper script somewhere where we can
|
// 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.
|
// later retrieve it from and cross-check that it hasn't been changed.
|
||||||
exportVariable(EnvVar.GO_BINARY_LOCATION, goWrapperPath);
|
core.exportVariable(EnvVar.GO_BINARY_LOCATION, goWrapperPath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warning(
|
logger.warning(
|
||||||
`Analyzing Go on Linux, but failed to install wrapper script. Tracing custom builds may fail: ${e}`,
|
`Analyzing Go on Linux, but failed to install wrapper script. Tracing custom builds may fail: ${e}`,
|
||||||
@@ -563,7 +563,7 @@ async function run(startedAt: Date) {
|
|||||||
} else {
|
} else {
|
||||||
// Store the location of the original Go binary, so we can check that no setup tasks were performed after the
|
// Store the location of the original Go binary, so we can check that no setup tasks were performed after the
|
||||||
// `init` Action ran.
|
// `init` Action ran.
|
||||||
exportVariable(EnvVar.GO_BINARY_LOCATION, goBinaryPath);
|
core.exportVariable(EnvVar.GO_BINARY_LOCATION, goBinaryPath);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warning(
|
logger.warning(
|
||||||
@@ -598,12 +598,12 @@ async function run(startedAt: Date) {
|
|||||||
// threads it would ask extractors to use. See help text for the "--ram" and "--threads"
|
// 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/
|
// options at https://codeql.github.com/docs/codeql-cli/manual/database-trace-command/
|
||||||
// for details.
|
// for details.
|
||||||
exportVariable(
|
core.exportVariable(
|
||||||
"CODEQL_RAM",
|
"CODEQL_RAM",
|
||||||
process.env["CODEQL_RAM"] ||
|
process.env["CODEQL_RAM"] ||
|
||||||
getCodeQLMemoryLimit(getOptionalInput("ram"), logger).toString(),
|
getCodeQLMemoryLimit(getOptionalInput("ram"), logger).toString(),
|
||||||
);
|
);
|
||||||
exportVariable(
|
core.exportVariable(
|
||||||
"CODEQL_THREADS",
|
"CODEQL_THREADS",
|
||||||
process.env["CODEQL_THREADS"] ||
|
process.env["CODEQL_THREADS"] ||
|
||||||
getThreadsFlagValue(getOptionalInput("threads"), logger).toString(),
|
getThreadsFlagValue(getOptionalInput("threads"), logger).toString(),
|
||||||
@@ -611,7 +611,7 @@ async function run(startedAt: Date) {
|
|||||||
|
|
||||||
// Disable Kotlin extractor if feature flag set
|
// Disable Kotlin extractor if feature flag set
|
||||||
if (await features.getValue(Feature.DisableKotlinAnalysisEnabled)) {
|
if (await features.getValue(Feature.DisableKotlinAnalysisEnabled)) {
|
||||||
exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
|
core.exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
const kotlinLimitVar =
|
const kotlinLimitVar =
|
||||||
@@ -620,7 +620,7 @@ async function run(startedAt: Date) {
|
|||||||
(await codeQlVersionAtLeast(codeql, "2.20.3")) &&
|
(await codeQlVersionAtLeast(codeql, "2.20.3")) &&
|
||||||
!(await codeQlVersionAtLeast(codeql, "2.20.4"))
|
!(await codeQlVersionAtLeast(codeql, "2.20.4"))
|
||||||
) {
|
) {
|
||||||
exportVariable(kotlinLimitVar, "2.1.20");
|
core.exportVariable(kotlinLimitVar, "2.1.20");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore dependency cache(s), if they exist.
|
// Restore dependency cache(s), if they exist.
|
||||||
@@ -669,7 +669,10 @@ async function run(startedAt: Date) {
|
|||||||
config.buildMode === BuildMode.None &&
|
config.buildMode === BuildMode.None &&
|
||||||
config.languages.includes(BuiltInLanguage.java)
|
config.languages.includes(BuiltInLanguage.java)
|
||||||
) {
|
) {
|
||||||
exportVariable(EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS, "true");
|
core.exportVariable(
|
||||||
|
EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS,
|
||||||
|
"true",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { registriesAuthTokens, qlconfigFile } =
|
const { registriesAuthTokens, qlconfigFile } =
|
||||||
@@ -726,7 +729,7 @@ async function run(startedAt: Date) {
|
|||||||
const tracerConfig = await getCombinedTracerConfig(codeql, config);
|
const tracerConfig = await getCombinedTracerConfig(codeql, config);
|
||||||
if (tracerConfig !== undefined) {
|
if (tracerConfig !== undefined) {
|
||||||
for (const [key, value] of Object.entries(tracerConfig.env)) {
|
for (const [key, value] of Object.entries(tracerConfig.env)) {
|
||||||
exportVariable(key, value);
|
core.exportVariable(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,7 +740,7 @@ async function run(startedAt: Date) {
|
|||||||
getOptionalEnvVar(JavaEnvVars.JAVA_TOOL_OPTIONS) || "";
|
getOptionalEnvVar(JavaEnvVars.JAVA_TOOL_OPTIONS) || "";
|
||||||
|
|
||||||
// Add the network debugging options.
|
// Add the network debugging options.
|
||||||
exportVariable(
|
core.exportVariable(
|
||||||
JavaEnvVars.JAVA_TOOL_OPTIONS,
|
JavaEnvVars.JAVA_TOOL_OPTIONS,
|
||||||
`${existingJavaToolOptions} -Djavax.net.debug=all`,
|
`${existingJavaToolOptions} -Djavax.net.debug=all`,
|
||||||
);
|
);
|
||||||
|
|||||||
+8
-8
@@ -1,13 +1,13 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
|
import * as core from "@actions/core";
|
||||||
import * as github from "@actions/github";
|
import * as github from "@actions/github";
|
||||||
import test, { ExecutionContext } from "ava";
|
import test, { ExecutionContext } from "ava";
|
||||||
import * as sinon from "sinon";
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
import * as actionsUtil from "./actions-util";
|
import * as actionsUtil from "./actions-util";
|
||||||
import { createStubCodeQL } from "./codeql";
|
import { createStubCodeQL } from "./codeql";
|
||||||
import * as environment from "./environment";
|
|
||||||
import { Feature } from "./feature-flags";
|
import { Feature } from "./feature-flags";
|
||||||
import {
|
import {
|
||||||
checkPacksForOverlayCompatibility,
|
checkPacksForOverlayCompatibility,
|
||||||
@@ -545,7 +545,7 @@ test.serial(
|
|||||||
test.serial(
|
test.serial(
|
||||||
"file coverage deprecation warning for org-owned repo with default setup recommends repo property",
|
"file coverage deprecation warning for org-owned repo with default setup recommends repo property",
|
||||||
(t) => {
|
(t) => {
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
||||||
github.context.payload = {
|
github.context.payload = {
|
||||||
repository: {
|
repository: {
|
||||||
@@ -572,7 +572,7 @@ test.serial(
|
|||||||
test.serial(
|
test.serial(
|
||||||
"file coverage deprecation warning for org-owned repo with advanced setup recommends env var and repo property",
|
"file coverage deprecation warning for org-owned repo with advanced setup recommends env var and repo property",
|
||||||
(t) => {
|
(t) => {
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
||||||
github.context.payload = {
|
github.context.payload = {
|
||||||
repository: {
|
repository: {
|
||||||
@@ -600,7 +600,7 @@ test.serial(
|
|||||||
test.serial(
|
test.serial(
|
||||||
"file coverage deprecation warning for user-owned repo with default setup recommends advanced setup",
|
"file coverage deprecation warning for user-owned repo with default setup recommends advanced setup",
|
||||||
(t) => {
|
(t) => {
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
||||||
github.context.payload = {
|
github.context.payload = {
|
||||||
repository: {
|
repository: {
|
||||||
@@ -626,7 +626,7 @@ test.serial(
|
|||||||
test.serial(
|
test.serial(
|
||||||
"file coverage deprecation warning for user-owned repo with advanced setup recommends env var",
|
"file coverage deprecation warning for user-owned repo with advanced setup recommends env var",
|
||||||
(t) => {
|
(t) => {
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
||||||
github.context.payload = {
|
github.context.payload = {
|
||||||
repository: {
|
repository: {
|
||||||
@@ -651,7 +651,7 @@ test.serial(
|
|||||||
test.serial(
|
test.serial(
|
||||||
"file coverage deprecation warning for unknown owner type with default setup recommends advanced setup",
|
"file coverage deprecation warning for unknown owner type with default setup recommends advanced setup",
|
||||||
(t) => {
|
(t) => {
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
sinon.stub(actionsUtil, "isDefaultSetup").returns(true);
|
||||||
github.context.payload = { repository: undefined };
|
github.context.payload = { repository: undefined };
|
||||||
const messages: LoggedMessage[] = [];
|
const messages: LoggedMessage[] = [];
|
||||||
@@ -672,7 +672,7 @@ test.serial(
|
|||||||
test.serial(
|
test.serial(
|
||||||
"file coverage deprecation warning for unknown owner type with advanced setup recommends env var",
|
"file coverage deprecation warning for unknown owner type with advanced setup recommends env var",
|
||||||
(t) => {
|
(t) => {
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
sinon.stub(actionsUtil, "isDefaultSetup").returns(false);
|
||||||
github.context.payload = { repository: undefined };
|
github.context.payload = { repository: undefined };
|
||||||
const messages: LoggedMessage[] = [];
|
const messages: LoggedMessage[] = [];
|
||||||
@@ -694,7 +694,7 @@ test.serial(
|
|||||||
(t) => {
|
(t) => {
|
||||||
process.env["CODEQL_ACTION_DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION"] =
|
process.env["CODEQL_ACTION_DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION"] =
|
||||||
"true";
|
"true";
|
||||||
const exportVariableStub = sinon.stub(environment, "exportVariable");
|
const exportVariableStub = sinon.stub(core, "exportVariable");
|
||||||
const messages: LoggedMessage[] = [];
|
const messages: LoggedMessage[] = [];
|
||||||
logFileCoverageOnPrsDeprecationWarning(getRecordingLogger(messages));
|
logFileCoverageOnPrsDeprecationWarning(getRecordingLogger(messages));
|
||||||
t.is(messages.length, 0);
|
t.is(messages.length, 0);
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
|
||||||
|
import * as core from "@actions/core";
|
||||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||||
import * as github from "@actions/github";
|
import * as github from "@actions/github";
|
||||||
import * as io from "@actions/io";
|
import * as io from "@actions/io";
|
||||||
@@ -15,7 +16,7 @@ import {
|
|||||||
import { GitHubApiDetails } from "./api-client";
|
import { GitHubApiDetails } from "./api-client";
|
||||||
import { CodeQL, setupCodeQL } from "./codeql";
|
import { CodeQL, setupCodeQL } from "./codeql";
|
||||||
import * as configUtils from "./config-utils";
|
import * as configUtils from "./config-utils";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import {
|
import {
|
||||||
CodeQLDefaultVersionInfo,
|
CodeQLDefaultVersionInfo,
|
||||||
Feature,
|
Feature,
|
||||||
@@ -417,5 +418,5 @@ export function logFileCoverageOnPrsDeprecationWarning(logger: Logger): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.warning(message);
|
logger.warning(message);
|
||||||
exportVariable(EnvVar.DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION, "true");
|
core.exportVariable(EnvVar.DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION, "true");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import * as sinon from "sinon";
|
|||||||
import * as actionsUtil from "../actions-util";
|
import * as actionsUtil from "../actions-util";
|
||||||
import * as apiClient from "../api-client";
|
import * as apiClient from "../api-client";
|
||||||
import type { ResolveDatabaseOutput } from "../codeql";
|
import type { ResolveDatabaseOutput } from "../codeql";
|
||||||
import * as environment from "../environment";
|
|
||||||
import * as gitUtils from "../git-utils";
|
import * as gitUtils from "../git-utils";
|
||||||
import { BuiltInLanguage } from "../languages";
|
import { BuiltInLanguage } from "../languages";
|
||||||
import { getRunnerLogger } from "../logging";
|
import { getRunnerLogger } from "../logging";
|
||||||
@@ -83,7 +82,7 @@ const testDownloadOverlayBaseDatabaseFromCache = makeMacro({
|
|||||||
|
|
||||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||||
|
|
||||||
sinon.stub(environment, "isInTestMode").returns(testCase.isInTestMode);
|
sinon.stub(utils, "isInTestMode").returns(testCase.isInTestMode);
|
||||||
|
|
||||||
if (testCase.restoreCacheResult instanceof Error) {
|
if (testCase.restoreCacheResult instanceof Error) {
|
||||||
sinon
|
sinon
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { AnalysisKind, getAnalysisKinds } from "./analyses";
|
|||||||
import { getGitHubVersion } from "./api-client";
|
import { getGitHubVersion } from "./api-client";
|
||||||
import { CodeQL } from "./codeql";
|
import { CodeQL } from "./codeql";
|
||||||
import { getRawLanguagesNoAutodetect } from "./config-utils";
|
import { getRawLanguagesNoAutodetect } from "./config-utils";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { initFeatures } from "./feature-flags";
|
import { initFeatures } from "./feature-flags";
|
||||||
import { initCodeQL } from "./init";
|
import { initCodeQL } from "./init";
|
||||||
import { getActionsLogger, Logger } from "./logging";
|
import { getActionsLogger, Logger } from "./logging";
|
||||||
@@ -125,7 +125,7 @@ async function run(startedAt: Date): Promise<void> {
|
|||||||
|
|
||||||
const jobRunUuid = uuidV4();
|
const jobRunUuid = uuidV4();
|
||||||
logger.info(`Job run UUID is ${jobRunUuid}.`);
|
logger.info(`Job run UUID is ${jobRunUuid}.`);
|
||||||
exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
|
core.exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
|
||||||
|
|
||||||
const statusReportBase = await createStatusReportBase(
|
const statusReportBase = await createStatusReportBase(
|
||||||
ActionName.SetupCodeQL,
|
ActionName.SetupCodeQL,
|
||||||
@@ -165,7 +165,7 @@ async function run(startedAt: Date): Promise<void> {
|
|||||||
core.setOutput("codeql-path", codeql.getPath());
|
core.setOutput("codeql-path", codeql.getPath());
|
||||||
core.setOutput("codeql-version", (await codeql.getVersion()).version);
|
core.setOutput("codeql-version", (await codeql.getVersion()).version);
|
||||||
|
|
||||||
exportVariable(EnvVar.SETUP_CODEQL_ACTION_HAS_RUN, "true");
|
core.exportVariable(EnvVar.SETUP_CODEQL_ACTION_HAS_RUN, "true");
|
||||||
} catch (unwrappedError) {
|
} catch (unwrappedError) {
|
||||||
const error = wrapError(unwrappedError);
|
const error = wrapError(unwrappedError);
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { getAnalysisKey, getApiClient } from "./api-client";
|
|||||||
import { parseRegistriesWithoutCredentials, type Config } from "./config-utils";
|
import { parseRegistriesWithoutCredentials, type Config } from "./config-utils";
|
||||||
import { DependencyCacheRestoreStatusReport } from "./dependency-caching";
|
import { DependencyCacheRestoreStatusReport } from "./dependency-caching";
|
||||||
import { DocUrl } from "./doc-url";
|
import { DocUrl } from "./doc-url";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { getRef } from "./git-utils";
|
import { getRef } from "./git-utils";
|
||||||
import { Logger } from "./logging";
|
import { Logger } from "./logging";
|
||||||
import { OverlayBaseDatabaseDownloadStats } from "./overlay/caching";
|
import { OverlayBaseDatabaseDownloadStats } from "./overlay/caching";
|
||||||
@@ -216,12 +216,12 @@ export function getJobStatusDisplayName(status: JobStatus): string {
|
|||||||
*/
|
*/
|
||||||
function setJobStatusIfUnsuccessful(actionStatus: ActionStatus) {
|
function setJobStatusIfUnsuccessful(actionStatus: ActionStatus) {
|
||||||
if (actionStatus === "user-error") {
|
if (actionStatus === "user-error") {
|
||||||
exportVariable(
|
core.exportVariable(
|
||||||
EnvVar.JOB_STATUS,
|
EnvVar.JOB_STATUS,
|
||||||
process.env[EnvVar.JOB_STATUS] ?? JobStatus.ConfigErrorStatus,
|
process.env[EnvVar.JOB_STATUS] ?? JobStatus.ConfigErrorStatus,
|
||||||
);
|
);
|
||||||
} else if (actionStatus === "failure" || actionStatus === "aborted") {
|
} else if (actionStatus === "failure" || actionStatus === "aborted") {
|
||||||
exportVariable(
|
core.exportVariable(
|
||||||
EnvVar.JOB_STATUS,
|
EnvVar.JOB_STATUS,
|
||||||
process.env[EnvVar.JOB_STATUS] ?? JobStatus.FailureStatus,
|
process.env[EnvVar.JOB_STATUS] ?? JobStatus.FailureStatus,
|
||||||
);
|
);
|
||||||
@@ -280,7 +280,7 @@ export async function createStatusReportBase(
|
|||||||
let workflowStartedAt = process.env[EnvVar.WORKFLOW_STARTED_AT];
|
let workflowStartedAt = process.env[EnvVar.WORKFLOW_STARTED_AT];
|
||||||
if (workflowStartedAt === undefined) {
|
if (workflowStartedAt === undefined) {
|
||||||
workflowStartedAt = actionStartedAt.toISOString();
|
workflowStartedAt = actionStartedAt.toISOString();
|
||||||
exportVariable(EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt);
|
core.exportVariable(EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt);
|
||||||
}
|
}
|
||||||
const runnerOs = getRequiredEnvParam("RUNNER_OS");
|
const runnerOs = getRequiredEnvParam("RUNNER_OS");
|
||||||
const codeQlCliVersion = getCachedCodeQlVersion();
|
const codeQlCliVersion = getCachedCodeQlVersion();
|
||||||
@@ -289,7 +289,7 @@ export async function createStatusReportBase(
|
|||||||
// re-export the testing environment variable so that it is available to subsequent steps,
|
// re-export the testing environment variable so that it is available to subsequent steps,
|
||||||
// even if it was only set for this step
|
// even if it was only set for this step
|
||||||
if (testingEnvironment) {
|
if (testingEnvironment) {
|
||||||
exportVariable(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
|
core.exportVariable(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
|
||||||
}
|
}
|
||||||
const isSteadyStateDefaultSetupRun =
|
const isSteadyStateDefaultSetupRun =
|
||||||
process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true";
|
process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true";
|
||||||
|
|||||||
@@ -560,7 +560,7 @@ export function mockBundleDownloadApi({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createTestConfig(overrides: Partial<Config>): Config {
|
export function createTestConfig(overrides: Partial<Config>): Config {
|
||||||
return Object.assign(
|
const config = Object.assign(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
version: getActionVersion(),
|
version: getActionVersion(),
|
||||||
@@ -590,6 +590,8 @@ export function createTestConfig(overrides: Partial<Config>): Config {
|
|||||||
} satisfies Config,
|
} satisfies Config,
|
||||||
overrides,
|
overrides,
|
||||||
);
|
);
|
||||||
|
config.codeQLMetadata ??= { codeQLCmd: config.codeQLCmd };
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeTestToken(length: number = 36) {
|
export function makeTestToken(length: number = 36) {
|
||||||
|
|||||||
+4
-4
@@ -14,7 +14,7 @@ import { getGitHubVersion, wrapApiConfigurationError } from "./api-client";
|
|||||||
import { CodeQL, getCodeQL } from "./codeql";
|
import { CodeQL, getCodeQL } from "./codeql";
|
||||||
import { getConfig } from "./config-utils";
|
import { getConfig } from "./config-utils";
|
||||||
import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils";
|
import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils";
|
||||||
import { EnvVar, exportVariable } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { FeatureEnablement } from "./feature-flags";
|
import { FeatureEnablement } from "./feature-flags";
|
||||||
import * as fingerprints from "./fingerprints";
|
import * as fingerprints from "./fingerprints";
|
||||||
import * as gitUtils from "./git-utils";
|
import * as gitUtils from "./git-utils";
|
||||||
@@ -126,7 +126,7 @@ async function combineSarifFilesUsingCLI(
|
|||||||
logger.warning(
|
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}`,
|
`Uploading multiple SARIF runs with the same category is deprecated ${deprecationWarningMessage}. Please update your workflow to upload a single run per category. ${deprecationMoreInformationMessage}`,
|
||||||
);
|
);
|
||||||
exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
|
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not, use the naive method of combining the files.
|
// If not, use the naive method of combining the files.
|
||||||
@@ -140,7 +140,7 @@ async function combineSarifFilesUsingCLI(
|
|||||||
|
|
||||||
const config = await getConfig(tempDir, logger);
|
const config = await getConfig(tempDir, logger);
|
||||||
if (config !== undefined) {
|
if (config !== undefined) {
|
||||||
codeQL = await getCodeQL(config.codeQLCmd);
|
codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
|
||||||
tempDir = config.tempDir;
|
tempDir = config.tempDir;
|
||||||
} else {
|
} else {
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -1023,7 +1023,7 @@ export function validateUniqueCategory(
|
|||||||
`Category: (${id ? id : "none"}) Tool: (${tool ? tool : "none"})`,
|
`Category: (${id ? id : "none"}) Tool: (${tool ? tool : "none"})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
exportVariable(sentinelEnvVar, sentinelEnvVar);
|
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-11
@@ -13,13 +13,11 @@ import * as apiCompatibility from "./api-compatibility.json";
|
|||||||
import type { CodeQL, VersionInfo } from "./codeql";
|
import type { CodeQL, VersionInfo } from "./codeql";
|
||||||
import type { Pack } from "./config/db-config";
|
import type { Pack } from "./config/db-config";
|
||||||
import type { Config } from "./config-utils";
|
import type { Config } from "./config-utils";
|
||||||
import { EnvVar, exportVariable, isInTestMode } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import * as json from "./json";
|
import * as json from "./json";
|
||||||
import { Language } from "./languages";
|
import { Language } from "./languages";
|
||||||
import { Logger } from "./logging";
|
import { Logger } from "./logging";
|
||||||
|
|
||||||
export { isInTestMode } from "./environment";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the file containing the base database OIDs, as stored in the
|
* The name of the file containing the base database OIDs, as stored in the
|
||||||
* root of the database location.
|
* root of the database location.
|
||||||
@@ -517,7 +515,7 @@ export function checkGitHubVersionInRange(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
hasBeenWarnedAboutVersion = true;
|
hasBeenWarnedAboutVersion = true;
|
||||||
exportVariable(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true);
|
core.exportVariable(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DisallowedAPIVersionReason {
|
export enum DisallowedAPIVersionReason {
|
||||||
@@ -561,11 +559,11 @@ export function assertNever(value: never): never {
|
|||||||
* knowing what version of CodeQL we're running.
|
* knowing what version of CodeQL we're running.
|
||||||
*/
|
*/
|
||||||
export function initializeEnvironment(version: string) {
|
export function initializeEnvironment(version: string) {
|
||||||
exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||||
exportVariable(EnvVar.FEATURE_SANDWICH, "false");
|
core.exportVariable(EnvVar.FEATURE_SANDWICH, "false");
|
||||||
exportVariable(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
core.exportVariable(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||||
exportVariable(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
core.exportVariable(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||||
exportVariable(EnvVar.VERSION, version);
|
core.exportVariable(EnvVar.VERSION, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -710,6 +708,15 @@ export function isGoodVersion(versionSpec: string) {
|
|||||||
return !BROKEN_VERSIONS.includes(versionSpec);
|
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.
|
* Returns whether we specifically want to skip uploading SARIF files.
|
||||||
*/
|
*/
|
||||||
@@ -928,7 +935,7 @@ export async function checkDiskUsage(
|
|||||||
} else {
|
} else {
|
||||||
logger.debug(message);
|
logger.debug(message);
|
||||||
}
|
}
|
||||||
exportVariable(EnvVar.HAS_WARNED_ABOUT_DISK_SPACE, "true");
|
core.exportVariable(EnvVar.HAS_WARNED_ABOUT_DISK_SPACE, "true");
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
numAvailableBytes: diskUsage.bavail * blockSizeInBytes,
|
numAvailableBytes: diskUsage.bavail * blockSizeInBytes,
|
||||||
@@ -977,7 +984,7 @@ export function checkActionVersion(
|
|||||||
"https://github.blog/changelog/2025-10-28-upcoming-deprecation-of-codeql-action-v3/",
|
"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
|
// set LOG_VERSION_DEPRECATION env var to prevent the warning from being logged multiple times
|
||||||
exportVariable(EnvVar.LOG_VERSION_DEPRECATION, "true");
|
core.exportVariable(EnvVar.LOG_VERSION_DEPRECATION, "true");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user