Merge pull request #114 from dihm/workflow_refresh #105
This file contains 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: Build and Release | |
on: | |
push: | |
branches: | |
- master | |
- maintenance/* | |
tags: | |
- 'v[0-9]+.[0-9]+.[0-9]+*' | |
env: | |
OS_LIST_UBUNTU: '["ubuntu-latest"]' | |
OS_LIST_ALL: '["ubuntu-latest", "windows-latest", "macos-latest", "macos-13"]' | |
jobs: | |
configure: | |
name: Configure workflow run | |
runs-on: ubuntu-latest | |
outputs: | |
DEFAULT_PYTHON: ${{ steps.config.outputs.DEFAULT_PYTHON }} | |
CIBW_BUILD: ${{ steps.config.outputs.CIBW_BUILD }} | |
PKGNAME: ${{ steps.config.outputs.PKGNAME }} | |
PKGVER: ${{ steps.config.outputs.PKGVER }} | |
PURE: ${{ steps.config.outputs.PURE }} | |
ANACONDA_USER: ${{ steps.config.outputs.ANACONDA_USER }} | |
CONDA_BUILD_ARGS: ${{ steps.config.outputs.CONDA_BUILD_ARGS }} | |
BUILD_OS_LIST: ${{ steps.config.outputs.BUILD_OS_LIST }} | |
RELEASE: ${{ steps.config.outputs.RELEASE }} | |
TESTPYPI_UPLOAD_THIS_RUN: ${{ steps.config.outputs.TESTPYPI_UPLOAD_THIS_RUN }} | |
PYPI_UPLOAD_THIS_RUN: ${{ steps.config.outputs.PYPI_UPLOAD_THIS_RUN }} | |
TEST_ANACONDA_UPLOAD_THIS_RUN: ${{ steps.config.outputs.TEST_ANACONDA_UPLOAD_THIS_RUN }} | |
ANACONDA_UPLOAD_THIS_RUN: ${{ steps.config.outputs.ANACONDA_UPLOAD_THIS_RUN }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Ignore Tags for non-tag pushes | |
if: "!startsWith(github.ref, 'refs/tags/')" | |
run: git tag -d $(git tag --points-at HEAD) | |
- name: Install Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: '3.x' | |
- name: Configure workflow | |
id: config | |
run: | | |
pip install ci-helper | |
# Load repo-specific variables and overrides: | |
VARS_FILE=".github/workflows/release-vars.sh" | |
if [ -f "${VARS_FILE}" ]; then | |
source "${VARS_FILE}" | |
fi | |
# Python version used to build sdists, pure wheels, and as host Python for | |
# `cibuildwheel`: | |
if [ -z "${DEFAULT_PYTHON}" ]; then | |
# Default to second-most recent supported Python version: | |
DEFAULT_PYTHON=$(ci-helper defaultpython) | |
fi | |
# Versions of Python to build conda packages for: | |
if [ -z "${CONDA_PYTHONS}" ]; then | |
# Default to all supported Python versions: | |
CONDA_PYTHONS=$(ci-helper pythons) | |
fi | |
# Env var for `cibuildwheel` specifying target Python versions: | |
if [ -z "${CIBW_BUILD}" ]; then | |
# default to all supported CPython versions: | |
CIBW_BUILD=$(ci-helper pythons --cibw) | |
fi | |
# Package name and version | |
if [ -z "${PKGNAME}" ]; then | |
# Default to package name from project metadata: | |
PKGNAME=$(ci-helper distinfo name .) | |
fi | |
if [ -z "${PKGVER}" ]; then | |
# Default to package version from project metadata: | |
PKGVER=$(ci-helper distinfo version .) | |
fi | |
# Whether the package is pure python | |
if [ -z "${PURE}" ]; then | |
# Default to whether the setuptools package declares no modules/libraries: | |
PURE=$(ci-helper distinfo is_pure .) | |
fi | |
# Whether the package requirements depend on platform or Python version: | |
if [ -z "${HAS_ENV_MARKERS}" ]; then | |
# Default to the presence of env markers in package metadata: | |
HAS_ENV_MARKERS=$(ci-helper distinfo has_env_markers .) | |
fi | |
# List of OSs we need to run the build job on and arguments to | |
# `setuptools-conda build`: | |
if [[ "${PURE}" == false || "${HAS_ENV_MARKERS}" == true ]]; then | |
BUILD_OS_LIST="${OS_LIST_ALL}" | |
CONDA_BUILD_ARGS="--pythons=${CONDA_PYTHONS}" | |
else | |
BUILD_OS_LIST="${OS_LIST_UBUNTU}" | |
CONDA_BUILD_ARGS="--noarch" | |
fi | |
# Release if a tag was pushed: | |
if [ "${{ contains(github.ref, '/tags') }}" == true ]; then | |
RELEASE=true | |
else | |
RELEASE=false | |
fi | |
# What types of package uploads are enabled: | |
if [ -z "${PYPI_UPLOAD}" ]; then | |
PYPI_UPLOAD=true | |
else | |
PYPI_UPLOAD=false | |
fi | |
if [ -z "${TESTPYPI_UPLOAD}" ]; then | |
TESTPYPI_UPLOAD=true | |
else | |
TESTPYPI_UPLOAD=false | |
fi | |
if [ -z "${ANACONDA_UPLOAD}" ]; then | |
ANACONDA_UPLOAD=true | |
else | |
ANACONDA_UPLOAD=false | |
fi | |
if [ -z "${TEST_ANACONDA_UPLOAD}" ]; then | |
TEST_ANACONDA_UPLOAD=true | |
else | |
TEST_ANACONDA_UPLOAD=false | |
fi | |
if [ "${{ github.repository }}" != "${RELEASE_REPO}" ]; then | |
echo "Workflow repo doesn't match ${RELEASE_REPO}, disabling package uploads" | |
PYPI_UPLOAD=false | |
TESTPYPI_UPLOAD=false | |
ANACONDA_UPLOAD=false | |
TEST_ANACONDA_UPLOAD=false | |
fi | |
# If Anaconda uploads enabled, check necessary username and token are | |
# available: | |
if [[ "${ANACONDA_UPLOAD}" == true || "${TEST_ANACONDA_UPLOAD}" == true ]]; then | |
if [ -z "${{ secrets.ANACONDA_API_TOKEN }}" ]; then | |
echo "Anaconda uploads enabled but ANACONDA_API_TOKEN secret not set" | |
exit 1 | |
fi | |
if [ -z "${ANACONDA_USER}" ]; then | |
echo "Anaconda uploads enabled but ANACONDA_USER not set" | |
exit 1 | |
fi | |
fi | |
# If enabled, upload releases to PyPI and Anaconda: | |
if [[ "${RELEASE}" == true && "${PYPI_UPLOAD}" == true ]]; then | |
PYPI_UPLOAD_THIS_RUN=true | |
else | |
PYPI_UPLOAD_THIS_RUN=false | |
fi | |
if [[ "${RELEASE}" == true && "${ANACONDA_UPLOAD}" == true ]]; then | |
ANACONDA_UPLOAD_THIS_RUN=true | |
else | |
ANACONDA_UPLOAD_THIS_RUN=false | |
fi | |
# If enabled, upload non-releases to Test PyPI and Anaconda test label: | |
if [[ "${RELEASE}" == false && "${TESTPYPI_UPLOAD}" == true ]]; then | |
TESTPYPI_UPLOAD_THIS_RUN=true | |
else | |
TESTPYPI_UPLOAD_THIS_RUN=false | |
fi | |
if [[ "${RELEASE}" == false && "${TEST_ANACONDA_UPLOAD}" == true ]]; then | |
TEST_ANACONDA_UPLOAD_THIS_RUN=true | |
else | |
TEST_ANACONDA_UPLOAD_THIS_RUN=false | |
fi | |
echo "DEFAULT_PYTHON=${DEFAULT_PYTHON}" >> "${GITHUB_OUTPUT}" | |
echo "CIBW_BUILD=${CIBW_BUILD}" >> "${GITHUB_OUTPUT}" | |
echo "PKGNAME=${PKGNAME}" >> "${GITHUB_OUTPUT}" | |
echo "PKGVER=${PKGVER}" >> "${GITHUB_OUTPUT}" | |
echo "PURE=${PURE}" >> "${GITHUB_OUTPUT}" | |
echo "ANACONDA_USER=${ANACONDA_USER}" >> "${GITHUB_OUTPUT}" | |
echo "CONDA_BUILD_ARGS=${CONDA_BUILD_ARGS}" >> "${GITHUB_OUTPUT}" | |
echo "BUILD_OS_LIST=${BUILD_OS_LIST}" >> "${GITHUB_OUTPUT}" | |
echo "RELEASE=${RELEASE}" >> "${GITHUB_OUTPUT}" | |
echo "TESTPYPI_UPLOAD_THIS_RUN=${TESTPYPI_UPLOAD_THIS_RUN}" >> "${GITHUB_OUTPUT}" | |
echo "PYPI_UPLOAD_THIS_RUN=${PYPI_UPLOAD_THIS_RUN}" >> "${GITHUB_OUTPUT}" | |
echo "TEST_ANACONDA_UPLOAD_THIS_RUN=${TEST_ANACONDA_UPLOAD_THIS_RUN}" >> "${GITHUB_OUTPUT}" | |
echo "ANACONDA_UPLOAD_THIS_RUN=${ANACONDA_UPLOAD_THIS_RUN}" >> "${GITHUB_OUTPUT}" | |
echo | |
echo "==========================" | |
echo "Workflow run configuration:" | |
echo "--------------------------" | |
cat "${GITHUB_OUTPUT}" | |
echo "==========================" | |
echo | |
build: | |
name: Build | |
runs-on: ${{ matrix.os }} | |
needs: configure | |
strategy: | |
matrix: | |
os: ${{ fromJSON(needs.configure.outputs.BUILD_OS_LIST) }} | |
env: | |
DEFAULT_PYTHON: ${{ needs.configure.outputs.DEFAULT_PYTHON }} | |
CIBW_BUILD: ${{ needs.configure.outputs.CIBW_BUILD }} | |
PURE: ${{ needs.configure.outputs.PURE }} | |
CONDA_BUILD_ARGS: ${{ needs.configure.outputs.CONDA_BUILD_ARGS }} | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Ignore Tags for non-tag pushes | |
if: "!startsWith(github.ref, 'refs/tags/')" | |
run: git tag -d $(git tag --points-at HEAD) | |
- name: Install Python | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ env.DEFAULT_PYTHON }} | |
- name: Install Python tools | |
run: python -m pip install --upgrade pip setuptools wheel build cibuildwheel | |
- name: Source distribution | |
if: strategy.job-index == 0 | |
run: python -m build -s . | |
- name: Wheel distribution (pure) | |
if: env.PURE == 'true' && strategy.job-index == 0 | |
run: python -m build -w . | |
- name: Wheel distribution (impure) | |
if: env.PURE == 'false' | |
run: cibuildwheel --output-dir dist | |
- name: Upload artifact | |
if: env.PURE == 'false' || strategy.job-index == 0 | |
uses: actions/upload-artifact@v4 | |
with: | |
name: dist-${{ matrix.os }} | |
path: ./dist | |
if-no-files-found: error | |
- name: Install Miniforge | |
uses: conda-incubator/setup-miniconda@v3 | |
with: | |
miniforge-version: "latest" | |
auto-update-conda: true | |
conda-remove-defaults: true | |
auto-activate-base: true | |
activate-environment: "" | |
- name: Conda package | |
shell: bash -l {0} | |
run: | | |
if [ "${{ runner.os }}" == Windows ]; then | |
# Short path to minimise odds of hitting Windows max path length | |
CONDA_BUILD_ARGS+=" --croot ${{ runner.temp }}\cb" | |
fi | |
conda install -c labscript-suite setuptools-conda | |
setuptools-conda build $CONDA_BUILD_ARGS . | |
- name: Upload artifact | |
uses: actions/upload-artifact@v4 | |
with: | |
name: conda_packages-${{ matrix.os }} | |
path: ./conda_packages | |
if-no-files-found: error | |
github-release: | |
name: Publish release (GitHub) | |
runs-on: ubuntu-latest | |
needs: [configure, build] | |
if: ${{ needs.configure.outputs.RELEASE == 'true' }} | |
permissions: | |
contents: write | |
env: | |
PKGNAME: ${{ needs.configure.outputs.PKGNAME }} | |
PKGVER: ${{ needs.configure.outputs.PKGVER }} | |
steps: | |
- name: Download Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: dist* | |
path: ./dist | |
merge-multiple: true | |
- name: Create GitHub release and upload release asset | |
uses: softprops/action-gh-release@v2 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
with: | |
tag_name: ${{ github.event.ref }} | |
name: ${{ env.PKGNAME }} ${{ env.PKGVER }} | |
draft: true | |
prerelease: ${{ contains(github.event.ref, 'rc') }} | |
files: ./dist/*.tar.gz | |
testpypi-upload: | |
name: Publish on Test PyPI | |
runs-on: ubuntu-latest | |
needs: [configure, build] | |
if: ${{ needs.configure.outputs.TESTPYPI_UPLOAD_THIS_RUN == 'true' }} | |
env: | |
PKGNAME: ${{ needs.configure.outputs.PKGNAME }} | |
PKGVER: ${{ needs.configure.outputs.PKGVER }} | |
environment: | |
name: testpypi | |
url: https://test.pypi.org/project/${{ env.PKGNAME }}/${{ env.PKGVER }} | |
permissions: | |
id-token: write | |
steps: | |
- name: Download Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: dist* | |
path: ./dist | |
merge-multiple: true | |
- name: Publish on TestPyPI | |
uses: pypa/gh-action-pypi-publish@release/v1 | |
with: | |
repository-url: https://test.pypi.org/legacy/ | |
pypi-upload: | |
name: Publish on PyPI | |
runs-on: ubuntu-latest | |
needs: [configure, build] | |
if: ${{ needs.configure.outputs.PYPI_UPLOAD_THIS_RUN == 'true' }} | |
env: | |
PKGNAME: ${{ needs.configure.outputs.PKGNAME }} | |
PKGVER: ${{ needs.configure.outputs.PKGVER }} | |
environment: | |
name: pypi | |
url: https://pypi.org/project/${{ env.PKGNAME }}/${{ env.PKGVER }} | |
permissions: | |
id-token: write | |
steps: | |
- name: Download Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: dist* | |
path: ./dist | |
merge-multiple: true | |
- name: Publish on PyPI | |
uses: pypa/gh-action-pypi-publish@release/v1 | |
test-anaconda-upload: | |
name: Publish on Anaconda (test label) | |
runs-on: ubuntu-latest | |
needs: [configure, build] | |
if: ${{ needs.configure.outputs.TEST_ANACONDA_UPLOAD_THIS_RUN == 'true' }} | |
steps: | |
- name: Download Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: conda_packages-* | |
path: ./conda_packages | |
merge-multiple: true | |
- name: Install Miniforge | |
uses: conda-incubator/setup-miniconda@v3 | |
with: | |
miniforge-version: "latest" | |
auto-update-conda: true | |
conda-remove-defaults: true | |
auto-activate-base: true | |
activate-environment: "" | |
- name: Install Anaconda cloud client | |
shell: bash -l {0} | |
run: conda install anaconda-client | |
- name: Publish to Anaconda test label | |
shell: bash -l {0} | |
run: | | |
anaconda \ | |
--token ${{ secrets.ANACONDA_API_TOKEN }} \ | |
upload \ | |
--skip-existing \ | |
--user ${{ needs.configure.outputs.ANACONDA_USER }} \ | |
--label test \ | |
conda_packages/*/* | |
anaconda-upload: | |
name: Publish on Anaconda | |
runs-on: ubuntu-latest | |
needs: [configure, build] | |
if: ${{ needs.configure.outputs.ANACONDA_UPLOAD_THIS_RUN == 'true' }} | |
steps: | |
- name: Download Artifact | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: conda_packages-* | |
path: ./conda_packages | |
merge-multiple: true | |
- name: Install Miniforge | |
uses: conda-incubator/setup-miniconda@v3 | |
with: | |
miniforge-version: "latest" | |
auto-update-conda: true | |
conda-remove-defaults: true | |
auto-activate-base: true | |
activate-environment: "" | |
- name: Install Anaconda cloud client | |
shell: bash -l {0} | |
run: conda install anaconda-client | |
- name: Publish to Anaconda main | |
shell: bash -l {0} | |
run: | | |
anaconda \ | |
--token ${{ secrets.ANACONDA_API_TOKEN }} \ | |
upload \ | |
--skip-existing \ | |
--user ${{ needs.configure.outputs.ANACONDA_USER }} \ | |
conda_packages/*/* |