Compare commits

..

57 Commits

Author SHA1 Message Date
Óscar San José 57b3666b1d Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-06-01 20:23:20 +02:00
Óscar San José 1251f87758 Improve testing 2026-06-01 20:19:50 +02:00
Óscar San José 6963dfbbc5 Add logging and telemetry for mode 2026-06-01 18:44:55 +02:00
Óscar San José d426d33115 Implement an enforce/dynamic approach 2026-06-01 18:33:23 +02:00
Óscar San José f22e7a29ce Merge branch 'main' into copilot/add-tools-input-source-repository 2026-06-01 17:31:14 +02:00
Óscar San José d8e5e3dbab Rebuild 2026-06-01 17:26:52 +02:00
copilot-swe-agent[bot] 9b49e27edb Allow repository tools property fallback in resolveToolsInput 2026-05-29 11:39:28 +00:00
Óscar San José aeb3e20ace Rebuild 2026-05-29 13:26:31 +02:00
Óscar San José d622e410d6 Lint 2026-05-29 13:23:34 +02:00
Óscar San José fb605661cd Missing files 2026-05-29 13:18:17 +02:00
Óscar San José 063bb8b614 Move resolve-tools-input.ts and tests to src/config 2026-05-29 13:16:55 +02:00
Óscar San José 3d8236de69 More fixes from CR 2026-05-29 13:14:23 +02:00
Henry Mercer d1eb1207b4 Merge pull request #3933 from github/update-supported-enterprise-server-versions
Update supported GitHub Enterprise Server versions
2026-05-29 11:10:43 +00:00
Óscar San José b1eeb13c4c Lint 2026-05-29 13:08:58 +02:00
Óscar San José 964d328667 More fixes from CR 2026-05-29 13:08:26 +02:00
Óscar San José f9b6569832 More fixes from CR 2026-05-29 13:07:20 +02:00
Óscar San José 3782e65e9f Easy fixes from CR 2026-05-29 12:52:51 +02:00
Óscar San José dafa67e1d3 Rebuild 2026-05-29 10:07:34 +02:00
Óscar San José 0d5f0f55c2 Lint fixes 2026-05-29 10:03:21 +02:00
Michael B. Gale 115001ba8d Merge pull request #3934 from github/dependabot/npm_and_yarn/npm-minor-86fb5ccea6
Bump the npm-minor group across 1 directory with 2 updates
2026-05-28 14:53:43 +00:00
Michael B. Gale cef2e7a910 Merge pull request #3925 from github/dependabot/github_actions/dot-github/workflows/actions-minor-da8be134b1
Bump ruby/setup-ruby from 1.306.0 to 1.307.0 in /.github/workflows in the actions-minor group across 1 directory
2026-05-28 13:59:27 +00:00
Michael B. Gale 5e6adf70ed Merge pull request #3936 from github/dependabot/npm_and_yarn/tmp-0.2.7
Bump tmp from 0.2.4 to 0.2.7
2026-05-28 13:54:02 +00:00
Michael B. Gale ad170e6c4e Merge branch 'main' into dependabot/github_actions/dot-github/workflows/actions-minor-da8be134b1 2026-05-28 14:48:30 +01:00
github-actions[bot] 6a37b3a57a Rebuild 2026-05-28 02:48:34 +00:00
dependabot[bot] bef1eb7126 Bump tmp from 0.2.4 to 0.2.7
Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.4 to 0.2.7.
- [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md)
- [Commits](https://github.com/raszi/node-tmp/compare/v0.2.4...v0.2.7)

---
updated-dependencies:
- dependency-name: tmp
  dependency-version: 0.2.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-28 02:46:38 +00:00
dependabot[bot] b42b7546a5 Bump the npm-minor group across 1 directory with 2 updates
Bumps the npm-minor group with 2 updates in the / directory: [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) and [tsx](https://github.com/privatenumber/tsx).


Updates `typescript-eslint` from 8.59.3 to 8.59.4
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.4/packages/typescript-eslint)

Updates `tsx` from 4.21.0 to 4.22.3
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.21.0...v4.22.3)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.59.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: tsx
  dependency-version: 4.22.3
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-27 20:06:49 +00:00
github-actions[bot] 8b0c522441 Update supported GitHub Enterprise Server versions 2026-05-27 00:44:49 +00:00
Óscar San José 7c7926f8df Fixed tests due to stale language.ts obscuring language/index.ts import when done at module level 2026-05-25 16:33:01 +02:00
Óscar San José 838486a3c3 Merge branch 'main' of https://github.com/github/codeql-action into copilot/add-tools-input-source-repository 2026-05-25 13:27:20 +02:00
copilot-swe-agent[bot] 09a0f62a7a Refactor resolveToolsInput: accept repository properties as parameter, simplify implementation and tests 2026-05-25 11:10:26 +00:00
Michael B. Gale 0e150e4076 Merge pull request #3921 from github/dependabot/npm_and_yarn/npm-minor-28e225f5ad
Bump the npm-minor group across 1 directory with 6 updates
2026-05-22 14:35:33 +00:00
Michael B. Gale 8a1e375368 Merge branch 'main' into dependabot/npm_and_yarn/npm-minor-28e225f5ad 2026-05-22 15:08:30 +01:00
Óscar San José 0fb8a6672b Merge pull request #3928 from github/mergeback/v4.36.0-to-main-7211b7c8
Mergeback v4.36.0 refs/heads/releases/v4 into main
2026-05-22 11:28:10 +00:00
github-actions[bot] 80795fb0d4 Rebuild 2026-05-22 11:08:00 +00:00
github-actions[bot] 0cd24d8654 Update changelog and version after v4.36.0 2026-05-22 11:07:48 +00:00
Óscar San José 7211b7c807 Merge pull request #3927 from github/update-v4.36.0-ebc2d9e2b
Merge main into releases/v4
2026-05-22 13:06:23 +02:00
github-actions[bot] 7740f2fb21 Update changelog for v4.36.0 2026-05-22 10:49:45 +00:00
Óscar San José ebc2d9e2bc Merge pull request #3926 from github/update-bundle/codeql-bundle-v2.25.5
Update default bundle to 2.25.5
2026-05-22 10:32:55 +00:00
github-actions[bot] d1f74b777c Add changelog note 2026-05-22 10:18:49 +00:00
github-actions[bot] 2dc40cec39 Update default bundle to codeql-bundle-v2.25.5 2026-05-22 10:18:43 +00:00
Henry Mercer 84498526a0 Merge pull request #3910 from github/henrymercer/repo-size-diff-check
Action size: Add a PR check that comments on significant repo size changes
2026-05-21 10:29:33 +00:00
Henry Mercer 72ac23c6d1 Update excluded required check list 2026-05-21 10:16:47 +01:00
github-actions[bot] 14c150999e Rebuild 2026-05-20 22:08:52 +00:00
github-actions[bot] 89c58e65c1 Rebuild 2026-05-20 22:07:31 +00:00
dependabot[bot] a0a8d16e7b Bump ruby/setup-ruby
Bumps the actions-minor group with 1 update in the /.github/workflows directory: [ruby/setup-ruby](https://github.com/ruby/setup-ruby).


Updates `ruby/setup-ruby` from 1.306.0 to 1.307.0
- [Release notes](https://github.com/ruby/setup-ruby/releases)
- [Changelog](https://github.com/ruby/setup-ruby/blob/master/release.rb)
- [Commits](https://github.com/ruby/setup-ruby/compare/c4e5b1316158f92e3d49443a9d58b31d25ac0f8f...6aaa311d81eba98ae12eaffbcb63296ace0efcde)

---
updated-dependencies:
- dependency-name: ruby/setup-ruby
  dependency-version: 1.307.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: actions-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 22:06:56 +00:00
dependabot[bot] bd77449ac2 Bump the npm-minor group across 1 directory with 6 updates
Bumps the npm-minor group with 6 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [semver](https://github.com/npm/node-semver) | `7.7.4` | `7.8.0` |
| [@eslint/compat](https://github.com/eslint/rewrite/tree/HEAD/packages/compat) | `2.0.5` | `2.1.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `20.19.39` | `20.19.41` |
| [nock](https://github.com/nock/nock) | `14.0.12` | `14.0.15` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.59.2` | `8.59.3` |
| [yaml](https://github.com/eemeli/yaml) | `2.8.4` | `2.9.0` |



Updates `semver` from 7.7.4 to 7.8.0
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v7.7.4...v7.8.0)

Updates `@eslint/compat` from 2.0.5 to 2.1.0
- [Release notes](https://github.com/eslint/rewrite/releases)
- [Changelog](https://github.com/eslint/rewrite/blob/main/packages/compat/CHANGELOG.md)
- [Commits](https://github.com/eslint/rewrite/commits/compat-v2.1.0/packages/compat)

Updates `@types/node` from 20.19.39 to 20.19.41
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `nock` from 14.0.12 to 14.0.15
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v14.0.12...v14.0.15)

Updates `typescript-eslint` from 8.59.2 to 8.59.3
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.59.3/packages/typescript-eslint)

Updates `yaml` from 2.8.4 to 2.9.0
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.8.4...v2.9.0)

---
updated-dependencies:
- dependency-name: semver
  dependency-version: 7.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor
- dependency-name: "@eslint/compat"
  dependency-version: 2.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-minor
- dependency-name: "@types/node"
  dependency-version: 20.19.41
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: nock
  dependency-version: 14.0.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: typescript-eslint
  dependency-version: 8.59.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-minor
- dependency-name: yaml
  dependency-version: 2.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: npm-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-20 22:05:27 +00:00
Henry Mercer f3f52bf568 Revert getErrorMessage import
To avoid requiring additional dependencies
2026-05-20 15:55:41 +01:00
Henry Mercer a14f75e3ac Address review comments 2026-05-20 15:39:14 +01:00
Henry Mercer 2c8faa5e9f Pass comment body file directly 2026-05-18 20:28:53 +01:00
Henry Mercer 15a712bbc2 Address review comments 2026-05-18 20:08:43 +01:00
Henry Mercer 9b6438e936 Tweak workflow 2026-05-18 18:25:26 +01:00
Henry Mercer b5b50d62f1 Merge branch 'main' into henrymercer/repo-size-diff-check 2026-05-18 18:20:16 +01:00
Henry Mercer 5a80681bb6 Address review comments 2026-05-18 17:53:50 +01:00
Henry Mercer bcffb2b658 Unify checks into a single job 2026-05-18 17:33:45 +01:00
Henry Mercer 6f8805e224 Default setup env vars: Restrict results to src 2026-05-18 17:15:30 +01:00
Henry Mercer 4fc0f3e51b Add a PR check that comments on significant repo size changes 2026-05-18 16:36:58 +01:00
Óscar San José 652e91defb Add repo property to override codeql-cli version 2026-04-16 17:09:34 +02:00
53 changed files with 1635 additions and 1072 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
use-all-platform-bundle: 'false'
setup-kotlin: 'true'
- name: Set up Ruby
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1.307.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
+112 -32
View File
@@ -33,6 +33,10 @@ jobs:
runs-on: ${{ matrix.os }}
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:
- name: Prepare git (Windows)
if: runner.os == 'Windows'
@@ -71,22 +75,21 @@ jobs:
sarif_file: eslint.sarif
category: eslint
# Verifying the PR checks are up-to-date requires Node 24. The PR checks are not dependent
# on the main codebase and therefore do not need to be run as part of the same matrix that
# we use for the `unit-tests` job.
verify-pr-checks:
name: Verify PR checks
# These checks do not need to be run as part of the same matrix that we use for the `unit-tests`
# job.
other-checks:
name: Other checks
if: github.triggering_actor != 'dependabot[bot]'
permissions:
contents: read
runs-on: ubuntu-slim
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Prepare git (Windows)
if: runner.os == 'Windows'
run: git config --global core.autocrlf false
concurrency:
cancel-in-progress: ${{ github.event_name == 'pull_request' || false }}
group: pr-checks-pr-checks-${{ github.ref }}-${{ github.event_name }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
@@ -97,34 +100,22 @@ jobs:
cache: 'npm'
- name: Install dependencies
id: install-deps
run: npm ci
- name: Verify PR checks up to date
if: always()
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
run: .github/workflows/script/verify-pr-checks.sh
- name: Run pr-checks tests
if: always()
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
working-directory: pr-checks
run: npx tsx --test
check-node-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
- name: Verify all Actions use the same Node version
id: head-version
run: |
NODE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
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 | .[]')
echo "NODE_VERSION: ${NODE_VERSION}"
if [[ $(echo "$NODE_VERSION" | wc -l) -gt 1 ]]; then
echo "::error::More than one node version used in 'action.yml' files."
@@ -132,22 +123,111 @@ jobs:
fi
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
- id: checkout-base
name: 'Backport: Check out base ref'
- name: Fetch base commit
id: fetch-base
# 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-') }}
uses: actions/checkout@v6
with:
ref: ${{ env.BASE_REF }}
ref: ${{ github.base_ref }}
- name: 'Backport: Verify Node versions unchanged'
if: steps.checkout-base.outcome == 'success'
env:
HEAD_VERSION: ${{ steps.head-version.outputs.node_version }}
run: |
BASE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
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 | .[]')
echo "HEAD_VERSION: ${HEAD_VERSION}"
echo "BASE_VERSION: ${BASE_VERSION}"
if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then
echo "::error::Cannot change the Node version of an Action in a backport PR."
exit 1
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
+5
View File
@@ -4,8 +4,13 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
## [UNRELEASED]
- Organizations can create a custom repository property named `github-codeql-tools` to set a default CodeQL CLI tools value. You can optionally set `github-codeql-tools-mode` to control scope: use `enforce` (default) to apply to all workflows, or `dynamic` to apply only to dynamic workflows. If a workflow provides an explicit `tools:` input, that input takes precedence. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization), [Repository properties for Code Scanning](https://docs.github.com/en/code-security/concepts/code-scanning/repository-properties) and [Customizing your advanced setup for code scanning](https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning).
## 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)
- 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 -4
View File
@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.25.4",
"cliVersion": "2.25.4",
"priorBundleVersion": "codeql-bundle-v2.25.3",
"priorCliVersion": "2.25.3"
"bundleVersion": "codeql-bundle-v2.25.5",
"cliVersion": "2.25.5",
"priorBundleVersion": "codeql-bundle-v2.25.4",
"priorCliVersion": "2.25.4"
}
+217 -100
View File
@@ -26704,6 +26704,47 @@ var require_coerce = __commonJS({
}
});
// node_modules/semver/functions/truncate.js
var require_truncate = __commonJS({
"node_modules/semver/functions/truncate.js"(exports2, module2) {
"use strict";
var parse2 = require_parse2();
var constants = require_constants6();
var SemVer = require_semver();
var truncate = (version, truncation, options) => {
if (!constants.RELEASE_TYPES.includes(truncation)) {
return null;
}
const clonedVersion = cloneInputVersion(version, options);
return clonedVersion && doTruncation(clonedVersion, truncation);
};
var cloneInputVersion = (version, options) => {
const versionStringToParse = version instanceof SemVer ? version.version : version;
return parse2(versionStringToParse, options);
};
var doTruncation = (version, truncation) => {
if (isPrerelease(truncation)) {
return version.version;
}
version.prerelease = [];
switch (truncation) {
case "major":
version.minor = 0;
version.patch = 0;
break;
case "minor":
version.patch = 0;
break;
}
return version.format();
};
var isPrerelease = (type2) => {
return type2.startsWith("pre");
};
module2.exports = truncate;
}
});
// node_modules/semver/internal/lrucache.js
var require_lrucache = __commonJS({
"node_modules/semver/internal/lrucache.js"(exports2, module2) {
@@ -27738,6 +27779,7 @@ var require_semver2 = __commonJS({
var lte = require_lte();
var cmp = require_cmp();
var coerce3 = require_coerce();
var truncate = require_truncate();
var Comparator = require_comparator();
var Range2 = require_range();
var satisfies2 = require_satisfies();
@@ -27776,6 +27818,7 @@ var require_semver2 = __commonJS({
lte,
cmp,
coerce: coerce3,
truncate,
Comparator,
Range: Range2,
satisfies: satisfies2,
@@ -124988,7 +125031,7 @@ var require_tmp = __commonJS({
cb(null, path28.join(parentDir, path28.basename(pathToResolve)));
});
} else {
fs30.realpath(path28, cb);
fs30.realpath(pathToResolve, cb);
}
});
}
@@ -125020,16 +125063,31 @@ var require_tmp = __commonJS({
].join("");
return path28.join(tmpDir, opts.dir, name);
}
function _assertPath(option, value) {
if (typeof value !== "string") {
throw new Error(`${option} option must be a string, got "${typeof value}".`);
}
if (value.includes("..")) {
throw new Error("Relative value not allowed");
}
return value;
}
function _assertOptionsBase(options) {
if (!_isUndefined(options.name)) {
const name = options.name;
if (path28.isAbsolute(name)) throw new Error(`name option must not contain an absolute path, found "${name}".`);
const basename2 = path28.basename(name);
if (basename2 === ".." || basename2 === "." || basename2 !== name)
if (basename2 === ".." || basename2 === "." || basename2 !== name) {
throw new Error(`name option must not contain a path, found "${name}".`);
}
}
if (!_isUndefined(options.template) && !options.template.match(TEMPLATE_PATTERN)) {
throw new Error(`Invalid template, found "${options.template}".`);
if (!_isUndefined(options.template)) {
if (typeof options.template !== "string") {
throw new Error(`template option must be a string, got "${typeof options.template}".`);
}
if (!options.template.match(TEMPLATE_PATTERN)) {
throw new Error(`Invalid template, found "${options.template}".`);
}
}
if (!_isUndefined(options.tries) && isNaN(options.tries) || options.tries < 0) {
throw new Error(`Invalid tries, found "${options.tries}".`);
@@ -125039,15 +125097,16 @@ var require_tmp = __commonJS({
options.detachDescriptor = !!options.detachDescriptor;
options.discardDescriptor = !!options.discardDescriptor;
options.unsafeCleanup = !!options.unsafeCleanup;
options.prefix = _isUndefined(options.prefix) ? "" : options.prefix;
options.postfix = _isUndefined(options.postfix) ? "" : options.postfix;
options.prefix = _isUndefined(options.prefix) ? "" : _assertPath("prefix", options.prefix);
options.postfix = _isUndefined(options.postfix) ? "" : _assertPath("postfix", options.postfix);
options.template = _isUndefined(options.template) ? void 0 : _assertPath("template", options.template);
}
function _getRelativePath(option, name, tmpDir, cb) {
if (_isUndefined(name)) return cb(null);
_resolvePath(name, tmpDir, function(err, resolvedPath) {
if (err) return cb(err);
const relativePath = path28.relative(tmpDir, resolvedPath);
if (!resolvedPath.startsWith(tmpDir)) {
if (relativePath.startsWith("..") || path28.isAbsolute(relativePath)) {
return cb(new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`));
}
cb(null, relativePath);
@@ -125057,7 +125116,7 @@ var require_tmp = __commonJS({
if (_isUndefined(name)) return;
const resolvedPath = _resolvePathSync(name, tmpDir);
const relativePath = path28.relative(tmpDir, resolvedPath);
if (!resolvedPath.startsWith(tmpDir)) {
if (relativePath.startsWith("..") || path28.isAbsolute(relativePath)) {
throw new Error(`${option} option must be relative to "${tmpDir}", found "${relativePath}".`);
}
return relativePath;
@@ -147623,7 +147682,7 @@ var safeDump = renamed("safeDump", "dump");
var semver = __toESM(require_semver2());
// src/api-compatibility.json
var maximumVersion = "3.21";
var maximumVersion = "3.22";
var minimumVersion = "3.16";
// src/json/index.ts
@@ -148307,7 +148366,7 @@ function getDiffRangesJsonFilePath() {
return path2.join(getTemporaryDirectory(), PR_DIFF_RANGE_JSON_FILENAME);
}
function getActionVersion() {
return "4.36.0";
return "4.36.1";
}
function getWorkflowEventName() {
return getRequiredEnvParam("GITHUB_EVENT_NAME");
@@ -148871,8 +148930,8 @@ function wrapApiConfigurationError(e) {
}
// src/defaults.json
var bundleVersion = "codeql-bundle-v2.25.4";
var cliVersion = "2.25.4";
var bundleVersion = "codeql-bundle-v2.25.5";
var cliVersion = "2.25.5";
// src/overlay/index.ts
var fs4 = __toESM(require("fs"));
@@ -150351,11 +150410,14 @@ function getUnknownLanguagesError(languages) {
}
// src/feature-flags/properties.ts
var github2 = __toESM(require_github());
var GITHUB_CODEQL_PROPERTY_PREFIX = "github-codeql-";
var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => {
RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay";
RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries";
RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs";
RepositoryPropertyName2["TOOLS"] = "github-codeql-tools";
RepositoryPropertyName2["TOOLS_MODE"] = "github-codeql-tools-mode";
return RepositoryPropertyName2;
})(RepositoryPropertyName || {});
function isString2(value) {
@@ -150373,7 +150435,12 @@ var booleanProperty = {
var repositoryPropertyParsers = {
["github-codeql-disable-overlay" /* DISABLE_OVERLAY */]: booleanProperty,
["github-codeql-extra-queries" /* EXTRA_QUERIES */]: stringProperty,
["github-codeql-file-coverage-on-prs" /* FILE_COVERAGE_ON_PRS */]: booleanProperty
["github-codeql-file-coverage-on-prs" /* FILE_COVERAGE_ON_PRS */]: booleanProperty,
["github-codeql-tools" /* TOOLS */]: stringProperty,
["github-codeql-tools-mode" /* TOOLS_MODE */]: {
validate: isString2,
parse: parseToolsModeRepositoryProperty
}
};
async function loadPropertiesFromApi(logger, repositoryNwo) {
try {
@@ -150426,6 +150493,26 @@ async function loadPropertiesFromApi(logger, repositoryNwo) {
);
}
}
async function loadRepositoryProperties(repositoryNwo, logger) {
const repositoryOwnerType = github2.context.payload.repository?.owner.type;
logger.debug(
`Repository owner type is '${repositoryOwnerType ?? "unknown"}'.`
);
if (repositoryOwnerType === "User") {
logger.debug(
"Skipping loading repository properties because the repository is owned by a user and therefore cannot have repository properties."
);
return new Success({});
}
try {
return new Success(await loadPropertiesFromApi(logger, repositoryNwo));
} catch (error3) {
logger.info(
`Failed to load repository properties: ${getErrorMessage(error3)}`
);
return new Failure(error3);
}
}
function setProperty2(properties, name, value, logger) {
const propertyOptions = repositoryPropertyParsers[name];
if (propertyOptions.validate(value)) {
@@ -150447,6 +150534,15 @@ function parseBooleanRepositoryProperty(name, value, logger) {
function parseStringRepositoryProperty(_name, value) {
return value;
}
function parseToolsModeRepositoryProperty(name, value, logger) {
if (value !== "dynamic" /* Dynamic */ && value !== "enforce" /* Enforce */) {
logger.warning(
`Repository property '${name}' has unexpected value '${value}'. Expected 'dynamic' or 'enforce'. Defaulting to 'enforce'.`
);
return "enforce" /* Enforce */;
}
return value;
}
var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set(
Object.values(RepositoryPropertyName)
);
@@ -151640,7 +151736,6 @@ async function initActionState({
computedConfig,
tempDir,
codeQLCmd: codeql.getPath(),
codeQLMetadata: codeql.getCliMetadata(),
gitHubVersion: githubVersion,
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
debugMode,
@@ -153318,7 +153413,7 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, rawLanguages, useO
);
} else {
if (allowToolcacheValueFF) {
logger.warning(
logger.info(
`Ignoring 'tools: ${toolsInput}' because the workflow was not triggered dynamically.`
);
} else {
@@ -153794,29 +153889,19 @@ Details: ${e.stack}` : ""}`
);
}
}
async function getCodeQL(cmd, cliMetadata) {
async function getCodeQL(cmd) {
if (cachedCodeQL === void 0) {
cachedCodeQL = await getCodeQLForCmd(cmd, true, cliMetadata);
} else {
cachedCodeQL.hydrateCliMetadata(cliMetadata);
cachedCodeQL = await getCodeQLForCmd(cmd, true);
}
return cachedCodeQL;
}
function cacheCodeQlVersionForStatusReports(versionInfo) {
if (getCachedCodeQlVersion() === void 0) {
cacheCodeQlVersion(versionInfo);
}
}
async function getCodeQLForCmd(cmd, checkVersion, initialCliMetadata) {
const cliMetadata = { codeQLCmd: cmd };
let cachedVersion;
let cachedUnfilteredBetterResolveLanguages;
async function getCodeQLForCmd(cmd, checkVersion) {
const codeql = {
getPath() {
return cmd;
},
async getVersion() {
let result = cachedVersion;
let result = getCachedCodeQlVersion();
if (result === void 0) {
const output = await runCli(cmd, ["version", "--format=json"], {
noStreamStdout: true
@@ -153828,17 +153913,12 @@ async function getCodeQLForCmd(cmd, checkVersion, initialCliMetadata) {
`Invalid JSON output from \`version --format=json\`: ${output}`
);
}
cachedVersion = result;
cacheCodeQlVersion(result);
}
cacheCodeQlVersionForStatusReports(result);
return result;
},
async printVersion() {
const version = await this.getVersion();
process.stdout.write(`[command]${cmd} version --format=json
`);
process.stdout.write(`${JSON.stringify(version)}
`);
await runCli(cmd, ["version", "--format=json"]);
},
async supportsFeature(feature) {
return isSupportedToolsFeature(await this.getVersion(), feature);
@@ -154008,9 +154088,6 @@ async function getCodeQLForCmd(cmd, checkVersion, initialCliMetadata) {
async betterResolveLanguages({
filterToLanguagesWithQueries
} = { filterToLanguagesWithQueries: false }) {
if (!filterToLanguagesWithQueries && cachedUnfilteredBetterResolveLanguages) {
return cachedUnfilteredBetterResolveLanguages;
}
const codeqlArgs = [
"resolve",
"languages",
@@ -154022,11 +154099,7 @@ async function getCodeQLForCmd(cmd, checkVersion, initialCliMetadata) {
];
const output = await runCli(cmd, codeqlArgs);
try {
const result = JSON.parse(output);
if (!filterToLanguagesWithQueries) {
cachedUnfilteredBetterResolveLanguages = result;
}
return result;
return JSON.parse(output);
} catch (e) {
throw new Error(
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`
@@ -154185,10 +154258,6 @@ ${output}`
await new toolrunner3.ToolRunner(cmd, args).exec();
},
async resolveExtractor(language) {
const cachedExtractorPath = cliMetadata.extractorPaths?.[language];
if (cachedExtractorPath !== void 0) {
return cachedExtractorPath;
}
let extractorPath = "";
await new toolrunner3.ToolRunner(
cmd,
@@ -154212,10 +154281,7 @@ ${output}`
}
}
).exec();
const resolvedExtractorPath = JSON.parse(extractorPath);
cliMetadata.extractorPaths ??= {};
cliMetadata.extractorPaths[language] = resolvedExtractorPath;
return resolvedExtractorPath;
return JSON.parse(extractorPath);
},
async resolveQueriesStartingPacks(queries) {
const codeqlArgs = [
@@ -154268,21 +154334,8 @@ ${output}`
args.push("--sarif-merge-runs-from-equal-category");
}
await runCli(cmd, args);
},
getCliMetadata() {
return cliMetadata;
},
hydrateCliMetadata(metadata) {
if (metadata?.codeQLCmd !== cliMetadata.codeQLCmd) {
return;
}
cliMetadata.extractorPaths = {
...metadata.extractorPaths,
...cliMetadata.extractorPaths
};
}
};
codeql.hydrateCliMetadata(initialCliMetadata);
if (checkVersion && !await codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION)) {
throw new ConfigurationError(
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${(await codeql.getVersion()).version}`
@@ -154467,7 +154520,7 @@ async function setupCppAutobuild(codeql, logger) {
}
async function runAutobuild(config, language, logger) {
logger.startGroup(`Attempting to automatically build ${language} code`);
const codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeQL = await getCodeQL(config.codeQLCmd);
if (language === "cpp" /* cpp */) {
await setupCppAutobuild(codeQL, logger);
}
@@ -156701,7 +156754,7 @@ var fs19 = __toESM(require("fs"));
var path17 = __toESM(require("path"));
var core14 = __toESM(require_core());
var toolrunner4 = __toESM(require_toolrunner());
var github2 = __toESM(require_github());
var github3 = __toESM(require_github());
var io6 = __toESM(require_io());
async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, rawLanguages, useOverlayAwareDefaultCliVersion, features, logger) {
logger.startGroup("Setup CodeQL tools");
@@ -156905,7 +156958,7 @@ function logFileCoverageOnPrsDeprecationWarning(logger) {
if (process.env["CODEQL_ACTION_DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION" /* DID_LOG_FILE_COVERAGE_ON_PRS_DEPRECATION */]) {
return;
}
const repositoryOwnerType = github2.context.payload.repository?.owner.type;
const repositoryOwnerType = github3.context.payload.repository?.owner.type;
let message = "Starting April 2026, the CodeQL Action will skip computing file coverage information on pull requests to improve analysis performance. File coverage information will still be computed on non-PR analyses.";
const envVarOptOut = "set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true`.";
const repoPropertyOptOut = 'create a custom repository property with the name `github-codeql-file-coverage-on-prs` and the type "True/false", then set this property to `true` in the repository\'s settings.';
@@ -157051,7 +157104,7 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo
let tempDir = getTemporaryDirectory();
const config = await getConfig(tempDir, logger);
if (config !== void 0) {
codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
codeQL = await getCodeQL(config.codeQLCmd);
tempDir = config.tempDir;
} else {
logger.info(
@@ -157785,7 +157838,7 @@ async function run(startedAt) {
"Config file could not be found at expected location. Has the 'init' action been called?"
);
}
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
if (hasBadExpectErrorInput()) {
throw new ConfigurationError(
"`expect-error` input parameter is for internal use only. It should only be set by codeql-action or a fork."
@@ -158554,7 +158607,7 @@ async function runWrapper2() {
logger
);
if (config !== void 0) {
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
const version = await codeql.getVersion();
await uploadCombinedSarifArtifacts(
logger,
@@ -158635,7 +158688,7 @@ async function run2(startedAt) {
"Config file could not be found at expected location. Has the 'init' action been called?"
);
}
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
languages = await determineAutobuildLanguages(codeql, config, logger);
if (languages !== void 0) {
const workingDirectory = getOptionalInput("working-directory");
@@ -158689,10 +158742,50 @@ async function runWrapper3() {
var fs27 = __toESM(require("fs"));
var path23 = __toESM(require("path"));
var core21 = __toESM(require_core());
var github3 = __toESM(require_github());
var io7 = __toESM(require_io());
var semver10 = __toESM(require_semver2());
// src/config/resolve-tools-input.ts
function resolveToolsInputWithMetadata(toolsWorkflowInput, isDynamicWorkflow2, repositoryProperties, logger) {
if (toolsWorkflowInput) {
logger.info(
`Setting tools: ${toolsWorkflowInput} based on workflow input.`
);
return {
effectiveToolsInput: toolsWorkflowInput,
effectiveToolsInputSource: "workflow-input" /* WorkflowInput */,
toolsRepoPropertyMode: void 0
};
}
const toolsPropertyValue = repositoryProperties["github-codeql-tools" /* TOOLS */];
const toolsMode = repositoryProperties["github-codeql-tools-mode" /* TOOLS_MODE */] ?? "enforce" /* Enforce */;
if (toolsPropertyValue && toolsMode === "dynamic" /* Dynamic */ && !isDynamicWorkflow2) {
logger.info(
`Ignoring '${"github-codeql-tools" /* TOOLS */}' repository property because '${"github-codeql-tools-mode" /* TOOLS_MODE */}' is set to '${toolsMode}' and this is not a dynamic workflow.`
);
return {
effectiveToolsInput: void 0,
effectiveToolsInputSource: "none" /* None */,
toolsRepoPropertyMode: toolsMode
};
}
if (toolsPropertyValue) {
logger.info(
`Setting tools: ${toolsPropertyValue} based on the '${"github-codeql-tools" /* TOOLS */}' repository property (mode: '${toolsMode}').`
);
return {
effectiveToolsInput: toolsPropertyValue,
effectiveToolsInputSource: "repository-property" /* RepositoryProperty */,
toolsRepoPropertyMode: toolsMode
};
}
return {
effectiveToolsInput: void 0,
effectiveToolsInputSource: "none" /* None */,
toolsRepoPropertyMode: void 0
};
}
// src/workflow.ts
var fs26 = __toESM(require("fs"));
var path22 = __toESM(require("path"));
@@ -158983,7 +159076,7 @@ async function sendStartingStatusReport(startedAt, config, logger) {
await sendStatusReport(statusReportBase);
}
}
async function sendCompletedStatusReport2(startedAt, config, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, overlayBaseDatabaseStats, dependencyCachingResults, logger, error3) {
async function sendCompletedStatusReport2(startedAt, config, configFile, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, effectiveToolsInput, effectiveToolsInputSource, toolsRepoPropertyMode, overlayBaseDatabaseStats, dependencyCachingResults, logger, error3) {
const statusReportBase = await createStatusReportBase(
"init" /* Init */,
getActionsStatus(error3),
@@ -159001,6 +159094,9 @@ async function sendCompletedStatusReport2(startedAt, config, configFile, toolsDo
const initStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
effective_tools_input: effectiveToolsInput || "",
effective_tools_input_source: effectiveToolsInputSource,
tools_repo_property_mode: toolsRepoPropertyMode || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || "UNKNOWN" /* Unknown */,
workflow_languages: workflowLanguages || ""
@@ -159044,6 +159140,9 @@ async function run3(startedAt) {
let toolsSource;
let toolsVersion;
let zstdAvailability;
let effectiveToolsInput;
let effectiveToolsInputSource = "none" /* None */;
let toolsRepoPropertyMode;
try {
initializeEnvironment(getActionVersion());
persistInputs();
@@ -159067,6 +159166,7 @@ async function run3(startedAt) {
repositoryNwo,
logger
);
const repositoryProperties = repositoryPropertiesResult.orElse({});
const jobRunUuid = v4_default();
logger.info(`Job run UUID is ${jobRunUuid}.`);
core21.exportVariable("JOB_RUN_UUID" /* JOB_RUN_UUID */, jobRunUuid);
@@ -159092,12 +159192,21 @@ async function run3(startedAt) {
}
const codeQLDefaultVersionInfo = await features.getEnabledDefaultCliVersions(gitHubVersion.type);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
const resolvedToolsInput = resolveToolsInputWithMetadata(
getOptionalInput("tools"),
isDynamicWorkflow(),
repositoryProperties,
logger
);
effectiveToolsInput = resolvedToolsInput.effectiveToolsInput;
effectiveToolsInputSource = resolvedToolsInput.effectiveToolsInputSource;
toolsRepoPropertyMode = resolvedToolsInput.toolsRepoPropertyMode;
const rawLanguages = getRawLanguagesNoAutodetect(
getOptionalInput("languages")
);
const useOverlayAwareDefaultCliVersion = analysisKinds?.length === 1 && analysisKinds[0] === "code-scanning" /* CodeScanning */;
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
effectiveToolsInput,
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
@@ -159133,7 +159242,6 @@ async function run3(startedAt) {
}
analysisKinds = await getAnalysisKinds(logger, features);
const debugMode = getOptionalInput("debug") === "true" || core21.isDebug();
const repositoryProperties = repositoryPropertiesResult.orElse({});
const fileCoverageResult = await getFileCoverageInformationEnabled(
debugMode,
codeql,
@@ -159431,6 +159539,9 @@ exec ${goBinaryPath} "$@"`
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
effectiveToolsInputSource,
toolsRepoPropertyMode,
overlayBaseDatabaseStats,
dependencyCachingStatus,
logger,
@@ -159448,31 +159559,14 @@ exec ${goBinaryPath} "$@"`
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
effectiveToolsInputSource,
toolsRepoPropertyMode,
overlayBaseDatabaseStats,
dependencyCachingStatus,
logger
);
}
async function loadRepositoryProperties(repositoryNwo, logger) {
const repositoryOwnerType = github3.context.payload.repository?.owner.type;
logger.debug(
`Repository owner type is '${repositoryOwnerType ?? "unknown"}'.`
);
if (repositoryOwnerType === "User") {
logger.debug(
"Skipping loading repository properties because the repository is owned by a user and therefore cannot have repository properties."
);
return new Success({});
}
try {
return new Success(await loadPropertiesFromApi(logger, repositoryNwo));
} catch (error3) {
logger.warning(
`Failed to load repository properties: ${getErrorMessage(error3)}`
);
return new Failure(error3);
}
}
async function recordZstdAvailability(config, zstdAvailability) {
addNoLanguageDiagnostic(
config,
@@ -159567,7 +159661,7 @@ async function prepareFailedSarif(logger, features, config) {
}
async function generateFailedSarif(features, config, category, checkoutPath, sarifFile) {
const databasePath = config.dbLocation;
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
if (sarifFile === void 0) {
sarifFile = "../codeql-failed-run.sarif";
}
@@ -159833,7 +159927,7 @@ async function run4(startedAt) {
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any."
);
} else {
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
uploadFailedSarifResult = await uploadFailureInfo(
tryUploadAllAvailableDebugArtifacts,
printDebugLogs,
@@ -160041,7 +160135,7 @@ async function runWrapper6() {
// src/setup-codeql-action.ts
var core24 = __toESM(require_core());
async function sendCompletedStatusReport3(startedAt, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, logger, error3) {
async function sendCompletedStatusReport3(startedAt, toolsDownloadStatusReport, toolsFeatureFlagsValid, toolsSource, toolsVersion, effectiveToolsInput, effectiveToolsInputSource, toolsRepoPropertyMode, logger, error3) {
const statusReportBase = await createStatusReportBase(
"setup-codeql" /* SetupCodeQL */,
getActionsStatus(error3),
@@ -160058,6 +160152,9 @@ async function sendCompletedStatusReport3(startedAt, toolsDownloadStatusReport,
const initStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
effective_tools_input: effectiveToolsInput || "",
effective_tools_input_source: effectiveToolsInputSource,
tools_repo_property_mode: toolsRepoPropertyMode || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || "UNKNOWN" /* Unknown */,
workflow_languages: ""
@@ -160078,6 +160175,9 @@ async function run6(startedAt) {
let toolsFeatureFlagsValid;
let toolsSource;
let toolsVersion;
let effectiveToolsInput;
let effectiveToolsInputSource = "none" /* None */;
let toolsRepoPropertyMode;
try {
initializeEnvironment(getActionVersion());
const apiDetails = {
@@ -160112,12 +160212,26 @@ async function run6(startedAt) {
}
const codeQLDefaultVersionInfo = await features.getEnabledDefaultCliVersions(gitHubVersion.type);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
const repositoryPropertiesResult = await loadRepositoryProperties(
repositoryNwo,
logger
);
const repositoryProperties = repositoryPropertiesResult.orElse({});
const resolvedToolsInput = resolveToolsInputWithMetadata(
getOptionalInput("tools"),
isDynamicWorkflow(),
repositoryProperties,
logger
);
effectiveToolsInput = resolvedToolsInput.effectiveToolsInput;
effectiveToolsInputSource = resolvedToolsInput.effectiveToolsInputSource;
toolsRepoPropertyMode = resolvedToolsInput.toolsRepoPropertyMode;
const rawLanguages = getRawLanguagesNoAutodetect(
getOptionalInput("languages")
);
const analysisKinds = await getAnalysisKinds(logger, features);
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
effectiveToolsInput,
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
@@ -160158,6 +160272,9 @@ async function run6(startedAt) {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
effectiveToolsInputSource,
toolsRepoPropertyMode,
logger
);
}
+93 -578
View File
@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "4.36.0",
"version": "4.36.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "4.36.0",
"version": "4.36.1",
"license": "MIT",
"workspaces": [
"pr-checks"
@@ -32,18 +32,18 @@
"jsonschema": "1.5.0",
"long": "^5.3.2",
"node-forge": "^1.4.0",
"semver": "^7.7.4",
"semver": "^7.8.0",
"uuid": "^14.0.0"
},
"devDependencies": {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.5",
"@eslint/compat": "^2.1.0",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^16.0.0",
"@types/archiver": "^7.0.0",
"@types/follow-redirects": "^1.14.4",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.19.39",
"@types/node": "^20.19.41",
"@types/node-forge": "^1.3.14",
"@types/sarif": "^2.1.7",
"@types/semver": "^7.7.1",
@@ -58,10 +58,10 @@
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^11.1.0",
"globals": "^17.6.0",
"nock": "^14.0.12",
"nock": "^14.0.15",
"sinon": "^22.0.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.2"
"typescript-eslint": "^8.59.4"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -1316,9 +1316,9 @@
}
},
"node_modules/@eslint/compat": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.5.tgz",
"integrity": "sha512-IbHDbHJfkVNv6xjlET8AIVo/K1NQt7YT4Rp6ok/clyBGcpRx1l6gv0Rq3vBvYfPJIZt6ODf66Zq08FJNDpnzgg==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.1.0.tgz",
"integrity": "sha512-LgaSCymEpw7tF53xvDw9SNsraPb1IBHxpdABIOM0hW8UAlP8znrjYtuxfR58FSJ3L9BhwD+FaPRFQpZq84Nh6g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -2469,9 +2469,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "20.19.39",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
"version": "20.19.41",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz",
"integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2528,17 +2528,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz",
"integrity": "sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.4.tgz",
"integrity": "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.59.2",
"@typescript-eslint/type-utils": "8.59.2",
"@typescript-eslint/utils": "8.59.2",
"@typescript-eslint/visitor-keys": "8.59.2",
"@typescript-eslint/scope-manager": "8.59.4",
"@typescript-eslint/type-utils": "8.59.4",
"@typescript-eslint/utils": "8.59.4",
"@typescript-eslint/visitor-keys": "8.59.4",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
@@ -2551,7 +2551,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.59.2",
"@typescript-eslint/parser": "^8.59.4",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
@@ -2567,16 +2567,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.2.tgz",
"integrity": "sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.4.tgz",
"integrity": "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.59.2",
"@typescript-eslint/types": "8.59.2",
"@typescript-eslint/typescript-estree": "8.59.2",
"@typescript-eslint/visitor-keys": "8.59.2",
"@typescript-eslint/scope-manager": "8.59.4",
"@typescript-eslint/types": "8.59.4",
"@typescript-eslint/typescript-estree": "8.59.4",
"@typescript-eslint/visitor-keys": "8.59.4",
"debug": "^4.4.3"
},
"engines": {
@@ -2610,14 +2610,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.2.tgz",
"integrity": "sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.4.tgz",
"integrity": "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.59.2",
"@typescript-eslint/types": "^8.59.2",
"@typescript-eslint/tsconfig-utils": "^8.59.4",
"@typescript-eslint/types": "^8.59.4",
"debug": "^4.4.3"
},
"engines": {
@@ -2650,14 +2650,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.2.tgz",
"integrity": "sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.4.tgz",
"integrity": "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.59.2",
"@typescript-eslint/visitor-keys": "8.59.2"
"@typescript-eslint/types": "8.59.4",
"@typescript-eslint/visitor-keys": "8.59.4"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2668,9 +2668,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.2.tgz",
"integrity": "sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.4.tgz",
"integrity": "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2685,15 +2685,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.2.tgz",
"integrity": "sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.4.tgz",
"integrity": "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.59.2",
"@typescript-eslint/typescript-estree": "8.59.2",
"@typescript-eslint/utils": "8.59.2",
"@typescript-eslint/types": "8.59.4",
"@typescript-eslint/typescript-estree": "8.59.4",
"@typescript-eslint/utils": "8.59.4",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
@@ -2728,9 +2728,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.2.tgz",
"integrity": "sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.4.tgz",
"integrity": "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2742,16 +2742,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.2.tgz",
"integrity": "sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.4.tgz",
"integrity": "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.59.2",
"@typescript-eslint/tsconfig-utils": "8.59.2",
"@typescript-eslint/types": "8.59.2",
"@typescript-eslint/visitor-keys": "8.59.2",
"@typescript-eslint/project-service": "8.59.4",
"@typescript-eslint/tsconfig-utils": "8.59.4",
"@typescript-eslint/types": "8.59.4",
"@typescript-eslint/visitor-keys": "8.59.4",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
@@ -2827,16 +2827,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.2.tgz",
"integrity": "sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.4.tgz",
"integrity": "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.59.2",
"@typescript-eslint/types": "8.59.2",
"@typescript-eslint/typescript-estree": "8.59.2"
"@typescript-eslint/scope-manager": "8.59.4",
"@typescript-eslint/types": "8.59.4",
"@typescript-eslint/typescript-estree": "8.59.4"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2851,13 +2851,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.2.tgz",
"integrity": "sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.4.tgz",
"integrity": "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.59.2",
"@typescript-eslint/types": "8.59.4",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
@@ -7415,9 +7415,9 @@
"license": "MIT"
},
"node_modules/nock": {
"version": "14.0.12",
"resolved": "https://registry.npmjs.org/nock/-/nock-14.0.12.tgz",
"integrity": "sha512-kZM3bHV0KzhHH6E2eRszHyML/w87AUzLBwupNTHohtYWP9fZYgUPmCbSKq6ITfEEmHqN4/p0MscvUipT4P5Qsg==",
"version": "14.0.15",
"resolved": "https://registry.npmjs.org/nock/-/nock-14.0.15.tgz",
"integrity": "sha512-S0a47C9pLvcYx/Ugf0H30BVBEcUgMMBDk9VJIDlJ8XGrfH2QDUD4Tgdp45qDIiHttokBG+IbsOtsvIjGR/j3bg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8311,9 +8311,9 @@
}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -9047,9 +9047,9 @@
}
},
"node_modules/tmp": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz",
"integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==",
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
"integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
"license": "MIT",
"engines": {
"node": ">=14.14"
@@ -9140,14 +9140,13 @@
"license": "0BSD"
},
"node_modules/tsx": {
"version": "4.21.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz",
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
"version": "4.22.3",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.3.tgz",
"integrity": "sha512-mdoNxBC/cSQObGGVQ5Bpn5i+yv7j68gk3Nfm3wFjcJg3Z0Mix9jzAFfP12prmm5eVGmDKtp0yyArrs0Q+8gZHg==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.27.0",
"get-tsconfig": "^4.7.5"
"esbuild": "~0.28.0"
},
"bin": {
"tsx": "dist/cli.mjs"
@@ -9159,490 +9158,6 @@
"fsevents": "~2.3.3"
}
},
"node_modules/tsx/node_modules/@esbuild/aix-ppc64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
"integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/android-arm": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
"integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/android-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
"integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/android-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
"integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/darwin-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
"integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/darwin-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
"integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/freebsd-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
"integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/freebsd-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
"integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-arm": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
"integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
"integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-ia32": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
"integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-loong64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
"integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-mips64el": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
"integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-ppc64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
"integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-riscv64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
"integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-s390x": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
"integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/linux-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
"integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/netbsd-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
"integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/netbsd-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
"integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/openbsd-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
"integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/openbsd-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
"integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/openharmony-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
"integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/sunos-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
"integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/win32-arm64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
"integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/win32-ia32": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
"integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/@esbuild/win32-x64": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
"integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/tsx/node_modules/esbuild": {
"version": "0.27.7",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz",
"integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.27.7",
"@esbuild/android-arm": "0.27.7",
"@esbuild/android-arm64": "0.27.7",
"@esbuild/android-x64": "0.27.7",
"@esbuild/darwin-arm64": "0.27.7",
"@esbuild/darwin-x64": "0.27.7",
"@esbuild/freebsd-arm64": "0.27.7",
"@esbuild/freebsd-x64": "0.27.7",
"@esbuild/linux-arm": "0.27.7",
"@esbuild/linux-arm64": "0.27.7",
"@esbuild/linux-ia32": "0.27.7",
"@esbuild/linux-loong64": "0.27.7",
"@esbuild/linux-mips64el": "0.27.7",
"@esbuild/linux-ppc64": "0.27.7",
"@esbuild/linux-riscv64": "0.27.7",
"@esbuild/linux-s390x": "0.27.7",
"@esbuild/linux-x64": "0.27.7",
"@esbuild/netbsd-arm64": "0.27.7",
"@esbuild/netbsd-x64": "0.27.7",
"@esbuild/openbsd-arm64": "0.27.7",
"@esbuild/openbsd-x64": "0.27.7",
"@esbuild/openharmony-arm64": "0.27.7",
"@esbuild/sunos-x64": "0.27.7",
"@esbuild/win32-arm64": "0.27.7",
"@esbuild/win32-ia32": "0.27.7",
"@esbuild/win32-x64": "0.27.7"
}
},
"node_modules/tunnel": {
"version": "0.0.6",
"license": "MIT",
@@ -9777,16 +9292,16 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.59.2",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.2.tgz",
"integrity": "sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==",
"version": "8.59.4",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.4.tgz",
"integrity": "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.59.2",
"@typescript-eslint/parser": "8.59.2",
"@typescript-eslint/typescript-estree": "8.59.2",
"@typescript-eslint/utils": "8.59.2"
"@typescript-eslint/eslint-plugin": "8.59.4",
"@typescript-eslint/parser": "8.59.4",
"@typescript-eslint/typescript-estree": "8.59.4",
"@typescript-eslint/utils": "8.59.4"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10212,9 +9727,9 @@
}
},
"node_modules/yaml": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz",
"integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
@@ -10302,11 +9817,11 @@
"@octokit/core": "^7.0.6",
"@octokit/plugin-paginate-rest": ">=9.2.2",
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
"yaml": "^2.8.4"
"yaml": "^2.9.0"
},
"devDependencies": {
"@types/node": "^20.19.39",
"tsx": "^4.21.0"
"@types/node": "^20.19.41",
"tsx": "^4.22.3"
}
}
}
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "4.36.0",
"version": "4.36.1",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -40,18 +40,18 @@
"jsonschema": "1.5.0",
"long": "^5.3.2",
"node-forge": "^1.4.0",
"semver": "^7.7.4",
"semver": "^7.8.0",
"uuid": "^14.0.0"
},
"devDependencies": {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.5",
"@eslint/compat": "^2.1.0",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^16.0.0",
"@types/archiver": "^7.0.0",
"@types/follow-redirects": "^1.14.4",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.19.39",
"@types/node": "^20.19.41",
"@types/node-forge": "^1.3.14",
"@types/sarif": "^2.1.7",
"@types/semver": "^7.7.1",
@@ -66,10 +66,10 @@
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^11.1.0",
"globals": "^17.6.0",
"nock": "^14.0.12",
"nock": "^14.0.15",
"sinon": "^22.0.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.59.2"
"typescript-eslint": "^8.59.4"
},
"overrides": {
"@actions/tool-cache": {
+259
View File
@@ -0,0 +1,259 @@
#!/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, "\\$&");
}
+223
View File
@@ -0,0 +1,223 @@
#!/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();
}
+1 -1
View File
@@ -5,7 +5,7 @@ versions:
- default
steps:
- name: Set up Ruby
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
uses: ruby/setup-ruby@6aaa311d81eba98ae12eaffbcb63296ace0efcde # v1.307.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
+5 -2
View File
@@ -6,14 +6,17 @@ export const OLDEST_SUPPORTED_MAJOR_VERSION = 3;
/** The `pr-checks` directory. */
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. */
export const PR_CHECK_EXCLUDED_FILE = path.join(PR_CHECKS_DIR, "excluded.yml");
/** The path to the esbuild metadata file. */
export const BUNDLE_METADATA_FILE = path.join(PR_CHECKS_DIR, "..", "meta.json");
export const BUNDLE_METADATA_FILE = path.join(REPO_ROOT, "meta.json");
/** The `src` directory. */
const SOURCE_ROOT = path.join(PR_CHECKS_DIR, "..", "src");
const SOURCE_ROOT = path.join(REPO_ROOT, "src");
/** The path to the built-in languages file. */
export const BUILTIN_LANGUAGES_FILE = path.join(
+8 -7
View File
@@ -1,16 +1,17 @@
# PR checks to exclude from required checks
contains:
- "https://"
- "Update"
- "ESLint"
- "update"
- "https://"
- "test-setup-python-scripts"
- "update"
- "Update"
is:
- "Agent"
- "check-expected-release-files"
- "Cleanup artifacts"
- "CodeQL"
- "Dependabot"
- "check-expected-release-files"
- "Agent"
- "Cleanup artifacts"
- "Label PR with size"
- "Post repo size comment"
- "Prepare"
- "Upload results"
- "Label PR with size"
+3 -3
View File
@@ -7,10 +7,10 @@
"@octokit/core": "^7.0.6",
"@octokit/plugin-paginate-rest": ">=9.2.2",
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
"yaml": "^2.8.4"
"yaml": "^2.9.0"
},
"devDependencies": {
"@types/node": "^20.19.39",
"tsx": "^4.21.0"
"@types/node": "^20.19.41",
"tsx": "^4.22.3"
}
}
@@ -43,6 +43,7 @@ predicate envVarRead(DataFlow::Node node, string envVar) {
from DataFlow::Node read, string envVar
where
envVarRead(read, envVar) and
read.getFile().getRelativePath().matches("src/%") and
not read.getFile().getBaseName().matches("%.test.ts") and
not isSafeForDefaultSetup(envVar)
select read,
+1 -1
View File
@@ -38,7 +38,7 @@ export async function runWrapper() {
logger,
);
if (config !== undefined) {
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
const version = await codeql.getVersion();
await debugArtifacts.uploadCombinedSarifArtifacts(
logger,
+2 -2
View File
@@ -30,7 +30,7 @@ import {
} from "./dependency-caching";
import { EnvVar } from "./environment";
import { initFeatures } from "./feature-flags";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { getActionsLogger, Logger } from "./logging";
import { cleanupAndUploadOverlayBaseDatabaseToCache } from "./overlay/caching";
import { getRepositoryNwo } from "./repository";
@@ -256,7 +256,7 @@ async function run(startedAt: Date) {
);
}
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
if (hasBadExpectErrorInput()) {
throw new util.ConfigurationError(
+1 -1
View File
@@ -14,7 +14,7 @@ import {
} from "./analyze";
import { createStubCodeQL } from "./codeql";
import { Feature } from "./feature-flags";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { getRunnerLogger } from "./logging";
import {
setupTests,
+1 -1
View File
@@ -21,7 +21,7 @@ import {
} from "./diff-informed-analysis-utils";
import { EnvVar } from "./environment";
import { FeatureEnablement, Feature } from "./feature-flags";
import { BuiltInLanguage, Language } from "./languages";
import { BuiltInLanguage, Language } from "./languages/index";
import { Logger, withGroupAsync } from "./logging";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
import type * as sarif from "./sarif";
+1 -1
View File
@@ -1 +1 @@
{"maximumVersion": "3.21", "minimumVersion": "3.16"}
{"maximumVersion": "3.22", "minimumVersion": "3.16"}
+2 -2
View File
@@ -10,7 +10,7 @@ import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
import { getCodeQL } from "./codeql";
import { Config, getConfig } from "./config-utils";
import { EnvVar } from "./environment";
import { Language } from "./languages";
import { Language } from "./languages/index";
import { Logger, getActionsLogger } from "./logging";
import {
StatusReportBase,
@@ -101,7 +101,7 @@ async function run(startedAt: Date) {
);
}
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
languages = await determineAutobuildLanguages(codeql, config, logger);
if (languages !== undefined) {
+2 -2
View File
@@ -7,7 +7,7 @@ import * as configUtils from "./config-utils";
import { DocUrl } from "./doc-url";
import { EnvVar } from "./environment";
import { Feature, featureConfig, initFeatures } from "./feature-flags";
import { BuiltInLanguage, Language } from "./languages";
import { BuiltInLanguage, Language } from "./languages/index";
import { Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
import { asyncFilter, BuildMode } from "./util";
@@ -155,7 +155,7 @@ export async function runAutobuild(
logger: Logger,
) {
logger.startGroup(`Attempting to automatically build ${language} code`);
const codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeQL = await getCodeQL(config.codeQLCmd);
if (language === BuiltInLanguage.cpp) {
await setupCppAutobuild(codeQL, logger);
}
+1 -162
View File
@@ -1,5 +1,4 @@
import * as fs from "fs";
import * as path from "path";
import { ExecOptions } from "@actions/exec";
import * as toolrunner from "@actions/exec/lib/toolrunner";
@@ -22,7 +21,7 @@ import {
import type { Config } from "./config-utils";
import * as defaults from "./defaults.json";
import { DocUrl } from "./doc-url";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { getRunnerLogger } from "./logging";
import { ToolsSource } from "./setup-codeql";
import {
@@ -124,166 +123,6 @@ async function stubCodeql(): Promise<codeql.CodeQL> {
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(
"downloads and caches explicitly requested bundles that aren't in the toolcache",
async (t) => {
+14 -88
View File
@@ -22,7 +22,7 @@ import {
FeatureEnablement,
} from "./feature-flags";
import { isAnalyzingDefaultBranch } from "./git-utils";
import { Language } from "./languages";
import { Language } from "./languages/index";
import { Logger } from "./logging";
import { writeBaseDatabaseOidsFile, writeOverlayChangesFile } from "./overlay";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
@@ -218,10 +218,6 @@ export interface CodeQL {
outputFile: string,
options: { mergeRunsFromEqualCategory?: boolean },
): 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 {
@@ -251,10 +247,12 @@ export interface BetterResolveLanguagesOutput {
[alias: string]: string;
};
extractors: {
[language: string]: Array<{
extractor_root: string;
extractor_options?: any;
}>;
[language: string]: [
{
extractor_root: string;
extractor_options?: any;
},
];
};
}
@@ -266,11 +264,6 @@ export interface ResolveBuildEnvironmentOutput {
};
}
export interface CodeQLCliMetadata {
codeQLCmd: string;
extractorPaths?: { [language: string]: string };
}
/**
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
*/
@@ -399,14 +392,9 @@ export async function setupCodeQL(
/**
* Use the CodeQL executable located at the given path.
*/
export async function getCodeQL(
cmd: string,
cliMetadata?: CodeQLCliMetadata,
): Promise<CodeQL> {
export async function getCodeQL(cmd: string): Promise<CodeQL> {
if (cachedCodeQL === undefined) {
cachedCodeQL = await getCodeQLForCmd(cmd, true, cliMetadata);
} else {
cachedCodeQL.hydrateCliMetadata(cliMetadata);
cachedCodeQL = await getCodeQLForCmd(cmd, true);
}
return cachedCodeQL;
}
@@ -504,14 +492,6 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
),
resolveDatabase: resolveFunction(partialCodeql, "resolveDatabase"),
mergeResults: resolveFunction(partialCodeql, "mergeResults"),
getCliMetadata: resolveFunction(partialCodeql, "getCliMetadata", () => ({
codeQLCmd: partialCodeql.getPath?.() ?? "/tmp/dummy-path",
})),
hydrateCliMetadata: resolveFunction(
partialCodeql,
"hydrateCliMetadata",
() => {},
),
};
}
@@ -526,12 +506,6 @@ export async function getCodeQLForTesting(
return getCodeQLForCmd(cmd, false);
}
function cacheCodeQlVersionForStatusReports(versionInfo: VersionInfo): void {
if (util.getCachedCodeQlVersion() === undefined) {
util.cacheCodeQlVersion(versionInfo);
}
}
/**
* Return a CodeQL object for CodeQL CLI access.
*
@@ -543,24 +517,13 @@ function cacheCodeQlVersionForStatusReports(versionInfo: VersionInfo): void {
async function getCodeQLForCmd(
cmd: string,
checkVersion: boolean,
initialCliMetadata?: CodeQLCliMetadata,
): 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 = {
getPath() {
return cmd;
},
async getVersion() {
let result = cachedVersion;
let result = util.getCachedCodeQlVersion();
if (result === undefined) {
const output = await runCli(cmd, ["version", "--format=json"], {
noStreamStdout: true,
@@ -572,15 +535,12 @@ async function getCodeQLForCmd(
`Invalid JSON output from \`version --format=json\`: ${output}`,
);
}
cachedVersion = result;
util.cacheCodeQlVersion(result);
}
cacheCodeQlVersionForStatusReports(result);
return result;
},
async printVersion() {
const version = await this.getVersion();
process.stdout.write(`[command]${cmd} version --format=json\n`);
process.stdout.write(`${JSON.stringify(version)}\n`);
await runCli(cmd, ["version", "--format=json"]);
},
async supportsFeature(feature: ToolsFeature) {
return isSupportedToolsFeature(await this.getVersion(), feature);
@@ -798,13 +758,6 @@ async function getCodeQLForCmd(
filterToLanguagesWithQueries: boolean;
} = { filterToLanguagesWithQueries: false },
) {
if (
!filterToLanguagesWithQueries &&
cachedUnfilteredBetterResolveLanguages
) {
return cachedUnfilteredBetterResolveLanguages;
}
const codeqlArgs = [
"resolve",
"languages",
@@ -819,11 +772,7 @@ async function getCodeQLForCmd(
const output = await runCli(cmd, codeqlArgs);
try {
const result = JSON.parse(output) as BetterResolveLanguagesOutput;
if (!filterToLanguagesWithQueries) {
cachedUnfilteredBetterResolveLanguages = result;
}
return result;
return JSON.parse(output) as BetterResolveLanguagesOutput;
} catch (e) {
throw new Error(
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`,
@@ -1019,11 +968,6 @@ async function getCodeQLForCmd(
await new toolrunner.ToolRunner(cmd, args).exec();
},
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
// the CLI.
let extractorPath = "";
@@ -1049,10 +993,7 @@ async function getCodeQLForCmd(
},
},
).exec();
const resolvedExtractorPath = JSON.parse(extractorPath) as string;
cliMetadata.extractorPaths ??= {};
cliMetadata.extractorPaths[language] = resolvedExtractorPath;
return resolvedExtractorPath;
return JSON.parse(extractorPath) as string;
},
async resolveQueriesStartingPacks(queries: string[]): Promise<string[]> {
const codeqlArgs = [
@@ -1117,22 +1058,7 @@ async function getCodeQLForCmd(
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
// possible, we want to call getVersion(), which populates the version value
// used by status reporting, at the earliest opportunity. But invoking
+1 -1
View File
@@ -18,7 +18,7 @@ import { Feature } from "./feature-flags";
import { RepositoryProperties } from "./feature-flags/properties";
import * as gitUtils from "./git-utils";
import { GitVersionInfo } from "./git-utils";
import { BuiltInLanguage, Language } from "./languages";
import { BuiltInLanguage, Language } from "./languages/index";
import { getRunnerLogger } from "./logging";
import { CODEQL_OVERLAY_MINIMUM_VERSION } from "./overlay";
import * as overlayDiagnostics from "./overlay/diagnostics";
+2 -7
View File
@@ -19,7 +19,7 @@ import {
} from "./analyses";
import * as api from "./api-client";
import { CachingKind, getCachingKind } from "./caching-utils";
import { type CodeQL, type CodeQLCliMetadata } from "./codeql";
import { type CodeQL } from "./codeql";
import {
calculateAugmentation,
ExcludeQueryFilter,
@@ -48,7 +48,7 @@ import {
hasSubmodules,
isAnalyzingDefaultBranch,
} from "./git-utils";
import { BuiltInLanguage, Language } from "./languages";
import { BuiltInLanguage, Language } from "./languages/index";
import { Logger } from "./logging";
import { CODEQL_OVERLAY_MINIMUM_VERSION } from "./overlay";
import {
@@ -177,10 +177,6 @@ export interface Config {
* Path of the CodeQL executable.
*/
codeQLCmd: string;
/**
* Cacheable metadata gathered from the CodeQL CLI while initializing the workflow.
*/
codeQLMetadata?: CodeQLCliMetadata;
/**
* Version of GitHub we are talking to.
*/
@@ -565,7 +561,6 @@ export async function initActionState(
computedConfig,
tempDir,
codeQLCmd: codeql.getPath(),
codeQLMetadata: codeql.getCliMetadata(),
gitHubVersion: githubVersion,
dbLocation: dbLocationOrDefault(dbLocation, tempDir),
debugMode,
+280
View File
@@ -0,0 +1,280 @@
import test from "ava";
import {
EffectiveToolsInputSource,
resolveToolsInput,
resolveToolsInputWithMetadata,
} from "../config/resolve-tools-input";
import {
RepositoryPropertyName,
ToolsModeRepositoryPropertyValue,
} from "../feature-flags/properties";
import type { RepositoryProperties } from "../feature-flags/properties";
import {
getRecordingLogger,
LoggedMessage,
setupTests,
} from "../testing-utils";
setupTests(test);
test("resolveToolsInput returns undefined when no tools input or repository property is set", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const result = resolveToolsInput(undefined, false, {}, logger);
t.is(result, undefined);
t.is(loggedMessages.length, 0);
});
test("resolveToolsInput returns workflow input when only workflow input is provided", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const result = resolveToolsInput("latest", false, {}, logger);
t.is(result, "latest");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: latest based on workflow input.",
);
});
test("resolveToolsInput returns repository property when only repository property is provided", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
};
const result = resolveToolsInput(
undefined,
false,
repositoryProperties,
logger,
);
t.is(result, "toolcache");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property (mode: 'enforce').",
);
});
test("resolveToolsInput prioritizes workflow input over repository property", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
};
const result = resolveToolsInput(
"nightly",
false,
repositoryProperties,
logger,
);
t.is(result, "nightly");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: nightly based on workflow input.",
);
});
test("resolveToolsInput treats empty string workflow input as not set", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
};
const result = resolveToolsInput("", false, repositoryProperties, logger);
t.is(result, "toolcache");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property (mode: 'enforce').",
);
});
test("resolveToolsInput returns undefined when repository property is undefined", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: undefined,
};
const result = resolveToolsInput(
undefined,
false,
repositoryProperties,
logger,
);
t.is(result, undefined);
t.is(loggedMessages.length, 0);
});
test("resolveToolsInput returns repository property when workflow input is not set", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
};
const result = resolveToolsInput(
undefined,
false,
repositoryProperties,
logger,
);
t.is(result, "toolcache");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property (mode: 'enforce').",
);
});
test("resolveToolsInput does not log when workflow input and repository property are not set", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const result = resolveToolsInput(undefined, false, {}, logger);
t.is(result, undefined);
t.is(loggedMessages.length, 0);
});
test("resolveToolsInput applies tools property in enforce mode for static workflows", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
[RepositoryPropertyName.TOOLS_MODE]:
ToolsModeRepositoryPropertyValue.Enforce,
};
const result = resolveToolsInput(
undefined,
false,
repositoryProperties,
logger,
);
t.is(result, "toolcache");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property (mode: 'enforce').",
);
});
test("resolveToolsInput applies tools property in dynamic mode for dynamic workflows", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
[RepositoryPropertyName.TOOLS_MODE]:
ToolsModeRepositoryPropertyValue.Dynamic,
};
const result = resolveToolsInput(
undefined,
true,
repositoryProperties,
logger,
);
t.is(result, "toolcache");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property (mode: 'dynamic').",
);
});
test("resolveToolsInput ignores tools property in dynamic mode for static workflows", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
const repositoryProperties: RepositoryProperties = {
[RepositoryPropertyName.TOOLS]: "toolcache",
[RepositoryPropertyName.TOOLS_MODE]:
ToolsModeRepositoryPropertyValue.Dynamic,
};
const result = resolveToolsInput(
undefined,
false,
repositoryProperties,
logger,
);
t.is(result, undefined);
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Ignoring 'github-codeql-tools' repository property because 'github-codeql-tools-mode' is set to 'dynamic' and this is not a dynamic workflow.",
);
});
test("resolveToolsInputWithMetadata reports workflow input source", (t) => {
const logger = getRecordingLogger([]);
const result = resolveToolsInputWithMetadata("latest", false, {}, logger);
t.is(result.effectiveToolsInput, "latest");
t.is(
result.effectiveToolsInputSource,
EffectiveToolsInputSource.WorkflowInput,
);
t.is(result.toolsRepoPropertyMode, undefined);
});
test("resolveToolsInputWithMetadata reports repository property source and mode", (t) => {
const logger = getRecordingLogger([]);
const result = resolveToolsInputWithMetadata(
undefined,
false,
{
[RepositoryPropertyName.TOOLS]: "toolcache",
[RepositoryPropertyName.TOOLS_MODE]:
ToolsModeRepositoryPropertyValue.Enforce,
},
logger,
);
t.is(result.effectiveToolsInput, "toolcache");
t.is(
result.effectiveToolsInputSource,
EffectiveToolsInputSource.RepositoryProperty,
);
t.is(result.toolsRepoPropertyMode, ToolsModeRepositoryPropertyValue.Enforce);
});
test("resolveToolsInputWithMetadata reports dynamic-mode skip on static workflows", (t) => {
const logger = getRecordingLogger([]);
const result = resolveToolsInputWithMetadata(
undefined,
false,
{
[RepositoryPropertyName.TOOLS]: "toolcache",
[RepositoryPropertyName.TOOLS_MODE]:
ToolsModeRepositoryPropertyValue.Dynamic,
},
logger,
);
t.is(result.effectiveToolsInput, undefined);
t.is(result.effectiveToolsInputSource, EffectiveToolsInputSource.None);
t.is(result.toolsRepoPropertyMode, ToolsModeRepositoryPropertyValue.Dynamic);
});
+100
View File
@@ -0,0 +1,100 @@
import {
RepositoryProperties,
RepositoryPropertyName,
ToolsModeRepositoryPropertyValue,
} from "../feature-flags/properties";
import { Logger } from "../logging";
export enum EffectiveToolsInputSource {
WorkflowInput = "workflow-input",
RepositoryProperty = "repository-property",
None = "none",
}
export type ResolvedToolsInput = {
effectiveToolsInput: string | undefined;
effectiveToolsInputSource: EffectiveToolsInputSource;
toolsRepoPropertyMode: ToolsModeRepositoryPropertyValue | undefined;
};
/**
* Resolves the effective tools input by combining the workflow input and repository properties.
* The explicit `tools` workflow input takes precedence. If none is provided,
* falls back to the repository property (if set). The optional
* `github-codeql-tools-mode` repository property controls whether this fallback
* applies to all workflows (`enforce`) or only dynamic workflows (`dynamic`).
*
* @param toolsWorkflowInput - The value of the `tools` workflow input, if provided.
* @param isDynamicWorkflow - Whether the current workflow is dynamic.
* @param repositoryProperties - The parsed repository properties.
* @param logger - Logger for outputting resolution messages.
* @returns The effective tools input value.
*/
export function resolveToolsInput(
toolsWorkflowInput: string | undefined,
isDynamicWorkflow: boolean,
repositoryProperties: RepositoryProperties,
logger: Logger,
): string | undefined {
return resolveToolsInputWithMetadata(
toolsWorkflowInput,
isDynamicWorkflow,
repositoryProperties,
logger,
).effectiveToolsInput;
}
export function resolveToolsInputWithMetadata(
toolsWorkflowInput: string | undefined,
isDynamicWorkflow: boolean,
repositoryProperties: RepositoryProperties,
logger: Logger,
): ResolvedToolsInput {
if (toolsWorkflowInput) {
logger.info(
`Setting tools: ${toolsWorkflowInput} based on workflow input.`,
);
return {
effectiveToolsInput: toolsWorkflowInput,
effectiveToolsInputSource: EffectiveToolsInputSource.WorkflowInput,
toolsRepoPropertyMode: undefined,
};
}
const toolsPropertyValue = repositoryProperties[RepositoryPropertyName.TOOLS];
const toolsMode =
repositoryProperties[RepositoryPropertyName.TOOLS_MODE] ??
ToolsModeRepositoryPropertyValue.Enforce;
if (
toolsPropertyValue &&
toolsMode === ToolsModeRepositoryPropertyValue.Dynamic &&
!isDynamicWorkflow
) {
logger.info(
`Ignoring '${RepositoryPropertyName.TOOLS}' repository property because '${RepositoryPropertyName.TOOLS_MODE}' is set to '${toolsMode}' and this is not a dynamic workflow.`,
);
return {
effectiveToolsInput: undefined,
effectiveToolsInputSource: EffectiveToolsInputSource.None,
toolsRepoPropertyMode: toolsMode,
};
}
if (toolsPropertyValue) {
logger.info(
`Setting tools: ${toolsPropertyValue} based on the '${RepositoryPropertyName.TOOLS}' repository property (mode: '${toolsMode}').`,
);
return {
effectiveToolsInput: toolsPropertyValue,
effectiveToolsInputSource: EffectiveToolsInputSource.RepositoryProperty,
toolsRepoPropertyMode: toolsMode,
};
}
return {
effectiveToolsInput: undefined,
effectiveToolsInputSource: EffectiveToolsInputSource.None,
toolsRepoPropertyMode: undefined,
};
}
+1 -1
View File
@@ -12,7 +12,7 @@ import { createStubCodeQL } from "./codeql";
import { Config } from "./config-utils";
import { cleanupAndUploadDatabases } from "./database-upload";
import * as gitUtils from "./git-utils";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { RepositoryNwo } from "./repository";
import {
checkExpectedLogMessages,
+1 -1
View File
@@ -13,7 +13,7 @@ import { type CodeQL } from "./codeql";
import { Config } from "./config-utils";
import { EnvVar } from "./environment";
import * as json from "./json";
import { Language } from "./languages";
import { Language } from "./languages/index";
import { Logger, withGroup } from "./logging";
import {
isSafeArtifactUpload,
+4 -4
View File
@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.25.4",
"cliVersion": "2.25.4",
"priorBundleVersion": "codeql-bundle-v2.25.3",
"priorCliVersion": "2.25.3"
"bundleVersion": "codeql-bundle-v2.25.5",
"cliVersion": "2.25.5",
"priorBundleVersion": "codeql-bundle-v2.25.4",
"priorCliVersion": "2.25.4"
}
+1 -1
View File
@@ -27,7 +27,7 @@ import {
CacheStoreResult,
} from "./dependency-caching";
import { Feature } from "./feature-flags";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import {
setupTests,
createFeatures,
+1 -1
View File
@@ -11,7 +11,7 @@ import { CodeQL } from "./codeql";
import { Config } from "./config-utils";
import { EnvVar } from "./environment";
import { Feature, FeatureEnablement } from "./feature-flags";
import { BuiltInLanguage, Language } from "./languages";
import { BuiltInLanguage, Language } from "./languages/index";
import { Logger } from "./logging";
import { getErrorMessage, getRequiredEnvParam } from "./util";
+1 -1
View File
@@ -2,7 +2,7 @@ import { existsSync, mkdirSync, writeFileSync } from "fs";
import path from "path";
import type { Config } from "./config-utils";
import { Language } from "./languages";
import { Language } from "./languages/index";
import { getActionsLogger } from "./logging";
import { getCodeQLDatabasePath } from "./util";
+39 -1
View File
@@ -78,6 +78,8 @@ test.serial("loadPropertiesFromApi loads known properties", async (t) => {
url: "",
data: [
{ property_name: "github-codeql-extra-queries", value: "+queries" },
{ property_name: "github-codeql-tools", value: "toolcache" },
{ property_name: "github-codeql-tools-mode", value: "dynamic" },
{ property_name: "unknown-property", value: "something" },
] satisfies properties.GitHubPropertiesResponse,
});
@@ -87,9 +89,45 @@ test.serial("loadPropertiesFromApi loads known properties", async (t) => {
logger,
mockRepositoryNwo,
);
t.deepEqual(response, { "github-codeql-extra-queries": "+queries" });
t.deepEqual(response, {
"github-codeql-extra-queries": "+queries",
"github-codeql-tools": "toolcache",
"github-codeql-tools-mode": "dynamic",
});
});
test.serial(
"loadPropertiesFromApi warns if tools mode property has unexpected value",
async (t) => {
sinon.stub(api, "getRepositoryProperties").resolves({
headers: {},
status: 200,
url: "",
data: [
{
property_name: "github-codeql-tools-mode",
value: "all",
},
] satisfies properties.GitHubPropertiesResponse,
});
const logger = getRunnerLogger(true);
const warningSpy = sinon.spy(logger, "warning");
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
const response = await properties.loadPropertiesFromApi(
logger,
mockRepositoryNwo,
);
t.deepEqual(response, {
"github-codeql-tools-mode": "enforce",
});
t.true(warningSpy.calledOnce);
t.is(
warningSpy.firstCall.args[0],
"Repository property 'github-codeql-tools-mode' has unexpected value 'all'. Expected 'dynamic' or 'enforce'. Defaulting to 'enforce'.",
);
},
);
test.serial("loadPropertiesFromApi parses true boolean property", async (t) => {
sinon.stub(api, "getRepositoryProperties").resolves({
headers: {},
+70
View File
@@ -1,7 +1,10 @@
import * as github from "@actions/github";
import { isDynamicWorkflow } from "../actions-util";
import { getRepositoryProperties } from "../api-client";
import { Logger } from "../logging";
import { RepositoryNwo } from "../repository";
import { getErrorMessage, Result, Success, Failure } from "../util";
/** The common prefix that we expect all of our repository properties to have. */
export const GITHUB_CODEQL_PROPERTY_PREFIX = "github-codeql-";
@@ -13,6 +16,13 @@ export enum RepositoryPropertyName {
DISABLE_OVERLAY = "github-codeql-disable-overlay",
EXTRA_QUERIES = "github-codeql-extra-queries",
FILE_COVERAGE_ON_PRS = "github-codeql-file-coverage-on-prs",
TOOLS = "github-codeql-tools",
TOOLS_MODE = "github-codeql-tools-mode",
}
export enum ToolsModeRepositoryPropertyValue {
Dynamic = "dynamic",
Enforce = "enforce",
}
/** Parsed types of the known repository properties. */
@@ -20,6 +30,8 @@ export type AllRepositoryProperties = {
[RepositoryPropertyName.DISABLE_OVERLAY]: boolean;
[RepositoryPropertyName.EXTRA_QUERIES]: string;
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: boolean;
[RepositoryPropertyName.TOOLS]: string;
[RepositoryPropertyName.TOOLS_MODE]: ToolsModeRepositoryPropertyValue;
};
/** Parsed repository properties. */
@@ -30,6 +42,8 @@ export type RepositoryPropertyApiType = {
[RepositoryPropertyName.DISABLE_OVERLAY]: string;
[RepositoryPropertyName.EXTRA_QUERIES]: string;
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: string;
[RepositoryPropertyName.TOOLS]: string;
[RepositoryPropertyName.TOOLS_MODE]: string;
};
/** The type of functions which take the `value` from the API and try to convert it to the type we want. */
@@ -77,6 +91,11 @@ const repositoryPropertyParsers: {
[RepositoryPropertyName.DISABLE_OVERLAY]: booleanProperty,
[RepositoryPropertyName.EXTRA_QUERIES]: stringProperty,
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: booleanProperty,
[RepositoryPropertyName.TOOLS]: stringProperty,
[RepositoryPropertyName.TOOLS_MODE]: {
validate: isString,
parse: parseToolsModeRepositoryProperty,
},
};
/**
@@ -172,6 +191,38 @@ export async function loadPropertiesFromApi(
}
}
/**
* Loads [repository properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) if applicable.
*/
export async function loadRepositoryProperties(
repositoryNwo: RepositoryNwo,
logger: Logger,
): Promise<Result<RepositoryProperties, unknown>> {
// See if we can skip loading repository properties early. In particular,
// repositories owned by users cannot have repository properties, so we can
// skip the API call entirely in that case.
const repositoryOwnerType = github.context.payload.repository?.owner.type;
logger.debug(
`Repository owner type is '${repositoryOwnerType ?? "unknown"}'.`,
);
if (repositoryOwnerType === "User") {
logger.debug(
"Skipping loading repository properties because the repository is owned by a user and " +
"therefore cannot have repository properties.",
);
return new Success({});
}
try {
return new Success(await loadPropertiesFromApi(logger, repositoryNwo));
} catch (error) {
logger.info(
`Failed to load repository properties: ${getErrorMessage(error)}`,
);
return new Failure(error);
}
}
/**
* Validate that `value` has the correct type for `K` and, if so, update the partial set of repository
* properties with the parsed value of the specified property.
@@ -217,6 +268,25 @@ function parseStringRepositoryProperty(_name: string, value: string): string {
return value;
}
/** Parse the tools mode repository property. */
function parseToolsModeRepositoryProperty(
name: string,
value: string,
logger: Logger,
): ToolsModeRepositoryPropertyValue {
if (
value !== ToolsModeRepositoryPropertyValue.Dynamic &&
value !== ToolsModeRepositoryPropertyValue.Enforce
) {
logger.warning(
`Repository property '${name}' has unexpected value '${value}'. Expected 'dynamic' or 'enforce'. Defaulting to 'enforce'.`,
);
return ToolsModeRepositoryPropertyValue.Enforce;
}
return value;
}
/** Set of known repository property names, for fast lookups. */
const KNOWN_REPOSITORY_PROPERTY_NAMES = new Set<string>(
Object.values(RepositoryPropertyName),
+1 -1
View File
@@ -163,7 +163,7 @@ async function generateFailedSarif(
sarifFile?: string,
) {
const databasePath = config.dbLocation;
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
// Set the filename for the SARIF file if not already set.
if (sarifFile === undefined) {
+1 -1
View File
@@ -75,7 +75,7 @@ async function run(startedAt: Date) {
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any.",
);
} else {
const codeql = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
const codeql = await getCodeQL(config.codeQLCmd);
uploadFailedSarifResult = await initActionPostHelper.uploadFailureInfo(
debugArtifacts.tryUploadAllAvailableDebugArtifacts,
+41 -42
View File
@@ -2,12 +2,12 @@ import * as fs from "fs";
import * as path from "path";
import * as core from "@actions/core";
import * as github from "@actions/github";
import * as io from "@actions/io";
import * as semver from "semver";
import { v4 as uuidV4 } from "uuid";
import {
isDynamicWorkflow,
FileCmdNotFoundError,
getActionVersion,
getFileType,
@@ -24,6 +24,10 @@ import {
shouldRestoreCache,
} from "./caching-utils";
import { CodeQL } from "./codeql";
import {
EffectiveToolsInputSource,
resolveToolsInputWithMetadata,
} from "./config/resolve-tools-input";
import * as configUtils from "./config-utils";
import {
DependencyCacheRestoreStatusReport,
@@ -40,8 +44,8 @@ import {
import { EnvVar } from "./environment";
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
import {
loadPropertiesFromApi,
RepositoryProperties,
loadRepositoryProperties,
ToolsModeRepositoryPropertyValue,
} from "./feature-flags/properties";
import {
checkInstallPython311,
@@ -53,14 +57,14 @@ import {
initConfig,
runDatabaseInitCluster,
} from "./init";
import { JavaEnvVars, BuiltInLanguage } from "./languages";
import { JavaEnvVars, BuiltInLanguage } from "./languages/index";
import { getActionsLogger, Logger, withGroupAsync } from "./logging";
import {
downloadOverlayBaseDatabaseFromCache,
OverlayBaseDatabaseDownloadStats,
} from "./overlay/caching";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
import { getRepositoryNwo, RepositoryNwo } from "./repository";
import { getRepositoryNwo } from "./repository";
import { ToolsSource } from "./setup-codeql";
import {
ActionName,
@@ -93,10 +97,7 @@ import {
checkActionVersion,
getErrorMessage,
BuildMode,
Result,
getOptionalEnvVar,
Success,
Failure,
} from "./util";
import { checkWorkflow } from "./workflow";
@@ -140,6 +141,9 @@ async function sendCompletedStatusReport(
toolsFeatureFlagsValid: boolean | undefined,
toolsSource: ToolsSource,
toolsVersion: string,
effectiveToolsInput: string | undefined,
effectiveToolsInputSource: EffectiveToolsInputSource,
toolsRepoPropertyMode: ToolsModeRepositoryPropertyValue | undefined,
overlayBaseDatabaseStats: OverlayBaseDatabaseDownloadStats | undefined,
dependencyCachingResults: DependencyCacheRestoreStatusReport | undefined,
logger: Logger,
@@ -165,6 +169,9 @@ async function sendCompletedStatusReport(
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
effective_tools_input: effectiveToolsInput || "",
effective_tools_input_source: effectiveToolsInputSource,
tools_repo_property_mode: toolsRepoPropertyMode || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || ToolsSource.Unknown,
workflow_languages: workflowLanguages || "",
@@ -219,6 +226,9 @@ async function run(startedAt: Date) {
let toolsSource: ToolsSource;
let toolsVersion: string;
let zstdAvailability: ZstdAvailability | undefined;
let effectiveToolsInput: string | undefined;
let effectiveToolsInputSource: EffectiveToolsInputSource;
let toolsRepoPropertyMode: ToolsModeRepositoryPropertyValue | undefined;
try {
initializeEnvironment(getActionVersion());
@@ -251,6 +261,7 @@ async function run(startedAt: Date) {
repositoryNwo,
logger,
);
const repositoryProperties = repositoryPropertiesResult.orElse({});
// Create a unique identifier for this run.
const jobRunUuid = uuidV4();
@@ -296,6 +307,21 @@ async function run(startedAt: Date) {
const codeQLDefaultVersionInfo =
await features.getEnabledDefaultCliVersions(gitHubVersion.type);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
// Determine the effective tools input.
// The explicit `tools` workflow input takes precedence. If none is provided,
// fall back to the 'github-codeql-tools' repository property (if set).
// If 'github-codeql-tools-mode' is set to 'dynamic', this fallback applies
// only to dynamic workflows. Otherwise, it applies to all workflows.
const resolvedToolsInput = resolveToolsInputWithMetadata(
getOptionalInput("tools"),
isDynamicWorkflow(),
repositoryProperties,
logger,
);
effectiveToolsInput = resolvedToolsInput.effectiveToolsInput;
effectiveToolsInputSource = resolvedToolsInput.effectiveToolsInputSource;
toolsRepoPropertyMode = resolvedToolsInput.toolsRepoPropertyMode;
const rawLanguages = configUtils.getRawLanguagesNoAutodetect(
getOptionalInput("languages"),
);
@@ -303,7 +329,7 @@ async function run(startedAt: Date) {
analysisKinds?.length === 1 &&
analysisKinds[0] === AnalysisKind.CodeScanning;
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
effectiveToolsInput,
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
@@ -350,7 +376,6 @@ async function run(startedAt: Date) {
analysisKinds = await getAnalysisKinds(logger, features);
const debugMode = getOptionalInput("debug") === "true" || core.isDebug();
const repositoryProperties = repositoryPropertiesResult.orElse({});
const fileCoverageResult = await getFileCoverageInformationEnabled(
debugMode,
codeql,
@@ -769,6 +794,9 @@ async function run(startedAt: Date) {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
effectiveToolsInputSource,
toolsRepoPropertyMode,
overlayBaseDatabaseStats,
dependencyCachingStatus,
logger,
@@ -786,44 +814,15 @@ async function run(startedAt: Date) {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
effectiveToolsInputSource,
toolsRepoPropertyMode,
overlayBaseDatabaseStats,
dependencyCachingStatus,
logger,
);
}
/**
* Loads [repository properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) if applicable.
*/
async function loadRepositoryProperties(
repositoryNwo: RepositoryNwo,
logger: Logger,
): Promise<Result<RepositoryProperties, unknown>> {
// See if we can skip loading repository properties early. In particular,
// repositories owned by users cannot have repository properties, so we can
// skip the API call entirely in that case.
const repositoryOwnerType = github.context.payload.repository?.owner.type;
logger.debug(
`Repository owner type is '${repositoryOwnerType ?? "unknown"}'.`,
);
if (repositoryOwnerType === "User") {
logger.debug(
"Skipping loading repository properties because the repository is owned by a user and " +
"therefore cannot have repository properties.",
);
return new Success({});
}
try {
return new Success(await loadPropertiesFromApi(logger, repositoryNwo));
} catch (error) {
logger.warning(
`Failed to load repository properties: ${getErrorMessage(error)}`,
);
return new Failure(error);
}
}
async function recordZstdAvailability(
config: configUtils.Config,
zstdAvailability: ZstdAvailability,
+1 -1
View File
@@ -15,7 +15,7 @@ import {
getFileCoverageInformationEnabled,
logFileCoverageOnPrsDeprecationWarning,
} from "./init";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import {
createFeatures,
LoggedMessage,
+1 -1
View File
@@ -26,7 +26,7 @@ import {
RepositoryProperties,
RepositoryPropertyName,
} from "./feature-flags/properties";
import { BuiltInLanguage, Language } from "./languages";
import { BuiltInLanguage, Language } from "./languages/index";
import { Logger, withGroupAsync } from "./logging";
import { ToolsSource } from "./setup-codeql";
import { ZstdAvailability } from "./tar";
+45 -1
View File
@@ -2,6 +2,7 @@ import * as core from "@actions/core";
import { v4 as uuidV4 } from "uuid";
import {
isDynamicWorkflow,
getActionVersion,
getOptionalInput,
getRequiredInput,
@@ -10,9 +11,17 @@ import {
import { AnalysisKind, getAnalysisKinds } from "./analyses";
import { getGitHubVersion } from "./api-client";
import { CodeQL } from "./codeql";
import {
EffectiveToolsInputSource,
resolveToolsInputWithMetadata,
} from "./config/resolve-tools-input";
import { getRawLanguagesNoAutodetect } from "./config-utils";
import { EnvVar } from "./environment";
import { initFeatures } from "./feature-flags";
import {
loadRepositoryProperties,
ToolsModeRepositoryPropertyValue,
} from "./feature-flags/properties";
import { initCodeQL } from "./init";
import { getActionsLogger, Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
@@ -48,6 +57,9 @@ async function sendCompletedStatusReport(
toolsFeatureFlagsValid: boolean | undefined,
toolsSource: ToolsSource,
toolsVersion: string,
effectiveToolsInput: string | undefined,
effectiveToolsInputSource: EffectiveToolsInputSource,
toolsRepoPropertyMode: ToolsModeRepositoryPropertyValue | undefined,
logger: Logger,
error?: Error,
): Promise<void> {
@@ -69,6 +81,9 @@ async function sendCompletedStatusReport(
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
effective_tools_input: effectiveToolsInput || "",
effective_tools_input_source: effectiveToolsInputSource,
tools_repo_property_mode: toolsRepoPropertyMode || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || ToolsSource.Unknown,
workflow_languages: "",
@@ -99,6 +114,9 @@ async function run(startedAt: Date): Promise<void> {
let toolsFeatureFlagsValid: boolean | undefined;
let toolsSource: ToolsSource;
let toolsVersion: string;
let effectiveToolsInput: string | undefined;
let effectiveToolsInputSource: EffectiveToolsInputSource;
let toolsRepoPropertyMode: ToolsModeRepositoryPropertyValue | undefined;
try {
initializeEnvironment(getActionVersion());
@@ -141,12 +159,35 @@ async function run(startedAt: Date): Promise<void> {
const codeQLDefaultVersionInfo =
await features.getEnabledDefaultCliVersions(gitHubVersion.type);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
// Fetch the values of known repository properties that affect us.
const repositoryPropertiesResult = await loadRepositoryProperties(
repositoryNwo,
logger,
);
const repositoryProperties = repositoryPropertiesResult.orElse({});
// Determine the effective tools input.
// The explicit `tools` workflow input takes precedence. If none is provided,
// fall back to the 'github-codeql-tools' repository property (if set).
// If 'github-codeql-tools-mode' is set to 'dynamic', this fallback applies
// only to dynamic workflows. Otherwise, it applies to all workflows.
const resolvedToolsInput = resolveToolsInputWithMetadata(
getOptionalInput("tools"),
isDynamicWorkflow(),
repositoryProperties,
logger,
);
effectiveToolsInput = resolvedToolsInput.effectiveToolsInput;
effectiveToolsInputSource = resolvedToolsInput.effectiveToolsInputSource;
toolsRepoPropertyMode = resolvedToolsInput.toolsRepoPropertyMode;
const rawLanguages = getRawLanguagesNoAutodetect(
getOptionalInput("languages"),
);
const analysisKinds = await getAnalysisKinds(logger, features);
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
effectiveToolsInput,
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
@@ -191,6 +232,9 @@ async function run(startedAt: Date): Promise<void> {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
effectiveToolsInputSource,
toolsRepoPropertyMode,
logger,
);
}
+1 -1
View File
@@ -559,7 +559,7 @@ export async function getCodeQLSource(
);
} else {
if (allowToolcacheValueFF) {
logger.warning(
logger.info(
`Ignoring 'tools: ${toolsInput}' because the workflow was not triggered dynamically.`,
);
} else {
+1 -1
View File
@@ -6,7 +6,7 @@ import * as core from "@actions/core";
import * as actionsUtil from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
import { BuiltInLanguage, parseBuiltInLanguage } from "./languages";
import { BuiltInLanguage, parseBuiltInLanguage } from "./languages/index";
import { getActionsLogger, Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
import {
+1 -1
View File
@@ -10,7 +10,7 @@ import * as defaults from "./defaults.json";
import { setUpFeatureFlagTests } from "./feature-flags/testing-util";
import { UnvalidatedObject, validateSchema } from "./json";
import { makeFromSchema } from "./json/testing-util";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { getRunnerLogger, Logger } from "./logging";
import * as startProxyExports from "./start-proxy";
import * as statusReport from "./status-report";
+1 -1
View File
@@ -18,7 +18,7 @@ import {
FeatureEnablement,
} from "./feature-flags";
import * as json from "./json";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { Logger } from "./logging";
import {
Address,
+64 -1
View File
@@ -2,9 +2,10 @@ import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import { EffectiveToolsInputSource } from "./config/resolve-tools-input";
import { Config } from "./config-utils";
import { EnvVar } from "./environment";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { getRunnerLogger } from "./logging";
import { ToolsSource } from "./setup-codeql";
import {
@@ -316,6 +317,9 @@ const testCreateInitWithConfigStatusReport = makeMacro({
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: "",
effective_tools_input: "",
effective_tools_input_source: EffectiveToolsInputSource.None,
tools_repo_property_mode: "",
tools_resolved_version: "foo",
tools_source: ToolsSource.Unknown,
workflow_languages: "actions",
@@ -347,6 +351,8 @@ testCreateInitWithConfigStatusReport.serial(
languages: [BuiltInLanguage.java, BuiltInLanguage.swift],
}),
{
effective_tools_input_source: EffectiveToolsInputSource.None,
tools_repo_property_mode: "",
trap_cache_download_size_bytes: 1024,
registries: "[]",
query_filters: "[]",
@@ -354,6 +360,63 @@ testCreateInitWithConfigStatusReport.serial(
},
);
test.serial(
"createInitWithConfigStatusReport preserves tools telemetry fields",
async (t) => {
await withTmpDir(async (tmpDir: string) => {
setupEnvironmentAndStub(tmpDir);
const config = createTestConfig({
buildMode: BuildMode.None,
languages: [BuiltInLanguage.java],
});
const statusReportBase = await createStatusReportBase(
ActionName.Init,
"failure",
new Date("May 19, 2023 05:19:00"),
config,
{ numAvailableBytes: 100, numTotalBytes: 500 },
getRunnerLogger(false),
"failure cause",
"exception stack trace",
);
if (t.truthy(statusReportBase)) {
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: "",
effective_tools_input: "toolcache",
effective_tools_input_source:
EffectiveToolsInputSource.RepositoryProperty,
tools_repo_property_mode: "dynamic",
tools_resolved_version: "foo",
tools_source: ToolsSource.Unknown,
workflow_languages: "actions",
};
const initWithConfigStatusReport =
await createInitWithConfigStatusReport(
config,
initStatusReport,
undefined,
1024,
undefined,
undefined,
);
if (t.truthy(initWithConfigStatusReport)) {
t.is(
initWithConfigStatusReport.effective_tools_input_source,
EffectiveToolsInputSource.RepositoryProperty,
);
t.is(initWithConfigStatusReport.tools_repo_property_mode, "dynamic");
}
}
});
},
);
testCreateInitWithConfigStatusReport.serial(
"includes packs for a single language",
createTestConfig({
+7
View File
@@ -12,6 +12,7 @@ import {
isSelfHostedRunner,
} from "./actions-util";
import { getAnalysisKey, getApiClient } from "./api-client";
import { EffectiveToolsInputSource } from "./config/resolve-tools-input";
import { parseRegistriesWithoutCredentials, type Config } from "./config-utils";
import { DependencyCacheRestoreStatusReport } from "./dependency-caching";
import { DocUrl } from "./doc-url";
@@ -482,6 +483,12 @@ export async function sendStatusReport<S extends StatusReportBase>(
export interface InitStatusReport extends StatusReportBase {
/** Value given by the user as the "tools" input. */
tools_input: string;
/** The effective tools input that was used, after applying defaults and repository properties. */
effective_tools_input: string;
/** Indicates where the effective tools input was resolved from. */
effective_tools_input_source: EffectiveToolsInputSource;
/** The value of the tools repository property mode, if relevant. */
tools_repo_property_mode: string;
/** Version of the bundle used. */
tools_resolved_version: string;
/** Where the bundle originated from. */
+1 -3
View File
@@ -560,7 +560,7 @@ export function mockBundleDownloadApi({
}
export function createTestConfig(overrides: Partial<Config>): Config {
const config = Object.assign(
return Object.assign(
{},
{
version: getActionVersion(),
@@ -590,8 +590,6 @@ export function createTestConfig(overrides: Partial<Config>): Config {
} satisfies Config,
overrides,
);
config.codeQLMetadata ??= { codeQLCmd: config.codeQLCmd };
return config;
}
export function makeTestToken(length: number = 36) {
+1 -1
View File
@@ -6,7 +6,7 @@ import * as sinon from "sinon";
import { CodeQL, getCodeQLForTesting } from "./codeql";
import * as configUtils from "./config-utils";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { createTestConfig, makeVersionInfo, setupTests } from "./testing-utils";
import { ToolsFeature } from "./tools-features";
import { getCombinedTracerConfig } from "./tracer-config";
+1 -1
View File
@@ -15,7 +15,7 @@ import {
import * as configUtils from "./config-utils";
import { Feature } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { BuiltInLanguage } from "./languages";
import { BuiltInLanguage } from "./languages/index";
import { getRunnerLogger } from "./logging";
import {
createFeatures,
+1 -1
View File
@@ -10,7 +10,7 @@ import { type Config } from "./config-utils";
import { DocUrl } from "./doc-url";
import { Feature, FeatureEnablement } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { Language } from "./languages";
import { Language } from "./languages/index";
import { Logger } from "./logging";
import {
asHTTPError,
+1 -1
View File
@@ -140,7 +140,7 @@ async function combineSarifFilesUsingCLI(
const config = await getConfig(tempDir, logger);
if (config !== undefined) {
codeQL = await getCodeQL(config.codeQLCmd, config.codeQLMetadata);
codeQL = await getCodeQL(config.codeQLCmd);
tempDir = config.tempDir;
} else {
logger.info(
+1 -1
View File
@@ -15,7 +15,7 @@ import type { Pack } from "./config/db-config";
import type { Config } from "./config-utils";
import { EnvVar } from "./environment";
import * as json from "./json";
import { Language } from "./languages";
import { Language } from "./languages/index";
import { Logger } from "./logging";
/**