Skip to content

Commit 0d74d18

Browse files
authored
Merge pull request #53 from Pipelex/release/v0.9.0
Pipelex dependency update
2 parents fb227af + 49fe035 commit 0d74d18

5 files changed

Lines changed: 295 additions & 151 deletions

File tree

.claude/skills/release/SKILL.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
name: release
3+
description: Prepare a new release for the pipelex-starter-python project. Bumps version in pyproject.toml, syncs uv.lock, updates CHANGELOG.md, manages the release/vX.Y.Z branch, runs lint/type checks and tests, and commits. Use when the user says "release", "prepare a release", "bump version", "new version", "cut a release", or "ship it". The user can optionally provide changelog content inline (e.g. "/release Added foo, fixed bar"), which becomes the entry for this version.
4+
---
5+
6+
# Release Workflow
7+
8+
Guides the user through preparing a new pipelex-starter-python release in 8 interactive steps. Every step requires explicit user confirmation before proceeding.
9+
10+
This is a **starter template, not a published package** — there is no PyPI publish. The release is cut by merging the `release/vX.Y.Z` PR into `main`: `github-release.yml` then creates a GitHub Release `vX.Y.Z` from the changelog notes. So the branch name, the `pyproject.toml` version, and the `CHANGELOG.md` heading must line up exactly, or CI blocks the PR.
11+
12+
## Step 1 — Gather State
13+
14+
Read the following and present a summary:
15+
16+
1. Current version from `pyproject.toml` (`version = "X.Y.Z"`, near the top of the `[project]` table)
17+
2. Latest entry in `CHANGELOG.md`
18+
3. Current git branch (`git branch --show-current`)
19+
4. Working tree status (`git status --short`)
20+
21+
If the working tree is dirty, **warn the user** and ask whether to continue, commit those changes as part of the release, or abort. Also run `git log origin/main..HEAD --oneline` to list commits that will ship with this release so the user knows what's included.
22+
23+
## Step 2 — Determine Target Version
24+
25+
Calculate the three semver bump options from the current version:
26+
27+
- **Patch**: `X.Y.Z+1`
28+
- **Minor**: `X.Y+1.0`
29+
- **Major**: `X+1.0.0`
30+
31+
Present these options to the user using `AskUserQuestion`, showing the concrete resulting version for each. If the current branch already looks like `release/vA.B.C` and the version in `pyproject.toml` was already bumped, offer a **"Keep current (A.B.C)"** option.
32+
33+
Store the chosen version as `TARGET_VERSION` (no `v` prefix, e.g. `0.9.0`).
34+
35+
## Step 3 — Branch Management
36+
37+
The release branch **must** be named `release/v{TARGET_VERSION}`. `guard-branches.yml` rejects any other source branch merging into `main`, and `version-check.yml` requires the branch version to match `pyproject.toml`, so this name is not optional.
38+
39+
- If already on the correct branch: inform the user and continue.
40+
- If on `dev`, `main`, or another branch: confirm with the user, then create and switch to `release/v{TARGET_VERSION}` from the current HEAD.
41+
- If on a *different* release branch: warn the user and ask how to proceed.
42+
43+
All version, changelog, and lock changes must be made **on this branch**.
44+
45+
## Step 4 — Update Version in pyproject.toml
46+
47+
Edit the `version = "..."` line in `pyproject.toml` to `version = "{TARGET_VERSION}"`. Only change the version field — don't touch anything else.
48+
49+
- If the version already matches: inform the user and skip.
50+
- Otherwise: use the Edit tool to make the change, then show the diff.
51+
52+
The version in `pyproject.toml` must **not** have a `v` prefix (e.g. `0.9.0`, not `v0.9.0`).
53+
54+
## Step 5 — Sync uv.lock
55+
56+
After updating `pyproject.toml`, regenerate the lock file so it reflects `TARGET_VERSION`:
57+
58+
```bash
59+
make li
60+
```
61+
62+
`make li` runs `uv lock` then `uv sync` (lock + install). CI's `package-check.yml` runs `uv lock --locked` and fails the PR if `uv.lock` is out of date, so this step is what keeps that check green. If you only need to refresh the lock without reinstalling, `uv lock` alone is sufficient.
63+
64+
- **If the lock file was already in sync**: inform the user and continue.
65+
- **On failure**: show the error and ask the user how to proceed.
66+
67+
## Step 6 — Update CHANGELOG.md
68+
69+
The changelog entry **must** match the CI grep pattern (`changelog-check.yml`): `## [vX.Y.Z] -`
70+
71+
Check if `CHANGELOG.md` already contains a `## [v{TARGET_VERSION}] -` entry.
72+
73+
- **If it exists**: show the existing entry and ask the user whether to keep it or edit it.
74+
75+
- **If it's missing**: draft a new entry and insert it directly after the `# Changelog` heading (newest entry on top), formatted as:
76+
77+
```markdown
78+
## [v{TARGET_VERSION}] - {TODAY'S DATE in YYYY-MM-DD}
79+
80+
- Item one
81+
- Item two
82+
```
83+
84+
Source the content, in priority order:
85+
1. **Inline content** the user passed when invoking the skill (e.g. `/release Bumped pipelex to 0.32.0`) — use it as the entry body.
86+
2. Otherwise, run `git log main..HEAD --oneline` (or `git log --oneline -20` if on `main`) to review recent commits and draft an entry from them.
87+
88+
Match the existing changelog style — plain bullets, as in the current entries. You may group under `### Added` / `### Changed` / `### Fixed` / `### Removed` subsections if the content clearly warrants it, but only include subsections that have content. The user may accept, edit, or rewrite the proposed entry.
89+
90+
This project does **not** use an `## [Unreleased]` placeholder — never add one. The changelog should only contain concrete version entries.
91+
92+
## Step 7 — Run Checks
93+
94+
Run the same gates CI enforces on the PR. Both are silent on success and only show output on failure:
95+
96+
```bash
97+
make agent-check # ruff format + lint, pyright, mypy (mirrors lint-check.yml)
98+
make agent-test # tests, excludes inference/LLM markers (mirrors tests-check.yml)
99+
```
100+
101+
`make agent-check` auto-formats with ruff, so it may modify files — include any resulting changes in the release commit.
102+
103+
- **On success**: report and continue.
104+
- **On failure**: show the errors and ask the user how to proceed (fix the issues, skip the check, or abort). Prefer fixing — a failing gate here means the PR's `lint-check` / `tests-check` will fail too.
105+
106+
## Step 8 — Review & Commit
107+
108+
Present a full summary:
109+
110+
- Target version: `v{TARGET_VERSION}`
111+
- Branch: `release/v{TARGET_VERSION}`
112+
- Files changed: `pyproject.toml`, `uv.lock`, `CHANGELOG.md` (plus any formatting changes from `make agent-check`, or other files the user chose to include in Step 1)
113+
- Changelog entry preview
114+
115+
Ask the user to confirm. On confirmation:
116+
117+
1. Stage **only** the release files — `pyproject.toml`, `uv.lock`, `CHANGELOG.md`, plus any formatting changes from the checks and any files the user explicitly chose to include. Never use `git add .` or `git add -A`.
118+
2. Commit with message: `Release v{TARGET_VERSION}: <one-line changelog summary>`
119+
3. Show the commit result.
120+
121+
Then offer (but do **not** automatically execute):
122+
123+
- **Push** the branch to origin: `git push -u origin release/v{TARGET_VERSION}`
124+
- **Create a PR** to `main`: `gh pr create --base main --title "Release/v{TARGET_VERSION}" --body "<changelog entries for this version>"`
125+
126+
Wait for explicit user approval before pushing or creating the PR. When you do create the PR, target `main`, title it `Release/v{TARGET_VERSION}`, and put the changelog entries for this version in the body. Report the PR URL back to the user.
127+
128+
## Rules
129+
130+
- Never use `git add .` or `git add -A` — stage only the release files (and any changes the user explicitly opted into).
131+
- Never push or create PRs without explicit user approval.
132+
- The `v` prefix appears in branch names, changelog headers, and the GitHub Release tag, but **not** in `pyproject.toml`.
133+
- Always use today's date for new changelog entries (format: `YYYY-MM-DD`; run `date +%F` if unsure).
134+
- Merging the `release/vX.Y.Z` PR into `main` is what ships — `github-release.yml` creates the GitHub Release on push to `main`. There is no PyPI publish; this is a starter template.
135+
- If any step fails or the user wants to abort, stop immediately — do not continue the workflow.

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# Changelog
22

3+
## [v0.9.0] - 2026-06-06
4+
5+
- Bump `pipelex` to `v0.32.0`: See `Pipelex` changelog [here](https://docs.pipelex.com/latest/changelog/)
6+
- Update `tests/integration/test_fundamentals.py` to use the new `BundleValidator().acquire_and_validate()` API (replaces the removed `dry_run_pipes` / `get_library_manager` dry-run path)
7+
38
## [v0.8.0] - 2026-05-06
49

5-
- Bump `pipelex` to `v0.26.4`: See `Pipelex` changelog [here](https://docs.pipelex.com/changelog/)
10+
- Bump `pipelex` to `v0.26.4`: See `Pipelex` changelog [here](https://docs.pipelex.com/latest/changelog/)
611
- Add `pipelex-tools` dev dependency
712
- Update `tests/integration/conftest.py` to use the new `needs_inference` kwarg on `Pipelex.make()` (replaces deprecated `disable_inference`)

pyproject.toml

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "my-project"
3-
version = "0.8.0"
3+
version = "0.9.0"
44
description = "Replace this with your project description"
55
# authors = [{ name = "Your Name", email = "your.email@example.com" }]
66
license = "MIT"
@@ -17,7 +17,7 @@ classifiers = [
1717
]
1818

1919
dependencies = [
20-
"pipelex[mistralai,anthropic,google,google-genai,bedrock,fal]>=0.26.4",
20+
"pipelex[mistralai,anthropic,google,google-genai,bedrock,fal]>=0.32.0",
2121
]
2222

2323
[tool.setuptools]
@@ -29,7 +29,7 @@ dev = [
2929
"boto3-stubs>=1.35.24",
3030
"mypy>=1.11.2",
3131
"pipelex-tools>=0.3.2",
32-
"pyright>=1.1.405",
32+
"pyright>=1.1.410",
3333
"pytest>=9.0.1",
3434
"pytest-sugar>=1.0.0",
3535
"pytest_asyncio>=0.24.0",
@@ -65,15 +65,25 @@ ignore_missing_imports = true
6565
module = ["json2html"]
6666

6767
[tool.pyright]
68+
venvPath = "."
69+
venv = ".venv"
70+
pythonVersion = "3.11"
6871
include = ["my_project", "tests"]
6972
analyzeUnannotatedFunctions = true
7073
deprecateTypingAliases = false
7174
disableBytesTypePromotions = true
7275
enableExperimentalFeatures = false
7376
enableTypeIgnoreComments = true
74-
exclude = ["**/node_modules", "**/__pycache__"]
77+
exclude = [
78+
"**/__pycache__",
79+
".venv",
80+
".git",
81+
"build",
82+
"dist",
83+
"**/node_modules",
84+
"**/.*",
85+
]
7586
extraPaths = ["./tests"]
76-
pythonVersion = "3.11"
7787
reportAbstractUsage = "error"
7888
reportArgumentType = "error"
7989
reportAssertAlwaysTrue = "error"
Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
from pathlib import Path
2-
31
import pytest
4-
from pipelex.hub import get_library_manager, get_pipes, set_current_library
5-
from pipelex.pipe_run.dry_run import DryRunStatus, dry_run_pipes
2+
from pipelex.pipe_run.exceptions import DryRunError
3+
from pipelex.pipeline.bundle_validator import BundleValidator
64

75

86
# We use gha_disabled here because those tests are called directly and explicitly by the tests-check.yml file before the rest of the tests.
@@ -15,17 +13,9 @@ def test_boot(self):
1513

1614
@pytest.mark.asyncio(loop_scope="class")
1715
async def test_dry_run_all_pipes(self):
18-
library_manager = get_library_manager()
19-
library_id, _ = library_manager.open_library()
20-
set_current_library(library_id)
21-
library_manager.load_libraries(library_id=library_id, library_dirs=[Path("my_project")])
22-
23-
results = await dry_run_pipes(pipes=get_pipes(), raise_on_failure=False)
24-
25-
# Check if there were any failures
26-
27-
failed_pipes = {pipe_code: output for pipe_code, output in results.items() if output.status == DryRunStatus.FAILURE}
28-
29-
if failed_pipes:
30-
failure_details = "\n".join([f" - {pipe_code}: {output.error_message}" for pipe_code, output in failed_pipes.items()])
31-
pytest.fail(f"Dry run failed for {len(failed_pipes)} pipes:\n{failure_details}")
16+
# acquire_and_validate opens a fresh library, loads my_project, dry-runs every pipe, and tears
17+
# the library down. It raises DryRunError aggregating any unexpected pipe failures.
18+
try:
19+
await BundleValidator().acquire_and_validate(library_dirs=["my_project"])
20+
except DryRunError as dry_run_error:
21+
pytest.fail(str(dry_run_error))

0 commit comments

Comments
 (0)