Skip to content

Clean up sidecar index files (.tbi, .bai) in refine_assembly #285

Clean up sidecar index files (.tbi, .bai) in refine_assembly

Clean up sidecar index files (.tbi, .bai) in refine_assembly #285

Workflow file for this run

name: Build and Test
on:
push:
branches:
- main
- '**'
tags:
- '**'
pull_request:
branches:
- main
env:
QUAY_REPO: quay.io/broadinstitute/viral-ngs
GHCR_REPO: ghcr.io/broadinstitute/viral-ngs
jobs:
# Determine which paths changed to enable smart test filtering
paths-filter:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
core: ${{ steps.filter.outputs.core }}
assemble: ${{ steps.filter.outputs.assemble }}
classify: ${{ steps.filter.outputs.classify }}
phylo: ${{ steps.filter.outputs.phylo }}
docker: ${{ steps.filter.outputs.docker }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check changed paths
uses: dorny/paths-filter@v3
id: filter
with:
filters: |
core:
- 'src/viral_ngs/*.py'
- 'src/viral_ngs/core/**'
- 'src/viral_ngs/util/**'
- 'tests/unit/core/**'
- 'tests/conftest.py'
- 'docker/requirements/core.txt'
- 'docker/requirements/core-x86.txt'
- 'docker/requirements/baseimage.txt'
- 'docker/Dockerfile.core'
- 'docker/Dockerfile.baseimage'
- 'pyproject.toml'
assemble:
- 'src/viral_ngs/assemble/**'
- 'src/viral_ngs/assembly.py'
- 'tests/unit/assemble/**'
- 'docker/requirements/assemble.txt'
- 'docker/Dockerfile.assemble'
classify:
- 'src/viral_ngs/classify/**'
- 'src/viral_ngs/metagenomics.py'
- 'src/viral_ngs/taxon_filter.py'
- 'src/viral_ngs/kmer_utils.py'
- 'tests/unit/classify/**'
- 'docker/requirements/classify.txt'
- 'docker/Dockerfile.classify'
phylo:
- 'src/viral_ngs/phylo/**'
- 'src/viral_ngs/interhost.py'
- 'src/viral_ngs/intrahost.py'
- 'src/viral_ngs/ncbi.py'
- 'tests/unit/phylo/**'
- 'docker/requirements/phylo.txt'
- 'docker/requirements/phylo-x86.txt'
- 'docker/Dockerfile.phylo'
docker:
- 'docker/**'
- '.github/workflows/docker.yml'
# Calculate version from git describe (once, shared by all jobs)
get-version:
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.version.outputs.version }}
image-tag-prefix: ${{ steps.image-tag.outputs.prefix }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for accurate git describe
fetch-tags: true
- name: Get version from git describe
id: version
run: |
# Get version like: v1.25.0, 3.0.0, or v1.25.0-42-gabcdef
# Match version tags with or without 'v' prefix, excluding archive/* tags
RAW_VERSION=$(git describe --tags --always --match 'v*' --match '[0-9]*')
# Strip leading 'v' if present
RAW_VERSION=${RAW_VERSION#v}
# Convert to PEP 440 format for setuptools_scm
# git describe: 1.25.0-42-gabcdef -> PEP 440: 1.25.0.dev42+gabcdef
if [[ "$RAW_VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-([0-9]+)-g([a-f0-9]+)$ ]]; then
VERSION="${BASH_REMATCH[1]}.dev${BASH_REMATCH[2]}+g${BASH_REMATCH[3]}"
else
# Clean version tag (e.g., 1.25.0)
VERSION="$RAW_VERSION"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Detected version: ${VERSION}"
- name: Compute Docker image tag prefix
id: image-tag
run: |
# For PRs, github.ref_name is "1020/merge" which contains "/" - invalid in Docker tags
# Convert to a valid tag prefix: "pr-1020" for PRs, sanitized branch name for branches
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
# Extract PR number from github.ref (refs/pull/1020/merge -> 1020)
PR_NUMBER="${{ github.event.pull_request.number }}"
PREFIX="pr-${PR_NUMBER}"
else
# For branches/tags, replace "/" with "-" to create valid Docker tags
PREFIX=$(echo "${{ github.ref_name }}" | sed 's|/|-|g')
# Strip leading 'v' for version tags (e.g., v3.0.1 -> 3.0.1)
PREFIX=${PREFIX#v}
fi
echo "prefix=${PREFIX}" >> $GITHUB_OUTPUT
echo "Image tag prefix: ${PREFIX}"
# ============================================================================
# BASEIMAGE BUILD JOBS - Native multi-arch builds (no QEMU)
# AMD64 and ARM64 build in parallel on native runners, then combined
# ============================================================================
# Build baseimage for AMD64
build-baseimage-amd64:
needs: get-version
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.baseimage
platforms: linux/amd64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-amd64
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-amd64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-amd64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Build baseimage for ARM64 (native runner)
build-baseimage-arm64:
needs: get-version
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.baseimage
platforms: linux/arm64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-arm64
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-arm64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-arm64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Create multi-arch manifest for baseimage
create-manifest-baseimage:
needs: [get-version, build-baseimage-amd64, build-baseimage-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
baseimage-tag: ${{ steps.get-tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Get baseimage tag
id: get-tag
run: echo "tag=${{ needs.get-version.outputs.image-tag-prefix }}-baseimage" >> $GITHUB_OUTPUT
- name: Create multi-arch manifest
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: ${{ steps.get-tag.outputs.tag }}
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-arm64
description: 'Viral genomics analysis tools - base image'
- name: Create additional tags for main branch
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: baseimage
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-arm64
description: 'Viral genomics analysis tools - base image'
- name: Create version tags
if: github.ref_type == 'tag'
run: |
VERSION="${{ needs.get-version.outputs.image-tag-prefix }}"
MAJOR_MINOR=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
# Create version tag
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${VERSION}-baseimage \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-arm64
# Create major.minor tag
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${MAJOR_MINOR}-baseimage \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-arm64
# ============================================================================
# CORE BUILD JOBS - Native multi-arch builds
# ============================================================================
# Build core for AMD64 (depends on baseimage-amd64, not manifest)
build-core-amd64:
needs: [get-version, build-baseimage-amd64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.core
platforms: linux/amd64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-amd64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-amd64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Build core for ARM64 (depends on baseimage-arm64, not manifest)
build-core-arm64:
needs: [get-version, build-baseimage-arm64]
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.core
platforms: linux/arm64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-baseimage-arm64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-baseimage-arm64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Create multi-arch manifest for core
create-manifest-core:
needs: [get-version, build-core-amd64, build-core-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
core-tag: ${{ steps.get-tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Get core tag
id: get-tag
run: echo "tag=${{ needs.get-version.outputs.image-tag-prefix }}-core" >> $GITHUB_OUTPUT
- name: Create multi-arch manifest
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: ${{ steps.get-tag.outputs.tag }}
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
description: 'Viral genomics analysis tools - core utilities'
- name: Create additional tags for main branch
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: core
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
description: 'Viral genomics analysis tools - core utilities'
- name: Create version tags
if: github.ref_type == 'tag'
run: |
VERSION="${{ needs.get-version.outputs.image-tag-prefix }}"
MAJOR_MINOR=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${VERSION}-core \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${MAJOR_MINOR}-core \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
# ============================================================================
# ASSEMBLE BUILD JOBS - Native multi-arch builds
# ============================================================================
# Build assemble for AMD64
build-assemble-amd64:
needs: [get-version, build-core-amd64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.assemble
platforms: linux/amd64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-assemble-amd64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-assemble-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-assemble-amd64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-assemble-amd64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Build assemble for ARM64
build-assemble-arm64:
needs: [get-version, build-core-arm64]
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.assemble
platforms: linux/arm64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-assemble-arm64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-assemble-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-assemble-arm64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-assemble-arm64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Create multi-arch manifest for assemble
create-manifest-assemble:
needs: [get-version, build-assemble-amd64, build-assemble-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
assemble-tag: ${{ steps.get-tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Get assemble tag
id: get-tag
run: echo "tag=${{ needs.get-version.outputs.image-tag-prefix }}-assemble" >> $GITHUB_OUTPUT
- name: Create multi-arch manifest
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: ${{ steps.get-tag.outputs.tag }}
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-assemble-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-assemble-arm64
description: 'Viral genomics analysis tools - assembly'
- name: Create additional tags for main branch
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: assemble
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-assemble-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-assemble-arm64
description: 'Viral genomics analysis tools - assembly'
- name: Create version tags
if: github.ref_type == 'tag'
run: |
VERSION="${{ needs.get-version.outputs.image-tag-prefix }}"
MAJOR_MINOR=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${VERSION}-assemble \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-assemble-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-assemble-arm64
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${MAJOR_MINOR}-assemble \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-assemble-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-assemble-arm64
# ============================================================================
# CLASSIFY BUILD JOBS - Native multi-arch builds
# ============================================================================
# Build classify for AMD64
build-classify-amd64:
needs: [get-version, build-core-amd64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.classify
platforms: linux/amd64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-classify-amd64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-classify-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-classify-amd64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-classify-amd64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Build classify for ARM64
build-classify-arm64:
needs: [get-version, build-core-arm64]
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.classify
platforms: linux/arm64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-classify-arm64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-classify-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-classify-arm64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-classify-arm64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Create multi-arch manifest for classify
create-manifest-classify:
needs: [get-version, build-classify-amd64, build-classify-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
classify-tag: ${{ steps.get-tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Get classify tag
id: get-tag
run: echo "tag=${{ needs.get-version.outputs.image-tag-prefix }}-classify" >> $GITHUB_OUTPUT
- name: Create multi-arch manifest
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: ${{ steps.get-tag.outputs.tag }}
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-classify-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-classify-arm64
description: 'Viral genomics analysis tools - metagenomic classification'
- name: Create additional tags for main branch
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: classify
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-classify-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-classify-arm64
description: 'Viral genomics analysis tools - metagenomic classification'
- name: Create version tags
if: github.ref_type == 'tag'
run: |
VERSION="${{ needs.get-version.outputs.image-tag-prefix }}"
MAJOR_MINOR=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${VERSION}-classify \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-classify-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-classify-arm64
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${MAJOR_MINOR}-classify \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-classify-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-classify-arm64
# ============================================================================
# PHYLO BUILD JOBS - Native multi-arch builds
# ============================================================================
# Build phylo for AMD64
build-phylo-amd64:
needs: [get-version, build-core-amd64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.phylo
platforms: linux/amd64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-phylo-amd64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-phylo-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-phylo-amd64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-phylo-amd64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Build phylo for ARM64
build-phylo-arm64:
needs: [get-version, build-core-arm64]
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.phylo
platforms: linux/arm64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-phylo-arm64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-phylo-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-phylo-arm64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-phylo-arm64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Create multi-arch manifest for phylo
create-manifest-phylo:
needs: [get-version, build-phylo-amd64, build-phylo-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
phylo-tag: ${{ steps.get-tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Get phylo tag
id: get-tag
run: echo "tag=${{ needs.get-version.outputs.image-tag-prefix }}-phylo" >> $GITHUB_OUTPUT
- name: Create multi-arch manifest
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: ${{ steps.get-tag.outputs.tag }}
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-phylo-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-phylo-arm64
description: 'Viral genomics analysis tools - phylogenetics'
- name: Create additional tags for main branch
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: phylo
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-phylo-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-phylo-arm64
description: 'Viral genomics analysis tools - phylogenetics'
- name: Create version tags
if: github.ref_type == 'tag'
run: |
VERSION="${{ needs.get-version.outputs.image-tag-prefix }}"
MAJOR_MINOR=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${VERSION}-phylo \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-phylo-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-phylo-arm64
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${MAJOR_MINOR}-phylo \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-phylo-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-phylo-arm64
# ============================================================================
# MEGA BUILD JOBS - Native multi-arch builds (all tools combined)
# ============================================================================
# Build mega for AMD64
build-mega-amd64:
needs: [get-version, build-core-amd64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (amd64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.mega
platforms: linux/amd64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-mega-amd64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-amd64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-mega-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-mega-amd64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-amd64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-mega-amd64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Build mega for ARM64
build-mega-arm64:
needs: [get-version, build-core-arm64]
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Build and push (arm64)
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.mega
platforms: linux/arm64
provenance: false
sbom: false
outputs: type=image,push=true,oci-mediatypes=false
tags: ${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-mega-arm64
build-args: |
BASEIMAGE=${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-core-arm64
VERSION=${{ needs.get-version.outputs.version }}
cache-from: |
type=registry,ref=${{ env.GHCR_REPO }}:cache-mega-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-mega-arm64-main
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-${{ needs.get-version.outputs.image-tag-prefix }}
type=registry,ref=${{ env.GHCR_REPO }}:cache-core-arm64-main
cache-to: type=registry,ref=${{ env.GHCR_REPO }}:cache-mega-arm64-${{ needs.get-version.outputs.image-tag-prefix }},mode=max
# Create multi-arch manifest for mega
create-manifest-mega:
needs: [get-version, build-mega-amd64, build-mega-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Docker build environment
uses: ./.github/actions/setup-docker-build
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
checkout: 'false'
- name: Create multi-arch manifest
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: ${{ needs.get-version.outputs.image-tag-prefix }}
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-mega-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-mega-arm64
description: 'Viral genomics analysis tools - all tools combined'
- name: Create additional tags for main branch
if: github.ref == 'refs/heads/main'
uses: ./.github/actions/create-manifest
with:
ghcr-repo: ${{ env.GHCR_REPO }}
target-tag: latest
source-amd64: ${{ needs.get-version.outputs.image-tag-prefix }}-mega-amd64
source-arm64: ${{ needs.get-version.outputs.image-tag-prefix }}-mega-arm64
description: 'Viral genomics analysis tools - all tools combined'
- name: Create version tags
if: github.ref_type == 'tag'
run: |
VERSION="${{ needs.get-version.outputs.image-tag-prefix }}"
MAJOR_MINOR=$(echo "$VERSION" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${VERSION} \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-mega-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-mega-arm64
docker buildx imagetools create \
--tag ${{ env.GHCR_REPO }}:${MAJOR_MINOR} \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-mega-amd64 \
${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-mega-arm64
# ============================================================================
# VULNERABILITY SCAN JOBS - Trivy scans of amd64 images after build
# Scans all 6 flavors in parallel; results uploaded as SARIF to Security tab
# ============================================================================
scan-containers:
needs: [get-version, build-baseimage-amd64, build-core-amd64, build-assemble-amd64, build-classify-amd64, build-phylo-amd64, build-mega-amd64]
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
security-events: write
strategy:
fail-fast: false
matrix:
flavor: [baseimage, core, assemble, classify, phylo, mega]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: '${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-${{ matrix.flavor }}-amd64'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
limit-severities-for-sarif: true
exit-code: '0'
ignore-unfixed: true
trivyignores: '.trivyignore'
ignore-policy: '.trivy-ignore-policy.rego'
- name: Run Trivy vulnerability scanner (JSON)
uses: aquasecurity/trivy-action@master
with:
image-ref: '${{ env.GHCR_REPO }}:${{ needs.get-version.outputs.image-tag-prefix }}-${{ matrix.flavor }}-amd64'
format: 'json'
output: 'trivy-results.json'
severity: 'CRITICAL,HIGH'
exit-code: '1'
ignore-unfixed: true
trivyignores: '.trivyignore'
ignore-policy: '.trivy-ignore-policy.rego'
- name: Log scan result count
if: always()
run: |
if [ -f trivy-results.sarif ]; then
COUNT=$(jq '[.runs[].results[]] | length' trivy-results.sarif)
echo "::notice::Trivy found $COUNT findings for ${{ matrix.flavor }} (after policy filtering)"
fi
- name: Upload Trivy scan results to GitHub Security tab
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
category: 'container-${{ matrix.flavor }}'
- name: Upload Trivy JSON results
if: always()
uses: actions/upload-artifact@v4
with:
name: trivy-${{ matrix.flavor }}
path: trivy-results.json
# ============================================================================
# TEST JOBS - Run after corresponding manifests are created
# Each test runs in its flavor's Docker container (x86 only)
# ============================================================================
# Test core (x86)
test-core:
needs: [paths-filter, get-version, create-manifest-core]
if: |
github.event_name == 'pull_request' ||
github.ref == 'refs/heads/main' ||
github.ref_type == 'tag' ||
needs.paths-filter.outputs.core == 'true' ||
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-core.outputs.core-tag }}
- name: Run core tests
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-core.outputs.core-tag }} \
pytest tests/unit/core/ \
-v --tb=short \
--cov=viral_ngs \
--cov-report=xml:/workspace/coverage-core.xml \
-n auto
- name: Upload coverage to Codecov
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref_type == 'tag'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage-core.xml
flags: core
name: codecov-core
fail_ci_if_error: false
# Test core (ARM64) - only on PRs with docker changes
test-core-arm64:
needs: [paths-filter, get-version, create-manifest-core]
if: |
github.event_name == 'pull_request' &&
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-24.04-arm
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-core.outputs.core-tag }}
- name: Run core tests (ARM64)
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-core.outputs.core-tag }} \
pytest tests/unit/core/ \
-v --tb=short \
-n auto
# Test assemble (x86)
test-assemble:
needs: [paths-filter, get-version, create-manifest-assemble]
if: |
github.event_name == 'pull_request' ||
github.ref == 'refs/heads/main' ||
github.ref_type == 'tag' ||
needs.paths-filter.outputs.assemble == 'true' ||
needs.paths-filter.outputs.core == 'true' ||
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-assemble.outputs.assemble-tag }}
- name: Run assemble tests
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-assemble.outputs.assemble-tag }} \
pytest tests/unit/assemble/ \
-v --tb=short \
--cov=viral_ngs \
--cov-report=xml:/workspace/coverage-assemble.xml \
-n auto
- name: Upload coverage to Codecov
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref_type == 'tag'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage-assemble.xml
flags: assemble
name: codecov-assemble
fail_ci_if_error: false
# Test assemble (ARM64) - only on PRs with docker changes
test-assemble-arm64:
needs: [paths-filter, get-version, create-manifest-assemble]
if: |
github.event_name == 'pull_request' &&
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-24.04-arm
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-assemble.outputs.assemble-tag }}
- name: Run assemble tests (ARM64)
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-assemble.outputs.assemble-tag }} \
pytest tests/unit/assemble/ \
-v --tb=short \
-n auto
# Test classify (x86)
test-classify:
needs: [paths-filter, get-version, create-manifest-classify]
if: |
github.event_name == 'pull_request' ||
github.ref == 'refs/heads/main' ||
github.ref_type == 'tag' ||
needs.paths-filter.outputs.classify == 'true' ||
needs.paths-filter.outputs.core == 'true' ||
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-classify.outputs.classify-tag }}
- name: Run classify tests
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-classify.outputs.classify-tag }} \
pytest tests/unit/classify/ \
-v --tb=short \
--cov=viral_ngs \
--cov-report=xml:/workspace/coverage-classify.xml \
-n auto
- name: Upload coverage to Codecov
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref_type == 'tag'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage-classify.xml
flags: classify
name: codecov-classify
fail_ci_if_error: false
# Test classify (ARM64) - only on PRs with docker changes
test-classify-arm64:
needs: [paths-filter, get-version, create-manifest-classify]
if: |
github.event_name == 'pull_request' &&
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-24.04-arm
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-classify.outputs.classify-tag }}
- name: Run classify tests (ARM64)
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-classify.outputs.classify-tag }} \
pytest tests/unit/classify/ \
-v --tb=short \
-n auto
# Test phylo (x86)
test-phylo:
needs: [paths-filter, get-version, create-manifest-phylo]
if: |
github.event_name == 'pull_request' ||
github.ref == 'refs/heads/main' ||
github.ref_type == 'tag' ||
needs.paths-filter.outputs.phylo == 'true' ||
needs.paths-filter.outputs.core == 'true' ||
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-phylo.outputs.phylo-tag }}
- name: Run phylo tests
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-phylo.outputs.phylo-tag }} \
pytest tests/unit/phylo/ \
-v --tb=short \
--cov=viral_ngs \
--cov-report=xml:/workspace/coverage-phylo.xml \
-n auto
- name: Upload coverage to Codecov
if: github.event_name == 'pull_request' || github.ref == 'refs/heads/main' || github.ref_type == 'tag'
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage-phylo.xml
flags: phylo
name: codecov-phylo
fail_ci_if_error: false
# Test phylo (ARM64) - only on PRs with docker changes
test-phylo-arm64:
needs: [paths-filter, get-version, create-manifest-phylo]
if: |
github.event_name == 'pull_request' &&
needs.paths-filter.outputs.docker == 'true'
runs-on: ubuntu-24.04-arm
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Pull test image (with retries)
uses: ./.github/actions/pull-with-retry
with:
image: ${{ env.GHCR_REPO }}:${{ needs.create-manifest-phylo.outputs.phylo-tag }}
- name: Run phylo tests (ARM64)
run: |
docker run --rm \
-v ${{ github.workspace }}:/workspace \
-w /workspace \
${{ env.GHCR_REPO }}:${{ needs.create-manifest-phylo.outputs.phylo-tag }} \
pytest tests/unit/phylo/ \
-v --tb=short \
-n auto
# ============================================================================
# AGGREGATOR JOB - Single status check for branch protection
# This job always runs and reports combined test status, allowing conditional
# test jobs to be skipped without blocking PRs that don't need those tests.
# ============================================================================
all-tests-pass:
if: always()
needs:
- test-core
- test-core-arm64
- test-assemble
- test-assemble-arm64
- test-classify
- test-classify-arm64
- test-phylo
- test-phylo-arm64
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Check test results
run: |
# Get all job results
results="${{ join(needs.*.result, ' ') }}"
echo "Job results: $results"
# Fail if any job failed or was cancelled
for result in $results; do
if [[ "$result" == "failure" || "$result" == "cancelled" ]]; then
echo "One or more test jobs failed or were cancelled"
exit 1
fi
done
echo "All test jobs passed or were skipped"
# ============================================================================
# DEPLOY JOBS - Copy images from GHCR to Quay after tests pass
# Uses crane to efficiently copy multi-arch manifests without re-pulling layers
# ============================================================================
deploy-to-quay:
needs: [
get-version,
create-manifest-baseimage,
create-manifest-core,
create-manifest-assemble,
create-manifest-classify,
create-manifest-phylo,
create-manifest-mega,
all-tests-pass
]
# Use always() to evaluate condition even when upstream jobs were skipped.
# Without this, GitHub skips this job if any job in the dependency chain was skipped,
# even if all direct dependencies succeeded.
if: |
always() &&
!cancelled() &&
needs.all-tests-pass.result == 'success' &&
needs.create-manifest-baseimage.result == 'success' &&
needs.create-manifest-core.result == 'success' &&
needs.create-manifest-assemble.result == 'success' &&
needs.create-manifest-classify.result == 'success' &&
needs.create-manifest-phylo.result == 'success' &&
needs.create-manifest-mega.result == 'success' &&
github.event_name != 'pull_request'
runs-on: ubuntu-latest
permissions:
contents: read
packages: read
strategy:
fail-fast: false
matrix:
include:
- flavor: baseimage
- flavor: core
- flavor: assemble
- flavor: classify
- flavor: phylo
- flavor: mega
steps:
- name: Install crane
uses: imjasonh/setup-crane@v0.4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Quay.io
uses: docker/login-action@v3
with:
registry: quay.io
username: ${{ secrets.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}
- name: Determine tags to copy
id: tags
run: |
FLAVOR="${{ matrix.flavor }}"
# Determine the suffix (mega has no suffix)
if [[ "$FLAVOR" == "mega" ]]; then
SUFFIX=""
else
SUFFIX="-${FLAVOR}"
fi
# Use image-tag-prefix which handles both branches and version tags
# (strips 'v' prefix from version tags, sanitizes '/' in branch names)
TAG_PREFIX="${{ needs.get-version.outputs.image-tag-prefix }}"
echo "src_tag=${TAG_PREFIX}${SUFFIX}" >> $GITHUB_OUTPUT
echo "dest_tags=${TAG_PREFIX}${SUFFIX}" >> $GITHUB_OUTPUT
# For version tags, also create major.minor tag
if [[ "${{ github.ref_type }}" == "tag" ]]; then
MAJOR_MINOR=$(echo "$TAG_PREFIX" | sed -E 's/^([0-9]+\.[0-9]+).*/\1/')
echo "extra_dest_tag=${MAJOR_MINOR}${SUFFIX}" >> $GITHUB_OUTPUT
else
echo "extra_dest_tag=" >> $GITHUB_OUTPUT
fi
# For main branch, also create the "latest" style tag
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
if [[ "$FLAVOR" == "mega" ]]; then
echo "latest_tag=latest" >> $GITHUB_OUTPUT
else
echo "latest_tag=${FLAVOR}" >> $GITHUB_OUTPUT
fi
else
echo "latest_tag=" >> $GITHUB_OUTPUT
fi
- name: Copy image to Quay.io
run: |
SRC="${{ env.GHCR_REPO }}:${{ steps.tags.outputs.src_tag }}"
DEST="${{ env.QUAY_REPO }}:${{ steps.tags.outputs.dest_tags }}"
echo "Copying $SRC -> $DEST"
crane copy "$SRC" "$DEST"
# Copy extra version tag if present (e.g., v1.25 for v1.25.0)
if [[ -n "${{ steps.tags.outputs.extra_dest_tag }}" ]]; then
EXTRA_DEST="${{ env.QUAY_REPO }}:${{ steps.tags.outputs.extra_dest_tag }}"
echo "Copying $SRC -> $EXTRA_DEST"
crane copy "$SRC" "$EXTRA_DEST"
fi
# Copy "latest" style tag for main branch
if [[ -n "${{ steps.tags.outputs.latest_tag }}" ]]; then
LATEST_DEST="${{ env.QUAY_REPO }}:${{ steps.tags.outputs.latest_tag }}"
echo "Copying $SRC -> $LATEST_DEST"
crane copy "$SRC" "$LATEST_DEST"
fi