Clean up sidecar index files (.tbi, .bai) in refine_assembly #285
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |