diff --git a/CHANGELOG.md b/CHANGELOG.md index 10f86b02c..f91773617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,22 @@ ## [Unreleased] +## [v4.8.3](https://github.com/OpenNMT/CTranslate2/releases/tag/v4.8.3) (2026-10-13) + ### New features -* Support converting UMT5 models from Hugging Face Transformers +* Support converting UMT5 models from Hugging Face Transformers (#2103) by [@the-cross-art](https://github.com/the-cross-art) ### Fixes and improvements -* Support Transformer models where each layer has its own relative attention bias +* Support Transformer models where each layer has its own relative attention bias by [@the-cross-art](https://github.com/the-cross-art) +* Fix Windows ROCm Translator hangs and DLL loading (#2106) by [@0xDELUXA](https://github.com/0xDELUXA) +* Fix crashes when loading model files from Python file-like objects (#2110) by [@Purfview](https://github.com/Purfview) +* Upgrade pybind11 to 2.13.6 for CPython 3.14 allocator safety (#2108) by [@cepeter](https://github.com/cepeter) +* Guard exhausted candidates in CUDA TopK stage 2 (#2104) by [@mzggr0914](https://github.com/mzggr0914) +* Fix Windows shutdown deadlocks and memory leaks with the Ruy backend (#2076) by [@timo9378](https://github.com/timo9378) +* Add Clang ThreadSanitizer testing (#1986) by [@3manifold](https://github.com/3manifold) +* Improve ROCm wheel testing and release checks; upgrade build actions to Node.js 24 (#2112) by [@jordimas](https://github.com/jordimas) +* Add local CUDA and ROCm release validation with CI wheels and commit status reporting by [@jordimas](https://github.com/jordimas) ## [v4.8.2](https://github.com/OpenNMT/CTranslate2/releases/tag/v4.8.2) (2026-08-31) diff --git a/contributors.md b/contributors.md new file mode 100644 index 000000000..a88e50772 --- /dev/null +++ b/contributors.md @@ -0,0 +1,29 @@ +# Release validation + +1. Open a release PR and wait for CI to pass. +2. On each Linux x86-64 GPU machine, check out the PR head and build its native + tests locally. Install test dependencies, model data, GPU drivers, and runtime + libraries, including a GPU-compatible PyTorch. Authenticate with `gh auth login` + using an account permitted to download artifacts and write commit statuses. +3. Run the native and Python tests, including GPU tests: + + ```bash + bash tools/release-check.sh cuda + ``` + + Replace `cuda` with `rocm` on the AMD machine. + +The script finds the current branch's PR in the GitHub repository named by `origin`. +It checks that tracked files are clean and HEAD matches the PR, then +publishes `release/cuda` or `release/rocm` as pending, then success or failure. +It downloads the CUDA or ROCm wheel from the latest push CI run for that exact +commit. Wait for the wheel artifact to be uploaded before running validation. +The wheel is installed into a temporary environment that reuses your Python +dependencies; the environment is removed afterwards. Your installed CTranslate2 +is left untouched. Native tests use your local build, since CI does not upload it. +The script requires a visible GPU and both test commands to pass. +Detailed output stays in the terminal. + +Configure both statuses as required checks for release PRs. Re-run validation +for every new commit. Publish the validated artifacts after CI and both GPU +checks pass; validate again if the final release changes the tested code. diff --git a/python/ctranslate2/version.py b/python/ctranslate2/version.py index ebb987b0d..eec04197c 100644 --- a/python/ctranslate2/version.py +++ b/python/ctranslate2/version.py @@ -1,3 +1,3 @@ """Version information.""" -__version__ = "4.8.2" +__version__ = "4.8.3" diff --git a/tools/release-check.sh b/tools/release-check.sh new file mode 100755 index 000000000..f65367d14 --- /dev/null +++ b/tools/release-check.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Usage: bash tools/release-check.sh cuda|rocm +set -euo pipefail +if (( $# != 1 )) || [[ $1 != cuda && $1 != rocm ]]; then + echo "Usage: bash tools/release-check.sh cuda|rocm" >&2 + exit 2 +fi +backend=$1 +cd "$(git rev-parse --show-toplevel)" + +if ! git diff HEAD --quiet; then + echo "Commit or stash changes to tracked files before validation." >&2 + exit 1 +fi +if git remote get-url upstream >/dev/null 2>&1; then + repo=$(git remote get-url upstream) +else + repo=$(git remote get-url origin) +fi +repo=${repo#*github.com[:/]} +repo=${repo%.git} +sha=$(git rev-parse HEAD) +branch=$(git branch --show-current) +pr=$(gh pr list --repo "$repo" --state open --head "$branch" --json number,headRefOid --jq ".[] | select(.headRefOid == \"$sha\") | .number" | head -n 1) +if [[ -z $pr ]]; then + echo "Local HEAD is not the head commit of an open PR for $branch in $repo." >&2 + exit 1 +fi +publish() { + gh api "repos/$repo/statuses/$sha" \ + -f "state=$1" -f "context=release/$backend" >/dev/null +} +publish pending +state=failure +workdir=$(mktemp -d) +trap 'result=$?; rm -rf "$workdir"; publish "$state" || exit 1; exit "$result"' EXIT +artifact=python-wheels-Linux-auto64 +[[ $backend == rocm ]] && artifact=rocm-python-wheels-Linux +run=${RELEASE_CHECK_RUN_ID:-} +if [[ -n $run ]]; then + artifacts=$(gh api --paginate "repos/$repo/actions/runs/$run/artifacts" --jq '.artifacts[] | select(.expired == false) | .name') + if [[ $'\n'"$artifacts"$'\n' != *$'\n'"$artifact"$'\n'* ]]; then + echo "CI run $run does not contain an available $artifact artifact." >&2 + exit 1 + fi +else + runs=$(gh run list --repo "$repo" --workflow ci.yml --commit "$sha" --limit 100 --json databaseId --jq '.[].databaseId') + for candidate in $runs; do + artifacts=$(gh api --paginate "repos/$repo/actions/runs/$candidate/artifacts" --jq '.artifacts[] | select(.expired == false) | .name') + if [[ $'\n'"$artifacts"$'\n' == *$'\n'"$artifact"$'\n'* ]]; then + run=$candidate + break + fi + done +fi +if [[ -z $run ]]; then + echo "No CI run for commit $sha contains an available $artifact artifact." >&2 + exit 1 +fi +echo "Downloading $artifact from https://github.com/$repo/actions/runs/$run" +gh run download "$run" --repo "$repo" --name "$artifact" --dir "$workdir/wheels" +python -m venv "$workdir/venv" +python="$workdir/venv/bin/python" +"$python" -m pip install -r python/tests/requirements.txt +"$python" -m pip install --force-reinstall --find-links "$workdir/wheels" ctranslate2 +"$python" -I -c "import ctranslate2; print(ctranslate2.__file__); assert ctranslate2.get_cuda_device_count() > 0, 'No GPU available in the PR wheel; check drivers and runtime libraries'" +if [[ -x tests/ctranslate2_test ]]; then + tests/ctranslate2_test tests/data +else + echo "Skipping native tests: tests/ctranslate2_test is not built." >&2 +fi +"$python" -I -m pytest -v python/tests/ --ignore=python/tests/test_fairseq.py --ignore=python/tests/test_opennmt_py.py --ignore=python/tests/test_opennmt_tf.py +state=success