diff --git a/.github/actions/spack-checkout-updated-ref/README.md b/.github/actions/spack-checkout-updated-ref/README.md new file mode 100644 index 00000000..a16199d2 --- /dev/null +++ b/.github/actions/spack-checkout-updated-ref/README.md @@ -0,0 +1,47 @@ +# Update Existing Repo and Checkout Ref + +Action that updates an existing repository, and checks out the updated ref. + +## Inputs + +| Name | Type | Description | Required | Default | Example | +| ---- | ---- | ----------- | -------- | ------- | ------- | +| `spack-packages-repository-name` | `string` | The name of the repository used by spack to update and checkout the ref (given in the spack config file `repos.yaml`) | `true` | N/A | `"builtin"` | +| `spack-packages-repository-path` | `string` (path) | The path to the repository to update and check out the ref | `true` | N/A | `"/root/.spack/package_repos/fncqgg4/repos/spack_repo/builtin"` | +| `ref` | `string` (git branch, tag or sha) | The git ref to check out | `true` | N/A | `"main"` or `"v1"` or `"f8r73g3"` | +| `spack-instance-root-path` | `string` (path) | The path to the spack instance root, used to setup the spack environment | `true` | N/A | `"/opt/spack"` | +An example [`repos.yaml` file](https://github.com/ACCESS-NRI/spack-config/blob/main/common-api-v2/repos.yaml) as referenced above. +## Outputs + +| Name | Type | Description | Example | +| ---- | ---- | ----------- | ------- | +| `sha` | `string` (sha) | The SHA of the checked out ref | `"5a1cdc4e4617fcd6ba1cccf1cd0432b5631983be"` | +| `updated` | `string` (boolean) | Whether there was actually an update to the ref | `"true"` or `"false"` | + +## Examples + +### Simple + +```yaml +# ... +jobs: + update-repo: + runs-on: ubuntu-latest + env: + SPACK_ROOT: /opt/spack + steps: + - id: repo + run: | + . ${{ env.SPACK_ROOT }}/share/spack/setup-env.sh + echo "path=$(spack location --repo builtin)" >> $GITHUB_OUTPUT + + - id: update + uses: ./.github/actions/spack-checkout-updated-ref + with: + spack-packages-repository-name: builtin + spack-packages-repository-path: ${{ steps.repo.outputs.path }} + ref: develop + spack-instance-root-path: ${{ env.SPACK_ROOT }} + + - run: echo "The builtin spack-packages repo was updated to ${{ steps.update.outputs.sha }}" +``` diff --git a/.github/actions/spack-checkout-updated-ref/action.yml b/.github/actions/spack-checkout-updated-ref/action.yml new file mode 100644 index 00000000..d437e6f3 --- /dev/null +++ b/.github/actions/spack-checkout-updated-ref/action.yml @@ -0,0 +1,72 @@ +name: Checkout Ref Via Spack +description: Updates and checks out a given ref for an existing spack-packages repository via spack +inputs: + spack-packages-repository-name: + description: | + The spack name of the repository to update and check out the ref. + This is the repos.NAME key in spacks repos.yaml config file - eg. builtin + required: true + spack-packages-repository-path: + description: The path to the repository to update and check out the ref + required: true + ref: + description: The git ref to check out + required: true + spack-instance-root-path: + description: The path to the spack instance root, used to setup the spack environment + required: true +outputs: + sha: + description: 'The SHA of the checked out ref' + value: ${{ steps.ref-sha.outputs.sha }} + updated: + description: 'Whether the repository was updated' + value: ${{ steps.post-update.outputs.updated }} +runs: + using: composite + steps: + - name: Get initial SHA + id: initial + shell: bash + run: | + sha=$(git -C ${{ inputs.spack-packages-repository-path }} rev-parse HEAD^{}) + echo "${{ inputs.spack-packages-repository-name }} Initial SHA: $sha" + + echo "sha=$sha" >> $GITHUB_OUTPUT + + - name: Fetch latest for repo + shell: bash + run: git -C ${{ inputs.spack-packages-repository-path }} fetch --force --tags + + - name: Get SHA for ref + id: ref-sha + uses: access-nri/actions/.github/actions/get-git-ref-info@main + with: + repository-path: ${{ inputs.spack-packages-repository-path }} + ref: ${{ inputs.ref }} + + - name: Update ref via Spack + shell: bash + id: update + continue-on-error: true + run: | + . ${{ inputs.spack-instance-root-path }}/share/spack/setup-env.sh + spack repo update ${{ inputs.spack-packages-repository-name }} --commit ${{ steps.ref-sha.outputs.sha }} + + - name: Force Update ref via Git if Failure + if: steps.update.outcome == 'failure' + shell: bash + # FIXME: If there is ever a spack repo update --force option, use that for the above command and delete this step + run: git -C ${{ inputs.spack-packages-repository-path }} checkout --force ${{ steps.ref-sha.outputs.sha }} + + - name: Check if updated + id: post-update + shell: bash + run: | + if [ "${{ steps.initial.outputs.sha }}" != "${{ steps.ref-sha.outputs.sha }}" ]; then + echo "Repository was updated from ${{ steps.initial.outputs.sha }} to ${{ inputs.ref }} (${{ steps.ref-sha.outputs.sha }})" + echo "updated=true" >> $GITHUB_OUTPUT + else + echo "Repository was not updated, stayed at ${{ inputs.ref }} (${{ steps.initial.outputs.sha }})" + echo "updated=false" >> $GITHUB_OUTPUT + fi diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 646c3afa..3d682745 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -14,9 +14,10 @@ This workflow handles building and running short CI tests on a given spack manif | `spack-manifest-data-path`| `string` (Path relative to component repository root) | File path in the caller model component repository that contains jinja data to fill in to the spack manifest jinja template given by `inputs.spack-manifest-path`. This doesn't include the pull request ref (`{{ pr }}`), which is filled in automatically | `false` | N/A | `".github/build/data/template-data.json"` | | `spack-compiler-manifest-path` | `string` (Path relative to component repository root) | A file path in the caller model component repository that contains the spack manifest to install local compilers not in the upstream | `false` | N/A | `".github/build/compilers/intel-2021.11.0.spack.yml"` | | `spack-manifest-data-pairs` | `string` | An optional, multi-line string of space-separated key-value pairs to fill in `inputs.spack-manifest-path`. This is useful for filling in template values created dynamically by earlier jobs needed by this workflow. This doesn't include `{{ ref }}`, which is filled in automatically. | `false` | N/A | `"package mom5`(newline)`compiler intel"` | -| `ref` | `string` (Git ref) | The branch, tag, or commit SHA of the caller model component repository | `false` | `github.event.pull_request.head.sha` for PRs, `github.sha` otherwise | `"02125b01eb7c778c8d0ae0a02a260de474782e81"`, `"main"`, `"2025.01.000"` | +| `ref` | `string` (Git ref) | The branch, tag, or commit SHA of the caller model component repository | `false` | `github.event.pull_request.head.sha` for PRs, `github.sha` otherwise | `"c0fef23fc1e69d3a31ec18fd8b7102acdf95f651"`, `"main"`, `"2025.01.000"` | | `spack-config-ref` | `string` (Git ref) | The branch, tag, or commit SHA of the access-nri/spack-config repository to use | `false` | `"main"` | `"02125b01eb7c778c8d0ae0a02a260de474782e81"`, `"main"`, `"2025.01.000"` | -| `spack-packages-ref` | `string` (Git ref) | The branch, tag, or commit SHA of the access-nri/spack-packages repository to use | `false` | `"main"` | `"02125b01eb7c778c8d0ae0a02a260de474782e81"`, `"main"`, `"2025.01.000"` | +| `builtin-spack-packages-ref` | `string` (Git ref) | The branch, tag, or commit SHA of the `spack/spack-packages` repository to use | `false` | `"main"` | `"f7314790111ec43cf9cff60421c155b922c349ad"`, `"main"`, `"2025.01.000"` | +| `access-spack-packages-ref` | `string` (Git ref) | The branch, tag, or commit SHA of the `access-nri/access-spack-packages` repository to use | `false` | `"main"` | `"e4ba85db0be4a9b9493cf7581623f9997b9404a5"`, `"main"`, `"2025.01.000"` | | `allow-ssh-into-spack-install` | `boolean` | Enable the actor of the workflow to SSH into the container where the spack packages have been installed. This is useful for gathering post-install information before the container is destroyed. This will also make the workflow wait until the actor SSHs into the container, or it times out, before continuing | `false` | `false` | `true`, `false` | | `container-image-version` | `string` (Docker version ref) | The version of the container image to use for the runner. Can be either a `:TAG` or a `@sha256:SHA`. | `false` | `":rocky"` | `':8.9'` (tag), `'@sha256:1234...'` (SHA) | | `spack-oci-buildcache-url` | `string` (OCI URL) | The URL to an oci-backed buildcache, available in spack >= v1.0. OCI-backed buildcaches are the only option for GitHub-hosted CI, and can be used as a backup for self-hosted CI's runner buildcache | `false` | N/A | `"oci://ghcr.io/ACCESS-NRI/build-ci-buildcache"`, `"oci://ghcr.io/ORG/IMAGE"` | @@ -43,9 +44,10 @@ This workflow handles building and running short CI tests on a given spack manif | ---- | ---- | ----------- | ------- | | `spec-concretization-graph` | `string` (multiline) | A visual representation of the dependencies and constraints of the spack manifest file installed | N/A | | `spack-sha` | `string` (Git commit SHA) | The SHA of the `ACCESS-NRI/spack` repository checked out | `"02125b01eb7c778c8d0ae0a02a260de474782e81"` | -| `spack-config-sha` | `string` (Git commit SHA) | The SHA of the `ACCESS-NRI/spack-config` repository checked out | `"02125b01eb7c778c8d0ae0a02a260de474782e81"` | -| `spack-packages-sha` | `string` (Git commit SHA) | The SHA of the `ACCESS-NRI/spack-packages` repository checked out | `"02125b01eb7c778c8d0ae0a02a260de474782e81"` | -| `sha` | `string` (Git commit SHA) | The SHA of the caller model component repository checked out | `"02125b01eb7c778c8d0ae0a02a260de474782e81"` | +| `spack-config-sha` | `string` (Git commit SHA) | The SHA of the `ACCESS-NRI/spack-config` repository checked out | `"c0fef23fc1e69d3a31ec18fd8b7102acdf95f651"` | +| `builtin-spack-packages-sha` | `string` (Git commit SHA) | The SHA of the `spack/spack-packages` repository checked out | `"9225ee95da5c6e212a80d933db8aca44271417a3"` | +| `access-spack-packages-sha` | `string` (Git commit SHA) | The SHA of the `ACCESS-NRI/access-spack-packages` repository checked out | `"2acb57187fc75c0fc83c898d1dd47bdaced2fca9"` | +| `sha` | `string` (Git commit SHA) | The SHA of the caller model component repository checked out | `"43ef5da423028a9a25133884e6e402900e87a3ce"` | | `container-id` | `string` | The ID of the container where the spack packages have been installed | `"ohfn2ofy2h2uyfg2uyg3uyg3uh"` | | `spack-files-artifact-pattern` | `string` (glob) | Wildcard pattern to match all spack file artifacts across a matrix job | `'spack-files-*'` | | `spack-files-artifact-url` | `string` (URL) | The URL of the spack manifest and lock files artifact | `"https://github.com/ACCESS-NRI/MOM5/actions/runs/15890554355/artifacts/3406449135"` | @@ -67,7 +69,7 @@ This workflow handles building and running short CI tests on a given spack manif ```yaml jobs: test: - uses: access-nri/build-ci/.github/workflows/ci.yml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yml@v3 with: spack-manifest-path: .github/build/spack.yaml.j2 ``` @@ -77,13 +79,14 @@ jobs: ```yaml jobs: test: - uses: access-nri/build-ci/.github/workflows/ci.yml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yml@v3 with: spack-manifest-path: .github/build/spack.yaml.j2 spack-manifest-data-path: .github/build/data/data.json spack-compiler-manifest-path: .github/build/compiler/intel.spack.yaml spack-ref: releases/v0.22 - spack-packages-ref: 2025.05.000 + builtin-spack-packages-ref: 2025.07.0 + access-spack-packages-ref: 2025.05.000 spack-config-ref: 2025.10.001 allow-ssh-into-spack-install: true secrets: @@ -106,7 +109,7 @@ jobs: - .github/build/one.spack.yaml.j2 - .github/build/two.spack.yaml.j2 - .github/build/three.spack.yaml.j2 - uses: access-nri/build-ci/.github/workflows/ci.yml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yml@v3 with: spack-manifest-path: ${{ matrix.manifest }} ``` @@ -126,7 +129,7 @@ jobs: compiler: .github/build/compiler/intel.spack.yaml - manifest: .github/build/two.spack.yaml.j2 compiler: .github/build/compiler/gcc.spack.yaml - uses: access-nri/build-ci/.github/workflows/ci.yml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yml@v3 with: spack-manifest-path: ${{ matrix.values.manifest }} spack-compiler-manifest-path: ${{ matrix.values.compiler }} @@ -144,7 +147,7 @@ jobs: # This would be a combination of all defined manifest/compilers (eg, 4 jobs) manifest: [".github/build/one.spack.yaml.j2", ".github/build/two.spack.yaml.j2"] compiler: [".github/build/compiler/intel.spack.yaml", ".github/build/compiler/gcc.spack.yaml"] - uses: access-nri/build-ci/.github/workflows/ci.yml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yml@v3 with: spack-manifest-path: ${{ matrix.values.manifest }} spack-compiler-manifest-path: ${{ matrix.values.compiler }} @@ -174,7 +177,7 @@ The jinja data file (and the jinja-templatable spack manifest) can be much more Alternatively, you can supply a newline-separated list of space-separated template-value pairs through `inputs.spack-manifest-data-pairs`, which are more useful if you are supplying data to this workflow through `need`ed job outputs. For example: ```yaml - uses: access-nri/build-ci/.github/workflows/ci.yml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yml@v3 with: spack-manifest-path: .github/build-ci/manifests/spack.yaml.j2 spack-manifest-data-pairs: |- @@ -229,7 +232,7 @@ jobs: file: - .github/build-ci/manifests/some.spack.yaml.j2 - .github/build-ci/manifests/another.spack.yaml.j2 - uses: access-nri/build-ci/.github/workflows/ci.yaml@v2 + uses: access-nri/build-ci/.github/workflows/ci.yaml@v3 with: spack-manifest-path: ${{ matrix.file }} diff --git a/.github/workflows/ci-github-hosted.yml b/.github/workflows/ci-github-hosted.yml index a04675f7..f13615d3 100644 --- a/.github/workflows/ci-github-hosted.yml +++ b/.github/workflows/ci-github-hosted.yml @@ -49,17 +49,25 @@ on: description: | The branch, tag, or commit SHA of the access-nri/spack-config repository to use. For example: main, 2025.03.0, 7ey2uy2. - spack-packages-ref: + builtin-spack-packages-ref: required: false type: string - default: main + default: develop + description: | + The branch, tag, or commit SHA of the spack/spack-packages repository to use. + For example: main, 2025.03.0, 7ey2uy2. + access-spack-packages-ref: + required: false + type: string + default: api-v2 description: | The branch, tag, or commit SHA of the access-nri/spack-packages repository to use. For example: main, 2025.03.0, 7ey2uy2. spack-ref: required: false type: string - default: releases/v0.22 + # Default spack version - must be changed across the Dockerfile as well + default: releases/v1.1 description: | The branch, tag, or commit SHA of the access-nri/spack repository to use. For example: develop, releases/0.22, 7ey2uy2. @@ -118,10 +126,14 @@ on: value: ${{ jobs.spack-install-and-test.outputs.spack-config-sha }} description: | The SHA of the spack-config repository checked out. - spack-packages-sha: - value: ${{ jobs.spack-install-and-test.outputs.spack-packages-sha }} + builtin-spack-packages-sha: + value: ${{ jobs.spack-install-and-test.outputs.builtin-spack-packages-sha }} + description: | + The SHA of the builtin spack-packages repository checked out. + access-spack-packages-sha: + value: ${{ jobs.spack-install-and-test.outputs.access-spack-packages-sha }} description: | - The SHA of the spack-packages repository checked out. + The SHA of the access-spack-packages repository checked out. sha: value: ${{ jobs.spack-install-and-test.outputs.sha }} description: | @@ -173,7 +185,8 @@ jobs: spec-concretization-graph: ${{ steps.install.outputs.spec }} spack-sha: ${{ steps.spack-update.outputs.sha }} spack-config-sha: ${{ steps.spack-config-update.outputs.sha }} - spack-packages-sha: ${{ steps.spack-packages-update.outputs.sha }} + builtin-spack-packages-sha: ${{ steps.builtin-spack-packages-update.outputs.sha }} + access-spack-packages-sha: ${{ steps.access-spack-packages-update.outputs.sha }} sha: ${{ steps.checkout.outputs.commit }} spack-files-artifact-pattern: ${{ steps.env.outputs.spack-files-artifact-pattern }} spack-files-artifact-url: ${{ steps.manifest-upload.outputs.artifact-url }} @@ -185,14 +198,14 @@ jobs: short-container-id: ${{ steps.env.outputs.short-container-id }} # test-artifact-url: ${{ steps.test.outputs.artifact-url }} steps: - - name: Export environment variables into GitHub Actions format + - name: Init - Export environment variables into GitHub Actions format # Environment variables inside containers are not accessible in the `env` context, # a context which would be used in future conditional steps. # This step exports important container environment variables as outputs. # And yes, this loop echoes name-of-var=value-of-var! id: env run: | - for var in SPACK_ROOT SPACK_CONFIG_DIR SPACK_REPO_VERSION SPACK_CONFIG_REPO_VERSION SPACK_PACKAGES_REPO_VERSION; do + for var in SPACK_ROOT INITIAL_SPACK_REPO_VERSION; do echo "$var=${!var}" >> $GITHUB_OUTPUT done @@ -215,28 +228,30 @@ jobs: echo "container-id=$container_id" >> $GITHUB_OUTPUT echo "short-container-id=$short_container_id" >> $GITHUB_OUTPUT - - name: Update spack-package version - id: spack-packages-update - uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v2 - with: - repository-path: ${{ steps.env.outputs.SPACK_ROOT }}/../spack-packages - ref: ${{ inputs.spack-packages-ref }} - - - name: Update spack-config version + - name: Update - spack-config version id: spack-config-update - uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v2 + uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v3 with: repository-path: ${{ steps.env.outputs.SPACK_ROOT }}/../spack-config ref: ${{ inputs.spack-config-ref }} - - name: Update spack version + - name: Update - spack version id: spack-update - uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v2 + uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v3 with: repository-path: ${{ steps.env.outputs.SPACK_ROOT }} ref: ${{ inputs.spack-ref }} - - name: Relink spack-config to spack + - name: Update - Validate non-updated spack + if: steps.spack-update.outputs.updated == 'false' && steps.spack-config-update.outputs.updated == 'false' + # We don't support spack < v1.0 in build-ci@v3, so we error out if the spack version is not updated and the version in the image is < v1.0 + run: | + if [[ "${{ steps.env.outputs.INITIAL_SPACK_REPO_VERSION }}" == "releases/v0"* ]]; then + echo "::error::spack branch ${{ steps.env.outputs.INITIAL_SPACK_REPO_VERSION }} is not a v1.x branch, and build-ci@v3 only supports spack >= v1.0. Use build-ci@v2 for spack < v1.0" + exit 2 + fi + + - name: Update - Validate and relink spack-config to spack if: steps.spack-config-update.outputs.updated == 'true' || steps.spack-update.outputs.updated == 'true' # If there was a change in spack or spack-config, we should relink the config to spack. # Furthermore, if spack has been updated, we need to make sure we link to the correct vX config directory in spack-config. @@ -257,31 +272,47 @@ jobs: echo "Linking spack with SHA ${{ steps.spack-update.outputs.sha }} to spack-config directory $spack_branch" fi + # Check if the determined spack_branch starts with v0, which is unsupported in build-ci@v3 + if [[ "$spack_branch" == "v0"* ]]; then + echo "::error::spack branch $spack_branch is not a v1.x branch, and build-ci@v3 only supports spack >= v1.0. Use build-ci@v2 for spack < v1.0" + exit 2 + fi + ln --symbolic --relative --verbose --force ${{ steps.env.outputs.SPACK_ROOT }}/../spack-config/${spack_branch}/ci-upstream/* ${{ steps.env.outputs.SPACK_ROOT }}/etc/spack/ - - name: Spack - Initial Enable + Compiler Load + - name: Spack - Initial Enable run: | . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh + echo "----- Compilers -----" + spack compiler list + echo "----- Packages -----" + spack find - # Find potential upstream compiler lockfile path - if [ -f "/opt/upstream/compilers.spack.lock" ]; then - compiler_lockfile_path="/opt/upstream/compilers.spack.lock" - elif [ -f "/opt/environments/compilers/spack.lock" ]; then - compiler_lockfile_path="/opt/environments/compilers/spack.lock" - else - echo "::warning::No upstream compilers.spack.lock or environments/compilers/spack.lock found, skipping compiler load from upstream" - exit 0 - fi + - name: Spack - Get spack-packages repo locations + id: spack-packages-locations + run: | + . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - # Attempt a load of compilers via upstream compilers lockfile - echo "Found $compiler_lockfile_path, attempting to load compilers from upstream" - yq '.roots[].hash' "$compiler_lockfile_path" | while read hash; do - echo "Loading compiler with hash: $hash" - spack load /$hash - spack compiler find --scope=user - done + echo "builtin=$(spack location --repo builtin)" >> $GITHUB_OUTPUT + echo "access-spack-packages=$(spack location --repo access.nri)" >> $GITHUB_OUTPUT - spack find + - name: Update - builtin spack-package version + id: builtin-spack-packages-update + uses: access-nri/build-ci/.github/actions/spack-checkout-updated-ref@v3 + with: + spack-packages-repository-name: builtin + spack-packages-repository-path: ${{ steps.spack-packages-locations.outputs.builtin }} + ref: ${{ inputs.builtin-spack-packages-ref }} + spack-instance-root-path: ${{ steps.env.outputs.SPACK_ROOT }} + + - name: Update - access-spack-package version + id: access-spack-packages-update + uses: access-nri/build-ci/.github/actions/spack-checkout-updated-ref@v3 + with: + spack-packages-repository-name: access_spack_packages + spack-packages-repository-path: ${{ steps.spack-packages-locations.outputs.access-spack-packages }} + ref: ${{ inputs.access-spack-packages-ref }} + spack-instance-root-path: ${{ steps.env.outputs.SPACK_ROOT }} - name: Spack - OCI Buildcache Init if: inputs.spack-oci-buildcache-url != '' @@ -315,7 +346,7 @@ jobs: spack env deactivate yq '.spack.specs[]' ${{ inputs.spack-compiler-manifest-path }} | while read compiler; do spack load $compiler - spack compiler find --scope=user + spack compiler find --scope=site done spack compiler list @@ -358,6 +389,8 @@ jobs: spack env create default ${{ steps.jinja-templated.outputs.spack-manifest-path }} spack env activate + spack concretize --force + echo "spec<> $GITHUB_OUTPUT echo "$(spack spec)" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT @@ -413,7 +446,7 @@ jobs: i=0 while read -r hash; do - spack -e default logs /$hash > "logs/spec_${i}.log" + spack -e default logs /$hash > "logs/spec_${i}.log" || true i=$((i + 1)) done <<< "$hashes" @@ -470,7 +503,8 @@ jobs: "spack_compiler_manifest_path": "${{ inputs.spack-compiler-manifest-path }}", "ref": "${{ inputs.ref }}", "spack_config_ref": "${{ inputs.spack-config-ref }}", - "spack_packages_ref": "${{ inputs.spack-packages-ref }}", + "builtin_spack_packages_ref": "${{ inputs.builtin-spack-packages-ref }}", + "access_spack_packages_ref": "${{ inputs.access-spack-packages-ref }}", "spack_ref": "${{ inputs.spack-ref }}", "pytest_test_markers": "${{ inputs.pytest-test-markers }}", "allow_ssh_into_spack_install": "${{ inputs.allow-ssh-into-spack-install }}", @@ -481,7 +515,8 @@ jobs: "spec_concretization_graph": $spec, "spack_sha": "${{ steps.spack-update.outputs.sha }}", "spack_config_sha": "${{ steps.spack-config-update.outputs.sha }}", - "spack_packages_sha": "${{ steps.spack-packages-update.outputs.sha }}", + "builtin_spack_packages_sha": "${{ steps.builtin-spack-packages-update.outputs.sha }}", + "access_spack_packages_sha": "${{ steps.access-spack-packages-update.outputs.sha }}", "sha": "${{ steps.checkout.outputs.commit }}", "container_id": "${{ steps.env.outputs.container-id }}", "short_container_id": "${{ steps.env.outputs.short-container-id }}", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41b6f119..8e752150 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,17 +49,25 @@ on: description: | The branch, tag, or commit SHA of the access-nri/spack-config repository to use. For example: main, 2025.03.0, 7ey2uy2. - spack-packages-ref: + builtin-spack-packages-ref: required: false type: string - default: main + default: develop + description: | + The branch, tag, or commit SHA of the spack/spack-packages repository to use. + For example: main, 2025.03.0, 7ey2uy2. + access-spack-packages-ref: + required: false + type: string + default: api-v2 description: | The branch, tag, or commit SHA of the access-nri/spack-packages repository to use. For example: main, 2025.03.0, 7ey2uy2. spack-ref: required: false type: string - default: releases/v0.22 + # Default spack version - must be changed across the Dockerfile as well + default: releases/v1.1 description: | The branch, tag, or commit SHA of the access-nri/spack repository to use. For example: develop, releases/0.22, 7ey2uy2. @@ -118,10 +126,14 @@ on: value: ${{ jobs.spack-install-and-test.outputs.spack-config-sha }} description: | The SHA of the spack-config repository checked out. - spack-packages-sha: - value: ${{ jobs.spack-install-and-test.outputs.spack-packages-sha }} + builtin-spack-packages-sha: + value: ${{ jobs.spack-install-and-test.outputs.builtin-spack-packages-sha }} description: | - The SHA of the spack-packages repository checked out. + The SHA of the builtin spack-packages repository checked out. + access-spack-packages-sha: + value: ${{ jobs.spack-install-and-test.outputs.access-spack-packages-sha }} + description: | + The SHA of the access-spack-packages repository checked out. sha: value: ${{ jobs.spack-install-and-test.outputs.sha }} description: | @@ -174,13 +186,14 @@ jobs: # FIXME: To be able to support both v0.22 and v1.0 upstreams at the same time # We need to pick the correct upstream volume based on the runner image spack version # This may not be required in the future if we only support v1.0+ - - /opt/upstream${{ contains(inputs.container-image-version, 'v1.0') && '-v1.0' || '' }}:/opt/upstream:ro + - /opt/upstream${{ contains(inputs.container-image-version, 'v1') && '-v1' || '' }}:/opt/upstream:ro - /opt/runner_set_buildcache:/opt/runner_set_buildcache:rw outputs: spec-concretization-graph: ${{ steps.install.outputs.spec }} spack-sha: ${{ steps.spack-update.outputs.sha }} spack-config-sha: ${{ steps.spack-config-update.outputs.sha }} - spack-packages-sha: ${{ steps.spack-packages-update.outputs.sha }} + builtin-spack-packages-sha: ${{ steps.builtin-spack-packages-update.outputs.sha }} + access-spack-packages-sha: ${{ steps.access-spack-packages-update.outputs.sha }} sha: ${{ steps.checkout.outputs.commit }} spack-files-artifact-pattern: ${{ steps.env.outputs.spack-files-artifact-pattern }} spack-files-artifact-url: ${{ steps.manifest-upload.outputs.artifact-url }} @@ -192,14 +205,14 @@ jobs: short-container-id: ${{ steps.env.outputs.short-container-id }} # test-artifact-url: ${{ steps.test.outputs.artifact-url }} steps: - - name: Export environment variables into GitHub Actions format + - name: Init - Export environment variables into GitHub Actions format # Environment variables inside containers are not accessible in the `env` context, # a context which would be used in future conditional steps. # This step exports important container environment variables as outputs. # And yes, this loop echoes name-of-var=value-of-var! id: env run: | - for var in SPACK_ROOT SPACK_CONFIG_DIR SPACK_REPO_VERSION SPACK_CONFIG_REPO_VERSION SPACK_PACKAGES_REPO_VERSION; do + for var in SPACK_ROOT INITIAL_SPACK_REPO_VERSION; do echo "$var=${!var}" >> $GITHUB_OUTPUT done @@ -222,28 +235,30 @@ jobs: echo "container-id=$container_id" >> $GITHUB_OUTPUT echo "short-container-id=$short_container_id" >> $GITHUB_OUTPUT - - name: Update spack-package version - id: spack-packages-update - uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v2 - with: - repository-path: ${{ steps.env.outputs.SPACK_ROOT }}/../spack-packages - ref: ${{ inputs.spack-packages-ref }} - - - name: Update spack-config version + - name: Update - spack-config version id: spack-config-update - uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v2 + uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v3 with: repository-path: ${{ steps.env.outputs.SPACK_ROOT }}/../spack-config ref: ${{ inputs.spack-config-ref }} - - name: Update spack version + - name: Update - spack version id: spack-update - uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v2 + uses: access-nri/build-ci/.github/actions/git-checkout-updated-ref@v3 with: repository-path: ${{ steps.env.outputs.SPACK_ROOT }} ref: ${{ inputs.spack-ref }} - - name: Relink spack-config to spack + - name: Update - Validate non-updated spack + if: steps.spack-update.outputs.updated == 'false' && steps.spack-config-update.outputs.updated == 'false' + # We don't support spack < v1.0 in build-ci@v3, so we error out if the spack version is not updated and the version in the image is < v1.0 + run: | + if [[ "${{ steps.env.outputs.INITIAL_SPACK_REPO_VERSION }}" == "releases/v0"* ]]; then + echo "::error::spack branch ${{ steps.env.outputs.INITIAL_SPACK_REPO_VERSION }} is not a v1.x branch, and build-ci@v3 only supports spack >= v1.0. Use build-ci@v2 for spack < v1.0" + exit 2 + fi + + - name: Update - Validate and relink spack-config to spack if: steps.spack-config-update.outputs.updated == 'true' || steps.spack-update.outputs.updated == 'true' # If there was a change in spack or spack-config, we should relink the config to spack. # Furthermore, if spack has been updated, we need to make sure we link to the correct vX config directory in spack-config. @@ -264,31 +279,47 @@ jobs: echo "Linking spack with SHA ${{ steps.spack-update.outputs.sha }} to spack-config directory $spack_branch" fi + # Check if the determined spack_branch starts with v0, which is unsupported in build-ci@v3 + if [[ "$spack_branch" == "v0"* ]]; then + echo "::error::spack branch $spack_branch is not a v1.x branch, and build-ci@v3 only supports spack >= v1.0. Use build-ci@v2 for spack < v1.0" + exit 2 + fi + ln --symbolic --relative --verbose --force ${{ steps.env.outputs.SPACK_ROOT }}/../spack-config/${spack_branch}/ci-runner/* ${{ steps.env.outputs.SPACK_ROOT }}/etc/spack/ - - name: Spack - Initial Enable + Compiler Load + - name: Spack - Initial Enable run: | . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh + echo "----- Compilers -----" + spack compiler list + echo "----- Packages -----" + spack find - # Find potential upstream compiler lockfile path - if [ -f "/opt/upstream/compilers.spack.lock" ]; then - compiler_lockfile_path="/opt/upstream/compilers.spack.lock" - elif [ -f "/opt/environments/compilers/spack.lock" ]; then - compiler_lockfile_path="/opt/environments/compilers/spack.lock" - else - echo "::warning::No upstream compilers.spack.lock or environments/compilers/spack.lock found, skipping compiler load from upstream" - exit 0 - fi + - name: Spack - Get spack-packages repo locations + id: spack-packages-locations + run: | + . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - # Attempt a load of compilers via upstream compilers lockfile - echo "Found $compiler_lockfile_path, attempting to load compilers from upstream" - yq '.roots[].hash' "$compiler_lockfile_path" | while read hash; do - echo "Loading compiler with hash: $hash" - spack load /$hash - spack compiler find --scope=user - done + echo "builtin=$(spack location --repo builtin)" >> $GITHUB_OUTPUT + echo "access-spack-packages=$(spack location --repo access.nri)" >> $GITHUB_OUTPUT - spack find + - name: Update - builtin spack-package version + id: builtin-spack-packages-update + uses: access-nri/build-ci/.github/actions/spack-checkout-updated-ref@v3 + with: + spack-packages-repository-name: builtin + spack-packages-repository-path: ${{ steps.spack-packages-locations.outputs.builtin }} + ref: ${{ inputs.builtin-spack-packages-ref }} + spack-instance-root-path: ${{ steps.env.outputs.SPACK_ROOT }} + + - name: Update - access-spack-package version + id: access-spack-packages-update + uses: access-nri/build-ci/.github/actions/spack-checkout-updated-ref@v3 + with: + spack-packages-repository-name: access_spack_packages + spack-packages-repository-path: ${{ steps.spack-packages-locations.outputs.access-spack-packages }} + ref: ${{ inputs.access-spack-packages-ref }} + spack-instance-root-path: ${{ steps.env.outputs.SPACK_ROOT }} - name: Spack - OCI Buildcache Init if: inputs.spack-oci-buildcache-url != '' @@ -322,7 +353,7 @@ jobs: spack env deactivate yq '.spack.specs[]' ${{ inputs.spack-compiler-manifest-path }} | while read compiler; do spack load $compiler - spack compiler find --scope=user + spack compiler find --scope=site done spack compiler list @@ -352,8 +383,7 @@ jobs: - name: Manifest - Install id: install env: - # For pulling and pushing OCI buildcache - # If secrets.GITHUB_TOKEN has permissions.packages:write, one would not have to specify secrets.spack-oci-buildcache-password + # For pulling OCI buildcache OCI_USERNAME: ${{ secrets.spack-oci-buildcache-username || github.actor }} OCI_PASSWORD: ${{ secrets.spack-oci-buildcache-password || secrets.GITHUB_TOKEN }} # This is needed to ensure that the spack install command can access private repositories - we replace all HTTPS git URLs with the PAT @@ -366,6 +396,8 @@ jobs: spack env create default ${{ steps.jinja-templated.outputs.spack-manifest-path }} spack env activate + spack concretize --force + echo "spec<> $GITHUB_OUTPUT echo "$(spack spec)" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT @@ -379,7 +411,8 @@ jobs: - name: Manifest - Push to Buildcache env: - # For pulling OCI buildcache + # For pulling and pushing OCI buildcache + # If secrets.GITHUB_TOKEN has permissions.packages:write, one would not have to specify secrets.spack-oci-buildcache-password OCI_USERNAME: ${{ secrets.spack-oci-buildcache-username || github.actor }} OCI_PASSWORD: ${{ secrets.spack-oci-buildcache-password || secrets.GITHUB_TOKEN }} if: inputs.spack-oci-buildcache-url != '' @@ -420,7 +453,7 @@ jobs: i=0 while read -r hash; do - spack -e default logs /$hash > "logs/spec_${i}.log" + spack -e default logs /$hash > "logs/spec_${i}.log" || true i=$((i + 1)) done <<< "$hashes" @@ -477,7 +510,8 @@ jobs: "spack_compiler_manifest_path": "${{ inputs.spack-compiler-manifest-path }}", "ref": "${{ inputs.ref }}", "spack_config_ref": "${{ inputs.spack-config-ref }}", - "spack_packages_ref": "${{ inputs.spack-packages-ref }}", + "builtin_spack_packages_ref": "${{ inputs.builtin-spack-packages-ref }}", + "access_spack_packages_ref": "${{ inputs.access-spack-packages-ref }}", "spack_ref": "${{ inputs.spack-ref }}", "pytest_test_markers": "${{ inputs.pytest-test-markers }}", "allow_ssh_into_spack_install": "${{ inputs.allow-ssh-into-spack-install }}", @@ -488,7 +522,8 @@ jobs: "spec_concretization_graph": $spec, "spack_sha": "${{ steps.spack-update.outputs.sha }}", "spack_config_sha": "${{ steps.spack-config-update.outputs.sha }}", - "spack_packages_sha": "${{ steps.spack-packages-update.outputs.sha }}", + "builtin_spack_packages_sha": "${{ steps.builtin-spack-packages-update.outputs.sha }}", + "access_spack_packages_sha": "${{ steps.access-spack-packages-update.outputs.sha }}", "sha": "${{ steps.checkout.outputs.commit }}", "container_id": "${{ steps.env.outputs.container-id }}", "short_container_id": "${{ steps.env.outputs.short-container-id }}", diff --git a/.gitignore b/.gitignore index 3a4ccf94..229db105 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1 @@ -keys -__pycache__ -.pytest_cache -.vscode \ No newline at end of file +containers/upstream/secrets \ No newline at end of file diff --git a/containers/Dockerfile b/containers/Dockerfile index 78ecc500..94ffe4a8 100644 --- a/containers/Dockerfile +++ b/containers/Dockerfile @@ -51,6 +51,7 @@ RUN dnf update -y \ python3-setuptools \ svn \ unzip \ + vim \ which \ xz \ zstd \ @@ -114,11 +115,6 @@ RUN zypper ref \ # Install yq && curl -L https://github.com/mikefarah/yq/releases/download/v4.45.1/yq_linux_amd64 -o /usr/bin/yq \ && chmod +x /usr/bin/yq \ - # Install tmate in the image for remote access during workflows via mxschmitt/action-tmate - && curl -L https://github.com/tmate-io/tmate/releases/download/2.4.0/tmate-2.4.0-static-linux-amd64.tar.xz -o static-tmate.tar.xz \ - && tar -xvf static-tmate.tar.xz --strip-components=1 \ - && mv tmate /usr/local/bin/tmate \ - && rm -rf static-tmate.tar.xz \ # Install gh && zypper addrepo https://cli.github.com/packages/rpm/gh-cli.repo \ && zypper ref \ @@ -131,9 +127,9 @@ RUN zypper ref \ FROM base-os-$OS AS base-spack ARG SPACK_GIT_URL=https://github.com/ACCESS-NRI/spack.git -ARG SPACK_VERSION=v0.22 +# Default spack version - must be changed across ci*.yml as well +ARG SPACK_VERSION=v1.1 ARG SPACK_REPO_VERSION=releases/${SPACK_VERSION} -ARG SPACK_PACKAGES_REPO_VERSION=main ARG SPACK_CONFIG_REPO_VERSION=main ARG SPACK_TARGET=x86_64 ARG SPACK_CONFIG_DIR=/opt/spack-config/${SPACK_VERSION}/ci @@ -147,9 +143,8 @@ ENV ENV_COMPILERS_SPACK_MANIFEST=/opt/compilers.spack.yaml ENV ENV_PACKAGES_SPACK_MANIFEST=/opt/packages.spack.yaml # Export the repo versions for comparison in the runner target -ENV SPACK_PACKAGES_REPO_VERSION=${SPACK_PACKAGES_REPO_VERSION} -ENV SPACK_CONFIG_REPO_VERSION=${SPACK_CONFIG_REPO_VERSION} -ENV SPACK_REPO_VERSION=${SPACK_REPO_VERSION} +ENV INITIAL_SPACK_CONFIG_REPO_VERSION=${SPACK_CONFIG_REPO_VERSION} +ENV INITIAL_SPACK_REPO_VERSION=${SPACK_REPO_VERSION} # Export the spack config directory for the runner target ENV SPACK_CONFIG_DIR=${SPACK_CONFIG_DIR} @@ -160,7 +155,6 @@ ENV SPACK_CONFIG_DIR=${SPACK_CONFIG_DIR} ENV SPACK_USER_CACHE_PATH=${SPACK_ROOT}/.. LABEL au.org.access-nri.image.spack-repo-version=${SPACK_REPO_VERSION} -LABEL au.org.access-nri.image.spack-packages-repo-version=${SPACK_PACKAGES_REPO_VERSION} LABEL au.org.access-nri.image.spack-config-repo-version=${SPACK_CONFIG_REPO_VERSION} SHELL ["/bin/bash", "-c"] @@ -169,14 +163,10 @@ SHELL ["/bin/bash", "-c"] RUN < '' <pr_body_file> <repos_dir>" + exit 1 +fi + +### Creation of changes and PR + +deployment_repos=$(gh search repos --owner access-nri --include-forks=true \ + --json name \ + --jq '[.[].name] | join(" ")' \ + -- topic:build-ci-enabled +) +branch="infra-update-$version" + +echo "MAKE SURE YOU HAVE UPDATED THE BODY FILE + PR TITLE IN SCRIPT" +echo "Going to change the following repos in 10s: $deployment_repos" +sleep 10 + +for repo in $deployment_repos; do + cd "$repos_dir/$repo" || exit + + # Check if there are uncommitted changes and exit if so - we don't want to commit something automatically + uncommitted_changes=$(git ls-files --others --directory --deleted --modified --exclude-standard) + if [ -n "$uncommitted_changes" ]; then + echo "Uncommitted changes in $repo: $uncommitted_changes. Exiting..." + exit 1 + fi + + # Getting repos in a state to create PR + git checkout main + git pull + git checkout -b "$branch" + + # Editing of files - be careful! + # Basic update of entrypoints to $version + sed -i -E "s|(access-nri/build-ci/.+)@v.+|\1@$version|g" .github/workflows/c*.yml + # Other changes here... + + + # git operations + git add . + git commit -m "infra: Update to $version" + git push + + # PR creation + cd - || exit + + default_branch=$(gh repo view "access-nri/$repo" --json defaultBranchRef --jq .defaultBranchRef.name) + gh pr create \ + --repo "access-nri/$repo" \ + --assignee @me \ + --title "$pr_title" \ + --body-file "$pr_body_file" \ + --base "$default_branch" \ + --head "$branch" \ + --draft + + sleep 3 +done \ No newline at end of file diff --git a/tools/mcr-change/templates/general.pull-request.md b/tools/mcr-change/templates/general.pull-request.md new file mode 100644 index 00000000..841bd1c1 --- /dev/null +++ b/tools/mcr-change/templates/general.pull-request.md @@ -0,0 +1,18 @@ +References issue ACCESS-NRI/build-cd#<NUM> and PR ACCESS-NRI/build-cd#<NUM> + +> [!IMPORTANT] +> This PR is a major update to the deployment infrastructure. See below for the prerequisites for this repository to be able to merge this PR. + +## Background + +<Short statement on the infrastructure update> + +The main new features include: + +* **Feature 1**: Something + +* **Feature 2**: Something else + +## Prerequisites for Merging + +- [ ] Update `build-cd` entrypoints (this PR!)