From 8c535b21ce17004d8e6d0ee1e8127de1f65fa12c Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Sun, 15 Feb 2026 16:56:56 +0800 Subject: [PATCH 1/4] feat: add release-driven conda publish workflow Build and upload all conda variants on GitHub release. Derive package version from release tag via HYPRE_VERSION. --- .github/workflows/conda-release.yml | 114 ++++++++++++++++++++++++++++ conda-recipe/meta.yaml | 3 +- 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/conda-release.yml diff --git a/.github/workflows/conda-release.yml b/.github/workflows/conda-release.yml new file mode 100644 index 0000000000..10140214a8 --- /dev/null +++ b/.github/workflows/conda-release.yml @@ -0,0 +1,114 @@ +name: Conda Release Publish + +on: + release: + types: [published] + workflow_dispatch: + inputs: + release_tag: + description: Release tag to publish (for example v3.1.0) + required: true + type: string + +jobs: + build-and-publish: + name: Publish (${{ matrix.os }} | mpi=${{ matrix.mpi }}, openmp=${{ matrix.openmp }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest] + mpi: [nompi, openmpi, mpich] + openmp: [on, off] + + steps: + - name: Checkout sources + uses: actions/checkout@v6 + + - name: Resolve package version from release tag + id: version + shell: bash + env: + RELEASE_TAG: ${{ github.event.release.tag_name || github.event.inputs.release_tag }} + run: | + set -euo pipefail + if [ -z "${RELEASE_TAG:-}" ]; then + echo "::error::Release tag is empty." + exit 1 + fi + + version="${RELEASE_TAG#refs/tags/}" + version="${version#v}" + + if ! [[ "${version}" =~ ^[0-9]+(\.[0-9]+){1,3}([A-Za-z0-9._-]+)?$ ]]; then + echo "::error::Unsupported release tag '${RELEASE_TAG}'. Use tags like v3.1.0 or 3.1.0." + exit 1 + fi + + echo "version=${version}" >> "${GITHUB_OUTPUT}" + echo "Using package version ${version}" + + - name: Setup Miniconda + uses: conda-incubator/setup-miniconda@v3 + with: + activate-environment: conda-build-env + auto-update-conda: true + channels: conda-forge + channel-priority: strict + python-version: "3.12" + + - name: Install conda tooling + shell: bash -el {0} + run: | + conda install -n conda-build-env -y conda-build anaconda-client + + - name: Build package variant + shell: bash -el {0} + env: + CONDA_BLD_PATH: ${{ runner.temp }}/conda-bld + HYPRE_VERSION: ${{ steps.version.outputs.version }} + run: | + set -euo pipefail + echo "Building version=${HYPRE_VERSION}, mpi=${{ matrix.mpi }}, openmp=${{ matrix.openmp }}" + variant_json=$(printf '{"mpi":"%s","openmp":"%s"}' "${{ matrix.mpi }}" "${{ matrix.openmp }}") + conda build conda-recipe \ + --channel conda-forge \ + --override-channels \ + --variants "${variant_json}" \ + --no-anaconda-upload + + - name: Upload package to Anaconda (opflow-dev) + shell: bash -el {0} + env: + CONDA_BLD_PATH: ${{ runner.temp }}/conda-bld + HYPRE_VERSION: ${{ steps.version.outputs.version }} + ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }} + run: | + set -euo pipefail + if [ -z "${ANACONDA_API_TOKEN:-}" ]; then + echo "::error::Missing secret ANACONDA_API_TOKEN." + exit 1 + fi + + pkg_files="$( + find "${CONDA_BLD_PATH}" -type f \ + \( -name "hypre-${HYPRE_VERSION}-*.conda" -o -name "hypre-${HYPRE_VERSION}-*.tar.bz2" \) \ + | sort + )" + + if [ -z "${pkg_files}" ]; then + echo "::error::No built packages found under ${CONDA_BLD_PATH}." + exit 1 + fi + + echo "Uploading packages:" + printf '%s\n' "${pkg_files}" + + while IFS= read -r pkg; do + [ -n "${pkg}" ] || continue + anaconda -t "${ANACONDA_API_TOKEN}" upload \ + --user opflow-dev \ + --label main \ + --skip-existing \ + "${pkg}" + done <<< "${pkg_files}" diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index a648b76264..48ce024e92 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,9 +1,10 @@ {% set enable_mpi = "ON" if mpi != "nompi" else "OFF" %} {% set enable_openmp = "ON" if openmp == "on" else "OFF" %} +{% set package_version = environ.get("HYPRE_VERSION", "3.1.0") %} package: name: hypre - version: 3.1.0 + version: {{ package_version }} source: path: .. From be9e1143344c2d11f2308c795fc31d1f2ddcfead Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Sun, 15 Feb 2026 16:59:21 +0800 Subject: [PATCH 2/4] ci: remove Run CI label gate Delete require-label job and run PR CI directly on open/reopen/synchronize events. --- .github/workflows/ci.yml | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f25c04eac..6d8fc1f2a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,30 +5,13 @@ on: branches: ["master"] pull_request: branches: ["**"] - types: [opened, reopened, synchronize, labeled, unlabeled] + types: [opened, reopened, synchronize] workflow_dispatch: jobs: - require-label: - name: Require Run CI label - runs-on: ubuntu-latest - if: github.event_name == 'pull_request' - steps: - - name: Ensure Run CI label is present - env: - HAS_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'Run CI') }} - run: | - if [ "${HAS_LABEL}" != "true" ]; then - echo "::error::Add the 'Run CI' label to this pull request to trigger CI." - exit 1 - fi - shell: bash - build-and-check: name: Build & Check (${{ matrix.os }}-${{ matrix.mpi }}) runs-on: ${{ matrix.os }} - needs: [require-label] - if: github.event_name != 'pull_request' || needs.require-label.result == 'success' strategy: matrix: include: @@ -136,8 +119,6 @@ jobs: code-formatting: name: Check Code Formatting runs-on: ubuntu-latest - needs: [require-label] - if: github.event_name != 'pull_request' || needs.require-label.result == 'success' steps: - name: Checkout sources uses: actions/checkout@v6 @@ -171,8 +152,6 @@ jobs: mixed-precision-check: name: Check Mixed-Precision Code runs-on: ubuntu-latest - needs: [require-label] - if: github.event_name != 'pull_request' || needs.require-label.result == 'success' steps: - name: Checkout sources uses: actions/checkout@v6 @@ -200,8 +179,6 @@ jobs: headers-check: name: Check Headers runs-on: ubuntu-latest - needs: [require-label] - if: github.event_name != 'pull_request' || needs.require-label.result == 'success' steps: - name: Checkout sources uses: actions/checkout@v6 @@ -228,8 +205,6 @@ jobs: code-checks: name: Code Checks (${{ matrix.check }}) runs-on: ubuntu-latest - needs: [require-label] - if: github.event_name != 'pull_request' || needs.require-label.result == 'success' strategy: fail-fast: false matrix: From f6f5f034d795b60e13481afeee4a01d01b19c3df Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Sun, 15 Feb 2026 17:03:21 +0800 Subject: [PATCH 3/4] fix: address review feedback for conda release workflow Align checkout with release tag, use array variants for conda-build, harden version parsing, and pin conda auto-update. --- .github/workflows/conda-release.yml | 6 ++++-- conda-recipe/meta.yaml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/conda-release.yml b/.github/workflows/conda-release.yml index 10140214a8..8016e63da2 100644 --- a/.github/workflows/conda-release.yml +++ b/.github/workflows/conda-release.yml @@ -24,6 +24,8 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@v6 + with: + ref: ${{ github.event.release.tag_name || github.event.inputs.release_tag }} - name: Resolve package version from release tag id: version @@ -52,7 +54,7 @@ jobs: uses: conda-incubator/setup-miniconda@v3 with: activate-environment: conda-build-env - auto-update-conda: true + auto-update-conda: false channels: conda-forge channel-priority: strict python-version: "3.12" @@ -70,7 +72,7 @@ jobs: run: | set -euo pipefail echo "Building version=${HYPRE_VERSION}, mpi=${{ matrix.mpi }}, openmp=${{ matrix.openmp }}" - variant_json=$(printf '{"mpi":"%s","openmp":"%s"}' "${{ matrix.mpi }}" "${{ matrix.openmp }}") + variant_json=$(printf '{"mpi":["%s"],"openmp":["%s"]}' "${{ matrix.mpi }}" "${{ matrix.openmp }}") conda build conda-recipe \ --channel conda-forge \ --override-channels \ diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 48ce024e92..2c2a627a8e 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,6 +1,6 @@ {% set enable_mpi = "ON" if mpi != "nompi" else "OFF" %} {% set enable_openmp = "ON" if openmp == "on" else "OFF" %} -{% set package_version = environ.get("HYPRE_VERSION", "3.1.0") %} +{% set package_version = (environ.get("HYPRE_VERSION") or "3.1.0").lstrip("v") %} package: name: hypre From 49005e5fc296c8aa1c928dacc196c6cb08fed2e1 Mon Sep 17 00:00:00 2001 From: Luohao Wang Date: Sun, 15 Feb 2026 17:09:21 +0800 Subject: [PATCH 4/4] fix: add SPDX headers for conda recipe files Satisfy AUTOTEST check-license gate for conda packaging files. --- conda-recipe/build.sh | 5 +++++ conda-recipe/conda_build_config.yaml | 5 +++++ conda-recipe/meta.yaml | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh index 66c6ab5d94..fc9571fe14 100755 --- a/conda-recipe/build.sh +++ b/conda-recipe/build.sh @@ -1,4 +1,9 @@ #!/usr/bin/env bash +# Copyright (c) 1998 Lawrence Livermore National Security, LLC and other +# HYPRE Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + set -euxo pipefail HYPRE_ENABLE_MPI="${HYPRE_ENABLE_MPI:-OFF}" diff --git a/conda-recipe/conda_build_config.yaml b/conda-recipe/conda_build_config.yaml index 2e0d9b3d39..1b5522735b 100644 --- a/conda-recipe/conda_build_config.yaml +++ b/conda-recipe/conda_build_config.yaml @@ -1,3 +1,8 @@ +# Copyright (c) 1998 Lawrence Livermore National Security, LLC and other +# HYPRE Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + mpi: - nompi - openmpi diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 2c2a627a8e..0b42f818b7 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -1,3 +1,8 @@ +# Copyright (c) 1998 Lawrence Livermore National Security, LLC and other +# HYPRE Project Developers. See the top-level COPYRIGHT file for details. +# +# SPDX-License-Identifier: (Apache-2.0 OR MIT) + {% set enable_mpi = "ON" if mpi != "nompi" else "OFF" %} {% set enable_openmp = "ON" if openmp == "on" else "OFF" %} {% set package_version = (environ.get("HYPRE_VERSION") or "3.1.0").lstrip("v") %}