Skip to content

[improve][ci] Start CodeQL without waiting for the unit tests - #27344

Merged
lhotari merged 1 commit into
apache:masterfrom
merlimat:mmerli/codeql-no-unit-test-wait
Nov 4, 2026
Merged

lhotari merged 1 commit into
apache:masterfrom
merlimat:mmerli/codeql-no-unit-test-wait

Conversation

@merlimat

@merlimat merlimat commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Motivation

Run CodeQL Analysis has needs: ['preconditions', 'unit-tests'], so it starts when the last unit-test job ends, then
runs for 6–18 min (a median of 12 on PRs last week). It runs on master runs and on PRs to master that change
src/main/java, and on those it is usually the last job:

Run Last other job ends CodeQL runs Run ends Without the wait
PR #27320, 41555390454 +32.5 min (Broker Group 1) +32.5 → +47.2 +47.3 +32.5
Scheduled, JDK 21, 41587218802 +40.9 (Broker Group 1) +41.0 → +58.6 +59.1 +40.9
Scheduled, JDK 25, 41634315240 +39.5 (System - Pulsar Connectors - Process) +34.9 → +51.0 +52.2 +39.5

Times are from the run's first job. Test-only PRs skip CodeQL, which is why their runs end sooner. Over the 110 PR runs
of 27 Oct – 3 Nov where CodeQL ran in the first attempt, starting it after Preconditions would have ended them a median
8.1 min sooner (p25 3.2, p75 13.7). 18 of them would have ended at the same time, because another job ended last.

The job uses nothing from the unit tests. Since #25932 it analyzes with build-mode: none: it reads the sources and
runs Gradle only to resolve dependencies, without the build job's outputs or the tests' results. The wait came with
#22132 (Feb 2024), when the job ran its own Maven build and the other secondary jobs were held back the same way: macos-build
and owasp-dep-check waited for the integration tests. The Gradle migration (#25398) already moved macos-build to
start after the build job.

Modifications

  • The codeql job needs only preconditions, with a comment saying why. Its if is unchanged, so it still runs only
    on master runs and on PRs to master that change **/src/main/java/**/*.java.

Nothing depends on the order. Pulsar CI checks completed, the only required check on master, lists codeql and
unit-tests in its own needs and still requires the unit tests to succeed and CodeQL to succeed or be skipped. The
SARIF upload goes to code scanning for the run's ref and reads no other job's output.

Trade-off

From the 374 PR runs of 27 Oct – 3 Nov, 250 of them on PRs that CodeQL applies to:

  • CodeQL also runs when the build or the tests fail. Before, it was skipped there. In 30 of the 250 runs, the first
    attempt failed in the unit tests (28) or the build (2) and wasn't re-run to a pass, so CodeQL never ran. Running it
    there would have cost 351 runner-minutes for the week: 20 % more than CodeQL used (1,788), and 0.24 % of the
    145,457 runner-minutes of all jobs in these runs.
  • A re-run of failed jobs no longer waits for CodeQL. CodeQL passed in the first attempt, so the re-run doesn't run
    it again. Before, 10 re-runs of failed unit test jobs ran CodeQL after their tests, a median 8.8 min more each.
  • A failed job can be re-run sooner. GitHub re-runs failed jobs only once every job of the run has ended. When an
    integration or system test job failed and the unit tests passed, the run stayed open until CodeQL ended.
  • One more job runs at a time. CodeQL runs alongside the build job and the first test jobs instead of after the
    unit tests; the number of jobs is the same. In the three runs above, the most jobs running at once (when the
    integration and system matrices overlap the unit tests) would go from 31, 28 and 25 to 32, 29 and 25.
  • When the build fails, Pulsar CI checks completed reports once CodeQL ends, up to ~10 min later. The failed build
    job shows right away.
  • CodeQL restores a different Gradle home on a PR's first run. It now starts before the run's own jobs save one, so
    it takes master's newest, as the build job does. Its Gradle step only resolves dependencies (1.0–1.8 min).

The alternative is needs: ['preconditions', 'build-and-license-check']. It skips CodeQL when the build fails, but the
build failed in only 2 of those first attempts, so it would have saved 23 of the 351 runner-minutes. In exchange,
CodeQL starts 8–13 min later and has less room before the last test job: over the 110 runs, it would end at least
7.6 min (median 30.5) before it, against 17.4 (median 42.5) when it starts after Preconditions. Neither would make
CodeQL the last job today. But it runs for up to 18 min plus queueing, and the slowest unit test jobs are getting
shorter, so after the build it would soon be last again. That's why this PR starts it after Preconditions.

Verifying this change

  • Make sure that the change passes the CI checks.

  • actionlint reports the same 17 findings before and after the change, all shellcheck notes on other jobs' scripts.

  • This PR changes no src/main/java file, so its own run skips CodeQL. The first scheduled master run after it should
    start CodeQL right after Preconditions and end before the last test job.

Does this pull request potentially affect one of the following parts:

If the box was checked, please highlight the changes

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

The CodeQL job analyzes with build-mode: none, so it reads the sources and
uses neither the build outputs nor the test results. Waiting for every unit
test job made its 13-18 min start after the slowest one, at the end of every
master run and of every PR run that changes Java main code. It now starts
after Preconditions; its condition is unchanged.

@codelipenghui codelipenghui left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review approval for commit 04bc2df.

Summary:

No actionable findings identified within the reviewed scope.

The approach is sound: CodeQL can run independently after Preconditions, while the final CI gate continues to enforce test results. Extra runner consumption and potentially later aggregate failure reporting are documented tradeoffs. Recommend approval; live validation of the new scheduling remains outstanding.

@lhotari
lhotari merged commit 11a7a43 into apache:master Nov 4, 2026
48 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants