Blueprint Release Process¶
This document explains how to create releases for the Blueprint framework, including both coordinated releases and independent provider versioning.
Overview¶
Blueprint uses a modular architecture with independent versioning for each provider module. This allows:
- Selective updates: Users install only the providers they need
- Independent releases: Providers can be updated without changing core
- Faster iteration: Bug fixes and features ship independently
- Reduced dependencies: Smaller footprint for applications
Repository Structure¶
blueprint/
├── go.mod # Core module (github.com/oddbit-project/blueprint)
├── provider/
│ ├── redis/go.mod # github.com/oddbit-project/blueprint/provider/redis
│ ├── s3/go.mod # github.com/oddbit-project/blueprint/provider/s3
│ ├── httpserver/go.mod # github.com/oddbit-project/blueprint/provider/httpserver
│ └── ... # 17 provider modules
└── go.work # Workspace for development
Release Types¶
1. Provider-Only Release¶
When updating a single provider without core changes:
Steps:¶
- Make changes to the specific provider
- Test the provider:
- Check provider requirements: if this provider's
[Unreleased]entries rely on another provider's change, or another provider's entries rely on this one, follow Providers that require other providers (the dependency is tagged first; the dependant'sgo.modis bumped before it is tagged). - Tag only that provider:
- Create GitHub release for the provider tag
- Update documentation if needed
Example Scenarios:¶
- Redis provider bug fix →
provider/redis/v0.8.1 - S3 provider new feature →
provider/s3/v0.8.2 - SMTP provider security update →
provider/smtp/v0.8.3
2. Core-Only Release¶
When updating core library without provider changes:
Steps:¶
- Make changes to core modules (
/db,/config,/crypt, etc.) - Test core and all providers:
- Tag core only:
- Create GitHub release for the core tag
3. Coordinated Release¶
When updating both core and providers:
Steps:¶
- Make changes across core and providers
- Run comprehensive tests:
- Tag and push core first, so that the version the providers are about to require exists:
- Bump the providers' core requirement to that version and commit the
go.mod/go.sumchanges: This bumps only the core requirement. - Tag the providers being released, each with its own next version, and push each tag. A
provider is released when it has changes of its own, or when its bumped requirement has to
ship; the others need no tag. Providers are versioned independently of core (at core
v0.14.0, nats was atv0.10.0and clickhouse atv0.11.0), so the tag is not core's version; pick it from the provider's own[Unreleased]entries, as in Version Strategy: Tag providers that others require first. Where a provider's release depends on another provider's change, bump its requirement once that tag is pushed, and before tagging it; see Providers that require other providers for the order.
make tag-version VERSION=vX.Y.Z tags core and every provider with that one version. It
fits only a release in which every module takes the same version: run it after the step 4
commit, in place of steps 3 and 5's tags, and push core's tag and each provider tag. In any
other release it would tag the providers with core's version.
6. Create GitHub release with comprehensive release notes
Release Commands Reference¶
Using Makefile¶
# Build and test everything
make build-all
make test-all
# Tag core and every provider with one version (only when all modules take the same version)
make tag-version VERSION=v0.9.0
# Update all provider dependencies to specific core version
make update-deps VERSION=v0.8.0
# Generate Software Bill of Materials
make sbom
Manual Git Commands¶
# Tag core module
git tag v0.8.0
# Tag specific provider
git tag provider/redis/v0.8.1
# Push specific tag
git push origin provider/redis/v0.8.1
# Push every local tag at once (it publishes all of them: check `git tag -l` first)
git push origin --tags
# List existing tags
git tag --sort=-version:refname
gohan/dbx release order¶
dbx and provider/clickhouse's non-test code depend on the standalone module
github.com/oddbit-project/gohan (dbx directly; provider/clickhouse via Client.Querier()).
gohan is released and tagged independently of Blueprint, in its own repository. make
tag-version VERSION=… tags core and every provider module at the same commit, but each
provider's go.mod still requires an older core version (shadowed in this workspace by a local
replace, which a real consumer does not get) until that require is bumped. Run as a single
step, tag-version therefore publishes provider/clickhouse at a version whose declared core
dependency does not contain the current dbx/gohan code — a broken release for any consumer
who resolves the provider's go.mod normally (i.e. without the workspace's replace).
For a release that bumps gohan, adds to or changes dbx, or anything a provider's non-test
code imports from core, tag in this order (the Coordinated Release order,
with gohan first):
- Tag
gohanfirst, in its own repository, if this release depends on a newgohanversion. - Tag core only:
git tag vX.Y.Z && git push origin vX.Y.Z. - Bump the core requirement in the affected providers'
go.mod— currentlyprovider/clickhouse,provider/pgsqlandprovider/sqlite(dbx/gohan), andprovider/etcd,provider/franz,provider/kafka,provider/mqtt,provider/nats,provider/redis,provider/s3andprovider/smtp(tls.ClientConfig.ValidateEnabled, whose rules a core release can change, as #115 did), andprovider/httpserverandprovider/metrics(tls.ServerConfig, for the same reason) — tovX.Y.Z:make update-deps VERSION=vX.Y.Z, orcd provider/<name> && go get github.com/oddbit-project/blueprint@vX.Y.Z && go mod tidyper module. Commit thego.mod/go.sumchanges. - Bump provider-to-provider requirements where a provider's release depends on another provider's change; see Providers that require other providers.
- Tag the providers, each with its own next version (
git tag provider/<name>/vA.B.C), now that steps 3 and 4 have landed.make tag-version VERSION=vX.Y.Ztags every provider with core's version, so use it only when every module takes that same version.
The Makefile's PROVIDERS list is derived from provider/*/go.mod in the working tree (it uses GNU
make functions), so
test-all, test-providers, build-providers, tidy-providers, sbom, update-deps and
tag-version act on every provider module, including one added later. A new module still needs
its use line in go.work and its entry in the lint matrix (.github/workflows/lint.yml), which
are written by hand. Because the list comes from the working tree, run the release targets from a
clean checkout: an uncommitted provider/<name>/go.mod would be bumped and tagged too.
Providers that require other providers¶
Some providers require other providers. Neither make update-deps nor the core steps above bump
those requirements, so each keeps the version it last pinned, and the workspace (go.work and each
module's local replace) hides a stale requirement from the tests. This applies to every release
type, including a provider-only release.
Whenever a provider's [Unreleased] entries rely on a change in another provider (for example a
prometheus entry that relies on a new httpserver check), or its code, tests included, uses a symbol
added to another provider since the version its go.mod requires, check that the provider's go.mod requires
a version of the dependency that has the change. This holds whether the dependency's change is still
unreleased or was released earlier: a provider can lag a dependency that is already tagged. If it
does not:
- If the change is unreleased, release the dependency first, and push its tag:
git tag provider/<dep>/vA.B.C && git push origin provider/<dep>/vA.B.C. - Bump the dependant's requirement on it and commit:
cd provider/<name> && go get github.com/oddbit-project/blueprint/provider/<dep>@vA.B.C && go mod tidy. The localreplacemeansgo getcan succeed even when the tag is not on the remote, so check step 1's push first. - Update the dependant's CHANGELOG line that states the requirement ("Requires …
provider/<dep>vA.B.C"). - Then release the dependant.
The direct requirements today, and the release order they imply:
| provider | requires |
|---|---|
provider/hmacprovider |
provider/redis |
provider/httpserver |
provider/hmacprovider, provider/htpasswd, provider/jwtprovider |
provider/prometheus |
provider/httpserver |
Order: redis; then hmacprovider, htpasswd and jwtprovider; then httpserver; then
prometheus. Check a provider's go.mod for others before relying on this list.
Version Strategy¶
Semantic Versioning¶
All modules follow Semantic Versioning:
- MAJOR.MINOR.PATCH (e.g.,
v0.8.1) - MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes (backward compatible)
Version Coordination¶
| Change Type | Core Version | Provider Action | Example |
|---|---|---|---|
| Provider bug fix | No change | Tag provider only | provider/redis/v0.8.1 |
| Provider feature | No change | Tag provider only | provider/s3/v0.8.2 |
| Core bug fix | Increment patch | Optional provider update | v0.8.1 |
| Core feature | Increment minor | Optional provider update | v0.9.0 |
| Interface changes | Increment major/minor | Update affected providers | v1.0.0 |
| Major release | Increment major | Update all providers | v1.0.0 |
User Installation Examples¶
Old Installation (Backward Compatible)¶
Modular Installation (New Way)¶
# Install only needed providers
go get github.com/oddbit-project/blueprint/provider/redis@v0.8.1
go get github.com/oddbit-project/blueprint/provider/s3@v0.8.2
go get github.com/oddbit-project/blueprint/provider/httpserver@v0.8.0
# Users can mix versions
go get github.com/oddbit-project/blueprint@v0.8.0 # Core
go get github.com/oddbit-project/blueprint/provider/redis@v0.8.1 # Latest Redis
go get github.com/oddbit-project/blueprint/provider/s3@v0.8.0 # Stable S3
Release Checklist¶
Pre-Release¶
- [ ] All tests passing (
make test-all) - [ ] All modules build (
make build-all) - [ ] Dependencies tidied (
make tidy-all) - [ ] Documentation updated
- [ ] CHANGELOG.md updated
- [ ] Cross-module dependencies resolved
Release Process¶
- [ ] Tags created and pushed
- [ ] GitHub release created with release notes
- [ ] SBOM generated and attached (
make sbom) - [ ] Release announcements prepared
Post-Release¶
- [ ] Test installation from public repositories
- [ ] Update examples and samples
- [ ] Notify community of changes
- [ ] Monitor for issues
GitHub Release Notes Template¶
For Provider Releases¶
## Redis Provider v0.8.1
### Fixed
- Fixed connection timeout issue in high-concurrency scenarios
- Resolved memory leak in TTL management
### Installation
```bash
go get github.com/oddbit-project/blueprint/provider/redis@v0.8.1
Core Compatibility: Works with Blueprint core v0.8.0+
### For Coordinated Releases
```markdown
## Blueprint v0.9.0
### Breaking Changes
- Updated minimum Go version to 1.21
- Renamed `Config` interface method `GetKey` to `Get`
### Added
- New encryption provider with AES-256-GCM support
- Enhanced logging with structured output
- Rate limiting middleware for HTTP server
### Changed
- Improved error handling across all providers
- Updated all dependencies to latest versions
### Fixed
- Fixed race condition in connection pooling
- Resolved deadlock in transaction handling
### Installation
```bash
# Full framework
go get github.com/oddbit-project/blueprint@v0.9.0
# Or individual providers, each at its own version (not core's)
go get github.com/oddbit-project/blueprint/provider/redis@v0.10.0
## Troubleshooting
### Common Issues
1. **Cross-module dependency errors during development**
- Use the workspace: `GOWORK=/path/to/blueprint/go.work go mod tidy`
- Check replace directives in go.mod files
2. **Tags not recognized**
- Ensure tags are pushed to remote: `git push origin <tag>` for each one (`git push origin
--tags` pushes every local tag, including any made by mistake)
- Wait for Go proxy cache refresh (up to 10 minutes)
3. **Version conflicts**
- Check all go.mod files for consistent versions
- Use `make update-deps` to synchronize versions
### Development vs Production
**Development** (using workspace):
```bash
GOWORK=/path/to/blueprint/go.work go build
Production (using published modules):
Best Practices¶
- Test thoroughly before releasing
- Keep providers focused - one responsibility per provider
- Maintain backward compatibility when possible
- Document breaking changes clearly
- Use semantic versioning consistently
- Coordinate breaking changes across dependent modules
- Release security fixes quickly as patch versions
Contributing¶
For contributors working on releases:
- Follow the branching model (main/develop/feature branches)
- Test cross-module changes thoroughly
- Update documentation with code changes
- Add changelog entries for user-facing changes
- Coordinate with maintainers for major releases