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
31 changes: 21 additions & 10 deletions .github/workflows/npm-build-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,37 @@ env:
jobs:
verify-ci:
name: verify CI passed
if: github.event_name == 'release'
if: github.repository == 'tableau/hyper-api-rust' && github.event_name == 'release'
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 35
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.release.tag_name }}

- name: Check CI status for commit
- name: Wait for CI to pass
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SHA=$(git rev-parse HEAD)
echo "Checking CI status for $SHA"
STATE=$(gh api "repos/${{ github.repository }}/commits/$SHA/status" --jq '.state')
echo "Combined status: $STATE"
if [[ "$STATE" != "success" ]]; then
echo "::error::CI has not passed for $SHA (state: $STATE). Aborting publish."
exit 1
fi
echo "Waiting for CI status on $SHA"
MAX_ATTEMPTS=30
SLEEP_SECONDS=60
for i in $(seq 1 $MAX_ATTEMPTS); do
STATE=$(gh api "repos/${{ github.repository }}/commits/$SHA/status" --jq '.state')
echo "Attempt $i/$MAX_ATTEMPTS: state=$STATE"
if [[ "$STATE" == "success" ]]; then
echo "CI passed."
exit 0
elif [[ "$STATE" == "failure" || "$STATE" == "error" ]]; then
echo "::error::CI failed for $SHA (state: $STATE). Aborting publish."
exit 1
fi
echo "CI still pending, waiting ${SLEEP_SECONDS}s..."
sleep $SLEEP_SECONDS
done
echo "::error::Timed out waiting for CI to pass ($SHA). State: $STATE"
exit 1

build-npm:
name: build-npm (${{ matrix.platform }})
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ permissions:

jobs:
release-please:
if: github.repository == 'tableau/hyper-api-rust'
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v5
Expand Down
32 changes: 19 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ name: release
# Publish to crates.io.
#
# Triggered by:
# - a GitHub Release published event (release-please drives this on
# merge of the release PR), or
# - a direct `git push origin v0.X.Y` tag push (emergency releases),
# - or a manual workflow_dispatch with an explicit existing tag.
# - a GitHub Release published event (release-please drives this via
# PAT, so this fires automatically on merge of the release PR), or
# - a manual workflow_dispatch with an explicit existing tag (for
# re-runs or emergency releases).
#
# Note: the `push: tags:` trigger was removed because release-please
# now uses a PAT (RELEASE_PLEASE_TOKEN) that fires both `release:
# published` AND `push: tags:` events. Keeping both caused duplicate
# runs. For emergency releases that bypass release-please, use
# workflow_dispatch.
#
# Stable tags (v0.1.0) mark the GitHub release as latest; pre-release
# tags (v0.1.0-rc.1) mark it as prerelease so it doesn't show as
Expand All @@ -19,16 +25,8 @@ name: release
# consistent for downstream crates.

on:
# release-please drives most releases by merging the release PR and
# publishing a GitHub Release; that fires the `release: published`
# event below. Direct `git push origin v0.X.Y` tag pushes also work
# (e.g. for emergency releases that bypass release-please).
release:
types: [published]
push:
tags:
- "v*.*.*-rc.*"
- "v*.*.*"
workflow_dispatch:
inputs:
tag:
Expand All @@ -45,6 +43,7 @@ env:

jobs:
verify:
if: github.repository == 'tableau/hyper-api-rust'
name: verify
runs-on: ubuntu-latest
timeout-minutes: 60
Expand Down Expand Up @@ -147,7 +146,14 @@ jobs:
publish() {
local crate="$1"
echo "::group::Publishing $crate"
cargo publish -p "$crate"
if ! cargo publish -p "$crate" 2>&1 | tee /tmp/publish_out; then
if grep -q "already exists on" /tmp/publish_out; then
echo "::warning::$crate already published — skipping"
else
echo "::endgroup::"
return 1
fi
fi
echo "::endgroup::"
# crates.io index propagation: downstream crates' own
# `cargo publish` verification step resolves their deps
Expand Down
23 changes: 11 additions & 12 deletions docs/GITHUB_OPERATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ the PR. Main-branch runs always complete. This is set via the
### Release (`release.yml`)

Runs on the **`release: published`** event (release-please publishes
the GitHub Release after merging the release PR), on direct **tag push**
matching `v*.*.*` (emergency releases that bypass release-please), or
via manual `workflow_dispatch` with an explicit tag input. Structure:
the GitHub Release after merging the release PR) or via manual
`workflow_dispatch` with an explicit tag input (for re-runs or
emergency releases). Structure:

```
verify ← full test suite + hyperd URL check, single-platform
Expand Down Expand Up @@ -212,19 +212,18 @@ steps are automated based on [Conventional Commits](https://www.conventionalcomm
4. **Merge the release PR.** release-please then:
- Creates a `vX.Y.Z` git tag on the merge commit.
- Creates a GitHub Release with the auto-generated changelog.
5. **Wait for CI to pass** on the merge commit (the `ci.yml` workflow
runs on push to `main`).
6. **Manually trigger the publish workflows.** Because release-please
uses `GITHUB_TOKEN`, the tag push and Release events it creates do
*not* fire other workflows (a GitHub Actions limitation). Once CI is
green, run:
5. **Publish workflows fire automatically.** Because release-please
uses a PAT (`RELEASE_PLEASE_TOKEN`), the `release: published` event
triggers both `release.yml` (crates.io) and `npm-build-publish.yml`
(npm) automatically. The npm workflow waits for CI to pass before
building.

If a publish workflow fails and needs a re-run:
```bash
gh workflow run release.yml -f tag=vX.Y.Z
gh workflow run npm-build-publish.yml -f tag=vX.Y.Z
```
`release.yml` publishes the 6 Rust crates to crates.io.
`npm-build-publish.yml` builds and publishes `hyperdb-mcp` and
`hyperdb-api-node` (plus their per-platform packages) to npm.
Already-published crates are skipped gracefully on re-run.

### How commits drive version bumps

Expand Down
Loading