Releasing and publishing#
Releasing a new version is a critical procedure. It should be automated as much as possible to avoid human error.
This sections explains the Git workflow and steps that must be followed to create a successful release.
Attention
A project needs to be authorized to be released into public by following the process explained in the Project approval and public release section.
Semantic versioning#
PyAnsys library releases are managed through both automated and manual review processes.
PyAnsys follows Semantic Versioning, which produces release names in the
form of X.Y.Z
, where each letter corresponds to an integer value. This
notation can also be understand as MAJOR.MINOR.PATCH
:
Major version when you make incompatible API changes.
Minor version when you add a feature in a backwards-compatible manner.
Patch version when you make backwards compatible bug fixes.
To match the versioning methodology used by the ‘big three’ data science Python
packages, numpy, scipy, and pandas, MAJOR
versions of PyAnsys
packages are not released when any incompatible API change is made but rather
when major, globally breaking API changes are made.
Note that 0.MINOR.PATCH
packages are expected to have fluid APIs and should
be solidified at the 1.MINOR.PATCH
release. At that point, APIs are expected
to be much more stable.
PyAnsys libraries should not match product versions.
For example, the PyMAPDL library ansys-mapdl-core
might have the version
0.59.0
whereas the product version is 22.2 (2022 R2). The reason behind
this is PyAnsys libraries are expected to be developed outside the product
release cycle in a rapid CI/CD manner.
Branch model#
The branching model for a PyAnsys project enables rapid development of features without sacrificing stability. The model closely follows the Trunk Based Development approach:
The
main
branch is the primary development branch. All features, patches, and other branches should be merged here. While all PRs should pass all applicable CI checks, this branch might be functionally unstable if changes have introduced unintended side effects or bugs that were not caught through unit testing. The version is always suffixed with.dev0
in themain
branch.Fig. 2 The main branch is the primary development branch.#
When a minor release candidate is ready, a new
release
branch is created frommain
with the next incremented minor version (for example,release/0.2
). Thisrelease
branch is thoroughly tested. When deemed stable, it is tagged with the version (0.2.0
in this case). Older release branches should not be deleted so that they can be patched as needed.There is one or more
release/
branches based on minor releases (for example,release/0.2
) that contain a stable version of the code base that is also reflected on PyPI. Hotfixes fromfix/
branches should be integrated both tomain
and to these branches. When creating a new patch release is necessary, these release branches have their version updated and are tagged with a patched Semantic versioning (for example,0.2.1
). This triggers CI to push to PyPI so that hotfixes for past versions can be rapidly push without having to worry about untested features.Fig. 3 Release branches are created based on minor releases.#
Releasing new versions#
Releasing is the process of creating a version of a software that developers consider useful for customers or other developers. Releases are usually labeled with tags. These tags are used to quickly identify a release in the version control system.
Your main or release branch is up to date.
All code and documentation style checks are passing successfully.
All tests are passing successfully.
All documentation builds successfully.
The project builds successfully.
Releasing major and minor versions
Before performing a release, you must verify that your origin main
branch is up to date using the these commands:
git checkout main
git fetch origin main
git rebase origin/main
If you encounter any issues when running the preceding command, solve them before continuing with the release. Ensure that your style, tests, and documentation checks are passing too.
Create a new branch for the version you want to release with this command:
git checkout -b release/X.Y
Update X
or Y
version numbers in your project and replace the dev0
with a 0
.
Check all locations, including
The setup.py file, The pyproject.toml file, and any
__init__.py
or __version__.py
your project may contain.
Stash and commit previous changes with the commands:
git add <files-edited-for-version-number-change>
git commit -m "Bump version X.Y.0"
Tag the previous commit using this command:
git tag vX.Y.0
Push the commit and the tag with these commands:
git push -u origin release/X.Y
git push origin vX.Y.0
Releasing patched versions
Patched versions allow you to fix issues discovered in published releases by
cherry-picking these fixes from the main
branch.
Before performing a patch release, you must first identify which
release/X.Y
branch it belongs to.
git checkout release/X.Y
git fetch origin release/X.Y
git reset --hard origin/release/X.Y
Now, use the following code to cherry-pick
the fix commit from main
, which solves for the bug. Do not merge changes from
main
into the release branch. Always cherry-pick them.
git cherry-pick <commit hash>
Ensure that your style, tests, and documentation checks are also passing.
Increase by one unit the value of Z
in your project version. Stash and
amend these new changes using this command:
git add <files-edited-for-version-number-change>
git commit --amend -m "Bump version X.Y.Z"
Tag the previous commit with this command:
git tag vX.Y.Z
Push the commit and the tag using this command:
git push -u origin release/X.Y
git push origin vX.Y.Z
Publishing artifacts#
When a new version is released, some artifacts are provided with it. In Python,
these Artifacts are typically the Wheel
and Source
files.
Documentation in the form of PDF and HTML files are also considered artifacts.
Attention
Do not distribute artifacts without approval.
A project needs to be authorized to be released into public by following the process explained in the Project approval and public release section.
There are three possible places where artifacts can be published:
Private PyPI#
It is sometimes necessary to host and pull packages that are not ready to be hosted on the public PyPI. For example, if a PyAnsys library requires auto-generated gRPC interface files from a feature or service that is still private, this package should be hosted on a private PyPI repository.
ANSYS, Inc. has a private repository at PyAnsys PyPI. Access is controlled via a username and a password:
Credentials for publishing to private PyPI |
Value |
---|---|
Username |
|
Password |
|
The PYANSYS_PYPI_PRIVATE_PAT
is a password in the form of a GitHub secret
which is available only to repositories within PyAnsys. This secret is
available during the execution of the CI/CD. Its value is never shown or shared
in the log files.
Forked GitHub repositories do not have access to GitHub secrets. This is designed to protect against pull-requests that could potentially scrape tokens from PyAnsys CI/CD.
Using GitHub actions
The following code allows you to publish any Python Artifacts contained in
the dist/
directory to the private PyPI. It is expected to be included when
Use GitHub actions:
release-pypi-private:
name: "Release to private PyPI"
runs-on: ubuntu-latest
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
steps:
- uses: pyansys/actions/release-pypi-private@v3
with:
library-name: "ansys-<product>-<library>"
twine-username: "__token__"
twine-token: ${{ secrets.PYANSYS_PYPI_PRIVATE_PAT }}
Using the command line
Alternatively, instead of command-line tool arguments for Twine, you can use environment variables:
set TWINE_USERNAME=<PAT>
set TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
set TWINE_REPOSITORY_URL=https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload
$env:TWINE_USERNAME=<PAT>
$env:TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
$env:TWINE_REPOSITORY_URL=https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload
export TWINE_USERNAME=<PAT>
export TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
export TWINE_REPOSITORY_URL="https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload"
export TWINE_USERNAME=<PAT>
export TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
export TWINE_REPOSITORY_URL="https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload"
Finally, run this command:
python -m twine upload dist/*
Public PyPI#
Publishing Artifacts to PyPI is the way of distributing Python libraries. Publishing to PyPI requires a username and a password:
Credentials for publishing to public PyPI |
Value |
---|---|
Username |
|
Password |
|
The PYPI_TOKEN
is a password in the form of a GitHub secret. This secret is
unique to each project. It can only be obtained after the first release to the
public PyPI. Follow the process Project approval and public release
process to obtain public release authorization.
Once authorized, contact pyansys.support@ansys.com to
get support during the first release of the project. The team then enables the
custom PYPI_TOKEN
once your project has been successfully released for the
first time. For future releases, everything is then automated.
Using GitHub actions
The following code allows you to publish any Python Artifacts contained in
the dist/
directory to the public PyPI. It is expected to be included when
Use GitHub actions:
release-pypi-public:
name: "Release to public PyPI"
runs-on: ubuntu-latest
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
steps:
- uses: pyansys/actions/release-pypi-public@v3
with:
library-name: "ansys-<product>-<library>"
twine-username: "__token__"
twine-token: ${{ secrets.PYPI_TOKEN }}
GitHub#
Publishing Artifacts to GitHub is also possible. These are available in
the https://github.com/pyansys/project-name/releases
section. The
visibility of these artifacts follows the one in the repository. Visibility can
be private, internal or public.
For enabling public visibility of a repository, follow the process explained in the Project approval and public release section.
Using GitHub actions
The following code allows you to publish any Python Artifacts contained in
the dist/
directory to the GitHub release created. It is expected to be included when
Use GitHub actions:
release-github:
name: "Release to GitHub"
runs-on: ubuntu-latest
if: github.event_name == 'push' && contains(github.ref, 'refs/tags')
steps:
- uses: pyansys/actions/release-github@v3
with:
library-name: "ansys-<product>-<library>"
Downloading artifacts#
Artifacts can be downloaded from all previous sources: Ansys private PyPI, public PyPI and GitHub.
Downloading artifacts from the Ansys private PyPI
Request the value of the PYANSYS_PYPI_PRIVATE_PAT
token by sending an
email to the pyansys.support@ansys.com email.
Create an environment variable named PYANSYS_PYPI_PRIVATE_PAT
in your
local machine an assign it the value of the token.
Warning
Take care to always use the --index-url
switch rather than the
--extra-index-url
switch. As noted in pip Documentation, the
--index-url
switch changes the Python Package Index, which forces pip
to use only packages from that package index.
The Ansys package index uses PyPI upstream. This prevents other users from being able to inject packages from PyPI that would supersede Ansys packages, even if they are of a higher version.
This is not the case if you use --extra-index-url
, which adds to rather
than replaces the default package index. For security, do not use
--extra-index-url
.
set PYANSYS_PYPI_PRIVATE_PAT=<REDACTED>
set INDEX_URL=https://%PYANSYS_PYPI_PRIVATE_PAT%@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/
python -m pip install ansys-<product/tool>-<library> --index-url %INDEX_URL% --no-dependencies
$env:INDEX_URL='https://$PYANSYS_PYPI_PRIVATE_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/'
python -m pip install ansys-<product/tool>-<library> --index-url $env:INDEX_URL --no-dependencies
export INDEX_URL='https://$PYANSYS_PYPI_PRIVATE_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/'
python -m pip install ansys-<product/tool>-<library> \
--index-url $INDEX_URL \
--no-dependencies
export INDEX_URL='https://$PYANSYS_PYPI_PRIVATE_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/'
python -m pip install ansys-<product/tool>-<library> \
--index-url $INDEX_URL \
--no-dependencies
Downloading artifacts from the public PyPI
Downloading artifacts from the public PyPI can be done by using the default
settings by pip
:
python -m pip install <package-name>
Downloading artifacts from GitHub
Downloading artifacts from GitHub can be done by checking the
https://github.com/pyansys/project-name/releases
section.
Note that if you download the Wheel
of a Python package, you still need
to manually install it by running:
python -m pip install path/to/package/wheel.whl