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
29 changes: 29 additions & 0 deletions .github/release-notes-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!-- TODO: one-line summary of this release -->

## Highlights

<!-- TODO: user-facing changes, one bullet each -->

## Install

```bash
curl -fsSL https://raven.evermind.ai/install.sh | bash
```

Then reload your shell and run:

```bash
raven onboard
```

## Release Status

- Version: `__VERSION__`
- Tag: `__TAG__`
- Stability: <!-- TODO: e.g. public preview patch / public preview minor -->
- Assets: wheel and source distribution attached to this release

## Notes

- Raven is still pre-1.0; CLI surfaces, plugin contracts, and runtime internals may continue to evolve.
- PyPI publishing is not enabled yet; the supported public install path uses the GitHub Release wheel asset.
62 changes: 58 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ on:
- "v*"
workflow_dispatch: {}

concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false

jobs:
build-wheel:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7

# 1) Node toolchain to build the TUI bundle.
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: "22"

Expand All @@ -44,7 +50,7 @@ jobs:
# an sdist and then builds the wheel from that sdist, which drops this
# gitignored bundle before the wheel hook can include it.
- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v8.2.0

- name: Build wheel + sdist
run: |
Expand Down Expand Up @@ -73,7 +79,55 @@ jobs:
name: dist
path: dist/*

# 5) (Optional, wire up when ready) publish to PyPI on tag:
# 5) On a version tag, publish a DRAFT GitHub Release with the built
# wheel + sdist attached. install.sh resolves the wheel from the
# latest Release asset, so a human reviews the draft and clicks
# Publish to make it live. Manual dispatch (no tag) stops after the
# artifact upload above.
- name: Check tag matches pyproject version
if: startsWith(github.ref, 'refs/tags/v')
run: |
tag="${{ github.ref_name }}"
v=$(grep -m1 '^version = ' pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
base="${tag#v}"; base="${base%%-*}" # v0.1.3-rc1 -> 0.1.3
[ "$base" = "$v" ] || { echo "tag $tag does not match pyproject version $v"; exit 1; }

- name: Create draft GitHub Release with assets
if: startsWith(github.ref, 'refs/tags/v')
env:
GH_TOKEN: ${{ github.token }}
run: |
tag="${{ github.ref_name }}"
repo="${{ github.repository }}"
ver="${tag#v}"
today="$(date -u +%Y-%m-%d)"
# prerelease tags (contain a hyphen, e.g. v0.1.3-rc1) must never become
# /releases/latest, which install.sh serves to curl|sh users.
pre=""
case "$tag" in *-*) pre="--prerelease" ;; esac
# Prefill notes from the template; the summary and Highlights stay TODO
# for a human to fill in the draft before publishing.
sed "s/__VERSION__/$ver/g; s/__TAG__/$tag/g" \
.github/release-notes-template.md > "$RUNNER_TEMP/notes.md"
# Detect an existing release via the LIST endpoint: the tag endpoint is
# published-only and the Actions token cannot see a draft through it
# (cli/cli #3037), so a re-run would 422 on create. Delete a stale draft
# (this keeps the git tag) and recreate; leave a published release alone.
rel=$(gh api "repos/$repo/releases?per_page=100" --jq "map(select(.tag_name==\"$tag\"))[0] // {}")
id=$(printf '%s' "$rel" | jq -r '.id // empty')
isdraft=$(printf '%s' "$rel" | jq -r '.draft // false')
if [ -n "$id" ] && [ "$isdraft" = "true" ]; then
gh api -X DELETE "repos/$repo/releases/$id"
id=""
fi
if [ -z "$id" ]; then
gh release create "$tag" dist/*.whl dist/*.tar.gz \
--title "Raven $ver ($today)" --notes-file "$RUNNER_TEMP/notes.md" --draft $pre
else
echo "Release $tag already published (id=$id); leaving as-is."
fi

# (Optional, wire up when ready) publish to PyPI on tag:
# - name: Publish to PyPI
# if: startsWith(github.ref, 'refs/tags/v')
# run: uv publish
Expand Down
71 changes: 71 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Releasing Raven

How a new Raven version is cut and published.

## Versioning

- Semantic versioning `MAJOR.MINOR.PATCH`. The source of truth is `version` in
`pyproject.toml`.
- Tags: `vX.Y.Z` for a stable release, `vX.Y.Z-rcN` for a pre-release. The tag
must match the `pyproject.toml` version -- CI enforces this (`release.yml`).
- For a pre-release, keep `pyproject.toml` at the base version (e.g. `0.1.3`
while tagging `v0.1.3-rc1`); CI compares only the base. Do NOT set the
version to `0.1.3-rc1` -- that is not a version hatch will build.

## Release title

`Raven X.Y.Z (YYYY-MM-DD)` -- for example `Raven 0.1.3 (2026-07-08)`. The CI
draft fills this in automatically (date is the build date; adjust when
publishing if needed).

## Release notes

Notes are hand-written and curated. The CI draft prefills the boilerplate
(Install, Release Status, Notes); a human writes the one-line summary and the
Highlights before publishing. Structure:

```
<one-line summary>

## Highlights
- <user-facing change>

## Install
curl -fsSL https://raven.evermind.ai/install.sh | bash
then: raven onboard

## Release Status
- Version: `X.Y.Z`
- Tag: `vX.Y.Z`
- Stability: <public preview patch | public preview minor | ...> # fill by hand per release type
- Assets: wheel and source distribution attached to this release

## Notes
- pre-1.0 evolution caveat
- PyPI not enabled; install via the GitHub Release wheel
```

`Stability` is not boilerplate -- set it by release type (patch / minor / rc).

## Flow

1. Bump `version` in `pyproject.toml`; open a PR; merge to `main`.
2. `git tag vX.Y.Z && git push origin vX.Y.Z`.
3. CI (`release.yml`) builds the wheel + sdist and creates a **draft** GitHub
Release with both attached, titled and prefilled from the template.
4. Fill the summary + Highlights in the draft, then click **Publish**.
Publishing makes it `/releases/latest`, which `install.sh` serves.

## Pre-releases

- `vX.Y.Z-rcN` tags build a draft marked **pre-release**. A pre-release is never
`/releases/latest`, so `curl | sh` users are unaffected. Use an rc tag to
verify the release pipeline before cutting the stable tag; delete the rc
release and tag afterward.

## Notes

- `main` is squash-merge + PR-only. The release itself is not automated past the
draft: publishing is a deliberate human step.
- PyPI publishing is not wired up; the supported install path is the GitHub
Release wheel asset resolved by `install.sh`.
Loading