From a4a69b93c115f89ce4a4aaa44d3532f90e43530e Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 10 Aug 2026 17:46:47 +0200 Subject: [PATCH 1/8] Add a CI that can check the 'bot:status last_build' output to see if it is complete in the sense that it supports all architectures, and all builds are done from the same software-layer commit --- .github/workflows/check_build_status.yml | 32 ++++ .github/workflows/scripts/check_builds.py | 220 ++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 .github/workflows/check_build_status.yml create mode 100644 .github/workflows/scripts/check_builds.py diff --git a/.github/workflows/check_build_status.yml b/.github/workflows/check_build_status.yml new file mode 100644 index 0000000000..65c13440bc --- /dev/null +++ b/.github/workflows/check_build_status.yml @@ -0,0 +1,32 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +# +# This workflow checks the bot's status table (posted in PR comments) to verify +# that all supported CPU targets have been successfully built before deployment. +name: Check bot build status +on: + issue_comment: + types: [created, edited] +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + check_builds: + if: > + github.event.issue.pull_request && + contains(github.event.comment.body, 'This is the status of all the `bot: build` commands:') + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 + - name: Check bot build status + # We pass the comment body via env variable instead of a command-line argument + # because the body contains special characters (pipes |, backticks, newlines, etc.) + # that would need complex quoting/escaping in bash. Passing via env is safer + # and preserves the content exactly as-is. The Python script reads both + # PR_NUMBER and COMMENT_BODY from the environment. + env: + PR_NUMBER: ${{ github.event.issue.number }} + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + python3 .github/workflows/scripts/check_builds.py diff --git a/.github/workflows/scripts/check_builds.py b/.github/workflows/scripts/check_builds.py new file mode 100644 index 0000000000..3a73505702 --- /dev/null +++ b/.github/workflows/scripts/check_builds.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +# Check that all supported CPU targets have been successfully built, based on +# the bot's status table in the PR comment. +# +# Usage: check_builds.py +# Reads PR_NUMBER and COMMENT_BODY from environment variables. +# No API calls required — the triggering comment body is already available. +# +# Exit codes: +# 0: Success (all supported targets have successful builds, or mapping is empty) +# 1: Failure (missing/failed builds, or commit SHA inconsistency) + +import datetime +import os +import sys +import re + + +# ============================================================================ +# TODO: FILL IN THE SUPPORTED CPU TARGETS PER REPO +# ============================================================================ +# This mapping defines which CPU targets (values of the 'for' column) must be +# successfully built for each repository (value of the 'repo' column). +# The values below are a placeholder — please fill in the actual supported +# targets for your repositories. +# +# Example structure: +# SUPPORTED_TARGETS = { +# "eessi.io-2025.06-software": [ +# "x86_64/amd/zen2", +# "x86_64/amd/zen3", +# "x86_64/amd/zen4", +# "x86_64/intel/haswell", +# # ... add all supported targets for this repo ... +# ], +# "eessi.io-2023.06-software": [ +# # ... supported targets for 2023.06 ... +# ], +# } +# ============================================================================ +SUPPORTED_TARGETS = { + # Placeholder — fill in your supported targets here + # "eessi.io-2025.06-software": ["x86_64/amd/zen2"], +} + + +def parse_date(date_str): + """ + Parse a date string like 'Aug 04 18:11:14 UTC 2026' into a datetime object. + Returns None if parsing fails. + """ + try: + return datetime.datetime.strptime(date_str, "%b %d %X %Z %Y") + except ValueError: + return None + + +def parse_markdown_table(body): + """ + Parse the bot's status table from the comment body. + Returns a list of dicts, one per row, with column names as keys. + Uses header-driven parsing (column names from the header row) so it + tolerates extra/missing columns like 'commit SHA'. + """ + marker = "This is the status of all the `bot: build` commands:" + if marker not in body: + return None + + # Find the table: start from the marker line, look for header row + lines = body.splitlines() + header_idx = None + for i, line in enumerate(lines): + if line.startswith("|on|"): + header_idx = i + break + + if header_idx is None: + return None + + # Parse header row + header_line = lines[header_idx] + # Split by | and strip whitespace, remove empty first/last from leading/trailing | + columns = [c.strip() for c in header_line.strip("|").split("|")] + + # Find separator row (line of dashes) + separator_idx = header_idx + 1 + while separator_idx < len(lines) and not lines[separator_idx].startswith("|"): + separator_idx += 1 + if separator_idx >= len(lines): + return None + + # Parse data rows + rows = [] + for line in lines[separator_idx + 1:]: + if not line.startswith("|"): + continue + cells = [c.strip() for c in line.strip("|").split("|")] + if len(cells) != len(columns): + continue + row = dict(zip(columns, cells)) + # Strip backticks from 'on' and 'for' values + for key in ["on", "for"]: + if key in row: + row[key] = row[key].strip("`") + rows.append(row) + + return rows + + +def dedup_by_for_repo(rows): + """ + Deduplicate rows by (for, repo) pair, keeping only the last build + (by date) for each pair. + Returns a dict: (for, repo) -> row + """ + latest = {} + for row in rows: + key = (row.get("for"), row.get("repo")) + if key == (None, None) or key[0] is None: + continue + date_str = row.get("date", "") + date = parse_date(date_str) + if date is None: + # Treat as oldest if date can't be parsed + date = datetime.datetime.min + if key not in latest or date > latest[key][0]: + latest[key] = (date, row) + return {k: v[1] for k, v in latest.items()} + + +def main(): + pr_number = os.environ.get("PR_NUMBER") + comment_body = os.environ.get("COMMENT_BODY") + + if not pr_number or not comment_body: + print("ERROR: PR_NUMBER and COMMENT_BODY must be set in environment") + sys.exit(1) + + # Parse the table + rows = parse_markdown_table(comment_body) + if rows is None: + print("ERROR: Could not find status table in comment") + sys.exit(1) + + if not rows: + print("ERROR: Status table is empty") + sys.exit(1) + + # Deduplicate by (for, repo) + deduped = dedup_by_for_repo(rows) + if not deduped: + print("ERROR: No valid builds found in table") + sys.exit(1) + + # Determine which repos are present in both table and mapping + table_repos = set(row.get("repo") for row in deduped.values() if row.get("repo")) + mapping_repos = set(SUPPORTED_TARGETS.keys()) + repos_to_check = table_repos & mapping_repos + + # Warn if repos in table are missing from mapping + for repo in table_repos - mapping_repos: + print(f"WARNING: Repo '{repo}' found in table but not in SUPPORTED_TARGETS mapping; skipping checks for this repo") + + # Check commit SHA consistency across all deduplicated builds (if column present) + commit_shas = set() + for row in deduped.values(): + sha = row.get("commit SHA") + if sha: + commit_shas.add(sha) + + if len(commit_shas) > 1: + print("ERROR: Commit SHA inconsistency detected across builds") + for sha in commit_shas: + matching_rows = [r for r in deduped.values() if r.get("commit SHA") == sha] + targets = [r.get("for") for r in matching_rows] + print(f" SHA {sha}: targets {targets}") + print("All builds must reference the same commit SHA.") + sys.exit(1) + + # Verify each supported target for each repo + failed = False + for repo in repos_to_check: + supported = SUPPORTED_TARGETS[repo] + print(f"\nChecking repo: {repo}") + builds_for_repo = {k: v for k, v in deduped.items() if v.get("repo") == repo} + + for target in supported: + key = (target, repo) + row = deduped.get(key) + if row is None: + print(f" FAIL: Target '{target}' not found in builds for {repo}") + failed = True + continue + + status = row.get("status", "").strip() + result = row.get("result", "") + if status != "finished" or "SUCCESS" not in result: + print(f" FAIL: Target '{target}' is not SUCCESS/finished") + print(f" status={status}, result={result}") + if row.get("url"): + print(f" URL: {row['url']}") + failed = True + else: + print(f" OK: Target '{target}' built successfully") + + # Check if mapping is empty + if not mapping_repos: + print("\nWARNING: SUPPORTED_TARGETS mapping is empty — no checks performed.") + print("Please populate SUPPORTED_TARGETS in check_builds.py with your supported targets.") + + if failed: + print("\nERROR: Build verification failed. Please fix the above issues.") + sys.exit(1) + + print("\nSUCCESS: All supported targets have been successfully built.") + sys.exit(0) + + +if __name__ == "__main__": + main() From 1272ba50799cd5058054ccd09a8c9294c63a65b8 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 5 Oct 2026 14:26:43 +0200 Subject: [PATCH 2/8] Move supported CPU/accelerator targets per EESSI version into a JSON file The list of supported CPU and accelerator targets per EESSI version was embedded as env variables in test-software.eessi.io.yml. Move it to .github/workflows/eessi_targets.json so it can be reused by other workflows and scripts (e.g. a check on the bot's build status), without duplicating it. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/eessi_targets.json | 175 +++++++++++++++++++ .github/workflows/test-software.eessi.io.yml | 171 +----------------- 2 files changed, 184 insertions(+), 162 deletions(-) create mode 100644 .github/workflows/eessi_targets.json diff --git a/.github/workflows/eessi_targets.json b/.github/workflows/eessi_targets.json new file mode 100644 index 0000000000..a788dec6b4 --- /dev/null +++ b/.github/workflows/eessi_targets.json @@ -0,0 +1,175 @@ +{ + "cpu_targets": { + "2023.06": { + "x86_64": [ + "x86_64/amd/zen2", + "x86_64/amd/zen3", + "x86_64/amd/zen4", + "x86_64/intel/haswell", + "x86_64/intel/sapphirerapids", + "x86_64/intel/skylake_avx512", + "x86_64/intel/icelake", + "x86_64/intel/cascadelake", + "x86_64/generic" + ], + "aarch64": [ + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", + "aarch64/a64fx" + ] + }, + "2025.06": { + "x86_64": [ + "x86_64/amd/zen2", + "x86_64/amd/zen3", + "x86_64/amd/zen4", + "x86_64/amd/zen5", + "x86_64/intel/haswell", + "x86_64/intel/sapphirerapids", + "x86_64/intel/skylake_avx512", + "x86_64/intel/icelake", + "x86_64/intel/cascadelake", + "x86_64/generic" + ], + "aarch64": [ + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", + "aarch64/a64fx" + ] + }, + "2026.06": { + "x86_64": [ + "x86_64/amd/zen2", + "x86_64/amd/zen3", + "x86_64/amd/zen4", + "x86_64/amd/zen5", + "x86_64/intel/haswell", + "x86_64/intel/sapphirerapids", + "x86_64/intel/graniterapids", + "x86_64/intel/skylake_avx512", + "x86_64/intel/icelake", + "x86_64/intel/cascadelake", + "x86_64/generic" + ], + "aarch64": [ + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", + "aarch64/a64fx", + "aarch64/aws/graviton4" + ] + } + }, + "accelerator_targets": { + "2023.06": { + "default": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90" + ], + "x86_64/amd/zen2": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90" + ], + "aarch64/a64fx": [] + }, + "2025.06": { + "default": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", + "amd/gfx908", + "amd/gfx90a", + "amd/gfx942", + "amd/gfx1030", + "amd/gfx1100", + "amd/gfx1101", + "amd/gfx1200", + "amd/gfx1201" + ], + "aarch64/generic": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/neoverse_n1": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/neoverse_v1": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/nvidia/grace": [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/a64fx": [] + }, + "2026.06": { + "default": [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", + "amd/gfx908", + "amd/gfx90a", + "amd/gfx942", + "amd/gfx1030", + "amd/gfx1100", + "amd/gfx1101", + "amd/gfx1200", + "amd/gfx1201" + ], + "aarch64/generic": [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/neoverse_n1": [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/neoverse_v1": [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/nvidia/grace": [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120" + ], + "aarch64/a64fx": [] + } + } +} diff --git a/.github/workflows/test-software.eessi.io.yml b/.github/workflows/test-software.eessi.io.yml index 4f0fa8ffa2..7f95f0f12c 100644 --- a/.github/workflows/test-software.eessi.io.yml +++ b/.github/workflows/test-software.eessi.io.yml @@ -9,162 +9,11 @@ on: permissions: contents: read # to fetch code (actions/checkout) env: - # list below should correspond with table @ https://eessi.io/docs/software_layer/cpu_targets/ - EESSI_CPU_TARGETS: | - 2023.06: - x86_64: - - x86_64/amd/zen2 - - x86_64/amd/zen3 - - x86_64/amd/zen4 - - x86_64/intel/haswell - - x86_64/intel/sapphirerapids - - x86_64/intel/skylake_avx512 - - x86_64/intel/icelake - - x86_64/intel/cascadelake - - x86_64/generic - aarch64: - - aarch64/generic - - aarch64/neoverse_n1 - - aarch64/neoverse_v1 - - aarch64/nvidia/grace - - aarch64/a64fx - - 2025.06: - x86_64: - - x86_64/amd/zen2 - - x86_64/amd/zen3 - - x86_64/amd/zen4 - - x86_64/amd/zen5 - - x86_64/intel/haswell - - x86_64/intel/sapphirerapids - - x86_64/intel/skylake_avx512 - - x86_64/intel/icelake - - x86_64/intel/cascadelake - - x86_64/generic - aarch64: - - aarch64/generic - - aarch64/neoverse_n1 - - aarch64/neoverse_v1 - - aarch64/nvidia/grace - - aarch64/a64fx - - 2026.06: - x86_64: - - x86_64/amd/zen2 - - x86_64/amd/zen3 - - x86_64/amd/zen4 - - x86_64/amd/zen5 - - x86_64/intel/haswell - - x86_64/intel/sapphirerapids - - x86_64/intel/graniterapids - - x86_64/intel/skylake_avx512 - - x86_64/intel/icelake - - x86_64/intel/cascadelake - - x86_64/generic - aarch64: - - aarch64/generic - - aarch64/neoverse_n1 - - aarch64/neoverse_v1 - - aarch64/nvidia/grace - - aarch64/a64fx - - aarch64/aws/graviton4 - - # list below should correspond with table @ https://eessi.io/docs/software_layer/gpu_targets/ - EESSI_ACCELERATOR_TARGETS: | - 2023.06: - # Provide a default set of compute capabilities - default: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - # and then allow for special cases for specific architectures - x86_64/amd/zen2: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - aarch64/a64fx: [] - - 2025.06: - default: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - - amd/gfx908 - - amd/gfx90a - - amd/gfx942 - - amd/gfx1030 - - amd/gfx1100 - - amd/gfx1101 - - amd/gfx1200 - - amd/gfx1201 - aarch64/generic: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/neoverse_n1: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/neoverse_v1: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/nvidia/grace: - - nvidia/cc70 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/a64fx: [] - - 2026.06: - default: - - nvidia/cc75 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - - amd/gfx908 - - amd/gfx90a - - amd/gfx942 - - amd/gfx1030 - - amd/gfx1100 - - amd/gfx1101 - - amd/gfx1200 - - amd/gfx1201 - aarch64/generic: - - nvidia/cc75 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/neoverse_n1: - - nvidia/cc75 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/neoverse_v1: - - nvidia/cc75 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/nvidia/grace: - - nvidia/cc75 - - nvidia/cc80 - - nvidia/cc90 - - nvidia/cc100 - - nvidia/cc120 - aarch64/a64fx: [] + # Supported CPU and accelerator targets per EESSI version live in a single JSON file, so that + # other workflows/scripts can reuse them. The CPU targets should correspond with the table @ + # https://eessi.io/docs/software_layer/cpu_targets/ and the accelerator targets with the table @ + # https://eessi.io/docs/software_layer/gpu_targets/ + EESSI_TARGETS_FILE: ${{ github.workspace }}/.github/workflows/eessi_targets.json jobs: # Checks whether this PR modifies any easystack files and, if so, # determines which EESSI versions are affected. @@ -298,7 +147,7 @@ jobs: run: | # From this extract the CPUs we need to loop over - cpu_subdirs=$(echo "${EESSI_CPU_TARGETS}" | yq ".\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\" | .[]") + cpu_subdirs=$(yq ".cpu_targets.\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\" | .[]" "${EESSI_TARGETS_FILE}") if [[ -z "${cpu_subdirs}" ]]; then echo "ERROR: No CPU subdirs resolved for ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}" exit 1 @@ -363,7 +212,7 @@ jobs: echo echo "now check accelerator builds for ${cpu}" - accelerators=$(echo "${EESSI_ACCELERATOR_TARGETS}" | yq ".\"${{matrix.EESSI_VERSION}}\".\"${cpu}\" // .\"${{matrix.EESSI_VERSION}}\".default | .[]") + accelerators=$(yq ".accelerator_targets.\"${{matrix.EESSI_VERSION}}\".\"${cpu}\" // .accelerator_targets.\"${{matrix.EESSI_VERSION}}\".default | .[]" "${EESSI_TARGETS_FILE}") if [[ -z "${accelerators}" ]]; then echo "no accelerator targets defined for ${cpu}" @@ -458,16 +307,14 @@ jobs: echo "::group::EESSI ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}" # Get all CPU targets belonging to this architecture family. - CPU_TARGETS=$(echo "${EESSI_CPU_TARGETS}" \ - | yq -r ".\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\"[]") + CPU_TARGETS=$(yq -r ".cpu_targets.\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\"[]" "${EESSI_TARGETS_FILE}") for COMPARISON_ARCH in ${CPU_TARGETS}; do echo "::group::Compare ${EESSI_VERSION} / ${COMPARISON_ARCH}" # Use architecture-specific accelerator targets where defined, # otherwise fall back to the default set. - ALL_ACCELERATOR_TARGETS=$(echo "${EESSI_ACCELERATOR_TARGETS}" \ - | yq ".\"${{ matrix.EESSI_VERSION }}\".\"${COMPARISON_ARCH}\" // .\"${{ matrix.EESSI_VERSION }}\".default | .[]" \ + ALL_ACCELERATOR_TARGETS=$(yq ".accelerator_targets.\"${{ matrix.EESSI_VERSION }}\".\"${COMPARISON_ARCH}\" // .accelerator_targets.\"${{ matrix.EESSI_VERSION }}\".default | .[]" "${EESSI_TARGETS_FILE}" \ | tr '\n' ' ') echo "COMPARISON_ARCH=${COMPARISON_ARCH}" From 7089f04144d8d35a6964e7f582aed4debd8cf49e Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 5 Oct 2026 14:27:02 +0200 Subject: [PATCH 3/8] check_builds.py: read supported CPU targets from eessi_targets.json Replace the placeholder SUPPORTED_TARGETS mapping with targets read from the shared .github/workflows/eessi_targets.json (also used by test-software.eessi.io.yml), so the list is defined only once. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/scripts/check_builds.py | 59 ++++++++++------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/.github/workflows/scripts/check_builds.py b/.github/workflows/scripts/check_builds.py index 3a73505702..aff53064f5 100644 --- a/.github/workflows/scripts/check_builds.py +++ b/.github/workflows/scripts/check_builds.py @@ -7,41 +7,37 @@ # No API calls required — the triggering comment body is already available. # # Exit codes: -# 0: Success (all supported targets have successful builds, or mapping is empty) +# 0: Success (all supported targets have successful builds) # 1: Failure (missing/failed builds, or commit SHA inconsistency) import datetime +import json import os import sys import re -# ============================================================================ -# TODO: FILL IN THE SUPPORTED CPU TARGETS PER REPO -# ============================================================================ -# This mapping defines which CPU targets (values of the 'for' column) must be -# successfully built for each repository (value of the 'repo' column). -# The values below are a placeholder — please fill in the actual supported -# targets for your repositories. -# -# Example structure: -# SUPPORTED_TARGETS = { -# "eessi.io-2025.06-software": [ -# "x86_64/amd/zen2", -# "x86_64/amd/zen3", -# "x86_64/amd/zen4", -# "x86_64/intel/haswell", -# # ... add all supported targets for this repo ... -# ], -# "eessi.io-2023.06-software": [ -# # ... supported targets for 2023.06 ... -# ], -# } -# ============================================================================ -SUPPORTED_TARGETS = { - # Placeholder — fill in your supported targets here - # "eessi.io-2025.06-software": ["x86_64/amd/zen2"], -} +# The supported CPU targets per EESSI version are defined in a single place, shared +# with the other workflows: .github/workflows/eessi_targets.json +TARGETS_FILE = os.environ.get( + "EESSI_TARGETS_FILE", + os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "eessi_targets.json"), +) + + +def load_supported_targets(targets_file=TARGETS_FILE): + """ + Build the mapping from repository name (value of the 'repo' column in the bot's + status table, e.g. 'eessi.io-2025.06-software') to the list of CPU targets (values + of the 'for' column) that must have been successfully built for it. + The JSON file lists the targets per EESSI version and per CPU family; those are flattened here. + """ + with open(targets_file) as f: + cpu_targets = json.load(f)["cpu_targets"] + return { + f"eessi.io-{version}-software": [t for family in families.values() for t in family] + for version, families in cpu_targets.items() + } def parse_date(date_str): @@ -152,6 +148,8 @@ def main(): print("ERROR: No valid builds found in table") sys.exit(1) + SUPPORTED_TARGETS = load_supported_targets() + # Determine which repos are present in both table and mapping table_repos = set(row.get("repo") for row in deduped.values() if row.get("repo")) mapping_repos = set(SUPPORTED_TARGETS.keys()) @@ -159,7 +157,7 @@ def main(): # Warn if repos in table are missing from mapping for repo in table_repos - mapping_repos: - print(f"WARNING: Repo '{repo}' found in table but not in SUPPORTED_TARGETS mapping; skipping checks for this repo") + print(f"WARNING: Repo '{repo}' found in table but not in eessi_targets.json; skipping checks for this repo") # Check commit SHA consistency across all deduplicated builds (if column present) commit_shas = set() @@ -203,11 +201,6 @@ def main(): else: print(f" OK: Target '{target}' built successfully") - # Check if mapping is empty - if not mapping_repos: - print("\nWARNING: SUPPORTED_TARGETS mapping is empty — no checks performed.") - print("Please populate SUPPORTED_TARGETS in check_builds.py with your supported targets.") - if failed: print("\nERROR: Build verification failed. Please fix the above issues.") sys.exit(1) From 64dfe1d2b5557c4b9fed66c263dc8b8d0f37cec3 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 5 Oct 2026 16:06:00 +0200 Subject: [PATCH 4/8] Use jq instead of yq to read eessi_targets.json yq infers its output format from the input file extension, so reading a .json file produced quoted JSON strings (e.g. "x86_64/amd/zen2"), which broke the CPU target detection. jq -r prints raw strings. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/test-software.eessi.io.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-software.eessi.io.yml b/.github/workflows/test-software.eessi.io.yml index 7f95f0f12c..950d10d062 100644 --- a/.github/workflows/test-software.eessi.io.yml +++ b/.github/workflows/test-software.eessi.io.yml @@ -147,7 +147,7 @@ jobs: run: | # From this extract the CPUs we need to loop over - cpu_subdirs=$(yq ".cpu_targets.\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\" | .[]" "${EESSI_TARGETS_FILE}") + cpu_subdirs=$(jq -r --arg v "${EESSI_VERSION}" --arg f "${EESSI_CPU_FAMILY}" '.cpu_targets[$v][$f][]' "${EESSI_TARGETS_FILE}") if [[ -z "${cpu_subdirs}" ]]; then echo "ERROR: No CPU subdirs resolved for ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}" exit 1 @@ -212,7 +212,7 @@ jobs: echo echo "now check accelerator builds for ${cpu}" - accelerators=$(yq ".accelerator_targets.\"${{matrix.EESSI_VERSION}}\".\"${cpu}\" // .accelerator_targets.\"${{matrix.EESSI_VERSION}}\".default | .[]" "${EESSI_TARGETS_FILE}") + accelerators=$(jq -r --arg v "${{matrix.EESSI_VERSION}}" --arg c "${cpu}" '.accelerator_targets[$v] | (.[$c] // .default) | .[]' "${EESSI_TARGETS_FILE}") if [[ -z "${accelerators}" ]]; then echo "no accelerator targets defined for ${cpu}" @@ -307,14 +307,14 @@ jobs: echo "::group::EESSI ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}" # Get all CPU targets belonging to this architecture family. - CPU_TARGETS=$(yq -r ".cpu_targets.\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\"[]" "${EESSI_TARGETS_FILE}") + CPU_TARGETS=$(jq -r --arg v "${EESSI_VERSION}" --arg f "${EESSI_CPU_FAMILY}" '.cpu_targets[$v][$f][]' "${EESSI_TARGETS_FILE}") for COMPARISON_ARCH in ${CPU_TARGETS}; do echo "::group::Compare ${EESSI_VERSION} / ${COMPARISON_ARCH}" # Use architecture-specific accelerator targets where defined, # otherwise fall back to the default set. - ALL_ACCELERATOR_TARGETS=$(yq ".accelerator_targets.\"${{ matrix.EESSI_VERSION }}\".\"${COMPARISON_ARCH}\" // .accelerator_targets.\"${{ matrix.EESSI_VERSION }}\".default | .[]" "${EESSI_TARGETS_FILE}" \ + ALL_ACCELERATOR_TARGETS=$(jq -r --arg v "${{ matrix.EESSI_VERSION }}" --arg c "${COMPARISON_ARCH}" '.accelerator_targets[$v] | (.[$c] // .default) | .[]' "${EESSI_TARGETS_FILE}" \ | tr '\n' ' ') echo "COMPARISON_ARCH=${COMPARISON_ARCH}" From 8366f079b3e2425785c5bcfafdca472262f45a29 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 5 Oct 2026 16:28:08 +0200 Subject: [PATCH 5/8] Upload per-CPU-target logs of the missing installations check as artifacts Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/test-software.eessi.io.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/test-software.eessi.io.yml b/.github/workflows/test-software.eessi.io.yml index 950d10d062..06e0f69c9d 100644 --- a/.github/workflows/test-software.eessi.io.yml +++ b/.github/workflows/test-software.eessi.io.yml @@ -274,6 +274,17 @@ jobs: done + # The per-CPU-target logs are only printed to the job output when a target fails (and then only + # the first failing one), so always keep them as an artifact, also for successful runs + - name: Upload per-CPU-target logs + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: missing-installations-logs-${{ matrix.EESSI_VERSION }}-${{ matrix.runs_on }} + path: log_*.txt + if-no-files-found: ignore + retention-days: 14 + - name: Test check_missing_installations.sh with missing package (GCC/8.3.0) run: | # This is a general check, doesn't need to be run for every CPU, just the host is fine From 71b5d2fe6825523b36c0fabb8d75cc776e42e583 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 6 Oct 2026 14:27:30 +0200 Subject: [PATCH 6/8] Use TOML instead of JSON for eessi_targets TOML is parseable from Python's standard library (tomllib, 3.11+) and from the shell with yq, and unlike JSON it allows comments. yq is called with explicit input/output formats (-p toml -o yaml) so the output is raw strings, rather than relying on yq inferring the output format from the file extension. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/eessi_targets.json | 175 ------------------ .github/workflows/eessi_targets.toml | 184 +++++++++++++++++++ .github/workflows/test-software.eessi.io.yml | 12 +- 3 files changed, 190 insertions(+), 181 deletions(-) delete mode 100644 .github/workflows/eessi_targets.json create mode 100644 .github/workflows/eessi_targets.toml diff --git a/.github/workflows/eessi_targets.json b/.github/workflows/eessi_targets.json deleted file mode 100644 index a788dec6b4..0000000000 --- a/.github/workflows/eessi_targets.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "cpu_targets": { - "2023.06": { - "x86_64": [ - "x86_64/amd/zen2", - "x86_64/amd/zen3", - "x86_64/amd/zen4", - "x86_64/intel/haswell", - "x86_64/intel/sapphirerapids", - "x86_64/intel/skylake_avx512", - "x86_64/intel/icelake", - "x86_64/intel/cascadelake", - "x86_64/generic" - ], - "aarch64": [ - "aarch64/generic", - "aarch64/neoverse_n1", - "aarch64/neoverse_v1", - "aarch64/nvidia/grace", - "aarch64/a64fx" - ] - }, - "2025.06": { - "x86_64": [ - "x86_64/amd/zen2", - "x86_64/amd/zen3", - "x86_64/amd/zen4", - "x86_64/amd/zen5", - "x86_64/intel/haswell", - "x86_64/intel/sapphirerapids", - "x86_64/intel/skylake_avx512", - "x86_64/intel/icelake", - "x86_64/intel/cascadelake", - "x86_64/generic" - ], - "aarch64": [ - "aarch64/generic", - "aarch64/neoverse_n1", - "aarch64/neoverse_v1", - "aarch64/nvidia/grace", - "aarch64/a64fx" - ] - }, - "2026.06": { - "x86_64": [ - "x86_64/amd/zen2", - "x86_64/amd/zen3", - "x86_64/amd/zen4", - "x86_64/amd/zen5", - "x86_64/intel/haswell", - "x86_64/intel/sapphirerapids", - "x86_64/intel/graniterapids", - "x86_64/intel/skylake_avx512", - "x86_64/intel/icelake", - "x86_64/intel/cascadelake", - "x86_64/generic" - ], - "aarch64": [ - "aarch64/generic", - "aarch64/neoverse_n1", - "aarch64/neoverse_v1", - "aarch64/nvidia/grace", - "aarch64/a64fx", - "aarch64/aws/graviton4" - ] - } - }, - "accelerator_targets": { - "2023.06": { - "default": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90" - ], - "x86_64/amd/zen2": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90" - ], - "aarch64/a64fx": [] - }, - "2025.06": { - "default": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", - "amd/gfx908", - "amd/gfx90a", - "amd/gfx942", - "amd/gfx1030", - "amd/gfx1100", - "amd/gfx1101", - "amd/gfx1200", - "amd/gfx1201" - ], - "aarch64/generic": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/neoverse_n1": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/neoverse_v1": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/nvidia/grace": [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/a64fx": [] - }, - "2026.06": { - "default": [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", - "amd/gfx908", - "amd/gfx90a", - "amd/gfx942", - "amd/gfx1030", - "amd/gfx1100", - "amd/gfx1101", - "amd/gfx1200", - "amd/gfx1201" - ], - "aarch64/generic": [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/neoverse_n1": [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/neoverse_v1": [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/nvidia/grace": [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120" - ], - "aarch64/a64fx": [] - } - } -} diff --git a/.github/workflows/eessi_targets.toml b/.github/workflows/eessi_targets.toml new file mode 100644 index 0000000000..5d5d10b78d --- /dev/null +++ b/.github/workflows/eessi_targets.toml @@ -0,0 +1,184 @@ +# Supported targets per EESSI version, shared by the CI workflows and scripts. +# +# cpu_targets: should correspond with the table @ https://eessi.io/docs/software_layer/cpu_targets/ +# Per EESSI version, the CPU targets for each CPU family. +# accelerator_targets: should correspond with the table @ https://eessi.io/docs/software_layer/gpu_targets/ +# Per EESSI version, the accelerator targets to build for. 'default' applies to every CPU target, +# unless a CPU target has an entry of its own (which may be empty, i.e. no accelerators). + + +[cpu_targets."2023.06"] +x86_64 = [ + "x86_64/amd/zen2", + "x86_64/amd/zen3", + "x86_64/amd/zen4", + "x86_64/intel/haswell", + "x86_64/intel/sapphirerapids", + "x86_64/intel/skylake_avx512", + "x86_64/intel/icelake", + "x86_64/intel/cascadelake", + "x86_64/generic", +] +aarch64 = [ + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", + "aarch64/a64fx", +] + +[cpu_targets."2025.06"] +x86_64 = [ + "x86_64/amd/zen2", + "x86_64/amd/zen3", + "x86_64/amd/zen4", + "x86_64/amd/zen5", + "x86_64/intel/haswell", + "x86_64/intel/sapphirerapids", + "x86_64/intel/skylake_avx512", + "x86_64/intel/icelake", + "x86_64/intel/cascadelake", + "x86_64/generic", +] +aarch64 = [ + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", + "aarch64/a64fx", +] + +[cpu_targets."2026.06"] +x86_64 = [ + "x86_64/amd/zen2", + "x86_64/amd/zen3", + "x86_64/amd/zen4", + "x86_64/amd/zen5", + "x86_64/intel/haswell", + "x86_64/intel/sapphirerapids", + "x86_64/intel/graniterapids", + "x86_64/intel/skylake_avx512", + "x86_64/intel/icelake", + "x86_64/intel/cascadelake", + "x86_64/generic", +] +aarch64 = [ + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", + "aarch64/a64fx", + "aarch64/aws/graviton4", +] + + +[accelerator_targets."2023.06"] +# Provide a default set of compute capabilities +default = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", +] +# and then allow for special cases for specific CPU targets +"x86_64/amd/zen2" = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", +] +"aarch64/a64fx" = [] + +[accelerator_targets."2025.06"] +# Provide a default set of compute capabilities +default = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", + "amd/gfx908", + "amd/gfx90a", + "amd/gfx942", + "amd/gfx1030", + "amd/gfx1100", + "amd/gfx1101", + "amd/gfx1200", + "amd/gfx1201", +] +# and then allow for special cases for specific CPU targets +"aarch64/generic" = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/neoverse_n1" = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/neoverse_v1" = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/nvidia/grace" = [ + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/a64fx" = [] + +[accelerator_targets."2026.06"] +# Provide a default set of compute capabilities +default = [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", + "amd/gfx908", + "amd/gfx90a", + "amd/gfx942", + "amd/gfx1030", + "amd/gfx1100", + "amd/gfx1101", + "amd/gfx1200", + "amd/gfx1201", +] +# and then allow for special cases for specific CPU targets +"aarch64/generic" = [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/neoverse_n1" = [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/neoverse_v1" = [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/nvidia/grace" = [ + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", + "nvidia/cc100", + "nvidia/cc120", +] +"aarch64/a64fx" = [] diff --git a/.github/workflows/test-software.eessi.io.yml b/.github/workflows/test-software.eessi.io.yml index 06e0f69c9d..b7b2ba904e 100644 --- a/.github/workflows/test-software.eessi.io.yml +++ b/.github/workflows/test-software.eessi.io.yml @@ -9,11 +9,11 @@ on: permissions: contents: read # to fetch code (actions/checkout) env: - # Supported CPU and accelerator targets per EESSI version live in a single JSON file, so that + # Supported CPU and accelerator targets per EESSI version live in a single TOML file, so that # other workflows/scripts can reuse them. The CPU targets should correspond with the table @ # https://eessi.io/docs/software_layer/cpu_targets/ and the accelerator targets with the table @ # https://eessi.io/docs/software_layer/gpu_targets/ - EESSI_TARGETS_FILE: ${{ github.workspace }}/.github/workflows/eessi_targets.json + EESSI_TARGETS_FILE: ${{ github.workspace }}/.github/workflows/eessi_targets.toml jobs: # Checks whether this PR modifies any easystack files and, if so, # determines which EESSI versions are affected. @@ -147,7 +147,7 @@ jobs: run: | # From this extract the CPUs we need to loop over - cpu_subdirs=$(jq -r --arg v "${EESSI_VERSION}" --arg f "${EESSI_CPU_FAMILY}" '.cpu_targets[$v][$f][]' "${EESSI_TARGETS_FILE}") + cpu_subdirs=$(yq -p toml -o yaml ".cpu_targets.\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\" | .[]" "${EESSI_TARGETS_FILE}") if [[ -z "${cpu_subdirs}" ]]; then echo "ERROR: No CPU subdirs resolved for ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}" exit 1 @@ -212,7 +212,7 @@ jobs: echo echo "now check accelerator builds for ${cpu}" - accelerators=$(jq -r --arg v "${{matrix.EESSI_VERSION}}" --arg c "${cpu}" '.accelerator_targets[$v] | (.[$c] // .default) | .[]' "${EESSI_TARGETS_FILE}") + accelerators=$(yq -p toml -o yaml ".accelerator_targets.\"${{matrix.EESSI_VERSION}}\".\"${cpu}\" // .accelerator_targets.\"${{matrix.EESSI_VERSION}}\".default | .[]" "${EESSI_TARGETS_FILE}") if [[ -z "${accelerators}" ]]; then echo "no accelerator targets defined for ${cpu}" @@ -318,14 +318,14 @@ jobs: echo "::group::EESSI ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}" # Get all CPU targets belonging to this architecture family. - CPU_TARGETS=$(jq -r --arg v "${EESSI_VERSION}" --arg f "${EESSI_CPU_FAMILY}" '.cpu_targets[$v][$f][]' "${EESSI_TARGETS_FILE}") + CPU_TARGETS=$(yq -p toml -o yaml ".cpu_targets.\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\" | .[]" "${EESSI_TARGETS_FILE}") for COMPARISON_ARCH in ${CPU_TARGETS}; do echo "::group::Compare ${EESSI_VERSION} / ${COMPARISON_ARCH}" # Use architecture-specific accelerator targets where defined, # otherwise fall back to the default set. - ALL_ACCELERATOR_TARGETS=$(jq -r --arg v "${{ matrix.EESSI_VERSION }}" --arg c "${COMPARISON_ARCH}" '.accelerator_targets[$v] | (.[$c] // .default) | .[]' "${EESSI_TARGETS_FILE}" \ + ALL_ACCELERATOR_TARGETS=$(yq -p toml -o yaml ".accelerator_targets.\"${{ matrix.EESSI_VERSION }}\".\"${COMPARISON_ARCH}\" // .accelerator_targets.\"${{ matrix.EESSI_VERSION }}\".default | .[]" "${EESSI_TARGETS_FILE}" \ | tr '\n' ' ') echo "COMPARISON_ARCH=${COMPARISON_ARCH}" From 5658f7d3c44e3efd9a7627e4a20aa933f5b18c2b Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 6 Oct 2026 14:27:43 +0200 Subject: [PATCH 7/8] check_builds.py: read eessi_targets.toml using tomllib Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/scripts/check_builds.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/scripts/check_builds.py b/.github/workflows/scripts/check_builds.py index aff53064f5..4bd7d80f6b 100644 --- a/.github/workflows/scripts/check_builds.py +++ b/.github/workflows/scripts/check_builds.py @@ -11,17 +11,17 @@ # 1: Failure (missing/failed builds, or commit SHA inconsistency) import datetime -import json import os import sys import re +import tomllib # The supported CPU targets per EESSI version are defined in a single place, shared -# with the other workflows: .github/workflows/eessi_targets.json +# with the other workflows: .github/workflows/eessi_targets.toml TARGETS_FILE = os.environ.get( "EESSI_TARGETS_FILE", - os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "eessi_targets.json"), + os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "eessi_targets.toml"), ) @@ -30,10 +30,10 @@ def load_supported_targets(targets_file=TARGETS_FILE): Build the mapping from repository name (value of the 'repo' column in the bot's status table, e.g. 'eessi.io-2025.06-software') to the list of CPU targets (values of the 'for' column) that must have been successfully built for it. - The JSON file lists the targets per EESSI version and per CPU family; those are flattened here. + The TOML file lists the targets per EESSI version and per CPU family; those are flattened here. """ - with open(targets_file) as f: - cpu_targets = json.load(f)["cpu_targets"] + with open(targets_file, "rb") as f: + cpu_targets = tomllib.load(f)["cpu_targets"] return { f"eessi.io-{version}-software": [t for family in families.values() for t in family] for version, families in cpu_targets.items() @@ -157,7 +157,7 @@ def main(): # Warn if repos in table are missing from mapping for repo in table_repos - mapping_repos: - print(f"WARNING: Repo '{repo}' found in table but not in eessi_targets.json; skipping checks for this repo") + print(f"WARNING: Repo '{repo}' found in table but not in eessi_targets.toml; skipping checks for this repo") # Check commit SHA consistency across all deduplicated builds (if column present) commit_shas = set() From 2904935b7d4419f78cb13e10f22bf51f6e36fd19 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 6 Oct 2026 14:52:00 +0200 Subject: [PATCH 8/8] Sort targets in eessi_targets.toml alphabetically Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/eessi_targets.toml | 200 +++++++++++++-------------- 1 file changed, 99 insertions(+), 101 deletions(-) diff --git a/.github/workflows/eessi_targets.toml b/.github/workflows/eessi_targets.toml index 5d5d10b78d..a328646738 100644 --- a/.github/workflows/eessi_targets.toml +++ b/.github/workflows/eessi_targets.toml @@ -6,179 +6,177 @@ # Per EESSI version, the accelerator targets to build for. 'default' applies to every CPU target, # unless a CPU target has an entry of its own (which may be empty, i.e. no accelerators). - [cpu_targets."2023.06"] +aarch64 = [ + "aarch64/a64fx", + "aarch64/generic", + "aarch64/neoverse_n1", + "aarch64/neoverse_v1", + "aarch64/nvidia/grace", +] x86_64 = [ "x86_64/amd/zen2", "x86_64/amd/zen3", "x86_64/amd/zen4", + "x86_64/generic", + "x86_64/intel/cascadelake", "x86_64/intel/haswell", + "x86_64/intel/icelake", "x86_64/intel/sapphirerapids", "x86_64/intel/skylake_avx512", - "x86_64/intel/icelake", - "x86_64/intel/cascadelake", - "x86_64/generic", ] + +[cpu_targets."2025.06"] aarch64 = [ + "aarch64/a64fx", "aarch64/generic", "aarch64/neoverse_n1", "aarch64/neoverse_v1", "aarch64/nvidia/grace", - "aarch64/a64fx", ] - -[cpu_targets."2025.06"] x86_64 = [ "x86_64/amd/zen2", "x86_64/amd/zen3", "x86_64/amd/zen4", "x86_64/amd/zen5", + "x86_64/generic", + "x86_64/intel/cascadelake", "x86_64/intel/haswell", + "x86_64/intel/icelake", "x86_64/intel/sapphirerapids", "x86_64/intel/skylake_avx512", - "x86_64/intel/icelake", - "x86_64/intel/cascadelake", - "x86_64/generic", ] + +[cpu_targets."2026.06"] aarch64 = [ + "aarch64/a64fx", + "aarch64/aws/graviton4", "aarch64/generic", "aarch64/neoverse_n1", "aarch64/neoverse_v1", "aarch64/nvidia/grace", - "aarch64/a64fx", ] - -[cpu_targets."2026.06"] x86_64 = [ "x86_64/amd/zen2", "x86_64/amd/zen3", "x86_64/amd/zen4", "x86_64/amd/zen5", + "x86_64/generic", + "x86_64/intel/cascadelake", + "x86_64/intel/graniterapids", "x86_64/intel/haswell", + "x86_64/intel/icelake", "x86_64/intel/sapphirerapids", - "x86_64/intel/graniterapids", "x86_64/intel/skylake_avx512", - "x86_64/intel/icelake", - "x86_64/intel/cascadelake", - "x86_64/generic", -] -aarch64 = [ - "aarch64/generic", - "aarch64/neoverse_n1", - "aarch64/neoverse_v1", - "aarch64/nvidia/grace", - "aarch64/a64fx", - "aarch64/aws/graviton4", ] - [accelerator_targets."2023.06"] # Provide a default set of compute capabilities default = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] # and then allow for special cases for specific CPU targets +"aarch64/a64fx" = [] "x86_64/amd/zen2" = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] -"aarch64/a64fx" = [] [accelerator_targets."2025.06"] # Provide a default set of compute capabilities default = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", - "amd/gfx908", - "amd/gfx90a", - "amd/gfx942", - "amd/gfx1030", - "amd/gfx1100", - "amd/gfx1101", - "amd/gfx1200", - "amd/gfx1201", + "amd/gfx1030", + "amd/gfx1100", + "amd/gfx1101", + "amd/gfx1200", + "amd/gfx1201", + "amd/gfx908", + "amd/gfx90a", + "amd/gfx942", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] # and then allow for special cases for specific CPU targets +"aarch64/a64fx" = [] "aarch64/generic" = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] "aarch64/neoverse_n1" = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] "aarch64/neoverse_v1" = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] "aarch64/nvidia/grace" = [ - "nvidia/cc70", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc70", + "nvidia/cc80", + "nvidia/cc90", ] -"aarch64/a64fx" = [] [accelerator_targets."2026.06"] # Provide a default set of compute capabilities default = [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", - "amd/gfx908", - "amd/gfx90a", - "amd/gfx942", - "amd/gfx1030", - "amd/gfx1100", - "amd/gfx1101", - "amd/gfx1200", - "amd/gfx1201", + "amd/gfx1030", + "amd/gfx1100", + "amd/gfx1101", + "amd/gfx1200", + "amd/gfx1201", + "amd/gfx908", + "amd/gfx90a", + "amd/gfx942", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", ] # and then allow for special cases for specific CPU targets +"aarch64/a64fx" = [] "aarch64/generic" = [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", ] "aarch64/neoverse_n1" = [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", ] "aarch64/neoverse_v1" = [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", ] "aarch64/nvidia/grace" = [ - "nvidia/cc75", - "nvidia/cc80", - "nvidia/cc90", - "nvidia/cc100", - "nvidia/cc120", + "nvidia/cc100", + "nvidia/cc120", + "nvidia/cc75", + "nvidia/cc80", + "nvidia/cc90", ] -"aarch64/a64fx" = []