Skip to content
Merged
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
115 changes: 115 additions & 0 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Releasing agentling

The pipeline is small: bump the version, validate, dry-run on TestPyPI, publish
to PyPI, then tag and cut a GitHub release. Versions on PyPI and TestPyPI are
**permanent and non-reusable**, which is why the dry run matters.

## 1. Prepare

- [ ] On `main`, working tree clean (release from `main` after the PR merges).
- [ ] Bump `version` in `pyproject.toml`.
- [ ] Add a `## [x.y.z]` section to `CHANGELOG.md`.
- [ ] The gate is green:

```bash
uv run pytest
uv run ruff check src tests examples
uv run ruff format --check src tests examples
uv run mypy src tests examples
```

## 2. Build and write the release notes

```bash
rm -rf dist && uv build
uv run --with twine twine check dist/*
```

Write the version's summary once and reuse it for the tag and the GitHub
release. Keep it in step with the `CHANGELOG.md` entry:

```bash
cat > /tmp/vX.Y.Z-notes.md <<'EOF'
vX.Y.Z — <one-line theme>

<short paragraph>

Highlights:
- ...

Full changelog: CHANGELOG.md
EOF
```

## 3. Handle the token securely

Never put a token on the command line or in a file (shell and git history are
forever). Read it into an env var at a silent prompt; uv reads
`UV_PUBLISH_TOKEN`:

```bash
read -rs UV_PUBLISH_TOKEN && export UV_PUBLISH_TOKEN
# Verify without revealing it (length + harmless prefix only):
echo "length: ${#UV_PUBLISH_TOKEN} | prefix: ${UV_PUBLISH_TOKEN:0:5}" # want ~150-200 and 'pypi-'
```

TestPyPI and PyPI use **separate** tokens. `unset UV_PUBLISH_TOKEN` before
switching between them, and again when done. The first-ever upload of a new
project needs an account-scoped token; use a project-scoped token afterward.

## 4. Dry run on TestPyPI

```bash
uv publish --publish-url https://test.pypi.org/legacy/
```

Install it back in a throwaway environment. agentling has real dependencies, so
`--extra-index-url` is required (TestPyPI does not host them):

```bash
uv venv /tmp/testpypi
uv pip install --python /tmp/testpypi \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
agentling
/tmp/testpypi/bin/python -c "import agentling; print(agentling.__version__)"
unset UV_PUBLISH_TOKEN && rm -rf /tmp/testpypi
```

## 5. Publish to PyPI

```bash
read -rs UV_PUBLISH_TOKEN && export UV_PUBLISH_TOKEN # PyPI token this time
uv publish # default target is real PyPI
unset UV_PUBLISH_TOKEN
```

Confirm a clean-environment install:

```bash
uv venv /tmp/pypi
uv pip install --python /tmp/pypi agentling
/tmp/pypi/bin/python -c "import agentling; print(agentling.__version__)"
rm -rf /tmp/pypi
```
Comment on lines +70 to +94

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Fixed /tmp venv paths 🐞 Bug ☼ Reliability

RELEASING.md hard-codes venv locations under /tmp (e.g. /tmp/testpypi, /tmp/pypi) and deletes
them with rm -rf, which can fail or collide if a previous run left the directory behind or two
releases are attempted concurrently. This makes the documented release workflow unnecessarily
fragile.
Agent Prompt
### Issue description
The release guide creates virtualenvs in fixed locations under `/tmp` and then cleans them with `rm -rf`. If those paths already exist (e.g. an interrupted prior run) or are used by another process, the documented steps may fail or behave unexpectedly.

### Issue Context
This is documentation, but it describes commands users will copy/paste during a release. Using unique temp directories and a `trap` makes the process more robust and ensures cleanup even if a command fails.

### Fix Focus Areas
- RELEASING.md[69-77]
- RELEASING.md[89-94]

### Suggested change (example)
Replace fixed `/tmp/...` dirs with a unique temp dir and ensure cleanup:

```bash
TMP_VENV=$(mktemp -d /tmp/agentling-testpypi.XXXXXX)
trap 'rm -rf "$TMP_VENV"; unset UV_PUBLISH_TOKEN' EXIT

uv venv "$TMP_VENV"
uv pip install --python "$TMP_VENV" \
  --index-url https://test.pypi.org/simple/ \
  --extra-index-url https://pypi.org/simple/ \
  agentling
"$TMP_VENV"/bin/python -c "import agentling; print(agentling.__version__)"
```

Do the same for the PyPI verification venv section.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


## 6. Tag and release

Use an **annotated** tag so the tag itself carries the summary (`git show
vX.Y.Z` prints it), and reuse the same notes file for the GitHub release:

```bash
git tag -a vX.Y.Z -F /tmp/vX.Y.Z-notes.md
git push origin vX.Y.Z # tags are not pushed by a normal push
gh release create vX.Y.Z --title "vX.Y.Z" --notes-file /tmp/vX.Y.Z-notes.md
```

## Checklist

- [ ] Version bumped in `pyproject.toml`
- [ ] `CHANGELOG.md` updated
- [ ] Gate green; `uv build` + `twine check` pass
- [ ] TestPyPI dry run installs and imports
- [ ] Published to PyPI; installs from a clean environment
- [ ] Annotated tag pushed; GitHub release created
- [ ] `UV_PUBLISH_TOKEN` unset
Loading