From 61eaea83f27e5c13c799031b2f893d319f1a5e90 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Tue, 28 Apr 2026 09:32:03 -0400 Subject: [PATCH 1/3] Add TestGroups reusable workflow with auto-discovery of test groups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces TestGroups.yml: a reusable workflow that auto-discovers subdirectories under test/ and runs each as a parallel job across a configurable Julia version × OS matrix. Includes a stable ci-success gate job for branch protection rules, fast-path support for draft PRs, and coverage restricted to a single OS/version to avoid redundant uploads. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/TestGroups.yml | 153 +++++++++++++++++++++++++++++++ README.md | 97 +++++++++++++++++++- 2 files changed, 248 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/TestGroups.yml diff --git a/.github/workflows/TestGroups.yml b/.github/workflows/TestGroups.yml new file mode 100644 index 0000000..621cbb3 --- /dev/null +++ b/.github/workflows/TestGroups.yml @@ -0,0 +1,153 @@ +name: "Reusable Test Groups Workflow" + +on: + workflow_call: + inputs: + exclude: + description: "JSON array of test/ subdirectories to exclude from auto-discovery" + default: '["setup", "gpu"]' + required: false + type: string + julia-version: + description: "JSON array of Julia versions to test (e.g. '[\"min\", \"1\"]')" + default: '["min", "1"]' + required: false + type: string + os: + description: "JSON array of runner operating systems" + default: '["ubuntu-latest", "macos-latest", "windows-latest"]' + required: false + type: string + fast: + description: "Collapse matrix to ubuntu-latest + julia 1, and append --fast to test args" + default: false + required: false + type: boolean + nthreads: + description: "Number of Julia threads" + default: 2 + required: false + type: number + timeout-minutes: + description: "Maximum time per job in minutes" + default: 60 + required: false + type: number + localregistry: + description: "Newline-separated list of local registry URLs to add before building" + default: "" + required: false + type: string + cache: + description: "Enable julia-actions/cache" + default: true + required: false + type: boolean + buildpkg: + description: "Enable julia-actions/julia-buildpkg" + default: true + required: false + type: boolean + coverage: + description: "Collect and upload coverage (restricted to ubuntu-latest + julia 1)" + default: true + required: false + type: boolean + coverage-directories: + description: "Comma-separated directories for julia-processcoverage" + default: "src,ext" + required: false + type: string + secrets: + CODECOV_TOKEN: + required: false + +jobs: + setup: + runs-on: ubuntu-latest + outputs: + groups: ${{ steps.discover.outputs.groups }} + versions: ${{ steps.discover.outputs.versions }} + systems: ${{ steps.discover.outputs.systems }} + steps: + - uses: actions/checkout@v4 + + - name: Discover test groups + id: discover + shell: bash + run: | + GROUPS=$(find test -mindepth 1 -maxdepth 1 -type d -printf '%f\n' \ + | sort \ + | jq -R -s -c --argjson exc '${{ inputs.exclude }}' \ + 'split("\n")[:-1] | map(select(. as $g | $exc | index($g) | not))') + echo "groups=$GROUPS" >> "$GITHUB_OUTPUT" + + if [[ "${{ inputs.fast }}" == "true" ]]; then + echo 'versions=["1"]' >> "$GITHUB_OUTPUT" + echo 'systems=["ubuntu-latest"]' >> "$GITHUB_OUTPUT" + else + echo 'versions=${{ inputs.julia-version }}' >> "$GITHUB_OUTPUT" + echo 'systems=${{ inputs.os }}' >> "$GITHUB_OUTPUT" + fi + + test: + needs: setup + name: "Test (${{ matrix.version }}, ${{ matrix.os }}, ${{ matrix.group }})" + runs-on: ${{ matrix.os }} + timeout-minutes: ${{ inputs.timeout-minutes }} + strategy: + fail-fast: false + matrix: + group: ${{ fromJSON(needs.setup.outputs.groups) }} + version: ${{ fromJSON(needs.setup.outputs.versions) }} + os: ${{ fromJSON(needs.setup.outputs.systems) }} + steps: + - uses: actions/checkout@v4 + + - name: "Setup Julia ${{ matrix.version }}" + uses: julia-actions/setup-julia@v2 + with: + version: "${{ matrix.version }}" + + - uses: julia-actions/cache@v2 + if: inputs.cache + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - uses: julia-actions/julia-buildpkg@v1 + if: inputs.buildpkg + with: + localregistry: "${{ inputs.localregistry }}" + + - name: "Run tests" + uses: julia-actions/julia-runtest@v1 + with: + test_args: "${{ matrix.group }}${{ inputs.fast && ' --fast' || '' }}" + coverage: "${{ inputs.coverage && matrix.os == 'ubuntu-latest' && matrix.version == '1' }}" + env: + JULIA_NUM_THREADS: "${{ inputs.nthreads }}" + + - uses: julia-actions/julia-processcoverage@v1 + if: inputs.coverage && matrix.os == 'ubuntu-latest' && matrix.version == '1' + with: + directories: "${{ inputs.coverage-directories }}" + + - name: "Report coverage with Codecov" + uses: codecov/codecov-action@v5 + if: inputs.coverage && matrix.os == 'ubuntu-latest' && matrix.version == '1' + with: + files: lcov.info + token: ${{ secrets.CODECOV_TOKEN }} + fail_ci_if_error: false + + ci-success: + name: ci-success + needs: test + if: always() + runs-on: ubuntu-latest + steps: + - name: Check all tests passed + run: | + if [[ "${{ contains(needs.test.result, 'failure') || contains(needs.test.result, 'cancelled') }}" == "true" ]]; then + exit 1 + fi diff --git a/README.md b/README.md index 33c7851..7deaf88 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,99 @@ -# ITensorActions +# QuantumKitHubActions -Shared workflows for the ITensors Julia packages +Shared workflows for the QuantumKitHub Julia packages + +## Test Groups + +The TestGroups workflow auto-discovers test groups from subdirectories of `test/` and runs them in parallel across a matrix of Julia versions and operating systems. Each subdirectory becomes a separate parallel job; groups are passed to the test suite via `test_args` and dispatched by [ParallelTestRunner.jl](https://github.com/QuantumKitHub/ParallelTestRunner.jl). + +### Test directory structure + +Organize your `test/` directory with one subfolder per test group. Place shared setup code in a `test/setup/` directory (excluded by default): + +``` +test/ +├── setup/ # shared utilities, excluded from test groups +├── core/ +│ └── runtests.jl +├── extensions/ +│ └── runtests.jl +└── runtests.jl # ParallelTestRunner.jl entry point +``` + +A minimal `test/runtests.jl` using ParallelTestRunner.jl: + +```julia +using ParallelTestRunner +ParallelTestRunner.runtests() +``` + +### Example workflow + +```yaml +name: "Tests" + +on: + push: + branches: + - main + tags: '*' + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + tests: + uses: "QuantumKitHub/QuantumKitHubActions/.github/workflows/TestGroups.yml@main" + with: + fast: ${{ github.event.pull_request.draft == true }} + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} +``` + +### Branch protection + +Add `ci-success` as a required status check in your repository's branch protection rules. This single stable check name reflects the combined result of all parallel test jobs regardless of how many groups exist. + +### Inputs + +| Input | Type | Default | Description | +|---|---|---|---| +| `exclude` | string | `'["setup", "gpu"]'` | JSON array of `test/` subdirectory names to exclude from discovery | +| `julia-version` | string | `'["min", "1"]'` | JSON array of Julia versions to test | +| `os` | string | `'["ubuntu-latest", "macos-latest", "windows-latest"]'` | JSON array of runner OSes | +| `fast` | boolean | `false` | Collapse matrix to `ubuntu-latest` + julia `1`, append `--fast` to test args | +| `nthreads` | number | `2` | Julia thread count per job | +| `timeout-minutes` | number | `60` | Per-job timeout | +| `localregistry` | string | `""` | Newline-separated local registry URLs | +| `cache` | boolean | `true` | Enable `julia-actions/cache` | +| `buildpkg` | boolean | `true` | Enable `julia-actions/julia-buildpkg` | +| `coverage` | boolean | `true` | Collect and upload coverage (only on `ubuntu-latest` + julia `1`) | +| `coverage-directories` | string | `"src,ext"` | Directories for `julia-processcoverage` | + +**Secrets:** `CODECOV_TOKEN` (optional, only needed when `coverage: true`) + +### Fast path + +When `fast: true`, the matrix collapses to a single OS and Julia version and `--fast` is appended to each group's test args. Wire it to draft PR detection for quick feedback during development: + +```yaml +with: + fast: ${{ github.event.pull_request.draft == true }} +``` + +ParallelTestRunner.jl passes `--fast` through to individual test files, which can use it to skip slow or expensive tests. + +### Excluding folders + +Override `exclude` to control which subdirectories are skipped: + +```yaml +with: + exclude: '["setup", "gpu", "cuda"]' +``` ## Tests From e51ce051effaf8fd27066d1bafd267487abf6f32 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Tue, 28 Apr 2026 09:39:28 -0400 Subject: [PATCH 2/3] Improve job and step names for cleaner PR checks view Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/TestGroups.yml | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/.github/workflows/TestGroups.yml b/.github/workflows/TestGroups.yml index 621cbb3..077b9a4 100644 --- a/.github/workflows/TestGroups.yml +++ b/.github/workflows/TestGroups.yml @@ -64,13 +64,15 @@ on: jobs: setup: + name: "Discover test groups" runs-on: ubuntu-latest outputs: groups: ${{ steps.discover.outputs.groups }} versions: ${{ steps.discover.outputs.versions }} systems: ${{ steps.discover.outputs.systems }} steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - name: Discover test groups id: discover @@ -92,7 +94,7 @@ jobs: test: needs: setup - name: "Test (${{ matrix.version }}, ${{ matrix.os }}, ${{ matrix.group }})" + name: "${{ matrix.group }} (${{ matrix.version }}, ${{ matrix.os }})" runs-on: ${{ matrix.os }} timeout-minutes: ${{ inputs.timeout-minutes }} strategy: @@ -102,24 +104,27 @@ jobs: version: ${{ fromJSON(needs.setup.outputs.versions) }} os: ${{ fromJSON(needs.setup.outputs.systems) }} steps: - - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - name: "Setup Julia ${{ matrix.version }}" uses: julia-actions/setup-julia@v2 with: version: "${{ matrix.version }}" - - uses: julia-actions/cache@v2 + - name: Restore cache + uses: julia-actions/cache@v2 if: inputs.cache with: token: ${{ secrets.GITHUB_TOKEN }} - - uses: julia-actions/julia-buildpkg@v1 + - name: Build package + uses: julia-actions/julia-buildpkg@v1 if: inputs.buildpkg with: localregistry: "${{ inputs.localregistry }}" - - name: "Run tests" + - name: "Run ${{ matrix.group }} tests" uses: julia-actions/julia-runtest@v1 with: test_args: "${{ matrix.group }}${{ inputs.fast && ' --fast' || '' }}" @@ -127,12 +132,13 @@ jobs: env: JULIA_NUM_THREADS: "${{ inputs.nthreads }}" - - uses: julia-actions/julia-processcoverage@v1 + - name: Process coverage + uses: julia-actions/julia-processcoverage@v1 if: inputs.coverage && matrix.os == 'ubuntu-latest' && matrix.version == '1' with: directories: "${{ inputs.coverage-directories }}" - - name: "Report coverage with Codecov" + - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 if: inputs.coverage && matrix.os == 'ubuntu-latest' && matrix.version == '1' with: From 18f2e817c02c474a8ee03a220adf10152558933e Mon Sep 17 00:00:00 2001 From: lkdvos Date: Tue, 28 Apr 2026 09:42:35 -0400 Subject: [PATCH 3/3] Update actions to latest versions (checkout@v6, setup-julia@v3, cache@v3, codecov@v6) Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/TestGroups.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/TestGroups.yml b/.github/workflows/TestGroups.yml index 077b9a4..88ae25c 100644 --- a/.github/workflows/TestGroups.yml +++ b/.github/workflows/TestGroups.yml @@ -72,7 +72,7 @@ jobs: systems: ${{ steps.discover.outputs.systems }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Discover test groups id: discover @@ -105,15 +105,15 @@ jobs: os: ${{ fromJSON(needs.setup.outputs.systems) }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: "Setup Julia ${{ matrix.version }}" - uses: julia-actions/setup-julia@v2 + uses: julia-actions/setup-julia@v3 with: version: "${{ matrix.version }}" - name: Restore cache - uses: julia-actions/cache@v2 + uses: julia-actions/cache@v3 if: inputs.cache with: token: ${{ secrets.GITHUB_TOKEN }} @@ -139,7 +139,7 @@ jobs: directories: "${{ inputs.coverage-directories }}" - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@v6 if: inputs.coverage && matrix.os == 'ubuntu-latest' && matrix.version == '1' with: files: lcov.info