Add comprehensive unit test suite for codecov coverage #138
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: Docker Build | |
| on: | |
| push: | |
| branches: ['**'] | |
| tags: ['**'] | |
| pull_request: | |
| branches: [main] | |
| merge_group: | |
| delete: # Trigger cleanup when branches are deleted | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| jobs: | |
| build-amd64: | |
| if: github.event_name != 'delete' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Container Registry | |
| if: github.event_name == 'push' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate tag suffix | |
| id: tag | |
| run: | | |
| # Sanitize ref_name: replace / with - for valid Docker tags | |
| echo "suffix=$(echo '${{ github.ref_name }}' | tr '/' '-')" >> $GITHUB_OUTPUT | |
| - name: Build and push (amd64) | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: linux/amd64 | |
| push: ${{ github.event_name == 'push' }} | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.suffix }}-amd64 | |
| provenance: false | |
| sbom: false | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache-amd64 | |
| type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main-amd64 | |
| cache-to: ${{ github.event_name == 'push' && format('type=registry,ref={0}/{1}:buildcache-amd64,mode=max', env.REGISTRY, env.IMAGE_NAME) || '' }} | |
| build-arm64: | |
| if: github.event_name != 'delete' | |
| runs-on: ubuntu-24.04-arm | |
| permissions: | |
| contents: read | |
| packages: write | |
| outputs: | |
| digest: ${{ steps.build.outputs.digest }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Container Registry | |
| if: github.event_name == 'push' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate tag suffix | |
| id: tag | |
| run: | | |
| # Sanitize ref_name: replace / with - for valid Docker tags | |
| echo "suffix=$(echo '${{ github.ref_name }}' | tr '/' '-')" >> $GITHUB_OUTPUT | |
| - name: Build and push (arm64) | |
| id: build | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| platforms: linux/arm64 | |
| push: ${{ github.event_name == 'push' }} | |
| tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.suffix }}-arm64 | |
| provenance: false | |
| sbom: false | |
| cache-from: | | |
| type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache-arm64 | |
| type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main-arm64 | |
| cache-to: ${{ github.event_name == 'push' && format('type=registry,ref={0}/{1}:buildcache-arm64,mode=max', env.REGISTRY, env.IMAGE_NAME) || '' }} | |
| create-manifest: | |
| if: github.event_name == 'push' | |
| needs: [build-amd64, build-arm64] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate tag suffix | |
| id: tag | |
| run: | | |
| # Sanitize ref_name: replace / with - for valid Docker tags | |
| echo "suffix=$(echo '${{ github.ref_name }}' | tr '/' '-')" >> $GITHUB_OUTPUT | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=ref,event=branch | |
| type=ref,event=tag | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Create and push manifest | |
| env: | |
| TAGS: ${{ steps.meta.outputs.tags }} | |
| SUFFIX: ${{ steps.tag.outputs.suffix }} | |
| run: | | |
| # Iterate over multi-line tags properly | |
| echo "$TAGS" | while IFS= read -r tag; do | |
| [ -z "$tag" ] && continue | |
| echo "Creating manifest for: $tag" | |
| docker buildx imagetools create \ | |
| --annotation "index:org.opencontainers.image.description=ML-guided qPCR primer design with off-target minimization" \ | |
| --annotation "index:org.opencontainers.image.source=https://github.com/broadinstitute/qprimer_designer" \ | |
| --annotation "index:org.opencontainers.image.licenses=MIT" \ | |
| -t "$tag" \ | |
| "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${SUFFIX}-amd64" \ | |
| "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${SUFFIX}-arm64" | |
| done | |
| cleanup-untagged: | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| needs: [create-manifest] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| packages: write | |
| steps: | |
| - uses: actions/delete-package-versions@v5 | |
| with: | |
| package-name: qprimer_designer | |
| package-type: container | |
| min-versions-to-keep: 5 | |
| delete-only-untagged-versions: true | |
| cleanup-branch-images: | |
| if: github.event_name == 'delete' && github.event.ref_type == 'branch' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| packages: write | |
| steps: | |
| - name: Delete branch images from ghcr.io | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Sanitize branch name (same logic as build jobs) | |
| SUFFIX=$(echo '${{ github.event.ref }}' | tr '/' '-') | |
| # Delete multi-arch manifest and arch-specific images | |
| for TAG in "${SUFFIX}" "${SUFFIX}-amd64" "${SUFFIX}-arm64"; do | |
| echo "Looking for tag: $TAG" | |
| # Get version IDs for this tag (may return multiple lines) | |
| # Use index() for exact match instead of contains() which does substring matching | |
| VERSION_IDS=$(gh api \ | |
| "orgs/${{ github.repository_owner }}/packages/container/qprimer_designer/versions" \ | |
| --jq ".[] | select(.metadata.container.tags | index(\"$TAG\")) | .id" \ | |
| 2>/dev/null || true) | |
| if [ -n "$VERSION_IDS" ]; then | |
| echo "$VERSION_IDS" | while read -r VERSION_ID; do | |
| [ -z "$VERSION_ID" ] && continue | |
| gh api --method DELETE \ | |
| "orgs/${{ github.repository_owner }}/packages/container/qprimer_designer/versions/$VERSION_ID" | |
| echo "Deleted version $VERSION_ID (tag: $TAG)" | |
| done | |
| else | |
| echo "Tag $TAG not found, skipping" | |
| fi | |
| done |