From 7fdf887747fc252cddecaf38eccbe70e5bff907f Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Tue, 23 Jun 2026 15:15:14 +0200 Subject: [PATCH 1/5] [CI] Prepare build_root.py for running without checkout. For some builds such as doxygen, it's sufficient to take the source directory prepared by the checkout action. Therefore, a --source_dir argument has been added to the script, which simply picks up the source directory without any checkouts or rebases. --- .../workflows/root-ci-config/build_root.py | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/root-ci-config/build_root.py b/.github/workflows/root-ci-config/build_root.py index b3dff0ad1ae20..3f5da7788269d 100755 --- a/.github/workflows/root-ci-config/build_root.py +++ b/.github/workflows/root-ci-config/build_root.py @@ -150,7 +150,8 @@ def main(): build_utils.print_warning(f'Failed to download: {err}') args.incremental = False - git_pull("src", args.repository, args.base_ref) + if not args.source_dir: + git_pull("src", args.repository, args.base_ref) benchmark: bool = 'rootbench' in options_dict and options_dict['rootbench'] == "ON" if benchmark: @@ -173,7 +174,10 @@ def main(): # Delete all the .gcda files produced by an artifact. build_utils.remove_file_match_ext(WORKDIR, "gcda") - build(options, args.buildtype) + if args.source_dir: + build(options, build_type=args.buildtype, source_dir=args.source_dir) + else: + build(options, build_type=args.buildtype) # Done before anything else touches the build tree, and reported only at the # very end so that a spurious rebuild does not cost us the test results. @@ -244,6 +248,7 @@ def parse_args(): parser.add_argument("--pull_repository", default="", help="Url to the pull request incoming repository") parser.add_argument("--head_ref", default=None, help="Ref to feature branch; it may contain a : part") parser.add_argument("--head_sha", default=None, help="Sha of commit that triggered the event") + parser.add_argument("--source_dir", default=None, help="Don't check out. Just use the source dir provided here.") parser.add_argument("--binaries", default="false", help="Whether to create binary artifacts") parser.add_argument("--architecture", default=None, help="Windows only, target arch") parser.add_argument("--repository", default="https://github.com/root-project/root.git", @@ -259,7 +264,7 @@ def parse_args(): args.binaries = args.binaries.lower() in ('yes', 'true', '1', 'on') args.upload_artifacts = args.upload_artifacts.lower() in ('yes', 'true', '1', 'on') - if not args.base_ref: + if not args.base_ref and not args.source_dir: die(os.EX_USAGE, "base_ref not specified") if not args.platform_config: # If nothing special, we take the standard platform configuration, called as the platform @@ -422,8 +427,11 @@ def archive_and_upload(archive_name, prefix): @github_log_group("Configure") -def cmake_configure(options, buildtype): - srcdir = os.path.join(WORKDIR, "src") +def cmake_configure(options, **kwargs): + if "source_dir" in kwargs: + srcdir = kwargs["source_dir"] + else: + srcdir = os.path.join(WORKDIR, "src") builddir = os.path.join(WORKDIR, "build") # Add a private option to make the CI build faster by not changing the @@ -432,7 +440,7 @@ def cmake_configure(options, buildtype): options = f"{options} -DROOT_COMPILEDATA_IGNORE_BUILD_NODE_CHANGES=ON" result = subprocess_with_log(f""" - cmake -S '{srcdir}' -B '{builddir}' -DCMAKE_BUILD_TYPE={buildtype} {options} + cmake -S '{srcdir}' -B '{builddir}' -DCMAKE_BUILD_TYPE={kwargs["build_type"]} {options} """) if result != 0: @@ -501,7 +509,7 @@ def rebuild() -> int: return not touched -def build(options, buildtype): +def build(options, **kwargs): if not os.path.isdir(os.path.join(WORKDIR, "build")): builddir = os.path.join(WORKDIR, "build") result = subprocess_with_log(f"mkdir {builddir}") @@ -510,13 +518,13 @@ def build(options, buildtype): die(result, "Failed to create build directory") if not os.path.exists(os.path.join(WORKDIR, "build", "CMakeCache.txt")): - cmake_configure(options, buildtype) + cmake_configure(options, **kwargs) else: cmake_dump_config() dump_requested_config(options) - cmake_build(buildtype) + cmake_build(kwargs["build_type"]) @github_log_group("Create binary packages") From 58c3a58fa8b53c3b66ffddc7f80d65fd61442348 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 14 Sep 2026 14:39:24 +0200 Subject: [PATCH 2/5] [CI] Build pull requests directly from the checked-out repo. Skip the internal checkout and rebase, directly use the github merge commit to run a pull request. --- .github/workflows/root-ci.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/root-ci.yml b/.github/workflows/root-ci.yml index 90c7e6664bc00..be853566f75e6 100644 --- a/.github/workflows/root-ci.yml +++ b/.github/workflows/root-ci.yml @@ -498,10 +498,18 @@ jobs: echo ROOT_OBJECT_AUTO_REGISTRATION=0 >> $GITHUB_ENV; fi - - name: Checkout - uses: actions/checkout@v6 + - name: Checkout root build scripts + uses: actions/checkout@v7 with: ref: ${{ inputs.ref_name }} + sparse-checkout: .github/workflows/ + show-progress: false + + - name: Checkout root + uses: actions/checkout@v7 + with: + path: src/ + show-progress: false - name: Dump GitHub context env: @@ -538,11 +546,7 @@ jobs: --dockeropts \"$CONTAINER_OPTIONS\" --incremental $INCREMENTAL --base_ref ${{ github.base_ref }} - --sha ${{ github.sha }} - --pull_repository ${{ github.event.pull_request.head.repo.clone_url }} - --head_ref refs/pull/${{ github.event.pull_request.number }}/head:${{ github.event.pull_request.head.ref }} - --head_sha ${{ github.event.pull_request.head.sha }} - --repository ${{ github.server_url }}/${{ github.repository }} + --source_dir ${GITHUB_WORKSPACE}/src --overrides ${GLOBAL_OVERRIDES} ${OVERRIDES} " @@ -611,13 +615,13 @@ jobs: - name: Check headers if: steps.install.outcome == 'success' - run: bash test/PostInstall/check-headers.sh ${{ env.INSTALL_DIR }}/include/ + run: bash ${{ github.workspace }}/src/test/PostInstall/check-headers.sh ${{ env.INSTALL_DIR }}/include/ - name: Build post-install test project id: postInstall if: steps.install.outcome == 'success' run: | - cmake -S test/PostInstall/ -B ${{ env.POST_INSTALL_DIR }} -DCMAKE_PREFIX_PATH=${{ env.INSTALL_DIR }}; + cmake -S ${GITHUB_WORKSPACE}/src/test/PostInstall/ -B ${{ env.POST_INSTALL_DIR }} -DCMAKE_PREFIX_PATH=${{ env.INSTALL_DIR }}; cmake --build ${{ env.POST_INSTALL_DIR }}; - name: CTest in post-install test project From 7164092c3facc75ce8e48e34eb8243e50b2a3358 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 14 Sep 2026 14:56:45 +0200 Subject: [PATCH 3/5] [CI] Always configure using "cmake --fresh" The old strategy of not rerunning configure when a build directory existed can build from a stale source directory or fail to update configs. Therefore, reconfigure always using --fresh. --- .../workflows/root-ci-config/build_root.py | 27 ++----------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/.github/workflows/root-ci-config/build_root.py b/.github/workflows/root-ci-config/build_root.py index 3f5da7788269d..a4de229f4d09f 100755 --- a/.github/workflows/root-ci-config/build_root.py +++ b/.github/workflows/root-ci-config/build_root.py @@ -440,31 +440,13 @@ def cmake_configure(options, **kwargs): options = f"{options} -DROOT_COMPILEDATA_IGNORE_BUILD_NODE_CHANGES=ON" result = subprocess_with_log(f""" - cmake -S '{srcdir}' -B '{builddir}' -DCMAKE_BUILD_TYPE={kwargs["build_type"]} {options} + cmake --fresh -S '{srcdir}' -B '{builddir}' -DCMAKE_BUILD_TYPE={kwargs["build_type"]} {options} """) if result != 0: die(result, "Failed cmake generation step") -@github_log_group("Dump existing configuration") -def cmake_dump_config(): - # Print CMake cached config - srcdir = os.path.join(WORKDIR, "src") - builddir = os.path.join(WORKDIR, "build") - result = subprocess_with_log(f""" - cmake -S '{srcdir}' -B '{builddir}' -N -L - """) - - if result != 0: - die(result, "Failed cmake cache print step") - - -@github_log_group("Dump requested build configuration") -def dump_requested_config(options): - print(f"\nBUILD OPTIONS: {options}") - - def cmake_build_command(buildtype) -> str: generator_flags = "-- '-verbosity:minimal' '-consoleloggerparameters:summary'" if WINDOWS else "" parallel_jobs = "4" if WINDOWS else str(os.cpu_count()) @@ -517,12 +499,7 @@ def build(options, **kwargs): if result != 0: die(result, "Failed to create build directory") - if not os.path.exists(os.path.join(WORKDIR, "build", "CMakeCache.txt")): - cmake_configure(options, **kwargs) - else: - cmake_dump_config() - - dump_requested_config(options) + cmake_configure(options, **kwargs) cmake_build(kwargs["build_type"]) From 66b4b21547104b97690604feee52606c808e64d5 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Mon, 14 Sep 2026 15:47:50 +0200 Subject: [PATCH 4/5] [CI] Don't upload the source folder to S3. --- .github/workflows/root-ci-config/build_root.py | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/root-ci-config/build_root.py b/.github/workflows/root-ci-config/build_root.py index a4de229f4d09f..27d55287226f2 100755 --- a/.github/workflows/root-ci-config/build_root.py +++ b/.github/workflows/root-ci-config/build_root.py @@ -407,7 +407,6 @@ def archive_and_upload(archive_name, prefix): os.chdir(WORKDIR) with tarfile.open(f"{WORKDIR}/{new_archive}", "x:gz", compresslevel=COMPRESSIONLEVEL) as targz: - targz.add("src") targz.add("build") try: From cdceb03976e0b71ac6d41b8d788d0085e857bc94 Mon Sep 17 00:00:00 2001 From: Stephan Hageboeck Date: Thu, 17 Sep 2026 10:52:40 +0200 Subject: [PATCH 5/5] fixup! [CI] Build pull requests directly from the checked-out repo. --- .github/workflows/root-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/root-ci.yml b/.github/workflows/root-ci.yml index be853566f75e6..4c3c53bcae5bd 100644 --- a/.github/workflows/root-ci.yml +++ b/.github/workflows/root-ci.yml @@ -615,7 +615,7 @@ jobs: - name: Check headers if: steps.install.outcome == 'success' - run: bash ${{ github.workspace }}/src/test/PostInstall/check-headers.sh ${{ env.INSTALL_DIR }}/include/ + run: bash ${GITHUB_WORKSPACE}/src/test/PostInstall/check-headers.sh ${{ env.INSTALL_DIR }}/include/ - name: Build post-install test project id: postInstall