Skip to content
Open
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
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Stave is created by [Ben Ranford](https://github.com/ben-ranford) and is

## Installation

Requires **Go 1.22 or later**. In your Go module, install the release candidate:
Requires **Go 1.22 or later**. In your Go module, install the documented version:
Comment thread
ben-ranford marked this conversation as resolved.

<!-- v1.0.0-rc.2 x-release-please-version -->
<!-- x-release-please-start-version -->
Expand All @@ -45,13 +45,17 @@ go get github.com/ben-ranford/stave@v1.0.0-rc.2

### Deliberate limits

Stave has not reached general availability. Promotion requires published,
immutable Lopper proving-client evidence for parity and rollback. The SSH,
Bubble Tea, and Lip Gloss adapters remain internal until they have independent
module versions and tags; begin with the root module. See the
A stable tag requires published, immutable Lopper proving-client evidence for
parity and rollback before GA promotion. The SSH, Bubble Tea, and Lip Gloss
adapters remain internal until they have independent module versions and tags;
begin with the root module. See the
[compatibility policy](docs/compatibility.md) and [security contract](docs/security.md)
before integrating consequential agent actions.

Development checkouts may contain unreleased changes. Pin a published tag
before deploying consequential agent actions; use the development branch for
evaluation only.

## Quick start

In an empty directory, run `go mod init example.com/hello-stave`, then use the
Expand Down
10 changes: 5 additions & 5 deletions docs/client-adoption.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ theme, actions, and effects. Stave provides the semantic UI and runtime
contracts that let those choices work consistently across human and automated
interfaces.

The current root module release candidate is `v1.0.0-rc.2` <!-- x-release-please-version -->.
It is not a GA promise; published Lopper parity and rollback evidence remains
the promotion gate. Begin with the root module only. The nested SSH, Bubble Tea,
and Lip Gloss modules are internal and are not yet supported consumer
dependencies. Pin this candidate after its release tag is published.
This guide tracks root module version `v1.0.0-rc.2` <!-- x-release-please-version -->.
Begin with the root module only. The nested SSH, Bubble Tea, and Lip Gloss
modules are internal and are not yet supported consumer dependencies. Pin a
published release tag before deployment. For Lopper promotion, verify the
published parity and rollback evidence described in the [release runbook](releasing.md).
Comment thread
ben-ranford marked this conversation as resolved.

For a compiled first semantic tree, use the [root quick start](../README.md#quick-start).

Expand Down
21 changes: 12 additions & 9 deletions docs/releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The root Go module is the only published Stave package. The nested SSH, Bubble
Tea, and Lip Gloss modules remain internal until they receive independent
versions and tags.

## Publish the prepared release candidate
## Publish the prepared release tag

Read the candidate from `.release-please-manifest.json`; publish it from the
hardened final `main` commit, never from an older release-please pull request
Expand All @@ -24,6 +24,7 @@ merge commit.
2. On the final `main` commit, wait for a fresh successful required-check run.
Record its commit SHA and confirm it contains the intended candidate
manifest, changelog, and release workflow.
Before deriving a stable tag, complete the GA promotion gate below.
3. Derive the release tag from the manifest and tag that exact SHA. Do not move
or recreate the tag after it is pushed:

Expand All @@ -41,9 +42,11 @@ merge commit.
```

4. The tag triggers [the release workflow](../.github/workflows/release.yml).
It validates the tag, runs `make ci` and `make release-contract`, then
publishes a prerelease with `CHANGELOG.md`, `LICENSE`, and the performance
evidence artifact. Wait for that workflow and verify all published assets.
It validates the tag and runs `make ci`. A prerelease tag then runs
`make release-contract` and publishes a prerelease; a stable tag runs
`make release-ga-contract` and publishes a non-prerelease release. Both
release paths attach `CHANGELOG.md`, `LICENSE`, and the performance evidence
artifact. Wait for that workflow and verify all published assets.
5. Change repository visibility only after the scheduler-boundary proof in
step 1 passes. Then run a controlled real public-fork pull request and
prove it uses the hosted untrusted path before approving general outside
Expand All @@ -55,11 +58,11 @@ merge commit.
go list -m -json "github.com/ben-ranford/stave@${release_tag}"
```

7. After the tag, prerelease, assets, and public Go resolution are verified,
replace `autorelease: pending` with `autorelease: tagged` on the original
release-please pull request. `skip-github-release: true` delegates
publication to the tag workflow, so release-please does not make that label
transition itself.
7. After the tag, its matching release channel, assets, and public Go
resolution are verified, replace `autorelease: pending` with
`autorelease: tagged` on the original release-please pull request.
`skip-github-release: true` delegates publication to the tag workflow, so
release-please does not make that label transition itself.

Release Please updates the annotated candidate versions in `README.md` and
`docs/client-adoption.md` for future release pull requests. Keep the
Expand Down
3 changes: 0 additions & 3 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
"packages": {
".": {
"release-type": "go",
"versioning": "prerelease",
"prerelease": true,
"prerelease-type": "rc",
"include-component-in-tag": false,
"extra-files": [
"README.md",
Expand Down
45 changes: 33 additions & 12 deletions requirements/release_please_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import (
"testing"
)

var releaseCandidateVersion = regexp.MustCompile(`^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)-rc\.([1-9][0-9]*)$`)
var releaseVersion = regexp.MustCompile(`^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-rc\.([1-9][0-9]*)|\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$`)

type releasePleasePackageConfig struct {
ReleaseType string `json:"release-type"`
Versioning string `json:"versioning"`
Prerelease bool `json:"prerelease"`
PrereleaseType string `json:"prerelease-type"`
IncludeComponentInTag bool `json:"include-component-in-tag"`
ExtraFiles []string `json:"extra-files"`
ExcludePaths []string `json:"exclude-paths"`
Expand All @@ -29,11 +26,31 @@ type releasePleaseConfig struct {
func TestRootReleasePleaseConfiguration(t *testing.T) {
root := rootReleasePleasePackage(t)
assertRootReleasePleasePackage(t, root)
assertReleasePleaseUsesDefaultVersioning(t)
assertReleasePleaseCandidateDocuments(t, root)
assertReleasePleaseManifestAndChangelog(t)
assertReleasePleaseWorkflow(t)
}

func assertReleasePleaseUsesDefaultVersioning(t *testing.T) {
t.Helper()
rawConfig, err := os.ReadFile("../release-please-config.json")
if err != nil {
t.Fatal(err)
}
var config struct {
Packages map[string]map[string]json.RawMessage `json:"packages"`
}
if err := json.Unmarshal(rawConfig, &config); err != nil {
t.Fatal(err)
}
for _, setting := range []string{"versioning", "prerelease", "prerelease-type"} {
if _, exists := config.Packages["."][setting]; exists {
t.Fatalf("root release must use Release Please default versioning; remove %q", setting)
}
}
}

func rootReleasePleasePackage(t *testing.T) releasePleasePackageConfig {
t.Helper()

Expand All @@ -56,8 +73,8 @@ func rootReleasePleasePackage(t *testing.T) releasePleasePackageConfig {
func assertRootReleasePleasePackage(t *testing.T, root releasePleasePackageConfig) {
t.Helper()

if root.ReleaseType != "go" || root.Versioning != "prerelease" || !root.Prerelease || root.PrereleaseType != "rc" {
t.Fatalf("root release must remain a Go rc prerelease: %+v", root)
if root.ReleaseType != "go" {
t.Fatalf("root release must remain a Go package: %+v", root)
}
if root.IncludeComponentInTag {
t.Fatal("root release tags must not include a component")
Expand Down Expand Up @@ -96,8 +113,8 @@ func assertReleasePleaseManifestAndChangelog(t *testing.T) {
if err := json.Unmarshal(rawManifest, &manifest); err != nil {
t.Fatalf("decode %s: %v", manifestPath, err)
}
if !releaseCandidateVersion.MatchString(manifest["."]) {
t.Fatalf("root manifest must contain a non-zero rc prerelease version, got %q", manifest["."])
if !releaseVersion.MatchString(manifest["."]) {
t.Fatalf("root manifest must contain an rc baseline or stable SemVer version, got %q", manifest["."])
}
changelogPath := filepath.Join("..", "CHANGELOG.md")
changelog, err := os.ReadFile(changelogPath)
Expand All @@ -124,24 +141,28 @@ func assertReleasePleaseWorkflow(t *testing.T) {
}
}

func TestReleaseCandidateVersionContract(t *testing.T) {
func TestReleaseVersionContract(t *testing.T) {
for version, want := range map[string]bool{
"1.0.0-rc.1": true,
"2.14.3-rc.42": true,
"0.0.0-rc.1": true,
"1.0.0+build.7": true,
"1.0.0+": false,
"1.0.0+build..7": false,
"1.1.0": true,
"2.14.3": true,
"01.0.0-rc.1": false,
"1.01.0-rc.1": false,
"1.0.01-rc.1": false,
"1.0.0-rc.0": false,
"1.0.0-rc.01": false,
"1.0.0": false,
"1.0.0-beta.1": false,
"v1.0.0-rc.1": false,
"1.0.0-rc.1+build.7": false,
} {
t.Run(version, func(t *testing.T) {
if got := releaseCandidateVersion.MatchString(version); got != want {
t.Fatalf("release candidate validation for %q = %t, want %t", version, got, want)
if got := releaseVersion.MatchString(version); got != want {
t.Fatalf("release version validation for %q = %t, want %t", version, got, want)
}
})
}
Expand Down
Loading