Skip to content

Add custom path state search queries for languages beyond C++ #65

Add custom path state search queries for languages beyond C++

Add custom path state search queries for languages beyond C++ #65

name: Build CodeQL Packs
on:
pull_request:
branches: [ main ]
workflow_dispatch:
jobs:
compile-and-test:
name: Compile and Test CodeQL Packs
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [ 'common', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
steps:
- uses: actions/checkout@v4
- name: Setup CodeQL
id: install-codeql
uses: ./.github/actions/install-codeql
- name: Install CodeQL packs
uses: ./.github/actions/install-codeql-packs
with:
cli_path: ${{ github.workspace }}/codeql_home/codeql
language: ${{ matrix.language }}
- name: Pre-Compile Queries
id: pre-compile-queries
if: ${{ matrix.language != 'common' }}
run: |
${{ github.workspace }}/codeql_home/codeql/codeql query compile --threads 0 ${{ matrix.language }}
- name: Test Queries
env:
RUNNER_TEMP: ${{ runner.temp }}
shell: python
run: |
import os
import sys
import subprocess
from pathlib import Path
def print_error(fmt, *args):
print(f"::error::{fmt}", *args)
def print_error_and_fail(fmt, *args):
print_error(fmt, args)
sys.exit(1)
runner_temp = os.environ['RUNNER_TEMP']
if '${{ matrix.language }}' == 'common':
test_root = Path('${{ github.workspace }}', 'test')
else:
test_root = Path('${{ github.workspace }}', '${{ matrix.language }}', 'test')
print(f"Executing tests found (recursively) in the directory '{test_root}'")
files_to_close = []
try:
# Runners have 4 cores, so split the tests into 4 "slices", and run one per thread
num_slices = 4
procs = []
for slice in range(1, num_slices+1):
test_report_path = os.path.join(runner_temp, "${{ matrix.language }}", f"test_report_slice_{slice}_of_{num_slices}.json")
os.makedirs(os.path.dirname(test_report_path), exist_ok=True)
test_report_file = open(test_report_path, 'w')
files_to_close.append(test_report_file)
procs.append(subprocess.Popen(["codeql", "test", "run", "--failing-exitcode=122", f"--slice={slice}/{num_slices}", "--ram=2048", "--format=json", test_root], stdout=test_report_file, stderr=subprocess.PIPE))
for p in procs:
_, err = p.communicate()
if p.returncode != 0:
if p.returncode == 122:
# Failed because a test case failed, so just print the regular output.
# This will allow us to proceed to validate-test-results, which will fail if
# any test cases failed
print(f"{err.decode()}")
else:
# Some more serious problem occurred, so print and fail fast
print_error_and_fail(f"Failed to run tests with return code {p.returncode}\n{err.decode()}")
finally:
for file in files_to_close:
file.close()
- name: Upload test results
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.language }}-test-results
path: |
${{ runner.temp }}/${{ matrix.language }}/test_report_slice_*.json
if-no-files-found: error
validate-test-results:
name: Validate test results
needs: compile-and-test
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- name: Check if compile-and-test job failed to complete, if so fail
if: ${{ needs.compile-and-test.result == 'failure' }}
uses: actions/github-script@v7
with:
script: |
core.setFailed('Test run job failed')
- name: Collect test results
uses: actions/download-artifact@v4
- name: Validate test results
run: |
if [[ ! -n "$(find . -name 'test_report_*' -print -quit)" ]]; then
echo "No test results found"
exit 0
fi
for json_report in *-test-results/test_report_*
do
jq --raw-output '"PASS \(map(select(.pass == true)) | length)/\(length)'" $json_report\"" "$json_report"
done
FAILING_TESTS=$(jq --raw-output '.[] | select(.pass == false)' *-test-results/test_report_*.json)
if [[ ! -z "$FAILING_TESTS" ]]; then
echo "ERROR: The following tests failed:"
echo $FAILING_TESTS | jq .
exit 1
fi