Skip to content

Conversation

Copilot
Copy link

@Copilot Copilot AI commented Sep 16, 2025

This PR enhances the Wave workflow to automatically generate and report HTTPS SIF URLs for Singularity containers built through the Wave service. The integration allows users to easily access direct download links for Singularity images without manual intervention.

Changes Made

New Singularity-specific workflow steps

Added three new steps to the conda-wave job that execute only for matrix.profile == 'singularity':

  1. Install uv: Uses astral-sh/setup-uv@v6 to install the uv package manager, which handles runtime dependency resolution for the Python script
  2. Extract ORAS reference: Captures the ORAS image reference from Wave's output using regex pattern matching
  3. Generate HTTPS SIF URL: Executes the existing .github/scripts/wave_singularity.py script to convert the ORAS reference into a direct HTTPS download URL

Key Features

  • Conditional execution: All new steps only run for Singularity matrix jobs, leaving Docker workflows unchanged
  • Error handling: Robust shell scripting with set -euo pipefail and validation that ORAS references are successfully extracted
  • Clean output: Only the final HTTPS SIF URL is appended to GITHUB_STEP_SUMMARY, providing users with the essential download link
  • Proper authentication: Uses existing TOWER_ACCESS_TOKEN secret as SEQERA_ACCESS_TOKEN for Wave API authentication

Workflow Integration

The script leverages the existing wave_singularity.py utility which:

  • Accepts ORAS image references as input arguments
  • Queries the Wave API to inspect container manifests
  • Validates that the container is a Singularity image (single .sif layer)
  • Returns the direct HTTPS URL for downloading the SIF file

Example Output

When a Singularity container is built, the workflow summary will now include:

https://community-cr-prod.seqera.io/docker/registry/v2/blobs/sha256/ab/abc123.../data

This enhancement streamlines the process of obtaining Singularity containers from Wave builds, eliminating the need for manual conversion from ORAS references to download URLs.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • astral.sh
    • Triggering command: curl -LsSf REDACTED (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

This pull request was created as a result of the following prompt from Copilot chat.

Update the GitHub Actions workflow to run the .github/scripts/wave_singularity.py script only for singularity matrix runs and report only the HTTPS SIF URL in the workflow summary. Install the correct dependencies using astral-sh/setup-uv, extract the ORAS image reference from wave output, invoke the script with the proper token, and append the resulting HTTPS SIF link to GITHUB_STEP_SUMMARY.

Please modify .github/workflows/wave.yml with the following content:

name: Wave
# When environment.yml is changed
on:
  pull_request:
    paths:
      - "**/environment.yml"
      - "**/Dockerfile"

# TODO On complete call testing CI
# TODO Skip testing CI if any changes to environment.yml

env:
  # renovate: datasource=github-releases depName=seqeralabs/wave-cli versioning=semver
  WAVE_VERSION: "1.5.0"
  # renovate: datasource=github-releases depName=askimed/nf-test versioning=semver
  NFT_VER: "0.9.2"
  # renovate: datasource=github-releases depName=nextflow/nextflow versioning=semver
  NXF_VER: "24.10.1"

jobs:
  generate-matrix:
    name: generate-matrix
    runs-on: ubuntu-latest
    # Only run on Pull Requests within the same repository, and not from forks
    if: github.event.pull_request.head.repo.full_name == github.repository
    outputs:
      conda-matrix: ${{ steps.conda-diff.outputs.all_changed_files }}
      dockerfile-matrix: ${{ steps.docker-diff.outputs.all_changed_files }}
    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

      - name: Find conda differences
        id: conda-diff
        uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47
        with:
          json: true
          escape_json: false
          files: |
            modules/**/environment.yml

      - name: Find Dockerfile differences
        id: docker-diff
        uses: tj-actions/changed-files@24d32ffd492484c1d75e0c0b894501ddb9d30d62 # v47
        with:
          json: true
          escape_json: false
          files: |
            modules/**/Dockerfile

  conda-wave:
    # NOTE This should get skipped because generate-matrix won't run
    # if: github.repository == 'nf-core/modules'
    if: ${{ needs.generate-matrix.outputs.conda-matrix != '[]' }}
    needs: generate-matrix
    name: Build ${{ matrix.profile }} ${{ matrix.platform }} Container
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      fail-fast: false
      max-parallel: 4
      matrix:
        files: "${{ fromJson(needs.generate-matrix.outputs.conda-matrix) }}"
        profile: [docker, singularity]
        platform: ["linux/amd64", "linux/arm64"]
    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

      - name: Install wave-cli
        run: |
          wget -q https://github.com/seqeralabs/wave-cli/releases/download/v${WAVE_VERSION}/wave-${WAVE_VERSION}-linux-x86_64
          sudo mv wave-${WAVE_VERSION}-linux-x86_64 /usr/local/bin/wave
          chmod +x /usr/local/bin/wave

      - name: Build ${{ matrix.profile }} container
        # FIXME Hack while iron out the CI
        continue-on-error: true
        env:
          PROFILE: ${{ (contains(matrix.profile, 'singularity') && '--singularity') || '' }}
        run: |
          wave --conda-file "${{ matrix.files }}" \
              $PROFILE \
              --freeze \
              --await \
              --platform ${{ matrix.platform }} \
              --tower-token ${{ secrets.TOWER_ACCESS_TOKEN }} \
              --tower-workspace-id ${{ secrets.TOWER_WORKSPACE_ID }}

      # Only for singularity matrix runs:
      # - Install uv (uses script-declared deps)
      # - Extract ORAS ref from wave output
      # - Run script to resolve HTTPS SIF URL
      # - Paste only the HTTPS SIF URL to the workflow summary
      - name: Install uv
        if: ${{ matrix.profile == 'singularity' && success() }}
        uses: astral-sh/setup-uv@v6

      - name: Get ORAS image reference for Singularity
        if: ${{ matrix.profile == 'singularity' && success() }}
        id: oras-ref
        env:
          TOWER_TOKEN: ${{ secrets.TOWER_ACCESS_TOKEN }}
          TOWER_WORKSPACE_ID: ${{ secrets.TOWER_WORKSPACE_ID }}
        run: |
          set -euo pipefail
          REF="$(wave --conda-file "${{ matrix.files }}" \
            --singularity \
            --freeze \
            --platform "${{ matrix.platform }}" \
            --tower-token "${TOWER_TOKEN}" \
            --tower-workspace-id "${TOWER_WORKSPACE_ID}" \
            2>&1 | grep -Eo 'oras://[^[:space:]]+' | head -n1 || true)"
          if [ -z "${REF}" ]; then
            echo "Failed to extract ORAS image reference from wave output" >&2
            exit 1
          fi
          echo "ref=${REF}" >> "${GITHUB_OUTPUT}"

      - name: Report HTTPS SIF URL
        if: ${{ matrix.profile == 'singularity' && success() }}
        env:
          # Script reads SEQERA_ACCESS_TOKEN when provided
          SEQERA_ACCESS_TOKEN: ${{ secrets.TOWER_ACCESS_TOKEN }}
        run: |
          set -euo pipefail
          SIF_URL="$(uv run .github/scripts/wave_singularity.py "${{ steps.oras-ref.outputs.ref }}")"
          echo "${SIF_URL}" >> "${GITHUB_STEP_SUMMARY}"
          echo "HTTPS SIF URL: ${SIF_URL}"

  dockerfile-wave:
    # NOTE This should get skipped because generate-matrix won't run
    # if: github.repository == 'nf-core/modules'
    if: ${{ needs.generate-matrix.outputs.dockerfile-matrix != '[]' }}
    needs: generate-matrix
    name: Build Dockerfile-based ${{ matrix.platform }} Container
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      fail-fast: false
      max-parallel: 4
      matrix:
        files: "${{ fromJson(needs.generate-matrix.outputs.dockerfile-matrix) }}"
        # NOTE singularity build requires a Singularity definition file in place of Dockerfile
        # https://nextflow.slack.com/archives/C0477AS31T5/p1731755350230149?thread_ts=1731697852.661849&cid=C0477AS31T5
        # profile: [docker]
        platform: ["linux/amd64", "linux/arm64"]
    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5

      - name: Install wave-cli
        run: |
          wget -q https://github.com/seqeralabs/wave-cli/releases/download/v${WAVE_VERSION}/wave-${WAVE_VERSION}-linux-x86_64
          sudo mv wave-${WAVE_VERSION}-linux-x86_64 /usr/local/bin/wave
          chmod +x /usr/local/bin/wave

      - name: Create a registry name
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
        id: registry-name
        with:
          result-encoding: string
          script: |
            return '${{ matrix.files }}'.replace('modules/nf-core/', '').replace('/Dockerfile', '').replace('/', '_');

      - name: Build ${{ matrix.platform }} container
        # NOTE If you're changing a Dockerfile and this is running, try to update the Dockerfile to build with wave
        continue-on-error: false
        run: |
          wave -f "${{ matrix.files }}" \
              --freeze \
              --await \
              --platform ${{ matrix.platform }} \
              --build-repo quay.io/nf-core/modules/${{steps.registry-name.outputs.result}} \
              --cache-repository quay.io/nf-core/wave-cache/docker/${{ matrix.platform }} \
              --tower-token ${{ secrets.TOWER_ACCESS_TOKEN }} \
              --tower-workspace-id ${{ secrets.TOWER_WORKSPACE_ID }}

  # bump-versions:
  #   needs: generate-matrix
  #   name: bump-versions
  #   runs-on: ubuntu-latest
  #   steps:
  #     - uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4
  #       with:
  #         distribution: "temurin"
  #         java-version: "17"

  #     - uses: nf-core/setup-nextflow@v2

  #     - uses: nf-core/setup-nf-test@v1
  #       with:
  #         version: ${{ env.NFT_VER }}

  #     - name: Bump Snapshot Versions
  #       env:
  #         # NFT_DIFF: "pdiff"
  #         # NFT_DIFF_ARGS: "--line-numbers --width 120 --expand-tabs=2"
  #         SENTIEON_LICSRVR_IP: ${{ secrets.SENTIEON_LICSRVR_IP }}
  #         SENTIEON_AUTH_MECH: "GitHub Actions - token"
  #       run: |
  #         # use "docker_self_hosted" if it runs on self-hosted runner and matrix.profile=docker
  #         if [ "${{ matrix.profile }}" == "docker" ]; then
  #           PROFILE="docker_self_hosted"
  #         else
  #           PROFILE=${{ matrix.profile }}
  #         fi

  #         NFT_WORKDIR=~ \
  #         nf-test test \
  #           --profile=${{ matrix.profile }} \
  #           --tap=test.tap \
  #           # --ci \
  #           --verbose \
  #           --only-changed \
  #           # --shard ${{ matrix.shard }}/${{ env.TOTAL_SHARDS }} \
  #           # --filter ${{ matrix.filter }} \
  #           --follow-dependencies \
  #           --tag version \
  #           --update-snapshot

  #     - name: Commit & push version bumps
  #       run: |
  #         git config user.email "[email protected]"
  #         git config user.name "nf-core-bot"
  #         git config push.default upstream
  #         git add .
  #         git status
  #         git commit -m "[automated] Bump versions snapshot"
  #         git push

Acceptance criteria:

  • The script .github/scripts/wave_singularity.py runs only for singularity matrix jobs.
  • Dependencies are installed via astral-sh/setup-uv and resolved at runtime with uv run using the script header.
  • The ORAS reference is extracted from wave output and used as the image_name argument to the script.
  • Only the resulting HTTPS SIF URL is appended to GITHUB_STEP_SUMMARY and echoed in logs.
  • No changes to behavior for docker matrix jobs or dockerfile-wave job.

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@Copilot Copilot AI changed the title [WIP] Wave CI: Run wave_singularity.py for singularity jobs and report HTTPS SIF URL feat: Integrate wave_singularity.py script for Singularity container HTTPS SIF URL reporting Sep 16, 2025
@Copilot Copilot AI requested a review from edmundmiller September 16, 2025 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants