mirror of
https://github.com/Canner/WrenAI.git
synced 2026-08-29 00:03:22 +08:00
ci(release): give the bindings a release trigger after a core release (#2663)
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
name: Release bindings after a core release
|
||||
|
||||
# wren-core-py and wren-core-wasm depend on the Rust core by path alone, and
|
||||
# release-please attributes commits to packages by file path. An engine change
|
||||
# under core/wren-core is therefore attributed to wren-semantic-core and never
|
||||
# to the bindings, so no release PR is ever opened for them — and the release
|
||||
# commit that bumps the core crates is a chore commit release-please skips by
|
||||
# design, so it cannot serve as the trigger either.
|
||||
#
|
||||
# This workflow closes that gap. After the core crates release, it refreshes the
|
||||
# two binding lockfiles against the new core version and opens a PR whose commit
|
||||
# touches both binding directories. Merging that PR is what gives the bindings a
|
||||
# release line of their own.
|
||||
#
|
||||
# The lockfile refresh used to happen inside the release commit (release-please
|
||||
# extra-files). It was moved here deliberately: anything the release commit
|
||||
# writes cannot trigger the next release. No workflow builds the bindings with
|
||||
# `cargo --locked`, so the lag between the release commit and this PR breaks
|
||||
# nothing, and the bindings' release tags are cut after this PR merges, so a
|
||||
# published wheel still ships a synced lockfile.
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
description: "Released wren-core version (e.g. 0.3.1)"
|
||||
required: true
|
||||
type: string
|
||||
# Manual fallback: re-run if the automatic run failed or was skipped.
|
||||
# Leave version blank to use the release tracked in the repo.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "wren-core version to sync to; blank = .release-please-manifest.json"
|
||||
required: false
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
# Serialize runs so two can't push the same branch at once. Constant key (not
|
||||
# per-version) because a blank-dispatch version is only known at run time.
|
||||
concurrency:
|
||||
group: release-bindings-after-core
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
sync-and-open-pr:
|
||||
if: ${{ github.repository == 'Canner/WrenAI' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout main
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# The release job takes minutes; main may have moved. Base the PR on
|
||||
# main tip.
|
||||
ref: main
|
||||
# Keep the write token out of .git/config; the push re-authenticates.
|
||||
persist-credentials: false
|
||||
|
||||
- name: Resolve and validate version
|
||||
env:
|
||||
INPUT_VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
# workflow_call always passes the released version; manual runs may
|
||||
# omit it and fall back to the release tracked in the repo.
|
||||
version="${INPUT_VERSION:-$(jq -r '."core/wren-core"' .release-please-manifest.json)}"
|
||||
# Guard a malformed version out of the assertion, branch name, and PR.
|
||||
if [[ ! "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "::error::Unsupported version: ${version}. Expected X.Y.Z."
|
||||
exit 1
|
||||
fi
|
||||
echo "Syncing bindings to wren-core ${version}"
|
||||
echo "VERSION=${version}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Refresh binding lockfiles
|
||||
run: |
|
||||
for dir in core/wren-core-py core/wren-core-wasm; do
|
||||
# Re-resolve against the bumped path crates. cargo rewrites only
|
||||
# what must change, so registry dependencies keep their locked
|
||||
# versions and the diff stays limited to the core crates.
|
||||
cargo metadata --manifest-path "${dir}/Cargo.toml" --format-version 1 >/dev/null
|
||||
done
|
||||
|
||||
- name: Assert the lockfiles record the released version
|
||||
env:
|
||||
RELEASED_VERSION: ${{ env.VERSION }}
|
||||
shell: python
|
||||
run: |
|
||||
import os, sys, tomllib
|
||||
|
||||
released = os.environ["RELEASED_VERSION"]
|
||||
# The three crates are linked to a single version by release-please,
|
||||
# so every one of them must read as the version just released.
|
||||
tracked = {"wren-semantic-core", "wren-core-base", "wren-manifest-macro"}
|
||||
failed = False
|
||||
for path in ("core/wren-core-py/Cargo.lock", "core/wren-core-wasm/Cargo.lock"):
|
||||
with open(path, "rb") as handle:
|
||||
packages = tomllib.load(handle)["package"]
|
||||
found = {p["name"]: p["version"] for p in packages if p["name"] in tracked}
|
||||
missing = tracked - found.keys()
|
||||
if missing:
|
||||
print(f"::error::{path} is missing {', '.join(sorted(missing))}")
|
||||
failed = True
|
||||
for name, version in sorted(found.items()):
|
||||
if version != released:
|
||||
print(f"::error::{path}: {name} is {version}, expected {released}")
|
||||
failed = True
|
||||
sys.exit(1 if failed else 0)
|
||||
|
||||
- name: Detect changes
|
||||
id: diff
|
||||
run: |
|
||||
if git diff --quiet -- core/wren-core-py/Cargo.lock core/wren-core-wasm/Cargo.lock; then
|
||||
echo "changed=false" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changed=true" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Report a no-op
|
||||
if: steps.diff.outputs.changed == 'false'
|
||||
run: |
|
||||
echo "::warning::Binding lockfiles already record wren-core ${VERSION};" \
|
||||
"no commit to open, so no binding release will be triggered."
|
||||
|
||||
# Opened with GITHUB_TOKEN, like sync-wren-core-py-lock.yml. GitHub puts
|
||||
# the pull_request runs of a token-created PR in an approval-required
|
||||
# state, so whoever reviews it also clicks "Approve and run workflows"
|
||||
# once. A PAT or App installation token would remove that click at the
|
||||
# cost of a long-lived credential in the repo; the click is cheaper.
|
||||
- name: Open the binding release PR
|
||||
if: steps.diff.outputs.changed == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
BRANCH="fix/release-bindings-wren-core-${VERSION}"
|
||||
TITLE="fix(bindings): build against wren-core ${VERSION}"
|
||||
# If a PR is already open for this bump, leave it untouched.
|
||||
if [ "$(gh pr list --repo "${GITHUB_REPOSITORY}" --state open --head "${BRANCH}" --json number --jq 'length')" != "0" ]; then
|
||||
echo "Open PR for ${BRANCH} already exists; leaving it untouched."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git checkout -b "${BRANCH}"
|
||||
git add core/wren-core-py/Cargo.lock core/wren-core-wasm/Cargo.lock
|
||||
git commit -m "${TITLE}"
|
||||
# No open PR: --force only overwrites a leftover branch from a closed
|
||||
# PR. Auth the push explicitly since credentials aren't persisted.
|
||||
git push --force \
|
||||
"https://x-access-token:${GH_TOKEN}@${GITHUB_SERVER_URL#https://}/${GITHUB_REPOSITORY}.git" \
|
||||
"${BRANCH}"
|
||||
cat > "${RUNNER_TEMP}/pr-body.md" <<EOF
|
||||
Automated follow-up to the wren-core ${VERSION} release. Relocks
|
||||
core/wren-core-py and core/wren-core-wasm against the released core crates.
|
||||
|
||||
Merging this PR is what gives the bindings a release: it is a fix commit under
|
||||
both binding directories, so release-please will open a release PR for
|
||||
wren-core-py and wren-core-wasm. Without it the bindings have no commit of their
|
||||
own, and the engine change never reaches PyPI or npm.
|
||||
|
||||
**Keep the title as-is when squashing** — release-please reads it as the commit
|
||||
subject.
|
||||
EOF
|
||||
gh pr create \
|
||||
--repo "${GITHUB_REPOSITORY}" \
|
||||
--base main \
|
||||
--head "${BRANCH}" \
|
||||
--title "${TITLE}" \
|
||||
--body-file "${RUNNER_TEMP}/pr-body.md"
|
||||
@@ -126,3 +126,19 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
# wren-core-py and wren-core-wasm depend on the core crates by path, so
|
||||
# release-please never attributes an engine change to them and they would
|
||||
# otherwise never release. Relock them against the new core version and open a
|
||||
# PR whose fix commit gives them a release line. Deliberately not gated on
|
||||
# publish-wren-crates: a crates.io publish failure should not also keep the
|
||||
# engine change out of PyPI and npm.
|
||||
release-bindings-after-core:
|
||||
needs: release-please
|
||||
if: needs.release-please.outputs['wren-semantic-core--release_created'] == 'true'
|
||||
uses: ./.github/workflows/release-bindings-after-core.yml
|
||||
with:
|
||||
version: ${{ needs.release-please.outputs['wren-semantic-core--version'] }}
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
@@ -56,19 +56,7 @@
|
||||
"core/wren-core-base/manifest-macro": {
|
||||
"component": "wren-manifest-macro",
|
||||
"release-type": "rust",
|
||||
"bump-minor-pre-major": true,
|
||||
"extra-files": [
|
||||
{
|
||||
"path": "/core/wren-core-py/Cargo.lock",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.package[?(@.name.value=='wren-manifest-macro')].version"
|
||||
},
|
||||
{
|
||||
"path": "/core/wren-core-wasm/Cargo.lock",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.package[?(@.name.value=='wren-manifest-macro')].version"
|
||||
}
|
||||
]
|
||||
"bump-minor-pre-major": true
|
||||
},
|
||||
"core/wren-core-base": {
|
||||
"component": "wren-core-base",
|
||||
@@ -79,16 +67,6 @@
|
||||
"path": "Cargo.toml",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.dependencies.wren-manifest-macro.version"
|
||||
},
|
||||
{
|
||||
"path": "/core/wren-core-py/Cargo.lock",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.package[?(@.name.value=='wren-core-base')].version"
|
||||
},
|
||||
{
|
||||
"path": "/core/wren-core-wasm/Cargo.lock",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.package[?(@.name.value=='wren-core-base')].version"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -111,16 +89,6 @@
|
||||
"path": "/core/wren-core-py/Cargo.toml",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.dependencies.wren-core.version"
|
||||
},
|
||||
{
|
||||
"path": "/core/wren-core-py/Cargo.lock",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.package[?(@.name.value=='wren-semantic-core')].version"
|
||||
},
|
||||
{
|
||||
"path": "/core/wren-core-wasm/Cargo.lock",
|
||||
"type": "toml",
|
||||
"jsonpath": "$.package[?(@.name.value=='wren-semantic-core')].version"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user