Skip to content

Merge remote-tracking branch 'origin/main' into cudaq-src #24

Merge remote-tracking branch 'origin/main' into cudaq-src

Merge remote-tracking branch 'origin/main' into cudaq-src #24

Workflow file for this run

on:

Check failure on line 1 in .github/workflows/docker_images.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/docker_images.yml

Invalid workflow file

(Line: 651, Col: 19): Unrecognized function: 'replace'. Located at position 1 within expression: replace(steps.prereqs.outputs.image_name, 'cuda-quantum', 'cuda-quantum-src')
workflow_call:
inputs:
platforms:
type: string
required: false
default: linux/amd64
devdeps_image:
required: false
type: string
devdeps_cache:
required: false
type: string
devdeps_archive:
required: false
type: string
ompidev_image:
required: false
type: string
build_docs:
required: false
type: string
cuda_version:
required: false
type: string
description: The CUDA version with which the development dependencies were built.
environment:
required: false
type: string
secrets:
NGC_CREDENTIALS:
description: 'Credentials for deployments to NGC.'
required: false
DOCKERHUB_USERNAME:
required: true
DOCKERHUB_READONLY_TOKEN:
required: true
name: Docker images
jobs:
metadata:
name: Metadata
runs-on: ubuntu-latest
permissions: {}
outputs:
runner: ${{ steps.info.outputs.runner }}
platform_tag: ${{ steps.info.outputs.platform_tag }}
build_docs: ${{ steps.info.outputs.build_docs }}
push_to_ngc: ${{ steps.info.outputs.push_to_ngc }}
is_versioned: ${{ steps.info.outputs.is_versioned }}
# Needed to define metadata depending on whether an environment secret is defined.
environment:
name: ${{ inputs.environment || 'default' }}
url: ${{ vars.deployment_url || format('https://github.com/{0}', github.repository) }}
steps:
- id: info
run: |
is_versioned=${{ github.ref_type == 'tag' || startsWith(github.ref_name, 'releases/') || startsWith(github.ref_name, 'staging/') }}
echo "is_versioned=$is_versioned" >> $GITHUB_OUTPUT
if [ -n "$(echo ${{ inputs.platforms }} | grep ',')" ]; then
# multi-platform builds get no platform tag
echo "runner=linux-amd64-cpu16" >> $GITHUB_OUTPUT
echo "build_docs=${{ inputs.build_docs != 'false' }}" >> $GITHUB_OUTPUT
has_continuous_deployment=${{ startsWith(github.ref_name, 'experimental/') || github.ref_name == 'main' }}
push_to_ngc=`${{ inputs.environment && secrets.NGC_CREDENTIALS != '' }} && ($is_versioned || $has_continuous_deployment) && echo true || echo`
echo "push_to_ngc=$push_to_ngc" >> $GITHUB_OUTPUT
elif [ -n "$(echo ${{ inputs.platforms }} | grep -i arm)" ]; then
platform_tag=`echo ${{ inputs.platforms }} | sed 's/linux\///g' | tr -d ' '`
echo "platform_tag=$platform_tag" >> $GITHUB_OUTPUT
echo "runner=linux-arm64-cpu16" >> $GITHUB_OUTPUT
echo "build_docs=${{ inputs.build_docs == 'true' }}" >> $GITHUB_OUTPUT
else
platform_tag=`echo ${{ inputs.platforms }} | sed 's/linux\///g' | tr -d ' '`
echo "platform_tag=$platform_tag" >> $GITHUB_OUTPUT
echo "runner=linux-amd64-cpu16" >> $GITHUB_OUTPUT
echo "build_docs=${{ inputs.build_docs != 'false' }}" >> $GITHUB_OUTPUT
fi
ompi_image:
name: open-mpi
needs: metadata
if: inputs.ompidev_image
runs-on: ${{ needs.metadata.outputs.runner }}
permissions:
contents: read
packages: write
id-token: write
outputs:
tar_cache: ${{ steps.build_info.outputs.tar_cache }}
tar_archive: ${{ steps.build_info.outputs.tar_archive }}
image_hash: ${{ steps.build_info.outputs.image_name }}@${{ steps.docker_build.outputs.digest }}
environment:
name: ${{ inputs.environment || 'default' }}
url: ${{ vars.deployment_url || format('https://github.com/{0}', github.repository) }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Log in to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_READONLY_TOKEN }}
- name: Log in to the container registry
if: inputs.environment && vars.registry
uses: docker/login-action@v3
with:
registry: ${{ vars.registry }}
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Determine build arguments
id: build_info
run: |
repo_owner=${{ github.repository_owner }}
registry=${{ vars.registry || 'localhost:5000' }}
image_name=$registry/${repo_owner,,}/${{ vars.packages_prefix }}open-mpi
echo "image_name=$image_name" >> $GITHUB_OUTPUT
docker pull ${{ inputs.ompidev_image }} # to get the tag
dev_tag=`docker inspect ${{ inputs.ompidev_image }} --format='{{json .Config.Labels}}' | jq -r '."org.opencontainers.image.version"'`
echo "image_tag=${dev_tag#ompi-}" >> $GITHUB_OUTPUT
docker image rm ${{ inputs.ompidev_image }}
docker image prune --force
if ${{ inputs.environment == '' }}; then
tar_archive=/tmp/open-mpi.tar
echo "tar_cache=tar-ompi-${{ needs.metadata.outputs.platform_tag }}-${{ github.sha }}" >> $GITHUB_OUTPUT
echo "tar_archive=$tar_archive" >> $GITHUB_OUTPUT
echo "docker_output=type=docker,dest=$tar_archive" >> $GITHUB_OUTPUT
fi
- name: Extract metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.build_info.outputs.image_name }}
flavor:
latest=false
tags: |
type=raw,value=${{ steps.build_info.outputs.image_tag }}
labels: |
org.opencontainers.image.title=open-mpi
org.opencontainers.image.description=Open MPI dependencies of CUDA Quantum
- name: Set up context for buildx
run: |
docker context create builder_context
- name: Set up buildx runner
uses: docker/setup-buildx-action@v3
with:
endpoint: builder_context
version: v0.19.0
buildkitd-config: ${{ needs.metadata.outputs.runner != 'ubuntu-latest' && '/etc/buildkit/buildkitd.toml' || null }}
driver-opts: |
network=host
image=moby/buildkit:v0.19.0
- name: Setup proxy cache
if: needs.metadata.outputs.runner != 'ubuntu-latest'
uses: nv-gha-runners/setup-proxy-cache@main
with:
enable-apt: true
- name: Build Open MPI
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/build/devcontainer.Dockerfile
build-args: |
ompidev_image=${{ inputs.ompidev_image }}
base_image=nvcr.io/nvidia/cuda:${{ inputs.cuda_version }}.0-runtime-ubuntu24.04
cuda_version=${{ inputs.cuda_version }}
cuda_packages=
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
platforms: ${{ inputs.platforms }}
push: ${{ inputs.environment != '' }}
outputs: ${{ steps.build_info.outputs.docker_output }}
- name: Install Cosign
if: inputs.environment
uses: sigstore/cosign-installer@v3.3.0
with:
cosign-release: 'v2.2.2'
- name: Sign image with GitHub OIDC Token
if: inputs.environment && false # Signing is disabled as long as the package is private, since we can't clean up signatures in that case
env:
DIGEST: ${{ steps.docker_build.outputs.digest }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: cosign sign --yes --recursive "${TAGS}@${DIGEST}"
- name: Cache cuda-quantum image
if: steps.build_info.outputs.tar_cache && steps.build_info.outputs.tar_archive
uses: actions/cache/save@v4
with:
path: ${{ steps.build_info.outputs.tar_archive }}
key: ${{ steps.build_info.outputs.tar_cache }}
cudaqdev_image:
name: cuda-quantum-dev (debug)
needs: metadata
runs-on: ${{ needs.metadata.outputs.runner }}
permissions:
contents: read
packages: write
id-token: write
outputs:
tar_cache: ${{ steps.prereqs.outputs.tar_cache }}
tar_archive: ${{ steps.prereqs.outputs.tar_archive }}
image_hash: ${{ steps.prereqs.outputs.image_name }}@${{ steps.docker_build.outputs.digest }}
environment:
name: ${{ inputs.environment || 'default' }}
url: ${{ vars.deployment_url || format('https://github.com/{0}', github.repository) }}
# Needed for making local images available to the docker/build-push-action.
# See also https://stackoverflow.com/a/63927832.
services:
registry:
image: registry:2
ports:
- 5000:5000
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Log in to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_READONLY_TOKEN }}
- name: Log in to GitHub CR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Log in to the container registry
if: inputs.environment && vars.registry
uses: docker/login-action@v3
with:
registry: ${{ vars.registry }}
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Restore build environment
if: inputs.devdeps_cache && inputs.devdeps_archive
id: restore
uses: actions/cache/restore@v4
with:
path: ${{ inputs.devdeps_archive }}
key: ${{ inputs.devdeps_cache }}
fail-on-cache-miss: true
- name: Load prerequisites
id: prereqs
run: |
if ${{ steps.restore.outcome != 'skipped' }}; then
load_output=`docker load --input "${{ inputs.devdeps_archive }}"`
base_image=`echo "$load_output" | grep -o 'Loaded image: \S*:\S*' | head -1 | cut -d ' ' -f 3`
echo "Base image: $base_image" >> $GITHUB_STEP_SUMMARY
# Push the image to the local registry to make it available within
# the containered environment that docker/build-push-action uses.
docker push $base_image
rm -rf "${{ inputs.devdeps_archive }}"
elif ${{ inputs.devdeps_image != '' }}; then
base_image=${{ inputs.devdeps_image }}
echo "Base image: $base_image" >> $GITHUB_STEP_SUMMARY
docker pull $base_image
else
echo "::error file=docker_images.yml::Missing configuration for development dependencies. Either specify the image (i.e. provide devdeps_image) or cache (i.e. provide devdeps_cache and devdeps_archive) that should be used for the build."
exit 1
fi
repo_owner=${{ github.repository_owner }}
registry=${{ vars.registry || 'localhost:5000' }}
image_name=$registry/${repo_owner,,}/${{ vars.packages_prefix }}cuda-quantum-dev
image_tag=`docker inspect $base_image --format='{{json .Config.Labels}}' | jq -r '."org.opencontainers.image.version"'`
docker image rm $base_image
docker image prune --force
echo "image_name=$image_name" >> $GITHUB_OUTPUT
echo "image_tag=$image_tag" >> $GITHUB_OUTPUT
echo "base_image=$base_image" >> $GITHUB_OUTPUT
if ${{ inputs.environment == '' }}; then
tar_archive=/tmp/cuda-quantum-dev.tar
echo "tar_cache=tar-cudaqdev-$image_tag-${{ needs.metadata.outputs.platform_tag }}-${{ github.sha }}" >> $GITHUB_OUTPUT
echo "tar_archive=$tar_archive" >> $GITHUB_OUTPUT
echo "docker_output=type=docker,dest=$tar_archive" >> $GITHUB_OUTPUT
fi
- name: Set up context for buildx
run: |
docker context create builder_context
- name: Set up buildx runner
uses: docker/setup-buildx-action@v3
with:
endpoint: builder_context
version: v0.19.0
buildkitd-config: ${{ needs.metadata.outputs.runner != 'ubuntu-latest' && '/etc/buildkit/buildkitd.toml' || null }}
driver-opts: |
network=host
image=moby/buildkit:v0.19.0
- name: Setup proxy cache
if: needs.metadata.outputs.runner != 'ubuntu-latest'
uses: nv-gha-runners/setup-proxy-cache@main
with:
enable-apt: true
- name: Extract metadata
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.prereqs.outputs.image_name }}
flavor: latest=false
tags: type=raw,value=${{ steps.prereqs.outputs.image_tag }}
labels: |
org.opencontainers.image.title=cuda-quantum-dev
org.opencontainers.image.description=Dev environment for CUDA Quantum (debug build)
- name: Build cuda-quantum-dev image (debug)
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/build/cudaq.dev.Dockerfile
build-args: |
base_image=${{ steps.prereqs.outputs.base_image }}
install="CMAKE_BUILD_TYPE=Debug"
git_source_sha=${{ github.sha }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
platforms: ${{ inputs.platforms }}
push: ${{ inputs.environment != '' }}
outputs: ${{ steps.prereqs.outputs.docker_output }}
- name: Write matrix outputs
uses: cloudposse/github-action-matrix-outputs-write@1.0.0
with:
matrix-step-name: docker_images
matrix-key: ${{ needs.metadata.outputs.platform_tag }}-cu${{ inputs.cuda_version }}-dev-image
outputs: |
digest: ${{ steps.docker_build.outputs.digest }}
image_tag: ${{ steps.metadata.outputs.tags }}
- name: Install Cosign
if: inputs.environment
uses: sigstore/cosign-installer@v3.3.0
with:
cosign-release: 'v2.2.2'
- name: Sign image with GitHub OIDC Token
if: inputs.environment
env:
DIGEST: ${{ steps.docker_build.outputs.digest }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: cosign sign --yes --recursive "${TAGS}@${DIGEST}"
- name: Cache cuda-quantum-dev image
if: steps.prereqs.outputs.tar_cache && steps.prereqs.outputs.tar_archive
uses: actions/cache/save@v4
with:
path: ${{ steps.prereqs.outputs.tar_archive }}
key: ${{ steps.prereqs.outputs.tar_cache }}
cudaq_image:
name: cuda-quantum (release)
needs: [metadata, ompi_image]
# Force this job to run even when some of the dependencies above are skipped.
if: always() && !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
runs-on: ${{ needs.metadata.outputs.runner }}
permissions:
contents: read
packages: write
id-token: write
outputs:
tar_cache: ${{ steps.prereqs.outputs.tar_cache }}
tar_archive: ${{ steps.prereqs.outputs.tar_archive }}
image_hash: ${{ steps.prereqs.outputs.image_name }}@${{ steps.cudaq_build.outputs.digest }}
environment:
name: ${{ inputs.environment || 'default' }}
url: ${{ vars.deployment_url || format('https://github.com/{0}', github.repository) }}
# Needed for making local images available to the docker/build-push-action.
# See also https://stackoverflow.com/a/63927832.
services:
registry:
image: registry:2
ports:
- 5000:5000
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
- name: Log in to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_READONLY_TOKEN }}
- name: Log in to GitHub CR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Log in to the container registry
if: inputs.environment && vars.registry
uses: docker/login-action@v3
with:
registry: ${{ vars.registry }}
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Restore build environment
if: inputs.devdeps_cache && inputs.devdeps_archive
id: restore_devdeps
uses: actions/cache/restore@v4
with:
path: ${{ inputs.devdeps_archive }}
key: ${{ inputs.devdeps_cache }}
fail-on-cache-miss: true
- name: Restore Open MPI dependencies
id: restore_openmpi
if: needs.ompi_image.outputs.tar_cache && needs.ompi_image.outputs.tar_archive
uses: actions/cache/restore@v4
with:
path: ${{ needs.ompi_image.outputs.tar_archive }}
key: ${{ needs.ompi_image.outputs.tar_cache }}
fail-on-cache-miss: true
- name: Load prerequisites
id: prereqs
run: |
if ${{ needs.ompi_image.result == 'skipped' }}; then
base_image=ghcr.io/nvidia/ubuntu:24.04
elif ${{ steps.restore_openmpi.outcome != 'skipped' }}; then
load_output=`docker load --input "${{ needs.ompi_image.outputs.tar_archive }}"`
base_image=`echo "$load_output" | grep -o 'Loaded image: \S*:\S*' | head -1 | cut -d ' ' -f 3`
echo "Base image: $base_image" >> $GITHUB_STEP_SUMMARY
# Push the image to the local registry to make it available within
# the containered environment that docker/build-push-action uses.
docker push $base_image
docker image rm $base_image
rm -rf "${{ needs.ompi_image.outputs.tar_archive }}"
else
base_image=${{ needs.ompi_image.outputs.image_hash }}
echo "Base image: $base_image" >> $GITHUB_STEP_SUMMARY
fi
if ${{ steps.restore_devdeps.outcome != 'skipped' }}; then
load_output=`docker load --input "${{ inputs.devdeps_archive }}"`
echo "$load_output"
devdeps_image=`echo "$load_output" | grep -o 'Loaded image: \S*:\S*' | head -1 | cut -d ' ' -f 3`
echo "Devdeps image: $devdeps_image" >> $GITHUB_STEP_SUMMARY
# Push the image to the local registry to make it available within
# the containered environment that docker/build-push-action uses.
docker push $devdeps_image
docker image rm $devdeps_image
rm -rf "${{ inputs.devdeps_archive }}"
elif ${{ inputs.devdeps_image != '' }}; then
devdeps_image=${{ inputs.devdeps_image }}
echo "Devdeps image: $devdeps_image" >> $GITHUB_STEP_SUMMARY
else
echo "::error file=docker_images.yml::Missing configuration for development dependencies. Either specify the image (i.e. provide devdeps_image) or cache (i.e. provide devdeps_cache and devdeps_archive) that should be used for the build."
exit 1
fi
docker image prune --force
repo_owner=${{ github.repository_owner }}
registry=${{ vars.registry || 'localhost:5000' }}/${repo_owner,,}
ngc_registry=`${{ needs.metadata.outputs.push_to_ngc == 'true' }} && echo nvcr.io/${repo_owner,,}/nightly || echo ''`
dev_image_name=${registry}/${{ vars.packages_prefix }}cuda-quantum-dev
image_name=${ngc_registry:-$registry}/${{ vars.packages_prefix }}cuda-quantum
image_description="CUDA Quantum toolkit for heterogeneous quantum-classical workflows"
platform_tag=${{ needs.metadata.outputs.platform_tag }}
cuda_major=`echo ${{ inputs.cuda_version }} | cut -d . -f1`
deprecation_notice=""
image_tag=${platform_tag:+$platform_tag-}${cuda_major:+cu${cuda_major}-}
if ${{ github.event.pull_request.number != '' }} || [ -n "$(echo ${{ github.ref_name }} | grep pull-request/)" ]; then
pr_number=`echo ${{ github.ref_name }} | grep -o [0-9]*`
image_tag+=pr-${pr_number:-${{ github.event.pull_request.number }}}
elif ${{ github.ref_type == 'branch' && github.ref_name == 'main' }}; then
image_tag+=latest
elif ${{ needs.metadata.outputs.is_versioned == 'true' }}; then
image_tag+=`echo ${{ github.ref_name }} | egrep -o "([0-9]{1,}\.)+[0-9]{1,}"`
else
image_tag+=`echo ${{ github.ref_name }} | tr '/' '-'`
fi
echo "image_name=$image_name" >> $GITHUB_OUTPUT
echo "image_tag=$image_tag" >> $GITHUB_OUTPUT
echo "image_tag_suffix=-base" >> $GITHUB_OUTPUT
echo "image_description=$image_description" >> $GITHUB_OUTPUT
echo "base_image=$base_image" >> $GITHUB_OUTPUT
echo "devdeps_image=$devdeps_image" >> $GITHUB_OUTPUT
echo "dev_image_name=$dev_image_name" >> $GITHUB_OUTPUT
echo "deprecation_notice=$deprecation_notice" >> $GITHUB_OUTPUT
if ${{ inputs.environment == '' }}; then
tar_archive=/tmp/cuda-quantum.tar
echo "tar_cache=tar-cudaq-${image_tag}-${{ github.sha }}" >> $GITHUB_OUTPUT
echo "tar_archive=$tar_archive" >> $GITHUB_OUTPUT
echo "docker_output=type=docker,dest=$tar_archive" >> $GITHUB_OUTPUT
fi
- name: Set up context for buildx
run: |
docker context create builder_context
- name: Set up buildx runner
uses: docker/setup-buildx-action@v3
with:
endpoint: builder_context
version: v0.19.0
buildkitd-config: ${{ needs.metadata.outputs.runner != 'ubuntu-latest' && '/etc/buildkit/buildkitd.toml' || null }}
driver-opts: |
network=host
image=moby/buildkit:v0.19.0
- name: Setup proxy cache
if: needs.metadata.outputs.runner != 'ubuntu-latest'
uses: nv-gha-runners/setup-proxy-cache@main
with:
enable-apt: true
- name: Extract cuda-quantum-dev metadata
id: cudaqdev_metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.prereqs.outputs.dev_image_name }}
flavor: |
latest=false
suffix=${{ steps.prereqs.outputs.image_tag_suffix }},onlatest=true
tags: type=raw,value=${{ steps.prereqs.outputs.image_tag }}
labels: |
org.opencontainers.image.title=cuda-quantum-dev
org.opencontainers.image.description=Dev environment for CUDA Quantum (release build)
- name: Build cuda-quantum-dev image (release)
id: release_build
if: success() && !cancelled()
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/build/cudaq.dev.Dockerfile
build-args: |
base_image=${{ steps.prereqs.outputs.devdeps_image }}
install="CMAKE_BUILD_TYPE=Release CUDA_QUANTUM_VERSION=${{ steps.prereqs.outputs.image_tag }}"
git_source_sha=${{ github.sha }}
tags: ${{ steps.cudaqdev_metadata.outputs.tags }}
labels: ${{ steps.cudaqdev_metadata.outputs.labels }}
platforms: ${{ inputs.platforms }}
push: true
- name: Install Cosign
if: inputs.environment
uses: sigstore/cosign-installer@v3.3.0
with:
cosign-release: 'v2.2.2'
- name: Sign image with GitHub OIDC Token
if: inputs.environment
env:
DIGEST: ${{ steps.release_build.outputs.digest }}
TAGS: ${{ steps.cudaqdev_metadata.outputs.tags }}
run: cosign sign --yes --recursive "${TAGS}@${DIGEST}"
- name: Log in to NGC
if: needs.metadata.outputs.push_to_ngc == 'true'
uses: docker/login-action@v3
with:
registry: nvcr.io
username: '$oauthtoken'
password: ${{ secrets.NGC_CREDENTIALS }}
- name: Extract cuda-quantum metadata
id: cudaq_metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.prereqs.outputs.image_name }}
flavor: |
latest=false
suffix=${{ steps.prereqs.outputs.image_tag_suffix }},onlatest=true
tags: type=raw,value=${{ steps.prereqs.outputs.image_tag }}
labels: |
org.opencontainers.image.title=cuda-quantum
org.opencontainers.image.description=${{ steps.prereqs.outputs.image_description }}
- name: Configure credentials
if: needs.metadata.outputs.platform_tag == ''
run: |
docker run --privileged multiarch/qemu-user-static:latest --reset -p yes --credential yes
- name: Build cuda-quantum image
id: cudaq_build
if: success() && !cancelled()
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/release/cudaq.Dockerfile
build-args: |
cudaqdev_image=${{ steps.prereqs.outputs.dev_image_name }}@${{ steps.release_build.outputs.digest }}
base_image=${{ steps.prereqs.outputs.base_image }}
release_version=${{ steps.prereqs.outputs.image_tag }}
deprecation_notice=${{ steps.prereqs.outputs.deprecation_notice }}
tags: ${{ steps.cudaq_metadata.outputs.tags }}
labels: ${{ steps.cudaq_metadata.outputs.labels }}
platforms: ${{ inputs.platforms }}
provenance: false
push: ${{ inputs.environment != '' }}
outputs: ${{ steps.prereqs.outputs.docker_output }}
- name: Extract cuda-quantum-src metadata
id: cudaq_src_metadata
if: success() && !cancelled() && inputs.environment != ''
uses: docker/metadata-action@v5
with:
images: ${{ replace(steps.prereqs.outputs.image_name, 'cuda-quantum', 'cuda-quantum-src') }}
flavor: |
latest=false
suffix=${{ steps.prereqs.outputs.image_tag_suffix }},onlatest=true
tags: type=raw,value=${{ steps.prereqs.outputs.image_tag }}
labels: |
org.opencontainers.image.title=cuda-quantum-src
org.opencontainers.image.description=CUDA Quantum base image with third-party library (tpls) source
- name: Build cuda-quantum-src image
id: cudaq_src_build
if: success() && !cancelled() && inputs.environment != ''
uses: docker/build-push-action@v5
with:
context: .
file: ./docker/release/cudaq-src.Dockerfile
build-args: |
base_image=${{ steps.prereqs.outputs.image_name }}@${{ steps.cudaq_build.outputs.digest }}
tags: ${{ steps.cudaq_src_metadata.outputs.tags }}
labels: ${{ steps.cudaq_src_metadata.outputs.labels }}
platforms: ${{ inputs.platforms }}
provenance: false
push: true
- name: Write matrix outputs
uses: cloudposse/github-action-matrix-outputs-write@1.0.0
with:
matrix-step-name: docker_images
matrix-key: ${{ needs.metadata.outputs.platform_tag }}-cu${{ inputs.cuda_version }}-image
outputs: |
digest: ${{ steps.cudaq_build.outputs.digest }}
image_tag: ${{ steps.cudaq_metadata.outputs.tags }}
- name: Cache cuda-quantum image
if: steps.prereqs.outputs.tar_cache && steps.prereqs.outputs.tar_archive
uses: actions/cache/save@v4
with:
path: ${{ steps.prereqs.outputs.tar_archive }}
key: ${{ steps.prereqs.outputs.tar_cache }}
- name: Sign image with GitHub OIDC Token
if: inputs.environment && needs.metadata.outputs.push_to_ngc != 'true'
env:
DIGEST: ${{ steps.cudaq_build.outputs.digest }}
TAGS: ${{ steps.cudaq_metadata.outputs.tags }}
run: cosign sign --yes --recursive "${TAGS}@${DIGEST}"
- name: Install NGC CLI
if: inputs.environment && needs.metadata.outputs.push_to_ngc == 'true'
uses: ./.github/actions/install-ngc-cli
with:
version: 3.31.0
checksum: b715e503e2c0b44814a51f330eafd605f5d240ea0987bf615700d359c993f138
- name: Sign image with NGC CLI
if: inputs.environment && needs.metadata.outputs.push_to_ngc == 'true'
env:
TAGS: ${{ steps.cudaq_metadata.outputs.tags }}
NGC_CLI_API_KEY: ${{ secrets.NGC_CREDENTIALS }}
NGC_CLI_ORG: ${{ github.repository_owner }}
NGC_CLI_TEAM: 'nightly'
run: |
echo "Signing ${TAGS}"
ngc-cli/ngc registry image publish --source ${TAGS} ${TAGS} --sign
- name: Sign cuda-quantum-src image with NGC CLI
if: steps.cudaq_src_build.outcome == 'success' && needs.metadata.outputs.push_to_ngc == 'true'
env:
TAGS: ${{ steps.cudaq_src_metadata.outputs.tags }}
NGC_CLI_API_KEY: ${{ secrets.NGC_CREDENTIALS }}
NGC_CLI_ORG: ${{ github.repository_owner }}
NGC_CLI_TEAM: 'nightly'
run: |
echo "Signing cuda-quantum-src ${TAGS}"
ngc-cli/ngc registry image publish --source ${TAGS} ${TAGS} --sign
documentation:
name: Documentation
needs: [metadata, cudaqdev_image, cudaq_image]
# Unfortunately, we basically inherit this from the cudaq_image job;
# all jobs that depend on it will need to add the same condition.
if: always() && !cancelled() && needs.metadata.outputs.build_docs == 'true' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
runs-on: ${{ needs.metadata.outputs.runner }}
permissions:
contents: read
packages: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Log in to GitHub CR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Log in to the container registry
if: inputs.environment && vars.registry
uses: docker/login-action@v3
with:
registry: ${{ vars.registry }}
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Restore CUDA Quantum build
id: restore_cudaqdev
if: needs.cudaqdev_image.outputs.tar_cache && needs.cudaqdev_image.outputs.tar_archive
uses: actions/cache/restore@v4
with:
path: ${{ needs.cudaqdev_image.outputs.tar_archive }}
key: ${{ needs.cudaqdev_image.outputs.tar_cache }}
fail-on-cache-miss: true
- name: Restore CUDA Quantum image
id: restore_cudaq
if: needs.cudaq_image.outputs.tar_cache && needs.cudaq_image.outputs.tar_archive
uses: actions/cache/restore@v4
with:
path: ${{ needs.cudaq_image.outputs.tar_archive }}
key: ${{ needs.cudaq_image.outputs.tar_cache }}
fail-on-cache-miss: true
- name: Build documentation
id: docs_build
run: |
if ${{ steps.restore_cudaq.outcome != 'skipped' }}; then
load_output=`docker load --input "${{ needs.cudaq_image.outputs.tar_archive }}"`
cudaq_image=`echo "$load_output" | grep -o 'Loaded image: \S*:\S*' | head -1 | cut -d ' ' -f 3`
else
cudaq_image=${{ needs.cudaq_image.outputs.image_hash }}
docker pull $cudaq_image
fi
image_tag=`docker inspect $cudaq_image --format='{{json .Config.Labels}}' | jq -r '."org.opencontainers.image.version"' | sed -E 's/^(arm64-|amd64-)//'`
docs_version="CUDA_QUANTUM_VERSION=$(echo $image_tag | sed -re 's/^(cu[0-9]+-)?(.*)-base$/\2/')"
docker image rm $cudaq_image
docker image prune --force
if ${{ steps.restore_cudaqdev.outcome != 'skipped' }}; then
load_output=`docker load --input "${{ needs.cudaqdev_image.outputs.tar_archive }}"`
cudaqdev_image=`echo "$load_output" | grep -o 'Loaded image: \S*:\S*' | head -1 | cut -d ' ' -f 3`
else
cudaqdev_image=${{ needs.cudaqdev_image.outputs.image_hash }}
docker pull $cudaqdev_image
fi
docker run --rm -dit --network host --name cuda-quantum-dev $cudaqdev_image
(docker exec cuda-quantum-dev bash -c "export $docs_version && bash scripts/build_docs.sh" && built=true) || built=false
if $built; then docker cp cuda-quantum-dev:"/usr/local/cudaq/docs/." docs; \
else docker cp cuda-quantum-dev:"/workspaces/cuda-quantum/build/." /tmp/build; fi
docker stop cuda-quantum-dev
if $built; then `exit 0`; else `exit 1`; fi
html_files=`find docs/api/ -type f -name "*.html"`
json="{\"html_files\":[]}"
for file in $html_files; do
file=\'$file\'
json=`echo $json | jq ".html_files |= . + [\"$file\"]"`
done
echo "json=$(echo $json)" >> $GITHUB_OUTPUT
- name: Upload build artifacts
if: failure()
uses: actions/upload-artifact@v4
with:
name: build
path: /tmp/build
retention-days: 1
- name: Upload documentation
if: success()
uses: actions/upload-artifact@v4
with:
name: cuda_quantum_docs # changing the artifact name requires updating other workflows
path: docs
retention-days: 30
if-no-files-found: error
- name: Spell check HTML documentation
if: success()
continue-on-error: true # to be removed once we update all docs for this check to pass
uses: rojopolis/spellcheck-github-actions@0.30.0
with:
config_path: '.github/pre-commit/spellcheck_config.yml'
task_name: html
source_files: ${{ join(fromJSON(steps.docs_build.outputs.json).html_files, ' ') }}
validation:
name: Validation
needs: [metadata, cudaq_image]
# Unfortunately, we basically inherit this from the cudaq_image job;
# all jobs that depend on it will need to add the same condition.
if: always() && !cancelled() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
runs-on: ${{ needs.metadata.outputs.runner }}
permissions:
contents: read
packages: read
outputs:
artifact_id: "${{ steps.job_summary.outputs.artifact_id }}"
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Log in to GitHub CR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Log in to the container registry
if: inputs.environment && vars.registry
uses: docker/login-action@v3
with:
registry: ${{ vars.registry }}
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Load cuda-quantum image
id: restore
if: needs.cudaq_image.outputs.tar_cache && needs.cudaq_image.outputs.tar_archive
uses: actions/cache/restore@v4
with:
path: ${{ needs.cudaq_image.outputs.tar_archive }}
key: ${{ needs.cudaq_image.outputs.tar_cache }}
fail-on-cache-miss: true
- name: Validate cuda-quantum image
run: |
if ${{ steps.restore.outcome != 'skipped' }}; then
load_output=`docker load --input "${{ needs.cudaq_image.outputs.tar_archive }}"`
cudaq_image=`echo "$load_output" | grep -o 'Loaded image: \S*:\S*' | head -1 | cut -d ' ' -f 3`
else
cudaq_image=${{ needs.cudaq_image.outputs.image_hash }}
docker pull $cudaq_image
fi
docker run --rm -dit --name cuda-quantum $cudaq_image
docker cp scripts/validate_installation.sh cuda-quantum:"/home/cudaq/validate_installation.sh"
docker cp docs/notebook_validation.py cuda-quantum:"/home/cudaq/notebook_validation.py"
# In containers without GPU support, UCX does not work properly since it is configured to work with GPU-support.
# Hence, don't enforce UCX when running these tests.
docker exec cuda-quantum bash -c "python3 -m pip install --break-system-packages pandas scipy seaborn h5py contfrac"
docker exec cuda-quantum bash -c "sudo apt install -y python3-venv"
(docker exec cuda-quantum bash -c "unset OMPI_MCA_pml && set -o pipefail && bash validate_installation.sh | tee /tmp/validation.out") && passed=true || passed=false
docker cp cuda-quantum:"/tmp/validation.out" /tmp/validation.out
docker stop cuda-quantum
if ! $passed; then
echo "::error::Validation failed; see job summary for more details."
exit 1
elif ${{ inputs.ompidev_image != '' }} && [ "$(cat /tmp/validation.out | grep '^nvidia$')" != "nvidia" ]; then
echo "Missing installation for nvidia backend."
exit 1
fi
- name: Create job summary
id: job_summary
if: always() && !cancelled()
run: |
cuda_major=`echo ${{ inputs.cuda_version }} | cut -d . -f1`
platform_id=${{ needs.metadata.outputs.platform_tag }}
artifact_id=image${platform_id:+_$platform_id}${cuda_major:+_cu$cuda_major} # changing the artifact name requires updating other workflows
echo "artifact_id=$artifact_id" >> $GITHUB_OUTPUT
if [ -f /tmp/validation.out ]; then
summary=/tmp/summary.txt
echo "## Validation" > $summary
echo "The validation of the cuda-quantum image produced the following output:" >> $summary
echo '```text' >> $summary
cat /tmp/validation.out >> $summary
echo '```' >> $summary
echo "validation_summary=$summary" >> $GITHUB_OUTPUT
fi
- name: Upload job summary
if: steps.job_summary.outputs.validation_summary != ''
uses: actions/upload-artifact@v4
with:
name: ${{ steps.job_summary.outputs.artifact_id }}_validation
path: ${{ steps.job_summary.outputs.validation_summary }}
retention-days: 1
if-no-files-found: warn
staging:
name: Staging
needs: [metadata, cudaqdev_image, cudaq_image, validation]
# Unfortunately, we basically inherit this from the cudaq_image job;
# all jobs that depend on it will need to add the same condition.
if: always() && !cancelled() && inputs.environment && needs.metadata.outputs.platform_tag == '' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled')
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
persist-credentials: false
- name: Create build info
id: staging
run: |
cudaqdev_hash=${{ needs.cudaqdev_image.outputs.image_hash }}
cudaq_hash=${{ needs.cudaq_image.outputs.image_hash }}
artifact_name=${{ needs.validation.outputs.artifact_id }}_publishing # changing the artifact name requires updating other workflows
echo "artifact_name=$artifact_name" >> $GITHUB_OUTPUT
info_file="$artifact_name.txt"
echo "info_file=$info_file" >> $GITHUB_OUTPUT
mkdir -p "$(dirname "$info_file")" && rm -rf "$info_file"
echo "source-sha: ${{ github.sha }}" >> "$info_file"
echo "cuda-quantum-image: $cudaq_hash" >> "$info_file"
echo "cuda-quantum-dev-image: $cudaqdev_hash" >> "$info_file"
echo "cuda-quantum-devdeps-image: ${{ inputs.devdeps_image }}" >> "$info_file"
echo "platforms: ${{ inputs.platforms }}" >> "$info_file"
echo "cuda-version: ${{ inputs.cuda_version }}" >> "$info_file"
cat .github/workflows/config/gitlab_commits.txt >> "$info_file"
- name: Upload build info
uses: actions/upload-artifact@v4
with:
name: ${{ steps.staging.outputs.artifact_name }} # changing the artifact name requires updating other workflows
path: ${{ steps.staging.outputs.info_file }}
retention-days: 30
if-no-files-found: error
clean_up:
name: Prepare cache clean-up
needs: [metadata, cudaqdev_image, cudaq_image, ompi_image, documentation, validation]
# We need to clean up even if the workflow is cancelled or fails.
if: always()
runs-on: ubuntu-latest
steps:
- name: Save cache keys
id: workflow_inputs
run: |
keys=${{ needs.cudaqdev_image.outputs.tar_cache }}
keys+=" ${{ needs.cudaq_image.outputs.tar_cache }}"
keys+=" ${{ needs.ompi_image.outputs.tar_cache }}"
echo "$keys" >> cache_keys.txt
echo "artifact_name=${{ needs.validation.outputs.artifact_id }}_cache_keys" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
with:
name: ${{ steps.workflow_inputs.outputs.artifact_name }}
path: cache_keys.txt
retention-days: 1
if-no-files-found: error