Skip to content

Work towards doctestplus compat with a facade for stdlib doctest #18

Work towards doctestplus compat with a facade for stdlib doctest

Work towards doctestplus compat with a facade for stdlib doctest #18

Workflow file for this run

# This workflow is autogenerated by xcookie.
# File kind: release
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
# Based on ~/code/xcookie/xcookie/builders/github_actions.py
# See: https://github.com/Erotemic/xcookie
name: PurePyRelease
on:
push:
workflow_dispatch:
jobs:
build_sdist:
##
# Build the sdist artifact used by the release workflow.
# This workflow intentionally builds artifacts but does not run the
# full test matrix.
##
name: Build sdist
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v6.0.2
- name: Set up Python 3.14
uses: actions/setup-python@v5.6.0
with:
python-version: '3.14'
- name: Build sdist
shell: bash
run: |-
python -m pip install pip uv -U
python -m uv pip install setuptools>=0.8 wheel build twine
python -m build --sdist --outdir wheelhouse
python -m twine check ./wheelhouse/xdoctest*.tar.gz
- name: Show built files
shell: bash
run: ls -la wheelhouse
- uses: actions/upload-artifact@v6.0.0
name: Upload sdist artifact
with:
name: sdist_wheels
path: ./wheelhouse/xdoctest*.tar.gz
build_purepy_wheels:
##
# Build the pure-python wheels used by the release workflow.
##
name: ${{ matrix.python-version }} on ${{ matrix.os }}, arch=${{ matrix.arch }} with ${{ matrix.install-extras }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
python-version:
- '3.14'
arch:
- auto
steps:
- name: Checkout source
uses: actions/checkout@v6.0.2
- name: Set up QEMU
uses: docker/setup-qemu-action@v3.7.0
if: runner.os == 'Linux' && matrix.arch != 'auto'
with:
platforms: all
- name: Setup Python
uses: actions/setup-python@v5.6.0
with:
python-version: ${{ matrix.python-version }}
- name: Build pure wheel
shell: bash
run: |-
python -m pip install pip uv -U
python -m uv pip install setuptools>=0.8 wheel build twine
python -m build --wheel --outdir wheelhouse
python -m twine check ./wheelhouse/xdoctest*.whl
- name: Show built files
shell: bash
run: ls -la wheelhouse
- uses: actions/upload-artifact@v6.0.0
name: Upload wheels artifact
with:
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
path: ./wheelhouse/xdoctest*.whl
test_deploy:
name: Deploy Test
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.event.ref == 'refs/heads/main'
needs:
- build_purepy_wheels
- build_sdist
steps:
- name: Checkout source
uses: actions/checkout@v6.0.2
- uses: actions/download-artifact@v4.1.8
name: Download wheels
with:
pattern: wheels-*
merge-multiple: true
path: wheelhouse
- uses: actions/download-artifact@v4.1.8
name: Download sdist
with:
name: sdist_wheels
path: wheelhouse
- name: Show files to upload
shell: bash
run: ls -la wheelhouse
- name: Sign distributions
env:
GPG_SECRET_SIGNING_SUBKEY_B64: ${{ secrets.GPG_SECRET_SIGNING_SUBKEY_B64 }}
GPG_PUBLIC_KEY_B64: ${{ secrets.GPG_PUBLIC_KEY_B64 }}
GPG_OWNER_TRUST_B64: ${{ secrets.GPG_OWNER_TRUST_B64 }}
run: |-
GPG_EXECUTABLE=gpg
$GPG_EXECUTABLE --version
openssl version
$GPG_EXECUTABLE --list-keys
echo "Importing GPG keys from CI secrets"
printf '%s' "$GPG_PUBLIC_KEY_B64" | base64 -d | $GPG_EXECUTABLE --import
printf '%s' "$GPG_OWNER_TRUST_B64" | base64 -d | $GPG_EXECUTABLE --import-ownertrust
printf '%s' "$GPG_SECRET_SIGNING_SUBKEY_B64" | base64 -d | $GPG_EXECUTABLE --import
echo "Finish importing GPG keys"
$GPG_EXECUTABLE --list-keys || true
$GPG_EXECUTABLE --list-keys
GPG_KEYID=$(cat dev/public_gpg_key)
echo "GPG_KEYID = '$GPG_KEYID'"
IMPORTED_FPR=$($GPG_EXECUTABLE --list-keys --with-colons "$GPG_KEYID" | awk -F: '/^fpr/ { print $10; exit }')
if [[ "$IMPORTED_FPR" != "$GPG_KEYID" ]]; then echo "ERROR: imported GPG fingerprint $IMPORTED_FPR does not match pinned $GPG_KEYID"; exit 1; fi
echo "GPG fingerprint verified: $IMPORTED_FPR"
VERSION=$(python -c "import setup; print(setup.VERSION)")
python -m pip install pip uv -U
python -m pip install packaging twine -U
python -m pip install urllib3 requests[security]
GPG_SIGN_CMD="$GPG_EXECUTABLE --batch --yes --detach-sign --armor --local-user $GPG_KEYID"
WHEEL_PATHS=(wheelhouse/*.whl wheelhouse/*.tar.gz)
WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_PATHS[@]}")
echo "$WHEEL_PATHS_STR"
for WHEEL_PATH in "${WHEEL_PATHS[@]}"
do
echo "------"
echo "WHEEL_PATH = $WHEEL_PATH"
$GPG_SIGN_CMD --output $WHEEL_PATH.asc $WHEEL_PATH
$GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH || echo "hack, the first run of gpg very fails"
$GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH
done
ls -la wheelhouse
python -m pip install opentimestamps-client
ots stamp wheelhouse/*.whl wheelhouse/*.tar.gz wheelhouse/*.asc
ls -la wheelhouse
- name: Prepare publish directory
shell: bash
run: |-
mkdir -p publish_wheelhouse
shopt -s nullglob
for FPATH in wheelhouse/*.whl wheelhouse/*.tar.gz wheelhouse/*.zip
do
cp "$FPATH" publish_wheelhouse/
done
ls -la publish_wheelhouse
- name: Publish test artifacts to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: publish_wheelhouse
skip-existing: true
repository-url: https://test.pypi.org/legacy/
- uses: actions/upload-artifact@v6.0.0
name: Upload deploy artifacts
with:
name: deploy_artifacts
path: |-
wheelhouse/*.whl
wheelhouse/*.zip
wheelhouse/*.tar.gz
wheelhouse/*.asc
wheelhouse/*.ots
permissions:
contents: read
id-token: write
environment: testpypi
live_deploy:
name: Deploy Live
runs-on: ubuntu-latest
if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || startsWith(github.event.ref, 'refs/heads/release'))
needs:
- build_purepy_wheels
- build_sdist
steps:
- name: Checkout source
uses: actions/checkout@v6.0.2
- uses: actions/download-artifact@v4.1.8
name: Download wheels
with:
pattern: wheels-*
merge-multiple: true
path: wheelhouse
- uses: actions/download-artifact@v4.1.8
name: Download sdist
with:
name: sdist_wheels
path: wheelhouse
- name: Show files to upload
shell: bash
run: ls -la wheelhouse
- name: Sign distributions
env:
GPG_SECRET_SIGNING_SUBKEY_B64: ${{ secrets.GPG_SECRET_SIGNING_SUBKEY_B64 }}
GPG_PUBLIC_KEY_B64: ${{ secrets.GPG_PUBLIC_KEY_B64 }}
GPG_OWNER_TRUST_B64: ${{ secrets.GPG_OWNER_TRUST_B64 }}
run: |-
GPG_EXECUTABLE=gpg
$GPG_EXECUTABLE --version
openssl version
$GPG_EXECUTABLE --list-keys
echo "Importing GPG keys from CI secrets"
printf '%s' "$GPG_PUBLIC_KEY_B64" | base64 -d | $GPG_EXECUTABLE --import
printf '%s' "$GPG_OWNER_TRUST_B64" | base64 -d | $GPG_EXECUTABLE --import-ownertrust
printf '%s' "$GPG_SECRET_SIGNING_SUBKEY_B64" | base64 -d | $GPG_EXECUTABLE --import
echo "Finish importing GPG keys"
$GPG_EXECUTABLE --list-keys || true
$GPG_EXECUTABLE --list-keys
GPG_KEYID=$(cat dev/public_gpg_key)
echo "GPG_KEYID = '$GPG_KEYID'"
IMPORTED_FPR=$($GPG_EXECUTABLE --list-keys --with-colons "$GPG_KEYID" | awk -F: '/^fpr/ { print $10; exit }')
if [[ "$IMPORTED_FPR" != "$GPG_KEYID" ]]; then echo "ERROR: imported GPG fingerprint $IMPORTED_FPR does not match pinned $GPG_KEYID"; exit 1; fi
echo "GPG fingerprint verified: $IMPORTED_FPR"
VERSION=$(python -c "import setup; print(setup.VERSION)")
python -m pip install pip uv -U
python -m pip install packaging twine -U
python -m pip install urllib3 requests[security]
GPG_SIGN_CMD="$GPG_EXECUTABLE --batch --yes --detach-sign --armor --local-user $GPG_KEYID"
WHEEL_PATHS=(wheelhouse/*.whl wheelhouse/*.tar.gz)
WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_PATHS[@]}")
echo "$WHEEL_PATHS_STR"
for WHEEL_PATH in "${WHEEL_PATHS[@]}"
do
echo "------"
echo "WHEEL_PATH = $WHEEL_PATH"
$GPG_SIGN_CMD --output $WHEEL_PATH.asc $WHEEL_PATH
$GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH || echo "hack, the first run of gpg very fails"
$GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH
done
ls -la wheelhouse
python -m pip install opentimestamps-client
ots stamp wheelhouse/*.whl wheelhouse/*.tar.gz wheelhouse/*.asc
ls -la wheelhouse
- name: Prepare publish directory
shell: bash
run: |-
mkdir -p publish_wheelhouse
shopt -s nullglob
for FPATH in wheelhouse/*.whl wheelhouse/*.tar.gz wheelhouse/*.zip
do
cp "$FPATH" publish_wheelhouse/
done
ls -la publish_wheelhouse
- name: Publish live artifacts to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: publish_wheelhouse
skip-existing: true
- uses: actions/upload-artifact@v6.0.0
name: Upload deploy artifacts
with:
name: deploy_artifacts
path: |-
wheelhouse/*.whl
wheelhouse/*.zip
wheelhouse/*.tar.gz
wheelhouse/*.asc
wheelhouse/*.ots
permissions:
contents: read
id-token: write
environment: pypi
release:
name: Create Github Release
if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || startsWith(github.event.ref, 'refs/heads/release'))
runs-on: ubuntu-latest
permissions:
contents: write
needs:
- live_deploy
steps:
- name: Checkout source
uses: actions/checkout@v6.0.2
- uses: actions/download-artifact@v4.1.8
name: Download artifacts
with:
name: deploy_artifacts
path: wheelhouse
- name: Show files to release
shell: bash
run: ls -la wheelhouse
- run: 'echo "Automatic Release Notes. TODO: improve" > ${{ github.workspace }}-CHANGELOG.txt'
- name: Tag Release Commit
if: (startsWith(github.event.ref, 'refs/heads/release'))
run: |-
export VERSION=$(python -c "import setup; print(setup.VERSION)")
git tag "v$VERSION"
git push origin "v$VERSION"
- uses: softprops/action-gh-release@v1
name: Create Release
id: create_release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
body_path: ${{ github.workspace }}-CHANGELOG.txt
tag_name: ${{ github.ref }}
name: Release ${{ github.ref }}
body: Automatic Release
generate_release_notes: true
draft: true
prerelease: false
files: |-
wheelhouse/*.whl
wheelhouse/*.asc
wheelhouse/*.ots
wheelhouse/*.zip
wheelhouse/*.tar.gz
###
# Trusted publishing setup checklist
#
# This release workflow file:
# .github/workflows/release.yml
# Workflow page:
# github.com/Erotemic/xdoctest/actions/workflows/release.yml
# Workflow source:
# github.com/Erotemic/xdoctest/blob/main/.github/workflows/release.yml
# GitHub environments:
# github.com/Erotemic/xdoctest/settings/environments
#
# Official references:
# https://docs.pypi.org/trusted-publishers/
# https://docs.pypi.org/trusted-publishers/using-a-publisher/
# https://docs.pypi.org/trusted-publishers/security-model/
# https://docs.github.com/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
# https://docs.github.com/actions/deployment/targeting-different-environments/using-environments-for-deployment
#
# If trusted publishing is not configured yet:
#
# 1. In GitHub, create or review these protected environments:
# - testpypi
# - pypi
# URL:
# github.com/Erotemic/xdoctest/settings/environments
#
# Some xcookie setups will expect a setup like:
#
# - testpypi:
# * environment name: testpypi
# * use for non-release pushes that publish to TestPyPI
# * usually no manual approval is needed
# * optionally restrict deployment branches if you only want
# TestPyPI publishes from selected branches
#
# - pypi:
# * environment name: pypi
# * use for real releases only
# * require manual approval / required reviewers
# * prevent self-review if your org supports it
# * restrict deployments to release branches / version tags
#
# - do not put TWINE_* secrets in these environments when using
# trusted publishing
#
# - if enable_gpg=true and ci_gpg_secret_transport=encrypted_repo:
# store CI_SECRET as an environment secret (not repo-wide)
# - if enable_gpg=true and ci_gpg_secret_transport=direct_ci:
# store GPG_SECRET_SIGNING_SUBKEY_B64, GPG_PUBLIC_KEY_B64, and
# GPG_OWNER_TRUST_B64 as environment secrets; no CI_SECRET needed
#
# 2. In PyPI, add a trusted publisher for this project:
# owner: Erotemic
# repository: xdoctest
# workflow filename: release.yml
# environment: pypi
# Project publishing page:
# https://pypi.org/manage/project/xdoctest/settings/publishing/
# Account publishing page:
# https://pypi.org/manage/account/publishing/
#
# 3. In TestPyPI, add a trusted publisher for this project:
# owner: Erotemic
# repository: xdoctest
# workflow filename: release.yml
# environment: testpypi
# Project publishing page:
# https://test.pypi.org/manage/project/xdoctest/settings/publishing/
# Account publishing page:
# https://test.pypi.org/manage/account/publishing/
#
# Notes:
# - Keep the workflow filename stable after registration.
# - The PyPI/TestPyPI project pages may not exist until the project
# exists there; use the account publishing pages for pending publishers.
# - Trusted publishing removes TWINE_* secrets.
# - When enable_gpg=true and ci_gpg_secret_transport="encrypted_repo":
# CI_SECRET is still required (environment-scoped to pypi/testpypi).
# - When enable_gpg=true and ci_gpg_secret_transport="direct_ci":
# GPG_SECRET_SIGNING_SUBKEY_B64, GPG_PUBLIC_KEY_B64, and GPG_OWNER_TRUST_B64
# are required (environment-scoped to pypi/testpypi). No CI_SECRET.
#
# Local act note:
# Trusted publishing cannot be fully emulated with local act secrets.
# The local approximation is to run the signing / build portions only.
# load_secrets
# unset GITHUB_TOKEN
# $HOME/.local/opt/act/act \
# --secret=GPG_SECRET_SIGNING_SUBKEY_B64=$GPG_SECRET_SIGNING_SUBKEY_B64 \
# --secret=GPG_PUBLIC_KEY_B64=$GPG_PUBLIC_KEY_B64 \
# --secret=GPG_OWNER_TRUST_B64=$GPG_OWNER_TRUST_B64