GitHub CI #7897
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: GitHub CI | |
| on: | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| revn: | |
| type: choice | |
| options: | |
| - 'candidate' | |
| - '261' | |
| - '252' | |
| - '251' | |
| - '242' | |
| - '241' | |
| description: 'The Mechanical revision number to run tests on.' | |
| default: '252' #stable version is 252, must match $stable_container | |
| schedule: | |
| - cron: '00 22 * * *' # UTC time, may start 5-15 mins later than scheduled time | |
| push: | |
| tags: | |
| - "*" | |
| branches: | |
| - main | |
| - release/* | |
| env: | |
| PYMECHANICAL_PORT: 10000 # default won't work on GitHub runners | |
| PYMECHANICAL_START_INSTANCE: false | |
| DOCKER_PACKAGE: ghcr.io/ansys/mechanical | |
| DOCKER_MECH_CONTAINER_NAME: mechanical | |
| PACKAGE_NAME: ansys-mechanical-core | |
| DOCUMENTATION_CNAME: mechanical.docs.pyansys.com | |
| MAIN_PYTHON_VERSION: '3.12' | |
| # DEV_REVN & its Docker image are used in scheduled or registry package runs | |
| STABLE_REVN: '252' | |
| DEV_REVN: '261' | |
| LICENSE_SERVER: ${{ secrets.LICENSE_SERVER }} | |
| ANSYSLMD_LICENSE_FILE: 1055@${{ secrets.LICENSE_SERVER }} | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| permissions: {} | |
| jobs: | |
| update-changelog: | |
| name: "Update CHANGELOG for new tag" | |
| if: github.event_name == 'push' && contains(github.ref, 'refs/tags') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # Needed to create changelog entries in repository | |
| pull-requests: write # Required to create pull requests for changelog updates | |
| steps: | |
| - uses: ansys/actions/doc-deploy-changelog@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| token: ${{ secrets.PYANSYS_CI_BOT_TOKEN }} | |
| bot-user: ${{ secrets.PYANSYS_CI_BOT_USERNAME }} | |
| bot-email: ${{ secrets.PYANSYS_CI_BOT_EMAIL }} | |
| style: | |
| name: Code style | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: PyAnsys code style checks | |
| uses: ansys/actions/code-style@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| python-version: ${{ env.MAIN_PYTHON_VERSION }} | |
| doc-style: | |
| name: Documentation Style Check | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: PyAnsys documentation style checks | |
| uses: ansys/actions/doc-style@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| check-vulnerabilities: | |
| name: Check Vulnerabilities | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: PyAnsys Vulnerability check (on main) | |
| if: github.ref == 'refs/heads/main' | |
| uses: ansys/actions/check-vulnerabilities@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| python-version: ${{ env.MAIN_PYTHON_VERSION }} | |
| python-package-name: ${{ env.PACKAGE_NAME }} | |
| token: ${{ secrets.PYANSYS_CI_BOT_TOKEN }} | |
| - name: PyAnsys Vulnerability check (on dev mode) | |
| if: github.ref != 'refs/heads/main' | |
| uses: ansys/actions/check-vulnerabilities@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| python-version: ${{ env.MAIN_PYTHON_VERSION }} | |
| python-package-name: ${{ env.PACKAGE_NAME }} | |
| token: ${{ secrets.PYANSYS_CI_BOT_TOKEN }} | |
| dev-mode: true | |
| check-actions-security: | |
| name: "Check Actions Security" | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: ansys/actions/check-actions-security@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| generate-summary: true | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| auditing-level: 'high' | |
| trust-ansys-actions: true | |
| smoke-tests: | |
| name: Build and Smoke tests | |
| runs-on: ${{ matrix.os }} | |
| needs: [style] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| python-version: ['3.10', '3.11', '3.12', '3.13'] | |
| should-release: | |
| - ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags') }} | |
| exclude: | |
| - should-release: false | |
| os: macos-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Build wheelhouse and perform smoke test | |
| uses: ansys/actions/build-wheelhouse@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| library-name: ${{ env.PACKAGE_NAME }} | |
| operating-system: ${{ matrix.os }} | |
| python-version: ${{ matrix.python-version }} | |
| revn-variations: | |
| name: Save variations of revn | |
| runs-on: ubuntu-latest | |
| outputs: | |
| stable_container: ${{ steps.save-versions.outputs.stable_container }} | |
| test_revn: '${{ steps.save-versions.outputs.test_revn }}' | |
| test_container: ${{ steps.save-versions.outputs.test_container }} | |
| test_docker_image_version: '${{ steps.save-versions.outputs.test_docker_image_version }}' | |
| permissions: | |
| contents: read | |
| steps: | |
| - id: save-versions | |
| env: | |
| GH_EVENT_NAME: ${{ github.event_name }} | |
| REVN_INPUT: ${{ github.event.inputs.revn }} | |
| DEV_REVN: ${{ env.DEV_REVN }} | |
| DOCKER_PACKAGE: ${{ env.DOCKER_PACKAGE }} | |
| STABLE_REVN: ${{ env.STABLE_REVN }} | |
| run: | | |
| # --- Help ---- | |
| # schedule nightly uses DEV_REVN candidate | |
| # PRs and merges use STABLE_REVN | |
| # Workflow dispatch can use any revision number | |
| if [[ "${GH_EVENT_NAME}" == "schedule" ]] || [[ "${REVN_INPUT}" == "candidate" ]]; then | |
| echo "test_revn=${DEV_REVN}" >> $GITHUB_OUTPUT | |
| test_mech_revn=${DEV_REVN} | |
| test_mech_image_version=${test_mech_revn:0:2}.${test_mech_revn:2}_candidate | |
| echo "test_container=${DOCKER_PACKAGE}:$test_mech_image_version" >> $GITHUB_OUTPUT | |
| echo "test_docker_image_version=$test_mech_image_version" >> $GITHUB_OUTPUT | |
| else | |
| if [[ -z "${REVN_INPUT}" ]]; then | |
| mech_revn=${STABLE_REVN} | |
| else | |
| mech_revn=${REVN_INPUT} | |
| fi | |
| export mech_image_version=${mech_revn:0:2}.${mech_revn:2}.0 | |
| echo "test_revn=$mech_revn" >> $GITHUB_OUTPUT | |
| echo "test_container=${DOCKER_PACKAGE}:$mech_image_version" >> $GITHUB_OUTPUT | |
| echo "test_docker_image_version=$mech_image_version" >> $GITHUB_OUTPUT | |
| fi | |
| stable_mech_revn=${STABLE_REVN} | |
| stable_mech_image_version=${mech_revn:0:2}.${mech_revn:2}.0 | |
| echo "stable_container=${DOCKER_PACKAGE}:$stable_mech_image_version" >> $GITHUB_OUTPUT | |
| test-container-info: | |
| name: Get SHA of test container | |
| runs-on: public-ubuntu-latest-8-cores | |
| needs: [revn-variations] | |
| outputs: | |
| sha: ${{ steps.get_sha.outputs.sha }} | |
| strategy: | |
| matrix: | |
| test_container: ['${{ needs.revn-variations.outputs.test_container }}'] | |
| permissions: | |
| packages: read # Required to pull Docker images from GitHub Container Registry | |
| steps: | |
| - name: Login in Github Container registry | |
| uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Pull, launch, and validate Mechanical service | |
| id: get_sha | |
| env: | |
| MECHANICAL_IMAGE: ${{ matrix.test_container }} | |
| run: | | |
| # Install jq for parsing JSON | |
| pip install jq | |
| # Get docker info | |
| image_info=$(docker manifest inspect -v ${MECHANICAL_IMAGE}) # --format ".Descriptor.digest" | |
| # Get digest SHA | |
| digest=$(echo "$image_info" | jq -r '.Descriptor.digest') | |
| # Remove the "sha256:" prefix to get only the SHA | |
| sha="${digest#*:}" | |
| echo "SHA of image ${MECHANICAL_IMAGE} is $sha" | |
| echo "sha=$sha" >> $GITHUB_OUTPUT | |
| config-matrix: | |
| name: Configure matrix | |
| runs-on: ubuntu-latest | |
| needs: [revn-variations] | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - id: set-matrix | |
| env: | |
| GH_EVENT_NAME: ${{ github.event_name }} | |
| TEST_DOCKER_IMAGE_VERSION: ${{ needs.revn-variations.outputs.test_docker_image_version }} | |
| GH_REF: ${{ github.ref }} | |
| run: | | |
| # if a tag(release) is pushed, test all versions | |
| if [[ "${GH_EVENT_NAME}" == "push" ]] && [[ "$GH_REF" =~ "refs/tags" ]]; then | |
| echo "matrix={\"mechanical-version\":['24.1.0', '24.2.0', '25.1.0', '25.2.0'],\"experimental\":[false]}" >> $GITHUB_OUTPUT | |
| else | |
| echo "matrix={\"mechanical-version\":['${TEST_DOCKER_IMAGE_VERSION}'],\"experimental\":[false]}" >> $GITHUB_OUTPUT | |
| fi | |
| container-stability-check: | |
| name: Container stability check | |
| runs-on: ubuntu-latest | |
| needs: [revn-variations] | |
| outputs: | |
| container_stable_exit: ${{ steps.check_stability.outputs.container_stable_exit }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - id: check_stability | |
| env: | |
| TEST_DOCKER_IMAGE_VERSION: ${{ needs.revn-variations.outputs.test_docker_image_version }} | |
| run: | | |
| sudo apt update | |
| sudo apt install bc -y | |
| container_version=$(echo "${TEST_DOCKER_IMAGE_VERSION}" | grep -o -E '[0-9]+(\.[0-9]+)?' | head -n 1) | |
| if (( $(echo "$container_version > 24.2" | bc -l) )); then | |
| echo "container_stable_exit=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "container_stable_exit=false" >> $GITHUB_OUTPUT | |
| fi | |
| remote-connect: | |
| name: Remote connect testing and coverage - Mechanical ${{ matrix.mechanical-version }} | |
| runs-on: public-ubuntu-latest-16-cores | |
| needs: [style, revn-variations, config-matrix] | |
| continue-on-error: ${{ matrix.experimental }} | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJSON(needs.config-matrix.outputs.matrix) }} | |
| permissions: | |
| contents: read | |
| packages: read # Required to pull Docker images from GitHub Container Registry | |
| checks: write # Needed to publish test results and status checks | |
| steps: | |
| - name: Login in Github Container registry | |
| uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Pull, launch, and validate Mechanical service | |
| env: | |
| MECHANICAL_IMAGE: ${{ env.DOCKER_PACKAGE }}:${{ matrix.mechanical-version }} | |
| # ANSYS_WORKBENCH_LOGGING_CONSOLE: 0 | |
| # ANSYS_WORKBENCH_LOGGING_DIRECTORY: /log_file # workbench.log file | |
| ANSYS_WORKBENCH_LOGGING_AUTO_FLUSH: 0 # turn off autoflush for faster performance | |
| DOCKER_MECH_CONTAINER_NAME: ${{ env.DOCKER_MECH_CONTAINER_NAME }} | |
| LICENSE_SERVER: ${{ env.LICENSE_SERVER }} | |
| PYMECHANICAL_PORT: ${{ env.PYMECHANICAL_PORT }} | |
| run: | | |
| docker pull ${MECHANICAL_IMAGE} | |
| echo "Run docker in detached mode" | |
| docker run -d --name ${DOCKER_MECH_CONTAINER_NAME} -e ANSYSLMD_LICENSE_FILE=1055@${LICENSE_SERVER} -p ${PYMECHANICAL_PORT}:10000 ${MECHANICAL_IMAGE} | |
| # Wait for Mechanical to initialize with intelligent polling | |
| max_wait=300 # Maximum wait time in seconds | |
| check_interval=10 # Check every 10 seconds | |
| elapsed=0 | |
| echo "Waiting for Mechanical to initialize..." | |
| while [ $elapsed -lt $max_wait ]; do | |
| docker logs ${DOCKER_MECH_CONTAINER_NAME} > log.txt | |
| if grep -q 'WB Initialize Done' log.txt 2>/dev/null; then | |
| echo "Mechanical initialized successfully after ${elapsed} seconds" | |
| break | |
| fi | |
| echo "Waiting for initialization... (${elapsed}/${max_wait}s)" | |
| sleep $check_interval | |
| elapsed=$((elapsed + check_interval)) | |
| done | |
| # Final check | |
| docker logs ${DOCKER_MECH_CONTAINER_NAME} > log.txt | |
| if ! grep -q 'WB Initialize Done' log.txt 2>/dev/null; then | |
| echo "ERROR: Mechanical failed to initialize within ${max_wait} seconds" | |
| echo "=== Last 50 lines of log.txt ===" | |
| tail -n 50 log.txt || echo "No log file found" | |
| exit 1 | |
| fi | |
| - name: Display info | |
| if: github.event_name == 'schedule' | |
| id: capture_info | |
| env: | |
| DOCKER_PACKAGE: ${{ env.DOCKER_PACKAGE }} | |
| MECH_VERSION: ${{ matrix.mechanical-version }} | |
| TEST_REVN: ${{ needs.revn-variations.outputs.test_revn }} | |
| run: | | |
| IMAGE_NAME=${DOCKER_PACKAGE}:${MECH_VERSION} | |
| BUILD_DATE=$(docker run --rm --entrypoint head $IMAGE_NAME -n 1 /install/ansys_inc/v${TEST_REVN}/aisol/CommonFiles/builddate.txt) | |
| PUSHED_AT=$(docker inspect --format='{{.Created}}' $IMAGE_NAME) | |
| echo "docker_info=$IMAGE_NAME was pushed at: $PUSHED_AT" >> $GITHUB_OUTPUT | |
| echo "::group::Docker Info" | |
| echo "docker_info=$PUSHED_AT" >> $GITHUB_OUTPUT | |
| echo "build_info=$BUILD_DATE" >> $GITHUB_OUTPUT | |
| echo "$IMAGE_NAME pushed at $PUSHED_AT" | |
| echo "Build date : $BUILD_DATE" | |
| echo "::endgroup::" | |
| - name: Testing | |
| uses: ansys/actions/tests-pytest@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| python-version: ${{ env.MAIN_PYTHON_VERSION }} | |
| pytest-markers: '-m remote_session_connect' | |
| pytest-extra-args: '-s --junitxml remote_results${{ env.MAIN_PYTHON_VERSION }}.xml' | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@e08919a3b1fb83a78393dfb775a9c37f17d8eea6 # v6.0.1 | |
| if: always() | |
| with: | |
| report_paths: '**/remote_results*.xml' | |
| check_name: Remote Connect Test Report ${{ matrix.python-version }} | |
| detailed_summary: true | |
| include_passed: true | |
| fail_on_failure: true | |
| - name: Upload coverage results | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: matrix.mechanical-version == needs.revn-variations.outputs.test_docker_image_version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-tests | |
| path: .cov | |
| retention-days: 7 | |
| - name: Upload coverage results (as .coverage) | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: matrix.mechanical-version == needs.revn-variations.outputs.test_docker_image_version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-file-tests | |
| path: .coverage | |
| retention-days: 7 | |
| - name: Get Mechanical container logs | |
| if: always() | |
| run: | # zizmor: ignore[template-injection] | |
| docker logs ${{ env.DOCKER_MECH_CONTAINER_NAME }} > mechanical_tests_log-${{ matrix.mechanical-version }}.txt 2>&1 | |
| echo CONTAINER LOGS OUTPUT | |
| cat mechanical_tests_log-${{ matrix.mechanical-version }}.txt | |
| echo CPU info | |
| lscpu | |
| - name: Upload container logs | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| name: mechanical_tests_log-${{ matrix.mechanical-version }} | |
| path: mechanical_tests_log-${{ matrix.mechanical-version }}.txt | |
| retention-days: 7 | |
| embedding-tests: | |
| name: Embedding testing and coverage | |
| runs-on: public-ubuntu-latest-16-cores | |
| timeout-minutes: 30 | |
| needs: [revn-variations, test-container-info, container-stability-check, smoke-tests] | |
| container: | |
| image: ${{ needs.revn-variations.outputs.test_container }} # zizmor: ignore[unpinned-images] | |
| options: --entrypoint /bin/bash | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13'] | |
| permissions: | |
| contents: read | |
| packages: read # Required to pull Docker images from GitHub Container Registry | |
| checks: write # Needed to publish test results and status checks | |
| steps: | |
| - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| shell: bash | |
| env: | |
| MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} | |
| run: | | |
| apt update | |
| apt install lsb-release xvfb git curl make -y | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| export PATH="$HOME/.local/bin:$PATH" | |
| uv python install python${MAIN_PYTHON_VERSION} | |
| uv venv /env | |
| - name: "Install packages for testing" | |
| run: | | |
| . /env/bin/activate | |
| uv pip install --upgrade pip | |
| uv pip install -e .[tests] | |
| - name: Unit Testing and coverage | |
| env: | |
| ANSYS_WORKBENCH_LOGGING_CONSOLE: 0 | |
| ANSYS_WORKBENCH_LOGGING: 0 | |
| ANSYS_WORKBENCH_LOGGING_FILTER_LEVEL: 2 | |
| CONTAINER_STABLE_EXIT: ${{ needs.container-stability-check.outputs.container_stable_exit }} | |
| MATRIX_PYTHON_VERSION: ${{ matrix.python-version }} | |
| NUM_CORES: 1 | |
| PYTHONUNBUFFERED: 1 | |
| run: | | |
| . /env/bin/activate | |
| if [ "${CONTAINER_STABLE_EXIT}" = "true" ]; then | |
| xvfb-run mechanical-env pytest -m embedding -s --junitxml test_results${MATRIX_PYTHON_VERSION}.xml | |
| else | |
| xvfb-run mechanical-env pytest -m embedding -s --junitxml test_results${MATRIX_PYTHON_VERSION}.xml || true | |
| fi | |
| - name: Upload coverage results | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: env.MAIN_PYTHON_VERSION == matrix.python-version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-tests-embedding | |
| path: .cov | |
| retention-days: 7 | |
| - name: Upload coverage results (as .coverage) | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: env.MAIN_PYTHON_VERSION == matrix.python-version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-file-tests-embedding | |
| path: .coverage | |
| retention-days: 7 | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@e08919a3b1fb83a78393dfb775a9c37f17d8eea6 # v6.0.1 | |
| if: always() | |
| with: | |
| report_paths: '**/test_results*.xml' | |
| check_name: Test Report ${{ matrix.python-version }} | |
| detailed_summary: true | |
| include_passed: true | |
| fail_on_failure: true | |
| embedding-scripts-tests: | |
| name: Embedding scripts testing and coverage | |
| runs-on: public-ubuntu-latest-16-cores | |
| timeout-minutes: 30 | |
| needs: [smoke-tests, revn-variations, test-container-info] | |
| container: | |
| image: ${{ needs.revn-variations.outputs.test_container }} # zizmor: ignore[unpinned-images] | |
| options: --entrypoint /bin/bash | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13'] | |
| permissions: | |
| contents: read | |
| packages: read # Required to pull Docker images from GitHub Container Registry | |
| checks: write # Needed to publish test results and status checks | |
| steps: | |
| - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| shell: bash | |
| env: | |
| MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} | |
| run: | | |
| apt update | |
| apt install lsb-release xvfb git curl make -y | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| export PATH="$HOME/.local/bin:$PATH" | |
| uv python install python${MAIN_PYTHON_VERSION} | |
| uv venv /env | |
| - name: "Install packages for testing" | |
| run: | | |
| . /env/bin/activate | |
| uv pip install --upgrade pip | |
| uv pip install -e .[tests] | |
| - name: Embedding scripts unit testing and coverage | |
| env: | |
| ANSYS_WORKBENCH_LOGGING_CONSOLE: 0 | |
| ANSYS_WORKBENCH_LOGGING: 0 | |
| ANSYS_WORKBENCH_LOGGING_FILTER_LEVEL: 2 | |
| MATRIX_PYTHON_VERSION: ${{ matrix.python-version }} | |
| NUM_CORES: 1 | |
| PYTHONUNBUFFERED: 1 | |
| run: | | |
| . /env/bin/activate | |
| mechanical-env pytest -m embedding_scripts -s --junitxml test_results_embedding_scripts${MAIN_PYTHON_VERSION}.xml | |
| pytest -m cli -s --junitxml test_results_cli_scripts${MAIN_PYTHON_VERSION}.xml | |
| - name: Upload coverage results | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: env.MAIN_PYTHON_VERSION == matrix.python-version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-tests-embedding-scripts | |
| path: .cov | |
| retention-days: 7 | |
| - name: Upload coverage results (as .coverage) | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: env.MAIN_PYTHON_VERSION == matrix.python-version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-file-tests-embedding-scripts | |
| path: .coverage | |
| retention-days: 7 | |
| - name: Publish Test Report | |
| uses: mikepenz/action-junit-report@e08919a3b1fb83a78393dfb775a9c37f17d8eea6 # v6.0.1 | |
| if: always() | |
| with: | |
| report_paths: '**/test_results*.xml' | |
| check_name: Test Report ${{ matrix.python-version }} | |
| detailed_summary: true | |
| include_passed: true | |
| fail_on_failure: true | |
| launch-tests: | |
| name: Launch testing and coverage | |
| runs-on: public-ubuntu-latest-16-cores | |
| timeout-minutes: 30 | |
| container: | |
| image: ${{ needs.revn-variations.outputs.test_container }} # zizmor: ignore[unpinned-images] | |
| options: --entrypoint /bin/bash | |
| needs: [ style, revn-variations, container-stability-check, test-container-info] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13'] | |
| permissions: | |
| contents: read | |
| packages: read # Required to pull Docker images from GitHub Container Registry | |
| checks: write # Needed to publish test results and status checks | |
| steps: | |
| - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| shell: bash | |
| env: | |
| MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} | |
| run: | | |
| apt update | |
| apt install lsb-release xvfb git curl make -y | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| export PATH="$HOME/.local/bin:$PATH" | |
| uv python install python${MAIN_PYTHON_VERSION} | |
| uv venv /env | |
| - name: "Install packages for testing" | |
| run: | | |
| . /env/bin/activate | |
| uv pip install --upgrade pip | |
| uv pip install -e .[tests] | |
| - name: Set environment variable | |
| env: | |
| TEST_REVN: ${{ needs.revn-variations.outputs.test_revn }} | |
| run: echo "ANSYSCL${TEST_REVN}_DIR=/install/ansys_inc/v${TEST_REVN}/licensingclient" >> $GITHUB_ENV | |
| - name: Unit Testing and coverage | |
| env: | |
| ANSYS_WORKBENCH_LOGGING_CONSOLE: 0 | |
| CONTAINER_STABLE_EXIT: ${{ needs.container-stability-check.outputs.container_stable_exit }} | |
| MATRIX_PYTHON_VERSION: ${{ matrix.python-version }} | |
| run: | | |
| unset PYMECHANICAL_PORT | |
| unset PYMECHANICAL_START_INSTANCE | |
| . /env/bin/activate | |
| if [ "${CONTAINER_STABLE_EXIT}" = "true" ]; then | |
| pytest -m remote_session_launch -s --junitxml launch_test_results${MATRIX_PYTHON_VERSION}.xml | |
| else | |
| pytest -m remote_session_launch -s --junitxml launch_test_results${MATRIX_PYTHON_VERSION}.xml || true | |
| fi | |
| - name: Publish Launch Test Report | |
| uses: mikepenz/action-junit-report@e08919a3b1fb83a78393dfb775a9c37f17d8eea6 # v6.0.1 | |
| if: always() | |
| with: | |
| report_paths: '**/launch_test_results*.xml' | |
| check_name: Launch Test Report ${{ matrix.python-version }} | |
| detailed_summary: true | |
| include_passed: true | |
| fail_on_failure: true | |
| - name: Upload coverage results | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: env.MAIN_PYTHON_VERSION == matrix.python-version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-tests-remote-session-launch | |
| path: .cov | |
| retention-days: 7 | |
| - name: Upload coverage results (as .coverage) | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| if: env.MAIN_PYTHON_VERSION == matrix.python-version | |
| with: | |
| include-hidden-files: true | |
| name: coverage-file-tests-remote-session-launch | |
| path: .coverage | |
| retention-days: 7 | |
| doc-build: | |
| name: Documentation | |
| runs-on: public-ubuntu-latest-16-cores | |
| timeout-minutes: 30 | |
| container: | |
| image: ${{ needs.revn-variations.outputs.test_container }} # zizmor: ignore[unpinned-images] | |
| options: --entrypoint /bin/bash | |
| needs: [style, doc-style, revn-variations, container-stability-check, test-container-info] | |
| permissions: | |
| contents: read | |
| packages: read # Required to pull Docker images from GitHub Container Registry | |
| steps: | |
| - name: Install Git and checkout project | |
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| shell: bash | |
| env: | |
| MAIN_PYTHON_VERSION: ${{ env.MAIN_PYTHON_VERSION }} | |
| run: | | |
| apt update | |
| apt install lsb-release xvfb git curl make -y | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| export PATH="$HOME/.local/bin:$PATH" | |
| uv python install python${MAIN_PYTHON_VERSION} | |
| uv venv /env | |
| - name: Install system dependencies | |
| env: | |
| DEBIAN_FRONTEND: 'noninteractive' | |
| TZ: 'Etc/UTC' | |
| run: | | |
| apt update | |
| apt install make lsb-release xvfb poppler-utils -y | |
| apt install zip pandoc libgl1-mesa-glx mesa-utils texlive-latex-extra latexmk nodejs npm graphviz -y | |
| - name: Install gh cli | |
| run: | | |
| (type -p wget >/dev/null || (apt update && apt-get install wget -y)) \ | |
| && mkdir -p -m 755 /etc/apt/keyrings \ | |
| && wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \ | |
| && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ | |
| && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ | |
| && apt update \ | |
| && apt install gh -y | |
| - name: Install quarto to build cheatsheet | |
| run: | # zizmor: ignore[template-injection] | |
| echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token | |
| gh release download v1.6.43 --repo github.com/quarto-dev/quarto-cli --pattern *linux-amd64.deb | |
| apt install ./quarto*linux-amd64.deb -y | |
| quarto install tool tinytex --log-level warning | |
| - name: Test quarto installation | |
| run: quarto --version | |
| - name: Install Python requirements | |
| run: | | |
| . /env/bin/activate | |
| uv pip install --upgrade pip | |
| uv pip install -e .[doc] | |
| - name: Build docs | |
| env: | |
| NUM_CORES: 1 | |
| ANSYS_WORKBENCH_LOGGING_FILTER_LEVEL: 0 | |
| BUILD_CHEATSHEET: true | |
| CONTAINER_STABLE_EXIT: ${{ needs.container-stability-check.outputs.container_stable_exit }} | |
| run: | | |
| . /env/bin/activate | |
| apt update | |
| apt install -y libjbig-dev | |
| # Add the /usr/lib/x86_64-linux-gnu/ path to the LD_LIBRARY_PATH (where libjbig-dev .so files are) | |
| export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu/ | |
| if [ "${CONTAINER_STABLE_EXIT}" = "true" ]; then | |
| xvfb-run mechanical-env make -C doc html | |
| else | |
| xvfb-run mechanical-env make -C doc html > output.txt 2>&1 || true | |
| cat output.txt | |
| if grep -q "build succeeded" output.txt; then | |
| echo "Documentation building succeeded" | |
| else | |
| echo "Documentation building failed" | |
| exit 1 | |
| fi | |
| fi | |
| - name: Check links | |
| run: | | |
| . /env/bin/activate | |
| make -C doc linkcheck | |
| - name: Upload HTML Documentation | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| name: documentation-html | |
| path: doc/_build/html | |
| retention-days: 7 | |
| doc-deploy-pr: | |
| name: "Deploy PR documentation" | |
| runs-on: ubuntu-latest | |
| needs: [doc-build] | |
| if: always() && (needs.doc-build.result == 'success' || needs.doc-build.result == 'skipped') | |
| permissions: | |
| contents: write # Required to push documentation to gh-pages branch | |
| pull-requests: write # Needed to comment on PR with documentation link | |
| steps: | |
| - uses: ansys/actions/doc-deploy-pr@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| cname: ${{ env.DOCUMENTATION_CNAME }} | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| bot-user: ${{ secrets.PYANSYS_CI_BOT_USERNAME }} | |
| bot-email: ${{ secrets.PYANSYS_CI_BOT_EMAIL }} | |
| maximum-pr-doc-deployments: 10 | |
| coverage: | |
| name: Merging coverage | |
| needs: [remote-connect, embedding-tests, embedding-scripts-tests, launch-tests] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0 | |
| with: | |
| python-version: ${{ env.MAIN_PYTHON_VERSION }} | |
| - name: Install coverage | |
| run: | | |
| rm -rf ./env | |
| python -m pip install -U pip | |
| pip install coverage | |
| pip install -e . | |
| - name: Create common coverage directory | |
| run: mkdir cov-dir | |
| - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: coverage-file-tests-embedding | |
| path: cov-dir/embedding | |
| - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: coverage-file-tests-embedding-scripts | |
| path: cov-dir/embedding-scripts | |
| - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: coverage-file-tests-remote-session-launch | |
| path: cov-dir/launch | |
| - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: coverage-file-tests | |
| path: cov-dir/normal | |
| - name: Display structure of downloaded files | |
| run: ls -Ra | |
| - name: Move files to common location | |
| run: | | |
| mv cov-dir/embedding/.coverage .coverage.Embedding | |
| mv cov-dir/embedding-scripts/.coverage .coverage.EmbeddingScripts | |
| mv cov-dir/launch/.coverage .coverage.Launch | |
| mv cov-dir/normal/.coverage .coverage.Normal | |
| rm -rf cov-dir | |
| - name: Generate .coveragerc file | |
| run: | | |
| cat > .coveragerc << 'EOF' | |
| # .coveragerc to control coverage.py | |
| [run] | |
| relative_files = True | |
| [paths] | |
| source = | |
| src/ansys/mechanical | |
| /opt/hostedtoolcache/**/ansys/mechanical | |
| /usr/local/lib/**/ansys/mechanical | |
| .venv/lib/**/ansys/mechanical | |
| /env/lib/**/ansys/mechanical | |
| EOF | |
| - name: Run coverage merge and show results | |
| run: | | |
| coverage combine --keep --debug=pathmap --rcfile=.coveragerc | |
| coverage report | |
| coverage html -d .coverage-combined/html | |
| coverage xml -o .coverage-combined/xml | |
| - name: Upload combined coverage results | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| include-hidden-files: true | |
| name: combined-coverage-results | |
| path: .coverage-combined | |
| retention-days: 7 | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2 | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| with: | |
| files: .coverage-combined/xml | |
| - name: Upload coverage to Codacy | |
| uses: codacy/codacy-coverage-reporter-action@89d6c85cfafaec52c72b6c5e8b2878d33104c699 # v1.3.0 | |
| with: | |
| project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} | |
| coverage-reports: '.coverage-combined/xml' | |
| package: | |
| name: Package library | |
| needs: [smoke-tests, remote-connect, embedding-tests, embedding-scripts-tests, doc-build] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| attestations: write # Required to generate package attestations for security | |
| contents: read | |
| id-token: write # Needed for OIDC authentication when generating attestations | |
| steps: | |
| - name: Build library source and wheel artifacts | |
| uses: ansys/actions/build-library@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| library-name: ${{ env.PACKAGE_NAME }} | |
| python-version: ${{ env.MAIN_PYTHON_VERSION }} | |
| attest-provenance: true | |
| release: | |
| name: Release project to GitHub | |
| if: github.event_name == 'push' && contains(github.ref, 'refs/tags') | |
| needs: [package, update-changelog] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write # Required for OIDC authentication during release | |
| contents: write # Needed to create GitHub releases and upload assets | |
| steps: | |
| - name: Release to GitHub | |
| uses: ansys/actions/release-github@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| library-name: ${{ env.PACKAGE_NAME }} | |
| only-code: true | |
| release-pypi: | |
| name: Release project to PyPI | |
| if: github.event_name == 'push' && contains(github.ref, 'refs/tags') | |
| needs: [package, update-changelog] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write # Required for PyPI trusted publisher authentication | |
| contents: write # Needed to download release artifacts | |
| steps: | |
| - name: "Download the library artifacts from build-library step" | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: ${{ env.PACKAGE_NAME }}-artifacts | |
| path: ${{ env.PACKAGE_NAME }}-artifacts | |
| - name: "Upload artifacts to PyPI using trusted publisher" | |
| uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 | |
| with: | |
| repository-url: "https://upload.pypi.org/legacy/" | |
| print-hash: true | |
| packages-dir: ${{ env.PACKAGE_NAME }}-artifacts | |
| skip-existing: false | |
| upload_dev_docs: | |
| name: Upload dev documentation | |
| if: github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| needs: [package] | |
| permissions: | |
| contents: write # Required to push documentation to gh-pages branch | |
| steps: | |
| - name: Deploy the latest documentation | |
| uses: ansys/actions/doc-deploy-dev@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| cname: ${{ env.DOCUMENTATION_CNAME }} | |
| token: ${{ secrets.PYANSYS_CI_BOT_TOKEN }} | |
| bot-user: ${{ secrets.PYANSYS_CI_BOT_USERNAME }} | |
| bot-email: ${{ secrets.PYANSYS_CI_BOT_EMAIL }} | |
| upload_docs_release: | |
| name: Upload release documentation | |
| if: github.event_name == 'push' && contains(github.ref, 'refs/tags') | |
| runs-on: ubuntu-latest | |
| needs: [release] | |
| permissions: | |
| contents: write # Required to push stable documentation to gh-pages branch | |
| steps: | |
| - name: Deploy the stable documentation | |
| uses: ansys/actions/doc-deploy-stable@41f86da4c9ead510db9135e428e33df9cc6f92e1 # v10.2.3 | |
| with: | |
| cname: ${{ env.DOCUMENTATION_CNAME }} | |
| token: ${{ secrets.PYANSYS_CI_BOT_TOKEN }} | |
| bot-user: ${{ secrets.PYANSYS_CI_BOT_USERNAME }} | |
| bot-email: ${{ secrets.PYANSYS_CI_BOT_EMAIL }} | |
| get-date: | |
| name: Get date | |
| runs-on: ubuntu-latest | |
| outputs: | |
| date: ${{ steps.date.outputs.date }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Get current date | |
| id: date | |
| run: | | |
| echo "date=$(date --iso-8601)" >> $GITHUB_OUTPUT | |
| notify-on-failure: | |
| name: Notify on failure | |
| needs: [get-date, embedding-tests, embedding-scripts-tests, launch-tests, remote-connect, doc-build] | |
| if: github.event_name == 'schedule' && (failure() || cancelled()) | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write # Required for OIDC authentication with notification services | |
| contents: read | |
| steps: | |
| - name: Microsoft Teams Notification | |
| uses: skitionek/notify-microsoft-teams@11e40c38c3a629ae65a985b582eca4897b01e79e # v1.0.9 | |
| with: | |
| webhook_url: ${{ secrets.MSTEAMS_WEBHOOK }} | |
| # Message to send to Teams as a webhook notification in JSON Payload format | |
| raw: >- | |
| { | |
| "type": "message", | |
| "attachments": [ | |
| { | |
| "contentType": "application/vnd.microsoft.card.adaptive", | |
| "content": { | |
| "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", | |
| "type": "AdaptiveCard", | |
| "version": "1.0", | |
| "body": [ | |
| { | |
| "type": "TextBlock", | |
| "text": "**PyMechanical Nightly Run Failed on ${{ needs.get-date.outputs.date }}**\n\n[View details in GitHub Actions](https://github.com/ansys/pymechanical/actions/runs/${{ github.run_id }})", | |
| "wrap": true | |
| } | |
| ] | |
| } | |
| } | |
| ] | |
| } |