# Releasing

This document is the runbook for cutting a go-redis release. It is intended
for maintainers with write/tag access to the repository.

For the format and style of the release notes themselves, see
[.github/RELEASE_NOTES_TEMPLATE.md](./.github/RELEASE_NOTES_TEMPLATE.md).

## Versioning

go-redis follows [Semantic Versioning](https://semver.org/):

- **Patch** (`vX.Y.Z+1`) — bug fixes, no API changes.
- **Minor** (`vX.Y+1.0`) — backwards-compatible new features, deprecations.
- **Major** (`vX+1.0.0`) — breaking changes. Coordinate with the team first.

Pre-releases use `vX.Y.Z-beta.N` / `vX.Y.Z-rc.N`.

## Pre-release checklist

- [ ] Target branch is `master` and CI is green on the latest commit.
- [ ] All PRs intended for this release are merged.
- [ ] There are no open issues in the release milestone (if used).
- [ ] `CHANGELOG` / release notes have been considered; dependabot-only
      and doc-only changes are excluded per the template.
- [ ] Confirm the next version number and decide if it's a patch / minor / major.

## 1. Draft the release notes

1. Open the draft release auto-generated by
   [release-drafter](.github/release-drafter-config.yml) on GitHub.
2. Prepend a new section to [`RELEASE-NOTES.md`](./RELEASE-NOTES.md) using
   [`.github/RELEASE_NOTES_TEMPLATE.md`](./.github/RELEASE_NOTES_TEMPLATE.md)
   as the format. Keep the file in chronological order (newest first).
3. Pick 3–5 **Highlights** — the most user-facing, impactful changes.
4. Remove dependabot bumps and doc-only typo fixes from the lists.
5. Verify every PR has a contributor attribution and link.
6. Open a PR with just the release-notes change if you want review before
   bumping versions, otherwise include it in the release PR below.

## 2. Bump versions and open the release PR

Create a release branch from `master`:

```shell
git checkout master && git pull --ff-only
git checkout -b release/vX.Y.Z
```

Run the release script on that branch:

```shell
TAG=vX.Y.Z ./scripts/release.sh
```

What the script does (and explicitly does **not** do):

- ✅ Validates `TAG` matches the semver regex and isn't already a git tag.
- ✅ Rewrites every `redis/go-redis*` line in every sub-module `go.mod` to
      point at the new `TAG`. Trailing `// indirect` markers are preserved.
- ✅ Runs `go mod tidy -compat=1.24` in each sub-module.
- ✅ Updates the return value in [`version.go`](./version.go).
- ❌ Does **not** switch branches (runs in your current branch).
- ❌ Does **not** require a clean working tree (so you can mix it with
      release-notes edits in the same branch).
- ❌ Does **not** commit, tag, or push anything.

Review and commit the changes yourself:

```shell
git diff                 # sanity-check the bumps
git add -u
git commit -m "chore: release vX.Y.Z"
git push origin release/vX.Y.Z
```

Then on GitHub:

- [ ] Open a PR from `release/vX.Y.Z` into `master`.
- [ ] Wait for all required CI checks (build, golangci-lint, spellcheck,
      doctests, e2e where applicable) to pass.
- [ ] Get at least one maintainer approval.
- [ ] Merge the PR (use a merge commit — the tag will point at the merge SHA).

## 3. Tag the release

After the release PR is merged, pull the latest `master` and dry-run the
tagger:

```shell
git checkout master && git pull --ff-only
TAG=vX.Y.Z ./scripts/tag.sh vX.Y.Z
```

The script defaults to **dry-run** and prints the commands it would run.
Verify the output, then apply for real with `-t`:

```shell
./scripts/tag.sh vX.Y.Z -t
```

This creates and pushes:
- The top-level tag `vX.Y.Z`.
- A per-module tag `<module>/vX.Y.Z` for each public sub-module
  (skipping `example/*` and `internal/*`).

## 4. Publish the GitHub release

1. On GitHub, open the draft release created by release-drafter.
2. Set the tag to `vX.Y.Z` and the target to `master`.
3. Replace the auto-generated body with the curated notes from
   `RELEASE-NOTES.md` for this version.
4. For pre-releases, check **"Set as a pre-release"**.
5. Publish.

## 5. Post-release

- [ ] Verify the release appears on
      [pkg.go.dev](https://pkg.go.dev/github.com/redis/go-redis/v9) within
      a few minutes (trigger a fetch by visiting the version URL if needed).
- [ ] Announce on Discord (see the link in `CONTRIBUTING.md`).
- [ ] Close the release milestone if one was used.
- [ ] Open follow-up issues for anything deferred from this release.

## Hotfix / patch release

For an urgent fix on top of the latest release:

1. Branch from the latest release tag: `git checkout -b hotfix/vX.Y.Z+1 vX.Y.Z`.
2. Cherry-pick (or re-apply) only the required fix commits.
3. Follow the normal release flow above with `TAG=vX.Y.Z+1`.
4. Make sure the fix is also present on `master` (forward-port if necessary).

## Troubleshooting

- **`release.sh` fails with "tag already exists"** — the tag has already
  been created. Pick the next version, or delete the local tag first if
  it was created by mistake.
- **`tag.sh` reports version mismatch in a `go.mod`** — a sub-module was
  not updated by `release.sh`. Fix the `go.mod` manually (or re-run
  `release.sh`), amend the release PR, and re-run the tagger.
- **`version.go` does not contain the tag** — `release.sh` did not run or
  the bump was reverted. Re-run `release.sh` on the release branch.
- **pkg.go.dev does not show the new version** — visit
  `https://pkg.go.dev/github.com/redis/go-redis/v9@vX.Y.Z` once to trigger
  a fetch from the module proxy.
