Skip to content

CI: Refact and extend CI/CD workflows to leverage ansys actions #22

CI: Refact and extend CI/CD workflows to leverage ansys actions

CI: Refact and extend CI/CD workflows to leverage ansys actions #22

Workflow file for this run

name: GitHub CI CD
on:
pull_request:
workflow_dispatch:
push:
tags:
- "*"
branches:
- main
env:
ANSYSLMD_LICENSE_FILE: ${{ format('1055@{0}', secrets.LICENSE_SERVER) }}
MAIN_PYTHON_VERSION: '3.10'
PACKAGE_NAME: 'PyAEDT'
DOCUMENTATION_CNAME: 'aedt.docs.pyansys.com'
MEILISEARCH_API_KEY: ${{ secrets.MEILISEARCH_API_KEY }}
MEILISEARCH_HOST_URL: ${{ vars.MEILISEARCH_HOST_URL }}
MEILISEARCH_PUBLIC_API_KEY: ${{ secrets.MEILISEARCH_PUBLIC_API_KEY }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
doc-style:
name: Documentation style check
runs-on: ubuntu-latest
steps:
- name: Check documentation style
uses: ansys/actions/doc-style@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
vale-config: "doc/.vale.ini"
vale-version: "2.29.6"
smoke-tests:
name: Build wheelhouse with target all and perform smoke tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
steps:
- name: Build wheelhouse and perform smoke test
uses: ansys/actions/build-wheelhouse@v4
with:
library-name: ${{ env.PACKAGE_NAME }}
operating-system: ${{ matrix.os }}
python-version: ${{ matrix.python-version }}
target: 'all'
- name: Import python package
run: |
python -c "import pyaedt; from pyaedt import __version__"
smoke-tests-with-install-target:
name: Build and smoke tests (${{ matrix.os }} | Python ${{ matrix.python-version }} | Target ${{ matrix.install_target}})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10', '3.11']
install_target: ['tests', 'dotnet', 'doc', 'doc-noexamples', 'full']
steps:
- name: "Install Git and clone project"
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: "Update pip and install the build and wheel libraries"
shell: bash
run: |
python -m pip install --upgrade pip build wheel
- name: "Install the library with specified install target"
shell: bash
run: |
python -m pip install .[${{ matrix.install_target }}]
- name: "Verify if importlib-metadata needs to be installed"
shell: bash
run: |
python_version="${{ matrix.python-version }}"
minor_python_version=$(echo "$python_version" | awk -F "." '{print $2}')
major_python_version=$(echo "$python_version" | awk -F "." '{print $1}')
if (( $(( $major_python_version == 3 )) )) && (( $(( $minor_python_version < 8 )) )); then
echo "needs_importlib_metadata=true" >> $GITHUB_ENV
elif (( $(( $major_python_version < 3 )) )); then
echo "needs_importlib_metadata=true" >> $GITHUB_ENV
else
echo "needs_importlib_metadata=false" >> $GITHUB_ENV
fi
- name: "Install importlib-metadata (only for Python <= 3.7)"
if: env.needs_importlib_metadata == 'true'
shell: bash
run: |
python -m pip install importlib-metadata
- name: "Verify pyaedt is properly installed and get its version number"
shell: bash
run: |
if [ ${{ env.needs_importlib_metadata }} == 'true' ]; then
version=$(python -c "import importlib_metadata; print(importlib_metadata.version('pyaedt'))")
else
version=$(python -c "import importlib.metadata as importlib_metadata; print(importlib_metadata.version('pyaedt'))")
fi
if [ -z "$version" ]; then
echo "Problem getting the library version"
exit 1;
else
echo "The library version is: $version";
fi;
echo "library_version=$version" >> $GITHUB_ENV
doc-build:
name: Documentation build without examples
runs-on: ubuntu-latest
needs: [doc-style]
steps:
- name: Install Git and checkout project
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}
- name: Update pip
run: |
pip install --upgrade pip
- name: Install pyaedt and documentation dependencies
run: |
pip install .[doc-noexamples]
- name: Retrieve PyAEDT version
id: version
run: |
echo "PYAEDT_VERSION=$(python -c 'from pyaedt import __version__; print(__version__)')" >> $GITHUB_OUTPUT
echo "PyAEDT version is: $(python -c "from pyaedt import __version__; print(__version__)")"
# TODO: Update this step once pyaedt-examples is ready
- name: Build documentation without examples
run: |
make -C doc clean
make -C doc html-noexamples
# Verify that sphinx generates no warnings
- name: Check for warnings
run: |
python doc/print_errors.py
- name: Upload HTML documentation without examples artifact
uses: actions/upload-artifact@v3
with:
name: documentation-no-examples-html
path: doc/_build/html
retention-days: 7
# # =================================================================================================
# # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv RUNNING ON SELF-HOSTED RUNNER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# # =================================================================================================
# doc-build-with-examples:
# name: Documentation build with examples
# # if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
# runs-on: [ self-hosted, Windows, pyaedt ]
# needs: [doc-style]
# timeout-minutes: 720
# steps:
# - name: Install Git and checkout project
# uses: actions/checkout@v4
# - name: Setup Python
# uses: actions/setup-python@v5
# with:
# python-version: ${{ env.MAIN_PYTHON_VERSION }}
# - name: Create virtual environment
# run: |
# python -m venv .venv
# .venv\Scripts\Activate.ps1
# python -m pip install pip -U
# python -m pip install wheel setuptools -U
# python -c "import sys; print(sys.executable)"
# - name: Install pyaedt and documentation dependencies
# run: |
# .venv\Scripts\Activate.ps1
# pip install .[doc]
# - name: Retrieve PyAEDT version
# id: version
# run: |
# .venv\Scripts\Activate.ps1
# echo "PYAEDT_VERSION=$(python -c 'from pyaedt import __version__; print(__version__)')" >> $GITHUB_OUTPUT
# echo "PyAEDT version is: $(python -c "from pyaedt import __version__; print(__version__)")"
# - name: Uninstall conflicting CI packages
# run: |
# .venv\Scripts\Activate.ps1
# pip uninstall vtk -y
# - name: Install CI related dependencies
# run: |
# .venv\Scripts\Activate.ps1
# pip install --extra-index-url https://wheels.vtk.org .[ci]
# # TODO: Update this step once pyaedt-examples is ready
# # NOTE: Use environment variable to keep the doctree and avoid redundant build for PDF pages
# - name: Build HTML documentation with examples
# env:
# SPHINXBUILD_KEEP_DOCTREEDIR: "1"
# run: |
# .venv\Scripts\Activate.ps1
# .\doc\make.bat clean
# .\doc\make.bat html
# - name: Upload HTML documentation with examples artifact
# uses: actions/upload-artifact@v3
# with:
# name: documentation-examples-html
# path: doc/_build/html
# retention-days: 7
# # TODO: Keeping this commented as reminder of https://github.com/ansys/pyaedt/issues/4296
# # # Verify that sphinx generates no warnings
# # - name: Check for warnings
# # run: |
# # .venv\Scripts\Activate.ps1
# # python doc/print_errors.py
# # # Use environment variable to remove the doctree after the build of PDF pages
# # - name: Build PDF documentation with examples
# # env:
# # SPHINXBUILD_KEEP_DOCTREEDIR: "0"
# # run: |
# # .venv\Scripts\Activate.ps1
# # .\doc\make.bat pdf
# # - name: Upload PDF documentation with examples artifact
# # uses: actions/upload-artifact@v3
# # with:
# # name: documentation-pdf
# # path: doc/_build/latex/*.pdf
# # retention-days: 7
# # =================================================================================================
# # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv RUNNING ON SELF-HOSTED RUNNER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# # =================================================================================================
test-solvers-windows:
name: Testing solvers and coverage (Windows)
needs: [smoke-tests]
runs-on: [ self-hosted, Windows, pyaedt ]
steps:
- name: Install Git and checkout project
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}
- name: Create virtual environment
run: |
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install pip -U
python -m pip install wheel setuptools -U
python -c "import sys; print(sys.executable)"
- name: Install pyaedt and tests dependencies
run: |
.venv\Scripts\Activate.ps1
pip install .[tests]
- name: Install CI dependencies (e.g. vtk-osmesa)
run: |
.venv\Scripts\Activate.ps1
# Uninstall conflicting dependencies
pip uninstall vtk -y
pip install --extra-index-url https://wheels.vtk.org .[ci]
- name: 'Unit testing'
uses: nick-fields/retry@v3
env:
PYTHONMALLOC: malloc
with:
max_attempts: 3
retry_on: error
timeout_minutes: 40
command: |
.venv\Scripts\Activate.ps1
pytest --durations=50 -v --cov=pyaedt --cov-report=xml --cov-report=html --junitxml=junit/test-results.xml _unittest_solvers
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
name: codecov-system-solver-tests
file: ./coverage.xml
flags: system,solver
- name: Upload pytest test results
uses: actions/upload-artifact@v3
with:
name: pytest-solver-results
path: junit/test-results.xml
if: ${{ always() }}
# # =================================================================================================
# # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv RUNNING ON SELF-HOSTED RUNNER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# # =================================================================================================
test-windows:
name: Testing and coverage (Windows)
needs: [smoke-tests]
runs-on: [ self-hosted, Windows, pyaedt ]
steps:
- name: Install Git and checkout project
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}
- name: Create virtual environment
run: |
python -m venv .venv
.venv\Scripts\Activate.ps1
python -m pip install pip -U
python -m pip install wheel setuptools -U
python -c "import sys; print(sys.executable)"
- name: Install pyaedt and tests dependencies
run: |
.venv\Scripts\Activate.ps1
pip install .[tests]
- name: Install CI dependencies (e.g. vtk-osmesa)
run: |
.venv\Scripts\Activate.ps1
# Uninstall conflicting dependencies
pip uninstall vtk -y
pip install --extra-index-url https://wheels.vtk.org .[ci]
- name: 'Unit testing'
uses: nick-fields/retry@v3
env:
PYTHONMALLOC: malloc
with:
max_attempts: 3
retry_on: error
timeout_minutes: 40
command: |
.venv\Scripts\Activate.ps1
pytest -n auto --dist loadfile --durations=50 -v --cov=pyaedt --cov-report=xml --cov-report=html --junitxml=junit/test-results.xml _unittest
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
name: codecov-system-tests
file: ./coverage.xml
flags: system
- name: Upload pytest test results
uses: actions/upload-artifact@v3
with:
name: pytest-results
path: junit/test-results.xml
if: ${{ always() }}
# # =================================================================================================
# # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv RUNNING ON SELF-HOSTED RUNNER vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# # =================================================================================================
test-ironpython-windows:
name: Testing and coverage (Windows)
needs: [smoke-tests]
runs-on: [ self-hosted, Windows, pyaedt ]
steps:
- uses: actions/checkout@v4
- name: Run Ironpython tests
timeout-minutes: 5
run: |
$processA = start-process 'cmd' -ArgumentList '/c .\_unittest_ironpython\run_unittests_batchmode.cmd' -PassThru
$processA.WaitForExit()
- name: Get log content
run: |
get-content .\_unittest_ironpython\pyaedt_unit_test_ironpython.log
- name: Check for errors
run: |
$test_errors_failures = Select-String -Path .\_unittest_ironpython\pyaedt_unit_test_ironpython.log -Pattern "TextTestResult errors="
if ($test_errors_failures -ne $null)
{
exit 1
}
package:
name: Package library
needs: [test-windows, test-solvers-windows, test-ironpython-windows, doc-build]
runs-on: ubuntu-latest
steps:
- name: Build library source and wheel artifacts
uses: ansys/actions/build-library@v4
with:
library-name: ${{ env.PACKAGE_NAME }}
python-version: ${{ env.MAIN_PYTHON_VERSION }}
release:
name: Release project
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
needs: [package]
runs-on: ubuntu-latest
steps:
- name: Release to the public PyPI repository
uses: ansys/actions/release-pypi-public@v4
with:
library-name: ${{ env.PACKAGE_NAME }}
twine-username: "__token__"
twine-token: ${{ secrets.PYPI_TOKEN }}
# TODO: Uncomment once PDF file generation is fixed in CICD
# - name: Release to GitHub
# uses: ansys/actions/release-github@v4
# with:
# library-name: ${{ env.PACKAGE_NAME }}
- name: "Download all artifacts that got generated in the CI/CD"
uses: actions/download-artifact@v3
with:
path: /tmp/artifacts
- name: "Generate a distribution folder that will contain the desired artifacts"
shell: bash
run: mkdir -p dist
- name: "Moving documentation artifacts to dist/documentation directory"
shell: bash
run: |
mkdir -p dist/documentation
mv /tmp/artifacts/documentation-html dist/documentation/documentation-html
- name: "Compressing HTML documentation"
uses: vimtor/[email protected]
with:
files: dist/documentation/documentation-html
dest: dist/documentation/documentation-html.zip
- name: "Move wheelhouse artifacts to dist/wheelhouse directory"
shell: bash
run: |
mkdir -p dist/wheelhouse
mv /tmp/artifacts/**/*-wheelhouse-*.zip dist/wheelhouse/
- name: "Move wheel artifacts to dist/${{ env.PACKAGE_NAME }}-artifacts directory"
shell: bash
run: |
mv /tmp/artifacts/${{ env.PACKAGE_NAME }}-artifacts dist/${{ env.PACKAGE_NAME }}-artifacts
- name: "Display the structure of the 'dist/' folder"
shell: bash
run: ls -R dist/
- name: "Release to GitHub"
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: false
generate_release_notes: true 
files: |
# Include wheel and source distribution artifacts
dist/${{ inputs.library-name }}-artifacts/*.whl
dist/${{ inputs.library-name }}-artifacts/*.tar.gz
# Include wheelhouse artifacts
dist/wheelhouse/**/*-wheelhouse-*.zip
# Include HTML documentation artifacts
dist/documentation/documentation-html.zip
upload-dev-doc:
name: Upload dev documentation
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
needs: [package]
steps:
- name: Deploy the latest documentation
uses: ansys/actions/doc-deploy-dev@v4
with:
cname: ${{ env.DOCUMENTATION_CNAME }}
token: ${{ secrets.GITHUB_TOKEN }}
doc-artifact-name: 'documentation-no-examples-html'
doc-index-dev:
name: "Deploy dev index docs"
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
needs: upload-dev-doc
steps:
- name: "Deploy the latest documentation index"
uses: ansys/actions/doc-deploy-index@v4
with:
cname: ${{ env.DOCUMENTATION_CNAME }}/version/dev
index-name: pyaedt-vdev
host-url: ${{ env.MEILISEARCH_HOST_URL }}
api-key: ${{ env.MEILISEARCH_API_KEY }}
python-version: ${{ env.MAIN_PYTHON_VERSION }}
upload-release-doc:
name: Upload release documentation
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
runs-on: ubuntu-latest
needs: [release]
steps:
- name: Deploy the stable documentation
uses: ansys/actions/doc-deploy-stable@v4
with:
cname: ${{ env.DOCUMENTATION_CNAME }}
token: ${{ secrets.GITHUB_TOKEN }}
doc-artifact-name: 'documentation-examples-html'
doc-index-stable:
name: "Deploy stable docs index"
runs-on: ubuntu-latest
needs: upload-release-doc
steps:
- name: "Install Git and clone project"
uses: actions/checkout@v4
- name: "Install the package requirements"
run: pip install -e .
- name: "Get the version to PyMeilisearch"
run: |
VERSION=$(python -c "from pyaedt import __version__; print('.'.join(__version__.split('.')[:2]))")
VERSION_MEILI=$(python -c "from pyaedt import __version__; print('-'.join(__version__.split('.')[:2]))")
echo "Calculated VERSION: $VERSION"
echo "Calculated VERSION_MEILI: $VERSION_MEILI"
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "VERSION_MEILI=$VERSION_MEILI" >> $GITHUB_ENV
- name: "Deploy the latest documentation index"
uses: ansys/actions/doc-deploy-index@v4
with:
cname: ${{ env.DOCUMENTATION_CNAME }}/version/${{ env.VERSION }}
index-name: pyaedt-v${{ env.VERSION_MEILI }}
host-url: ${{ env.MEILISEARCH_HOST_URL }}
api-key: ${{ env.MEILISEARCH_API_KEY }}
python-version: ${{ env.MAIN_PYTHON_VERSION }}