Skip to content

{2026.06}[2026.1] Dependencies of GROMACS 2026.3 #5120

{2026.06}[2026.1] Dependencies of GROMACS 2026.3

{2026.06}[2026.1] Dependencies of GROMACS 2026.3 #5120

# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions
name: Check for missing software installations in software.eessi.io
on:
push:
branches: [ "main" ]
pull_request:
types: [opened, synchronize, reopened, labeled]
workflow_dispatch:
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: []
jobs:
# Checks whether this PR modifies any easystack files and, if so,
# determines which EESSI versions are affected.
# It then stores those versions as a space-separated list in an
# environment variable.
# Finally, it writes that value to GITHUB_OUTPUT using the correct
# heredoc format.
check_EESSI_version_changed_files:
runs-on: ubuntu-24.04
outputs:
EESSI_VERSIONS: ${{ steps.detect.outputs.EESSI_VERSIONS }}
steps:
- name: Check out software-layer repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # Fetch all history for all branches and tags
- name: Detect EESSI version in modified easystack files
id: detect
run: |
# Fetch base branch explicitly to ensure it's available
git fetch origin ${{ github.base_ref }}
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
changed_files=$(git diff --name-only "${{ github.event.pull_request.base.sha }}...HEAD")
else
changed_files=$(git diff --name-only "${{ github.event.before }}...HEAD")
fi
echo "Files changed: $changed_files"
# Default to not checking missing software for any version
EESSI_VERSIONS=""
# Check for specific versions in the changed easystack files
# The regex pattern matches a prefix, but only returns the part after \K, so that we get only the version
# The sort ensures predictable ordering, and with -u only keeps unique items (neither are probably essential, but both are nice)
# Finally, since the grep returns multiple lines if there are multiple versions that were touched,
# the tr replaces newlines with space, to make this space-separated.
EESSI_VERSIONS=$(printf '%s\n' "$changed_files" \
| grep -oP 'easystacks/software\.eessi\.io/\K[0-9]+\.[0-9]+' \
| sort -u \
| tr '\n' ' ')
echo "PR easystack changes related to EESSI VERSION: $EESSI_VERSIONS"
# Use GITHUB_OUTPUT heredoc correctly
echo "EESSI_VERSIONS<<EOF" >> "$GITHUB_OUTPUT"
echo "$EESSI_VERSIONS" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
requires_forced_ci:
if: github.event_name == 'pull_request'
runs-on: ubuntu-24.04
needs: check_EESSI_version_changed_files
steps:
- name: Check whether force-ci-checks is required
if: >
needs.check_EESSI_version_changed_files.outputs.EESSI_VERSIONS == ''
&& !contains(github.event.pull_request.labels.*.name, 'force-ci-checks')
run: |
echo "::error::No EasyStack changes detected, so missing-installation CI was skipped."
echo "::error::All PRs require missing-installation CI, someone with triage rights needs to add the 'force-ci-checks' label."
exit 1
- name: Force CI label is present or EasyStack changes detected
if: >
needs.check_EESSI_version_changed_files.outputs.EESSI_VERSIONS != ''
|| contains(github.event.pull_request.labels.*.name, 'force-ci-checks')
run: echo "No forced CI required."
check_missing:
if: >
(
contains(github.event.pull_request.labels.*.name, 'bot:deploy')
|| contains(github.event.pull_request.labels.*.name, 'force-ci-checks')
)
needs: check_EESSI_version_changed_files
strategy:
fail-fast: false
matrix:
include:
# Arm CPU targets (EESSI 2023.06)
- runs_on: ubuntu-24.04-arm
EESSI_VERSION: 2023.06
# x86_64 CPU targets (EESSI 2023.06)
- runs_on: ubuntu-24.04
EESSI_VERSION: 2023.06
# Arm CPU targets (EESSI 2025.06)
- runs_on: ubuntu-24.04-arm
EESSI_VERSION: 2025.06
# x86_64 CPU targets (EESSI 2025.06)
- runs_on: ubuntu-24.04
EESSI_VERSION: 2025.06
# Arm CPU targets (EESSI 2026.06)
- runs_on: ubuntu-24.04-arm
EESSI_VERSION: 2026.06
# x86_64 CPU targets (EESSI 2026.06)
- runs_on: ubuntu-24.04
EESSI_VERSION: 2026.06
runs-on: ${{ matrix.runs_on }}
steps:
- name: Check out software-layer repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # Fetch all history for all branches and tags
- name: Clone EESSI/software-layer-scripts repository
run: |
git clone https://github.com/EESSI/software-layer-scripts
- name: Show host system info
run: |
echo "/proc/cpuinfo:"
cat /proc/cpuinfo
echo
echo "lscpu:"
lscpu
- name: Mount EESSI CernVM-FS repository
uses: eessi/github-action-eessi@v3
with:
eessi_stack_version: '${{matrix.EESSI_VERSION}}'
- name: Check for missing installations
if: >
contains(github.event.pull_request.labels.*.name, 'force-ci-checks')
|| contains(
needs.check_EESSI_version_changed_files.outputs.EESSI_VERSIONS,
matrix.EESSI_VERSION
)
run: |
# From this extract the CPUs we need to loop over
cpu_subdirs=$(echo "${EESSI_CPU_TARGETS}" | yq ".\"${EESSI_VERSION}\".\"${EESSI_CPU_FAMILY}\" | .[]")
if [[ -z "${cpu_subdirs}" ]]; then
echo "ERROR: No CPU subdirs resolved for ${EESSI_VERSION} / ${EESSI_CPU_FAMILY}"
exit 1
fi
cpu_array=($cpu_subdirs)
for ((i=0; i<${#cpu_array[@]}; i+=2)); do
pids=()
labels=()
logs=()
for ((j=i; j<i+2 && j<${#cpu_array[@]}; j++)); do
cpu="${cpu_array[j]}"
safe_cpu="${cpu//\//_}"
log="log_${safe_cpu}.txt"
echo ""
echo "---------------- CPU TARGET ----------------"
echo "$cpu"
echo "-------------------------------------------"
(
set -e -o pipefail
module --force purge
export EESSI_SOFTWARE_SUBDIR_OVERRIDE="$cpu"
module load EESSI/${{matrix.EESSI_VERSION}}
env | grep ^EESSI | sort
cache_file="${EESSI_SOFTWARE_PATH}/.lmod/cache/spiderT.lua"
if [[ -f "$cache_file" ]]; then
ls -l "$cache_file"
else
echo "ERROR: Lmod cache file is missing for CPU target"
echo "Expected file: $cache_file"
exit 1
fi
echo "first run check_missing_installations.sh for CPU-only builds"
for easystack_file in $(EESSI_VERSION=${{matrix.EESSI_VERSION}} .github/workflows/scripts/only_latest_easystacks.sh); do
eb_version=$(echo ${easystack_file} | sed 's/.*eb-\([0-9.]*\).*.yml/\1/g')
echo "checking ${easystack_file} with EasyBuild ${eb_version}..."
if [[ "$easystack_file" =~ /(additional_arch|arch_specific)/ ]]; then
if [[ "$easystack_file" != *"/$EESSI_CPU_FAMILY/"* ]]; then
echo "Detected an additional arch or arch-specific easystack with CPU family not matching host ($EESSI_CPU_FAMILY), skipping CI for $easystack_file"
continue
fi
fi
module purge
module load EasyBuild/${eb_version}
which eb
eb --version
software-layer-scripts/check_missing_installations.sh ${easystack_file}
done
echo
echo "now check accelerator builds for ${cpu}"
accelerators=$(echo "${EESSI_ACCELERATOR_TARGETS}" | yq ".\"${{matrix.EESSI_VERSION}}\".\"${cpu}\" // .\"${{matrix.EESSI_VERSION}}\".default | .[]")
if [[ -z "${accelerators}" ]]; then
echo "no accelerator targets defined for ${cpu}"
else
for accel in ${accelerators}; do
module use ${EESSI_SOFTWARE_PATH}/accel/${accel}/modules/all
echo "checking accelerator ${accel}"
for easystack_file in $(EESSI_VERSION=${{matrix.EESSI_VERSION}} ACCEL_EASYSTACKS=1 .github/workflows/scripts/only_latest_easystacks.sh); do
vendor="${accel%%/*}"
if [[ "${easystack_file}" == *"accel/${vendor}"* ]]; then
eb_version=$(echo ${easystack_file} | sed 's/.*eb-\([0-9.]*\).*.yml/\1/g')
module purge
module load EasyBuild/${eb_version}
which eb
eb --version
software-layer-scripts/check_missing_installations.sh ${easystack_file}
else
echo "Skipping ${easystack_file} (vendor mismatch for ${accel})"
fi
done
module unuse ${EESSI_SOFTWARE_PATH}/accel/${accel}/modules/all
done
fi
) >"$log" 2>&1 &
pids+=($!)
labels+=("$cpu")
logs+=("$log")
done
# wait + report results for this batch of 2
for ((k=0; k<${#pids[@]}; k++)); do
pid="${pids[k]}"
cpu="${labels[k]}"
log="${logs[k]}"
if ! wait "$pid"; then
echo "========================================"
echo "FAILED CPU TARGET: $cpu"
echo "LOG FILE: $log"
echo "========================================"
cat "$log"
exit 1
else
echo "SUCCESS: $cpu"
# Show any architectures that were intentionally skipped
grep "Detected an additional arch" "$log" || true
fi
done
done
- 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
source /cvmfs/software.eessi.io/versions/${{matrix.EESSI_VERSION}}/init/bash
module load EasyBuild
which eb
eb --version
env | grep ^EESSI | sort
# create dummy easystack file with a single entry (something that is not installed in EESSI)
easystack_file="test.yml"
echo "easyconfigs:" > ${easystack_file}
echo " - GCC-8.3.0:" >> ${easystack_file}
echo "created easystack file '${easystack_file}' with a missing installation (GCC/8.3.0):"
cat ${easystack_file}
# note, check_missing_installations.sh exits 1 if a package was
# missing, which is intepreted as false (exit code based, not
# boolean logic), hence when the script exits 0 if no package was
# missing it is interpreted as true, thus the test did not capture
# the missing package
if software-layer-scripts/check_missing_installations.sh ${easystack_file}; then
echo "did NOT capture missing package; test FAILED"
exit 1
else
echo "captured missing package; test PASSED"
exit 0
fi
- name: Compare stacks across architectures
shell: bash
run: |
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}\"[]")
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 | .[]" \
| tr '\n' ' ')
echo "COMPARISON_ARCH=${COMPARISON_ARCH}"
echo "ACCELERATOR_TARGETS=${ALL_ACCELERATOR_TARGETS}"
for ACCELERATOR_TYPE in nvidia amd; do
ACCELERATOR_TARGETS_TYPE=$(echo "${ALL_ACCELERATOR_TARGETS}" \
| tr ' ' '\n' \
| grep "^${ACCELERATOR_TYPE}/" \
| tr '\n' ' ' || true)
if [[ -z "${ACCELERATOR_TARGETS_TYPE}" ]]; then
continue
fi
export ACCELERATOR_TARGETS="${ACCELERATOR_TARGETS_TYPE}"
echo "Comparing ${ACCELERATOR_TYPE} accelerator targets:"
echo "ACCELERATOR_TARGETS=${ACCELERATOR_TARGETS}"
.github/workflows/scripts/compare_to_generic.sh \
"${EESSI_PREFIX}/software/${EESSI_OS_TYPE}" \
"${COMPARISON_ARCH}"
done
echo "::endgroup::"
done