Using continuous integration#
Continuous Integration (CI) is the process of merging new changes into the main code base while ensuring that these changes are functional and do not break the existing logic.
This process is automated as much as possible to alleviate the developer’s workload and ensure a quick development workflow.
Because PyAnsys
projects are hosted in GitHub, the
GitHub Actions framework is used.
Enable GitHub actions#
By default, Actions
are enabled in new repositories and can be accessed
using the associated GitHub repository sections.
If Actions
are not enabled, you can enable them by changing Actions
Permissions
in Settings -> Actions -> General
.
Use GitHub actions#
Actions to be executed in the CI process must be declared in a YML
and
stored in the .github/workflows/
directory. Although each action is
different, they all have a common structure:
A
name
identifying the action.A collection of
triggering events
that run the action when required.A collection of
concurrent
workflows conditions to, for example, avoid running several workflows for the same branch. (Multiple consecutive pushes could lead to multiple ongoing workflows when you want only the last push to run).A collection of
jobs
with different steps to follow during the CI process.
name: <Name of the action>
on:
<Trigering events and conditions>
concurrency:
<Avoid concurrent workflows to be run>
jobs:
<All jobs must be defined below this line>
Disable concurrent workflows#
Handling hardware resources is a big deal, especially when running with self-hosted agents. Also, if you are using public GitHub hardware for running your workflows, you should try to care about the environment and sustainability.
Disabling concurrent CI workflows is a good way to do so. For example, imagine the following situation:
You push some changes to your branch.
The CI workflow kicks in and starts executing the different stages.
You suddenly realize that there is a typo/file missing.
You push the new commit to your PR.
A new CI workflow kicks in and starts running.
At this moment, you probably have two parallel workflows running at the same time, though you are only interested in the results from the last one.
One way to solve this is manually cancelling the oldest workflow. However, it is also possible to
automatically cancel pre-existing workflows for a certain branch/PR. To do so, prior to the
jobs
section, you should add the following lines to your workflow:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Required workflows#
These workflows are required for any PyAnsys
project:
Coding style workflow
Documentation style, Build documentation, and Deploying documentation Workflows
Testing and Test code coverage workflows
Releasing and publishing workflow
You should collect all workflows under a common
ci.yml
file. For more information, see Workflow examples.
Parametrize workflows#
It is important to test a PyAnsys
library on different operating systems
using different Python versions:
The most common operating systems are Windows
, macOS
, and Linux
. For
Python versions, see Supporting Python versions.
Because having a YML
file for each workflow would be tedious, GitHub
Actions
provides the matrix
parameter inside the strategy
. For more
information, see Using a Matrix for your Jobs.
Consider this example of a parametrized workflow example:
jobs:
example_matrix:
strategy:
matrix:
python: ['3.7', '3.8', '3.9', '3.10']
os: [windows-latest, macos-latest, ubuntu-latest]
steps:
- echo "Running Python ${{ matrix.python }} in ${{ matrix.os }}"
Running Python 3.7 in windows-latest
Running Python 3.8 in windows-latest
Running Python 3.9 in windows-latest
Running Python 3.10 in windows-latest
Running Python 3.7 in macos-latest
Running Python 3.8 in macos-latest
Running Python 3.9 in macos-latest
Running Python 3.10 in macos-latest
Running Python 3.7 in ubuntu-latest
Running Python 3.8 in ubuntu-latest
Running Python 3.9 in ubuntu-latest
Running Python 3.10 in ubuntu-latest
Workflow examples#
Workflow examples are provided for checking Coding style, Documenting, Testing, and Releasing and publishing.
code-style:
name: Code style
runs-on: ubuntu-latest
steps:
- name: "Run PyAnsys code style checks"
uses: pyansys/actions/code-style@v3
doc-style:
name: Doc style
runs-on: ubuntu-latest
steps:
- name: "Run PyAnsys documentation style checks"
uses: pyansys/actions/doc-style@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
tests:
name: "Test library"
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10']
steps:
- name: "Run pytest"
uses: pyansys/actions/tests-pytest@v3
with:
python-version: ${{ matrix.python-version }}
pytest-markers: "-k 'mocked'"
pytest-extra-args: "--cov=ansys.<library> --cov-report=term --cov-report=xml:.cov/coverage.xml --cov-report=html:.cov/html"
- name: "Upload coverage results"
uses: actions/upload-artifact@v3
if: matrix.python-version == ${{ env.MAIN_PYTHON_VERSION }}
with:
name: coverage-html
path: .cov/html
retention-days: 7
doc-build:
name: "Build project documentation"
runs-on: ubuntu-latest
steps:
- name: "Build project documentation"
uses: pyansys/actions/doc-build@v3
with:
python-version: ${{ env.MAIN_PYTHON_VERSION }}
doc-deploy-dev:
name: "Deploy development documentation"
if: github.event_name == 'push'
runs-on: ubuntu-latest
needs: doc-build
steps:
- name: "Deploy development documentation"
uses: pyansys/actions/doc-deploy-dev@v3
with:
cname: ${{ env.CNAME }}
token: ${{ secrets.GITHUB_TOKEN }}
doc-deploy-stable:
name: "Deploy stable documentation"
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
runs-on: ubuntu-latest
needs: doc-deploy-dev
steps:
- name: "Deploy stable documentation"
uses: pyansys/actions/doc-deploy-stable@v3
with:
cname: ${{ env.CNAME }}
token: ${{ secrets.GITHUB_TOKEN }}
build-wheelhouse:
name: Build the wheelhouse of the Python library
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
python-version: ['3.7', '3.8', '3.9', '3.10']
steps:
- name: "Build a wheelhouse of the Python library"
uses: pyansys/actions/build-wheelhouse@v3
with:
library-name: ${{ env.LIBRARY_NAME }}
library-namespace: ${{ env.LIBRARY_NAMESPACE }}
operating-system: ${{ matrix.os }}
python-version: ${{ matrix.python-version }}
build-library:
name: Build library
runs-on: ubuntu-latest
steps:
- name: "Build library source and wheel artifacts"
uses: pyansys/actions/build-library@v3
with:
library-name: ${{ env.LIBRARY_NAME }}
release-pypi-private:
name: "Release to the private PyPI repository"
runs-on: ubuntu-latest
needs: [build-library]
steps:
- name: "Release to the private PyPI repository"
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
uses: pyansys/actions/release-pypi-private@v3
with:
library-name: ${{ env.LIBRARY_NAME }}
twine-username: "__token__"
twine-token: ${{ secrets.PYANSYS_PYPI_PRIVATE_PAT }}
release-pypi-public:
name: "Release to the public PyPI repository"
runs-on: ubuntu-latest
needs: [release-pypi-private]
steps:
- name: "Release to the public PyPI repository"
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
uses: pyansys/actions/release-pypi-public@v3
with:
library-name: ${{ env.LIBRARY_NAME }}
twine-username: "__token__"
twine-token: ${{ secrets.PYPI_TOKEN }}
release-gitub:
name: "Release to GitHub"
runs-on: ubuntu-latest
needs: [release-pypi-public]
steps:
- name: "Release to GitHub"
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
uses: pyansys/actions/release-github@v3
with:
library-name: ${{ env.LIBRARY_NAME }}