CI: Artifacts upload check v1 #159
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: macOS | |
| # Build and run tests on macOS | |
| on: | |
| push: | |
| branches: | |
| - priotestci | |
| pull_request: | |
| branches: | |
| - priotestci | |
| env: | |
| CACHE_NUMBER: 0 | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} | |
| cancel-in-progress: true | |
| permissions: | |
| actions: read # Allows Github to fetch artifacts | |
| jobs: | |
| macos_build: | |
| name: macOS build | |
| runs-on: macos-15 | |
| env: | |
| PYTHONWARNINGS: always | |
| steps: | |
| - name: Info | |
| run: | | |
| echo "macOS version $(sw_vers -productVersion)" | |
| echo "architecture $(uname -a)" | |
| - name: Disabling Spotlight | |
| run: sudo mdutil -a -i off | |
| - name: Uninstalling Homebrew | |
| run: | | |
| echo "Moving directories..." | |
| sudo mkdir /opt/local-off /opt/homebrew-off | |
| test ! -d /usr/local || /usr/bin/sudo /usr/bin/find /usr/local \ | |
| -mindepth 1 -maxdepth 1 -type d -print -exec /bin/mv {} \ | |
| /opt/local-off/ \; | |
| test ! -d /opt/homebrew || /usr/bin/sudo /usr/bin/find /opt/homebrew \ | |
| -mindepth 1 -maxdepth 1 -type d -print -exec /bin/mv {} \ | |
| /opt/homebrew-off/ \; | |
| echo "Removing files..." | |
| test ! -d /usr/local || /usr/bin/sudo /usr/bin/find /usr/local \ | |
| -mindepth 1 -maxdepth 1 -type f -print -delete | |
| test ! -d /opt/homebrew || /usr/bin/sudo /usr/bin/find /opt/homebrew \ | |
| -mindepth 1 -maxdepth 1 -type f -print -delete | |
| # Rehash to forget about the deleted files | |
| hash -r | |
| - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 | |
| with: | |
| persist-credentials: false | |
| - name: Get current date cache key segment | |
| id: date | |
| # Year and week of year so cache key changes weekly | |
| run: echo "date=$(date +%Y-%U)" >> "${GITHUB_OUTPUT}" | |
| - name: Prepare Conda environment file | |
| env: | |
| test_dependencies: | | |
| ipython | |
| pytest | |
| pytest-github-actions-annotate-failures | |
| pytest-timeout | |
| pytest-xdist | |
| pyyaml | |
| run: | | |
| cp ./macos/files/conda-requirements-dev-arm64.txt "${RUNNER_TEMP}/macos_dependencies.txt" | |
| echo "${test_dependencies// /\n}" >> "${RUNNER_TEMP}/macos_dependencies.txt" | |
| - name: Setup Mamba | |
| uses: mamba-org/setup-micromamba@add3a49764cedee8ee24e82dfde87f5bc2914462 # v2.0.7 | |
| with: | |
| init-shell: bash | |
| environment-file: ${{ runner.temp }}/macos_dependencies.txt | |
| environment-name: grass-env | |
| # Persist on the same period (date). | |
| cache-environment-key: environment-${{ steps.date.outputs.date }} | |
| - name: Environment info | |
| shell: bash -el {0} | |
| run: | | |
| printenv | sort | |
| $CC --version | |
| - name: Create installation directory | |
| run: mkdir "${HOME}/install" | |
| - name: Build and install | |
| shell: micromamba-shell {0} | |
| run: source ./.github/workflows/macos_install.sh "${HOME}/install" | |
| - name: Add the bin directory to PATH | |
| run: echo "${HOME}/install/bin" >> "${GITHUB_PATH}" | |
| - name: Check installed version | |
| if: ${{ !cancelled() }} | |
| shell: micromamba-shell {0} | |
| run: source ./.github/workflows/print_versions.sh | |
| - name: Get PR ID | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| echo "PR_ID=${{ github.event.number }}" >> "$GITHUB_ENV" | |
| echo "This run is for PR #${{ github.event.number }}" | |
| else | |
| echo "PR_ID=none" >> "$GITHUB_ENV" | |
| echo "This run is not a PR (branch: ${GITHUB_REF_NAME})" | |
| fi | |
| - name: Install jq in micromamba env | |
| shell: micromamba-shell {0} | |
| run: micromamba install -y jq | |
| - name: Install pytest-json-report | |
| shell: micromamba-shell {0} | |
| run: python -m pip install --upgrade pytest-json-report | |
| - name: Check If Previous Artifacts Exist | |
| id: check_artifacts | |
| shell: micromamba-shell {0} | |
| run: | | |
| echo "Checking if previous artifacts exist for PR-${PR_ID}..." | |
| ARTIFACTS_RESPONSE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/actions/artifacts") | |
| ARTIFACT_COUNT=$(echo "$ARTIFACTS_RESPONSE" \ | |
| | jq -r --arg NAME "pr_${PR_ID}_macos_smoketest" \ | |
| '[.artifacts[] | select(.name==$NAME and .expired==false)] | length') | |
| echo "Found ${ARTIFACT_COUNT} matching artifact(s)." | |
| if [[ "$ARTIFACT_COUNT" -gt 0 ]]; then | |
| echo "PREV_ARTIFACT_EXISTS=true" >> "$GITHUB_ENV" | |
| else | |
| echo "PREV_ARTIFACT_EXISTS=false" >> "$GITHUB_ENV" | |
| fi | |
| - name: Create smoketest file (pr_<id>/macos) | |
| shell: bash | |
| run: | | |
| PR_DIR="pr_${PR_ID}" | |
| mkdir -p "artifacts/${PR_DIR}/macos" | |
| { | |
| echo "workflow: macOS" | |
| echo "event: ${{ github.event_name }}" | |
| echo "branch: ${GITHUB_REF_NAME}" | |
| echo "pr_id: ${PR_ID}" | |
| echo "timestamp: $(date -Iseconds)" | |
| } > "artifacts/${PR_DIR}/macos/smoketest.txt" | |
| - name: Upload smoketest artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pr_${{ env.PR_ID }}_macos_smoketest | |
| path: artifacts/pr_${{ env.PR_ID }}/macos/smoketest.txt | |
| retention-days: 3 | |
| - name: Download smoketest artifact (to verify upload) | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: pr_${{ env.PR_ID }}_macos_smoketest | |
| path: retrieved | |
| - name: Show downloaded artifact contents | |
| shell: bash | |
| run: | | |
| echo "==== Retrieved Artifact Files ====" | |
| find retrieved -type f | |
| echo "----------------------------------" | |
| echo "Content of smoketest.txt:" | |
| cat retrieved/smoketest.txt || echo "No smoketest file found." | |
| # - name: Run pytest with multiple workers in parallel | |
| # shell: micromamba-shell {0} | |
| # run: | | |
| # PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| # LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| # export PYTHONPATH | |
| # export LD_LIBRARY_PATH | |
| # pytest \ | |
| # @.github/workflows/pytest_args_ci.txt \ | |
| # @.github/workflows/pytest_args_parallel.txt \ | |
| # --junitxml=pytest.xdist.junit.xml \ | |
| # -k 'not testsuite' | |
| - name: Check If Previous macOS Parallel Artifacts Exist | |
| shell: micromamba-shell {0} | |
| run: | | |
| echo "Checking previous artifacts for PR-${PR_ID}..." | |
| ARTIFACTS_RESPONSE=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/actions/artifacts") | |
| ARTIFACT_COUNT=$(echo "$ARTIFACTS_RESPONSE" \ | |
| | jq -r --arg NAME "pr_${PR_ID}_macos_parallel_results" \ | |
| '[.artifacts[] | select(.name==$NAME and .expired==false)] | length') | |
| echo "Found ${ARTIFACT_COUNT} matching artifact(s)." | |
| if [[ "$ARTIFACT_COUNT" -gt 0 ]]; then | |
| echo "PREV_ARTIFACT_EXISTS=true" >> "$GITHUB_ENV" | |
| else | |
| echo "PREV_ARTIFACT_EXISTS=false" >> "$GITHUB_ENV" | |
| fi | |
| - name: Retrieve Previous macOS Parallel Artifacts | |
| if: env.PREV_ARTIFACT_EXISTS == 'true' | |
| shell: micromamba-shell {0} | |
| run: | | |
| echo "Retrieving previous macOS parallel results for PR-${PR_ID}..." | |
| ARTIFACT_URL=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| "https://api.github.com/repos/${{ github.repository }}/actions/artifacts" \ | |
| | jq -r --arg NAME "pr_${PR_ID}_macos_parallel_results" \ | |
| '[.artifacts[] | select(.name==$NAME)] | sort_by(.created_at) | reverse | .[0].archive_download_url') | |
| if [[ -z "$ARTIFACT_URL" || "$ARTIFACT_URL" == "null" ]]; then | |
| echo "Artifact URL not found." | |
| exit 0 | |
| fi | |
| mkdir -p artifacts/pr_${PR_ID}/macos_prev | |
| curl -L -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ | |
| -o artifacts/pr_${PR_ID}/macos_prev/results.zip "$ARTIFACT_URL" | |
| unzip -o artifacts/pr_${PR_ID}/macos_prev/results.zip -d artifacts/pr_${PR_ID}/macos_prev | |
| echo "===== Previous macOS parallel test results =====" | |
| cat artifacts/pr_${PR_ID}/macos_prev/test_results.json || echo "No previous JSON found" | |
| echo "================================================" | |
| - name: Run previously failed tests first (macOS) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| export PYTHONPATH | |
| export LD_LIBRARY_PATH | |
| PR_DIR="pr_${PR_ID}" | |
| PREV_DIR="artifacts/${PR_DIR}/macos_prev" | |
| CURR_DIR="artifacts/${PR_DIR}/macos" | |
| mkdir -p "${CURR_DIR}" | |
| FAILED_TESTS_FILE="${PREV_DIR}/failed_tests.txt" | |
| TEMP_RESULTS="${CURR_DIR}/temp_test_results.json" | |
| if [[ -s "${FAILED_TESTS_FILE}" ]]; then | |
| echo "Re-running previously failed tests first:" | |
| cat "${FAILED_TESTS_FILE}" | |
| pytest \ | |
| @.github/workflows/pytest_args_ci.txt \ | |
| @.github/workflows/pytest_args_parallel.txt \ | |
| --json-report --json-report-file="${TEMP_RESULTS}" \ | |
| $(cat "${FAILED_TESTS_FILE}") || true | |
| else | |
| echo "No previously failed tests found." | |
| # create empty JSON file so next steps never break | |
| echo '{"tests": []}' > "${TEMP_RESULTS}" | |
| fi | |
| - name: Check if any tests failed again (macOS) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PR_DIR="pr_${PR_ID}" | |
| CURR_DIR="artifacts/${PR_DIR}/macos" | |
| TEMP_RESULTS="${CURR_DIR}/temp_test_results.json" | |
| FAILED_AGAIN_FILE="${CURR_DIR}/failed_again.txt" | |
| if [[ -f "${TEMP_RESULTS}" ]]; then | |
| echo "Checking if any previously failed tests are still failing..." | |
| jq -r '.tests | map(select(.outcome == "failed")) | .[].nodeid' \ | |
| "${TEMP_RESULTS}" > "${FAILED_AGAIN_FILE}" || true | |
| else | |
| echo "No temp JSON results found, assuming no tests failed again." | |
| : > "${FAILED_AGAIN_FILE}" | |
| fi | |
| if [[ -s "${FAILED_AGAIN_FILE}" ]]; then | |
| echo "Some tests failed again. Stopping execution." | |
| echo "Tests failing again:" | |
| cat "${FAILED_AGAIN_FILE}" | |
| exit 1 | |
| else | |
| echo "No tests failed again. Continuing with remaining tests..." | |
| fi | |
| - name: Collect all test cases (parallel macOS) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| export PYTHONPATH | |
| export LD_LIBRARY_PATH | |
| PR_DIR="pr_${PR_ID}" | |
| mkdir -p "artifacts/${PR_DIR}/macos" | |
| pytest \ | |
| @.github/workflows/pytest_args_ci.txt \ | |
| @.github/workflows/pytest_args_parallel.txt \ | |
| --collect-only --quiet \ | |
| -k 'not testsuite' \ | |
| | grep "::" > "artifacts/${PR_DIR}/macos/all_tests.txt" || true | |
| - name: Identify remaining tests to run (macOS) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| export PYTHONPATH | |
| export LD_LIBRARY_PATH | |
| PR_DIR="pr_${PR_ID}" | |
| PREV_DIR="artifacts/${PR_DIR}/macos_prev" | |
| CURR_DIR="artifacts/${PR_DIR}/macos" | |
| ALL_TESTS_FILE="${CURR_DIR}/all_tests.txt" | |
| FAILED_PREV="${PREV_DIR}/failed_tests.txt" | |
| REMAINING_TESTS_FILE="${CURR_DIR}/remaining_tests.txt" | |
| mkdir -p "${CURR_DIR}" | |
| if [[ -f "${FAILED_PREV}" && -s "${FAILED_PREV}" ]]; then | |
| echo "Computing remaining tests (excluding previously failed ones)..." | |
| grep -v -F -f "${FAILED_PREV}" "${ALL_TESTS_FILE}" > "${REMAINING_TESTS_FILE}" || true | |
| else | |
| echo "No previous failed tests list found or it is empty." | |
| echo "Treating all collected tests as remaining." | |
| cp "${ALL_TESTS_FILE}" "${REMAINING_TESTS_FILE}" || true | |
| fi | |
| echo "Remaining tests to run:" | |
| cat "${REMAINING_TESTS_FILE}" || echo "No remaining tests found." | |
| # - name: Run pytest with multiple workers in parallel (JSON report) | |
| # shell: micromamba-shell {0} | |
| # run: | | |
| # PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| # LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| # export PYTHONPATH | |
| # export LD_LIBRARY_PATH | |
| # PR_DIR="pr_${PR_ID}" | |
| # mkdir -p "artifacts/${PR_DIR}/macos" | |
| # OUT_JSON="artifacts/${PR_DIR}/macos/test_results.json" | |
| # pytest \ | |
| # @.github/workflows/pytest_args_ci.txt \ | |
| # @.github/workflows/pytest_args_parallel.txt \ | |
| # --junitxml=pytest.xdist.junit.xml \ | |
| # --json-report --json-report-file="${OUT_JSON}" \ | |
| # -k 'not testsuite' || true | |
| - name: Run pytest with multiple workers in parallel (JSON report) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| export PYTHONPATH | |
| export LD_LIBRARY_PATH | |
| PR_DIR="pr_${PR_ID}" | |
| CURR_DIR="artifacts/${PR_DIR}/macos" | |
| mkdir -p "${CURR_DIR}" | |
| OUT_JSON="${CURR_DIR}/test_results.json" | |
| REMAINING_TESTS_FILE="${CURR_DIR}/remaining_tests.txt" | |
| if [[ -s "${REMAINING_TESTS_FILE}" ]]; then | |
| echo "Running remaining test cases (macOS)..." | |
| pytest \ | |
| @.github/workflows/pytest_args_ci.txt \ | |
| @.github/workflows/pytest_args_parallel.txt \ | |
| --junitxml=pytest.xdist.junit.xml \ | |
| --json-report --json-report-file="${OUT_JSON}" \ | |
| $(cat "${REMAINING_TESTS_FILE}") || true | |
| else | |
| echo "No remaining test cases to run. Writing empty JSON." | |
| echo '{"tests": []}' > "${OUT_JSON}" | |
| fi | |
| - name: Extract failed and passed tests (parallel macOS) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PR_DIR="pr_${PR_ID}" | |
| BASE_DIR="artifacts/${PR_DIR}/macos" | |
| RESULTS="${BASE_DIR}/test_results.json" | |
| FAILED="${BASE_DIR}/failed_tests.txt" | |
| PASSED="${BASE_DIR}/passed_tests.txt" | |
| if [[ -f "${RESULTS}" ]]; then | |
| jq -r '.tests | map(select(.outcome == "failed")) | .[].nodeid' \ | |
| "${RESULTS}" > "${FAILED}" || true | |
| jq -r '.tests | map(select(.outcome == "passed")) | .[].nodeid' \ | |
| "${RESULTS}" > "${PASSED}" || true | |
| else | |
| : > "${FAILED}" | |
| : > "${PASSED}" | |
| fi | |
| echo "Failed tests:" | |
| cat "${FAILED}" || true | |
| echo "Passed tests:" | |
| cat "${PASSED}" || true | |
| - name: Upload macOS parallel test artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pr_${{ env.PR_ID }}_macos_parallel_results | |
| path: | | |
| artifacts/pr_${{ env.PR_ID }}/macos/all_tests.txt | |
| artifacts/pr_${{ env.PR_ID }}/macos/failed_tests.txt | |
| artifacts/pr_${{ env.PR_ID }}/macos/passed_tests.txt | |
| artifacts/pr_${{ env.PR_ID }}/macos/test_results.json | |
| retention-days: 7 | |
| - name: Run pytest with a single worker (for tests marked with needs_solo_run) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| export PYTHONPATH | |
| export LD_LIBRARY_PATH | |
| pytest \ | |
| @.github/workflows/pytest_args_ci.txt \ | |
| @.github/workflows/pytest_args_not_parallel.txt \ | |
| --junitxml=pytest.needs_solo_run.junit.xml \ | |
| -k 'not testsuite' | |
| - name: Run pytest with a single worker (for gunittest-based tests) | |
| shell: micromamba-shell {0} | |
| run: | | |
| PYTHONPATH="$(grass --config python_path):${PYTHONPATH}" | |
| LD_LIBRARY_PATH="$(grass --config path)/lib:${LD_LIBRARY_PATH}" | |
| export PYTHONPATH | |
| export LD_LIBRARY_PATH | |
| pytest \ | |
| @.github/workflows/pytest_args_gunittest.txt \ | |
| --junitxml=pytest.gunittest.junit.xml | |
| - name: Upload test results to Codecov | |
| if: ${{ !cancelled() }} | |
| uses: codecov/test-results-action@47f89e9acb64b76debcd5ea40642d25a4adced9f # v1.1.1 | |
| with: | |
| exclude: gui | |
| flags: macos-pytest-python | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Cache GRASS Sample Dataset | |
| id: cached-data | |
| uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| with: | |
| path: sample-data/nc_spm_full_v2alpha2.tar.gz | |
| key: nc_spm_full_v2alpha2.tar.gz | |
| enableCrossOsArchive: true | |
| - name: Download GRASS Sample Dataset | |
| if: steps.cached-data.outputs.cache-hit != 'true' | |
| run: | | |
| mkdir -p sample-data | |
| curl -L "$SAMPLE_DATA" -o sample-data/nc_spm_full_v2alpha2.tar.gz | |
| env: | |
| SAMPLE_DATA: "https://grass.osgeo.org/sampledata/north_carolina/\ | |
| nc_spm_full_v2alpha2.tar.gz" | |
| - name: Save GRASS Sample Dataset to cache | |
| uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 | |
| if: steps.cached-data.outputs.cache-hit != 'true' | |
| with: | |
| path: sample-data/nc_spm_full_v2alpha2.tar.gz | |
| key: nc_spm_full_v2alpha2.tar.gz | |
| - name: Run gunittest tests | |
| shell: micromamba-shell {0} | |
| run: .github/workflows/test_thorough.sh --config .github/workflows/macos_gunittest.cfg | |
| env: | |
| SAMPLE_DATA_URL: "file://${{ github.workspace }}/sample-data/\ | |
| nc_spm_full_v2alpha2.tar.gz" | |
| - name: Make HTML test report available | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: testreport-macOS | |
| path: testreport | |
| retention-days: 3 |