Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 73 additions & 3 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
name: Release Please

# `next` accumulates validated SDK changes in one versioned PR to `main`.
# Merging that PR creates the GitHub release; the package publishing workflow
# runs from the release event.
on:
push:
branches:
- next
- main

permissions:
contents: read

concurrency:
group: release-please
cancel-in-progress: false

jobs:
release-please:
if: github.repository == 'kernel/kernel-python-sdk'
Expand All @@ -26,7 +35,68 @@ jobs:
permission-pull-requests: write
permission-workflows: write

- uses: googleapis/release-please-action@5c625bfb5d1ff62eadeeb3772007f7f66fdcf071 # v4.4.1
id: release
- name: Set up Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: '18.20.2'

- name: Set up pnpm
uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4
with:
token: ${{ steps.release-token.outputs.token }}
version: '9.11.0'
run_install: false

- name: Build pinned release tooling
id: tooling
env:
RELEASE_PLEASE_DIR: ${{ runner.temp }}/release-please
RELEASE_PLEASE_SHA: a116e1e520e0f87824acf46a2e79c91d41e819d7
run: |
set -euo pipefail
rm -rf "$RELEASE_PLEASE_DIR"
git init "$RELEASE_PLEASE_DIR"
git -C "$RELEASE_PLEASE_DIR" remote add origin https://github.com/stainless-api/release-please.git
git -C "$RELEASE_PLEASE_DIR" fetch --depth=1 origin "$RELEASE_PLEASE_SHA"
git -C "$RELEASE_PLEASE_DIR" checkout --detach FETCH_HEAD
pnpm --dir "$RELEASE_PLEASE_DIR" install --frozen-lockfile
pnpm --dir "$RELEASE_PLEASE_DIR" build
echo "cli=$RELEASE_PLEASE_DIR/build/src/bin/release-please.js" >> "$GITHUB_OUTPUT"

- name: Open or update the release PR
if: github.ref_name == 'next'
env:
GH_TOKEN: ${{ steps.release-token.outputs.token }}
RELEASE_PLEASE: ${{ steps.tooling.outputs.cli }}
run: |
set -euo pipefail
node "$RELEASE_PLEASE" release-pr \
--repo-url "$GITHUB_REPOSITORY" \
--token "$GH_TOKEN" \
--target-branch main \
--changes-branch next

- name: Remove the legacy promotion PR
if: github.ref_name == 'next'
env:
GH_TOKEN: ${{ steps.release-token.outputs.token }}
run: |
set -euo pipefail
legacy=$(gh pr list --repo "$GITHUB_REPOSITORY" --head stainless/release \
--state open --json number --jq '.[].number')
for pr in $legacy; do
gh pr close "$pr" --repo "$GITHUB_REPOSITORY" \
--comment "Superseded by the versioned release PR from next to main."
done
gh api -X DELETE "repos/$GITHUB_REPOSITORY/git/refs/heads/stainless/release" >/dev/null 2>&1 || true

- name: Create the GitHub release
if: github.ref_name == 'main'
env:
GH_TOKEN: ${{ steps.release-token.outputs.token }}
RELEASE_PLEASE: ${{ steps.tooling.outputs.cli }}
run: |
set -euo pipefail
node "$RELEASE_PLEASE" github-release \
--repo-url "$GITHUB_REPOSITORY" \
--token "$GH_TOKEN" \
--target-branch main
118 changes: 84 additions & 34 deletions .github/workflows/stlc-promote.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
name: Promote SDKs
name: Promote SDK changes

# Production requires pull requests, so staging is promoted through a merge-
# commit PR. Never squash or rebase this cross-repo PR: preserving the incoming
# commits keeps production and staging on one ancestry chain.
# Staging is the generator's integration history. Production `next` is the
# developer-facing queue for the next release. This workflow combines the
# latest released state with validated staging changes, then advances `next`.
# Release automation maintains the single versioned PR from `next` to `main`.
on:
push:
branches: [main]
Expand Down Expand Up @@ -34,50 +35,99 @@ jobs:
owner: kernel
repositories: kernel-python-sdk
permission-contents: write
permission-workflows: write
permission-pull-requests: write
permission-workflows: write

- name: Fetch production main
- name: Fetch production branches
id: production
env:
GH_TOKEN: ${{ steps.production-token.outputs.token }}
PRODUCTION_REPO: kernel/kernel-python-sdk
run: |
git remote add production "https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git"
set -euo pipefail
git remote add production \
"https://x-access-token:${GH_TOKEN}@github.com/${PRODUCTION_REPO}.git"
git fetch production main

- name: Check whether production already has staging's content
id: diff
run: |
MERGED=$(git merge-tree --write-tree production/main origin/main) || MERGED=conflict
PRODUCTION_TREE=$(git rev-parse 'production/main^{tree}')
if [ "$MERGED" = "$PRODUCTION_TREE" ]; then
echo "Production already contains staging's content. Nothing to promote."
echo "synced=true" >> "$GITHUB_OUTPUT"
if git ls-remote --exit-code --heads production next >/dev/null 2>&1; then
git fetch production next
echo "has_next=true" >> "$GITHUB_OUTPUT"
else
echo "synced=false" >> "$GITHUB_OUTPUT"
echo "has_next=false" >> "$GITHUB_OUTPUT"
fi

- name: Push the production release branch
if: steps.diff.outputs.synced == 'false'
env:
GH_TOKEN: ${{ steps.production-token.outputs.token }}
PRODUCTION_REPO: kernel/kernel-python-sdk
run: git push production origin/main:refs/heads/stainless/release --force

- name: Open or update the promote PR
if: steps.diff.outputs.synced == 'false'
- name: Prepare the next release branch
env:
APP_SLUG: ${{ steps.production-token.outputs.app-slug }}
GH_TOKEN: ${{ steps.production-token.outputs.token }}
HAS_NEXT: ${{ steps.production.outputs.has_next }}
PRODUCTION_REPO: kernel/kernel-python-sdk
run: |
body=$(mktemp)
git log --oneline production/main..origin/main > "$body"
existing=$(gh pr list --repo "$PRODUCTION_REPO" --head stainless/release --state open --json number --jq 'if length == 0 then "" else .[0].number end')
if [ -z "$existing" ]; then
gh pr create --repo "$PRODUCTION_REPO" --base main --head stainless/release --title "Release SDK updates" --body-file "$body"
set -euo pipefail
bot_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id)
git config user.name "${APP_SLUG}[bot]"
git config user.email "${bot_id}+${APP_SLUG}[bot]@users.noreply.github.com"

open_conflict_pr() {
source_ref=$1
source_name=$2
advance_next=$3
conflict_branch=stlc/promotion-conflict

git merge --abort
existing=$(gh pr list --repo "$PRODUCTION_REPO" --base next \
--head "$conflict_branch" --state open --json url --jq '.[0].url // ""')
if [ -n "$existing" ]; then
echo "::error title=SDK promotion blocked::Resolve the existing recovery PR: $existing"
exit 1
fi

if [ "$advance_next" = "true" ]; then
git push production HEAD:refs/heads/next
fi
git push production "$source_ref:refs/heads/$conflict_branch" --force

body=$(mktemp)
printf '%s\n' \
'## SDK promotion conflict' \
'' \
"The automated promotion could not merge $source_name into the pending next release." \
'' \
'Resolve the conflicts on this branch, validate the SDK, mark this PR ready, and merge it with a merge commit.' \
'' \
'After merging, rerun the staging Promote SDK changes workflow to include any newer generated changes.' \
> "$body"
recovery_url=$(gh pr create --repo "$PRODUCTION_REPO" --draft \
--base next --head "$conflict_branch" \
--title 'chore: resolve SDK promotion conflict' --body-file "$body")
echo "::error title=SDK promotion conflict::Resolve the recovery PR: $recovery_url"
exit 1
}

if [ "$HAS_NEXT" = "true" ]; then
git checkout -B stlc/promote-next production/next
else
gh pr edit "$existing" --repo "$PRODUCTION_REPO" --title "Release SDK updates" --body-file "$body"
git checkout -B stlc/promote-next production/main
fi

if ! git merge-base --is-ancestor production/main HEAD; then
if ! git merge --no-edit production/main; then
open_conflict_pr production/main 'production main' false
fi
fi
if ! git merge-base --is-ancestor origin/main HEAD; then
if ! git merge --no-edit origin/main; then
open_conflict_pr origin/main 'validated staging changes' true
fi
fi
if ! gh pr merge stainless/release --repo "$PRODUCTION_REPO" --merge --auto; then
echo "::warning title=Manual promotion required::Merge the promote PR with a merge commit."

if [ "$HAS_NEXT" = "true" ]; then
git merge-base --is-ancestor production/next HEAD
fi

- name: Update the pending release
env:
GH_TOKEN: ${{ steps.production-token.outputs.token }}
run: |
set -euo pipefail
git push production HEAD:refs/heads/next
echo "Updated production next; the versioned release PR will be opened or refreshed."
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.88.0"
".": "0.88.1"
}
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.88.1 (2026-08-10)

Full Changelog: [v0.88.0...v0.88.1](https://github.com/kernel/kernel-python-sdk/compare/v0.88.0...v0.88.1)

## [0.88.0](https://github.com/kernel/kernel-python-sdk/compare/v0.87.0...v0.88.0) (2026-08-10)

### Features
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "kernel"
version = "0.88.0"
version = "0.88.1"
description = "The official Python library for the kernel API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": false,
"pull-request-header": "Automated Release PR",
"pull-request-footer": "Merge this pull request with a merge commit. Merging creates the GitHub release and publishes the package.",
"pull-request-title-pattern": "release: ${version}",
"changelog-sections": [
{
Expand Down
2 changes: 1 addition & 1 deletion src/kernel/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "kernel"
__version__ = "0.88.0" # x-release-please-version
__version__ = "0.88.1" # x-release-please-version
Loading