Skip to content

docs: retranslate the 简体中文 README and manual; pypi: pip install mcpp-bin #1

docs: retranslate the 简体中文 README and manual; pypi: pip install mcpp-bin

docs: retranslate the 简体中文 README and manual; pypi: pip install mcpp-bin #1

Workflow file for this run

name: pypi-publish
# Publish the `mcpp-bin` wheels to PyPI (`pip install mcpp-bin`).
#
# Downstream of `release`, like aur-publish.yml and homebrew-publish.yml: the
# wheels are built from the release's own mcpp-release.json and payloads, so
# this runs only once the release workflow has completed.
#
# CREDENTIALS: none stored. Publishing uses PyPI Trusted Publishing (OIDC):
# PyPI trusts this repository + workflow file + the `pypi` environment, and
# the job exchanges its GitHub OIDC token for a short-lived upload token.
# One-time setup is in scripts/pypi/README.md.
#
# ARMING: the automatic trigger builds, verifies and reports, and publishes
# only when the repository variable PYPI_AUTOPUBLISH is `true`, for the reason
# aur-publish.yml gives: an unattended push to a third-party service must be
# armed by a human who has watched one publish succeed, not inherited from a
# merge. `workflow_dispatch` carries its own explicit `publish` switch.
on:
workflow_run:
workflows: [release]
types: [completed]
# Changes to the packaging itself build and pip-install the wheels of the
# latest release on every platform. A pull request never publishes.
pull_request:
paths:
- scripts/pypi/**
- tests/scripts/test_pypi_wheels.py
- .github/workflows/pypi-publish.yml
workflow_dispatch:
inputs:
publish:
description: 'Upload to PyPI (false builds and verifies only)'
type: boolean
required: true
default: false
tag:
description: 'Release tag, e.g. v2026.9.21.3 (default: the latest release)'
type: string
required: false
concurrency:
group: pypi-mcpp-bin
cancel-in-progress: false
permissions:
contents: read
jobs:
build:
name: build wheels
if: >-
github.event_name != 'workflow_run' ||
github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-24.04
timeout-minutes: 20
outputs:
version: ${{ steps.resolve.outputs.version }}
publish: ${{ steps.resolve.outputs.publish }}
env:
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha || github.ref }}
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Builder contract tests
run: python3 tests/scripts/test_pypi_wheels.py
- name: Resolve the release and whether to publish
id: resolve
env:
TRIGGER: ${{ github.event_name }}
INPUT_TAG: ${{ inputs.tag }}
MANUAL_PUBLISH: ${{ inputs.publish }}
AUTOPUBLISH: ${{ vars.PYPI_AUTOPUBLISH }}
run: |
set -euo pipefail
if [[ -n "${INPUT_TAG:-}" ]]; then
tag="$INPUT_TAG"
elif [[ "$TRIGGER" == "workflow_run" ]]; then
# The released commit's mcpp.toml carries the released version.
tag="v$(grep -m1 -E '^\s*version\s*=' mcpp.toml | sed -E 's/.*"([^"]+)".*/\1/')"
else
tag="$(gh release view -R "$GITHUB_REPOSITORY" --json tagName --jq .tagName)"
fi
version="${tag#v}"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
# PyPI never accepts the same file twice, so an existing version is
# a finished job rather than something to retry.
code=$(curl -s -o /dev/null -w '%{http_code}' --retry 3 --retry-all-errors \
"https://pypi.org/pypi/mcpp-bin/$version/json")
if [[ "$code" == "200" ]]; then
echo "::notice::mcpp-bin $version is already on PyPI; nothing to publish."
publish=false
elif [[ "$TRIGGER" == "workflow_run" ]]; then
if [[ "${AUTOPUBLISH:-}" == "true" ]]; then
publish=true
else
publish=false
echo "::notice::PYPI_AUTOPUBLISH is not set — building and verifying $tag without publishing."
fi
elif [[ "$TRIGGER" == "workflow_dispatch" ]]; then
publish="${MANUAL_PUBLISH:-false}"
else
publish=false
fi
echo "publish=$publish" >> "$GITHUB_OUTPUT"
echo "mcpp-bin $version from $tag; publish=$publish" >> "$GITHUB_STEP_SUMMARY"
- name: Build wheels from the release manifest
run: python3 scripts/pypi/build_wheels.py --tag "${{ steps.resolve.outputs.tag }}" --out dist
- name: Check metadata
run: |
python3 -m pip install --quiet twine
python3 -m twine check --strict dist/*.whl
- uses: actions/upload-artifact@v4
with:
name: mcpp-bin-wheels
path: dist/*.whl
if-no-files-found: error
# pip, not this workflow, picks the wheel: each runner installs from the
# directory of all four, so a wrong platform tag fails here rather than on a
# user's machine. The run then checks the two properties the launcher exists
# for: the per-user home is outside the Python environment, and the bundled
# xlings is the one seeded into it.
smoke:
name: pip install (${{ matrix.os }})
needs: build
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
timeout-minutes: 20
steps:
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: actions/download-artifact@v4
with:
name: mcpp-bin-wheels
path: dist
- name: Install and run
shell: bash
env:
VERSION: ${{ needs.build.outputs.version }}
run: |
set -euo pipefail
python -m venv venv
if [[ -x venv/Scripts/python.exe ]]; then py=venv/Scripts/python.exe; bin=venv/Scripts; else py=venv/bin/python; bin=venv/bin; fi
"$py" -m pip install --quiet --no-index --find-links dist mcpp-bin
home="$RUNNER_TEMP/home"; mkdir -p "$home"
export HOME="$home" USERPROFILE="$home"
unset MCPP_HOME MCPP_VENDORED_XLINGS
out="$("$bin/mcpp" --version)"
echo "$out"
[[ "$out" == *"$VERSION"* ]] || { echo "::error::expected $VERSION, got: $out"; exit 1; }
"$bin/mcpp" self env | tee env.txt
grep -F "MCPP_HOME" env.txt | grep -F ".mcpp" \
|| { echo "::error::MCPP_HOME is not the per-user home"; exit 1; }
if grep -F "MCPP_HOME" env.txt | grep -qF "site-packages"; then
echo "::error::MCPP_HOME resolved into the Python environment"; exit 1
fi
# On Windows mcpp runs the vendored xlings in place (src/config.cppm,
# make_xlings_env), so the seeded copy is checked on POSIX only.
if [[ "$RUNNER_OS" != "Windows" ]]; then
ls "$home/.mcpp/registry/bin/" | grep -q '^xlings' \
|| { echo "::error::the bundled xlings was not seeded into the home"; exit 1; }
fi
publish:
name: publish to PyPI
needs: [build, smoke]
if: needs.build.outputs.publish == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 15
environment:
name: pypi
url: https://pypi.org/project/mcpp-bin/${{ needs.build.outputs.version }}/
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: mcpp-bin-wheels
path: dist
- uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: dist/