[PATCH 4/5] github: unify self-hosted runner workflows

Daniel Gomez <[email protected]> Fri, 26 Sep 2025 15:18:12 +0200
Newsgroups dev.linux.lists.kdevops
Message-ID <[email protected]>
From: Daniel Gomez <[email protected]>

This resolves concurrency issues from the previous refactor by merging
jobs into a single run while preserving and extending the reusable
actions. It consolidates multiple GitHub Actions workflows into a single
YAML that supports push events, pull requests, manual dispatch, and
scheduled runs with intelligent parameter selection.

Fixes: 61d8cbea ("github: refactor into reusable actions and workflows")
Generated-by: Claude AI
Signed-off-by: Daniel Gomez <[email protected]>
---
 .github/actions/archive/action.yml              |  20 +-
 .github/actions/bringup/action.yml              |  16 ++
 .github/actions/build-test/action.yml           |  19 ++
 .github/actions/cleanup/action.yml              |  13 +-
 .github/actions/{setup => configure}/action.yml |  53 +----
 .github/actions/linux/action.yml                |  27 +++
 .github/actions/test/action.yml                 |  42 ++--
 .github/workflows/destroy.yml                   |  93 ---------
 .github/workflows/kdevops.yml                   | 257 ++++++++++++++++++++++++
 .github/workflows/main.yml                      | 114 -----------
 .github/workflows/manual.yml                    | 122 -----------
 .github/workflows/push.yml                      |  29 ---
 .github/workflows/schedule.yml                  |  55 -----
 13 files changed, 365 insertions(+), 495 deletions(-)

diff --git a/.github/actions/archive/action.yml b/.github/actions/archive/action.yml
index 6efe20fc..f3d3b464 100644
--- a/.github/actions/archive/action.yml
+++ b/.github/actions/archive/action.yml
@@ -7,22 +7,32 @@ inputs:
     required: false
     type: string
     default: 'demo'
-  dir:
-    description: 'Directory'
+  ssh_private_key:
+    description: 'SSH private key for results repository'
     required: true
-    default: 'workdir'
 
 runs:
   using: "composite"
   steps:
+    - name: Start SSH Agent
+      uses: webfactory/[email protected]
+      with:
+        ssh-private-key: ${{ inputs.ssh_private_key }}
+
     - name: Get systemd journal files
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
+        set -euxo pipefail
         make journal-dump
 
     - name: Build our kdevops archive results
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
+        set -euxo pipefail
         make ci-archive CI_WORKFLOW="${{ inputs.ci_workflow }}"
+
+    - name: Upload kdevops results archive
+      uses: actions/upload-artifact@v4
+      with:
+        name: kdevops-ci-results-${{ inputs.ci_workflow }}
+        path: archive/*.zip
diff --git a/.github/actions/bringup/action.yml b/.github/actions/bringup/action.yml
new file mode 100644
index 00000000..00558537
--- /dev/null
+++ b/.github/actions/bringup/action.yml
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0
+---
+name: Bringup guests
+description: Bringup kdevops guests
+
+inputs: {}
+
+runs:
+  using: "composite"
+  steps:
+    - name: Run kdevops make bringup
+      shell: bash
+      run: |
+        set -euxo pipefail
+        make destroy
+        make bringup
diff --git a/.github/actions/build-test/action.yml b/.github/actions/build-test/action.yml
new file mode 100644
index 00000000..dce8564e
--- /dev/null
+++ b/.github/actions/build-test/action.yml
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0
+---
+name: Setup kdevops
+description: Setup kdevops workspace
+
+inputs:
+  ci_workflow:
+    required: false
+    type: string
+    default: 'demo'
+
+runs:
+  using: "composite"
+  steps:
+    - name: Build required ci tests
+      shell: bash
+      run: |
+        set -euxo pipefail
+        make ci-build-test CI_WORKFLOW=${{ inputs.ci_workflow }}
diff --git a/.github/actions/cleanup/action.yml b/.github/actions/cleanup/action.yml
index 18a8656a..1a886cd9 100644
--- a/.github/actions/cleanup/action.yml
+++ b/.github/actions/cleanup/action.yml
@@ -3,22 +3,13 @@
 name: Cleanup kdevops VMs
 description: Destroy VMs and cleanup workspace
 
-inputs:
-  dir:
-    description: 'Directory'
-    required: true
-    default: 'workdir'
+inputs: {}
 
 runs:
   using: "composite"
   steps:
     - name: Run kdevops make destroy
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
+        set -euxo pipefail
         make destroy
-
-    - name: Remove working-directory
-      shell: bash
-      run: |
-        rm --recursive --force --verbose ${{ inputs.dir }}
diff --git a/.github/actions/setup/action.yml b/.github/actions/configure/action.yml
similarity index 66%
rename from .github/actions/setup/action.yml
rename to .github/actions/configure/action.yml
index f19e19df..2be05313 100644
--- a/.github/actions/setup/action.yml
+++ b/.github/actions/configure/action.yml
@@ -8,10 +8,6 @@ inputs:
     required: false
     type: string
     default: 'demo'
-  dir:
-    description: 'Directory'
-    required: true
-    default: 'workdir'
   kernel_tree:
     required: false
     type: string
@@ -38,7 +34,6 @@ runs:
 
     - name: Make sure our repo kdevops defconfig exists
       id: defconfig
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
         set -euxo pipefail
@@ -49,18 +44,16 @@ runs:
           exit 1
         fi
 
-        "${{ github.workspace }}/scripts/github_output.sh" \
+        ./scripts/github_output.sh \
           KDEVOPS_DEFCONFIG "$KDEVOPS_DEFCONFIG"
 
     - name: Initialize CI metadata for kdevops-results-archive
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
         set -euxo pipefail
         echo "${{ inputs.kernel_tree }}" > ci.trigger
         # Get the kdevops commit subject, not kernel commit
-        cd "${{ github.workspace }}" && git log -1 --pretty=format:"%s" > "${{ inputs.dir }}/kdevops/ci.subject"
-        cd - > /dev/null
+        git log -1 --pretty=format:"%s" > ci.subject
         echo "${{ inputs.kernel_ref }}" > ci.ref
 
         # Start out pessimistic
@@ -68,7 +61,6 @@ runs:
         echo "Nothing to write home about." > ci.commit_extra
 
     - name: Run kdevops make defconfig-repo
-      working-directory: ${{ inputs.dir }}/kdevops
       env:
         KDEVOPS_DEFCONFIG: ${{ steps.defconfig.outputs.KDEVOPS_DEFCONFIG }}
       shell: bash
@@ -80,9 +72,9 @@ runs:
         # Use GitHub run ID for unique host prefix to avoid conflicts
         # between concurrent runs on same server
         if [[ "${{ inputs.test_mode }}" == "kdevops-ci" ]]; then
-          KDEVOPS_HOSTS_PREFIX="kci-${{ github.run_id }}"
+          KDEVOPS_HOSTS_PREFIX="kci-${{ github.run_id }}-${{ github.run_number }}"
         else
-          KDEVOPS_HOSTS_PREFIX="lci-${{ github.run_id }}"
+          KDEVOPS_HOSTS_PREFIX="lci-${{ github.run_id }}-${{ github.run_number }}"
         fi
 
         echo "Going to use defconfig-$KDEVOPS_DEFCONFIG"
@@ -127,44 +119,7 @@ runs:
         ${VM_CONFIG_ARG}
 
     - name: Run kdevops make
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
         set -euxo pipefail
         make -j$(nproc)
-
-    - name: Run kdevops make bringup
-      working-directory: ${{ inputs.dir }}/kdevops
-      shell: bash
-      run: |
-        set -euxo pipefail
-        make destroy
-        make bringup
-
-    - name: Build linux and boot test nodes on test kernel
-      working-directory: ${{ inputs.dir }}/kdevops
-      shell: bash
-      run: |
-        set -euxo pipefail
-        make linux
-
-    - name: Generate additional CI metadata after linux checkout
-      working-directory: ${{ inputs.dir }}/kdevops
-      shell: bash
-      run: |
-        set -euxo pipefail
-        # Now that we have the linux git repo, generate additional metadata
-        cd linux
-        RELEVANT_GIT_TAG="${{ inputs.kernel_ref }}"
-        RELEVANT_GIT_REF=$(git rev-parse --short=12 $RELEVANT_GIT_TAG 2>/dev/null || echo $RELEVANT_GIT_TAG)
-
-        # Save the git ref for use by the commit message script
-        echo "$RELEVANT_GIT_REF" > ../ci.git_ref
-        echo "Generated git ref: $RELEVANT_GIT_REF for tag: $RELEVANT_GIT_TAG"
-
-    - name: Build required ci tests
-      working-directory: ${{ inputs.dir }}/kdevops
-      shell: bash
-      run: |
-        set -euxo pipefail
-        make ci-build-test CI_WORKFLOW=${{ inputs.ci_workflow }}
diff --git a/.github/actions/linux/action.yml b/.github/actions/linux/action.yml
new file mode 100644
index 00000000..2f4e8cc9
--- /dev/null
+++ b/.github/actions/linux/action.yml
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
+---
+name: Install Linux
+description: Install Linux kernel reference target
+
+inputs: {}
+
+runs:
+  using: "composite"
+  steps:
+    - name: Build linux and boot test nodes on test kernel
+      shell: bash
+      run: |
+        set -euxo pipefail
+        make linux
+
+    - name: Generate additional CI metadata after linux checkout
+      shell: bash
+      run: |
+        set -euxo pipefail
+        # Now that we have the linux git repo, generate additional metadata
+        cd linux/
+        RELEVANT_GIT_REF=$(git rev-parse --short=12 HEAD)
+
+        # Save the git ref for use by the commit message script
+        echo "$RELEVANT_GIT_REF" > ../ci.git_ref
+        echo "Generated git ref: $RELEVANT_GIT_REF"
diff --git a/.github/actions/test/action.yml b/.github/actions/test/action.yml
index 92175f27..895231b4 100644
--- a/.github/actions/test/action.yml
+++ b/.github/actions/test/action.yml
@@ -4,10 +4,6 @@ name: Setup kdevops
 description: Setup kdevops workspace
 
 inputs:
-  dir:
-    description: 'Directory'
-    required: true
-    default: 'workdir'
   ci_workflow:
     required: false
     type: string
@@ -15,10 +11,12 @@ inputs:
   test_mode:
     description: 'Testing mode'
     required: false
+    type: string
     default: 'kdevops-ci'
   tests:
     description: 'Custom test to run'
     required: false
+    type: string
     default: ''
 
 runs:
@@ -26,7 +24,6 @@ runs:
   steps:
     - name: Run CI tests
       id: ci_test
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
         set -euxo pipefail
@@ -61,13 +58,12 @@ runs:
 
         # Export TESTS for current step and save to GitHub output for later steps
         export TESTS="$TESTS"
-        "${{ github.workspace }}/scripts/github_output.sh" TESTS "$TESTS"
+        ./scripts/github_output.sh TESTS "$TESTS"
 
         make ci-test CI_WORKFLOW="${{ inputs.ci_workflow }}"
 
     - name: Generate workflow results path
       id: setpath
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
         set -euxo pipefail
@@ -81,10 +77,9 @@ runs:
           *) wpath="workflows/selftests" ;;
         esac
 
-        "${{ github.workspace }}/scripts/github_output.sh" wpath "$wpath"
+        ./scripts/github_output.sh wpath "$wpath"
 
     - name: Generate CI commit info with workflow-specific logic
-      working-directory: ${{ inputs.dir }}/kdevops
       shell: bash
       run: |
         set -euxo pipefail
@@ -110,8 +105,10 @@ runs:
             elif grep -E "[1-9][0-9]* failures|[1-9][0-9]* errors" ci.commit_extra >/dev/null 2>&1; then
               echo "not ok" > ci.result
             else
-              # Fallback: if we can't determine, mark as unknown but lean towards success
-              echo "ok" > ci.result
+              # Fallback: if we can't determine from content, no results were found
+              echo "no results found" > ci.result
+              echo "::warning::No fstests results found - tests may not have executed properly"
+              exit 1
             fi
             ;;
           blktests*)
@@ -165,12 +162,18 @@ runs:
             fi
 
             # blktests success detection - look for .out.bad files (failures)
-            bad_check=$(find "$wpath/results/last-run" -name "*.out.bad" -type f | head -1)
-
-            if [ -n "$bad_check" ]; then
-              echo "not ok" > ci.result
+            if [ -d "$wpath/results/last-run" ]; then
+              bad_check=$(find "$wpath/results/last-run" -name "*.out.bad" -type f | head -1)
+              if [ -n "$bad_check" ]; then
+                echo "not ok" > ci.result
+              else
+                echo "ok" > ci.result
+              fi
             else
-              echo "ok" > ci.result
+              # No results directory - no tests were run
+              echo "no results found" > ci.result
+              echo "::warning::No blktests results directory found - tests may not have executed properly"
+              exit 1
             fi
             ;;
           *selftests*|*modules*|*mm*|*firmware*)
@@ -181,8 +184,13 @@ runs:
             # selftests success detection
             if grep -q "passed\|PASS" ci.commit_extra && ! grep -q "FAIL\|failed\|ERROR" ci.commit_extra; then
               echo "ok" > ci.result
-            else
+            elif grep -q "FAIL\|failed\|ERROR" ci.commit_extra; then
               echo "not ok" > ci.result
+            else
+              # No clear pass/fail indicators - no results found
+              echo "no results found" > ci.result
+              echo "::warning::No selftests results found - tests may not have executed properly"
+              exit 1
             fi
             ;;
           *)
diff --git a/.github/workflows/destroy.yml b/.github/workflows/destroy.yml
deleted file mode 100644
index 3c77e950..00000000
--- a/.github/workflows/destroy.yml
+++ /dev/null
@@ -1,93 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
----
-name: Run kdevops Destroyer - Manual
-
-on:
-  workflow_dispatch:
-    inputs:
-      ci_workflow:
-        description: "CI Workflow"
-        required: true
-        default: 'blktests_nvme'
-        type: choice
-        options:
-          - blktests
-          - blktests_block
-          - blktests_loop
-          - blktests_meta
-          - blktests_nbd
-          - blktests_nvme
-          - blktests_nvmemp
-          - blktests_scsi
-          - blktests_srp
-          - blktests_zbd
-          - lbs-xfs
-          - lbs-xfs-bdev-large-nvme
-          - lbs-xfs-bdev-nvme
-          - lbs-xfs-small
-          - xfs
-          - xfs_crc
-          - xfs_crc_logdev
-          - xfs_crc_rtdev
-          - xfs_crc_rtdev_extsize_28k
-          - xfs_crc_rtdev_extsize_64k
-          - xfs_nocrc
-          - xfs_nocrc_16k_4ks
-          - xfs_nocrc_1k
-          - xfs_nocrc_2k
-          - xfs_nocrc_32_4ks
-          - xfs_nocrc_4k
-          - xfs_nocrc_512
-          - xfs_nocrc_64_4ks
-          - xfs_nocrc_8k_4ks
-          - xfs_nocrc_lbs
-          - xfs_reflink
-          - xfs_reflink_1024
-          - xfs_reflink_16k_4ks
-          - xfs_reflink_2k
-          - xfs_reflink_32k_4ks
-          - xfs_reflink_4k
-          - xfs_reflink_4k_8ks
-          - xfs_reflink_64k_4ks
-          - xfs_reflink_dir_bsize_8k
-          - xfs_reflink_lbs
-          - xfs_reflink_logdev
-          - xfs_reflink_normapbt
-          - xfs_reflink_nrext64
-          - xfs_reflink_stripe_len
-          - xfs-soak
-      host_prefix:
-        description: "Host prefix"
-        required: true
-        default: 'debian13'
-        type: string
-
-jobs:
-  destroyer:
-    name: Destroy guests
-    runs-on: [self-hosted]
-    steps:
-      - name: Create workdir
-        run: |
-          rm --recursive --force --verbose ${{ inputs.ci_workflow }}
-          mkdir --parent --verbose ${{ inputs.ci_workflow }}
-
-      - name: Checkout kdevops
-        run: |
-          cd ${{ inputs.ci_workflow }}
-          git clone /mirror/kdevops.git --branch main kdevops
-
-      - name: Run kdevops make defconfig-repo
-        run: |
-          set -euxo pipefail
-
-          sudo virsh list --all
-
-          cd ${{ inputs.ci_workflow }}/kdevops
-          make \
-            KDEVOPS_HOSTS_PREFIX="${{ inputs.host_prefix }}" \
-            defconfig-${{ inputs.ci_workflow }}
-
-          make destroy
-
-          sudo virsh list --all
diff --git a/.github/workflows/kdevops.yml b/.github/workflows/kdevops.yml
new file mode 100644
index 00000000..ac2ac625
--- /dev/null
+++ b/.github/workflows/kdevops.yml
@@ -0,0 +1,257 @@
+# SPDX-License-Identifier: GPL-2.0
+---
+name: Run kdevops CI Workflow - Push/PR/Manual/Schedule
+
+on:
+  schedule:
+    - cron: '0 14 * * *'  # Daily at 2 PM UTC
+  push:
+    branches:
+      - '**'
+  pull_request:
+    branches:
+      - '**'
+  workflow_dispatch:
+    inputs:
+      ci_workflow:
+        description: "CI Workflow"
+        required: true
+        default: 'blktests_nvme'
+        type: choice
+        options:
+          - blktests
+          - blktests_block
+          - blktests_loop
+          - blktests_meta
+          - blktests_nbd
+          - blktests_nvme
+          - blktests_nvmemp
+          - blktests_scsi
+          - blktests_srp
+          - blktests_zbd
+          - lbs-xfs
+          - lbs-xfs-bdev-large-nvme
+          - lbs-xfs-bdev-nvme
+          - lbs-xfs-small
+          - xfs
+          - xfs-soak
+          - xfs_crc
+          - xfs_crc_logdev
+          - xfs_crc_rtdev
+          - xfs_crc_rtdev_extsize_28k
+          - xfs_crc_rtdev_extsize_64k
+          - xfs_nocrc
+          - xfs_nocrc_16k_4ks
+          - xfs_nocrc_1k
+          - xfs_nocrc_2k
+          - xfs_nocrc_32_4ks
+          - xfs_nocrc_4k
+          - xfs_nocrc_512
+          - xfs_nocrc_64_4ks
+          - xfs_nocrc_8k_4ks
+          - xfs_nocrc_lbs
+          - xfs_reflink
+          - xfs_reflink_1024
+          - xfs_reflink_16k_4ks
+          - xfs_reflink_2k
+          - xfs_reflink_32k_4ks
+          - xfs_reflink_4k
+          - xfs_reflink_4k_8ks
+          - xfs_reflink_64k_4ks
+          - xfs_reflink_dir_bsize_8k
+          - xfs_reflink_lbs
+          - xfs_reflink_logdev
+          - xfs_reflink_normapbt
+          - xfs_reflink_nrext64
+          - xfs_reflink_stripe_len
+      kernel_tree:
+        description: "Linux kernel tree to use"
+        required: true
+        default: 'linux'
+        type: choice
+        options:
+          - linux
+          - linux-next
+          - linux-stable
+      kernel_ref:
+        description: "Linux tree git reference (branch/tag/commit-id)"
+        required: true
+        default: 'master'
+        type: string
+      test_mode:
+        description: 'Testing mode'
+        required: false
+        default: 'kdevops-ci'
+        type: choice
+        options:
+          - 'kdevops-ci'
+          - 'linux-ci'
+      tests:
+        description: 'Custom test to run (for kdevops-ci mode only)'
+        required: false
+        type: string
+        default: ''
+
+jobs:
+  generate_kernel_ref:
+    name: Generate Kernel Reference for Scheduled Runs
+    runs-on: [self-hosted]
+    if: github.event_name == 'schedule'
+    outputs:
+      kernel_ref: ${{ steps.kernel_ref.outputs.kernel_ref }}
+      kernel_tree: ${{ steps.kernel_ref.outputs.kernel_tree }}
+    steps:
+      - name: Checkout repo
+        uses: actions/checkout@v4
+
+      - name: Generate kernel reference based on day of week
+        id: kernel_ref
+        run: |
+          set -euxo pipefail
+          day_of_week=$(date +%u)
+
+          if [ "$day_of_week" -eq 1 ]; then
+            # Monday: Use mainline
+            kernel_ref=$(./scripts/korg-releases.py --moniker mainline)
+            kernel_tree=linux
+          else
+            # Other days: Use linux-next
+            kernel_ref=$(./scripts/korg-releases.py --moniker linux-next)
+            kernel_tree=linux-next
+          fi
+
+          ./scripts/github_output.sh kernel_ref "$kernel_ref"
+          ./scripts/github_output.sh kernel_tree "$kernel_tree"
+
+  check_ref:
+    name: Check Linux kernel Git Reference
+    runs-on: [self-hosted]
+    if: github.event_name == 'workflow_dispatch'
+    steps:
+      - name: Checkout repo
+        uses: actions/checkout@v4
+
+      - name: Check kernel_ref exists
+        id: check_kernel_ref
+        run: |
+          set -euxo pipefail
+
+          ref="${{ github.event.inputs.kernel_ref }}"
+          tree="${{ github.event.inputs.kernel_tree }}"
+          mirror="/mirror/${tree}.git"
+          ls_remote="$(git ls-remote "$mirror" "refs/*/${ref}" || true)"
+          contains_branch="$(git -C "$mirror" branch --contains "${ref}" || true)"
+          contains_tag="$(git -C "$mirror" branch --contains "${ref}" || true)"
+
+          if [ -z "$ls_remote" ] && [ -z "$contains_branch" ] && [ -z "$contains_tag" ]; then
+            echo "Linux kernel ${ref} does not exist."
+            exit 1
+          fi
+
+  kdevops-ci-matrix:
+    name: "${{ github.event.inputs.test_mode || 'kdevops-ci' }}: ${{ matrix.ci_workflow }}"
+    runs-on: self-hosted
+    needs: [check_ref, generate_kernel_ref]
+    if: >-
+      always() &&
+      (
+        needs.check_ref.result == 'success' ||
+        needs.check_ref.result == 'skipped'
+      ) &&
+      (
+        needs.generate_kernel_ref.result == 'success' ||
+        needs.generate_kernel_ref.result == 'skipped'
+      )
+    strategy:
+      fail-fast: false
+      matrix:
+        ci_workflow: >-
+          ${{
+            github.event_name == 'schedule'
+              && fromJSON('["blktests"]')
+            || github.event_name == 'workflow_dispatch'
+              && fromJSON(format('["{0}"]', github.event.inputs.ci_workflow))
+            || fromJSON('["blktests_nvme", "xfs_reflink_4k"]')
+          }}
+    steps:
+      - name: Checkout repository for ${{ matrix.ci_workflow }}
+        shell: bash
+        run: |
+          set -euxo pipefail
+
+          # More efficient approach similar to actions/checkout
+          if [[ -d ".git" ]]; then
+            # Repo exists - clean and update (like actions/checkout)
+            git clean -ffdx
+            git reset --hard HEAD
+            # Ensure correct remote URL
+            git remote set-url origin $GITHUB_SERVER_URL/$GITHUB_REPOSITORY
+            git fetch --depth=1 origin ${{ github.ref_name }}
+            git reset --hard FETCH_HEAD
+          else
+            # No repo - fresh clone with local mirror optimization
+            if [[ -f "/mirror/kdevops.git/HEAD" ]]; then
+              git clone --verbose --progress \
+                --reference /mirror/kdevops.git \
+                --depth=1 \
+                --branch ${{ github.ref_name }} \
+                $GITHUB_SERVER_URL/$GITHUB_REPOSITORY .
+            else
+              git clone --verbose --progress \
+                --depth=1 \
+                --branch ${{ github.ref_name }} \
+                $GITHUB_SERVER_URL/$GITHUB_REPOSITORY .
+            fi
+          fi
+
+      - name: Configure kdevops
+        uses: ./.github/actions/configure
+        with:
+          ci_workflow: ${{ matrix.ci_workflow }}
+          kernel_ref: >-
+            ${{
+              github.event_name == 'schedule' && needs.generate_kernel_ref.outputs.kernel_ref
+              || github.event.inputs.kernel_ref
+              || 'v6.15'
+            }}
+          kernel_tree: >-
+            ${{
+              github.event_name == 'schedule' && needs.generate_kernel_ref.outputs.kernel_tree
+              || github.event.inputs.kernel_tree
+              || 'linux'
+            }}
+          test_mode: >-
+            ${{
+              github.event_name == 'schedule' && 'linux-ci'
+              || github.event.inputs.test_mode
+              || 'kdevops-ci'
+            }}
+
+      - name: Bringup guests
+        uses: ./.github/actions/bringup
+
+      - name: Install linux
+        uses: ./.github/actions/linux
+
+      - name: Install tests
+        uses: ./.github/actions/build-test
+        with:
+          ci_workflow: ${{ matrix.ci_workflow }}
+
+      - name: Run tests
+        uses: ./.github/actions/test
+        with:
+          ci_workflow: ${{ matrix.ci_workflow }}
+          test_mode: ${{ github.event.inputs.test_mode || 'kdevops-ci' }}
+          tests: ${{ github.event.inputs.tests || '' }}
+        timeout-minutes: 120
+
+      - name: Archive results
+        uses: ./.github/actions/archive
+        with:
+          ci_workflow: ${{ matrix.ci_workflow }}
+          ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
+
+      - name: Cleanup
+        if: always()
+        uses: ./.github/actions/cleanup
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
deleted file mode 100644
index c34346fe..00000000
--- a/.github/workflows/main.yml
+++ /dev/null
@@ -1,114 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
----
-name: Run kdevops CI Workflow - Reusable
-
-on:
-  workflow_call:
-    inputs:
-      ci_workflow:
-        description: "CI Workflow"
-        required: true
-        default: 'blktests_nvme'
-        type: string
-      kernel_ref:
-        description: "Linux tree git reference (branch/tag/commit-id)"
-        required: true
-        default: 'master'
-        type: string
-      kernel_tree:
-        description: "Linux kernel tree to use"
-        required: true
-        default: 'linux'
-        type: string
-      test_mode:
-        description: 'Testing mode'
-        required: false
-        default: 'linux-ci'
-        type: string
-      tests:
-        description: 'Custom test to run (for kdevops-ci mode only)'
-        required: false
-        default: ''
-        type: string
-
-jobs:
-  setup:
-    name: Setup kdevops workspace
-    runs-on: ${{
-        inputs.test_mode == 'kdevops-ci'
-        && fromJSON('["self-hosted", "Linux", "X64", "kdevops-ci"]')
-        || fromJSON('["self-hosted", "Linux", "X64", "linux-ci"]')
-      }}
-    steps:
-      - name: Checkout kdevops
-        uses: actions/checkout@v4
-        with:
-          path: ${{ inputs.ci_workflow }}-${{ github.run_id }}/kdevops
-
-      - name: kdevops setup
-        uses: ./.github/actions/setup
-        with:
-          ci_workflow: ${{ inputs.ci_workflow }}
-          dir: ${{ inputs.ci_workflow }}-${{ github.run_id }}
-          kernel_ref: ${{ inputs.kernel_ref }}
-          kernel_tree: ${{ inputs.kernel_tree }}
-          test_mode: ${{ inputs.test_mode }}
-
-  test:
-    name: Run kdevops ci-test
-    runs-on: ${{
-        inputs.test_mode == 'kdevops-ci'
-        && fromJSON('["self-hosted", "Linux", "X64", "kdevops-ci"]')
-        || fromJSON('["self-hosted", "Linux", "X64", "linux-ci"]')
-      }}
-    needs: [setup]
-    timeout-minutes: 120
-    steps:
-      - name: kdevops ci-test
-        uses: ./.github/actions/test
-        with:
-          ci_workflow: ${{ inputs.ci_workflow }}
-          dir: ${{ inputs.ci_workflow }}-${{ github.run_id }}
-          test_mode: ${{ inputs.test_mode }}
-          tests: ${{ inputs.tests }}
-
-  archive:
-    name: Archive kdevops
-    runs-on: ${{
-        inputs.test_mode == 'kdevops-ci'
-        && fromJSON('["self-hosted", "Linux", "X64", "kdevops-ci"]')
-        || fromJSON('["self-hosted", "Linux", "X64", "linux-ci"]')
-      }}
-    needs: [setup, test]
-    steps:
-      - name: Start SSH Agent
-        uses: webfactory/[email protected]
-        with:
-          ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
-
-      - name: Archive ci-test results
-        uses: ./.github/actions/archive
-        with:
-          ci_workflow: ${{ inputs.ci_workflow }}
-          dir: ${{ inputs.ci_workflow }}-${{ github.run_id }}
-
-      - name: Upload our kdevops results archive
-        uses: actions/upload-artifact@v4
-        with:
-          name: kdevops-ci-results
-          path: ${{ inputs.ci_workflow }}-${{ github.run_id }}/kdevops/archive/*.zip
-
-  cleanup:
-    name: Cleanup kdevops workspace
-    runs-on: ${{
-        inputs.test_mode == 'kdevops-ci'
-        && fromJSON('["self-hosted", "Linux", "X64", "kdevops-ci"]')
-        || fromJSON('["self-hosted", "Linux", "X64", "linux-ci"]')
-      }}
-    needs: [setup, test, archive]
-    if: always()
-    steps:
-      - name: kdevops cleanup
-        uses: ./.github/actions/cleanup
-        with:
-          dir: ${{ inputs.ci_workflow }}-${{ github.run_id }}
diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml
deleted file mode 100644
index 5a5d083c..00000000
--- a/.github/workflows/manual.yml
+++ /dev/null
@@ -1,122 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
----
-name: Run kdevops CI Workflow - Manual
-
-on:
-  workflow_dispatch:
-    inputs:
-      ci_workflow:
-        description: "CI Workflow"
-        required: true
-        default: 'blktests_nvme'
-        type: choice
-        options:
-          - blktests
-          - blktests_block
-          - blktests_loop
-          - blktests_meta
-          - blktests_nbd
-          - blktests_nvme
-          - blktests_nvmemp
-          - blktests_scsi
-          - blktests_srp
-          - blktests_zbd
-          - lbs-xfs
-          - lbs-xfs-bdev-large-nvme
-          - lbs-xfs-bdev-nvme
-          - lbs-xfs-small
-          - xfs
-          - xfs_crc
-          - xfs_crc_logdev
-          - xfs_crc_rtdev
-          - xfs_crc_rtdev_extsize_28k
-          - xfs_crc_rtdev_extsize_64k
-          - xfs_nocrc
-          - xfs_nocrc_16k_4ks
-          - xfs_nocrc_1k
-          - xfs_nocrc_2k
-          - xfs_nocrc_32_4ks
-          - xfs_nocrc_4k
-          - xfs_nocrc_512
-          - xfs_nocrc_64_4ks
-          - xfs_nocrc_8k_4ks
-          - xfs_nocrc_lbs
-          - xfs_reflink
-          - xfs_reflink_1024
-          - xfs_reflink_16k_4ks
-          - xfs_reflink_2k
-          - xfs_reflink_32k_4ks
-          - xfs_reflink_4k
-          - xfs_reflink_4k_8ks
-          - xfs_reflink_64k_4ks
-          - xfs_reflink_dir_bsize_8k
-          - xfs_reflink_lbs
-          - xfs_reflink_logdev
-          - xfs_reflink_normapbt
-          - xfs_reflink_nrext64
-          - xfs_reflink_stripe_len
-          - xfs-soak
-      kernel_tree:
-        description: "Linux kernel tree to use"
-        required: true
-        default: 'linux'
-        type: choice
-        options:
-          - linux
-          - linux-next
-          - linux-stable
-      kernel_ref:
-        description: "Linux tree git reference (branch/tag/commit-id)"
-        required: true
-        default: 'master'
-        type: string
-      test_mode:
-        description: 'Testing mode'
-        required: false
-        default: 'kdevops-ci'
-        type: choice
-        options:
-          - 'kdevops-ci'
-          - 'linux-ci'
-      tests:
-        description: 'Custom test to run (for kdevops-ci mode only)'
-        required: false
-        type: string
-        default: ''
-
-jobs:
-  check_ref:
-    name: Check Linux kernel Git Reference
-    runs-on: [self-hosted]
-    steps:
-      - name: Checkout repo
-        uses: actions/checkout@v4
-
-      - name: Check kernel_ref exists
-        id: check_kernel_ref
-        run: |
-          set -euxo pipefail
-
-          ref="${{ github.event.inputs.kernel_ref }}"
-          tree="${{ github.event.inputs.kernel_tree }}"
-          mirror="/mirror/${tree}.git"
-          ls_remote="$(git ls-remote "$mirror" "refs/*/${ref}" || true)"
-          contains_branch="$(git -C "$mirror" branch --contains "${ref}" || true)"
-          contains_tag="$(git -C "$mirror" branch --contains "${ref}" || true)"
-
-          if [ -z "$ls_remote" ] && [ -z "$contains_branch" ] && [ -z "$contains_tag" ]; then
-            echo "Linux kernel ${ref} does not exist."
-            exit 1
-          fi
-
-  manual:
-    name: Manual kdevops CI
-    needs: [check_ref]
-    uses: ./.github/workflows/main.yml
-    secrets: inherit
-    with:
-      ci_workflow: ${{ inputs.ci_workflow }}
-      kernel_ref: ${{ inputs.kernel_ref }}
-      kernel_tree: ${{ inputs.kernel_tree }}
-      test_mode: ${{ inputs.test_mode }}
-      tests: ${{ inputs.tests }}
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
deleted file mode 100644
index aa4d6ff3..00000000
--- a/.github/workflows/push.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
----
-name: Run kdevops CI Workflow - Push/PR
-
-on:
-  push:
-    branches:
-      - '**'
-  pull_request:
-    branches:
-      - '**'
-
-jobs:
-  push-pr:
-    name: Push/PR kdevops CI
-    uses: ./.github/workflows/main.yml
-    secrets: inherit
-    strategy:
-      fail-fast: false  # Don't cancel other jobs if one fails
-      matrix:
-        ci_workflow:
-          - blktests_nvme
-          - xfs_reflink_4k
-    with:
-      ci_workflow: ${{ matrix.ci_workflow }}
-      kernel_ref: 'v6.15'
-      kernel_tree: 'linux'
-      test_mode: 'kdevops-ci'
-      tests: ''
diff --git a/.github/workflows/schedule.yml b/.github/workflows/schedule.yml
deleted file mode 100644
index cb3396c6..00000000
--- a/.github/workflows/schedule.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
----
-name: Run kdevops CI Workflow - Schedule
-
-on:
-  schedule:
-    - cron: '0 14 * * *'
-
-  workflow_dispatch:
-
-jobs:
-  check_ref:
-    name: Check Linux kernel Git Reference
-    outputs:
-      kernel_ref: ${{ steps.check_kernel_ref.outputs.kernel_ref }}
-      kernel_tree: ${{ steps.check_kernel_ref.outputs.kernel_tree }}
-    runs-on: [self-hosted]
-    steps:
-      - name: Checkout repo
-        uses: actions/checkout@v4
-
-      - name: Generate kernel_ref
-        id: check_kernel_ref
-        run: |
-          set -euxo pipefail
-          day_of_week=$(date +%u)
-
-          kernel_ref=$(./scripts/korg-releases.py --moniker linux-next)
-          kernel_tree=linux-next
-          if [ "$day_of_week" -eq 1 ]; then
-            kernel_ref=$(./scripts/korg-releases.py --moniker mainline)
-            kernel_tree=linux
-          fi
-
-          "${{ github.workspace }}/scripts/github_output.sh" kernel_ref "$kernel_ref"
-          "${{ github.workspace }}/scripts/github_output.sh" kernel_tree "$kernel_tree"
-
-  schedule:
-    name: Scheduled Linux CI
-    needs: [check_ref]
-    uses: ./.github/workflows/main.yml
-    secrets: inherit
-    strategy:
-      fail-fast: false  # Don't cancel other jobs if one fails
-      matrix:
-        ci_workflow:
-          - blktests
-          - linux-mm-kpd
-          - linux-modules-kpd
-          - tmpfs
-    with:
-      ci_workflow: ${{ matrix.ci_workflow }}
-      kernel_ref: ${{ needs.check_ref.outputs.kernel_ref }}
-      kernel_tree: ${{ needs.check_ref.outputs.kernel_tree }}
-      test_mode: 'linux-ci'

-- 
2.50.1