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
102 changes: 102 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
name: Release

on:
push:
tags:
- "v[0-9]*"

permissions:
contents: write
id-token: write

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

jobs:
release:
name: Build and publish
runs-on: ubuntu-latest
timeout-minutes: 20
environment: pypi

steps:
- name: Check out repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false

- name: Install uv and Python
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "0.11.32"
python-version: "3.11"
enable-cache: true

- name: Install locked dependencies
run: uv sync --frozen

- name: Check formatting
run: uv run ruff format --check .

- name: Run linting
run: uv run ruff check .

- name: Run type checking
run: uv run mypy

- name: Run tests
run: uv run pytest

- name: Verify release tag
shell: bash
run: |
set -euo pipefail

package_version="$(uv version --short)"
expected_tag="v${package_version}"

if [[ "${GITHUB_REF_NAME}" != "${expected_tag}" ]]; then
echo "Tag ${GITHUB_REF_NAME} does not match ${expected_tag}." >&2
exit 1
fi

if ! grep -Fq "## [${package_version}]" CHANGELOG.md; then
echo "CHANGELOG.md does not document ${package_version}." >&2
exit 1
fi

- name: Build distributions
run: |
rm -rf dist
uv build --no-sources

- name: Verify distribution contents
run: uv run python scripts/check_distribution.py

- name: Smoke-test wheel
shell: bash
run: |
set -euo pipefail

uv venv --python 3.11 .release-venv

uv pip install --python .release-venv/bin/python dist/*.whl

.release-venv/bin/runbookproof --version

.release-venv/bin/runbookproof rules --format json > /tmp/runbookproof-rules.json

python -m json.tool /tmp/runbookproof-rules.json > /dev/null

.release-venv/bin/runbookproof scan README.md

- name: Publish distributions to PyPI
run: uv publish

- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${GITHUB_REF_NAME}" dist/* --verify-tag --generate-notes --title "RunbookProof ${GITHUB_REF_NAME}"
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Changelog

All notable changes to RunbookProof are documented in this file.

The format follows Keep a Changelog, and the project uses Semantic Versioning.

## [Unreleased]

## [0.1.0] - 2026-08-04

### Added

- Static analysis for commands embedded in Markdown documents
- Recursive directory scanning for Markdown files
- Command extraction from fenced code blocks
- Text, JSON, and SARIF 2.1.0 reports
- Stable finding fingerprints and source locations
- Exit codes suitable for CI and automation
- AWS CLI verification pack
- Azure CLI verification pack
- Bash verification pack
- Docker verification pack
- Git verification pack
- Kubernetes verification pack
- Node package-manager verification pack
- Python package-manager verification pack
- Terraform verification pack
- Universal verification pack
- Rule-level ignore controls
- `.runbookproof.toml` configuration support
- Built-in rule catalogue command
- Generated rule reference documentation
- GitHub Code Scanning integration
- Multi-version CI for Python 3.11 through Python 3.14
- Strict Ruff, MyPy, and test-coverage validation

[Unreleased]: https://github.com/antonisloukis/runbookproof/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/antonisloukis/runbookproof/releases/tag/v0.1.0
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@ uv run pytest
git diff --check
```

## Release process

Release preparation and publishing instructions are documented in
[`docs/releasing.md`](docs/releasing.md).

Release history is maintained in
[`CHANGELOG.md`](CHANGELOG.md).

## Roadmap

- Finding suppression with documented justifications
Expand Down
94 changes: 94 additions & 0 deletions docs/releasing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Releasing RunbookProof

RunbookProof releases are built, verified, published to PyPI, and attached to a
GitHub release by `.github/workflows/release.yml`.

## One-time PyPI setup

Before publishing the first version:

1. Create or sign in to the PyPI account that will own `runbookproof`.
2. Configure a PyPI Trusted Publisher with:
- Owner: `antonisloukis`
- Repository: `runbookproof`
- Workflow: `release.yml`
- Environment: `pypi`
3. In the GitHub repository, create an environment named `pypi`.
4. Add environment protection rules before publishing production releases.

No PyPI API token is stored in the repository.

## Release checklist

1. Start from an up-to-date `main` branch.
2. Confirm the intended version in `pyproject.toml`.
3. Add the release notes to `CHANGELOG.md`.
4. Run the complete validation suite.
5. Build the wheel and source distribution.
6. Run the distribution-content checker.
7. Install and smoke-test the generated wheel.
8. Merge the release-preparation pull request.
9. Create and push an annotated version tag.
10. Confirm that the Release workflow succeeds.
11. Confirm the package appears on PyPI.
12. Confirm the GitHub release contains both distribution files.

## Local release validation

```bash
uv sync --frozen
uv run ruff format --check .
uv run ruff check .
uv run mypy
uv run pytest
git diff --check
```

Build fresh distributions:

```bash
rm -rf dist
uv build --no-sources
uv run python scripts/check_distribution.py
```

Smoke-test the built wheel in an isolated environment:

```bash
rm -rf .release-venv

uv venv --python 3.11 .release-venv

uv pip install --python .release-venv/bin/python dist/*.whl

.release-venv/bin/runbookproof --version
.release-venv/bin/runbookproof rules --format json
.release-venv/bin/runbookproof scan README.md

rm -rf .release-venv
```

## Creating a release

For version `0.1.0`:

```bash
git switch main
git pull origin main

git tag -a v0.1.0 -m "RunbookProof v0.1.0"

git push origin v0.1.0
```

The tag must exactly match the project version prefixed with `v`.

The release workflow will:

1. run formatting, linting, type checking, and tests
2. verify that the tag matches `pyproject.toml`
3. build the source distribution and wheel
4. inspect the distribution contents
5. install and smoke-test the wheel
6. publish the distributions through PyPI Trusted Publishing
7. create a GitHub release and attach the distributions
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ runbookproof = "runbookproof.cli:main"
Homepage = "https://github.com/antonisloukis/runbookproof"
Repository = "https://github.com/antonisloukis/runbookproof"
Issues = "https://github.com/antonisloukis/runbookproof/issues"
Changelog = "https://github.com/antonisloukis/runbookproof/blob/main/CHANGELOG.md"
Documentation = "https://github.com/antonisloukis/runbookproof/tree/main/docs"

[build-system]
requires = ["uv_build>=0.11.32,<0.12.0"]
Expand Down
Loading
Loading