diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 3d68274..9e150eb 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,10 +1,10 @@ # Entrypoint Workflows -## `ci.yml`, `ci-github-hosted.yml` - Build and Test Workflow Entrypoint +## `ci.yml` - Build and Test Workflow Entrypoint ### Overview -This workflow handles building and running short CI tests on a given spack manifest. It offers customisation of `spack`, `spack-config` and `spack-packages`, and allows SSH access to the installation to the author of the PR. +This workflow handles building and running short CI tests on a given spack manifest. It offers customisation of `spack`, `spack-config`, and spack packages repos, and allows SSH access to the installation to the author of the PR. ### Inputs @@ -21,6 +21,7 @@ This workflow handles building and running short CI tests on a given spack manif | `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"` | +| `run-self-hosted` | `boolean` | Whether to run the job on a self-hosted runner. For security, workflow runs will hang if this is `true` but it is not using a valid `v*` branch or tag for the workflow ref | `false` | `true` | `true`, `false` | #### Future Inputs @@ -89,6 +90,7 @@ jobs: access-spack-packages-ref: 2025.05.000 spack-config-ref: 2025.10.001 allow-ssh-into-spack-install: true + run-self-hosted: false secrets: spack-install-command-pat: ${{ secrets.GH_PAT }} ``` diff --git a/.github/workflows/ci-github-hosted.yml b/.github/workflows/ci-github-hosted.yml deleted file mode 100644 index f13615d..0000000 --- a/.github/workflows/ci-github-hosted.yml +++ /dev/null @@ -1,537 +0,0 @@ -name: CI (GH) -run-name: CI Test ${{ github.repository }} at ${{ github.event.number }} (${{ github.sha }}) -on: - workflow_call: - inputs: - spack-manifest-path: - required: true - type: string - description: | - A file path in the caller model component repository that contains the spack manifest template to install. - For example: .github/build/manifests/template/access-om2.spack.yaml.j2. - spack-manifest-data-path: - required: false - type: string - description: | - An optional file path in the caller model component repository that contains data to fill in the spack manifest jinja template. - This doesn't include {{ ref }}, which is filled in automatically. - For example: .github/build/manifests/data/access-om2.spack.yaml.j2.json. - spack-manifest-data-pairs: - required: false - type: string - description: | - 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. - For example: - package mom5 - compiler intel - spack-compiler-manifest-path: - required: false - type: string - description: | - A file path in the caller model component repository that contains the spack manifest to install local compilers not in the upstream. - For example: .github/build/manifests/compilers.spack.yaml. - ref: - required: false - type: string - # Since the github.sha for a pull request is the commit SHA of the merge commit (which - # doesn't exist in the caller model component repository), we will instead use the PR HEAD SHA. - default: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} - description: | - The branch, tag, or commit SHA of the caller model component repository. - This value is filled in to the inputs.spack-manifest-path template as {{ ref }}. - For example: main, 2025.03.0, 7ey2uy2. - spack-config-ref: - required: false - type: string - default: main - description: | - The branch, tag, or commit SHA of the access-nri/spack-config repository to use. - For example: main, 2025.03.0, 7ey2uy2. - builtin-spack-packages-ref: - required: false - type: string - 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 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. - pytest-test-markers: - required: false - type: string - description: | - A string of pytest markers to use to filter tests in the caller model component repository's .github/build/tests directory. - For example: "not slow and not mpi". - allow-ssh-into-spack-install: - required: false - type: boolean - default: false - description: | - 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. - container-image-version: - required: false - type: string - default: :rocky - description: | - The version of the container image to use for the runner. - Can be either a tag (specified by ':TAG') or a SHA (specified by '@sha256:SHA'). - For example: ':8.9' or 'rocky@sha256:1234...'. - spack-oci-buildcache-url: - required: false - type: string - description: | - 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. - For example: 'oci://ghcr.io/ACCESS-NRI/build-ci-buildcache'. - secrets: - spack-install-command-pat: - required: false - description: | - An optional GitHub PAT to use for the spack install command, for access to potentially private repositories. - spack-oci-buildcache-username: - required: false - description: | - A username (or GitHub username for oci://ghcr.io buildcaches) to use for reading and writing to the spack OCI buildcache, if inputs.spack-oci-buildcache-url is defined. - spack-oci-buildcache-password: - required: false - description: | - A password (or GitHub PAT for oci://ghcr.io buildcaches) to use for reading and writing to the spack OCI buildcache, if inputs.spack-oci-buildcache-url is defined. - outputs: - spec-concretization-graph: - value: ${{jobs.spack-install-and-test.outputs.spec-concretization-graph }} - description: | - A visual representation of the dependencies and constraints of the spack manifest file installed. - spack-sha: - value: ${{ jobs.spack-install-and-test.outputs.spack-sha }} - description: | - The SHA of the spack repository checked out. - spack-config-sha: - value: ${{ jobs.spack-install-and-test.outputs.spack-config-sha }} - description: | - The SHA of the spack-config repository checked out. - 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 access-spack-packages repository checked out. - sha: - value: ${{ jobs.spack-install-and-test.outputs.sha }} - description: | - The SHA of the caller model component repository checked out. - container-id: - value: ${{ jobs.spack-install-and-test.outputs.container-id }} - description: | - The ID of the container where the spack packages have been installed. - short-container-id: - value: ${{ jobs.spack-install-and-test.outputs.short-container-id }} - description: | - The short ID of the container where the spack packages have been installed - used for artifact disambiguation. - ## These outputs contain information on data uploaded as artifacts - spack-files-artifact-pattern: - value: ${{ jobs.spack-install-and-test.outputs.spack-files-artifact-pattern }} - description: | - Wildcard pattern to match all spack file artifacts across a matrix job. - spack-files-artifact-url: - value: ${{ jobs.spack-install-and-test.outputs.spack-files-artifact-url }} - description: | - The URL of the spack file artifact, which contains the spack files created. - job-output-artifact-pattern: - value: ${{ jobs.spack-install-and-test.outputs.job-output-artifact-pattern }} - description: | - Wildcard pattern to match all job output artifacts across a matrix job. - job-output-artifact-url: - value: ${{ jobs.spack-install-and-test.outputs.job-output-artifact-url }} - description: | - The URL of the job output artifact, which contains the job outputs in JSON format. - spack-logs-artifact-pattern: - value: ${{ jobs.spack-install-and-test.outputs.spack-logs-artifact-pattern }} - description: | - Wildcard pattern to match all spack log artifacts across a matrix job. - spack-logs-artifact-url: - value: ${{ jobs.spack-install-and-test.outputs.spack-logs-artifact-url }} - description: | - The URL of the spack log artifact, which contains the spack logs created. - # test-artifact-url: - # value: ${{}} - # description: | - # The URL of the pytest result artifact. -jobs: - spack-install-and-test: - name: Install and Test - runs-on: ubuntu-latest - container: - image: ghcr.io/access-nri/build-ci-upstream${{ inputs.container-image-version }} - outputs: - spec-concretization-graph: ${{ steps.install.outputs.spec }} - spack-sha: ${{ steps.spack-update.outputs.sha }} - spack-config-sha: ${{ steps.spack-config-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 }} - job-output-artifact-pattern: ${{ steps.env.outputs.job-output-artifact-pattern }} - job-output-artifact-url: ${{ steps.output-upload.outputs.artifact-url }} - spack-logs-artifact-pattern: ${{ steps.env.outputs.spack-logs-artifact-pattern }} - spack-logs-artifact-url: ${{ steps.logs-upload.outputs.artifact-url }} - container-id: ${{ steps.env.outputs.container-id }} - short-container-id: ${{ steps.env.outputs.short-container-id }} - # test-artifact-url: ${{ steps.test.outputs.artifact-url }} - steps: - - 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 INITIAL_SPACK_REPO_VERSION; do - echo "$var=${!var}" >> $GITHUB_OUTPUT - done - - # The upload step later requires a non-relative path, hence the realpath - echo "spack-env-dir=$(realpath $SPACK_ROOT/../environments)" >> $GITHUB_OUTPUT - - container_id=${{ job.container.id }} - short_container_id=${container_id:0:8} - - # We can only get the job.container.id after the container is started, so we set it as the file name here - echo "job-output-artifact-name=job-output-$short_container_id" >> $GITHUB_OUTPUT - echo "job-output-artifact-pattern=job-output-*" >> $GITHUB_OUTPUT - - echo "spack-files-artifact-name=spack-files-$short_container_id" >> $GITHUB_OUTPUT - echo "spack-files-artifact-pattern=spack-files-*" >> $GITHUB_OUTPUT - - echo "spack-logs-artifact-name=spack-logs-$short_container_id" >> $GITHUB_OUTPUT - echo "spack-logs-artifact-pattern=spack-logs-*" >> $GITHUB_OUTPUT - - echo "container-id=$container_id" >> $GITHUB_OUTPUT - echo "short-container-id=$short_container_id" >> $GITHUB_OUTPUT - - - name: Update - spack-config version - id: spack-config-update - 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 - id: spack-update - 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: 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. - # We find what branch the spack SHA is part of, and attempt to link to that directory. - run: | - spack_branch=$(git -C ${{ steps.env.outputs.SPACK_ROOT }} for-each-ref --format='%(refname:short)' refs/remotes --contains ${{ steps.spack-update.outputs.sha }} \ - | grep origin/releases/ \ - | sed -E 's|^origin/releases/(.+)|\1|' \ - ) - - if [[ $(echo "$spack_branch" | wc -l) -gt 1 ]]; then - echo "::error::${{ steps.spack-update.outputs.sha }} is part of multiple spack release branches, and we can't determine which to link spack-config to" - exit 2 - elif [[ -z "$spack_branch" ]]; then - echo "::error::${{ steps.spack-update.outputs.sha }} is not part of any spack release branch, so we can't link spack-config to anything" - exit 2 - else - 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 - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - echo "----- Compilers -----" - spack compiler list - echo "----- Packages -----" - spack find - - - name: Spack - Get spack-packages repo locations - id: spack-packages-locations - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - - echo "builtin=$(spack location --repo builtin)" >> $GITHUB_OUTPUT - echo "access-spack-packages=$(spack location --repo access.nri)" >> $GITHUB_OUTPUT - - - 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 != '' - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - spack mirror add --scope=system \ - --unsigned \ - --oci-username-variable OCI_USERNAME \ - --oci-password-variable OCI_PASSWORD \ - oci_buildcache ${{ inputs.spack-oci-buildcache-url }} - spack mirror list - - - name: Manifest - Checkout ${{ github.repository }} - id: checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - submodules: recursive - - - name: Manifest - Install Compilers Locally - # Some compilers may not be available upstream, so we install them locally in a separate spack.yaml - if: inputs.spack-compiler-manifest-path != '' - env: - # For pulling OCI buildcache - OCI_USERNAME: ${{ secrets.spack-oci-buildcache-username || github.actor }} - OCI_PASSWORD: ${{ secrets.spack-oci-buildcache-password || secrets.GITHUB_TOKEN }} - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - spack env activate local_compilers --create --prompt --envfile ${{ inputs.spack-compiler-manifest-path }} - spack --debug install --fail-fast --deprecated - spack env deactivate - yq '.spack.specs[]' ${{ inputs.spack-compiler-manifest-path }} | while read compiler; do - spack load $compiler - spack compiler find --scope=site - done - spack compiler list - - - name: Manifest - Install jinja-cli - run: python3 -m pip install jinja-cli==1.2.2 - - - name: Manifest - Replace jinja template variables - # This means that the caller manifest files can remain unchanged, but still vary based on the {{ pr }} - # Additional data can be provided to fill in the jinja template through the `spack-manifest-data-path` input - id: jinja-templated - run: | - templated_manifest_path=$(dirname ${{ inputs.spack-manifest-path }})/templated/$(basename ${{ inputs.spack-manifest-path }} .j2) - mkdir -p $(dirname $templated_manifest_path) - - jinja \ - --define ref ${{ inputs.ref }} \ - $( [ -n "${{ inputs.spack-manifest-data-pairs }}" ] && while read -r d; do echo "--define $d"; done <<< "${{ inputs.spack-manifest-data-pairs }}") \ - ${{ inputs.spack-manifest-data-path != '' && format('--data {0}', inputs.spack-manifest-data-path) || '' }} \ - ${{ inputs.spack-manifest-path}} \ - > $templated_manifest_path - - echo "Templated manifest at $templated_manifest_path is:" - cat $templated_manifest_path - - echo "spack-manifest-path=$templated_manifest_path" >> $GITHUB_OUTPUT - - - name: Manifest - Install - id: install - env: - # 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 - # We set the git config via environment variables, so that the PATs are not persisted in the container - GIT_CONFIG_COUNT: 1 - GIT_CONFIG_KEY_0: url.https://oauth2:${{ secrets.spack-install-command-pat || secrets.GITHUB_TOKEN }}@github.com/.insteadOf - GIT_CONFIG_VALUE_0: https://github.com/ - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - 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 - - # Output config before install for debugging - echo "::group::Spack Config Blame Output" - spack config blame - echo "::endgroup::" - - spack --debug install --fail-fast --deprecated - - - name: Manifest - Push to Buildcache - 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 - 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 != '' - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - spack -e default buildcache push --unsigned --only=dependencies oci_buildcache - - - name: Manifest - Upload - if: always() && (steps.install.conclusion == 'failure' || steps.install.conclusion == 'success') - id: manifest-upload - # Upload spack manifest and lock files - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.env.outputs.spack-files-artifact-name }} - path: ${{ steps.env.outputs.spack-env-dir }}/default/spack.* - if-no-files-found: error - - - name: Manifest - Logs Create - if: always() && (steps.install.conclusion == 'failure' || steps.install.conclusion == 'success') - id: logs-create - # Logs may not be available if the spack install failed before concretization, so we'd rather direct users to the - # above install failure than have this step fail. - continue-on-error: true - run: | - . ${{ steps.env.outputs.SPACK_ROOT }}/share/spack/setup-env.sh - - mkdir logs - - if [ ! -f ${{ steps.env.outputs.spack-env-dir }}/default/spack.lock ]; then - echo "Spack lock file not found, skipping log creation." - exit 0 - fi - - # Get all the top-level hashes from the manifest - hashes="$(jq --raw-output '.roots[].hash' ${{ steps.env.outputs.spack-env-dir }}/default/spack.lock)" - echo "Found top-level hashes:" - echo "$hashes" - - i=0 - while read -r hash; do - spack -e default logs /$hash > "logs/spec_${i}.log" || true - i=$((i + 1)) - done <<< "$hashes" - - - name: Manifest - Logs Upload - if: always() && (steps.install.conclusion == 'failure' || steps.install.conclusion == 'success') - id: logs-upload - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.env.outputs.spack-logs-artifact-name }} - path: logs/*.log - if-no-files-found: warn - - - name: Tmate - Create session - # Only create the session if the spack installation was attempted, and we want a tmate session - if: >- - always() && - (steps.install.conclusion == 'failure' || steps.install.conclusion == 'success') && - inputs.allow-ssh-into-spack-install - id: tmate - uses: mxschmitt/action-tmate@e5c7151931ca95bad1c6f4190c730ecf8c7dde48 # v3.19 - with: - # sudo is not accessible in this container - sudo: false - # allow future steps to run without awaiting tmate session close - detached: true - # Only allow actor to access the tmate session - limit-access-to-actor: true - # Our runner container has tmate pre-installed - install-dependencies: false - - # TODO: Add pytest infrastructure - # - name: Run pytests - # id: test - # run: | - # python -m pytest -v -m "${{ inputs.pytest-test-markers }}" --junitxml=pytest.xml - # echo "pytest=$(cat pytest.xml)" >> $GITHUB_OUTPUT - - - name: Job Outputs - Create - if: always() && (steps.install.conclusion == 'failure' || steps.install.conclusion == 'success') - id: output-create - # The outputs of the job also contain the inputs to the job, so that they can be used in future jobs. - # We need to serialize the spec concretization graph and data pairs to a single line, so that it can be used in JSON. - run: | - serialized_spec_concretization_graph=$(echo "${{ steps.install.outputs.spec }}" | sed -z 's/\n/\\n/g') - serialized_spack_manifest_data_pairs=$(echo ${{ inputs.spack-manifest-data-pairs }} | sed -z 's/\n/\\n/g') - - jq --null-input \ - --arg spec "$serialized_spec_concretization_graph" \ - --arg pairs "$serialized_spack_manifest_data_pairs" \ - '{ - "spack_manifest_path": "${{ inputs.spack-manifest-path }}", - "spack_manifest_data_path": "${{ inputs.spack-manifest-data-path }}", - "spack_manifest_data_pairs": $pairs, - "spack_compiler_manifest_path": "${{ inputs.spack-compiler-manifest-path }}", - "ref": "${{ inputs.ref }}", - "spack_config_ref": "${{ inputs.spack-config-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 }}", - "container_image_version": "${{ inputs.container-image-version }}", - - "spack_install_result": "${{ steps.install.conclusion }}", - - "spec_concretization_graph": $spec, - "spack_sha": "${{ steps.spack-update.outputs.sha }}", - "spack_config_sha": "${{ steps.spack-config-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 }}", - "spack_files_artifact_pattern": "${{ steps.env.outputs.spack-files-artifact-pattern }}", - "spack_files_artifact_url": "${{ steps.manifest-upload.outputs.artifact-url }}", - "job_output_artifact_pattern": "${{ steps.env.outputs.job-output-artifact-pattern }}", - "spack_logs_artifact_url": "${{ steps.logs-upload.outputs.artifact-url }}", - "spack_logs_artifact_pattern": "${{ steps.env.outputs.artifact-pattern }}" - }' > ./${{ steps.env.outputs.job-output-artifact-name }} - - - name: Job Outputs - Upload - if: always() && (steps.install.conclusion == 'failure' || steps.install.conclusion == 'success') - id: output-upload - uses: actions/upload-artifact@v4 - with: - name: ${{ steps.env.outputs.job-output-artifact-name }} - path: ./${{ steps.env.outputs.job-output-artifact-name }} - if-no-files-found: error diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 106ec86..3692919 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,6 +100,13 @@ on: 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. For example: 'oci://ghcr.io/ACCESS-NRI/build-ci-buildcache'. + run-self-hosted: + required: false + type: boolean + default: true + description: | + Whether to run the job on a self-hosted runner. + For security, workflow runs will hang if this is true but it is not using a valid v* branch or tag for the workflow ref. secrets: spack-install-command-pat: required: false @@ -178,13 +185,14 @@ on: jobs: spack-install-and-test: name: Install and Test - runs-on: - group: build-ci + runs-on: ${{ inputs.run-self-hosted && fromJson('{"group":"build-ci"}') || 'ubuntu-latest' }} container: - image: ghcr.io/access-nri/build-ci-runner${{ inputs.container-image-version }} + image: ${{ inputs.run-self-hosted && 'ghcr.io/access-nri/build-ci-runner' || 'ghcr.io/access-nri/build-ci-upstream' }}${{ inputs.container-image-version }} volumes: - - /opt/upstream-v1:/opt/upstream:ro - - /opt/runner_set_buildcache:/opt/runner_set_buildcache:rw + # For self-hosted runners, mount the proper upstream and buildcache volumes from the kubernetes cluster + # For GitHub-hosted runners, mount the dummy volume /dev/null to avoid errors or undefined behavior, eg. fromJson('[]') + - ${{ inputs.run-self-hosted && '/opt/upstream-v1:/opt/upstream:ro' || '/dev/null:/dev/null:ro' }} + - ${{ inputs.run-self-hosted && '/opt/runner_set_buildcache:/opt/runner_set_buildcache:rw' || '/dev/null:/dev/null:ro' }} outputs: spec-concretization-graph: ${{ steps.install.outputs.spec }} spack-sha: ${{ steps.spack-update.outputs.sha }} diff --git a/README.md b/README.md index 1c7a55c..a8f4917 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ This repository also contains the resources required to build images that are us ### Using The Entrypoint Workflows -Generally, the [`ci.yml`](./.github/workflows/ci.yml) workflow can be used by any model component repository in the ACCESS-NRI organisation, it just requires using the reusable workflow from this repository. +The [`ci.yml`](./.github/workflows/ci.yml) workflow can be used by any model component repository in the ACCESS-NRI organisation using self-hosted runners, it just requires using the reusable workflow from this repository. -Alternatively, for organisations outside of ACCESS-NRI, the `ci-github-hosted.yml` can be used. But... +Alternatively, for organisations outside of ACCESS-NRI, the `ci.yml` can be used if the `run-self-hosted: false` argument is set. But... > [!IMPORTANT] -> Note that the `ci-github-hosted.yml` is slower than the self-hosted variant due to GitHub not caching large images used to initialize compilers and packages, and the lack of a persistent buildcache. +> Note that the workflow is slower than the self-hosted variant due to GitHub not caching large images used to initialize compilers and packages, and the lack of a persistent buildcache. Basic templates for model component repositories CI are available under [`model-component-ci-templates`](./model-component-ci-templates/) - more complex use cases are possible and encouraged!