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 you must follow to create a successful release.
Attention
A project must be authorized to be publicly released. For an explanation of the process, see Project approval and public release.
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
:
A
MAJOR
version is when you make incompatible API changes.A
MINOR
version is when you add a feature in a backwards-compatible manner.A
PATCH
version is 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 library versions should not match product versions.
PyAnsys libraries are expected to be developed outside the product
release cycle in a rapid CI/CD manner. Thus, library versions should
not match product versions. For example, PyMAPDL library (ansys-mapdl-core
)
might have the version 0.59.0
whereas the product (Ansys Parametric
Design Language (APDL) might have the version is 22.2
(2022 R2).
Branching 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.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.
New releases#
Releasing is the process of creating a version of the 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.
Release major and minor versions
Before performing a release, you must verify that your origin main
branch is up to date
with these commands:
git checkout main
git fetch origin main
git rebase origin/main
If you encounter any issues when running the preceding commands, 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 that 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
files that your project may contain.
Stage and commit previous changes with these commands:
git add <files-edited-for-version-number-change>
git commit -m "Bump version X.Y.0"
Tag the previous commit with this command:
git tag vX.Y.0
Push the commit and the tag it with these commands:
git push -u origin release/X.Y
git push origin vX.Y.0
Release patched versions
Patched versions allow you to fix issues discovered in published releases by
cherry-picking these fixes from the main
branch. For more information, see
the get-cherry-pick description
in the Git documentation.
Before performing a patch release, you must first identify which
release/X.Y
branch it belongs to with these commands.
git checkout release/X.Y
git fetch origin release/X.Y
git reset --hard origin/release/X.Y
Next, use the following code to cherry-pick the fix commit from the main
branch, which solves for the bug. Do not merge changes from the
main
branch 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. Stage and
amend these new changes with these commands:
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 it using this command:
git push -u origin release/X.Y
git push origin vX.Y.Z
Artifact publication#
When a new version is released, some artifacts are provided with it. In Python, these Artifacts are typically wheel and source files. Documentation in the form of HTML and PDF files are also considered artifacts.
Attention
Do not distribute artifacts without approval.
A project must be authorized to be publicly released. For an explanation of the process, see Project approval and public release.
There are three possible places where artifacts can be published:
This is a private index used to share artifacts across the company while making sure that projects remain private.
This is the public PyPI used by the Python community to distribute libraries. A project requires Ansys authorization before being published in this index.
This is a section created by GitHub within a project repository where artifacts can be published. A project requires Ansys authorization before being public in GitHub.
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. You must have the proper credentials for publishing to this private repository:
Credentials |
Value |
---|---|
Username |
|
Password |
|
repository-url |
|
The PYANSYS_PYPI_PRIVATE_PAT
is a password in the form of a GitHub secret
that is available only to PyAnsys projects. This secret is
available during the execution of the CI/CD. Its value is never shown or shared
in the log files.
When using Twine from the command line, you must
add in --repository-url
as an extra option. Otherwise, Twine attempts to upload
the package to the public PyPI repository.
Forked GitHub repositories do not have access to GitHub secrets. This is designed to protect against pull requests that could potentially scrape tokens from the PyAnsys CI/CD.
Here’s a cross-platform, one-line command for using Twine to upload a package:
python -m twine upload dist/* --repository-url https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload -u __token__ -p <TOKEN-REDACTED>
Replace <TOKEN-REDACTED>
with the private PyPI token.
Use GitHub Actions
The following code lets you publish Python Artifacts in
the dist
directory to the private PyPI. This code is expected to be included when you
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: ansys/actions/release-pypi-private@v8
with:
library-name: "ansys-<product>-<library>"
twine-username: "__token__"
twine-token: ${{ secrets.PYANSYS_PYPI_PRIVATE_PAT }}
Use the command line
Alternatively, instead of command-line tool arguments for Twine, you can use environment variables:
set TWINE_USERNAME=__token__
set TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
set TWINE_REPOSITORY_URL=https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload
$env:TWINE_USERNAME=__token__
$env:TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
$env:TWINE_REPOSITORY_URL=https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload
export TWINE_USERNAME=__token__
export TWINE_PASSWORD=<PYANSYS_PYPI_PRIVATE_PAT>
export TWINE_REPOSITORY_URL="https://pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/upload"
export TWINE_USERNAME=__token__
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. Before being publicly released, projects must follow the process Project approval and public release to obtain public release authorization. Once authorized, contact the PyAnsys Core team to get support during the first release of the project.
Publishing to PyPI can be performed following the Trusted Publisher approach or the API token approach. When possible, it is recommended to use the Trusted Publisher as it provides enhanced security and simplifies the management of authentication credentials. Existing repositories currently using the API Token approach are encouraged to transition to the Trusted Publisher approach to benefit from its security and management improvements.
Publish with trusted publisher#
Publishing with Trusted Publisher requires an initial setup to configure OIDC trust between PyPI and Github. This action is performed by the PyAnsy core team which adds your project to the list of authorized repositories to release as a Trusted Publisher.
It is recommended to create en environment in your Github repository to manage deployments. Environments provide a way to configure deployment-specific setting and ensure that sensitive operations are performed in a controller manner. For more information, see the Environment documentation. Contact the PyAnsys Core team in case of doubts.
Use GitHub Actions
The following code lets you publish any Python Artifacts contained in
the dist
directory to the public PyPI. It is expected to be included when you
Use GitHub Actions.
release-pypi-public:
name: Release project to public PyPI
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' && contains(github.ref, 'refs/tags') }}
# Specifying a GitHub environment is optional, but strongly encouraged
environment: release
permissions:
id-token: write
contents: write
steps:
- uses: ansys/actions/release-pypi-public@v8
with:
library-name: "ansys-<product>-<library>"
use-trusted-publisher: true
Publish with API token#
Publishing with API token 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. The PyAnsys Core team enables the custom
PYPI_TOKEN
once your project has been successfully released for the first
time. For future releases, everything is automated.
Here’s a cross-platform, one-line command for using Twine to download a package:
python -m pip install <PACKAGE-NAME> --index-url <TOKEN-REDACTED>@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/
Replace <PACKAGE-NAME>
and <TOKEN-REDACTED>
with the package name and private PyPI token respectively.
Use GitHub Actions
The following code lets you publish any Python Artifacts contained in
the dist
directory to the public PyPI. It is expected to be included when you
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: ansys/actions/release-pypi-public@v8
with:
library-name: "ansys-<product>-<library>"
twine-username: "__token__"
twine-token: ${{ secrets.PYPI_TOKEN }}
GitHub#
You can publish Artifacts to GitHub, which makes them available in
the https://github.com/ansys/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 Project approval and public release.
Use GitHub Actions
The following code lets you publish any Python Artifacts contained in
the dist
directory to the GitHub release created. It is expected to be included
when you 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: ansys/actions/release-github@v8
with:
library-name: "ansys-<product>-<library>"
Artifact download#
You can download artifacts from the Ansys private PyPI, public PyPI, and GitHub.
Download artifacts from the Ansys private PyPI
Request the value of the PYANSYS_PYPI_PRIVATE_READ_PAT
token by sending an
email to the pyansys.core@ansys.com email.
Create an environment variable named PYANSYS_PYPI_PRIVATE_READ_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_READ_PAT=<REDACTED>
set INDEX_URL=https://%PYANSYS_PYPI_PRIVATE_READ_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://$env:PYANSYS_PYPI_PRIVATE_READ_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_READ_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_READ_PAT@pkgs.dev.azure.com/pyansys/_packaging/pyansys/pypi/simple/"
python -m pip install ansys-<product/tool>-<library> \
--index-url $INDEX_URL \
--no-dependencies
Download artifacts from the public PyPI
Downloading artifacts from the public PyPI can be done by using pip
:
python -m pip install <package-name>
Download artifacts from GitHub
Downloading artifacts from GitHub can be done by checking the
https://github.com/ansys/project-name/releases
section.
Note that if you download the wheel of a Python package, you must manually install it with a command like this:
python -m pip install path/to/package/wheel.whl