diff --git a/README.md b/README.md index 5d365c0..833e593 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -
-
-
diff --git a/docs/RELEASE_PROCESS.md b/docs/RELEASE_PROCESS.md
new file mode 100644
index 0000000..e2b9717
--- /dev/null
+++ b/docs/RELEASE_PROCESS.md
@@ -0,0 +1,117 @@
+# Release process
+
+This document is the **operational** companion to [`.github/workflows/release.yml`](../.github/workflows/release.yml). The workflow is tag-triggered (`v*.*.*`); pushing such a tag builds wheel + sdist, attaches a `testBench-vX.Y.Z.zip`, creates a GitHub Release, and publishes to PyPI. **All three actions are partially or fully irreversible** — PyPI in particular does not allow re-publishing a version. Run through this checklist before tagging.
+
+## One-time setup
+
+These have to be done once per repository and persist across releases.
+
+### 1. GitHub Environment: `pypi`
+
+The release workflow's `pypi` job declares `environment: pypi`. That environment must exist on the repo, otherwise the OIDC token exchange with PyPI's Trusted Publisher endpoint fails.
+
+```bash
+# Create the empty environment (idempotent)
+gh api -X PUT repos/knowledgestack/ks-xlsx-parser/environments/pypi
+```
+
+Optional but recommended after creation: open https://github.com/knowledgestack/ks-xlsx-parser/settings/environments/pypi and add a **required reviewer** so a tag push needs explicit approval before the PyPI publish step runs. This is a safety net — once a tag is pushed the release workflow auto-fires; a reviewer gate gives you one last "are you sure?" before the irreversible PyPI publish.
+
+### 2. PyPI Trusted Publisher binding
+
+This **cannot** be done via API or a PR — it requires logging into pypi.org as a maintainer of `ks-xlsx-parser`.
+
+1. Go to https://pypi.org/manage/project/ks-xlsx-parser/settings/publishing/
+2. Click **Add a new publisher** → **GitHub**
+3. Fill in:
+ - **PyPI Project Name:** `ks-xlsx-parser`
+ - **Owner:** `knowledgestack`
+ - **Repository:** `ks-xlsx-parser`
+ - **Workflow filename:** `release.yml`
+ - **Environment name:** `pypi`
+4. Save.
+
+Verify with:
+
+```bash
+# Should list any publishers tied to the project (requires you to be logged in)
+open "https://pypi.org/manage/project/ks-xlsx-parser/settings/publishing/"
+```
+
+If you're spinning up a new project that doesn't exist on PyPI yet, the publisher has to be configured as a **pending publisher** under your account first. Same form, accessible at https://pypi.org/manage/account/publishing/.
+
+### 3. Branch protection on `main`
+
+CI on a PR validates {ubuntu, macOS} × Python {3.10, 3.11, 3.12} before merge. Add a branch protection rule on `main` requiring those status checks to pass before a PR is mergeable:
+
+```bash
+gh api -X PUT repos/knowledgestack/ks-xlsx-parser/branches/main/protection \
+ -F required_status_checks[strict]=true \
+ -F 'required_status_checks[contexts][]=tests (ubuntu-latest / py3.10)' \
+ -F 'required_status_checks[contexts][]=tests (ubuntu-latest / py3.11)' \
+ -F 'required_status_checks[contexts][]=tests (ubuntu-latest / py3.12)' \
+ -F 'required_status_checks[contexts][]=tests (macos-latest / py3.10)' \
+ -F 'required_status_checks[contexts][]=tests (macos-latest / py3.11)' \
+ -F 'required_status_checks[contexts][]=tests (macos-latest / py3.12)' \
+ -F 'required_status_checks[contexts][]=testBench round-trip (ubuntu / py3.12)' \
+ -F enforce_admins=false \
+ -F required_pull_request_reviews[required_approving_review_count]=1 \
+ -F restrictions= 2>/dev/null
+```
+
+Or set in the UI: https://github.com/knowledgestack/ks-xlsx-parser/settings/branches
+
+## Per-release checklist
+
+For every new version `X.Y.Z`:
+
+1. **Decide the version number.** Follow [SemVer](https://semver.org/). Breaking API change → major bump. New feature, no breakage → minor. Bugfix only → patch.
+2. **Bump version in two places** (kept in sync to avoid drift):
+ - `pyproject.toml` — `version = "X.Y.Z"`
+ - `src/ks_xlsx_parser/__init__.py` — `__version__ = "X.Y.Z"`
+3. **Write the CHANGELOG entry** under a new `## [X.Y.Z] — YYYY-MM-DD` heading in [`CHANGELOG.md`](../CHANGELOG.md). Use the section labels documented at the top of that file (Added / Changed / Fixed / Performance / Docs / Internal / ⚠️ BREAKING).
+4. **(Optional but recommended) Write hand-curated release notes** at `docs/launch/RELEASE_NOTES_vX.Y.Z.md`. If present, the release workflow picks it up automatically as the GitHub Release body; otherwise GitHub auto-generates from commits.
+5. **Run `make test` locally** and verify all tests pass.
+6. **Open a PR**, wait for CI green on all matrix cells, get a review, merge to `main`.
+7. **Tag from `main`:**
+ ```bash
+ git checkout main && git pull
+ git tag -a vX.Y.Z -m "vX.Y.Z —