Skip to content

ci: Test geos integration of geosPythonPackages for every new PR #471

ci: Test geos integration of geosPythonPackages for every new PR

ci: Test geos integration of geosPythonPackages for every new PR #471

name: geosPythonPackages CI
on: pull_request
# Cancels in-progress workflows for a PR when updated
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# Checks if PR title follows conventional semantics
semantic_pull_request:
permissions:
pull-requests: write # for amannn/action-semantic-pull-request to analyze PRs and
statuses: write # for amannn/action-semantic-pull-request to mark status of analyzed PR
contents: read
runs-on: ubuntu-latest
steps:
- name: Check if the PR name has conventional semantics
if: github.event_name == 'pull_request'
uses: amannn/action-semantic-pull-request@v5.5.3
id: lint_pr_title
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
wip: true
# Configure that a scope doesn't need to be provided.
requireScope: false
- name: Skip the check on main branch
if: github.ref_name == 'main'
run: |
echo "This is not a Pull-Request, skipping"
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 3
matrix:
python-version: ["3.10", "3.11", "3.12"]
package-name:
- geos-ats
- geos-geomechanics
- geos-mesh
- geos-posp
- geos-timehistory
- geos-trame
- geos-utils
- geos-xml-tools
- hdf5-wrapper
- pygeos-tools
include:
- package-name: geos-geomechanics
dependencies: "geos-utils"
- package-name: geos-mesh
dependencies: "geos-utils geos-geomechanics"
- package-name: geos-posp
dependencies: "geos-utils geos-mesh geos-geomechanics"
- package-name: pygeos-tools
dependencies: "geos-utils geos-mesh"
- package-name: geos-timehistory
dependencies: "hdf5-wrapper"
steps:
- uses: actions/checkout@v4
- uses: mpi4py/setup-mpi@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
- name: Install package
# working-directory: ./${{ matrix.package-name }}
run: |
python -m pip install --upgrade pip
python -m pip install pytest yapf toml
DEPS="${{ matrix.dependencies || '' }}"
if [ -n "$DEPS" ]; then
echo "Installing additional dependencies: $DEPS"
for dep in $DEPS; do
python -m pip install ./$dep
done
fi
echo "Installing main package..."
python -m pip install ./${{ matrix.package-name }}/[test]
- name: Lint with yapf
# working-directory: ./${{ matrix.package-name }}
run: |
yapf -r --diff ./${{ matrix.package-name }} --style .style.yapf
- name: Test with pytest
#working-directory: ./${{ matrix.package-name }}
run:
# python -m pytest ./${{ matrix.package-name }} --doctest-modules --junitxml=junit/test-results.xml --cov-report=xml --cov-report=html |
# wrap pytest to avoid error when no tests in the package
sh -c 'python -m pytest ./${{ matrix.package-name }}; ret=$?; [ $ret = 5 ] && exit 0 || exit $ret'
# Step 1: Validate that all standard CI tests pass BEFORE checking GEOS integration
validate_standard_ci:
runs-on: ubuntu-latest
needs: [semantic_pull_request, build]
steps:
- name: Check standard CI results
run: |
echo "Checking standard CI results..."
echo "Semantic PR check: ${{ needs.semantic_pull_request.result }}"
echo "Build and test: ${{ needs.build.result }}"
# All standard tests must pass before proceeding
if [[ "${{ needs.semantic_pull_request.result }}" != "success" ]]; then
echo "❌ Semantic PR check failed - fix PR title before proceeding"
exit 1
fi
if [[ "${{ needs.build.result }}" != "success" ]]; then
echo "❌ Build and test failed - fix code issues before proceeding"
exit 1
fi
echo "✅ All standard CI tests passed! Ready for GEOS integration testing."
# Step 2: Only after standard tests pass, check for GEOS integration label
check_geos_integration_label:
runs-on: ubuntu-latest
needs: [validate_standard_ci]
permissions:
pull-requests: read
outputs:
should_test_geos: ${{ steps.check_label.outputs.should_test_geos }}
has_label: ${{ steps.check_label.outputs.has_label }}
steps:
- name: Check for GEOS integration test label
id: check_label
run: |
set -e # Exit immediately if a command exits with a non-zero status.
echo "Standard CI tests have passed. Now checking for GEOS integration requirements..."
# Check if the PR has the 'test-geos-integration' label
# -fsS gives Fails on Error (f), Silent on Success (s), Shows Error Message (S)
pr_json=$(curl -fsS -H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.number }})
LABELS=$(echo ${pr_json} | jq -r '[.labels[].name] | join(",")')
echo "PR labels: ${LABELS}"
if [[ "${LABELS}" == *"test-geos-integration"* ]]; then
echo "has_label=true" >> $GITHUB_OUTPUT
echo "should_test_geos=true" >> $GITHUB_OUTPUT
echo "✅ Found 'test-geos-integration' label - will proceed with GEOS integration testing"
else
echo "has_label=false" >> $GITHUB_OUTPUT
echo "should_test_geos=false" >> $GITHUB_OUTPUT
echo "❌ Missing 'test-geos-integration' label"
echo ""
echo "REQUIRED: This PR must have the 'test-geos-integration' label to be merged"
echo "This ensures that changes are tested against GEOS before merging"
echo ""
echo "To add the label:"
echo "1. Go to your PR page"
echo "2. Click on 'Labels' in the right sidebar"
echo "3. Add the 'test-geos-integration' label"
exit 1
fi
# Step 3: Only trigger GEOS integration if label exists AND standard tests passed
trigger_geos_integration_test:
runs-on: ubuntu-latest
needs: [check_geos_integration_label]
if: needs.check_geos_integration_label.outputs.should_test_geos == 'true'
permissions:
pull-requests: read
outputs:
workflow_run_id: ${{ steps.trigger_workflow.outputs.workflow_run_id }}
steps:
- name: Get PR information
id: pr_info
run: |
echo "Triggering GEOS integration test..."
pr_json=$(curl -fsSL -H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.number }}")
LABELS=$(echo "${pr_json}" | jq -r '[.labels[].name] | join(",")')
PR_HEAD_REPO=$(echo ${pr_json} | jq -r '.head.repo.clone_url')
PR_HEAD_BRANCH=$(echo ${pr_json} | jq -r '.head.ref')
PR_HEAD_SHA=$(echo ${pr_json} | jq -r '.head.sha')
echo "pr_repo=${PR_HEAD_REPO}" >> $GITHUB_OUTPUT
echo "pr_branch=${PR_HEAD_BRANCH}" >> $GITHUB_OUTPUT
echo "pr_sha=${PR_HEAD_SHA}" >> $GITHUB_OUTPUT
echo "PR Repository: ${PR_HEAD_REPO}"
echo "PR Branch: ${PR_HEAD_BRANCH}"
echo "PR SHA: ${PR_HEAD_SHA}"
- name: Trigger GEOS integration test workflow
id: trigger_workflow
run: |
set -e
echo "All standard tests passed ✅"
echo "GEOS integration label found ✅"
echo "Now triggering GEOS integration test workflow..."
# Trigger the workflow_dispatch event in the GEOS repository
response=$(curl -fsS -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GEOS_INTEGRATION_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/GEOS-DEV/GEOS/actions/workflows/test_geospythonpackages_integration.yml/dispatches \
-d '{
"ref": "${{ steps.pr_info.outputs.pr_branch }}",
"inputs": {
"python_package_repo": "${{ steps.pr_info.outputs.pr_repo }}",
"python_package_branch": "${{ steps.pr_info.outputs.pr_branch }}",
"python_package_pr": "${{ github.event.number }}",
"requested_by": "${{ github.actor }}"
}
}')
echo "Workflow dispatch response: $response"
echo "✅ GEOS integration test workflow triggered successfully"
# Wait a moment for the workflow to start, then find the run ID
sleep 10
# Get the latest workflow runs to find our triggered run
runs_response=$(curl -fsS -H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GEOS_INTEGRATION_TOKEN }}" \
https://api.github.com/repos/GEOS-DEV/GEOS/actions/workflows/test_geospythonpackages_integration.yml/runs?per_page=5)
# Find the most recent run (this assumes it's our triggered run)
workflow_run_id=$(echo "$runs_response" | jq -r '.workflow_runs[0].id')
echo "workflow_run_id=${workflow_run_id}" >> $GITHUB_OUTPUT
echo "Triggered workflow run ID: ${workflow_run_id}"
# Step 4: Wait for GEOS integration results (only if triggered)
wait_for_geos_integration_result:
runs-on: ubuntu-latest
needs: [trigger_geos_integration_test]
if: needs.trigger_geos_integration_test.outputs.workflow_run_id != ''
outputs:
geos_test_result: ${{ steps.wait_for_result.outputs.geos_test_result }}
steps:
- name: Wait for GEOS integration test to complete
id: wait_for_result
run: |
WORKFLOW_RUN_ID="${{ needs.trigger_geos_integration_test.outputs.workflow_run_id }}"
echo "Waiting for GEOS integration test to complete (Run ID: ${WORKFLOW_RUN_ID})..."
echo "This may take 15-30 minutes..."
# Wait for the workflow to complete (with timeout)
timeout=1800 # 30 minutes
elapsed=0
interval=60
while [ $elapsed -lt $timeout ]; do
run_status=$(curl -H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GEOS_INTEGRATION_TOKEN }}" \
https://api.github.com/repos/GEOS-DEV/GEOS/actions/runs/${WORKFLOW_RUN_ID} \
| jq -r '.status')
conclusion=$(curl -H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ secrets.GEOS_INTEGRATION_TOKEN }}" \
https://api.github.com/repos/GEOS-DEV/GEOS/actions/runs/${WORKFLOW_RUN_ID} \
| jq -r '.conclusion')
echo "Workflow status: ${run_status}, conclusion: ${conclusion} (${elapsed}s elapsed)"
if [[ "${run_status}" == "completed" ]]; then
echo "Workflow completed with conclusion: ${conclusion}"
if [[ "${conclusion}" == "success" ]]; then
echo "✅ GEOS integration test PASSED"
echo "geos_test_result=success" >> $GITHUB_OUTPUT
exit 0
else
echo "❌ GEOS integration test FAILED"
echo "geos_test_result=failure" >> $GITHUB_OUTPUT
exit 1
fi
fi
sleep $interval
elapsed=$((elapsed + interval))
done
echo "❌ TIMEOUT: GEOS integration test did not complete within ${timeout} seconds"
echo "geos_test_result=timeout" >> $GITHUB_OUTPUT
exit 1
# Step 5: Final validation - requires ALL tests to pass
final_validation:
runs-on: ubuntu-latest
needs: [check_geos_integration_label, wait_for_geos_integration_result]
if: always()
steps:
- name: Final merge validation
run: |
echo "=== FINAL MERGE VALIDATION ==="
echo ""
echo "Standard CI Tests: ✅ PASSED (already validated)"
echo "GEOS Integration Label: ${{ needs.check_geos_integration_label.outputs.has_label == 'true' && '✅ PRESENT' || '❌ MISSING' }}"
echo "GEOS Integration Tests: ${{ needs.wait_for_geos_integration_result.outputs.geos_test_result == 'success' && '✅ PASSED' || needs.wait_for_geos_integration_result.result == 'skipped' && '⏭️ SKIPPED (no label)' || '❌ FAILED' }}"
echo ""
# Check label requirement
if [[ "${{ needs.check_geos_integration_label.outputs.has_label }}" != "true" ]]; then
echo "❌ INVALID: Missing 'test-geos-integration' label"
echo ""
echo "This PR cannot be merged without the 'test-geos-integration' label"
echo "Please add the label and wait for GEOS integration tests to pass"
exit 1
fi
# Check GEOS test results (only if they were supposed to run)
if [[ "${{ needs.wait_for_geos_integration_result.result }}" == "failure" || "${{ needs.wait_for_geos_integration_result.outputs.geos_test_result }}" == "failure" ]]; then
echo "❌ INVALID: GEOS integration tests failed"
echo ""
echo "The changes in this PR break GEOS functionality"
echo "Please check the GEOS workflow logs and fix the issues"
echo "GEOS workflow: https://github.com/GEOS-DEV/GEOS/actions/runs/${{ needs.trigger_geos_integration_test.outputs.workflow_run_id }}"
exit 1
fi
if [[ "${{ needs.wait_for_geos_integration_result.outputs.geos_test_result }}" == "timeout" ]]; then
echo "❌ INVALID: GEOS integration tests timed out"
echo ""
echo "Please check the GEOS workflow manually and re-run if needed"
echo "GEOS workflow: https://github.com/GEOS-DEV/GEOS/actions/runs/${{ needs.trigger_geos_integration_test.outputs.workflow_run_id }}"
exit 1
fi
# All validations passed
echo "✅ VALID: All requirements met"
echo ""
echo "This PR is ready for review and merge:"
echo " ✅ Standard CI tests passed"
echo " ✅ 'test-geos-integration' label present"
echo " ✅ GEOS integration tests passed"
echo ""
echo "🎉 Ready for merge!"