diff --git a/.github/workflows/rocprofiler-compute-code-coverage.yml b/.github/workflows/rocprofiler-compute-code-coverage.yml deleted file mode 100644 index cb3b32aed2..0000000000 --- a/.github/workflows/rocprofiler-compute-code-coverage.yml +++ /dev/null @@ -1,157 +0,0 @@ -name: rocprofiler-compute Code Coverage -run-name: rocprofiler-compute-code-coverage - -on: - schedule: - - cron: '0 2 * * *' - workflow_dispatch: - inputs: - runner_matrix: - description: 'Runner configuration' - required: false - type: string - -env: - ROCM_PATH: "/opt/rocm" - ROCM_VERSION: "7.0.2" - -jobs: - prepare_matrix: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.generate_matrix.outputs.matrix }} - - steps: - - name: Generate matrix - id: generate_matrix - run: | - MATRIX='[{"os-release":"22.04","gpu":"mi355","arch":"gfx950","runner":"linux-mi355-1gpu-ossci-rocm","code-name":"jammy"},{"os-release":"24.04","gpu":"mi355","arch":"gfx950","runner":"linux-mi355-1gpu-ossci-rocm","code-name":"noble"},{"os-release":"22.04","gpu":"mi325","arch":"gfx94X","runner":"linux-mi325-1gpu-ossci-rocm","code-name":"jammy"},{"os-release":"24.04","gpu":"mi325","arch":"gfx94X","runner":"linux-mi325-1gpu-ossci-rocm","code-name":"noble"}]' - - if [ -n "${{ github.event.inputs.runner_matrix }}" ]; then - MATRIX='${{ github.event.inputs.runner_matrix }}' - fi - - echo "matrix=${MATRIX}" >> $GITHUB_OUTPUT - - coverage: - name: Coverage • ${{ matrix.system.gpu }} • Ubuntu ${{ matrix.system.os-release }} - needs: prepare_matrix - strategy: - fail-fast: false - matrix: - system: ${{ fromJSON(needs.prepare_matrix.outputs.matrix) }} - runs-on: ${{ matrix.system.runner }} - env: - HIP_PLATFORM: "amd" - OMPI_ALLOW_RUN_AS_ROOT: 1 - OMPI_ALLOW_RUN_AS_ROOT_CONFIRM: 1 - permissions: - packages: read - container: - image: ghcr.io/rocm/rocprofiler-ubuntu:${{ matrix.system.os-release }}-systems-ci-${{ matrix.system.arch }} - options: - --privileged - --ipc host - --group-add video - --device /dev/kfd - --device /dev/dri - --cap-add CAP_SYS_ADMIN - - steps: - - uses: actions/checkout@v5 - with: - sparse-checkout: projects/rocprofiler-compute/ - - - name: Update system packages - run: | - apt-get update - apt-get dist-upgrade -y - echo "✅ System packages updated!" - - - name: Install amdgpu and dependencies - shell: bash - run: | - ROCM_MAJOR=$(echo ${{ env.ROCM_VERSION }} | sed 's/\./ /g' | awk '{print $1}') - ROCM_MINOR=$(echo ${{ env.ROCM_VERSION }} | sed 's/\./ /g' | awk '{print $2}') - ROCM_VERSN=$(( (${ROCM_MAJOR}*10000)+(${ROCM_MINOR}*100) )) - wget -N -P /tmp/ https://repo.radeon.com/amdgpu-install/${ROCM_MAJOR}.${ROCM_MINOR}/ubuntu/${{ matrix.system.code-name }}/amdgpu-install_${ROCM_MAJOR}.${ROCM_MINOR}.${ROCM_VERSN}-1_all.deb - apt-get install -y /tmp/amdgpu-install_${ROCM_MAJOR}.${ROCM_MINOR}.${ROCM_VERSN}-1_all.deb - apt-get update - apt install -y amd-smi-lib libdw-dev - echo "✅ amdgpu and dependencies Installed!" - - - name: Install MPI - run: | - apt install -y libopenmpi-dev - echo "✅ MPI Installed!" - - - name: Install ROCm - run: | - apt install -y rocm-dev - echo "✅ ROCm Installation Complete!" - - - name: Install Python Dependencies - working-directory: projects/rocprofiler-compute - run: | - pip install -r requirements.txt --break-system-packages --ignore-installed - pip install -r requirements-test.txt --break-system-packages --ignore-installed - echo "✅ Python dependencies installed!" - - - name: Configure, Build, Test, and Upload Coverage - id: run_coverage - timeout-minutes: 120 - working-directory: projects/rocprofiler-compute - continue-on-error: true - run: | - set -e - git config --global --add safe.directory ${GITHUB_WORKSPACE} - git config --global --add safe.directory ${PWD} - - BUILD_NAME="ROCm/rocprofiler-compute-${{ github.ref_name }}-ubuntu-${{ matrix.system.os-release }}-${{ matrix.system.gpu }}" - SITE_NAME="${{ matrix.system.runner }}" - - PATH=${{ env.ROCM_PATH }}/bin:${{ env.ROCM_PATH }}/llvm/bin:$PATH \ - LD_LIBRARY_PATH=${{ env.ROCM_PATH }}/lib:${{ env.ROCM_PATH }}/llvm/lib:$LD_LIBRARY_PATH \ - python3 ./tools/run-code-coverage.py \ - --build-name "${BUILD_NAME}" \ - --site "${SITE_NAME}" \ - --mode "Nightly" \ - --build-jobs 16 \ - --pytest-numprocs 8 \ - --install - - - name: Check Coverage Configuration - if: always() - working-directory: projects/rocprofiler-compute - run: | - echo "=== Checking Build Configuration ===" - if [ -f "build/CMakeCache.txt" ]; then - echo "CMakeCache.txt contents (relevant variables):" - grep -E "ENABLE_TESTS|ENABLE_COVERAGE|INSTALL_TESTS|PYTEST_NUMPROCS" build/CMakeCache.txt || echo "⚠️ Coverage variables not found!" - echo "" - echo "=== Checking for coverage.xml ===" - if [ -f "build/coverage.xml" ]; then - echo "✅ coverage.xml found!" - ls -lh build/coverage.xml - else - echo "❌ coverage.xml NOT found!" - fi - echo "" - echo "=== Checking CTest results ===" - if [ -f "build/Testing/Temporary/LastTest.log" ]; then - echo "Last 50 lines of test log:" - tail -n 50 build/Testing/Temporary/LastTest.log - fi - else - echo "❌ build/CMakeCache.txt not found - build may have failed!" - fi - - - name: Upload Logs on Failure - if: failure() - uses: actions/upload-artifact@v4 - with: - name: test-logs-${{ matrix.system.gpu }}-${{ matrix.system.os-release }} - path: | - projects/rocprofiler-compute/build/Testing/Temporary/LastTest*.log - projects/rocprofiler-compute/build/coverage.xml - retention-days: 7 diff --git a/.github/workflows/rocprofiler-compute-continuous-integration.yml b/.github/workflows/rocprofiler-compute-continuous-integration.yml index 224b7aab0b..1ef0669b55 100644 --- a/.github/workflows/rocprofiler-compute-continuous-integration.yml +++ b/.github/workflows/rocprofiler-compute-continuous-integration.yml @@ -5,6 +5,15 @@ on: schedule: - cron: '0 6 * * *' workflow_dispatch: + inputs: + mode: + description: 'Build mode' + required: false + default: 'continuous' + type: choice + options: + - continuous + - nightly push: branches: [ develop ] paths: @@ -49,7 +58,7 @@ jobs: id: generate_matrix working-directory: projects/rocprofiler-compute/.github run: | - if [ '${{ github.event_name }}' = 'schedule' ]; then + if [ '${{ github.event_name }}' = 'schedule' ] || [ '${{ inputs.mode }}' = 'nightly' ]; then MATRIX_CONTENT=$(cat ci-matrix.yml | yq '.matrix-ubuntu-nightly' -I=0 -o=json) else MATRIX_CONTENT=$(cat ci-matrix.yml | yq '.matrix-ubuntu-ci' -I=0 -o=json) @@ -88,17 +97,20 @@ jobs: - name: Setup Environment id: setup_env run: | - if [ '${{ github.event_name }}' = 'schedule' ]; then + if [ '${{ github.event_name }}' = 'schedule' ] || [ '${{ inputs.mode }}' = 'nightly' ]; then MODE=Nightly EXCLUDED_TESTS="" + ADD_COVERAGE="--coverage" else MODE=Continuous EXCLUDED_TESTS="test_profile_live_attach_detach" + ADD_COVERAGE="" fi echo "mode=${MODE}" >> $GITHUB_OUTPUT echo "excluded_tests=${EXCLUDED_TESTS}" >> $GITHUB_OUTPUT + echo "add_coverage=${ADD_COVERAGE}" >> $GITHUB_OUTPUT - if [ '${{ matrix.system.os-release }}' = '24.04']; then + if [ '${{ matrix.system.os-release }}' = '24.04' ]; then CODE_NAME=noble else CODE_NAME=jammy @@ -129,13 +141,21 @@ jobs: - name: Install Python Requirements working-directory: projects/rocprofiler-compute run: | - pip install -r requirements.txt --break-system-packages --ignore-installed - pip install -r requirements-test.txt --break-system-packages --ignore-installed + for i in 1 2 3; do + pip install -r requirements.txt --break-system-packages --ignore-installed --timeout 60 && break + echo "⚠️ pip install attempt $i failed, retrying..." + sleep 10 + done + for i in 1 2 3; do + pip install -r requirements-test.txt --break-system-packages --ignore-installed --timeout 60 && break + echo "⚠️ pip install attempt $i failed, retrying..." + sleep 10 + done echo "✅ pip requirements installed!" - name: Configure, Build, and Test id: test - timeout-minutes: 90 + timeout-minutes: ${{ steps.setup_env.outputs.mode == 'Nightly' && 120 || 90 }} working-directory: projects/rocprofiler-compute run: | set -e @@ -145,9 +165,11 @@ jobs: LD_LIBRARY_PATH=${{ env.ROCM_PATH }}/lib:${{ env.ROCM_PATH }}/llvm/lib:${{ env.ROCM_PATH }}/lib/rocm_sysdeps/lib:$LD_LIBRARY_PATH \ python3 ./tools/run-ci.py \ --name "ROCm/rocprofiler-compute-${{ github.ref_name }}-ubuntu-${{ matrix.system.os-release }}-${{ matrix.system.gpu }}" \ + --actor "${{ github.actor }}" \ --site ${{ matrix.system.runner }} \ --mode ${{ steps.setup_env.outputs.mode }} \ --build-jobs 16 \ + ${{ steps.setup_env.outputs.add_coverage }} \ -- \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH=${{ env.ROCM_PATH }} \ @@ -158,8 +180,14 @@ jobs: -E "${{ steps.setup_env.outputs.excluded_tests }}" - name: Output Logs - if: failure() && steps.test.outcome == 'failure' + if: failure() working-directory: projects/rocprofiler-compute run: | - echo "❌ Run Failed: Now outputting LastTest.log files for detailed logs..." - cat build/Testing/Temporary/LastTest*.log + echo "❌ Run Failed: Outputting available log files..." + for log in build/Testing/Temporary/LastTest*.log build/Testing/Temporary/LastConfigure*.log; do + if [ -f "$log" ]; then + echo "=== $log ===" + cat "$log" + fi + done + diff --git a/projects/rocprofiler-compute/tools/run-ci.py b/projects/rocprofiler-compute/tools/run-ci.py index e1733a2b7f..9bdb56c6ee 100755 --- a/projects/rocprofiler-compute/tools/run-ci.py +++ b/projects/rocprofiler-compute/tools/run-ci.py @@ -58,7 +58,12 @@ def generate_custom(args, cmake_args, ctest_args): CMAKE_CMD = which("cmake", require=True) _ = which("ctest", require=True) - NAME = re.sub(r"(.*)-([0-9]+)/merge", "PR_\\2_\\1", NAME) + # For Continuous builds transform to PR_XXXX format and include the actor + match = re.match(r"(.*)-([0-9]+)/merge(.*)", NAME) + if match and args.actor: + NAME = f"[{args.actor}] PR_{match.group(2)}_{match.group(1)}{match.group(3)}" + elif match: + NAME = f"PR_{match.group(2)}_{match.group(1)}{match.group(3)}" return f""" set(CTEST_PROJECT_NAME "rocprofiler-compute") @@ -138,7 +143,10 @@ def generate_dashboard_script(args): ctest_submit(PARTS Coverage RETURN_VALUE _submit_ret) endif() - handle_error("Testing" _test_ret) + # Report test failures but don't fail the build, post results to CDash + if(NOT ${{_test_ret}} EQUAL 0) + message(WARNING "Some tests failed (see CDash for details)") + endif() ctest_submit(PARTS Done RETURN_VALUE _submit_ret) """ @@ -167,6 +175,13 @@ def parse_cdash_args(args): parser.add_argument( "-n", "--name", help="Job name", default=None, type=str, required=True ) + parser.add_argument( + "-a", + "--actor", + help="GitHub actor/username (included in Continuous builds)", + default=None, + type=str, + ) parser.add_argument("-s", "--site", help="Site name", default=SITE, type=str) parser.add_argument( "-c", "--coverage", help="Enable code coverage", action="store_true" diff --git a/projects/rocprofiler-compute/tools/run-code-coverage.py b/projects/rocprofiler-compute/tools/run-code-coverage.py deleted file mode 100644 index 467fccdfd1..0000000000 --- a/projects/rocprofiler-compute/tools/run-code-coverage.py +++ /dev/null @@ -1,403 +0,0 @@ -#!/usr/bin/env python3 -############################################################################## -# MIT License -# -# Copyright (c) 2025 Advanced Micro Devices, Inc. All Rights Reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -############################################################################## - -import argparse -import os -import subprocess -import sys -import tempfile -from pathlib import Path - - -def detect_repo_structure(): - """Detect if in monorepo or standalone structure""" - cwd = Path.cwd() - - if "projects/rocprofiler-compute" in str(cwd): - parts = cwd.parts - idx = parts.index("rocprofiler-compute") - if idx > 0 and parts[idx - 1] == "projects": - monorepo_root = Path(*parts[: idx - 1]) - project_root = monorepo_root / "projects" / "rocprofiler-compute" - return True, monorepo_root, project_root - - if (cwd / "CMakeLists.txt").exists(): - with open(cwd / "CMakeLists.txt") as f: - content = f.read() - if ( - "project(rocprofiler-compute" in content - or "project(\n rocprofiler-compute" in content - ): - return False, None, cwd - - return False, None, cwd - - -def generate_ctest_dashboard_script(args, source_dir, binary_dir): - """ - Generate a complete CTest dashboard script that handles: - - Configuration - - Build - - Test - - Coverage - - Submit to CDash - """ - - cache_entries = [ - "CMAKE_BUILD_TYPE:STRING=Release", - f"CMAKE_PREFIX_PATH:PATH={os.environ.get('ROCM_PATH', '/opt/rocm')}", - "ENABLE_TESTS:BOOL=ON", - "INSTALL_TESTS:BOOL=ON", - "ENABLE_COVERAGE:BOOL=ON", - f"PYTEST_NUMPROCS:STRING={args.pytest_numprocs}", - ] - - test_args = "" - if args.ctest_args: - test_args = " ".join(args.ctest_args) - - # ruff: noqa - script_content = f""" -cmake_minimum_required(VERSION 3.19) - -############################################################################## -# CTest Dashboard Script for rocprofiler-compute -# Auto-generated by run-ci.py -############################################################################## - -# Dashboard configuration -set(CTEST_PROJECT_NAME "{args.project_name}") -set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") -set(CTEST_DROP_SITE_CDASH TRUE) - -# CDash submission settings -if(CMAKE_VERSION VERSION_GREATER 3.14) - set(CTEST_SUBMIT_URL "{args.submit_url}") -else() - set(CTEST_DROP_METHOD "https") - set(CTEST_DROP_SITE "{args.cdash_host}") - set(CTEST_DROP_LOCATION "{args.submit_path}") -endif() - -# Build identification -set(CTEST_SITE "{args.site}") -set(CTEST_BUILD_NAME "{args.build_name}") -set(CTEST_SOURCE_DIRECTORY "{source_dir}") -set(CTEST_BINARY_DIRECTORY "{binary_dir}") - -# Build config -set(CTEST_CMAKE_GENERATOR "Unix Makefiles") -set(CTEST_BUILD_CONFIGURATION "Release") - -# Config CMake command with all required options -set(CTEST_CONFIGURE_COMMAND "cmake -B ${{CTEST_BINARY_DIRECTORY}} ${{CTEST_SOURCE_DIRECTORY}} -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH={os.environ.get("ROCM_PATH", "/opt/rocm")} -DENABLE_TESTS=ON -DINSTALL_TESTS=ON -DENABLE_COVERAGE=ON -DPYTEST_NUMPROCS={args.pytest_numprocs}") - -message(STATUS "CMake configure command: ${{CTEST_CONFIGURE_COMMAND}}") - -message(STATUS "Starting {args.mode} dashboard...") -ctest_start({args.mode}) - -# Config step -message(STATUS "Configuring project...") -ctest_configure( - RETURN_VALUE configure_result - CAPTURE_CMAKE_ERROR configure_error -) - -if(configure_result OR configure_error) - message(WARNING "Configuration had issues but continuing...") -endif() - -# Build step -message(STATUS "Building project...") -set(CTEST_BUILD_FLAGS "-j{args.build_jobs}") -ctest_build( - TARGET {"install" if args.install else "all"} - RETURN_VALUE build_result - CAPTURE_CMAKE_ERROR build_error -) - -if(build_result OR build_error) - message(WARNING "Build had issues but continuing...") -endif() - -# Test step -message(STATUS "Running tests...") -ctest_test( - {test_args} - PARALLEL_LEVEL 1 - RETURN_VALUE test_result - CAPTURE_CMAKE_ERROR test_error -) - -if(test_result OR test_error) - message(WARNING "Some tests failed but continuing with coverage and upload...") -endif() - -# Coverage step (if coverage file exists) -set(COVERAGE_FILE "${{CTEST_BINARY_DIRECTORY}}/coverage.xml") -if(EXISTS "${{COVERAGE_FILE}}") - message(STATUS "Processing coverage data...") - - file(MAKE_DIRECTORY "${{CTEST_BINARY_DIRECTORY}}/Testing/CoverageInfo") - file(COPY "${{COVERAGE_FILE}}" - DESTINATION "${{CTEST_BINARY_DIRECTORY}}/Testing/CoverageInfo/") - - ctest_coverage( - RETURN_VALUE coverage_result - CAPTURE_CMAKE_ERROR coverage_error - ) - - if(coverage_result OR coverage_error) - message(WARNING "Coverage processing had issues but continuing...") - endif() -else() - message(STATUS "No coverage file found at ${{COVERAGE_FILE}}") - message(STATUS "Skipping coverage step") -endif() - -message(STATUS "Submitting to CDash...") -ctest_submit( - RETRY_COUNT 3 - RETRY_DELAY 5 - RETURN_VALUE submit_result - CAPTURE_CMAKE_ERROR submit_error -) - -if(submit_result OR submit_error) - message(WARNING "CDash submission encountered issues") - message(STATUS "Results available locally in: ${{CTEST_BINARY_DIRECTORY}}/Testing/") -else() - message(STATUS "Successfully submitted to CDash!") - message(STATUS "View at: {args.submit_url.replace("/submit.php?project=", "/index.php?project=")}") - message(STATUS "Build name: {args.build_name}") -endif() - -message(STATUS "") -message(STATUS "========================================") -message(STATUS "Dashboard Summary") -message(STATUS "========================================") -if(test_result) - message(STATUS "Tests: FAILED (some tests failed or timed out)") -else() - message(STATUS "Tests: PASSED") -endif() -if(submit_result OR submit_error) - message(STATUS "CDash Upload: FAILED") -else() - message(STATUS "CDash Upload: SUCCESS") -endif() -message(STATUS "========================================") - -# For nightly/continuous, don't fail on test failures -# Only warn in Experimental mode -if("{args.mode}" STREQUAL "Experimental" AND test_result) - message(WARNING "Tests failed in Experimental mode") -endif() -""" - - return script_content - - -def main(): - parser = argparse.ArgumentParser( - description="CI script for rocprofiler-compute: build, test, and upload to CDash" - ) - - parser.add_argument( - "--build-name", - "--name", - dest="build_name", - required=True, - help="Build name for CDash", - ) - - parser.add_argument( - "--project-name", - default="rocprofiler-compute", - help="CDash project name", - ) - parser.add_argument( - "--submit-url", - default="https://my.cdash.org/submit.php?project=rocprofiler-compute", - help="CDash submission URL", - ) - parser.add_argument( - "--cdash-host", - default="my.cdash.org", - help="CDash host (for older CMake)", - ) - parser.add_argument( - "--submit-path", - default="/submit.php?project=rocprofiler-compute", - help="CDash submission path (for older CMake)", - ) - parser.add_argument( - "--site", - default=None, - help="Site name for CDash (auto-detected if not provided)", - ) - parser.add_argument( - "--source-dir", - "-S", - default=None, - help="Source directory path (auto-detected if not provided)", - ) - parser.add_argument( - "--binary-dir", - "-B", - default=None, - help="Binary directory path (defaults to source-dir/build)", - ) - parser.add_argument( - "--mode", - default="Experimental", - choices=["Experimental", "Nightly", "Continuous"], - help="CTest dashboard mode", - ) - parser.add_argument( - "--build-jobs", - "-j", - type=int, - default=8, - help="Number of parallel build jobs", - ) - parser.add_argument( - "--install", - action="store_true", - help="Build install target instead of all target", - ) - parser.add_argument( - "--dry-run", - action="store_true", - help="Generate dashboard script but don't execute", - ) - parser.add_argument( - "--pytest-numprocs", - type=int, - default=4, - help="Number of parallel processes for pytest", - ) - - args, unknown = parser.parse_known_args() - - args.cmake_args = [] - args.ctest_args = [] - - is_monorepo, monorepo_root, project_root = detect_repo_structure() - - if not args.source_dir: - args.source_dir = str(project_root) - - if not args.binary_dir: - args.binary_dir = os.path.join(args.source_dir, "build") - - if not args.site: - if is_monorepo: - args.site = f"Monorepo-{os.uname().nodename}" - else: - args.site = os.uname().nodename - - source_dir = Path(args.source_dir).absolute() - binary_dir = Path(args.binary_dir).absolute() - - print("=" * 80) - print("rocprofiler-compute CI Dashboard") - print("=" * 80) - print(f"Repository type: {'Monorepo' if is_monorepo else 'Standalone'}") - print(f"Source directory: {source_dir}") - print(f"Binary directory: {binary_dir}") - print(f"Build name: {args.build_name}") - print(f"Dashboard mode: {args.mode}") - print(f"CDash project: {args.project_name}") - print(f"Site: {args.site}") - print("=" * 80) - - script_content = generate_ctest_dashboard_script(args, source_dir, binary_dir) - - if args.dry_run: - print("\nGenerated CTest Dashboard Script:") - print("=" * 80) - print(script_content) - print("=" * 80) - return 0 - - binary_dir.mkdir(parents=True, exist_ok=True) - - with tempfile.NamedTemporaryFile( - mode="w", suffix=".cmake", delete=False, dir=binary_dir - ) as f: - f.write(script_content) - script_path = f.name - - print(f"\nDashboard script: {script_path}") - print("=" * 80) - - try: - cmd = ["ctest", "-S", script_path, "-V"] - print(f"Running: {' '.join(cmd)}") - print("=" * 80) - print() - - process = subprocess.Popen( - cmd, - cwd=source_dir, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - text=True, - bufsize=1, - universal_newlines=True, - ) - - for line in process.stdout: - print(line, end="") - - returncode = process.wait() - - print() - print("=" * 80) - if returncode == 0: - print("✅ Dashboard completed successfully!") - else: - print(f"⚠️ Dashboard completed with return code: {returncode}") - print("=" * 80) - - return returncode - - except Exception as e: - print(f"\n❌ Error executing dashboard script: {e}", file=sys.stderr) - import traceback - - traceback.print_exc() - return 1 - finally: - try: - os.unlink(script_path) - except Exception: - pass - - -if __name__ == "__main__": - sys.exit(main())