mirror of
https://github.com/github/codeql-action.git
synced 2026-05-24 16:14:33 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 652e91defb |
@@ -41,38 +41,7 @@ runs:
|
||||
git add .
|
||||
git commit -m "Update changelog and version after ${VERSION}"
|
||||
|
||||
# Update the build artifacts with the new version number
|
||||
- name: Rebuild the Action
|
||||
shell: bash
|
||||
run: |
|
||||
set -exu
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Check for rebuild changes
|
||||
id: rebuild_changes
|
||||
shell: bash
|
||||
run: |
|
||||
set -exu
|
||||
git add --all
|
||||
if git diff --cached --quiet; then
|
||||
echo "has_changes=false" >> "${GITHUB_OUTPUT}"
|
||||
else
|
||||
echo "has_changes=true" >> "${GITHUB_OUTPUT}"
|
||||
fi
|
||||
|
||||
- name: Commit rebuild
|
||||
if: steps.rebuild_changes.outputs.has_changes == 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -exu
|
||||
git commit -m "Rebuild"
|
||||
|
||||
- name: Push mergeback branch
|
||||
shell: bash
|
||||
env:
|
||||
NEW_BRANCH: "${{ inputs.branch }}"
|
||||
run: git push origin "${NEW_BRANCH}"
|
||||
git push origin "${NEW_BRANCH}"
|
||||
|
||||
- name: Create PR
|
||||
shell: bash
|
||||
@@ -91,6 +60,8 @@ runs:
|
||||
|
||||
Please do the following:
|
||||
|
||||
- [ ] Remove and re-add the "Rebuild" label to the PR to trigger just this workflow.
|
||||
- [ ] Wait for the "Rebuild" workflow to push a commit updating the distribution files.
|
||||
- [ ] Mark the PR as ready for review to trigger the full set of PR checks.
|
||||
- [ ] Approve and merge the PR. When merging the PR, make sure "Create a merge commit" is
|
||||
selected rather than "Squash and merge" or "Rebase and merge".
|
||||
@@ -103,6 +74,7 @@ runs:
|
||||
--head "${NEW_BRANCH}" \
|
||||
--base "${BASE_BRANCH}" \
|
||||
--title "${pr_title}" \
|
||||
--label "Rebuild" \
|
||||
--body "${pr_body}" \
|
||||
--assignee "${GITHUB_ACTOR}" \
|
||||
--draft
|
||||
|
||||
@@ -18,7 +18,7 @@ runs:
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
|
||||
- name: Set up Python
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "CodeQL config"
|
||||
queries:
|
||||
queries:
|
||||
- name: Run custom queries
|
||||
uses: ./queries
|
||||
# Run all extra query suites, both because we want to
|
||||
@@ -13,5 +13,3 @@ queries:
|
||||
paths-ignore:
|
||||
- lib
|
||||
- tests
|
||||
- "**/*.test.ts"
|
||||
- "**/testing-util.ts"
|
||||
|
||||
@@ -16,27 +16,12 @@ No user facing changes.
|
||||
"""
|
||||
|
||||
# NB: This exact commit message is used to find commits for reverting during backports.
|
||||
# Changing it requires a transition period where both old and new versions are supported.
|
||||
# Changing it requires a transition period where both old and new versions are supported.
|
||||
BACKPORT_COMMIT_MESSAGE = 'Update version and changelog for v'
|
||||
|
||||
# Commit message used for rebuild commits, both those produced by this script and those produced
|
||||
# by the `Rebuild Action` workflow (`.github/workflows/rebuild.yml`).
|
||||
REBUILD_COMMIT_MESSAGE = 'Rebuild'
|
||||
|
||||
# Name of the remote
|
||||
ORIGIN = 'origin'
|
||||
|
||||
# Environment variables to check for a GitHub API token.
|
||||
TOKEN_ENVIRONMENT_VARIABLES = ('GH_TOKEN', 'GITHUB_TOKEN')
|
||||
|
||||
# Gets a GitHub API token from one of the supported environment variables.
|
||||
def get_github_token():
|
||||
for variable_name in TOKEN_ENVIRONMENT_VARIABLES:
|
||||
token = os.environ.get(variable_name, '').strip()
|
||||
if token:
|
||||
return token
|
||||
raise Exception('Missing GitHub token. Set GITHUB_TOKEN or GH_TOKEN.')
|
||||
|
||||
# Runs git with the given args and returns the stdout.
|
||||
# Raises an error if git does not exit successfully (unless passed
|
||||
# allow_non_zero_exit_code=True).
|
||||
@@ -47,28 +32,6 @@ def run_git(*args, allow_non_zero_exit_code=False):
|
||||
raise Exception(f'Call to {" ".join(cmd)} exited with code {p.returncode} stderr: {p.stderr.decode("ascii")}.')
|
||||
return p.stdout.decode('ascii')
|
||||
|
||||
# Runs the given command, streaming output to the console.
|
||||
# Raises an error if the command does not exit successfully.
|
||||
def run_command(*args):
|
||||
cmd = list(args)
|
||||
print(f'Running `{" ".join(cmd)}`.')
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
# Rebuilds the action and commits any changes.
|
||||
def rebuild_action():
|
||||
# For backports, the only source-level change vs the source branch is the new version number,
|
||||
# so we just need to refresh the version embedded in `lib/`.
|
||||
run_command('npm', 'ci')
|
||||
run_command('npm', 'run', 'build')
|
||||
|
||||
run_git('add', '--all')
|
||||
# `git diff --cached --quiet` exits 0 if there are no staged changes, 1 if there are.
|
||||
if subprocess.run(['git', 'diff', '--cached', '--quiet']).returncode == 0:
|
||||
print('Rebuild produced no changes; skipping Rebuild commit.')
|
||||
else:
|
||||
run_git('commit', '-m', REBUILD_COMMIT_MESSAGE)
|
||||
print('Created Rebuild commit.')
|
||||
|
||||
# Returns true if the given branch exists on the origin remote
|
||||
def branch_exists_on_remote(branch_name):
|
||||
return run_git('ls-remote', '--heads', ORIGIN, branch_name).strip() != ''
|
||||
@@ -124,11 +87,9 @@ def open_pr(
|
||||
body.append('Please do the following:')
|
||||
if len(conflicted_files) > 0:
|
||||
body.append(' - [ ] Ensure `package.json` file contains the correct version.')
|
||||
body.append(' - [ ] Add a commit to this branch to resolve the merge conflicts ' +
|
||||
body.append(' - [ ] Add commits to this branch to resolve the merge conflicts ' +
|
||||
'in the following files:')
|
||||
body.extend([f' - `{file}`' for file in conflicted_files])
|
||||
body.append(' - [ ] Rebuild the Action locally (`npm run build`) and push any changes to the ' +
|
||||
f'built output in `lib` as a separate commit named exactly `{REBUILD_COMMIT_MESSAGE}`.')
|
||||
body.extend([f' - [ ] `{file}`' for file in conflicted_files])
|
||||
body.append(' - [ ] Ensure another maintainer has reviewed the additional commits you added to this ' +
|
||||
'branch to resolve the merge conflicts.')
|
||||
body.append(' - [ ] Ensure the CHANGELOG displays the correct version and date.')
|
||||
@@ -136,6 +97,10 @@ def open_pr(
|
||||
body.append(f' - [ ] Check that there are not any unexpected commits being merged into the `{target_branch}` branch.')
|
||||
body.append(' - [ ] Ensure the docs team is aware of any documentation changes that need to be released.')
|
||||
|
||||
if not is_primary_release:
|
||||
body.append(' - [ ] Remove and re-add the "Rebuild" label to the PR to trigger just this workflow.')
|
||||
body.append(' - [ ] Wait for the "Rebuild" workflow to push a commit updating the distribution files.')
|
||||
|
||||
body.append(' - [ ] Mark the PR as ready for review to trigger the full set of PR checks.')
|
||||
body.append(' - [ ] Approve and merge this PR. Make sure `Create a merge commit` is selected rather than `Squash and merge` or `Rebase and merge`.')
|
||||
|
||||
@@ -144,11 +109,13 @@ def open_pr(
|
||||
body.append(' - [ ] Merge all backport PRs to older release branches, that will automatically be created once this PR is merged.')
|
||||
|
||||
title = f'Merge {source_branch} into {target_branch}'
|
||||
labels = ['Rebuild'] if not is_primary_release else []
|
||||
|
||||
# Create the pull request
|
||||
# PR checks won't be triggered on PRs created by Actions. Therefore mark the PR as draft so that
|
||||
# a maintainer can take the PR out of draft, thereby triggering the PR checks.
|
||||
pr = repo.create_pull(title=title, body='\n'.join(body), head=new_branch_name, base=target_branch, draft=True)
|
||||
pr.add_to_labels(*labels)
|
||||
print(f'Created PR #{str(pr.number)}')
|
||||
|
||||
# Assign the conductor
|
||||
@@ -303,6 +270,12 @@ def update_changelog(version):
|
||||
def main():
|
||||
parser = argparse.ArgumentParser('update-release-branch.py')
|
||||
|
||||
parser.add_argument(
|
||||
'--github-token',
|
||||
type=str,
|
||||
required=True,
|
||||
help='GitHub token, typically from GitHub Actions.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--repository-nwo',
|
||||
type=str,
|
||||
@@ -340,7 +313,7 @@ def main():
|
||||
target_branch = args.target_branch
|
||||
is_primary_release = args.is_primary_release
|
||||
|
||||
repo = Github(get_github_token()).get_repo(args.repository_nwo)
|
||||
repo = Github(args.github_token).get_repo(args.repository_nwo)
|
||||
|
||||
# the target branch will be of the form releases/vN, where N is the major version number
|
||||
target_branch_major_version = target_branch.strip('releases/v')
|
||||
@@ -407,9 +380,8 @@ def main():
|
||||
# releases.
|
||||
run_git('revert', vOlder_update_commits[0], '--no-edit')
|
||||
|
||||
# Also revert the "Rebuild" commit, whether created by this script or by the
|
||||
# `Rebuild Action` workflow.
|
||||
rebuild_commit = run_git('log', '--grep', f'^{REBUILD_COMMIT_MESSAGE}$', '--format=%H').split()[0]
|
||||
# Also revert the "Rebuild" commit created by Actions.
|
||||
rebuild_commit = run_git('log', '--grep', '^Rebuild$', '--format=%H').split()[0]
|
||||
print(f' Reverting {rebuild_commit}')
|
||||
run_git('revert', rebuild_commit, '--no-edit')
|
||||
|
||||
@@ -424,10 +396,9 @@ def main():
|
||||
run_git('add', '.')
|
||||
run_git('commit', '--no-edit')
|
||||
|
||||
# Migrate the package version number from a vLatest version number to a vOlder version number.
|
||||
# `package-lock.json` is updated as part of the subsequent rebuild step (see `rebuild_action`).
|
||||
# Migrate the package version number from a vLatest version number to a vOlder version number
|
||||
print(f'Setting version number to {version} in package.json')
|
||||
replace_version_package_json(get_current_version(), version)
|
||||
replace_version_package_json(get_current_version(), version) # We rely on the `Rebuild` workflow to update package-lock.json
|
||||
run_git('add', 'package.json')
|
||||
|
||||
# Migrate the changelog notes from vLatest version numbers to vOlder version numbers
|
||||
@@ -450,13 +421,6 @@ def main():
|
||||
run_git('add', 'CHANGELOG.md')
|
||||
run_git('commit', '-m', f'Update changelog for v{version}')
|
||||
|
||||
if not is_primary_release:
|
||||
if len(conflicted_files) == 0:
|
||||
print('Rebuilding the Action.')
|
||||
rebuild_action()
|
||||
else:
|
||||
print(f'Skipping automatic rebuild because the merge produced conflicts in {conflicted_files}.')
|
||||
|
||||
run_git('push', ORIGIN, new_branch_name)
|
||||
|
||||
# Open a PR to update the branch
|
||||
|
||||
+4
-4
@@ -49,6 +49,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.17.6
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.18.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.19.4
|
||||
- os: ubuntu-latest
|
||||
@@ -57,10 +61,6 @@ jobs:
|
||||
version: stable-v2.21.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.22.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.23.9
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.24.3
|
||||
- os: ubuntu-latest
|
||||
version: default
|
||||
- os: ubuntu-latest
|
||||
|
||||
+4
-4
@@ -49,6 +49,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.17.6
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.18.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.19.4
|
||||
- os: ubuntu-latest
|
||||
@@ -57,10 +61,6 @@ jobs:
|
||||
version: stable-v2.21.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.22.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.23.9
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.24.3
|
||||
- os: ubuntu-latest
|
||||
version: default
|
||||
- os: ubuntu-latest
|
||||
|
||||
+4
-4
@@ -49,6 +49,10 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.17.6
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.18.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.19.4
|
||||
- os: ubuntu-latest
|
||||
@@ -57,10 +61,6 @@ jobs:
|
||||
version: stable-v2.21.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.22.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.23.9
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.24.3
|
||||
- os: ubuntu-latest
|
||||
version: default
|
||||
- os: ubuntu-latest
|
||||
|
||||
+15
-15
@@ -59,41 +59,41 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.17.6
|
||||
- os: macos-latest
|
||||
version: stable-v2.17.6
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.18.4
|
||||
- os: macos-latest
|
||||
version: stable-v2.18.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.19.4
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: stable-v2.19.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.20.7
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: stable-v2.20.7
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.21.4
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: stable-v2.21.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.22.4
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: stable-v2.22.4
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.23.9
|
||||
- os: macos-latest-xlarge
|
||||
version: stable-v2.23.9
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.24.3
|
||||
- os: macos-latest-xlarge
|
||||
version: stable-v2.24.3
|
||||
- os: ubuntu-latest
|
||||
version: default
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: default
|
||||
- os: ubuntu-latest
|
||||
version: linked
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: linked
|
||||
- os: ubuntu-latest
|
||||
version: nightly-latest
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: nightly-latest
|
||||
name: Multi-language repository
|
||||
if: github.triggering_actor != 'dependabot[bot]'
|
||||
|
||||
+1
-1
@@ -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@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1.301.0
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
- name: Install Code Scanning integration
|
||||
|
||||
Generated
+1
-1
@@ -40,7 +40,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.19.4
|
||||
version: stable-v2.19.3
|
||||
- os: ubuntu-latest
|
||||
version: stable-v2.22.1
|
||||
- os: ubuntu-latest
|
||||
|
||||
Generated
+1
-1
@@ -39,7 +39,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-latest-xlarge
|
||||
- os: macos-latest
|
||||
version: nightly-latest
|
||||
name: Swift analysis using autobuild
|
||||
if: github.triggering_actor != 'dependabot[bot]'
|
||||
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04,ubuntu-24.04,windows-2022,windows-2025,macos-14-xlarge,macos-15-xlarge]
|
||||
os: [ubuntu-22.04,ubuntu-24.04,windows-2022,windows-2025,macos-14,macos-15]
|
||||
tools: ${{ fromJson(needs.check-codeql-versions.outputs.versions) }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
|
||||
@@ -6,6 +6,13 @@ env:
|
||||
# Diff informed queries add an additional query filter which is not yet
|
||||
# taken into account by these tests.
|
||||
CODEQL_ACTION_DIFF_INFORMED_QUERIES: false
|
||||
# Specify overlay enablement manually to ensure stability around the exclude-from-incremental
|
||||
# query filter. Here we only enable for the default code scanning suite.
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS: true
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_JAVASCRIPT: false
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_JAVASCRIPT: true
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_STATUS_CHECK: false
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_SKIP_RESOURCE_CHECKS: true
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -72,13 +79,33 @@ jobs:
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
|
||||
- name: Empty file
|
||||
# On PRs, overlay analysis may change the config that is passed to the CLI.
|
||||
# Therefore, we have two variants of the following test, one for PRs and one for other events.
|
||||
- name: Empty file (non-PR)
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: ./../action/.github/actions/check-codescanning-config
|
||||
with:
|
||||
expected-config-file-contents: "{}"
|
||||
languages: javascript
|
||||
tools: ${{ steps.prepare-test.outputs.tools-url }}
|
||||
|
||||
- name: Empty file (PR)
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: ./../action/.github/actions/check-codescanning-config
|
||||
with:
|
||||
expected-config-file-contents: |
|
||||
{
|
||||
"query-filters": [
|
||||
{
|
||||
"exclude": {
|
||||
"tags": "exclude-from-incremental"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
languages: javascript
|
||||
tools: ${{ steps.prepare-test.outputs.tools-url }}
|
||||
|
||||
- name: Packs from input
|
||||
if: success() || failure()
|
||||
uses: ./../action/.github/actions/check-codescanning-config
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
# Workflow runs on main, on a release branch, and that were triggered as part of a merge group have
|
||||
# already passed CI before being merged. Therefore if they fail, we should make sure that there
|
||||
# wasn't a transient failure by rerunning the failed jobs once before investigating further.
|
||||
name: Deflake
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
types: [completed]
|
||||
# Exclude workflows that have significant side effects, like publishing releases. It's OK to
|
||||
# retry CodeQL analysis.
|
||||
workflows:
|
||||
- Check Expected Release Files
|
||||
- Code-Scanning config CLI tests
|
||||
- CodeQL action
|
||||
- Manual Check - go
|
||||
- "PR Check - All-platform bundle"
|
||||
- "PR Check - Analysis kinds"
|
||||
- "PR Check - Analyze: 'ref' and 'sha' from inputs"
|
||||
- "PR Check - autobuild-action"
|
||||
- "PR Check - Autobuild direct tracing (custom working directory)"
|
||||
- "PR Check - Autobuild working directory"
|
||||
- "PR Check - Build mode autobuild"
|
||||
- "PR Check - Build mode manual"
|
||||
- "PR Check - Build mode none"
|
||||
- "PR Check - Build mode rollback"
|
||||
- "PR Check - Bundle: Caching checks"
|
||||
- "PR Check - Bundle: From nightly"
|
||||
- "PR Check - Bundle: From toolcache"
|
||||
- "PR Check - Bundle: Zstandard checks"
|
||||
- "PR Check - C/C\\+\\+: autoinstalling dependencies (Linux)"
|
||||
- "PR Check - C/C\\+\\+: autoinstalling dependencies is skipped (macOS)"
|
||||
- "PR Check - C/C\\+\\+: disabling autoinstalling dependencies (Linux)"
|
||||
- "PR Check - Clean up database cluster directory"
|
||||
- "PR Check - CodeQL Bundle All"
|
||||
- "PR Check - Config export"
|
||||
- "PR Check - Config input"
|
||||
- "PR Check - Custom source root"
|
||||
- "PR Check - Debug artifact upload"
|
||||
- "PR Check - Debug artifacts after failure"
|
||||
- "PR Check - Diagnostic export"
|
||||
- "PR Check - Export file baseline information"
|
||||
- "PR Check - Extractor ram and threads options test"
|
||||
- "PR Check - Go: Custom queries"
|
||||
- "PR Check - Go: diagnostic when Go is changed after init step"
|
||||
- "PR Check - Go: diagnostic when `file` is not installed"
|
||||
- "PR Check - Go: tracing with autobuilder step"
|
||||
- "PR Check - Go: tracing with custom build steps"
|
||||
- "PR Check - Go: tracing with legacy workflow"
|
||||
- "PR Check - Go: workaround for indirect tracing"
|
||||
- "PR Check - Job run UUID added to SARIF"
|
||||
- "PR Check - Language aliases"
|
||||
- "PR Check - Local CodeQL bundle"
|
||||
- "PR Check - Multi-language repository"
|
||||
- "PR Check - Overlay database init fallback"
|
||||
- "PR Check - Packaging: Action input"
|
||||
- "PR Check - Packaging: Config and input"
|
||||
- "PR Check - Packaging: Config and input passed to the CLI"
|
||||
- "PR Check - Packaging: Config file"
|
||||
- "PR Check - Packaging: Download using registries"
|
||||
- "PR Check - Proxy test"
|
||||
- "PR Check - Remote config file"
|
||||
- "PR Check - Resolve environment"
|
||||
- "PR Check - RuboCop multi-language"
|
||||
- "PR Check - Ruby analysis"
|
||||
- "PR Check - Rust analysis"
|
||||
- "PR Check - Split workflow"
|
||||
- "PR Check - Start proxy"
|
||||
- "PR Check - Submit SARIF after failure"
|
||||
- "PR Check - Swift analysis using a custom build command"
|
||||
- "PR Check - Swift analysis using autobuild"
|
||||
- "PR Check - Test different uses of `upload-sarif`"
|
||||
- "PR Check - Test unsetting environment variables"
|
||||
- "PR Check - Upload-sarif: ref and sha from inputs"
|
||||
- "PR Check - Use a custom `checkout_path`"
|
||||
- PR Checks
|
||||
- Query filters tests
|
||||
- Test that the workaround for python 3.12 on windows works
|
||||
|
||||
jobs:
|
||||
rerun-on-failure:
|
||||
name: Rerun failed jobs
|
||||
if: >-
|
||||
github.event.workflow_run.conclusion == 'failure' &&
|
||||
github.event.workflow_run.run_attempt == 1 &&
|
||||
(
|
||||
github.event.workflow_run.head_branch == 'main' ||
|
||||
startsWith(github.event.workflow_run.head_branch, 'releases/') ||
|
||||
github.event.workflow_run.event == 'merge_group'
|
||||
)
|
||||
runs-on: ubuntu-slim
|
||||
permissions:
|
||||
actions: write
|
||||
steps:
|
||||
- name: Rerun failed jobs in ${{ github.event.workflow_run.name }}
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
RUN_ID: ${{ github.event.workflow_run.id }}
|
||||
RUN_NAME: ${{ github.event.workflow_run.name }}
|
||||
RUN_URL: ${{ github.event.workflow_run.html_url }}
|
||||
run: |
|
||||
echo "Rerunning failed jobs for workflow run ${RUN_ID}"
|
||||
gh run rerun "${RUN_ID}" --failed
|
||||
echo "### Reran failed jobs :recycle:" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "Workflow: [${RUN_NAME}](${RUN_URL})" >> "$GITHUB_STEP_SUMMARY"
|
||||
@@ -48,9 +48,6 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0 # ensure we have all tags and can push commits
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
cache: 'npm'
|
||||
- uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
@@ -134,7 +131,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Generate token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@v3.1.1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||
|
||||
@@ -105,10 +105,10 @@ jobs:
|
||||
run: npx tsx --test
|
||||
|
||||
check-node-version:
|
||||
if: github.triggering_actor != 'dependabot[bot]' && startsWith(github.head_ref, 'backport-')
|
||||
name: Check Action Node versions for Backport
|
||||
if: github.triggering_actor != 'dependabot[bot]'
|
||||
name: Check Action Node versions
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
timeout-minutes: 45
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
|
||||
@@ -116,40 +116,31 @@ jobs:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- uses: actions/checkout@v6
|
||||
- id: head-version
|
||||
name: Determine Node version for HEAD
|
||||
name: Verify all Actions use the same Node version
|
||||
run: |
|
||||
if [[ ! -f ".nvmrc" ]]; then
|
||||
echo "::error::Cannot find .nvmrc in the HEAD commit."
|
||||
NODE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
|
||||
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."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
NODE_VERSION=$(cat .nvmrc)
|
||||
echo "NODE_VERSION: ${NODE_VERSION}"
|
||||
echo "node_version=${NODE_VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
- id: checkout-base
|
||||
name: 'Backport: Check out base ref'
|
||||
if: ${{ startsWith(github.head_ref, 'backport-') }}
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ env.BASE_REF }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: 'Backport: Verify Node versions unchanged'
|
||||
if: steps.checkout-base.outcome == 'success'
|
||||
env:
|
||||
HEAD_VERSION: ${{ steps.head-version.outputs.node_version }}
|
||||
run: |
|
||||
if [[ ! -f ".nvmrc" ]]; then
|
||||
echo "::error::Cannot find .nvmrc in the base commit."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BASE_VERSION=$(cat .nvmrc)
|
||||
BASE_VERSION=$(find . -name "action.yml" -exec yq -e '.runs.using' {} \; | grep node | sort | uniq)
|
||||
echo "HEAD_VERSION: ${HEAD_VERSION}"
|
||||
echo "BASE_VERSION: ${BASE_VERSION}"
|
||||
if [[ "$BASE_VERSION" != "$HEAD_VERSION" ]]; then
|
||||
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
|
||||
- name: Generate token
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@v3.1.1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||
|
||||
@@ -64,12 +64,11 @@ jobs:
|
||||
|
||||
- name: Update current release branch
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo SOURCE_BRANCH=${REF_NAME}
|
||||
echo TARGET_BRANCH=releases/${MAJOR_VERSION}
|
||||
python .github/update-release-branch.py \
|
||||
--github-token ${{ secrets.GITHUB_TOKEN }} \
|
||||
--repository-nwo ${{ github.repository }} \
|
||||
--source-branch '${{ env.REF_NAME }}' \
|
||||
--target-branch 'releases/${{ env.MAJOR_VERSION }}' \
|
||||
@@ -94,7 +93,7 @@ jobs:
|
||||
pull-requests: write # needed to create pull request
|
||||
steps:
|
||||
- name: Generate token
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
uses: actions/create-github-app-token@v3.1.1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||
@@ -108,12 +107,11 @@ jobs:
|
||||
- uses: ./.github/actions/release-initialise
|
||||
|
||||
- name: Update older release branch
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
echo SOURCE_BRANCH=${SOURCE_BRANCH}
|
||||
echo TARGET_BRANCH=${TARGET_BRANCH}
|
||||
python .github/update-release-branch.py \
|
||||
--github-token ${{ secrets.GITHUB_TOKEN }} \
|
||||
--repository-nwo ${{ github.repository }} \
|
||||
--source-branch ${SOURCE_BRANCH} \
|
||||
--target-branch ${TARGET_BRANCH} \
|
||||
|
||||
Vendored
+1
-1
@@ -19,7 +19,7 @@
|
||||
"scope": "javascript, typescript",
|
||||
"prefix": "testMacro",
|
||||
"body": [
|
||||
"const ${1:nameMacro} = makeMacro({",
|
||||
"const ${1:nameMacro} = test.macro({",
|
||||
" exec: async (t: ExecutionContext<unknown>) => {},",
|
||||
"",
|
||||
" title: (providedTitle = \"\") => `${2:common title} - \\${providedTitle}`,",
|
||||
|
||||
+1
-21
@@ -4,27 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||
|
||||
## [UNRELEASED]
|
||||
|
||||
- _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)
|
||||
|
||||
## 4.35.5 - 15 May 2026
|
||||
|
||||
- We have improved how the JavaScript bundles for the CodeQL Action are generated to avoid duplication across bundles and reduce the size of the repository by around 70%. This should have no effect on the runtime behaviour of the CodeQL Action. [#3899](https://github.com/github/codeql-action/pull/3899)
|
||||
- For performance and accuracy reasons, [improved incremental analysis](https://github.com/github/roadmap/issues/1158) will now only be enabled on a pull request when diff-informed analysis is also enabled for that run. If diff-informed analysis is unavailable (for example, because the PR diff ranges could not be computed), the action will fall back to a full analysis. [#3791](https://github.com/github/codeql-action/pull/3791)
|
||||
- If multiple inputs are provided for the GitHub-internal `analysis-kinds` input, only `code-scanning` will be enabled. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892)
|
||||
- Added an experimental change which, when running a Code Scanning analysis for a PR with [improved incremental analysis](https://github.com/github/roadmap/issues/1158) enabled, prefers CodeQL CLI versions that have a cached overlay-base database for the configured languages. This speeds up analysis for a repository when there is not yet a cached overlay-base database for the latest CLI version. We expect to roll this change out to everyone in May. [#3880](https://github.com/github/codeql-action/pull/3880)
|
||||
|
||||
## 4.35.4 - 07 May 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.25.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4). [#3881](https://github.com/github/codeql-action/pull/3881)
|
||||
|
||||
## 4.35.3 - 01 May 2026
|
||||
|
||||
- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. [#3837](https://github.com/github/codeql-action/pull/3837)
|
||||
- Configurations for private registries that use Cloudsmith or GCP OIDC are now accepted. [#3850](https://github.com/github/codeql-action/pull/3850)
|
||||
- Best-effort connection tests for private registries now use `GET` requests instead of `HEAD` for better compatibility with various registry implementations. For NuGet feeds, the test is now always performed against the service index. [#3853](https://github.com/github/codeql-action/pull/3853)
|
||||
- Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. [#3852](https://github.com/github/codeql-action/pull/3852)
|
||||
- Update default CodeQL bundle version to [2.25.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3). [#3865](https://github.com/github/codeql-action/pull/3865)
|
||||
- Organizations can now create a custom repository property with the name `github-codeql-tools` to control the CodeQL CLI tools input at the repository level. When this property is set to a valid tools input value (such as `"toolcache"`, `"latest"`, or a specific version), it will override the default tools configuration for that repository. This allows organization administrators to standardize CodeQL CLI versions across repositories or enable toolcache usage on repositories where it would otherwise be restricted. For more information on creating custom repository properties, 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).
|
||||
|
||||
## 4.35.2 - 15 Apr 2026
|
||||
|
||||
|
||||
+1
-1
@@ -71,7 +71,7 @@ Once the mergeback and backport pull request have been merged, the release is co
|
||||
|
||||
Since the `codeql-action` runs most of its testing through individual Actions workflows, there are over two hundred required jobs that need to pass in order for a PR to turn green. It would be too tedious to maintain that list manually. You can regenerate the set of required checks automatically by running the [sync-checks.ts](pr-checks/sync-checks.ts) script:
|
||||
|
||||
- At a minimum, you must provide a token with permissions to update branch protection rules. For example, `gh auth token | pr-checks/sync-checks.ts --token-stdin` uses the same token that `gh` uses. You can also set the `GH_TOKEN` or `GITHUB_TOKEN` environment variable. If no token is provided or the token has insufficient permissions, the script will fail.
|
||||
- At a minimum, you must provide an argument for the `--token` input. For example, `--token "$(gh auth token)"` to use the same token that `gh` uses. If no token is provided or the token has insufficient permissions, the script will fail.
|
||||
- By default, the script performs a dry run and outputs information about the changes it would make to the branch protection rules. To actually apply the changes, specify the `--apply` flag.
|
||||
- If you run the script without any other arguments, it will retrieve the set of workflows that ran for the latest commit on `main`.
|
||||
- You can specify a different git ref with the `--ref` input. You will likely want to use this if you have a PR that removes or adds PR checks. For example, `--ref "some/branch/name"` to use the HEAD of the `some/branch/name` branch.
|
||||
|
||||
@@ -72,12 +72,13 @@ We typically release new minor versions of the CodeQL Action and Bundle when a n
|
||||
|
||||
| Minimum CodeQL Action | Minimum CodeQL Bundle Version | GitHub Environment | Notes |
|
||||
|-----------------------|-------------------------------|--------------------|-------|
|
||||
| `v4.33.0` | `2.24.3` | Enterprise Server 3.21 | |
|
||||
| `v4.31.10` | `2.23.9` | Enterprise Server 3.20 | |
|
||||
| `v3.29.11` | `2.22.4` | Enterprise Server 3.19 | |
|
||||
| `v3.28.21` | `2.21.3` | Enterprise Server 3.18 | |
|
||||
| `v3.28.12` | `2.20.7` | Enterprise Server 3.17 | |
|
||||
| `v3.28.6` | `2.20.3` | Enterprise Server 3.16 | |
|
||||
| `v3.28.6` | `2.20.3` | Enterprise Server 3.15 | |
|
||||
| `v3.28.6` | `2.20.3` | Enterprise Server 3.14 | |
|
||||
|
||||
See the full list of GHES release and deprecation dates at [GitHub Enterprise Server releases](https://docs.github.com/en/enterprise-server/admin/all-releases#releases-of-github-enterprise-server).
|
||||
|
||||
|
||||
+2
-2
@@ -95,5 +95,5 @@ outputs:
|
||||
description: The ID of the uploaded SARIF file.
|
||||
runs:
|
||||
using: node24
|
||||
main: "../lib/analyze-entry.js"
|
||||
post: "../lib/analyze-post-entry.js"
|
||||
main: "../lib/analyze-action.js"
|
||||
post: "../lib/analyze-action-post.js"
|
||||
|
||||
@@ -16,4 +16,4 @@ inputs:
|
||||
required: false
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/autobuild-entry.js'
|
||||
main: '../lib/autobuild-action.js'
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { copyFile, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { basename, dirname, join } from "node:path";
|
||||
import { copyFile, rm, writeFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import * as esbuild from "esbuild";
|
||||
import { globSync } from "glob";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
import pkg from "./package.json" with { type: "json" };
|
||||
|
||||
@@ -28,70 +27,6 @@ const cleanPlugin = {
|
||||
},
|
||||
};
|
||||
|
||||
/** A plugin that checks that the Node versions in all `action.yml` files are the same. */
|
||||
const checkNodeVersionsPlugin = {
|
||||
name: "check-node-versions",
|
||||
setup(build) {
|
||||
build.onStart(async () => {
|
||||
// Find all the `action.yml` files. We don't care about the stub in the repository root,
|
||||
// since that is a `composite` action.
|
||||
const actionSpecifications = globSync("*/action.yml");
|
||||
|
||||
// Track the Node versions we find for each file.
|
||||
const nodeVersions = {};
|
||||
|
||||
// We will store the first Node version we find and use it to compare against the others.
|
||||
// If there's any disagreement, we set `versionMismatch` to `true` and throw an error
|
||||
// that includes all the discovered Node versions at the end.
|
||||
let nodeVersion = undefined;
|
||||
let versionMismatch = false;
|
||||
|
||||
for (const actionSpecification of actionSpecifications) {
|
||||
// Read the contents of the action.yml file.
|
||||
const contents = await readFile(actionSpecification, "utf-8");
|
||||
const specification = yaml.load(contents);
|
||||
|
||||
// Find the `runs.using` value in the specification.
|
||||
const using = specification.runs.using;
|
||||
if (using === undefined || using === null) {
|
||||
throw new Error(
|
||||
`Couldn't find 'runs.using' in ${actionSpecification}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof using !== "string" || !using.startsWith("node")) {
|
||||
throw new Error(
|
||||
`Expected 'runs.using' to be a string starting with 'node' in ${actionSpecification}`,
|
||||
);
|
||||
}
|
||||
|
||||
if (nodeVersion === undefined) {
|
||||
// First one we found: set it as the baseline.
|
||||
nodeVersion = using;
|
||||
} else if (nodeVersion !== using) {
|
||||
// Disagreement: set `versionMismatch` to indicate that we should throw an error later.
|
||||
versionMismatch = true;
|
||||
}
|
||||
nodeVersions[actionSpecification] = using;
|
||||
}
|
||||
|
||||
// Throw an error if there was a version mismatch.
|
||||
if (versionMismatch) {
|
||||
throw new Error(
|
||||
`More than one node version used in 'action.yml' files: ${JSON.stringify(nodeVersions)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Write the node version to `.nvmrc`.
|
||||
await writeFile(
|
||||
join(__dirname, ".nvmrc"),
|
||||
nodeVersion.substring("node".length) + "\n",
|
||||
"utf-8",
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy defaults.json to the output directory since other projects depend on it.
|
||||
*
|
||||
@@ -127,159 +62,18 @@ const onEndPlugin = {
|
||||
},
|
||||
};
|
||||
|
||||
/** The name of the virtual `entry-points` module. */
|
||||
const SHARED_ENTRYPOINT = "entry-points";
|
||||
|
||||
/** The property name under which `upload-lib`'s namespace is exposed in `entry-points`. */
|
||||
const UPLOAD_LIB_EXPORT = "uploadLib";
|
||||
|
||||
/** The relative source path of the `upload-lib` module that we re-export from `entry-points`. */
|
||||
const UPLOAD_LIB_SRC = "./src/upload-lib";
|
||||
|
||||
/**
|
||||
* This plugin finds all source files that contain Action entry points. It then generates the
|
||||
* virtual `entry-points` module which imports all identified files, and re-exports their
|
||||
* `runWrapper` functions with suitable aliases.
|
||||
*
|
||||
* The virtual module additionally re-exports `upload-lib` under the `uploadLib` namespace so that
|
||||
* external consumers can access it via the small `lib/upload-lib.js` stub emitted below.
|
||||
*
|
||||
* A tiny stub file is emitted for each Action entrypoint, and one for `upload-lib`. Each stub
|
||||
* imports the shared bundle and calls/re-exports from the respective entry point.
|
||||
*
|
||||
* @type {esbuild.Plugin}
|
||||
*/
|
||||
const entryPointsPlugin = {
|
||||
name: "entry-points",
|
||||
setup(build) {
|
||||
const namespace = "actions";
|
||||
const actions = [];
|
||||
|
||||
const toPascal = (s) =>
|
||||
s.replace(/(^|-)([a-z0-9])/gi, (_, __, c) => c.toUpperCase());
|
||||
|
||||
// Find the source files containing Action entry points.
|
||||
build.onStart(() => {
|
||||
const actionFiles = globSync("src/*-action{,-post}.ts");
|
||||
for (const actionFile of actionFiles) {
|
||||
const match = basename(actionFile).match(/(.*)-action(-post)?/);
|
||||
|
||||
if (match.length < 2) {
|
||||
throw new Error(`'${actionFile}' didn't match expected pattern.`);
|
||||
}
|
||||
|
||||
const actionName = match[1];
|
||||
const isPost = match[2] !== undefined;
|
||||
|
||||
actions.push({
|
||||
path: actionFile,
|
||||
name: actionName,
|
||||
isPost,
|
||||
pascalCaseName: `${toPascal(actionName)}${isPost ? "Post" : ""}Action`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Resolve the virtual `entry-points` file and set the corresponding namespace.
|
||||
// Ideally, we'd `RegExp.escape` the entrypoint here, but that API isn't supported in Node 20.
|
||||
// Since we're dealing with a hardcoded string, this isn't too much of a problem.
|
||||
build.onResolve({ filter: new RegExp(`^${SHARED_ENTRYPOINT}$`) }, () => {
|
||||
return { path: SHARED_ENTRYPOINT, namespace };
|
||||
});
|
||||
|
||||
// Generate the virtual `entry-points` file based on the Actions we discovered.
|
||||
// Restrict using the namespace. The path filter does not need to discriminate any further.
|
||||
build.onLoad({ filter: /.*/, namespace }, async () => {
|
||||
const wrapperTemplatePath = "entry-wrapper.js.tpl";
|
||||
const wrapperTemplate = await readFile(
|
||||
join(SRC_DIR, wrapperTemplatePath),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const actionsSorted = actions.sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
);
|
||||
const imports = actionsSorted
|
||||
.map(
|
||||
(action) =>
|
||||
`import * as ${action.pascalCaseName} from "./src/${basename(action.path)}";`,
|
||||
)
|
||||
.join("\n");
|
||||
const wrappers = actionsSorted
|
||||
.map((action) =>
|
||||
wrapperTemplate.replaceAll("__ACTION__", action.pascalCaseName),
|
||||
)
|
||||
.join("\n\n");
|
||||
|
||||
// Also re-export the `upload-lib` namespace so that external consumers can reach it
|
||||
// via the `lib/upload-lib.js` stub without us having to bundle a second copy.
|
||||
const uploadLibReExport = `export * as ${UPLOAD_LIB_EXPORT} from "${UPLOAD_LIB_SRC}";`;
|
||||
|
||||
return {
|
||||
contents: `"use strict";\n${imports}\n\n${uploadLibReExport}\n\n${wrappers}\n`,
|
||||
resolveDir: ".",
|
||||
loader: "ts",
|
||||
};
|
||||
});
|
||||
|
||||
// Emit entry point stubs for each Action using the entry template.
|
||||
build.onEnd(async () => {
|
||||
const makeHeader = (templatePath, sourceFile) =>
|
||||
`// Automatically generated from '${templatePath}' for 'src/${basename(sourceFile)}'.\n\n`;
|
||||
|
||||
// Read the entry point template.
|
||||
const actionTemplatePath = "action-entry.js.tpl";
|
||||
const actionTemplate = await readFile(
|
||||
join(SRC_DIR, actionTemplatePath),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
// Write entry point stubs for each Action.
|
||||
for (const action of actions) {
|
||||
await writeFile(
|
||||
join(
|
||||
OUT_DIR,
|
||||
`${action.name}${action.isPost ? "-post" : ""}-entry.js`,
|
||||
),
|
||||
makeHeader(actionTemplatePath, action.path) +
|
||||
actionTemplate.replaceAll("__ACTION__", action.pascalCaseName),
|
||||
);
|
||||
}
|
||||
|
||||
// Write a small stub for `upload-lib` that re-exports it from the shared bundle.
|
||||
// External callers (e.g. internal testing environments) `require("./lib/upload-lib")`
|
||||
// and expect the same shape as before, so we expose the namespace as `module.exports`.
|
||||
const uploadLibStubTemplatePath = "upload-lib-stub.js.tpl";
|
||||
const uploadLibStubTemplate = await readFile(
|
||||
join(SRC_DIR, uploadLibStubTemplatePath),
|
||||
"utf-8",
|
||||
);
|
||||
await writeFile(
|
||||
join(OUT_DIR, "upload-lib.js"),
|
||||
makeHeader(uploadLibStubTemplatePath, `${UPLOAD_LIB_SRC}.ts`) +
|
||||
uploadLibStubTemplate.replaceAll(
|
||||
"__UPLOAD_LIB_EXPORT__",
|
||||
UPLOAD_LIB_EXPORT,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const context = await esbuild.context({
|
||||
entryPoints: [{ in: SHARED_ENTRYPOINT, out: SHARED_ENTRYPOINT }],
|
||||
// Include upload-lib.ts as an entry point for use in testing environments.
|
||||
entryPoints: globSync([
|
||||
`${SRC_DIR}/*-action.ts`,
|
||||
`${SRC_DIR}/*-action-post.ts`,
|
||||
"src/upload-lib.ts",
|
||||
]),
|
||||
bundle: true,
|
||||
format: "cjs",
|
||||
outdir: OUT_DIR,
|
||||
platform: "node",
|
||||
external: ["./entry-points"],
|
||||
plugins: [
|
||||
cleanPlugin,
|
||||
checkNodeVersionsPlugin,
|
||||
copyDefaultsPlugin,
|
||||
entryPointsPlugin,
|
||||
onEndPlugin,
|
||||
],
|
||||
plugins: [cleanPlugin, copyDefaultsPlugin, onEndPlugin],
|
||||
target: ["node20"],
|
||||
define: {
|
||||
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),
|
||||
|
||||
+2
-2
@@ -171,5 +171,5 @@ outputs:
|
||||
description: The version of the CodeQL binary used for analysis
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/init-entry.js'
|
||||
post: '../lib/init-post-entry.js'
|
||||
main: '../lib/init-action.js'
|
||||
post: '../lib/init-action-post.js'
|
||||
|
||||
Generated
+163860
File diff suppressed because one or more lines are too long
Generated
+113783
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/analyze-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runAnalyzeAction)();
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/analyze-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runAnalyzePostAction)();
|
||||
Generated
+106162
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/autobuild-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runAutobuildAction)();
|
||||
+4
-4
@@ -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.2",
|
||||
"cliVersion": "2.25.2",
|
||||
"priorBundleVersion": "codeql-bundle-v2.25.1",
|
||||
"priorCliVersion": "2.25.1"
|
||||
}
|
||||
|
||||
+81173
-71158
File diff suppressed because one or more lines are too long
Generated
+110793
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/init-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runInitAction)();
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/init-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runInitPostAction)();
|
||||
Generated
+105721
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/resolve-environment-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runResolveEnvironmentAction)();
|
||||
Generated
+107425
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/setup-codeql-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runSetupCodeqlAction)();
|
||||
Generated
+162672
File diff suppressed because one or more lines are too long
Generated
+122883
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/start-proxy-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runStartProxyAction)();
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/start-proxy-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runStartProxyPostAction)();
|
||||
Generated
+111438
-3
File diff suppressed because one or more lines are too long
Generated
+162697
File diff suppressed because one or more lines are too long
Generated
+112125
File diff suppressed because one or more lines are too long
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/upload-sarif-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runUploadSarifAction)();
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/upload-sarif-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runUploadSarifPostAction)();
|
||||
Generated
+542
-419
File diff suppressed because it is too large
Load Diff
+14
-15
@@ -1,19 +1,18 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.36.0",
|
||||
"version": "4.35.3",
|
||||
"private": true,
|
||||
"description": "CodeQL action",
|
||||
"scripts": {
|
||||
"_build_comment": "echo 'Run the full build so we typecheck the project and can reuse the transpiled files in npm test'",
|
||||
"build": "./scripts/check-node-modules.sh && npm run transpile && node build.mjs",
|
||||
"build": "./scripts/check-node-modules.sh && npm run transpile && node build.mjs && npx tsx ./pr-checks/bundle-metadata.ts",
|
||||
"lint": "eslint --report-unused-disable-directives --max-warnings=0 .",
|
||||
"lint-ci": "SARIF_ESLINT_IGNORE_SUPPRESSED=true eslint --report-unused-disable-directives --max-warnings=0 . --format @microsoft/eslint-formatter-sarif --output-file=eslint.sarif",
|
||||
"lint-fix": "eslint --report-unused-disable-directives --max-warnings=0 . --fix",
|
||||
"ava": "npm run transpile && ava --verbose",
|
||||
"test": "npm run ava -- src/",
|
||||
"test-debug": "npm run test -- --timeout=20m",
|
||||
"transpile": "tsc --build --verbose tsconfig.json",
|
||||
"update-pr-checks": "./pr-checks/sync.sh"
|
||||
"transpile": "tsc --build --verbose tsconfig.json"
|
||||
},
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
@@ -41,7 +40,7 @@
|
||||
"long": "^5.3.2",
|
||||
"node-forge": "^1.4.0",
|
||||
"semver": "^7.7.4",
|
||||
"uuid": "^14.0.0"
|
||||
"uuid": "^13.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ava/typescript": "6.0.0",
|
||||
@@ -51,25 +50,25 @@
|
||||
"@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.9",
|
||||
"@types/node-forge": "^1.3.14",
|
||||
"@types/sarif": "^2.1.7",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/sinon": "^21.0.1",
|
||||
"ava": "^6.4.1",
|
||||
"ava": "^7.0.0",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-import-resolver-typescript": "^3.8.7",
|
||||
"eslint-plugin-github": "^6.0.0",
|
||||
"eslint-plugin-import-x": "^4.16.2",
|
||||
"eslint-plugin-jsdoc": "^62.9.0",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^11.1.0",
|
||||
"globals": "^17.6.0",
|
||||
"globals": "^17.4.0",
|
||||
"nock": "^14.0.12",
|
||||
"sinon": "^22.0.0",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.59.2"
|
||||
"sinon": "^21.0.3",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript-eslint": "^8.58.1"
|
||||
},
|
||||
"overrides": {
|
||||
"@actions/tool-cache": {
|
||||
@@ -90,7 +89,7 @@
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"semver": ">=6.3.1"
|
||||
},
|
||||
"glob": "^11.1.0",
|
||||
"undici": "^6.24.0"
|
||||
"brace-expansion@2.0.1": "2.0.2",
|
||||
"glob": "^11.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ name: "Multi-language repository"
|
||||
description: "An end-to-end integration test of a multi-language repository using automatic language detection"
|
||||
operatingSystems:
|
||||
- ubuntu
|
||||
- os: macos
|
||||
runner-image: macos-latest-xlarge
|
||||
- macos
|
||||
env:
|
||||
CODEQL_ACTION_RESOLVE_SUPPORTED_LANGUAGES_USING_CLI: true
|
||||
installGo: true
|
||||
|
||||
@@ -5,7 +5,7 @@ versions:
|
||||
- default
|
||||
steps:
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
|
||||
uses: ruby/setup-ruby@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1.301.0
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
- name: Install Code Scanning integration
|
||||
|
||||
@@ -2,7 +2,7 @@ name: "Rust analysis"
|
||||
description: "Tests creation of a Rust database"
|
||||
versions:
|
||||
# experimental rust support introduced, requires action to set `CODEQL_ENABLE_EXPERIMENTAL_FEATURES`
|
||||
- stable-v2.19.4
|
||||
- stable-v2.19.3
|
||||
# first public preview version
|
||||
- stable-v2.22.1
|
||||
- linked
|
||||
|
||||
@@ -3,8 +3,7 @@ description: "Tests creation of a Swift database using autobuild"
|
||||
versions:
|
||||
- nightly-latest
|
||||
operatingSystems:
|
||||
- os: macos
|
||||
runner-image: macos-latest-xlarge
|
||||
- macos
|
||||
steps:
|
||||
- uses: ./../action/init
|
||||
id: init
|
||||
|
||||
@@ -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.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.19.39",
|
||||
"@types/node": "^20.19.9",
|
||||
"tsx": "^4.21.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,7 @@ Tests for the sync-checks.ts script
|
||||
import * as assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
|
||||
import {
|
||||
CheckInfo,
|
||||
Exclusions,
|
||||
Options,
|
||||
removeExcluded,
|
||||
resolveToken,
|
||||
} from "./sync-checks";
|
||||
import { CheckInfo, Exclusions, Options, removeExcluded } from "./sync-checks";
|
||||
|
||||
const defaultOptions: Options = {
|
||||
apply: false,
|
||||
@@ -64,46 +58,3 @@ describe("removeExcluded", async () => {
|
||||
assert.deepEqual(retained, expectedExactMatches);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveToken", async () => {
|
||||
await it("reads the token from standard input", async () => {
|
||||
const token = await resolveToken(
|
||||
{ tokenStdin: true },
|
||||
{ env: {}, readStdin: async () => " stdin-token\n" },
|
||||
);
|
||||
assert.equal(token, "stdin-token");
|
||||
});
|
||||
|
||||
await it("reads the token from the GH_TOKEN environment variable", async () => {
|
||||
const token = await resolveToken(
|
||||
{},
|
||||
{ env: { GH_TOKEN: "env-token" }, readStdin: async () => "" },
|
||||
);
|
||||
assert.equal(token, "env-token");
|
||||
});
|
||||
|
||||
await it("reads the token from the GITHUB_TOKEN environment variable", async () => {
|
||||
const token = await resolveToken(
|
||||
{},
|
||||
{ env: { GITHUB_TOKEN: "env-token" }, readStdin: async () => "" },
|
||||
);
|
||||
assert.equal(token, "env-token");
|
||||
});
|
||||
|
||||
await it("rejects an empty standard input token", async () => {
|
||||
await assert.rejects(
|
||||
resolveToken(
|
||||
{ tokenStdin: true },
|
||||
{ env: {}, readStdin: async () => "\n" },
|
||||
),
|
||||
/No token received on standard input/,
|
||||
);
|
||||
});
|
||||
|
||||
await it("rejects missing token sources", async () => {
|
||||
await assert.rejects(
|
||||
resolveToken({}, { env: {}, readStdin: async () => "" }),
|
||||
/Missing authentication token/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
|
||||
/** Represents the command-line options. */
|
||||
export interface Options {
|
||||
/** Whether to read the GitHub API token from standard input. */
|
||||
tokenStdin?: boolean;
|
||||
/** The token to use to authenticate to the GitHub API. */
|
||||
token?: string;
|
||||
/** The git ref to use the checks for. */
|
||||
ref?: string;
|
||||
/** Whether to actually apply the changes or not. */
|
||||
@@ -31,65 +31,6 @@ const codeqlActionRepo = {
|
||||
repo: "codeql-action",
|
||||
};
|
||||
|
||||
/** Environment variables to check for a GitHub API token. */
|
||||
const TOKEN_ENVIRONMENT_VARIABLES = ["GH_TOKEN", "GITHUB_TOKEN"];
|
||||
|
||||
/** Represents the sources from which we can retrieve the GitHub API token. */
|
||||
interface TokenSource {
|
||||
/** Environment variables to inspect. */
|
||||
env: NodeJS.ProcessEnv;
|
||||
/** Reads a token from standard input. */
|
||||
readStdin: () => Promise<string>;
|
||||
}
|
||||
|
||||
/** Reads the GitHub API token from standard input. */
|
||||
async function readTokenFromStdin(): Promise<string> {
|
||||
let token = "";
|
||||
process.stdin.setEncoding("utf8");
|
||||
for await (const chunk of process.stdin) {
|
||||
token += chunk;
|
||||
}
|
||||
return token.trim();
|
||||
}
|
||||
|
||||
/** Gets a GitHub API token from one of the supported environment variables. */
|
||||
function getTokenFromEnvironment(env: NodeJS.ProcessEnv): string | undefined {
|
||||
for (const variableName of TOKEN_ENVIRONMENT_VARIABLES) {
|
||||
const token = env[variableName]?.trim();
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Gets the token to use to authenticate to the GitHub API. */
|
||||
export async function resolveToken(
|
||||
options: Pick<Options, "tokenStdin">,
|
||||
tokenSource: TokenSource = {
|
||||
env: process.env,
|
||||
readStdin: readTokenFromStdin,
|
||||
},
|
||||
): Promise<string> {
|
||||
if (options.tokenStdin) {
|
||||
const token = (await tokenSource.readStdin()).trim();
|
||||
if (token.length === 0) {
|
||||
throw new Error("No token received on standard input.");
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
const environmentToken = getTokenFromEnvironment(tokenSource.env);
|
||||
if (environmentToken !== undefined) {
|
||||
return environmentToken;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
"Missing authentication token. Set GH_TOKEN/GITHUB_TOKEN or pipe a token " +
|
||||
"to --token-stdin.",
|
||||
);
|
||||
}
|
||||
|
||||
/** Represents a configuration of which checks should not be set up as required checks. */
|
||||
export interface Exclusions {
|
||||
/** A list of strings that, if contained in a check name, are excluded. */
|
||||
@@ -264,10 +205,9 @@ async function updateBranch(
|
||||
async function main(): Promise<void> {
|
||||
const { values: options } = parseArgs({
|
||||
options: {
|
||||
// Read the token to use to authenticate to the API from standard input.
|
||||
"token-stdin": {
|
||||
type: "boolean",
|
||||
default: false,
|
||||
// The token to use to authenticate to the API.
|
||||
token: {
|
||||
type: "string",
|
||||
},
|
||||
// The git ref for which to retrieve the check runs.
|
||||
ref: {
|
||||
@@ -288,16 +228,16 @@ async function main(): Promise<void> {
|
||||
strict: true,
|
||||
});
|
||||
|
||||
const token = await resolveToken({
|
||||
tokenStdin: options["token-stdin"],
|
||||
});
|
||||
if (options.token === undefined) {
|
||||
throw new Error("Missing --token");
|
||||
}
|
||||
|
||||
console.info(
|
||||
`Oldest supported major version is: ${OLDEST_SUPPORTED_MAJOR_VERSION}`,
|
||||
);
|
||||
|
||||
// Initialise the API client.
|
||||
const client = getApiClient(token);
|
||||
const client = getApiClient(options.token);
|
||||
|
||||
// Find the check runs for the specified `ref` that we will later set as the required checks
|
||||
// for the main and release branches.
|
||||
|
||||
+11
-42
@@ -28,24 +28,6 @@ interface WorkflowInput {
|
||||
/** A partial mapping from known input names to input definitions. */
|
||||
type WorkflowInputs = Partial<Record<KnownInputName, WorkflowInput>>;
|
||||
|
||||
/** An operating system identifier. */
|
||||
type OperatingSystemIdentifier = "ubuntu" | "macos" | "windows";
|
||||
|
||||
/**
|
||||
* Represents an operating system matrix entry for a generated PR check workflow.
|
||||
*
|
||||
* Either a string containing the OS identifier or an object containing the OS identifier and an
|
||||
* optional runner image label.
|
||||
*/
|
||||
type OperatingSystem =
|
||||
| OperatingSystemIdentifier
|
||||
| {
|
||||
/** OS identifier. */
|
||||
os: OperatingSystemIdentifier;
|
||||
/** Optional runner image label. */
|
||||
"runner-image"?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents PR check specifications.
|
||||
*/
|
||||
@@ -54,8 +36,8 @@ interface Specification extends JobSpecification {
|
||||
inputs?: Record<string, WorkflowInput>;
|
||||
/** CodeQL bundle versions to test against. Defaults to `DEFAULT_TEST_VERSIONS`. */
|
||||
versions?: string[];
|
||||
/** Operating system prefixes, either as strings or with explicit runner image labels. */
|
||||
operatingSystems?: OperatingSystem[];
|
||||
/** Operating system prefixes used to select runner images (e.g. `["ubuntu", "macos"]`). */
|
||||
operatingSystems?: string[];
|
||||
/** Per-OS version overrides. If specified for an OS, only those versions are tested on that OS. */
|
||||
osCodeQlVersions?: Record<string, string[]>;
|
||||
/** Whether to use the all-platform CodeQL bundle. */
|
||||
@@ -115,6 +97,10 @@ type LanguageSetups = Partial<Record<BuiltInLanguage, LanguageSetup>>;
|
||||
// The default set of CodeQL Bundle versions to use for the PR checks.
|
||||
const defaultTestVersions = [
|
||||
// The oldest supported CodeQL version. If bumping, update `CODEQL_MINIMUM_VERSION` in `codeql.ts`
|
||||
"stable-v2.17.6",
|
||||
// The last CodeQL release in the 2.18 series.
|
||||
"stable-v2.18.4",
|
||||
// The last CodeQL release in the 2.19 series.
|
||||
"stable-v2.19.4",
|
||||
// The last CodeQL release in the 2.20 series.
|
||||
"stable-v2.20.7",
|
||||
@@ -122,10 +108,6 @@ const defaultTestVersions = [
|
||||
"stable-v2.21.4",
|
||||
// The last CodeQL release in the 2.22 series.
|
||||
"stable-v2.22.4",
|
||||
// The last CodeQL release in the 2.23 series.
|
||||
"stable-v2.23.9",
|
||||
// The last CodeQL release in the 2.24 series.
|
||||
"stable-v2.24.3",
|
||||
// The default version of CodeQL for Dotcom, as determined by feature flags.
|
||||
"default",
|
||||
// The version of CodeQL shipped with the Action in `defaults.json`. During the release process
|
||||
@@ -329,19 +311,10 @@ function generateJobMatrix(
|
||||
);
|
||||
}
|
||||
|
||||
const defaultRunnerImages = [
|
||||
"ubuntu-latest",
|
||||
"macos-latest",
|
||||
"windows-latest",
|
||||
];
|
||||
const runnerImages = ["ubuntu-latest", "macos-latest", "windows-latest"];
|
||||
const operatingSystems = checkSpecification.operatingSystems ?? ["ubuntu"];
|
||||
|
||||
for (const operatingSystemConfig of operatingSystems) {
|
||||
const operatingSystem =
|
||||
typeof operatingSystemConfig === "string"
|
||||
? operatingSystemConfig
|
||||
: operatingSystemConfig.os;
|
||||
|
||||
for (const operatingSystem of operatingSystems) {
|
||||
// If osCodeQlVersions is set for this OS, only include the specified CodeQL versions.
|
||||
const allowedVersions =
|
||||
checkSpecification.osCodeQlVersions?.[operatingSystem];
|
||||
@@ -349,13 +322,9 @@ function generateJobMatrix(
|
||||
continue;
|
||||
}
|
||||
|
||||
const runnerImagesForOs =
|
||||
typeof operatingSystemConfig === "string" ||
|
||||
operatingSystemConfig["runner-image"] === undefined
|
||||
? defaultRunnerImages.filter((image) =>
|
||||
image.startsWith(operatingSystem),
|
||||
)
|
||||
: [operatingSystemConfig["runner-image"]];
|
||||
const runnerImagesForOs = runnerImages.filter((image) =>
|
||||
image.startsWith(operatingSystem),
|
||||
);
|
||||
|
||||
for (const runnerImage of runnerImagesForOs) {
|
||||
matrix.push({
|
||||
|
||||
@@ -22,4 +22,4 @@ outputs:
|
||||
description: The inferred build environment configuration.
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/resolve-environment-entry.js'
|
||||
main: '../lib/resolve-environment-action.js'
|
||||
|
||||
+1
-20
@@ -19,25 +19,6 @@ inputs:
|
||||
If not specified, the Action will check in several places until it finds
|
||||
the CodeQL tools.
|
||||
required: false
|
||||
languages:
|
||||
description: >-
|
||||
A comma-separated list of CodeQL languages that will be analyzed in subsequent
|
||||
`github/codeql-action/init` and `github/codeql-action/analyze` invocations. If specified, the
|
||||
Action may use this list to select a CodeQL CLI version that is best suited to analyzing those
|
||||
languages, for example by preferring a version that has a cached overlay-base database for the
|
||||
specified languages. This input is not remembered and must also be passed to
|
||||
`github/codeql-action/init`.
|
||||
required: false
|
||||
analysis-kinds:
|
||||
description: >-
|
||||
[Internal] A comma-separated list of analysis kinds that subsequent
|
||||
`github/codeql-action/init` invocations will enable. If specified, the Action may use this
|
||||
list to select a CodeQL CLI version that is best suited to those analysis kinds. This input is
|
||||
not remembered and must also be passed to `github/codeql-action/init`.
|
||||
|
||||
Available options are the same as for the `analysis-kinds` input on the `init` Action.
|
||||
default: 'code-scanning'
|
||||
required: true
|
||||
token:
|
||||
description: GitHub token to use for authenticating with this instance of GitHub.
|
||||
default: ${{ github.token }}
|
||||
@@ -55,4 +36,4 @@ outputs:
|
||||
description: The version of the CodeQL binary that was installed.
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/setup-codeql-entry.js'
|
||||
main: '../lib/setup-codeql-action.js'
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.run__ACTION__)();
|
||||
+9
-96
@@ -16,12 +16,7 @@ import {
|
||||
} from "./analyses";
|
||||
import { EnvVar } from "./environment";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import {
|
||||
createFeatures,
|
||||
RecordingLogger,
|
||||
setupBaseActionsVars,
|
||||
setupTests,
|
||||
} from "./testing-utils";
|
||||
import { setupTests } from "./testing-utils";
|
||||
import { AssessmentPayload } from "./upload-lib/types";
|
||||
import { ConfigurationError } from "./util";
|
||||
|
||||
@@ -58,91 +53,24 @@ test("Parsing analysis kinds requires at least one analysis kind", async (t) =>
|
||||
test.serial(
|
||||
"getAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input",
|
||||
async (t) => {
|
||||
process.env[EnvVar.TEST_MODE] = "true";
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns("code-scanning,code-quality");
|
||||
const result = await getAnalysisKinds(
|
||||
getRunnerLogger(true),
|
||||
features,
|
||||
true,
|
||||
);
|
||||
const result = await getAnalysisKinds(getRunnerLogger(true), true);
|
||||
t.assert(result.includes(AnalysisKind.CodeScanning));
|
||||
t.assert(result.includes(AnalysisKind.CodeQuality));
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getAnalysisKinds - only use `code-scanning` for multiple analysis kinds outside of test mode",
|
||||
async (t) => {
|
||||
setupBaseActionsVars();
|
||||
process.env[EnvVar.TEST_MODE] = "false";
|
||||
const features = createFeatures([]);
|
||||
const logger = new RecordingLogger();
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns("code-scanning,code-quality");
|
||||
const result = await getAnalysisKinds(logger, features, true);
|
||||
t.deepEqual(result, [AnalysisKind.CodeScanning]);
|
||||
t.assert(
|
||||
logger.hasMessage(
|
||||
"Continuing with only `analysis-kinds: code-scanning`.",
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getAnalysisKinds - logs error for non-default `analysis-kinds` in custom workflow",
|
||||
async (t) => {
|
||||
setupBaseActionsVars({ GITHUB_EVENT_NAME: "push" });
|
||||
process.env[EnvVar.TEST_MODE] = "false";
|
||||
const features = createFeatures([]);
|
||||
const logger = new RecordingLogger();
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("analysis-kinds").returns("code-quality");
|
||||
const result = await getAnalysisKinds(logger, features, true);
|
||||
t.deepEqual(result, [AnalysisKind.CodeQuality]);
|
||||
t.assert(
|
||||
logger.hasMessage(
|
||||
"An analysis kind other than `code-scanning` was specified in a custom workflow.",
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getAnalysisKinds - no error for non-default `analysis-kinds` in managed workflow",
|
||||
async (t) => {
|
||||
setupBaseActionsVars({ GITHUB_EVENT_NAME: "dynamic" });
|
||||
process.env[EnvVar.TEST_MODE] = "false";
|
||||
const features = createFeatures([]);
|
||||
const logger = new RecordingLogger();
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("analysis-kinds").returns("code-quality");
|
||||
const result = await getAnalysisKinds(logger, features, true);
|
||||
t.deepEqual(result, [AnalysisKind.CodeQuality]);
|
||||
t.deepEqual(logger.messages, []);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used",
|
||||
async (t) => {
|
||||
process.env[EnvVar.TEST_MODE] = "true";
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("analysis-kinds").returns("code-scanning");
|
||||
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
|
||||
optionalInputStub.withArgs("quality-queries").returns("code-quality");
|
||||
const result = await getAnalysisKinds(
|
||||
getRunnerLogger(true),
|
||||
features,
|
||||
true,
|
||||
);
|
||||
const result = await getAnalysisKinds(getRunnerLogger(true), true);
|
||||
t.assert(result.includes(AnalysisKind.CodeScanning));
|
||||
t.assert(result.includes(AnalysisKind.CodeQuality));
|
||||
},
|
||||
@@ -151,12 +79,9 @@ test.serial(
|
||||
test.serial(
|
||||
"getAnalysisKinds - throws if `analysis-kinds` input is invalid",
|
||||
async (t) => {
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing");
|
||||
await t.throwsAsync(
|
||||
getAnalysisKinds(getRunnerLogger(true), features, true),
|
||||
);
|
||||
await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true));
|
||||
},
|
||||
);
|
||||
|
||||
@@ -173,18 +98,11 @@ for (let i = 0; i < analysisKinds.length; i++) {
|
||||
test.serial(
|
||||
`getAnalysisKinds - allows ${analysisKind} with ${otherAnalysis}`,
|
||||
async (t) => {
|
||||
setupBaseActionsVars();
|
||||
process.env[EnvVar.TEST_MODE] = "true";
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns([analysisKind, otherAnalysis].join(","));
|
||||
const result = await getAnalysisKinds(
|
||||
getRunnerLogger(true),
|
||||
features,
|
||||
true,
|
||||
);
|
||||
const result = await getAnalysisKinds(getRunnerLogger(true), true);
|
||||
t.is(result.length, 2);
|
||||
},
|
||||
);
|
||||
@@ -192,19 +110,14 @@ for (let i = 0; i < analysisKinds.length; i++) {
|
||||
test.serial(
|
||||
`getAnalysisKinds - throws if ${analysisKind} is enabled with ${otherAnalysis}`,
|
||||
async (t) => {
|
||||
setupBaseActionsVars();
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns([analysisKind, otherAnalysis].join(","));
|
||||
await t.throwsAsync(
|
||||
getAnalysisKinds(getRunnerLogger(true), features, true),
|
||||
{
|
||||
instanceOf: ConfigurationError,
|
||||
message: `${analysisKind} and ${otherAnalysis} cannot be enabled at the same time`,
|
||||
},
|
||||
);
|
||||
await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true), {
|
||||
instanceOf: ConfigurationError,
|
||||
message: `${analysisKind} and ${otherAnalysis} cannot be enabled at the same time`,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+1
-58
@@ -2,17 +2,15 @@ import {
|
||||
fixCodeQualityCategory,
|
||||
getOptionalInput,
|
||||
getRequiredInput,
|
||||
isDynamicWorkflow,
|
||||
} from "./actions-util";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import {
|
||||
AssessmentPayload,
|
||||
BasePayload,
|
||||
UploadPayload,
|
||||
} from "./upload-lib/types";
|
||||
import { ConfigurationError, getRequiredEnvParam, isInTestMode } from "./util";
|
||||
import { ConfigurationError, getRequiredEnvParam } from "./util";
|
||||
|
||||
export enum AnalysisKind {
|
||||
CodeScanning = "code-scanning",
|
||||
@@ -66,21 +64,6 @@ export async function parseAnalysisKinds(
|
||||
// Used to avoid re-parsing the input after we have done it once.
|
||||
let cachedAnalysisKinds: AnalysisKind[] | undefined;
|
||||
|
||||
/** Determines whether `code-scanning` is the only enabled analysis kind in `analysisKinds`. */
|
||||
function isOnlyCodeScanningEnabled(analysisKinds: AnalysisKind[]) {
|
||||
return (
|
||||
analysisKinds.length === 1 && analysisKinds[0] === AnalysisKind.CodeScanning
|
||||
);
|
||||
}
|
||||
|
||||
/** Prepends a generic message about the intended usage for `analysis-kinds` to `message`. */
|
||||
function makeAnalysisKindUsageError(message: string) {
|
||||
return (
|
||||
"The `analysis-kinds` input is experimental and for GitHub-internal use only. " +
|
||||
`Its behaviour may change at any time or be removed entirely. ${message}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the analysis kinds for the analysis based on the `analysis-kinds` input.
|
||||
* This function will also use the deprecated `quality-queries` input as an indicator to enable `code-quality`.
|
||||
@@ -94,7 +77,6 @@ function makeAnalysisKindUsageError(message: string) {
|
||||
*/
|
||||
export async function getAnalysisKinds(
|
||||
logger: Logger,
|
||||
features: FeatureEnablement,
|
||||
skipCache: boolean = false,
|
||||
): Promise<AnalysisKind[]> {
|
||||
if (!skipCache && cachedAnalysisKinds !== undefined) {
|
||||
@@ -105,26 +87,6 @@ export async function getAnalysisKinds(
|
||||
getRequiredInput("analysis-kinds"),
|
||||
);
|
||||
|
||||
// Log an error if we are outside of a GitHub-managed workflow and an analysis kind
|
||||
// other than `code-scanning` is enabled.
|
||||
if (
|
||||
!isInTestMode() &&
|
||||
!isDynamicWorkflow() &&
|
||||
!isOnlyCodeScanningEnabled(analysisKinds)
|
||||
) {
|
||||
const codeQualityHint = analysisKinds.includes(AnalysisKind.CodeQuality)
|
||||
? " If your intention is to use quality queries outside of Code Quality, " +
|
||||
"use the `queries` input with `code-quality` instead."
|
||||
: "";
|
||||
|
||||
logger.error(
|
||||
makeAnalysisKindUsageError(
|
||||
"An analysis kind other than `code-scanning` was specified in a custom workflow. " +
|
||||
`This is not supported and will become a fatal error in a future version of the CodeQL Action.${codeQualityHint}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Warn that `quality-queries` is deprecated if there is an argument for it.
|
||||
const qualityQueriesInput = getOptionalInput("quality-queries");
|
||||
|
||||
@@ -158,25 +120,6 @@ export async function getAnalysisKinds(
|
||||
}
|
||||
}
|
||||
|
||||
// Log an error if we have multiple inputs for `analysis-kinds` outside of test mode,
|
||||
// and enable only `code-scanning`.
|
||||
if (
|
||||
!isInTestMode() &&
|
||||
analysisKinds.length > 1 &&
|
||||
!(await features.getValue(Feature.AllowMultipleAnalysisKinds))
|
||||
) {
|
||||
logger.error(
|
||||
makeAnalysisKindUsageError(
|
||||
"Specifying multiple values as input is no longer supported. " +
|
||||
"Continuing with only `analysis-kinds: code-scanning`.",
|
||||
),
|
||||
);
|
||||
|
||||
// Only enable Code Scanning.
|
||||
cachedAnalysisKinds = [AnalysisKind.CodeScanning];
|
||||
return cachedAnalysisKinds;
|
||||
}
|
||||
|
||||
// Cache the analysis kinds and return them.
|
||||
cachedAnalysisKinds = analysisKinds;
|
||||
return cachedAnalysisKinds;
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import test from "ava";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as analyze from "./analyze";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as gitUtils from "./git-utils";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
setupTests,
|
||||
setupActionsVars,
|
||||
mockFeatureFlagApiEndpoint,
|
||||
} from "./testing-utils";
|
||||
import * as util from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
// This test needs to be in its own file so that ava would run it in its own
|
||||
// nodejs process. The code being tested is in analyze-action.ts, which runs
|
||||
// immediately on load. So the file needs to be loaded during part of the test,
|
||||
// and that can happen only once per nodejs process. If multiple such tests are
|
||||
// in the same test file, ava would run them in the same nodejs process, and all
|
||||
// but the first test would fail.
|
||||
|
||||
test("analyze action with RAM & threads from environment variables", async (t) => {
|
||||
// This test frequently times out on Windows with the default timeout, so we bump
|
||||
// it a bit to 20s.
|
||||
t.timeout(1000 * 20);
|
||||
await util.withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
sinon
|
||||
.stub(statusReport, "createStatusReportBase")
|
||||
.resolves({} as statusReport.StatusReportBase);
|
||||
sinon.stub(statusReport, "sendStatusReport").resolves();
|
||||
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
|
||||
|
||||
const gitHubVersion: util.GitHubVersion = {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
};
|
||||
sinon.stub(configUtils, "getConfig").resolves({
|
||||
gitHubVersion,
|
||||
augmentationProperties: {},
|
||||
languages: [],
|
||||
packs: [],
|
||||
trapCaches: {},
|
||||
} as unknown as configUtils.Config);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("token").returns("fake-token");
|
||||
requiredInputStub.withArgs("upload-database").returns("false");
|
||||
requiredInputStub.withArgs("output").returns("out");
|
||||
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
|
||||
optionalInputStub.withArgs("expect-error").returns("false");
|
||||
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
|
||||
mockFeatureFlagApiEndpoint(200, {});
|
||||
|
||||
// When there are no action inputs for RAM and threads, the action uses
|
||||
// environment variables (passed down from the init action) to set RAM and
|
||||
// threads usage.
|
||||
process.env["CODEQL_THREADS"] = "-1";
|
||||
process.env["CODEQL_RAM"] = "4992";
|
||||
|
||||
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
|
||||
const runQueriesStub = sinon.stub(analyze, "runQueries");
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const analyzeAction = require("./analyze-action");
|
||||
|
||||
// When analyze-action.ts loads, it runs an async function from the top
|
||||
// level but does not wait for it to finish. To ensure that calls to
|
||||
// runFinalize and runQueries are correctly captured by spies, we explicitly
|
||||
// wait for the action promise to complete before starting verification.
|
||||
await analyzeAction.runPromise;
|
||||
|
||||
t.assert(
|
||||
runFinalizeStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
sinon.match.any,
|
||||
"--threads=-1",
|
||||
"--ram=4992",
|
||||
),
|
||||
);
|
||||
t.assert(
|
||||
runQueriesStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
"--ram=4992",
|
||||
"--threads=-1",
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
import test from "ava";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as analyze from "./analyze";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as gitUtils from "./git-utils";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
setupTests,
|
||||
setupActionsVars,
|
||||
mockFeatureFlagApiEndpoint,
|
||||
} from "./testing-utils";
|
||||
import * as util from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
// This test needs to be in its own file so that ava would run it in its own
|
||||
// nodejs process. The code being tested is in analyze-action.ts, which runs
|
||||
// immediately on load. So the file needs to be loaded during part of the test,
|
||||
// and that can happen only once per nodejs process. If multiple such tests are
|
||||
// in the same test file, ava would run them in the same nodejs process, and all
|
||||
// but the first test would fail.
|
||||
|
||||
test("analyze action with RAM & threads from action inputs", async (t) => {
|
||||
t.timeout(1000 * 20);
|
||||
await util.withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
sinon
|
||||
.stub(statusReport, "createStatusReportBase")
|
||||
.resolves({} as statusReport.StatusReportBase);
|
||||
sinon.stub(statusReport, "sendStatusReport").resolves();
|
||||
const gitHubVersion: util.GitHubVersion = {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
};
|
||||
sinon.stub(configUtils, "getConfig").resolves({
|
||||
gitHubVersion,
|
||||
augmentationProperties: {},
|
||||
languages: [],
|
||||
packs: [],
|
||||
trapCaches: {},
|
||||
} as unknown as configUtils.Config);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("token").returns("fake-token");
|
||||
requiredInputStub.withArgs("upload-database").returns("false");
|
||||
requiredInputStub.withArgs("output").returns("out");
|
||||
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
|
||||
optionalInputStub.withArgs("expect-error").returns("false");
|
||||
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
|
||||
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
|
||||
mockFeatureFlagApiEndpoint(200, {});
|
||||
|
||||
process.env["CODEQL_THREADS"] = "1";
|
||||
process.env["CODEQL_RAM"] = "4992";
|
||||
|
||||
// Action inputs have precedence over environment variables.
|
||||
optionalInputStub.withArgs("threads").returns("-1");
|
||||
optionalInputStub.withArgs("ram").returns("3012");
|
||||
|
||||
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
|
||||
const runQueriesStub = sinon.stub(analyze, "runQueries");
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const analyzeAction = require("./analyze-action");
|
||||
|
||||
// When analyze-action.ts loads, it runs an async function from the top
|
||||
// level but does not wait for it to finish. To ensure that calls to
|
||||
// runFinalize and runQueries are correctly captured by spies, we explicitly
|
||||
// wait for the action promise to complete before starting verification.
|
||||
await analyzeAction.runPromise;
|
||||
|
||||
t.assert(
|
||||
runFinalizeStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
sinon.match.any,
|
||||
"--threads=-1",
|
||||
"--ram=3012",
|
||||
),
|
||||
);
|
||||
t.assert(
|
||||
runQueriesStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
"--ram=3012",
|
||||
"--threads=-1",
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -20,7 +20,7 @@ import { EnvVar } from "./environment";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import { checkGitHubVersionInRange, getErrorMessage } from "./util";
|
||||
|
||||
export async function runWrapper() {
|
||||
async function runWrapper() {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
|
||||
@@ -72,3 +72,5 @@ export async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
import test from "ava";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as analyze from "./analyze";
|
||||
import { runWrapper } from "./analyze-action";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as gitUtils from "./git-utils";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
setupTests,
|
||||
setupActionsVars,
|
||||
mockFeatureFlagApiEndpoint,
|
||||
} from "./testing-utils";
|
||||
import * as util from "./util";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test.serial(
|
||||
"analyze action with RAM & threads from environment variables",
|
||||
async (t) => {
|
||||
// This test frequently times out on Windows with the default timeout, so we bump
|
||||
// it a bit to 20s.
|
||||
t.timeout(1000 * 20);
|
||||
await util.withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
sinon
|
||||
.stub(statusReport, "createStatusReportBase")
|
||||
.resolves({} as statusReport.StatusReportBase);
|
||||
sinon.stub(statusReport, "sendStatusReport").resolves();
|
||||
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
|
||||
|
||||
const gitHubVersion: util.GitHubVersion = {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
};
|
||||
sinon.stub(configUtils, "getConfig").resolves({
|
||||
gitHubVersion,
|
||||
augmentationProperties: {},
|
||||
languages: [],
|
||||
packs: [],
|
||||
trapCaches: {},
|
||||
} as unknown as configUtils.Config);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("token").returns("fake-token");
|
||||
requiredInputStub.withArgs("upload-database").returns("false");
|
||||
requiredInputStub.withArgs("output").returns("out");
|
||||
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
|
||||
optionalInputStub.withArgs("expect-error").returns("false");
|
||||
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
|
||||
mockFeatureFlagApiEndpoint(200, {});
|
||||
|
||||
// When there are no action inputs for RAM and threads, the action uses
|
||||
// environment variables (passed down from the init action) to set RAM and
|
||||
// threads usage.
|
||||
process.env["CODEQL_THREADS"] = "-1";
|
||||
process.env["CODEQL_RAM"] = "4992";
|
||||
|
||||
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
|
||||
const runQueriesStub = sinon.stub(analyze, "runQueries");
|
||||
|
||||
await runWrapper();
|
||||
|
||||
t.assert(
|
||||
runFinalizeStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
sinon.match.any,
|
||||
"--threads=-1",
|
||||
"--ram=4992",
|
||||
),
|
||||
);
|
||||
t.assert(
|
||||
runQueriesStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
"--ram=4992",
|
||||
"--threads=-1",
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"analyze action with RAM & threads from action inputs",
|
||||
async (t) => {
|
||||
t.timeout(1000 * 20);
|
||||
await util.withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
sinon
|
||||
.stub(statusReport, "createStatusReportBase")
|
||||
.resolves({} as statusReport.StatusReportBase);
|
||||
sinon.stub(statusReport, "sendStatusReport").resolves();
|
||||
const gitHubVersion: util.GitHubVersion = {
|
||||
type: util.GitHubVariant.DOTCOM,
|
||||
};
|
||||
sinon.stub(configUtils, "getConfig").resolves({
|
||||
gitHubVersion,
|
||||
augmentationProperties: {},
|
||||
languages: [],
|
||||
packs: [],
|
||||
trapCaches: {},
|
||||
} as unknown as configUtils.Config);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("token").returns("fake-token");
|
||||
requiredInputStub.withArgs("upload-database").returns("false");
|
||||
requiredInputStub.withArgs("output").returns("out");
|
||||
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
|
||||
optionalInputStub.withArgs("expect-error").returns("false");
|
||||
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
|
||||
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
|
||||
mockFeatureFlagApiEndpoint(200, {});
|
||||
|
||||
process.env["CODEQL_THREADS"] = "1";
|
||||
process.env["CODEQL_RAM"] = "4992";
|
||||
|
||||
// Action inputs have precedence over environment variables.
|
||||
optionalInputStub.withArgs("threads").returns("-1");
|
||||
optionalInputStub.withArgs("ram").returns("3012");
|
||||
|
||||
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
|
||||
const runQueriesStub = sinon.stub(analyze, "runQueries");
|
||||
|
||||
await runWrapper();
|
||||
|
||||
t.assert(
|
||||
runFinalizeStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
sinon.match.any,
|
||||
"--threads=-1",
|
||||
"--ram=3012",
|
||||
),
|
||||
);
|
||||
t.assert(
|
||||
runQueriesStub.calledOnceWith(
|
||||
sinon.match.any,
|
||||
"--ram=3012",
|
||||
"--threads=-1",
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -523,11 +523,14 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
// Module-level startedAt so it can be accessed by runWrapper for error reporting
|
||||
const startedAt = new Date();
|
||||
export const runPromise = run(startedAt);
|
||||
|
||||
async function runWrapper() {
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
await run(startedAt);
|
||||
await runPromise;
|
||||
} catch (error) {
|
||||
core.setFailed(`analyze action failed: ${util.getErrorMessage(error)}`);
|
||||
await sendUnhandledErrorStatusReport(
|
||||
@@ -539,3 +542,5 @@ export async function runWrapper() {
|
||||
}
|
||||
await util.checkForTimeout();
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+18
-6
@@ -251,9 +251,16 @@ export async function setupDiffInformedQueryRun(
|
||||
diffRanges,
|
||||
checkoutPath,
|
||||
);
|
||||
logger.info(
|
||||
`Successfully created diff range extension pack at ${packDir}.`,
|
||||
);
|
||||
if (packDir === undefined) {
|
||||
logger.warning(
|
||||
"Cannot create diff range extension pack for diff-informed queries; " +
|
||||
"reverting to performing full analysis.",
|
||||
);
|
||||
} else {
|
||||
logger.info(
|
||||
`Successfully created diff range extension pack at ${packDir}.`,
|
||||
);
|
||||
}
|
||||
return packDir;
|
||||
},
|
||||
);
|
||||
@@ -307,13 +314,18 @@ extensions:
|
||||
* @param ranges The file line ranges, as returned by
|
||||
* `getPullRequestEditedDiffRanges`.
|
||||
* @param checkoutPath The path at which the repository was checked out.
|
||||
* @returns The absolute path of the directory containing the extension pack.
|
||||
* @returns The absolute path of the directory containing the extension pack, or
|
||||
* `undefined` if no extension pack was created.
|
||||
*/
|
||||
function writeDiffRangeDataExtensionPack(
|
||||
logger: Logger,
|
||||
ranges: DiffThunkRange[],
|
||||
ranges: DiffThunkRange[] | undefined,
|
||||
checkoutPath: string,
|
||||
): string {
|
||||
): string | undefined {
|
||||
if (ranges === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (ranges.length === 0) {
|
||||
// An empty diff range means that there are no added or modified lines in
|
||||
// the pull request. But the `restrictAlertsTo` extensible predicate
|
||||
|
||||
+5
-22
@@ -128,8 +128,6 @@ export async function getGitHubVersionFromApi(
|
||||
|
||||
// Doesn't strictly have to be the meta endpoint as we're only
|
||||
// using the response headers which are available on every request.
|
||||
//
|
||||
// See https://docs.github.com/en/rest/meta/meta#get-github-meta-information.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
const response = await apiClient.rest.meta.get();
|
||||
|
||||
@@ -166,9 +164,6 @@ export async function getGitHubVersion(): Promise<GitHubVersion> {
|
||||
|
||||
/**
|
||||
* Get the path of the currently executing workflow relative to the repository root.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/actions/workflow-runs#get-a-workflow-run
|
||||
* and https://docs.github.com/en/rest/actions/workflows#get-a-workflow.
|
||||
*/
|
||||
export async function getWorkflowRelativePath(): Promise<string> {
|
||||
const repo_nwo = getRepositoryNwo();
|
||||
@@ -257,13 +252,9 @@ export interface ActionsCacheItem {
|
||||
size_in_bytes?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all Actions cache entries starting with the provided key prefix and matching the provided ref.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/actions/cache#list-github-actions-caches-for-a-repository.
|
||||
*/
|
||||
/** List all Actions cache entries matching the provided key and ref. */
|
||||
export async function listActionsCaches(
|
||||
keyPrefix: string,
|
||||
key: string,
|
||||
ref?: string,
|
||||
): Promise<ActionsCacheItem[]> {
|
||||
const repositoryNwo = getRepositoryNwo();
|
||||
@@ -273,17 +264,13 @@ export async function listActionsCaches(
|
||||
{
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
key: keyPrefix,
|
||||
key,
|
||||
ref,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an Actions cache item by its ID.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/actions/cache#delete-a-github-actions-cache-for-a-repository-using-a-cache-id.
|
||||
*/
|
||||
/** Delete an Actions cache item by its ID. */
|
||||
export async function deleteActionsCache(id: number) {
|
||||
const repositoryNwo = getRepositoryNwo();
|
||||
|
||||
@@ -294,11 +281,7 @@ export async function deleteActionsCache(id: number) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all custom repository properties.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/repos/custom-properties#get-all-custom-property-values-for-a-repository.
|
||||
*/
|
||||
/** Retrieve all custom repository properties. */
|
||||
export async function getRepositoryProperties(repositoryNwo: RepositoryNwo) {
|
||||
return getApiClient().request("GET /repos/:owner/:repo/properties/values", {
|
||||
owner: repositoryNwo.owner,
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"maximumVersion": "3.21", "minimumVersion": "3.16"}
|
||||
{"maximumVersion": "3.21", "minimumVersion": "3.14"}
|
||||
|
||||
@@ -141,9 +141,9 @@ test("scanArtifactsForTokens handles files without tokens", async (t) => {
|
||||
}
|
||||
});
|
||||
|
||||
// `scanArchiveFile` does not support Windows, so we skip this test there.
|
||||
if (os.platform() !== "win32") {
|
||||
test("scanArtifactsForTokens finds token in debug artifacts", async (t) => {
|
||||
t.timeout(15000); // 15 seconds
|
||||
const messages: LoggedMessage[] = [];
|
||||
const logger = getRecordingLogger(messages, { logToConsole: false });
|
||||
// The zip here is a regression test based on
|
||||
|
||||
@@ -156,10 +156,6 @@ async function scanArchiveFile(
|
||||
);
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
throw new Error("Scanning archives is not supported on Windows.");
|
||||
}
|
||||
|
||||
const result: ScanResult = {
|
||||
scannedFiles: 0,
|
||||
findings: [],
|
||||
|
||||
@@ -142,7 +142,7 @@ async function run(startedAt: Date) {
|
||||
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
|
||||
}
|
||||
|
||||
export async function runWrapper() {
|
||||
async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -157,3 +157,5 @@ export async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+38
-58
@@ -33,7 +33,6 @@ import {
|
||||
mockBundleDownloadApi,
|
||||
makeVersionInfo,
|
||||
createTestConfig,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { ToolsDownloadStatusReport } from "./tools-download";
|
||||
import * as util from "./util";
|
||||
@@ -71,10 +70,8 @@ async function installIntoToolcache({
|
||||
tmpDir,
|
||||
util.GitHubVariant.GHES,
|
||||
cliVersion !== undefined
|
||||
? { enabledVersions: [{ cliVersion, tagName }] }
|
||||
? { cliVersion, tagName }
|
||||
: SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -146,8 +143,6 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -180,8 +175,6 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -221,8 +214,6 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -273,8 +264,6 @@ for (const {
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -295,11 +284,11 @@ for (const {
|
||||
for (const toolcacheVersion of [
|
||||
// Test that we use the tools from the toolcache when `SAMPLE_DEFAULT_CLI_VERSION` is requested
|
||||
// and `SAMPLE_DEFAULT_CLI_VERSION-` is in the toolcache.
|
||||
SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion,
|
||||
`${SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion}-20230101`,
|
||||
SAMPLE_DEFAULT_CLI_VERSION.cliVersion,
|
||||
`${SAMPLE_DEFAULT_CLI_VERSION.cliVersion}-20230101`,
|
||||
]) {
|
||||
test.serial(
|
||||
`uses tools from toolcache when ${SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion} is requested and ` +
|
||||
`uses tools from toolcache when ${SAMPLE_DEFAULT_CLI_VERSION.cliVersion} is requested and ` +
|
||||
`${toolcacheVersion} is installed`,
|
||||
async (t) => {
|
||||
const features = createFeatures([]);
|
||||
@@ -319,16 +308,11 @@ for (const toolcacheVersion of [
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
);
|
||||
t.is(
|
||||
result.toolsVersion,
|
||||
SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion,
|
||||
);
|
||||
t.is(result.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
|
||||
t.is(result.toolsSource, ToolsSource.Toolcache);
|
||||
t.is(result.toolsDownloadStatusReport?.combinedDurationMs, undefined);
|
||||
t.is(result.toolsDownloadStatusReport?.downloadDurationMs, undefined);
|
||||
@@ -358,15 +342,9 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.GHES,
|
||||
{
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -406,15 +384,9 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.GHES,
|
||||
{
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -454,8 +426,6 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -497,8 +467,6 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -572,7 +540,7 @@ test.serial("getExtraOptions throws for bad content", (t) => {
|
||||
});
|
||||
|
||||
// Test macro for ensuring different variants of injected augmented configurations
|
||||
const injectedConfigMacro = makeMacro({
|
||||
const injectedConfigMacro = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
augmentationProperties: AugmentationProperties,
|
||||
@@ -622,8 +590,9 @@ const injectedConfigMacro = makeMacro({
|
||||
`databaseInitCluster() injected config: ${providedTitle}`,
|
||||
});
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"basic",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
},
|
||||
@@ -631,8 +600,9 @@ injectedConfigMacro.serial(
|
||||
{},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected packs from input",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
packsInput: ["xxx", "yyy"],
|
||||
@@ -643,8 +613,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected packs from input with existing packs combines",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
packsInputCombines: true,
|
||||
@@ -664,8 +635,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected packs from input with existing packs overrides",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
packsInput: ["xxx", "yyy"],
|
||||
@@ -683,8 +655,9 @@ injectedConfigMacro.serial(
|
||||
);
|
||||
|
||||
// similar, but with queries
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected queries from input",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInput: [{ uses: "xxx" }, { uses: "yyy" }],
|
||||
@@ -702,8 +675,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected queries from input overrides",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInput: [{ uses: "xxx" }, { uses: "yyy" }],
|
||||
@@ -725,8 +699,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected queries from input combines",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -752,8 +727,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected queries from input combines 2",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -773,8 +749,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"injected queries and packs, but empty",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -791,8 +768,9 @@ injectedConfigMacro.serial(
|
||||
{},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"repo property queries have the highest precedence",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -812,8 +790,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"repo property queries combines with queries input",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: false,
|
||||
@@ -838,8 +817,9 @@ injectedConfigMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
injectedConfigMacro.serial(
|
||||
test.serial(
|
||||
"repo property queries combines everything else",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -1072,7 +1052,7 @@ test.serial(
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"Avoids duplicating --force-overwrite flag if specified in CODEQL_ACTION_EXTRA_OPTIONS",
|
||||
"Avoids duplicating --overwrite flag if specified in CODEQL_ACTION_EXTRA_OPTIONS",
|
||||
async (t) => {
|
||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||
const codeqlObject = await stubCodeql();
|
||||
@@ -1080,7 +1060,7 @@ test.serial(
|
||||
sinon.stub(io, "which").resolves("");
|
||||
|
||||
process.env["CODEQL_ACTION_EXTRA_OPTIONS"] =
|
||||
'{ "database": { "init": ["--force-overwrite"] } }';
|
||||
'{ "database": { "init": ["--overwrite"] } }';
|
||||
|
||||
await codeqlObject.databaseInitCluster(
|
||||
stubConfig,
|
||||
@@ -1093,9 +1073,9 @@ test.serial(
|
||||
t.true(runnerConstructorStub.calledOnce);
|
||||
const args = runnerConstructorStub.firstCall.args[1] as string[];
|
||||
t.is(
|
||||
args.filter((option: string) => option === "--force-overwrite").length,
|
||||
args.filter((option: string) => option === "--overwrite").length,
|
||||
1,
|
||||
"--force-overwrite should only be passed once",
|
||||
"--overwrite should only be passed once",
|
||||
);
|
||||
|
||||
// Clean up
|
||||
|
||||
+21
-22
@@ -277,22 +277,22 @@ let cachedCodeQL: CodeQL | undefined = undefined;
|
||||
* The version flags below can be used to conditionally enable certain features
|
||||
* on versions newer than this.
|
||||
*/
|
||||
const CODEQL_MINIMUM_VERSION = "2.19.4";
|
||||
const CODEQL_MINIMUM_VERSION = "2.17.6";
|
||||
|
||||
/**
|
||||
* This version will shortly become the oldest version of CodeQL that the Action will run with.
|
||||
*/
|
||||
const CODEQL_NEXT_MINIMUM_VERSION = "2.19.4";
|
||||
const CODEQL_NEXT_MINIMUM_VERSION = "2.17.6";
|
||||
|
||||
/**
|
||||
* This is the version of GHES that was most recently deprecated.
|
||||
*/
|
||||
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.15";
|
||||
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.13";
|
||||
|
||||
/**
|
||||
* This is the deprecation date for the version of GHES that was most recently deprecated.
|
||||
*/
|
||||
const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-04-09";
|
||||
const GHES_MOST_RECENT_DEPRECATION_DATE = "2025-06-19";
|
||||
|
||||
/** The CLI verbosity level to use for extraction in debug mode. */
|
||||
const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
|
||||
@@ -305,8 +305,6 @@ const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
|
||||
* @param tempDir
|
||||
* @param variant
|
||||
* @param defaultCliVersion
|
||||
* @param rawLanguages Raw set of languages.
|
||||
* @param useOverlayAwareDefaultCliVersion Whether to select an overlay-aware default CLI version.
|
||||
* @param features Information about the features that are enabled.
|
||||
* @param logger
|
||||
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
||||
@@ -319,8 +317,6 @@ export async function setupCodeQL(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
checkVersion: boolean,
|
||||
@@ -344,8 +340,6 @@ export async function setupCodeQL(
|
||||
tempDir,
|
||||
variant,
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
@@ -592,6 +586,13 @@ async function getCodeQLForCmd(
|
||||
extraArgs.push(`--qlconfig-file=${qlconfigFile}`);
|
||||
}
|
||||
|
||||
const overwriteFlag = isSupportedToolsFeature(
|
||||
await this.getVersion(),
|
||||
ToolsFeature.ForceOverwrite,
|
||||
)
|
||||
? "--force-overwrite"
|
||||
: "--overwrite";
|
||||
|
||||
const overlayDatabaseMode = config.overlayDatabaseMode;
|
||||
if (overlayDatabaseMode === OverlayDatabaseMode.Overlay) {
|
||||
const overlayChangesFile = await writeOverlayChangesFile(
|
||||
@@ -618,7 +619,7 @@ async function getCodeQLForCmd(
|
||||
"init",
|
||||
...(overlayDatabaseMode === OverlayDatabaseMode.Overlay
|
||||
? []
|
||||
: ["--force-overwrite"]),
|
||||
: [overwriteFlag]),
|
||||
"--db-cluster",
|
||||
config.dbLocation,
|
||||
`--source-root=${sourceRoot}`,
|
||||
@@ -629,14 +630,7 @@ async function getCodeQLForCmd(
|
||||
// Some user configs specify `--no-calculate-baseline` as an additional
|
||||
// argument to `codeql database init`. Therefore ignore the baseline file
|
||||
// options here to avoid specifying the same argument twice and erroring.
|
||||
//
|
||||
// Ignore `--overwrite` to avoid passing both `--force-overwrite` and `--overwrite` if
|
||||
// the user has configured `--overwrite`.
|
||||
ignoringOptions: [
|
||||
"--force-overwrite",
|
||||
"--overwrite",
|
||||
...baselineFilesOptions,
|
||||
],
|
||||
ignoringOptions: ["--overwrite", ...baselineFilesOptions],
|
||||
}),
|
||||
],
|
||||
{ stdin: externalRepositoryToken },
|
||||
@@ -853,7 +847,7 @@ async function getCodeQLForCmd(
|
||||
"--sarif-group-rules-by-pack",
|
||||
"--sarif-include-query-help=always",
|
||||
"--sublanguage-file-coverage",
|
||||
...(await getJobRunUuidSarifOptions()),
|
||||
...(await getJobRunUuidSarifOptions(this)),
|
||||
...getExtraOptionsFromEnv(["database", "interpret-results"]),
|
||||
];
|
||||
if (sarifRunPropertyFlag !== undefined) {
|
||||
@@ -1283,8 +1277,13 @@ function applyAutobuildAzurePipelinesTimeoutFix() {
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
async function getJobRunUuidSarifOptions() {
|
||||
async function getJobRunUuidSarifOptions(codeql: CodeQL) {
|
||||
const jobRunUuid = process.env[EnvVar.JOB_RUN_UUID];
|
||||
|
||||
return jobRunUuid ? [`--sarif-run-property=jobRunUuid=${jobRunUuid}`] : [];
|
||||
return jobRunUuid &&
|
||||
(await codeql.supportsFeature(
|
||||
ToolsFeature.DatabaseInterpretResultsSupportsSarifRunProperty,
|
||||
))
|
||||
? [`--sarif-run-property=jobRunUuid=${jobRunUuid}`]
|
||||
: [];
|
||||
}
|
||||
|
||||
+127
-155
@@ -21,7 +21,6 @@ import { GitVersionInfo } from "./git-utils";
|
||||
import { BuiltInLanguage, Language } from "./languages";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { CODEQL_OVERLAY_MINIMUM_VERSION } from "./overlay";
|
||||
import * as overlayDiagnostics from "./overlay/diagnostics";
|
||||
import { OverlayDisabledReason } from "./overlay/diagnostics";
|
||||
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
|
||||
import * as overlayStatus from "./overlay/status";
|
||||
@@ -35,7 +34,6 @@ import {
|
||||
LoggedMessage,
|
||||
mockCodeQLVersion,
|
||||
createTestConfig,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import {
|
||||
GitHubVariant,
|
||||
@@ -1036,9 +1034,10 @@ const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = {
|
||||
repositoryProperties: {},
|
||||
};
|
||||
|
||||
const checkOverlayEnablementMacro = makeMacro({
|
||||
const checkOverlayEnablementMacro = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
setupOverrides: Partial<OverlayDatabaseModeTestSetup>,
|
||||
expected:
|
||||
| {
|
||||
@@ -1132,10 +1131,11 @@ const checkOverlayEnablementMacro = makeMacro({
|
||||
}
|
||||
});
|
||||
},
|
||||
title: (title) => `checkOverlayEnablement: ${title}`,
|
||||
title: (_, title) => `checkOverlayEnablement: ${title}`,
|
||||
});
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Environment variable override - Overlay",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1146,7 +1146,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Environment variable override - OverlayBase",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay-base",
|
||||
@@ -1157,7 +1158,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Environment variable override - None",
|
||||
{
|
||||
overlayDatabaseEnvVar: "none",
|
||||
@@ -1167,7 +1169,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Ignore invalid environment variable",
|
||||
{
|
||||
overlayDatabaseEnvVar: "invalid-mode",
|
||||
@@ -1177,7 +1180,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Ignore feature flag when analyzing non-default branch",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1188,7 +1192,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch when feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1201,14 +1206,15 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch when feature enabled with custom analysis",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
},
|
||||
} as UserConfig,
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1217,7 +1223,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch when code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1233,7 +1240,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch if runner disk space is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1252,7 +1260,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch if we can't determine runner disk space",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1268,7 +1277,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch if runner disk space is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1289,7 +1299,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch if runner disk space is below v2 limit and v2 resource checks enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1309,7 +1320,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch if runner disk space is between v2 and v1 limits and v2 resource checks enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1330,7 +1342,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch if runner disk space is between v2 and v1 limits and v2 resource checks not enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1349,7 +1362,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch if memory flag is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1365,7 +1379,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch if memory flag is too low but CodeQL >= 2.24.3",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1383,7 +1398,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay-base database on default branch if memory flag is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1401,7 +1417,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when cached status indicates previous failure",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1418,7 +1435,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when cached status indicates previous failure",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1435,7 +1453,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with disable-default-queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1445,7 +1464,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"disable-default-queries": true,
|
||||
},
|
||||
} as UserConfig,
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1453,7 +1472,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with packs",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1463,7 +1483,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
},
|
||||
} as UserConfig,
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1471,7 +1491,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1481,7 +1502,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
queries: [{ uses: "some-query.ql" }],
|
||||
},
|
||||
} as UserConfig,
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1489,7 +1510,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with query-filters",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1499,7 +1521,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"query-filters": [{ include: { "security-severity": "high" } }],
|
||||
},
|
||||
} as UserConfig,
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1507,7 +1529,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when only language-specific feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1519,7 +1542,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when only code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1531,7 +1555,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay-base database on default branch when language-specific feature disabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1543,7 +1568,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay analysis on PR when feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1556,14 +1582,15 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay analysis on PR when feature enabled with custom analysis",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
},
|
||||
} as UserConfig,
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1572,7 +1599,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay analysis on PR when code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1588,7 +1616,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR if runner disk space is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1607,7 +1636,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay analysis on PR if runner disk space is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1628,7 +1658,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR if we can't determine runner disk space",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1644,7 +1675,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR if memory flag is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1660,7 +1692,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay analysis on PR if memory flag is too low but CodeQL >= 2.24.3",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1678,7 +1711,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay analysis on PR if memory flag is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1696,7 +1730,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when code-scanning feature enabled with disable-default-queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1706,7 +1741,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"disable-default-queries": true,
|
||||
},
|
||||
} as UserConfig,
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1714,7 +1749,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when code-scanning feature enabled with packs",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1724,7 +1760,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
},
|
||||
} as UserConfig,
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1732,7 +1768,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when code-scanning feature enabled with queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1742,7 +1779,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
queries: [{ uses: "some-query.ql" }],
|
||||
},
|
||||
} as UserConfig,
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1750,7 +1787,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when code-scanning feature enabled with query-filters",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1760,7 +1798,7 @@ checkOverlayEnablementMacro.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"query-filters": [{ include: { "security-severity": "high" } }],
|
||||
},
|
||||
} as UserConfig,
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1768,7 +1806,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when only language-specific feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1780,7 +1819,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when only code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1792,7 +1832,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis on PR when language-specific feature disabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1804,7 +1845,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay PR analysis by env",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1815,7 +1857,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay PR analysis by env on a runner with low disk space",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1827,7 +1870,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay PR analysis by feature flag",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1840,7 +1884,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Fallback due to autobuild with traced language",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1852,7 +1897,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Fallback due to no build mode with traced language",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1864,7 +1910,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Fallback due to old CodeQL version",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1875,7 +1922,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Fallback due to missing git root",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1886,7 +1934,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Fallback due to old git version with submodules",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1898,7 +1947,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Fallback when git version cannot be determined and repo has submodules",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1910,7 +1960,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay enabled when git version cannot be determined and repo has no submodules",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1923,7 +1974,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay when disabled via repository property",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1938,7 +1990,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Overlay not disabled when repository property is false",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1954,7 +2007,8 @@ checkOverlayEnablementMacro.serial(
|
||||
},
|
||||
);
|
||||
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"Environment variable override takes precedence over repository property",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1970,7 +2024,8 @@ checkOverlayEnablementMacro.serial(
|
||||
|
||||
// Exercise language-specific overlay analysis features code paths
|
||||
for (const language in BuiltInLanguage) {
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
`Check default overlay analysis feature for ${language}`,
|
||||
{
|
||||
languages: [language],
|
||||
@@ -1987,7 +2042,8 @@ for (const language in BuiltInLanguage) {
|
||||
// overlay analysis enabled, even when the base overlay feature flag is on.
|
||||
// Using swift here as it doesn't currently have overlay support — update this if
|
||||
// swift gains overlay support.
|
||||
checkOverlayEnablementMacro.serial(
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
"No overlay analysis for language without per-language overlay feature flag",
|
||||
{
|
||||
languages: [BuiltInLanguage.swift],
|
||||
@@ -2144,87 +2200,3 @@ test.serial(
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test("applyIncrementalAnalysisSettings: no-op when mode is not Overlay and diff ranges are unavailable", async (t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
false,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, []);
|
||||
});
|
||||
|
||||
test("applyIncrementalAnalysisSettings: keeps overlay mode and adds exclusions when diff ranges are available", async (t) => {
|
||||
const config = createTestConfig({
|
||||
overlayDatabaseMode: OverlayDatabaseMode.Overlay,
|
||||
});
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
true,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.Overlay);
|
||||
t.deepEqual(config.extraQueryExclusions, [
|
||||
{ exclude: { tags: "exclude-from-incremental" } },
|
||||
]);
|
||||
});
|
||||
|
||||
test("applyIncrementalAnalysisSettings: disables overlay analysis when diff ranges are unavailable", async (t) => {
|
||||
const config = createTestConfig({
|
||||
overlayDatabaseMode: OverlayDatabaseMode.Overlay,
|
||||
});
|
||||
config.useOverlayDatabaseCaching = true;
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
const addDiagnosticsStub = sinon
|
||||
.stub(overlayDiagnostics, "addOverlayDisablementDiagnostics")
|
||||
.resolves();
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
false,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.is(config.useOverlayDatabaseCaching, false);
|
||||
t.deepEqual(config.extraQueryExclusions, []);
|
||||
t.true(addDiagnosticsStub.calledOnce);
|
||||
t.is(
|
||||
addDiagnosticsStub.firstCall.args[2],
|
||||
OverlayDisabledReason.DiffInformedAnalysisNotEnabled,
|
||||
);
|
||||
});
|
||||
|
||||
test("applyIncrementalAnalysisSettings: adds exclusions for diff-informed-only runs", async (t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
true,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, [
|
||||
{ exclude: { tags: "exclude-from-incremental" } },
|
||||
]);
|
||||
});
|
||||
|
||||
+13
-56
@@ -31,7 +31,7 @@ import {
|
||||
addNoLanguageDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||
import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import * as errorMessages from "./error-messages";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
@@ -407,7 +407,6 @@ export async function getLanguages(
|
||||
return languages;
|
||||
}
|
||||
|
||||
/** Splits the `languages` input into a list of raw languages without checking if they are supported by CodeQL. */
|
||||
export function getRawLanguagesNoAutodetect(
|
||||
languagesInput: string | undefined,
|
||||
): string[] {
|
||||
@@ -1077,48 +1076,6 @@ function hasQueryCustomisation(userConfig: UserConfig): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the incremental-analysis configuration for this run.
|
||||
*
|
||||
* Overlay analysis has only been validated in combination with diff-informed
|
||||
* analysis, so if `Overlay` mode was selected for a pull request but the diff
|
||||
* ranges could not be computed, fall back to a full non-overlay analysis.
|
||||
*
|
||||
* Query exclusions for incremental-only queries are then applied whenever the
|
||||
* diff ranges are available — which, after the fallback above, is exactly the
|
||||
* set of runs where any kind of incremental analysis (overlay or
|
||||
* diff-informed) is in effect.
|
||||
*/
|
||||
export async function applyIncrementalAnalysisSettings(
|
||||
config: Config,
|
||||
hasDiffRanges: boolean,
|
||||
codeql: CodeQL,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay &&
|
||||
!hasDiffRanges
|
||||
) {
|
||||
logger.info(
|
||||
`Reverting overlay database mode to ${OverlayDatabaseMode.None} ` +
|
||||
"because the PR diff ranges could not be computed.",
|
||||
);
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
config.useOverlayDatabaseCaching = false;
|
||||
await addOverlayDisablementDiagnostics(
|
||||
config,
|
||||
codeql,
|
||||
OverlayDisabledReason.DiffInformedAnalysisNotEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
if (hasDiffRanges) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and return the config.
|
||||
*
|
||||
@@ -1273,18 +1230,18 @@ export async function initConfig(
|
||||
);
|
||||
}
|
||||
|
||||
const hasDiffRanges = await prepareDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger,
|
||||
);
|
||||
|
||||
await applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
hasDiffRanges,
|
||||
inputs.codeql,
|
||||
logger,
|
||||
);
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
|
||||
(await shouldPerformDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger,
|
||||
))
|
||||
) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" },
|
||||
});
|
||||
}
|
||||
|
||||
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
|
||||
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
checkExpectedLogMessages,
|
||||
getRecordingLogger,
|
||||
LoggedMessage,
|
||||
makeMacro,
|
||||
} from "../testing-utils";
|
||||
import { ConfigurationError, prettyPrintPack } from "../util";
|
||||
|
||||
@@ -16,7 +15,7 @@ import * as dbConfig from "./db-config";
|
||||
/**
|
||||
* Test macro for ensuring the packs block is valid
|
||||
*/
|
||||
const parsePacksMacro = makeMacro({
|
||||
const parsePacksMacro = test.macro({
|
||||
exec: (
|
||||
t: ExecutionContext<unknown>,
|
||||
packsInput: string,
|
||||
@@ -34,7 +33,7 @@ const parsePacksMacro = makeMacro({
|
||||
/**
|
||||
* Test macro for testing when the packs block is invalid
|
||||
*/
|
||||
const parsePacksErrorMacro = makeMacro({
|
||||
const parsePacksErrorMacro = test.macro({
|
||||
exec: (
|
||||
t: ExecutionContext<unknown>,
|
||||
packsInput: string,
|
||||
@@ -50,32 +49,34 @@ const parsePacksErrorMacro = makeMacro({
|
||||
/**
|
||||
* Test macro for testing when the packs block is invalid
|
||||
*/
|
||||
const invalidPackNameMacro = makeMacro({
|
||||
exec: (t: ExecutionContext, arg: string) =>
|
||||
parsePacksErrorMacro.fn(
|
||||
const invalidPackNameMacro = test.macro({
|
||||
exec: (t: ExecutionContext, name: string) =>
|
||||
parsePacksErrorMacro.exec(
|
||||
t,
|
||||
arg,
|
||||
name,
|
||||
[BuiltInLanguage.cpp],
|
||||
new RegExp(`^"${arg}" is not a valid pack$`),
|
||||
new RegExp(`^"${name}" is not a valid pack$`),
|
||||
),
|
||||
title: (_providedTitle: string | undefined, arg: string | undefined) =>
|
||||
`Invalid pack string: ${arg}`,
|
||||
});
|
||||
|
||||
parsePacksMacro("no packs", "", [], undefined);
|
||||
parsePacksMacro("two packs", "a/b,c/d@1.2.3", [BuiltInLanguage.cpp], {
|
||||
test("no packs", parsePacksMacro, "", [], undefined);
|
||||
test("two packs", parsePacksMacro, "a/b,c/d@1.2.3", [BuiltInLanguage.cpp], {
|
||||
[BuiltInLanguage.cpp]: ["a/b", "c/d@1.2.3"],
|
||||
});
|
||||
parsePacksMacro(
|
||||
test(
|
||||
"two packs with spaces",
|
||||
parsePacksMacro,
|
||||
" a/b , c/d@1.2.3 ",
|
||||
[BuiltInLanguage.cpp],
|
||||
{
|
||||
[BuiltInLanguage.cpp]: ["a/b", "c/d@1.2.3"],
|
||||
},
|
||||
);
|
||||
parsePacksErrorMacro(
|
||||
test(
|
||||
"two packs with language",
|
||||
parsePacksErrorMacro,
|
||||
"a/b,c/d@1.2.3",
|
||||
[BuiltInLanguage.cpp, BuiltInLanguage.java],
|
||||
new RegExp(
|
||||
@@ -84,8 +85,9 @@ parsePacksErrorMacro(
|
||||
),
|
||||
);
|
||||
|
||||
parsePacksMacro(
|
||||
test(
|
||||
"packs with other valid names",
|
||||
parsePacksMacro,
|
||||
[
|
||||
// ranges are ok
|
||||
"c/d@1.0",
|
||||
@@ -121,23 +123,23 @@ parsePacksMacro(
|
||||
},
|
||||
);
|
||||
|
||||
invalidPackNameMacro.test("c"); // all packs require at least a scope and a name
|
||||
invalidPackNameMacro.test("c-/d");
|
||||
invalidPackNameMacro.test("-c/d");
|
||||
invalidPackNameMacro.test("c/d_d");
|
||||
invalidPackNameMacro.test("c/d@@");
|
||||
invalidPackNameMacro.test("c/d@1.0.0:");
|
||||
invalidPackNameMacro.test("c/d:");
|
||||
invalidPackNameMacro.test("c/d:/a");
|
||||
invalidPackNameMacro.test("@1.0.0:a");
|
||||
invalidPackNameMacro.test("c/d@../a");
|
||||
invalidPackNameMacro.test("c/d@b/../a");
|
||||
invalidPackNameMacro.test("c/d:z@1");
|
||||
test(invalidPackNameMacro, "c"); // all packs require at least a scope and a name
|
||||
test(invalidPackNameMacro, "c-/d");
|
||||
test(invalidPackNameMacro, "-c/d");
|
||||
test(invalidPackNameMacro, "c/d_d");
|
||||
test(invalidPackNameMacro, "c/d@@");
|
||||
test(invalidPackNameMacro, "c/d@1.0.0:");
|
||||
test(invalidPackNameMacro, "c/d:");
|
||||
test(invalidPackNameMacro, "c/d:/a");
|
||||
test(invalidPackNameMacro, "@1.0.0:a");
|
||||
test(invalidPackNameMacro, "c/d@../a");
|
||||
test(invalidPackNameMacro, "c/d@b/../a");
|
||||
test(invalidPackNameMacro, "c/d:z@1");
|
||||
|
||||
/**
|
||||
* Test macro for pretty printing pack specs
|
||||
*/
|
||||
const packSpecPrettyPrintingMacro = makeMacro({
|
||||
const packSpecPrettyPrintingMacro = test.macro({
|
||||
exec: (t: ExecutionContext, packStr: string, packObj: dbConfig.Pack) => {
|
||||
const parsed = dbConfig.parsePacksSpecification(packStr);
|
||||
t.deepEqual(parsed, packObj, "parsed pack spec is correct");
|
||||
@@ -161,35 +163,36 @@ const packSpecPrettyPrintingMacro = makeMacro({
|
||||
) => `Prettyprint pack spec: '${packStr}'`,
|
||||
});
|
||||
|
||||
packSpecPrettyPrintingMacro.test("a/b", {
|
||||
test(packSpecPrettyPrintingMacro, "a/b", {
|
||||
name: "a/b",
|
||||
version: undefined,
|
||||
path: undefined,
|
||||
});
|
||||
packSpecPrettyPrintingMacro.test("a/b@~1.2.3", {
|
||||
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3", {
|
||||
name: "a/b",
|
||||
version: "~1.2.3",
|
||||
path: undefined,
|
||||
});
|
||||
packSpecPrettyPrintingMacro.test("a/b@~1.2.3:abc/def", {
|
||||
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3:abc/def", {
|
||||
name: "a/b",
|
||||
version: "~1.2.3",
|
||||
path: "abc/def",
|
||||
});
|
||||
packSpecPrettyPrintingMacro.test("a/b:abc/def", {
|
||||
test(packSpecPrettyPrintingMacro, "a/b:abc/def", {
|
||||
name: "a/b",
|
||||
version: undefined,
|
||||
path: "abc/def",
|
||||
});
|
||||
packSpecPrettyPrintingMacro.test(" a/b:abc/def ", {
|
||||
test(packSpecPrettyPrintingMacro, " a/b:abc/def ", {
|
||||
name: "a/b",
|
||||
version: undefined,
|
||||
path: "abc/def",
|
||||
});
|
||||
|
||||
const calculateAugmentationMacro = makeMacro({
|
||||
const calculateAugmentationMacro = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
rawPacksInput: string | undefined,
|
||||
rawQueriesInput: string | undefined,
|
||||
languages: Language[],
|
||||
@@ -204,10 +207,11 @@ const calculateAugmentationMacro = makeMacro({
|
||||
);
|
||||
t.deepEqual(actualAugmentationProperties, expectedAugmentationProperties);
|
||||
},
|
||||
title: (title) => `Calculate Augmentation: ${title}`,
|
||||
title: (_, title) => `Calculate Augmentation: ${title}`,
|
||||
});
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"All empty",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -218,7 +222,8 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"With queries",
|
||||
undefined,
|
||||
" a, b , c, d",
|
||||
@@ -230,7 +235,8 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"With queries combining",
|
||||
undefined,
|
||||
" + a, b , c, d ",
|
||||
@@ -243,7 +249,8 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"With packs",
|
||||
" codeql/a , codeql/b , codeql/c , codeql/d ",
|
||||
undefined,
|
||||
@@ -255,7 +262,8 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"With packs combining",
|
||||
" + codeql/a, codeql/b, codeql/c, codeql/d",
|
||||
undefined,
|
||||
@@ -268,7 +276,8 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"With repo property queries",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -285,7 +294,8 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
calculateAugmentationMacro(
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
"With repo property queries combining",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -302,9 +312,10 @@ calculateAugmentationMacro(
|
||||
},
|
||||
);
|
||||
|
||||
const calculateAugmentationErrorMacro = makeMacro({
|
||||
const calculateAugmentationErrorMacro = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
rawPacksInput: string | undefined,
|
||||
rawQueriesInput: string | undefined,
|
||||
languages: Language[],
|
||||
@@ -322,10 +333,11 @@ const calculateAugmentationErrorMacro = makeMacro({
|
||||
{ message: expectedError },
|
||||
);
|
||||
},
|
||||
title: (title) => `Calculate Augmentation Error: ${title}`,
|
||||
title: (_, title) => `Calculate Augmentation Error: ${title}`,
|
||||
});
|
||||
|
||||
calculateAugmentationErrorMacro(
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
"Plus (+) with nothing else (queries)",
|
||||
undefined,
|
||||
" + ",
|
||||
@@ -334,7 +346,8 @@ calculateAugmentationErrorMacro(
|
||||
/The workflow property "queries" is invalid/,
|
||||
);
|
||||
|
||||
calculateAugmentationErrorMacro(
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
"Plus (+) with nothing else (packs)",
|
||||
" + ",
|
||||
undefined,
|
||||
@@ -343,7 +356,8 @@ calculateAugmentationErrorMacro(
|
||||
/The workflow property "packs" is invalid/,
|
||||
);
|
||||
|
||||
calculateAugmentationErrorMacro(
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
"Plus (+) with nothing else (repo property queries)",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -354,7 +368,8 @@ calculateAugmentationErrorMacro(
|
||||
/The repository property "github-codeql-extra-queries" is invalid/,
|
||||
);
|
||||
|
||||
calculateAugmentationErrorMacro(
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
"Packs input with multiple languages",
|
||||
" + a/b, c/d ",
|
||||
undefined,
|
||||
@@ -363,7 +378,8 @@ calculateAugmentationErrorMacro(
|
||||
/Cannot specify a 'packs' input in a multi-language analysis/,
|
||||
);
|
||||
|
||||
calculateAugmentationErrorMacro(
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
"Packs input with no languages",
|
||||
" + a/b, c/d ",
|
||||
undefined,
|
||||
@@ -372,7 +388,8 @@ calculateAugmentationErrorMacro(
|
||||
/No languages specified/,
|
||||
);
|
||||
|
||||
calculateAugmentationErrorMacro(
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
"Invalid packs",
|
||||
" a-pack-without-a-scope ",
|
||||
undefined,
|
||||
|
||||
@@ -263,7 +263,7 @@ export function getArtifactSuffix(matrix: string | undefined): string {
|
||||
try {
|
||||
const matrixObject = JSON.parse(matrix);
|
||||
if (json.isObject(matrixObject)) {
|
||||
for (const matrixKey of Object.keys(matrixObject).sort())
|
||||
for (const matrixKey of Object.keys(matrixObject as object).sort())
|
||||
suffix += `-${matrixObject[matrixKey]}`;
|
||||
} else {
|
||||
core.warning("User-specified `matrix` input is not an object.");
|
||||
|
||||
+4
-4
@@ -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.2",
|
||||
"cliVersion": "2.25.2",
|
||||
"priorBundleVersion": "codeql-bundle-v2.25.1",
|
||||
"priorCliVersion": "2.25.1"
|
||||
}
|
||||
|
||||
+2
-17
@@ -72,13 +72,6 @@ let unwrittenDiagnostics: UnwrittenDiagnostic[] = [];
|
||||
*/
|
||||
let unwrittenDefaultLanguageDiagnostics: DiagnosticMessage[] = [];
|
||||
|
||||
/**
|
||||
* Counter used to generate a unique suffix for each diagnostic filename, so that
|
||||
* two diagnostics produced within the same millisecond do not overwrite each
|
||||
* other on disk.
|
||||
*/
|
||||
let diagnosticCounter = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new diagnostic message with the specified id and name, as well as optional additional data.
|
||||
*
|
||||
@@ -174,18 +167,10 @@ function writeDiagnostic(
|
||||
// Create the directory if it doesn't exist yet.
|
||||
mkdirSync(diagnosticsPath, { recursive: true });
|
||||
|
||||
// Include a monotonically increasing suffix to avoid filename collisions
|
||||
// between diagnostics produced within the same millisecond.
|
||||
const uniqueSuffix = (diagnosticCounter++).toString();
|
||||
// We should only need to remove colons, but to be defensive, only allow a restricted set of
|
||||
// characters.
|
||||
const sanitizedTimestamp = diagnostic.timestamp.replace(
|
||||
/[^a-zA-Z0-9.-]/g,
|
||||
"",
|
||||
);
|
||||
const jsonPath = path.resolve(
|
||||
diagnosticsPath,
|
||||
`codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json`,
|
||||
// Remove colons from the timestamp as these are not allowed in Windows filenames.
|
||||
`codeql-action-${diagnostic.timestamp.replaceAll(":", "")}.json`,
|
||||
);
|
||||
|
||||
writeFileSync(jsonPath, JSON.stringify(diagnostic));
|
||||
|
||||
@@ -5,20 +5,17 @@ import * as actionsUtil from "./actions-util";
|
||||
import type { PullRequestBranches } from "./actions-util";
|
||||
import * as apiClient from "./api-client";
|
||||
import {
|
||||
getDiffInformedAnalysisBranches,
|
||||
prepareDiffInformedAnalysis,
|
||||
shouldPerformDiffInformedAnalysis,
|
||||
exportedForTesting,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
import { Feature, initFeatures } from "./feature-flags";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { parseRepositoryNwo } from "./repository";
|
||||
import {
|
||||
setupTests,
|
||||
createFeatures,
|
||||
mockCodeQLVersion,
|
||||
mockFeatureFlagApiEndpoint,
|
||||
setupActionsVars,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { GitHubVariant, withTmpDir } from "./util";
|
||||
import type { GitHubVersion } from "./util";
|
||||
@@ -45,9 +42,10 @@ const defaultTestCase: DiffInformedAnalysisTestCase = {
|
||||
codeQLVersion: "2.21.0",
|
||||
};
|
||||
|
||||
const testShouldPerformDiffInformedAnalysis = makeMacro({
|
||||
const testShouldPerformDiffInformedAnalysis = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
partialTestCase: Partial<DiffInformedAnalysisTestCase>,
|
||||
expectedResult: boolean,
|
||||
) => {
|
||||
@@ -75,34 +73,39 @@ const testShouldPerformDiffInformedAnalysis = makeMacro({
|
||||
[Feature.DiffInformedQueries]: testCase.featureEnabled,
|
||||
});
|
||||
|
||||
sinon
|
||||
const getGitHubVersionStub = sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves(testCase.gitHubVersion);
|
||||
sinon
|
||||
const getPullRequestBranchesStub = sinon
|
||||
.stub(actionsUtil, "getPullRequestBranches")
|
||||
.returns(testCase.pullRequestBranches);
|
||||
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
const result = await shouldPerformDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(branches !== undefined, expectedResult);
|
||||
t.is(result, expectedResult);
|
||||
|
||||
delete process.env.CODEQL_ACTION_DIFF_INFORMED_QUERIES;
|
||||
|
||||
getGitHubVersionStub.restore();
|
||||
getPullRequestBranchesStub.restore();
|
||||
});
|
||||
},
|
||||
title: (title) => `getDiffInformedAnalysisBranches: ${title}`,
|
||||
title: (_, title) => `shouldPerformDiffInformedAnalysis: ${title}`,
|
||||
});
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns true in the default test case",
|
||||
{},
|
||||
true,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns false when feature flag is disabled from the API",
|
||||
{
|
||||
featureEnabled: false,
|
||||
@@ -110,7 +113,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns false when CODEQL_ACTION_DIFF_INFORMED_QUERIES is set to false",
|
||||
{
|
||||
featureEnabled: true,
|
||||
@@ -119,7 +123,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns true when CODEQL_ACTION_DIFF_INFORMED_QUERIES is set to true",
|
||||
{
|
||||
featureEnabled: false,
|
||||
@@ -128,7 +133,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
true,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns false for CodeQL version 2.20.0",
|
||||
{
|
||||
codeQLVersion: "2.20.0",
|
||||
@@ -136,7 +142,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns false for invalid GHES version",
|
||||
{
|
||||
gitHubVersion: {
|
||||
@@ -147,7 +154,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns false for GHES version 3.18.5",
|
||||
{
|
||||
gitHubVersion: {
|
||||
@@ -158,7 +166,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns true for GHES version 3.19.0",
|
||||
{
|
||||
gitHubVersion: {
|
||||
@@ -169,7 +178,8 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
true,
|
||||
);
|
||||
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
"returns false when not a pull request",
|
||||
{
|
||||
pullRequestBranches: undefined,
|
||||
@@ -177,135 +187,6 @@ testShouldPerformDiffInformedAnalysis.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns false when not a pull request",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
const features = createFeatures([Feature.DiffInformedQueries]);
|
||||
|
||||
sinon.stub(actionsUtil, "getPullRequestBranches").returns(undefined);
|
||||
sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves({ type: GitHubVariant.DOTCOM });
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.false(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns false when applicability check throws",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
// A features implementation whose getValue rejects, simulating an
|
||||
// unexpected failure when determining whether diff-informed analysis
|
||||
// should run.
|
||||
const features: FeatureEnablement = {
|
||||
getEnabledDefaultCliVersions: async () => {
|
||||
throw new Error("not implemented");
|
||||
},
|
||||
getValue: async () => {
|
||||
throw new Error("feature flag lookup failed");
|
||||
},
|
||||
};
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.false(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns true when the diff is fetched successfully",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
const features = createFeatures([Feature.DiffInformedQueries]);
|
||||
|
||||
sinon
|
||||
.stub(actionsUtil, "getPullRequestBranches")
|
||||
.returns({ base: "main", head: "feature" });
|
||||
sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves({ type: GitHubVariant.DOTCOM });
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
sinon.stub(apiClient, "getApiClient").returns({
|
||||
rest: {
|
||||
repos: {
|
||||
compareCommitsWithBasehead: sinon
|
||||
.stub()
|
||||
.resolves({ data: { files: [] } }),
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.true(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns false when the diff API call fails",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
const features = createFeatures([Feature.DiffInformedQueries]);
|
||||
|
||||
sinon
|
||||
.stub(actionsUtil, "getPullRequestBranches")
|
||||
.returns({ base: "main", head: "feature" });
|
||||
sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves({ type: GitHubVariant.DOTCOM });
|
||||
const notFoundError: any = new Error("Not Found");
|
||||
notFoundError.status = 404;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
sinon.stub(apiClient, "getApiClient").returns({
|
||||
rest: {
|
||||
repos: {
|
||||
compareCommitsWithBasehead: sinon.stub().rejects(notFoundError),
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.false(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
function runGetDiffRanges(changes: number, patch: string[] | undefined): any {
|
||||
return exportedForTesting.getDiffRanges(
|
||||
{
|
||||
|
||||
@@ -5,9 +5,9 @@ import type { PullRequestBranches } from "./actions-util";
|
||||
import { getApiClient, getGitHubVersion } from "./api-client";
|
||||
import type { CodeQL } from "./codeql";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger, withGroupAsync } from "./logging";
|
||||
import { Logger } from "./logging";
|
||||
import { getRepositoryNwoFromEnv } from "./repository";
|
||||
import { getErrorMessage, GitHubVariant, satisfiesGHESVersion } from "./util";
|
||||
import { GitHubVariant, satisfiesGHESVersion } from "./util";
|
||||
|
||||
/**
|
||||
* This interface is an abbreviated version of the file diff object returned by
|
||||
@@ -21,6 +21,20 @@ interface FileDiff {
|
||||
patch?: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the action should perform diff-informed analysis.
|
||||
*/
|
||||
export async function shouldPerformDiffInformedAnalysis(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
return (
|
||||
(await getDiffInformedAnalysisBranches(codeql, features, logger)) !==
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the branches to use for diff-informed analysis.
|
||||
*
|
||||
@@ -55,46 +69,6 @@ export async function getDiffInformedAnalysisBranches(
|
||||
return branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the diff ranges needed for diff-informed analysis for the current
|
||||
* run.
|
||||
*
|
||||
* @returns `true` if the diff ranges were successfully computed and persisted
|
||||
* and are therefore available for use, `false` otherwise.
|
||||
*/
|
||||
export async function prepareDiffInformedAnalysis(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
let branches: PullRequestBranches | undefined;
|
||||
try {
|
||||
branches = await getDiffInformedAnalysisBranches(codeql, features, logger);
|
||||
} catch (e) {
|
||||
// If we cannot determine whether diff-informed analysis applies (for
|
||||
// example, because a feature-flag lookup failed), treat it as not
|
||||
// applicable rather than triggering the overlay fallback.
|
||||
logger.warning(
|
||||
`Failed to determine branch information for diff-informed analysis: ${getErrorMessage(e)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!branches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await withGroupAsync("Computing PR diff ranges", async () => {
|
||||
try {
|
||||
return await computeAndPersistDiffRanges(branches, logger);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute diff-informed analysis ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export interface DiffThunkRange {
|
||||
/** Relative path from the repository root, using forward slashes as separators. */
|
||||
path: string;
|
||||
@@ -177,33 +151,6 @@ export async function getPullRequestEditedDiffRanges(
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and persist the diff ranges for a pull request. This fetches the
|
||||
* diff from the GitHub API and writes it to the diff ranges JSON file so that
|
||||
* CodeQL can use it for diff-informed analysis.
|
||||
*
|
||||
* @param branches The base and head branches of the pull request, as returned
|
||||
* by `getDiffInformedAnalysisBranches`.
|
||||
* @param logger
|
||||
* @returns `true` if the diff ranges were successfully computed and persisted,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
export async function computeAndPersistDiffRanges(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return false;
|
||||
}
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
|
||||
logger.info(
|
||||
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function getFileDiffsWithBasehead(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
|
||||
@@ -8,7 +8,6 @@ export enum DocUrl {
|
||||
CODEQL_BUILD_MODES = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#codeql-build-modes",
|
||||
DEFINE_ENV_VARIABLES = "https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow",
|
||||
DELETE_ACTIONS_CACHE_ENTRIES = "https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manage-caches#deleting-cache-entries",
|
||||
PRIVATE_REGISTRY_LOGS = "https://docs.github.com/en/code-security/reference/code-scanning/code-scanning-logs#diagnostic-information-for-private-package-registries",
|
||||
SCANNING_ON_PUSH = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#scanning-on-push",
|
||||
SPECIFY_BUILD_STEPS_MANUALLY = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#about-specifying-build-steps-manually",
|
||||
SYSTEM_REQUIREMENTS = "https://codeql.github.com/docs/codeql-overview/system-requirements/",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export async function run__ACTION__() {
|
||||
return await __ACTION__.runWrapper();
|
||||
}
|
||||
+12
-27
@@ -451,16 +451,12 @@ test.serial(`selects CLI from defaults.json on GHES`, async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
const features = setUpFeatureFlagTests(tmpDir);
|
||||
|
||||
const defaultCliVersion = await features.getEnabledDefaultCliVersions(
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
GitHubVariant.GHES,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -486,13 +482,10 @@ for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||
false;
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion =
|
||||
await features.getEnabledDefaultCliVersions(variant);
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
enabledVersions: [
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
{ cliVersion: "2.20.0", tagName: "codeql-bundle-v2.20.0" },
|
||||
],
|
||||
cliVersion: "2.20.1",
|
||||
tagName: "codeql-bundle-v2.20.1",
|
||||
toolsFeatureFlagsValid: true,
|
||||
});
|
||||
});
|
||||
@@ -507,15 +500,10 @@ for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||
const expectedFeatureEnablement = initializeFeatures(true);
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion =
|
||||
await features.getEnabledDefaultCliVersions(variant);
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
toolsFeatureFlagsValid: false,
|
||||
});
|
||||
});
|
||||
@@ -541,13 +529,10 @@ for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||
] = true;
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion =
|
||||
await features.getEnabledDefaultCliVersions(variant);
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
enabledVersions: [
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
{ cliVersion: "2.20.0", tagName: "codeql-bundle-v2.20.0" },
|
||||
],
|
||||
cliVersion: "2.20.1",
|
||||
tagName: "codeql-bundle-v2.20.1",
|
||||
toolsFeatureFlagsValid: true,
|
||||
});
|
||||
|
||||
|
||||
+25
-86
@@ -26,38 +26,12 @@ const DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled";
|
||||
|
||||
/**
|
||||
* The first version of the CodeQL Bundle that shipped with zstd-compressed bundles.
|
||||
*
|
||||
* This is now below the minimum version of CodeQL, but we keep this around because we currently set
|
||||
* up CodeQL before checking that the version is new enough.
|
||||
*/
|
||||
export const CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0";
|
||||
|
||||
const LINKED_CODEQL_VERSION: CodeQLVersionInfo = {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
};
|
||||
|
||||
export interface CodeQLVersionInfo {
|
||||
/** The version number of the CodeQL CLI, e.g. `2.19.0`. */
|
||||
cliVersion: string;
|
||||
/**
|
||||
* The tag name of the CodeQL Bundle associated with this version, e.g. `codeql-bundle-v2.19.0`.
|
||||
*/
|
||||
tagName: string;
|
||||
}
|
||||
|
||||
export interface CodeQLDefaultVersionInfo {
|
||||
/**
|
||||
* CodeQL CLI versions that are enabled as defaults, sorted from highest to lowest.
|
||||
*
|
||||
* Guaranteed to be non-empty. When feature flags are unavailable, this falls back to a single
|
||||
* entry containing the version pinned in `defaults.json`.
|
||||
*/
|
||||
enabledVersions: CodeQLVersionInfo[];
|
||||
/**
|
||||
* If accessed, whether the tools feature flags are valid, i.e. contain at least one enabled
|
||||
* version.
|
||||
*/
|
||||
cliVersion: string;
|
||||
tagName: string;
|
||||
toolsFeatureFlagsValid?: boolean;
|
||||
}
|
||||
|
||||
@@ -70,8 +44,6 @@ export interface CodeQLDefaultVersionInfo {
|
||||
* Legacy features should end with `_enabled`.
|
||||
*/
|
||||
export enum Feature {
|
||||
/** Controls whether we allow multiple values for the `analysis-kinds` input. */
|
||||
AllowMultipleAnalysisKinds = "allow_multiple_analysis_kinds",
|
||||
AllowToolcacheInput = "allow_toolcache_input",
|
||||
CleanupTrapCaches = "cleanup_trap_caches",
|
||||
CppDependencyInstallation = "cpp_dependency_installation_enabled",
|
||||
@@ -100,19 +72,6 @@ export enum Feature {
|
||||
OverlayAnalysisGo = "overlay_analysis_go",
|
||||
OverlayAnalysisJava = "overlay_analysis_java",
|
||||
OverlayAnalysisJavascript = "overlay_analysis_javascript",
|
||||
/**
|
||||
* When set, chooses the default CodeQL CLI version as the highest version that is both enabled by
|
||||
* feature flags and present as an overlay-base database in the Actions cache for the configured
|
||||
* languages. Falls back to the highest feature flagged version if no intersecting overlay-base
|
||||
* database exists in the cache.
|
||||
*/
|
||||
OverlayAnalysisMatchCodeqlVersion = "overlay_analysis_match_codeql_version",
|
||||
/**
|
||||
* Like `OverlayAnalysisMatchCodeqlVersion`, but only logs a diagnostic with the version that
|
||||
* would have been chosen instead of actually changing the default CodeQL CLI version.
|
||||
* `OverlayAnalysisMatchCodeqlVersion` overrides this flag.
|
||||
*/
|
||||
OverlayAnalysisMatchCodeqlVersionDryRun = "overlay_analysis_match_codeql_version_dry_run",
|
||||
OverlayAnalysisPython = "overlay_analysis_python",
|
||||
/**
|
||||
* Controls whether lower disk space requirements are used for overlay hardware checks.
|
||||
@@ -165,11 +124,6 @@ export type FeatureConfig = {
|
||||
};
|
||||
|
||||
export const featureConfig = {
|
||||
[Feature.AllowMultipleAnalysisKinds]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.AllowToolcacheInput]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT",
|
||||
@@ -323,16 +277,6 @@ export const featureConfig = {
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_DISABLE_TRAP_CACHING",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.OverlayAnalysisMatchCodeqlVersion]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_MATCH_CODEQL_VERSION",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.OverlayAnalysisMatchCodeqlVersionDryRun]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_MATCH_CODEQL_VERSION_DRY_RUN",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.OverlayAnalysisResourceChecksV2]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_RESOURCE_CHECKS_V2",
|
||||
@@ -402,12 +346,8 @@ export type FeatureWithoutCLI = {
|
||||
}[keyof typeof featureConfig];
|
||||
|
||||
export interface FeatureEnablement {
|
||||
/**
|
||||
* Returns the set of default CodeQL CLI versions to consider, sorted from
|
||||
* highest to lowest. The first entry is the version that the CodeQL Action
|
||||
* will use by default. The list is always non-empty.
|
||||
*/
|
||||
getEnabledDefaultCliVersions(
|
||||
/** Gets the default version of the CodeQL tools. */
|
||||
getDefaultCliVersion(
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo>;
|
||||
getValue(feature: FeatureWithoutCLI): Promise<boolean>;
|
||||
@@ -431,11 +371,12 @@ export const FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json";
|
||||
class OfflineFeatures implements FeatureEnablement {
|
||||
constructor(protected readonly logger: Logger) {}
|
||||
|
||||
async getEnabledDefaultCliVersions(
|
||||
async getDefaultCliVersion(
|
||||
_variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
return {
|
||||
enabledVersions: [LINKED_CODEQL_VERSION],
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -445,7 +386,7 @@ class OfflineFeatures implements FeatureEnablement {
|
||||
getFeatureConfig(feature: Feature): FeatureConfig {
|
||||
// Narrow the type to FeatureConfig to avoid type errors. To avoid unsafe use of `as`, we
|
||||
// check that the required properties exist using `satisfies`.
|
||||
return featureConfig[feature] satisfies FeatureConfig;
|
||||
return featureConfig[feature] satisfies FeatureConfig as FeatureConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -577,13 +518,13 @@ class Features extends OfflineFeatures {
|
||||
);
|
||||
}
|
||||
|
||||
async getEnabledDefaultCliVersions(
|
||||
async getDefaultCliVersion(
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
if (supportsFeatureFlags(variant)) {
|
||||
return await this.gitHubFeatureFlags.getEnabledDefaultCliVersionsFromFlags();
|
||||
return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags();
|
||||
}
|
||||
return super.getEnabledDefaultCliVersions(variant);
|
||||
return super.getDefaultCliVersion(variant);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -659,22 +600,16 @@ class GitHubFeatureFlags {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns CLI versions enabled by `default_codeql_version_*_enabled` feature
|
||||
* flags, sorted from highest to lowest. Falls back to the version pinned in
|
||||
* `defaults.json` if no such flags are enabled.
|
||||
*/
|
||||
async getEnabledDefaultCliVersionsFromFlags(): Promise<CodeQLDefaultVersionInfo> {
|
||||
async getDefaultCliVersionFromFlags(): Promise<CodeQLDefaultVersionInfo> {
|
||||
const response = await this.getAllFeatures();
|
||||
|
||||
const sortedCliVersions = Object.entries(response)
|
||||
const enabledFeatureFlagCliVersions = Object.entries(response)
|
||||
.map(([f, isEnabled]) =>
|
||||
isEnabled ? this.getCliVersionFromFeatureFlag(f) : undefined,
|
||||
)
|
||||
.filter((f): f is string => f !== undefined)
|
||||
.sort(semver.rcompare);
|
||||
.filter((f): f is string => f !== undefined);
|
||||
|
||||
if (sortedCliVersions.length === 0) {
|
||||
if (enabledFeatureFlagCliVersions.length === 0) {
|
||||
// We expect at least one default CLI version to be enabled on Dotcom at any time. However if
|
||||
// the feature flags are misconfigured, rather than crashing, we fall back to the CLI version
|
||||
// shipped with the Action in defaults.json. This has the effect of immediately rolling out
|
||||
@@ -690,7 +625,8 @@ class GitHubFeatureFlags {
|
||||
`shipped with the Action. This is ${defaults.cliVersion}.`,
|
||||
);
|
||||
const result: CodeQLDefaultVersionInfo = {
|
||||
enabledVersions: [LINKED_CODEQL_VERSION],
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
};
|
||||
if (this.hasAccessedRemoteFeatureFlags) {
|
||||
result.toolsFeatureFlagsValid = false;
|
||||
@@ -698,14 +634,17 @@ class GitHubFeatureFlags {
|
||||
return result;
|
||||
}
|
||||
|
||||
const maxCliVersion = enabledFeatureFlagCliVersions.reduce(
|
||||
(maxVersion, currentVersion) =>
|
||||
currentVersion > maxVersion ? currentVersion : maxVersion,
|
||||
enabledFeatureFlagCliVersions[0],
|
||||
);
|
||||
this.logger.debug(
|
||||
`Derived default CLI version of ${sortedCliVersions[0]} from feature flags.`,
|
||||
`Derived default CLI version of ${maxCliVersion} from feature flags.`,
|
||||
);
|
||||
return {
|
||||
enabledVersions: sortedCliVersions.map((cliVersion) => ({
|
||||
cliVersion,
|
||||
tagName: `codeql-bundle-v${cliVersion}`,
|
||||
})),
|
||||
cliVersion: maxCliVersion,
|
||||
tagName: `codeql-bundle-v${maxCliVersion}`,
|
||||
toolsFeatureFlagsValid: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@ 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: "unknown-property", value: "something" },
|
||||
] satisfies properties.GitHubPropertiesResponse,
|
||||
});
|
||||
@@ -87,7 +88,10 @@ 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",
|
||||
});
|
||||
});
|
||||
|
||||
test.serial("loadPropertiesFromApi parses true boolean property", async (t) => {
|
||||
|
||||
@@ -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,7 @@ 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",
|
||||
}
|
||||
|
||||
/** Parsed types of the known repository properties. */
|
||||
@@ -20,6 +24,7 @@ export type AllRepositoryProperties = {
|
||||
[RepositoryPropertyName.DISABLE_OVERLAY]: boolean;
|
||||
[RepositoryPropertyName.EXTRA_QUERIES]: string;
|
||||
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: boolean;
|
||||
[RepositoryPropertyName.TOOLS]: string;
|
||||
};
|
||||
|
||||
/** Parsed repository properties. */
|
||||
@@ -30,6 +35,7 @@ export type RepositoryPropertyApiType = {
|
||||
[RepositoryPropertyName.DISABLE_OVERLAY]: string;
|
||||
[RepositoryPropertyName.EXTRA_QUERIES]: string;
|
||||
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: string;
|
||||
[RepositoryPropertyName.TOOLS]: string;
|
||||
};
|
||||
|
||||
/** The type of functions which take the `value` from the API and try to convert it to the type we want. */
|
||||
@@ -77,6 +83,7 @@ const repositoryPropertyParsers: {
|
||||
[RepositoryPropertyName.DISABLE_OVERLAY]: booleanProperty,
|
||||
[RepositoryPropertyName.EXTRA_QUERIES]: stringProperty,
|
||||
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: booleanProperty,
|
||||
[RepositoryPropertyName.TOOLS]: stringProperty,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -172,6 +179,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.warning(
|
||||
`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.
|
||||
|
||||
+14
-77
@@ -33,6 +33,7 @@ test.serial(
|
||||
|
||||
const actualRef = await gitUtils.getRef();
|
||||
t.deepEqual(actualRef, expectedRef);
|
||||
callback.restore();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -53,6 +54,7 @@ test.serial(
|
||||
|
||||
const actualRef = await gitUtils.getRef();
|
||||
t.deepEqual(actualRef, expectedRef);
|
||||
callback.restore();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -71,6 +73,7 @@ test.serial(
|
||||
|
||||
const actualRef = await gitUtils.getRef();
|
||||
t.deepEqual(actualRef, "refs/pull/1/head");
|
||||
callback.restore();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -97,6 +100,8 @@ test.serial(
|
||||
|
||||
const actualRef = await gitUtils.getRef();
|
||||
t.deepEqual(actualRef, "refs/pull/2/merge");
|
||||
callback.restore();
|
||||
getAdditionalInputStub.restore();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -156,6 +161,7 @@ test.serial(
|
||||
"Both 'ref' and 'sha' are required if one of them is provided.",
|
||||
},
|
||||
);
|
||||
getAdditionalInputStub.restore();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -182,6 +188,7 @@ test.serial(
|
||||
"Both 'ref' and 'sha' are required if one of them is provided.",
|
||||
},
|
||||
);
|
||||
getAdditionalInputStub.restore();
|
||||
});
|
||||
},
|
||||
);
|
||||
@@ -235,6 +242,7 @@ test.serial("isAnalyzingDefaultBranch()", async (t) => {
|
||||
process.env["GITHUB_EVENT_NAME"] = "schedule";
|
||||
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||
t.deepEqual(await gitUtils.isAnalyzingDefaultBranch(), false);
|
||||
getAdditionalInputStub.restore();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -246,6 +254,8 @@ test.serial("determineBaseBranchHeadCommitOid non-pullrequest", async (t) => {
|
||||
const result = await gitUtils.determineBaseBranchHeadCommitOid(__dirname);
|
||||
t.deepEqual(result, undefined);
|
||||
t.deepEqual(0, infoStub.callCount);
|
||||
|
||||
infoStub.restore();
|
||||
});
|
||||
|
||||
test.serial(
|
||||
@@ -266,6 +276,8 @@ test.serial(
|
||||
"git call failed. Will calculate the base branch SHA on the server. Error: " +
|
||||
"The checkout path provided to the action does not appear to be a git repository.",
|
||||
);
|
||||
|
||||
infoStub.restore();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -289,27 +301,10 @@ test.serial("determineBaseBranchHeadCommitOid other error", async (t) => {
|
||||
"The checkout path provided to the action does not appear to be a git repository.",
|
||||
),
|
||||
);
|
||||
|
||||
infoStub.restore();
|
||||
});
|
||||
|
||||
test.serial(
|
||||
"determineBaseBranchHeadCommitOid accepts SHA-256 OIDs",
|
||||
async (t) => {
|
||||
const mergeSha = "a".repeat(64);
|
||||
const baseOid = "b".repeat(64);
|
||||
const headOid = "c".repeat(64);
|
||||
|
||||
process.env["GITHUB_EVENT_NAME"] = "pull_request";
|
||||
process.env["GITHUB_SHA"] = mergeSha;
|
||||
|
||||
sinon
|
||||
.stub(gitUtils as any, "runGitCommand")
|
||||
.resolves(`commit ${mergeSha}\nparent ${baseOid}\nparent ${headOid}\n`);
|
||||
|
||||
const result = await gitUtils.determineBaseBranchHeadCommitOid(__dirname);
|
||||
t.deepEqual(result, baseOid);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial("decodeGitFilePath unquoted strings", async (t) => {
|
||||
t.deepEqual(gitUtils.decodeGitFilePath("foo"), "foo");
|
||||
t.deepEqual(gitUtils.decodeGitFilePath("foo bar"), "foo bar");
|
||||
@@ -441,64 +436,6 @@ test.serial("getFileOidsUnderPath handles quoted paths", async (t) => {
|
||||
});
|
||||
});
|
||||
|
||||
test.serial("getFileOidsUnderPath handles SHA-256 OIDs", async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
const sha256OidA =
|
||||
"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2c0d4b7e8f9a1234567890ab";
|
||||
const sha256OidB =
|
||||
"aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899";
|
||||
|
||||
sinon
|
||||
.stub(gitUtils as any, "runGitCommand")
|
||||
.callsFake(async (_cwd: any, args: any) => {
|
||||
if (args[0] === "rev-parse") {
|
||||
return `${tmpDir}\n`;
|
||||
}
|
||||
return (
|
||||
`100644 ${sha256OidA} 0\tlib/sha256-file-a.js\n` +
|
||||
`100644 ${sha256OidB} 0\tsrc/sha256-file-b.ts`
|
||||
);
|
||||
});
|
||||
|
||||
const result = await gitUtils.getFileOidsUnderPath("/fake/path");
|
||||
|
||||
t.deepEqual(result, {
|
||||
"lib/sha256-file-a.js": sha256OidA,
|
||||
"src/sha256-file-b.ts": sha256OidB,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.serial(
|
||||
"getFileOidsUnderPath rejects OIDs of unsupported length",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
// 50-char OID: not a valid SHA-1 (40) or SHA-256 (64) length. The regex
|
||||
// must not accept this even though every character is a valid hex digit.
|
||||
const invalidLine =
|
||||
"100644 30d998ded095371488be3a729eb61d86ed721a1830d998ded0 0\tlib/bad.js";
|
||||
sinon
|
||||
.stub(gitUtils as any, "runGitCommand")
|
||||
.callsFake(async (_cwd: any, args: any) => {
|
||||
if (args[0] === "rev-parse") {
|
||||
return `${tmpDir}\n`;
|
||||
}
|
||||
return invalidLine;
|
||||
});
|
||||
|
||||
await t.throwsAsync(
|
||||
async () => {
|
||||
await gitUtils.getFileOidsUnderPath("/fake/path");
|
||||
},
|
||||
{
|
||||
instanceOf: Error,
|
||||
message: `Unexpected "git ls-files" output: ${invalidLine}`,
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial("getFileOidsUnderPath handles empty output", async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
sinon
|
||||
|
||||
+4
-6
@@ -163,12 +163,11 @@ export const determineBaseBranchHeadCommitOid = async function (
|
||||
}
|
||||
}
|
||||
|
||||
// Let's confirm our assumptions: We had a merge commit and the parsed parent
|
||||
// data looks correct. OIDs are either 40 (SHA-1) or 64 (SHA-256) hex characters.
|
||||
// Let's confirm our assumptions: We had a merge commit and the parsed parent data looks correct
|
||||
if (
|
||||
commitOid === mergeSha &&
|
||||
(headOid.length === 40 || headOid.length === 64) &&
|
||||
(baseOid.length === 40 || baseOid.length === 64)
|
||||
headOid.length === 40 &&
|
||||
baseOid.length === 40
|
||||
) {
|
||||
return baseOid;
|
||||
}
|
||||
@@ -297,8 +296,7 @@ export const getFileOidsUnderPath = async function (
|
||||
// 100644 4c51bc1d9e86cd86e01b0f340cb8ce095c33b283 0\tsrc/git-utils.test.ts
|
||||
// 100644 6b792ea543ce75d7a8a03df591e3c85311ecb64f 0\tsrc/git-utils.ts
|
||||
// The fields are: <mode> <oid> <stage>\t<path>
|
||||
// The OID is either 40 (SHA-1) or 64 (SHA-256) hex characters.
|
||||
const regex = /^[0-9]+ ([0-9a-f]{40}|[0-9a-f]{64}) [0-9]+\t(.+)$/;
|
||||
const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/;
|
||||
for (const line of stdout.split("\n")) {
|
||||
if (line) {
|
||||
const match = line.match(regex);
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
createFeatures,
|
||||
createTestConfig,
|
||||
DEFAULT_ACTIONS_VARS,
|
||||
makeMacro,
|
||||
makeVersionInfo,
|
||||
RecordingLogger,
|
||||
setupActionsVars,
|
||||
@@ -602,7 +601,7 @@ async function testFailedSarifUpload(
|
||||
uploadFiles.resolves({
|
||||
sarifID: "42",
|
||||
statusReport: { raw_upload_size_bytes: 20, zipped_upload_size_bytes: 10 },
|
||||
});
|
||||
} as uploadLib.UploadResult);
|
||||
const waitForProcessing = sinon.stub(uploadLib, "waitForProcessing");
|
||||
|
||||
const features = [] as Feature[];
|
||||
@@ -797,7 +796,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
const skippedUploadTest = makeMacro({
|
||||
const skippedUploadTest = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
config: Partial<configUtils.Config>,
|
||||
@@ -824,8 +823,9 @@ const skippedUploadTest = makeMacro({
|
||||
`tryUploadSarifIfRunFailed - skips upload ${providedTitle}`,
|
||||
});
|
||||
|
||||
skippedUploadTest.serial(
|
||||
test.serial(
|
||||
"without CodeQL command",
|
||||
skippedUploadTest,
|
||||
// No codeQLCmd
|
||||
{
|
||||
analysisKinds: [AnalysisKind.RiskAssessment],
|
||||
@@ -834,8 +834,9 @@ skippedUploadTest.serial(
|
||||
"CodeQL command not found",
|
||||
);
|
||||
|
||||
skippedUploadTest.serial(
|
||||
test.serial(
|
||||
"if no language is configured",
|
||||
skippedUploadTest,
|
||||
// No explicit language configuration
|
||||
{
|
||||
analysisKinds: [AnalysisKind.RiskAssessment],
|
||||
@@ -844,8 +845,9 @@ skippedUploadTest.serial(
|
||||
"Unexpectedly, the configuration is not for a single language.",
|
||||
);
|
||||
|
||||
skippedUploadTest.serial(
|
||||
test.serial(
|
||||
"if multiple languages is configured",
|
||||
skippedUploadTest,
|
||||
// Multiple explicit languages configured
|
||||
{
|
||||
analysisKinds: [AnalysisKind.RiskAssessment],
|
||||
|
||||
@@ -207,7 +207,7 @@ function getJobStatusFromEnvironment(): JobStatus | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function runWrapper() {
|
||||
async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -222,3 +222,5 @@ export async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+72
-67
@@ -2,7 +2,6 @@ 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";
|
||||
@@ -37,12 +36,14 @@ import {
|
||||
makeDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import {
|
||||
getDiffInformedAnalysisBranches,
|
||||
getPullRequestEditedDiffRanges,
|
||||
writeDiffRangesJsonFile,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
import {
|
||||
loadPropertiesFromApi,
|
||||
RepositoryProperties,
|
||||
} from "./feature-flags/properties";
|
||||
import { loadRepositoryProperties } from "./feature-flags/properties";
|
||||
import {
|
||||
checkInstallPython311,
|
||||
checkPacksForOverlayCompatibility,
|
||||
@@ -60,7 +61,8 @@ import {
|
||||
OverlayBaseDatabaseDownloadStats,
|
||||
} from "./overlay/caching";
|
||||
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
|
||||
import { getRepositoryNwo, RepositoryNwo } from "./repository";
|
||||
import { getRepositoryNwo } from "./repository";
|
||||
import { resolveToolsInput } from "./resolve-tools-input";
|
||||
import { ToolsSource } from "./setup-codeql";
|
||||
import {
|
||||
ActionName,
|
||||
@@ -93,10 +95,7 @@ import {
|
||||
checkActionVersion,
|
||||
getErrorMessage,
|
||||
BuildMode,
|
||||
Result,
|
||||
getOptionalEnvVar,
|
||||
Success,
|
||||
Failure,
|
||||
} from "./util";
|
||||
import { checkWorkflow } from "./workflow";
|
||||
|
||||
@@ -140,6 +139,7 @@ async function sendCompletedStatusReport(
|
||||
toolsFeatureFlagsValid: boolean | undefined,
|
||||
toolsSource: ToolsSource,
|
||||
toolsVersion: string,
|
||||
effectiveToolsInput: string | undefined,
|
||||
overlayBaseDatabaseStats: OverlayBaseDatabaseDownloadStats | undefined,
|
||||
dependencyCachingResults: DependencyCacheRestoreStatusReport | undefined,
|
||||
logger: Logger,
|
||||
@@ -165,6 +165,7 @@ async function sendCompletedStatusReport(
|
||||
const initStatusReport: InitStatusReport = {
|
||||
...statusReportBase,
|
||||
tools_input: getOptionalInput("tools") || "",
|
||||
computed_tools_input: effectiveToolsInput || "",
|
||||
tools_resolved_version: toolsVersion,
|
||||
tools_source: toolsSource || ToolsSource.Unknown,
|
||||
workflow_languages: workflowLanguages || "",
|
||||
@@ -219,6 +220,7 @@ async function run(startedAt: Date) {
|
||||
let toolsSource: ToolsSource;
|
||||
let toolsVersion: string;
|
||||
let zstdAvailability: ZstdAvailability | undefined;
|
||||
let effectiveToolsInput: string | undefined;
|
||||
|
||||
try {
|
||||
initializeEnvironment(getActionVersion());
|
||||
@@ -276,7 +278,7 @@ async function run(startedAt: Date) {
|
||||
// successful, the results are cached so that we don't duplicate the work in normal runs.
|
||||
let analysisKinds: AnalysisKind[] | undefined;
|
||||
try {
|
||||
analysisKinds = await getAnalysisKinds(logger, features);
|
||||
analysisKinds = await getAnalysisKinds(logger);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
`Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}`,
|
||||
@@ -293,23 +295,22 @@ async function run(startedAt: Date) {
|
||||
);
|
||||
}
|
||||
|
||||
const codeQLDefaultVersionInfo =
|
||||
await features.getEnabledDefaultCliVersions(gitHubVersion.type);
|
||||
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
|
||||
const rawLanguages = configUtils.getRawLanguagesNoAutodetect(
|
||||
getOptionalInput("languages"),
|
||||
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
|
||||
gitHubVersion.type,
|
||||
);
|
||||
const useOverlayAwareDefaultCliVersion =
|
||||
analysisKinds?.length === 1 &&
|
||||
analysisKinds[0] === AnalysisKind.CodeScanning;
|
||||
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).
|
||||
effectiveToolsInput = await resolveToolsInput(repositoryNwo, logger);
|
||||
|
||||
const initCodeQLResult = await initCodeQL(
|
||||
getOptionalInput("tools"),
|
||||
effectiveToolsInput,
|
||||
apiDetails,
|
||||
getTemporaryDirectory(),
|
||||
gitHubVersion.type,
|
||||
codeQLDefaultVersionInfo,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
@@ -348,7 +349,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
analysisKinds = await getAnalysisKinds(logger, features);
|
||||
analysisKinds = await getAnalysisKinds(logger);
|
||||
const debugMode = getOptionalInput("debug") === "true" || core.isDebug();
|
||||
const repositoryProperties = repositoryPropertiesResult.orElse({});
|
||||
const fileCoverageResult = await getFileCoverageInformationEnabled(
|
||||
@@ -429,6 +430,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
|
||||
await checkInstallPython311(config.languages, codeql);
|
||||
await computeAndPersistDiffRanges(codeql, features, logger);
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
core.setFailed(error.message);
|
||||
@@ -466,23 +468,18 @@ async function run(startedAt: Date) {
|
||||
// necessary preparations. So, in that mode, we would assume that
|
||||
// everything is in order and let the analysis fail if that turns out not
|
||||
// to be the case.
|
||||
await withGroupAsync(
|
||||
"Checking cache for overlay-base database",
|
||||
async () => {
|
||||
overlayBaseDatabaseStats = await downloadOverlayBaseDatabaseFromCache(
|
||||
codeql,
|
||||
config,
|
||||
logger,
|
||||
);
|
||||
if (!overlayBaseDatabaseStats) {
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
logger.info(
|
||||
"No overlay-base database found in cache, " +
|
||||
`reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
|
||||
);
|
||||
}
|
||||
},
|
||||
overlayBaseDatabaseStats = await downloadOverlayBaseDatabaseFromCache(
|
||||
codeql,
|
||||
config,
|
||||
logger,
|
||||
);
|
||||
if (!overlayBaseDatabaseStats) {
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
logger.info(
|
||||
"No overlay-base database found in cache, " +
|
||||
`reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.overlayDatabaseMode !== OverlayDatabaseMode.Overlay) {
|
||||
@@ -769,6 +766,7 @@ async function run(startedAt: Date) {
|
||||
toolsFeatureFlagsValid,
|
||||
toolsSource,
|
||||
toolsVersion,
|
||||
effectiveToolsInput,
|
||||
overlayBaseDatabaseStats,
|
||||
dependencyCachingStatus,
|
||||
logger,
|
||||
@@ -786,6 +784,7 @@ async function run(startedAt: Date) {
|
||||
toolsFeatureFlagsValid,
|
||||
toolsSource,
|
||||
toolsVersion,
|
||||
effectiveToolsInput,
|
||||
overlayBaseDatabaseStats,
|
||||
dependencyCachingStatus,
|
||||
logger,
|
||||
@@ -793,37 +792,41 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads [repository properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) if applicable.
|
||||
* Compute and persist diff ranges when diff-informed analysis is enabled
|
||||
* (feature flag + PR context). This writes the standard pr-diff-range.json
|
||||
* file for later reuse in the analyze step. Failures are logged but non-fatal.
|
||||
*/
|
||||
async function loadRepositoryProperties(
|
||||
repositoryNwo: RepositoryNwo,
|
||||
async function computeAndPersistDiffRanges(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
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);
|
||||
}
|
||||
): Promise<void> {
|
||||
await withGroupAsync("Computing PR diff ranges", async () => {
|
||||
try {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
if (!branches) {
|
||||
return;
|
||||
}
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return;
|
||||
}
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
|
||||
logger.info(
|
||||
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
|
||||
);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute and persist PR diff ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function recordZstdAvailability(
|
||||
config: configUtils.Config,
|
||||
zstdAvailability: ZstdAvailability,
|
||||
@@ -838,7 +841,7 @@ async function recordZstdAvailability(
|
||||
);
|
||||
}
|
||||
|
||||
export async function runWrapper() {
|
||||
async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -854,3 +857,5 @@ export async function runWrapper() {
|
||||
}
|
||||
await checkForTimeout();
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+27
-15
@@ -22,7 +22,6 @@ import {
|
||||
createTestConfig,
|
||||
getRecordingLogger,
|
||||
setupTests,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { ConfigurationError, withTmpDir } from "./util";
|
||||
|
||||
@@ -159,9 +158,10 @@ type PackInfo = {
|
||||
qlpackFileName?: string;
|
||||
};
|
||||
|
||||
const testCheckPacksForOverlayCompatibility = makeMacro({
|
||||
const testCheckPacksForOverlayCompatibility = test.macro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
{
|
||||
cliOverlayVersion,
|
||||
languages,
|
||||
@@ -234,10 +234,11 @@ const testCheckPacksForOverlayCompatibility = makeMacro({
|
||||
);
|
||||
});
|
||||
},
|
||||
title: (title) => `checkPacksForOverlayCompatibility: ${title}`,
|
||||
title: (_, title) => `checkPacksForOverlayCompatibility: ${title}`,
|
||||
});
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns false when CLI does not support overlay",
|
||||
{
|
||||
cliOverlayVersion: undefined,
|
||||
@@ -252,7 +253,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns true when there are no query packs",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -262,7 +264,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns true when query pack has not been compiled",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -278,7 +281,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns true when query pack has expected overlay version",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -293,7 +297,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns true when query packs for all languages to analyze are compatible",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -312,7 +317,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns true when query pack for a language not analyzed is incompatible",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -331,7 +337,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns false when query pack for a language to analyze is incompatible",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -350,7 +357,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns false when query pack is missing .packinfo",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -369,7 +377,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns false when query pack has different overlay version",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -388,7 +397,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns false when query pack is missing overlayVersion in .packinfo",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -407,7 +417,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns false when .packinfo is not valid JSON",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -426,7 +437,8 @@ testCheckPacksForOverlayCompatibility(
|
||||
},
|
||||
);
|
||||
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
"returns true when query pack uses codeql-pack.yml filename",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
|
||||
@@ -39,8 +39,6 @@ export async function initCodeQL(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
@@ -63,8 +61,6 @@ export async function initCodeQL(
|
||||
tempDir,
|
||||
variant,
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
true,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user