Skip to content

fix: 修正 changelog 检查脚本中变量引用错误 #54

fix: 修正 changelog 检查脚本中变量引用错误

fix: 修正 changelog 检查脚本中变量引用错误 #54

Workflow file for this run

name: ci
on:
push:
branches:
- main
tags:
- "**"
pull_request: {}
env:
COLUMNS: 150
UV_PYTHON: 3.13
# Avoid duplicate runs on rapid pushes
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# 检测哪些文件类型发生了变更
changes:
runs-on: ubuntu-latest
# 如果是 tag push(发版),跳过这个检测,所有 jobs 都运行
if: "!startsWith(github.ref, 'refs/tags/')"
outputs:
code: ${{ steps.filter.outputs.code }}
docs: ${{ steps.filter.outputs.docs }}
ci: ${{ steps.filter.outputs.ci }}
deps: ${{ steps.filter.outputs.deps }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
code:
- 'src/**'
- 'python/**'
- 'tests/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'pyproject.toml'
- 'build.rs'
docs:
- '**.md'
- 'LICENSE'
ci:
- '.github/workflows/**'
- 'Makefile'
deps:
- 'Cargo.toml'
- 'Cargo.lock'
- 'pyproject.toml'
coverage:
runs-on: ubuntu-latest
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')
steps:
- uses: actions/checkout@v4
# rust-nightly used for `#[coverage(off)]`
- uses: dtolnay/rust-toolchain@nightly
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@cargo-llvm-cov
- name: install uv
uses: astral-sh/setup-uv@v6
- name: install deps
run: uv sync --group testing
- run: rustc --version --verbose
- run: |
source <(cargo llvm-cov show-env --export-prefix)
cargo llvm-cov clean --workspace --profraw-only
make build-dev
env:
RUST_BACKTRACE: 1
RUSTFLAGS: "-C instrument-coverage"
- run: uv pip freeze
- run: uv run coverage run -m pytest --junitxml=junit.xml -o junit_family=legacy
- run: ls -lha
- run: uv run coverage xml
- run: |
source <(cargo llvm-cov show-env --export-prefix)
cargo llvm-cov --codecov --output-path=codecov.json
- uses: codecov/codecov-action@v5
with:
files: codecov.json
token: ${{ secrets.CODECOV_TOKEN }}
- uses: codecov/test-results-action@v1
# See https://github.com/PyO3/pyo3/discussions/2781
# tests intermittently segfault with pypy and cpython 3.7 when using `coverage run ...`, hence separate job
test-python:
name: test ${{ matrix.python-version }}
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')
strategy:
fail-fast: false
matrix:
python-version:
- "3.10"
- "3.11"
- "3.12"
- "3.13"
runs-on: ubuntu-latest
# TODO: get test suite stable with free-threaded python
continue-on-error: false
steps:
- uses: actions/checkout@v4
- name: install rust stable
uses: dtolnay/rust-toolchain@stable
- name: cache rust
uses: Swatinem/rust-cache@v2
with:
key: test-v3
- name: install uv
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
- name: install deps
run: uv sync --group testing
- run: uv pip install -e .
env:
RUST_BACKTRACE: 1
- run: uv pip freeze
- run: uv run pytest -n logical
env:
HYPOTHESIS_PROFILE: slow
PYTEST_ADDOPTS: ${{ (endsWith(matrix.python-version, 't') || matrix.python-version == '3.14') && '--parallel-threads=2' || '' }}
test-os:
name: test on ${{ matrix.os }}
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos, windows]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v4
- name: install rust stable
uses: dtolnay/rust-toolchain@stable
- name: cache rust
uses: Swatinem/rust-cache@v2
- name: install uv
uses: astral-sh/setup-uv@v6
- name: install deps
run: uv sync --group testing
- run: uv pip install -e .
env:
RUST_BACKTRACE: 1
- run: uv pip freeze
- run: uv run pytest -n logical
- run: cargo test
test-msrv:
name: test MSRV
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install uv
uses: astral-sh/setup-uv@v6
- name: install deps
run: uv sync --group testing
- name: resolve MSRV
id: resolve-msrv
run: echo MSRV=`uv run python -c 'import tomllib; print(tomllib.load(open("Cargo.toml", "rb"))["package"]["rust-version"])'` >> $GITHUB_OUTPUT
- name: install rust MSRV
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.resolve-msrv.outputs.MSRV }}
- name: cache rust
uses: Swatinem/rust-cache@v2
- run: uv pip install -e .
env:
RUST_BACKTRACE: 1
- run: uv pip freeze
- run: uv run pytest -n logical
- run: cargo test
# test with a debug build as it picks up errors which optimised release builds do not
test-debug:
name: test-debug ${{ matrix.python-version }}
runs-on: ubuntu-latest
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')
strategy:
fail-fast: false
matrix:
python-version:
- "3.13"
steps:
- uses: actions/checkout@v4
- name: install uv
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.python-version }}
- name: install rust stable
uses: dtolnay/rust-toolchain@stable
- name: cache rust
uses: Swatinem/rust-cache@v2
- name: install deps
run: uv sync --group testing
- run: make build-dev
- run: uv pip freeze
- run: uv run pytest -n logical
lint:
runs-on: ubuntu-latest
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')
steps:
- uses: actions/checkout@v4
- name: install rust stable
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: cache rust
uses: Swatinem/rust-cache@v2
# used to lint js code
- uses: actions/setup-node@v4
with:
node-version: "18"
- name: install uv
uses: astral-sh/setup-uv@v6
- name: install deps
run: |
uv sync --group linting
make build-dev
uv pip freeze
- run: make lint
# https://github.com/marketplace/actions/alls-green#why used for branch protection checks
check:
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
needs.changes.result == 'skipped' ||
(needs.changes.result == 'success' &&
(needs.changes.outputs.code == 'true' ||
needs.changes.outputs.ci == 'true' ||
needs.changes.outputs.deps == 'true')))
needs: [coverage, test-python, test-os, test-debug, lint]
runs-on: ubuntu-latest
steps:
- name: Decide whether the needed jobs succeeded or failed
uses: re-actors/alls-green@release/v1
with:
jobs: ${{ toJSON(needs) }}
allowed-failures: coverage
build-sdist:
name: build sdist
runs-on: ubuntu-latest
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
contains(github.event.pull_request.labels.*.name, 'Full Build') ||
needs.changes.result == 'skipped' ||
(github.ref == 'refs/heads/main' &&
(needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true')))
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
rust-toolchain: stable
- uses: actions/upload-artifact@v4
with:
name: pypi_files_sdist
path: dist
build:
name: build on ${{ matrix.os }} (${{ matrix.target }} - ${{ matrix.interpreter || 'all' }}${{ matrix.os == 'linux' && format(' - {0}', matrix.manylinux == 'auto' && 'manylinux' || matrix.manylinux) || '' }})
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
contains(github.event.pull_request.labels.*.name, 'Full Build') ||
needs.changes.result == 'skipped' ||
(github.ref == 'refs/heads/main' &&
(needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true')))
strategy:
fail-fast: false
matrix:
os: [linux, macos, windows]
target: [x86_64, aarch64]
manylinux: [auto]
include:
# manylinux for various platforms, plus x86_64 pypy
- os: linux
manylinux: auto
target: i686
- os: linux
manylinux: auto
target: armv7
interpreter: 3.10 3.11 3.12 3.13
- os: linux
manylinux: auto
target: ppc64le
interpreter: 3.10 3.11 3.12 3.13
- os: linux
manylinux: auto
target: s390x
interpreter: 3.10 3.11 3.12 3.13
- os: linux
manylinux: auto
target: x86_64
interpreter: pypy3.11
# musllinux
- os: linux
manylinux: musllinux_1_1
target: x86_64
- os: linux
manylinux: musllinux_1_1
target: aarch64
- os: linux
manylinux: musllinux_1_1
target: armv7
# macos;
# all versions x86_64
# arm pypy and older pythons which can't be run on the arm hardware for PGO
- os: macos
target: x86_64
- os: macos
target: aarch64
interpreter: pypy3.11
# windows;
# x86_64 pypy builds are not PGO optimized
# i686 not supported by pypy
# aarch64 only 3.11 and up, also not PGO optimized
- os: windows
target: x86_64
interpreter: pypy3.11
- os: windows
target: i686
python-architecture: x86
interpreter: 3.10 3.11 3.12 3.13
exclude:
# See above; disabled for now.
- os: windows
target: aarch64
runs-on: ${{ (matrix.os == 'linux' && 'ubuntu') || matrix.os }}-latest
steps:
- uses: actions/checkout@v4
- name: set up python
uses: actions/setup-python@v5
with:
python-version: "3.13"
architecture: ${{ matrix.python-architecture || 'x64' }}
- run: pip install -U twine 'ruff==0.5.0' typing_extensions
- name: build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
manylinux: ${{ matrix.manylinux }}
args: --release --out dist --interpreter ${{ matrix.interpreter || '3.10 3.11 3.12 3.13 pypy3.11' }}
rust-toolchain: stable
docker-options: -e CI
- run: ${{ (matrix.os == 'windows' && 'dir') || 'ls -lh' }} dist/
- run: twine check --strict dist/*
- uses: actions/upload-artifact@v4
with:
name: pypi_files_${{ matrix.os }}_${{ matrix.target }}_${{ matrix.interpreter || 'all' }}_${{ matrix.manylinux }}
path: dist
build-pgo:
name: build pgo-optimized on ${{ matrix.os }} / ${{ matrix.interpreter }}
needs: [changes]
if: |
always() &&
(startsWith(github.ref, 'refs/tags/') ||
contains(github.event.pull_request.labels.*.name, 'Full Build') ||
needs.changes.result == 'skipped' ||
(github.ref == 'refs/heads/main' &&
(needs.changes.outputs.code == 'true' || needs.changes.outputs.deps == 'true')))
strategy:
fail-fast: false
matrix:
os: [linux, windows, macos]
interpreter: ["3.10", "3.11", "3.12", "3.13"]
include:
# standard runners with override for macos arm
- os: linux
runs-on: ubuntu-latest
- os: windows
ls: dir
runs-on: windows-latest
- os: macos
runs-on: macos-latest
continue-on-error: false
runs-on: ${{ matrix.runs-on }}
steps:
- uses: actions/checkout@v4
- name: install uv
uses: astral-sh/setup-uv@v6
with:
python-version: ${{ matrix.interpreter }}
- name: install rust stable
id: rust-toolchain
uses: dtolnay/rust-toolchain@master
with:
components: llvm-tools
toolchain: stable
- name: Build PGO wheel
id: pgo-wheel
uses: ./.github/actions/build-pgo-wheel
with:
interpreter: ${{ matrix.interpreter }}
rust-toolchain: ${{ steps.rust-toolchain.outputs.name }}
- run: ${{ matrix.ls || 'ls -lh' }} dist/
- uses: actions/upload-artifact@v4
with:
name: pypi_files_${{ matrix.os }}_${{ matrix.interpreter }}
path: dist
inspect-pypi-assets:
needs: [build, build-sdist, build-pgo]
runs-on: ubuntu-latest
# 只在 build jobs 实际运行时才运行
if: |
always() &&
(needs.build.result == 'success' ||
needs.build-sdist.result == 'success' ||
needs.build-pgo.result == 'success')
steps:
- uses: actions/checkout@v4
- name: get dist artifacts
uses: actions/download-artifact@v4
with:
pattern: pypi_files_*
merge-multiple: true
path: dist
- name: list dist files
run: |
ls -lh dist/
ls -l dist/
echo "`ls dist | wc -l` files"
- name: extract and list sdist file
run: |
mkdir sdist-files
tar -xvf dist/*.tar.gz -C sdist-files
tree -a sdist-files
- name: extract and list wheel file
run: |
ls dist/*cp310-manylinux*x86_64.whl | head -n 1
python -m zipfile --list `ls dist/*cp310-manylinux*x86_64.whl | head -n 1`
test-builds-arch:
name: test build on ${{ matrix.target }}-${{ matrix.distro }}
needs: [build]
runs-on: ubuntu-latest
# 只在 build job 成功后运行
if: needs.build.result == 'success'
strategy:
fail-fast: false
matrix:
target: [aarch64, armv7, s390x, ppc64le]
distro: ["ubuntu22.04"]
include:
- target: aarch64
distro: alpine_latest
steps:
- uses: actions/checkout@v4
- name: get dist artifacts
uses: actions/download-artifact@v4
with:
pattern: pypi_files_linux_*
merge-multiple: true
path: dist
- uses: uraimo/run-on-arch-action@v3.0.1
name: install & test
with:
arch: ${{ matrix.target }}
distro: ${{ matrix.distro }}
githubToken: ${{ github.token }}
install: |
set -x
if command -v apt-get &> /dev/null; then
echo "installing python & pip with apt-get..."
apt-get update
apt-get install -y --no-install-recommends python3 python3-pip python3-venv git curl iputils-ping
else
echo "installing python & pip with apk..."
apk update
apk add python3 py3-pip git curl iputils-ping
fi
run: |
set -x
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
uv sync --frozen --group testing --no-install-project
uv pip install ping-rs --no-index --no-deps --find-links dist --force-reinstall
uv run --no-sync pytest -n logical
uv run --no-sync python -c 'import ping_rs._ping_rs; print(ping_rs._ping_rs.__version__)'
test-builds-os:
name: test build on ${{ matrix.os }}
needs: [build, build-pgo]
# 只在 build jobs 成功后运行
if: |
always() &&
(needs.build.result == 'success' || needs.build-pgo.result == 'success')
strategy:
fail-fast: false
matrix:
os: [ubuntu, macos, windows]
runs-on: ${{ matrix.os }}-latest
steps:
- uses: actions/checkout@v4
- name: install uv
uses: astral-sh/setup-uv@v6
- name: get dist artifacts
uses: actions/download-artifact@v4
with:
pattern: pypi_files_*
merge-multiple: true
path: dist
- run: uv sync --group testing
- run: uv pip install ping-rs --no-index --no-deps --find-links dist --force-reinstall
- run: uv run pytest -n logical
release:
needs: [test-builds-arch, test-builds-os, build-sdist, check]
if: always() && startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4
- name: set up python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- run: pip install -U twine
- name: check package version
run: python .github/check_version.py
- name: get dist artifacts
uses: actions/download-artifact@v4
with:
pattern: pypi_files_*
merge-multiple: true
path: dist
- run: twine check --strict dist/*
- name: Derive version from tag (strip leading 'v')
id: derive_version
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Read Changelog (English)
id: changelog_en
uses: mindsers/changelog-reader-action@v2
continue-on-error: true
with:
validation_level: none
version: ${{ steps.derive_version.outputs.version }}
path: ./CHANGELOG.md
- name: Read Changelog (Chinese)
id: changelog_zh
uses: mindsers/changelog-reader-action@v2
continue-on-error: true
with:
validation_level: none
version: ${{ steps.derive_version.outputs.version }}
path: ./CHANGELOG_ZH.md
- name: Create bilingual release notes
run: |
cat << 'EOF' > release_notes.md
## English
${{ steps.changelog_en.outputs.changes }}
---
## 简体中文
${{ steps.changelog_zh.outputs.changes }}
EOF
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
- name: upload to github release
uses: softprops/action-gh-release@v2
with:
body_path: release_notes.md
files: |
dist/*.whl
dist/*.tar.gz
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}