Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions .github/actions/build-bioconda-utils-container/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Build bioconda-utils container
description: Build and test the multi-architecture bioconda-utils build environment.

inputs:
tags:
description: Whitespace-separated tags to apply to the local manifest.
required: true

outputs:
image:
description: Local multi-architecture manifest name.
value: ${{ steps.metadata.outputs.image }}
tags:
description: Whitespace-separated tags applied to the local manifest.
value: ${{ steps.metadata.outputs.tags }}

runs:
using: composite
steps:
- name: Prepare metadata
id: metadata
shell: bash
env:
TAGS: ${{ inputs.tags }}
run: |
set -euo pipefail

tags="$( xargs <<< "${TAGS}" )"
test -n "${tags}"
printf '%s\n' \
'image=bioconda-utils-build-env-cos7' \
"tags=${tags}" \
>> "${GITHUB_OUTPUT}"

- name: Set up QEMU
shell: bash
run: |
set -euo pipefail
podman run --rm --privileged \
docker.io/tonistiigi/binfmt --install arm64

- name: Install tools
shell: bash
run: |
set -euo pipefail
# jq is not installed in travier/podman-action.
dnf install -qy jq

- name: Build amd64 image
uses: redhat-actions/buildah-build@v3
with:
image: bioconda-utils-build-env-cos7-amd64
arch: amd64
build-args: |
BASE_IMAGE=quay.io/condaforge/linux-anvil-cos7-x86_64
tags: ${{ steps.metadata.outputs.tags }}
containerfiles: ./Dockerfile

- name: Build arm64 image
uses: redhat-actions/buildah-build@v3
with:
image: bioconda-utils-build-env-cos7-arm64
arch: arm64
build-args: |
BASE_IMAGE=quay.io/condaforge/linux-anvil-aarch64
tags: ${{ steps.metadata.outputs.tags }}
containerfiles: ./Dockerfile

- name: Assemble multi-architecture manifest
shell: bash
env:
IMAGE: ${{ steps.metadata.outputs.image }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: |
set -euo pipefail

read -r -a tags <<< "${TAGS}"
for tag in "${tags[@]}" ; do
buildah manifest create "${IMAGE}:${tag}"
buildah manifest add \
"${IMAGE}:${tag}" \
"${IMAGE}-amd64:${tag}"
buildah manifest add \
"${IMAGE}:${tag}" \
"${IMAGE}-arm64:${tag}"
done

- name: Test
shell: bash
env:
LOCAL_IMAGE: ${{ steps.metadata.outputs.image }}
LOCAL_TAGS: ${{ steps.metadata.outputs.tags }}
run: |
set -euo pipefail

read -r -a tags <<< "${LOCAL_TAGS}"
for tag in "${tags[@]}" ; do
for architecture in amd64 arm64 ; do
podman run --rm --pull=never \
--arch="${architecture}" \
"${LOCAL_IMAGE}:${tag}" \
bioconda-utils --version
done
done

.github/scripts/test-local-container Dockerfile.test .
129 changes: 129 additions & 0 deletions .github/actions/publish-container/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
name: Publish container
description: Protect immutable tags, push a local image, and verify the remote platforms.

inputs:
image:
description: Local image or manifest name.
required: true
tags:
description: Whitespace-separated tags to publish.
required: true
mutable-tags:
description: Whitespace-separated tags that may be overwritten.
required: false
default: ''
registry:
description: Registry hostname and namespace.
required: true
username:
description: Registry username.
required: true
password:
description: Registry password or token.
required: true

outputs:
test-image:
description: Immutable remote manifest reference to use for functional tests.
value: ${{ steps.verify.outputs.test-image }}

runs:
using: composite
steps:
- name: Check immutable tags
shell: bash
env:
IMAGE: ${{ inputs.image }}
MUTABLE_TAGS: ${{ inputs.mutable-tags }}
REGISTRY: ${{ inputs.registry }}
TAGS: ${{ inputs.tags }}
run: |
set -euo pipefail

existing_tags="$(
skopeo list-tags "docker://${REGISTRY}/${IMAGE}" \
| jq -r '.Tags[]'
)" \
|| {
echo 'Could not list tags via skopeo.'
exit 1
}

for tag in ${TAGS} ; do
case " ${MUTABLE_TAGS} " in
*" ${tag} "* ) continue ;;
esac
if printf '%s\n' "${existing_tags}" | grep -qxF "${tag}" ; then
printf 'Tag %s already exists!\n' "${tag}"
exit 1
fi
done

- name: Push
id: push
uses: redhat-actions/push-to-registry@v3
with:
image: ${{ inputs.image }}
tags: ${{ inputs.tags }}
registry: ${{ inputs.registry }}
username: ${{ inputs.username }}
password: ${{ inputs.password }}

- name: Verify remote architectures
id: verify
shell: bash
env:
REGISTRY_PATHS: ${{ steps.push.outputs.registry-paths }}
run: |
set -euo pipefail

jq -e 'type == "array" and length > 0' > /dev/null \
<<< "${REGISTRY_PATHS}"
expected='amd64 arm64'
expected_digest=''
expected_repository=''

while read -r image ; do
raw_manifest="$( skopeo inspect --raw "docker://${image}" )"
if jq -e 'has("manifests")' > /dev/null <<< "${raw_manifest}" ; then
actual="$(
jq -r \
'.manifests[] | select(.platform.os == "linux") | .platform.architecture' \
<<< "${raw_manifest}" \
| sort -u \
| xargs
)"
else
actual="$(
skopeo inspect "docker://${image}" \
| jq -r '.Architecture'
)"
fi

if [[ "${actual}" != "${expected}" ]] ; then
printf 'Unexpected architectures for %s: expected "%s", found "%s".\n' \
"${image}" "${expected}" "${actual}"
exit 1
fi
printf 'Verified remote architectures for %s: %s\n' "${image}" "${actual}"

repository="${image%:*}"
digest="$(
skopeo inspect \
--format '{{.Digest}}' \
"docker://${image}"
)"
if [[ -z "${expected_digest}" ]] ; then
expected_digest="${digest}"
expected_repository="${repository}"
elif [[ "${repository}" != "${expected_repository}" \
|| "${digest}" != "${expected_digest}" ]] ; then
printf 'Pushed tag %s does not reference %s@%s.\n' \
"${image}" "${expected_repository}" "${expected_digest}"
exit 1
fi
done < <( jq -er '.[]' <<< "${REGISTRY_PATHS}" )

printf 'test-image=%s@%s\n' \
"${expected_repository}" "${expected_digest}" \
>> "${GITHUB_OUTPUT}"
54 changes: 54 additions & 0 deletions .github/scripts/test-local-container
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env bash

# Functionally test both architectures of a local multi-architecture manifest.

set -euo pipefail

cleanup() {
buildah rmi --prune || true
}
trap cleanup EXIT

if [[ "$#" -ne 2 ]]; then
echo 'Usage: test-local-container TEST_CONTAINERFILE CONTEXT' >&2
exit 2
fi
: "${LOCAL_IMAGE:?Set LOCAL_IMAGE to the local manifest name.}"
: "${LOCAL_TAGS:?Set LOCAL_TAGS to its whitespace-separated tags.}"

test_containerfile="$1"
context="$2"
test -f "${test_containerfile}"
test -d "${context}"

tags="$(xargs <<<"${LOCAL_TAGS}")"
read -r -a tag_list <<<"${tags}"
test "${#tag_list[@]}" -gt 0

for tag in "${tag_list[@]}"; do
actual="$(
buildah manifest inspect "${LOCAL_IMAGE}:${tag}" |
jq -r \
'.manifests[] | select(.platform.os == "linux") | .platform.architecture' |
sort -u |
xargs
)"
if [[ "${actual}" != 'amd64 arm64' ]]; then
printf 'Unexpected architectures for %s:%s: expected "amd64 arm64", found "%s".\n' \
"${LOCAL_IMAGE}" "${tag}" "${actual}" >&2
exit 1
fi
done

base="${LOCAL_IMAGE}:${tag_list[0]}"
for architecture in amd64 arm64; do
printf 'Testing local %s image %s\n' "${architecture}" "${base}"
# The manifest under test is known to exist locally, but the test
# Containerfile may use additional base images in later stages.
buildah build \
--pull=missing \
--arch="${architecture}" \
--build-arg=base="${base}" \
--file="${test_containerfile}" \
"${context}"
done
29 changes: 29 additions & 0 deletions .github/scripts/test-pushed-container
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash

# Functionally test both architectures of an immutable remote manifest.

set -euo pipefail

cleanup() {
buildah rmi --prune || true
}
trap cleanup EXIT

if [[ "$#" -ne 2 ]]; then
echo 'Usage: test-pushed-container TEST_CONTAINERFILE CONTEXT' >&2
exit 2
fi
: "${TEST_IMAGE:?Set TEST_IMAGE to the publish action test-image output.}"

test_containerfile="$1"
context="$2"

for architecture in amd64 arm64; do
printf 'Testing pushed %s image %s\n' "${architecture}" "${TEST_IMAGE}"
buildah build \
--pull=always \
--arch="${architecture}" \
--build-arg=base="${TEST_IMAGE}" \
--file="${test_containerfile}" \
"${context}"
done
8 changes: 4 additions & 4 deletions .github/workflows/GithubActionTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
qc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- uses: astral-sh/ruff-action@v4.0.0
name: ruff check
- uses: astral-sh/ruff-action@v4.0.0
Expand Down Expand Up @@ -37,7 +37,7 @@ jobs:
- long_running_2

steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0

Expand Down Expand Up @@ -71,7 +71,7 @@ jobs:
name: OSX tests
runs-on: macos-15-intel
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0

Expand Down Expand Up @@ -99,7 +99,7 @@ jobs:
name: autobump test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7

- uses: prefix-dev/setup-pixi@v0
with:
Expand Down
Loading
Loading