Skip to content
Merged
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/hypeman-ts'
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
114 changes: 93 additions & 21 deletions .github/workflows/stlc-promote.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
name: Promote SDKs
name: Promote SDK changes

# Manually fast-forwards production main to the reviewed staging main. The
# ancestor check refuses divergent histories; this workflow never force-pushes.
# 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]
workflow_dispatch: {}

permissions:
Expand All @@ -12,7 +16,9 @@ jobs:
promote:
if: github.repository == 'kernel/hypeman-ts-staging'
runs-on: ${{ vars.STLC_RUNNER || 'ubuntu-latest' }}
environment: production
concurrency:
group: stlc-promote
cancel-in-progress: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Promote cancel race breaks push

Medium Severity

cancel-in-progress: true on stlc-promote can cancel a run whose push to next still lands, while the newer run already fetched the old tip and later built a different merge commit. The final git push to next then fails as a non-fast-forward, so validated staging changes stay off next until someone reruns the workflow.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c46e332. Configure here.

steps:
- name: Check out staging
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -29,33 +35,99 @@ jobs:
owner: kernel
repositories: hypeman-ts
permission-contents: 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/hypeman-ts
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: Promote staging to production
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/hypeman-ts
run: |
if ! git merge-base --is-ancestor production/main origin/main; then
echo "::error title=Promote blocked::production/main is not an ancestor of staging main. Back-sync production first."
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conflict abort assumes active merge

Low Severity

open_conflict_pr always runs git merge --abort under set -e, but it is invoked for any failed git merge, not only conflicted merges. If merge fails before entering a mergable state, abort itself fails and the recovery PR path never runs.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 573786c. Configure here.

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
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 [ "$HAS_NEXT" = "true" ]; then
git merge-base --is-ancestor production/next HEAD
fi
git push production origin/main:refs/heads/main

- 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.5.1"
".": "0.6.0"
}
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
configured_endpoints: 58
configured_endpoints: 61
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.6.0](https://github.com/kernel/hypeman-ts/compare/v0.5.1...v0.6.0) (2026-08-12)


### Features

* Add QEMU microvm hypervisor backend ([f8c18cf](https://github.com/kernel/hypeman-ts/commit/f8c18cf81953831bf2464f08c9e19a918ffdfb0c))
* Add request header authorization to ingress rules ([2fb6855](https://github.com/kernel/hypeman-ts/commit/2fb68550870bace083b8636cc32e5d92255e527b))
* chore(stlc): seal custom-code tracking files ([fd74279](https://github.com/kernel/hypeman-ts/commit/fd74279abdea5b466a4c5b031150aba1b0d0cdc0))

## 0.5.1 (2026-08-06)

Full Changelog: [v0.5.0...v0.5.1](https://github.com/kernel/hypeman-ts/compare/v0.5.0...v0.5.1)
Expand Down
16 changes: 16 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,19 @@ Methods:
- <code title="delete /builds/{id}">client.builds.<a href="./src/resources/builds.ts">cancel</a>(id) -> void</code>
- <code title="get /builds/{id}/events">client.builds.<a href="./src/resources/builds.ts">events</a>(id, { ...params }) -> BuildEvent</code>
- <code title="get /builds/{id}">client.builds.<a href="./src/resources/builds.ts">get</a>(id) -> Build</code>

# Pushes

Types:

- <code><a href="./src/resources/pushes.ts">CreatePushRequest</a></code>
- <code><a href="./src/resources/pushes.ts">Push</a></code>
- <code><a href="./src/resources/pushes.ts">PushCredentials</a></code>
- <code><a href="./src/resources/pushes.ts">PushStatus</a></code>
- <code><a href="./src/resources/pushes.ts">PushListResponse</a></code>

Methods:

- <code title="post /pushes">client.pushes.<a href="./src/resources/pushes.ts">create</a>({ ...params }) -> Push</code>
- <code title="get /pushes">client.pushes.<a href="./src/resources/pushes.ts">list</a>() -> PushListResponse</code>
- <code title="get /pushes/{id}">client.pushes.<a href="./src/resources/pushes.ts">get</a>(id) -> Push</code>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onkernel/hypeman",
"version": "0.5.1",
"version": "0.6.0",
"description": "The official TypeScript library for the Hypeman API",
"author": "Hypeman <>",
"types": "dist/index.d.ts",
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
21 changes: 21 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ import {
IngressTarget,
Ingresses,
} from './resources/ingresses';
import {
CreatePushRequest,
Push,
PushCreateParams,
PushCredentials,
PushListResponse,
PushStatus,
Pushes,
} from './resources/pushes';
import {
DiskBreakdown,
GPUProfile,
Expand Down Expand Up @@ -850,6 +859,7 @@ export class Hypeman {
resources: API.Resources = new API.Resources(this);
builders: API.Builders = new API.Builders(this);
builds: API.Builds = new API.Builds(this);
pushes: API.Pushes = new API.Pushes(this);
}

Hypeman.Health = Health;
Expand All @@ -861,6 +871,7 @@ Hypeman.Devices = Devices;
Hypeman.Ingresses = Ingresses;
Hypeman.Builders = Builders;
Hypeman.Builds = Builds;
Hypeman.Pushes = Pushes;

export declare namespace Hypeman {
export type RequestOptions = Opts.RequestOptions;
Expand Down Expand Up @@ -987,5 +998,15 @@ export declare namespace Hypeman {
type BuildEventsParams as BuildEventsParams,
};

export {
Pushes as Pushes,
type CreatePushRequest as CreatePushRequest,
type Push as Push,
type PushCredentials as PushCredentials,
type PushStatus as PushStatus,
type PushListResponse as PushListResponse,
type PushCreateParams as PushCreateParams,
};

export type SnapshotCompressionConfig = API.SnapshotCompressionConfig;
}
9 changes: 9 additions & 0 deletions src/resources/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ export {
type InstanceStatParams,
type InstanceWaitParams,
} from './instances/instances';
export {
Pushes,
type CreatePushRequest,
type Push,
type PushCredentials,
type PushStatus,
type PushListResponse,
type PushCreateParams,
} from './pushes';
export {
Resources,
type DiskBreakdown,
Expand Down
Loading
Loading