Update documentation #8
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
| # SPDX-License-Identifier: Apache-2.0 | |
| name: TestSuite | |
| env: | |
| LATEST_PYTHON_VERSION: '3.13' | |
| on: | |
| push: | |
| branches: [ develop, main ] | |
| pull_request: | |
| branches: [ develop, main ] | |
| workflow_dispatch: | |
| jobs: | |
| test-chiltepin-amd64: | |
| runs-on: ubuntu2204-16c-64g-600ssd | |
| timeout-minutes: 360 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13'] | |
| permissions: | |
| packages: write | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - | |
| name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - | |
| name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - | |
| name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - | |
| name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| logout: false | |
| - | |
| name: Clean up any existing containers from previous runs | |
| run: | | |
| # Stop and remove any containers from previous runs | |
| cd docker | |
| docker compose -f docker-compose.yml down --remove-orphans --volumes || true | |
| - | |
| name: Prune pre-loaded GHA docker images | |
| run: | | |
| docker images | |
| docker image prune -a -f | |
| docker images | |
| - | |
| name: Start Slurm cluster containers | |
| run: | | |
| cd docker | |
| export DOCKER_CLIENT_TIMEOUT=600 | |
| export COMPOSE_HTTP_TIMEOUT=600 | |
| docker compose version | |
| docker compose -f docker-compose.yml config | |
| docker images | |
| docker ps -a | |
| docker compose -f docker-compose.yml up -d | |
| - | |
| name: Install Python ${{ matrix.python-version }} on all nodes | |
| run: | | |
| # Install on frontend | |
| docker exec frontend bash -c "sudo apt-get update && sudo apt-get install -y software-properties-common" | |
| docker exec frontend bash -c "sudo add-apt-repository -y ppa:deadsnakes/ppa" | |
| docker exec frontend bash -c "sudo apt-get update && sudo apt-get install -y python${{ matrix.python-version }} python${{ matrix.python-version }}-venv python${{ matrix.python-version }}-dev" | |
| # Install on all compute nodes | |
| for node in node1 node2 node3 node4 node5; do | |
| docker exec $node bash -c "sudo apt-get update && sudo apt-get install -y software-properties-common" | |
| docker exec $node bash -c "sudo add-apt-repository -y ppa:deadsnakes/ppa" | |
| docker exec $node bash -c "sudo apt-get update && sudo apt-get install -y python${{ matrix.python-version }} python${{ matrix.python-version }}-venv python${{ matrix.python-version }}-dev" | |
| done | |
| - | |
| name: Copy test files to work directory | |
| run: | | |
| docker exec frontend bash -l -c "mkdir -p work; cd work ; cp -r ../chiltepin/* ." | |
| - | |
| name: Install chiltepin package | |
| run: | | |
| docker exec frontend bash -l -c "cd work ; module use /opt/spack-stack/envs/unified-env/install/modulefiles/Core ; module load stack-gcc; module load stack-openmpi ; python${{ matrix.python-version }} -m venv .venv-py${{ matrix.python-version }}" | |
| docker exec frontend bash -l -c "cd work ; source .venv-py${{ matrix.python-version }}/bin/activate ; pip install -e .[test]" | |
| - | |
| name: Run test suite with coverage | |
| id: pytest | |
| env: | |
| GLOBUS_COMPUTE_CLIENT_ID: ${{ secrets.GC_CLIENT_ID }} | |
| GLOBUS_COMPUTE_CLIENT_SECRET: ${{ secrets.GC_CLIENT_SECRET }} | |
| run: | | |
| docker exec -e GLOBUS_COMPUTE_CLIENT_ID="$GLOBUS_COMPUTE_CLIENT_ID" -e GLOBUS_COMPUTE_CLIENT_SECRET="$GLOBUS_COMPUTE_CLIENT_SECRET" frontend bash -l -c "cd work; source .venv-py${{ matrix.python-version }}/bin/activate; pytest -s -v --assert=plain --cov=src/chiltepin --cov-report=term-missing --cov-report=markdown:coverage.md --cov-report=xml --cov-report=html --cov-fail-under=0 --config=tests/configs/docker.yaml" | |
| - | |
| name: Copy coverage reports from container | |
| if: always() | |
| run: | | |
| docker cp frontend:/home/admin/work/coverage.md ./coverage.md || true | |
| docker cp frontend:/home/admin/work/coverage.xml ./coverage.xml || true | |
| docker cp frontend:/home/admin/work/htmlcov ./htmlcov || true | |
| - | |
| name: Upload coverage reports | |
| id: upload-coverage | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report-py${{ matrix.python-version }} | |
| path: | | |
| coverage.md | |
| coverage.xml | |
| htmlcov/ | |
| retention-days: 30 | |
| - | |
| name: Debug session | |
| if: failure() | |
| uses: mxschmitt/action-tmate@v3 | |
| timeout-minutes: 60 | |
| with: | |
| limit-access-to-actor: true | |
| - | |
| name: Shut down Slurm cluster containers | |
| if: always() | |
| run: | | |
| cd docker | |
| export DOCKER_CLIENT_TIMEOUT=600 | |
| export COMPOSE_HTTP_TIMEOUT=600 | |
| docker compose -f docker-compose.yml down --remove-orphans --volumes | |
| test-chiltepin-arm64: | |
| runs-on: LinuxARM64-16core-64G-600Gb | |
| timeout-minutes: 360 | |
| permissions: | |
| packages: write | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - | |
| # ARM runners do not have Docker installed | |
| name: Install Docker | |
| run: | | |
| # Uninstall incompatible packages | |
| for pkg in docker.io containerd runc; do sudo apt-get remove $pkg; done | |
| # Add Docker's official GPG key: | |
| sudo apt-get update -y | |
| sudo apt-get install -y ca-certificates curl | |
| sudo install -m 0755 -d /etc/apt/keyrings | |
| sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc | |
| sudo chmod a+r /etc/apt/keyrings/docker.asc | |
| # Add the repository to Apt sources: | |
| echo \ | |
| "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ | |
| $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ | |
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null | |
| sudo apt-get update -y | |
| # Install docker packages | |
| sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin | |
| # Allow runner use to run docker without sudo | |
| sudo usermod -aG docker $USER | |
| sudo apt-get install acl | |
| sudo setfacl --modify user:$USER:rw /var/run/docker.sock | |
| - | |
| name: Test Docker Installation | |
| run: docker run hello-world | |
| - | |
| name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - | |
| name: Set up QEMU | |
| uses: docker/setup-qemu-action@v3 | |
| - | |
| name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - | |
| name: Login to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| logout: false | |
| - | |
| name: Clean up any existing containers from previous runs | |
| run: | | |
| # Stop and remove any containers from previous runs | |
| cd docker | |
| docker compose -f docker-compose.yml down --remove-orphans --volumes || true | |
| - | |
| name: Prune pre-loaded GHA docker images | |
| run: | | |
| docker images | |
| docker image prune -a -f | |
| docker images | |
| - | |
| name: Start Slurm cluster containers | |
| run: | | |
| cd docker | |
| export DOCKER_CLIENT_TIMEOUT=600 | |
| export COMPOSE_HTTP_TIMEOUT=600 | |
| docker compose version | |
| docker compose -f docker-compose.yml config | |
| docker images | |
| docker ps -a | |
| docker compose -f docker-compose.yml up -d | |
| - | |
| name: Install Python ${{ env.LATEST_PYTHON_VERSION }} on all nodes | |
| run: | | |
| # Install on frontend | |
| docker exec frontend bash -c "sudo apt-get update && sudo apt-get install -y software-properties-common" | |
| docker exec frontend bash -c "sudo add-apt-repository -y ppa:deadsnakes/ppa" | |
| docker exec frontend bash -c "sudo apt-get update && sudo apt-get install -y python${{ env.LATEST_PYTHON_VERSION }} python${{ env.LATEST_PYTHON_VERSION }}-venv python${{ env.LATEST_PYTHON_VERSION }}-dev" | |
| # Install on all compute nodes | |
| for node in node1 node2 node3 node4 node5; do | |
| docker exec $node bash -c "sudo apt-get update && sudo apt-get install -y software-properties-common" | |
| docker exec $node bash -c "sudo add-apt-repository -y ppa:deadsnakes/ppa" | |
| docker exec $node bash -c "sudo apt-get update && sudo apt-get install -y python${{ env.LATEST_PYTHON_VERSION }} python${{ env.LATEST_PYTHON_VERSION }}-venv python${{ env.LATEST_PYTHON_VERSION }}-dev" | |
| done | |
| - | |
| name: Copy test files to work directory | |
| run: | | |
| docker exec frontend bash -l -c "mkdir -p work; cd work ; cp -r ../chiltepin/* ." | |
| - | |
| name: Install chiltepin package | |
| run: | | |
| docker exec frontend bash -l -c "cd work ; module use /opt/spack-stack/envs/unified-env/install/modulefiles/Core ; module load stack-gcc; module load stack-openmpi ; python${{ env.LATEST_PYTHON_VERSION }} -m venv .venv-py${{ env.LATEST_PYTHON_VERSION }}" | |
| docker exec frontend bash -l -c "cd work ; source .venv-py${{ env.LATEST_PYTHON_VERSION }}/bin/activate ; pip install -e .[test]" | |
| - | |
| name: Run test suite | |
| env: | |
| GLOBUS_COMPUTE_CLIENT_ID: ${{ secrets.GC_CLIENT_ID }} | |
| GLOBUS_COMPUTE_CLIENT_SECRET: ${{ secrets.GC_CLIENT_SECRET }} | |
| run: | | |
| docker exec -e GLOBUS_COMPUTE_CLIENT_ID="$GLOBUS_COMPUTE_CLIENT_ID" -e GLOBUS_COMPUTE_CLIENT_SECRET="$GLOBUS_COMPUTE_CLIENT_SECRET" frontend bash -l -c "cd work; source .venv-py${{ env.LATEST_PYTHON_VERSION }}/bin/activate; pytest -s -v --assert=plain --config=tests/configs/docker.yaml" | |
| - | |
| name: Debug session | |
| if: ${{ failure() }} | |
| uses: mxschmitt/action-tmate@v3 | |
| timeout-minutes: 60 | |
| with: | |
| limit-access-to-actor: true | |
| - | |
| name: Shut down Slurm cluster containers | |
| if: always() | |
| run: | | |
| cd docker | |
| export DOCKER_CLIENT_TIMEOUT=600 | |
| export COMPOSE_HTTP_TIMEOUT=600 | |
| docker compose -f docker-compose.yml down --remove-orphans --volumes | |
| coverage-check: | |
| name: Coverage Check | |
| runs-on: ubuntu-latest | |
| needs: [test-chiltepin-amd64] | |
| if: always() | |
| permissions: | |
| pull-requests: write | |
| contents: read | |
| steps: | |
| - | |
| name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - | |
| name: Download coverage report | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: coverage-report-py${{ env.LATEST_PYTHON_VERSION }} | |
| path: ./coverage | |
| continue-on-error: true | |
| - | |
| name: Check coverage threshold | |
| id: coverage | |
| run: | | |
| # Extract threshold from pyproject.toml | |
| THRESHOLD=$(grep -A 5 '\[tool.coverage.report\]' pyproject.toml | grep 'fail_under' | grep -oP '\d+(\.\d+)?' | head -1) | |
| THRESHOLD=${THRESHOLD:-80.0} # Default to 80.0 if not found | |
| # Extract coverage percentage from XML | |
| if [ -f ./coverage/coverage.xml ]; then | |
| line_rate=$(grep -oP 'line-rate="\K[0-9.]+' ./coverage/coverage.xml | head -1) | |
| coverage=$(echo "$line_rate * 100" | bc -l | xargs printf "%.2f") | |
| echo "Coverage: ${coverage}% | Threshold: ${THRESHOLD}%" | |
| # Determine pass/fail | |
| if (( $(echo "$coverage >= $THRESHOLD" | bc -l) )); then | |
| STATUS="✅ **PASS**" | |
| RESULT="success" | |
| echo "✅ Coverage ${coverage}% meets threshold ${THRESHOLD}%" | |
| else | |
| STATUS="❌ **FAIL**" | |
| RESULT="failure" | |
| echo "❌ Coverage ${coverage}% is below threshold ${THRESHOLD}%" | |
| fi | |
| else | |
| STATUS="⚠️ **UNKNOWN**" | |
| coverage="N/A" | |
| RESULT="failure" | |
| echo "⚠️ Coverage report not found" | |
| fi | |
| # Save outputs | |
| echo "coverage=$coverage" >> $GITHUB_OUTPUT | |
| echo "threshold=$THRESHOLD" >> $GITHUB_OUTPUT | |
| echo "status=$STATUS" >> $GITHUB_OUTPUT | |
| echo "result=$RESULT" >> $GITHUB_OUTPUT | |
| # Build PR comment | |
| echo "COVERAGE_REPORT<<EOF" >> $GITHUB_OUTPUT | |
| echo "## 📊 Test Coverage Report" >> $GITHUB_OUTPUT | |
| echo "" >> $GITHUB_OUTPUT | |
| echo "**Status:** $STATUS (Coverage: ${coverage}% | Threshold: ${THRESHOLD}%)" >> $GITHUB_OUTPUT | |
| echo "" >> $GITHUB_OUTPUT | |
| if [ -f ./coverage/coverage.md ]; then | |
| cat ./coverage/coverage.md >> $GITHUB_OUTPUT | |
| else | |
| echo "❌ Coverage report not available" >> $GITHUB_OUTPUT | |
| fi | |
| echo "" >> $GITHUB_OUTPUT | |
| echo "---" >> $GITHUB_OUTPUT | |
| echo "*Coverage report generated by pytest-cov. Full HTML report available in workflow artifacts.*" >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - | |
| name: Post coverage comment to PR | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: process.env.COVERAGE_REPORT | |
| }); | |
| env: | |
| COVERAGE_REPORT: ${{ steps.coverage.outputs.COVERAGE_REPORT }} | |
| - | |
| name: Fail if coverage below threshold | |
| if: steps.coverage.outputs.result == 'failure' | |
| run: | | |
| echo "❌ Coverage check failed: ${{ steps.coverage.outputs.coverage }}% < ${{ steps.coverage.outputs.threshold }}%" | |
| exit 1 |