Add source publication command and runbook
This commit is contained in:
30
README.md
30
README.md
@@ -2,12 +2,12 @@
|
||||
|
||||
ReleaseKit is an opinionated Go library and executable for a shared release
|
||||
process. The Go module, root `releasekit` facade, `buildinfo` runtime package,
|
||||
local candidate check, source-tag publication API, and `version` and `check`
|
||||
commands are implemented. A publication command, builds, delivery, and release
|
||||
automation remain to be implemented. Their selected
|
||||
behavior and sequence are described in the
|
||||
[product roadmap](docs/roadmap/releasekit.md) and
|
||||
[implementation plan](docs/roadmap/implementation.md).
|
||||
local candidate check, source-tag publication API, and `version`, `check`, and
|
||||
`publish` commands are implemented. ReleaseKit's source-only maintainer
|
||||
procedure is documented. Executable builds and delivery remain future work.
|
||||
The [product roadmap](docs/roadmap/releasekit.md) and
|
||||
[implementation plan](docs/roadmap/implementation.md) describe their selected
|
||||
behavior and sequence.
|
||||
|
||||
Run the offline Go test suite from the repository root with:
|
||||
|
||||
@@ -28,25 +28,37 @@ configured checks (or the default offline Go test command):
|
||||
go run ./cmd/releasekit check v1.2.3
|
||||
```
|
||||
|
||||
Publish the source tag from a committed candidate with:
|
||||
|
||||
```sh
|
||||
./scripts/release v1.2.3
|
||||
```
|
||||
|
||||
See the [ReleaseKit maintainer procedure](docs/release.md) for preparation and
|
||||
failure recovery.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [ReleaseKit proposal](docs/roadmap/releasekit.md): proposed publication, builds,
|
||||
version injection, and delivery, with the initial implementation plan.
|
||||
- [Contributor guide](docs/development.md): orientation, validation, and selective
|
||||
policy reading.
|
||||
- [CLI contract](docs/cli.md): the `version` and local `check` commands.
|
||||
- [CLI contract](docs/cli.md): the `version`, local `check`, and source
|
||||
`publish` commands.
|
||||
- [Configuration](docs/config.md): profile fields and child-command settings.
|
||||
- [Runtime version guidance](docs/consumers/runtime-version.md): how applications
|
||||
read their embedded version through `buildinfo`.
|
||||
- [Candidate check guidance](docs/consumers/check.md): local candidate validation
|
||||
through the Go API and CLI.
|
||||
- [Maintainer release procedure](docs/release.md): ReleaseKit's source-only
|
||||
publication workflow and recovery.
|
||||
- [Internal package inventory](docs/internal/overview.md): implemented internal
|
||||
components and their responsibilities.
|
||||
- [Architecture policy](docs/policy/architecture.md): responsibility and dependency
|
||||
boundaries for development.
|
||||
- [ADR 0001](docs/adr/0001-public-facade.md): the accepted public facade decision.
|
||||
- [Policy adoption roadmap](docs/roadmap/policy.md): completed adoption and pending
|
||||
release bootstrap work.
|
||||
- [Policy adoption roadmap](docs/roadmap/policy.md): completed adoption and the
|
||||
current source-release path.
|
||||
|
||||
ReleaseKit is licensed under the [LGPL v3.0 or later](COPYRIGHT).
|
||||
|
||||
|
||||
@@ -16,13 +16,14 @@ import (
|
||||
"gitea.maximumdirect.net/eric/ReleaseKit/internal/process"
|
||||
)
|
||||
|
||||
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION"
|
||||
const Usage = "usage: releasekit version\n releasekit check [--repo DIR] [--config FILE] VERSION\n releasekit publish [--repo DIR] [--config FILE] VERSION"
|
||||
|
||||
type Command string
|
||||
|
||||
const (
|
||||
VersionCommand Command = "version"
|
||||
CheckAction Command = "check"
|
||||
PublishAction Command = "publish"
|
||||
)
|
||||
|
||||
// Invocation contains parsed command settings owned by the CLI adapter.
|
||||
@@ -44,8 +45,9 @@ func Parse(args []string) (Invocation, error) {
|
||||
return Invocation{}, errors.New("version takes no arguments")
|
||||
}
|
||||
return Invocation{Command: VersionCommand}, nil
|
||||
case string(CheckAction):
|
||||
flags := flag.NewFlagSet("check", flag.ContinueOnError)
|
||||
case string(CheckAction), string(PublishAction):
|
||||
action := Command(args[0])
|
||||
flags := flag.NewFlagSet(string(action), flag.ContinueOnError)
|
||||
flags.SetOutput(io.Discard)
|
||||
repository := flags.String("repo", ".", "repository directory")
|
||||
configPath := flags.String("config", "", "profile path")
|
||||
@@ -53,9 +55,9 @@ func Parse(args []string) (Invocation, error) {
|
||||
return Invocation{}, err
|
||||
}
|
||||
if flags.NArg() != 1 {
|
||||
return Invocation{}, errors.New("check requires one version argument")
|
||||
return Invocation{}, fmt.Errorf("%s requires one version argument", action)
|
||||
}
|
||||
return Invocation{Command: CheckAction, Repository: *repository, ConfigPath: *configPath, Version: flags.Arg(0)}, nil
|
||||
return Invocation{Command: action, Repository: *repository, ConfigPath: *configPath, Version: flags.Arg(0)}, nil
|
||||
default:
|
||||
return Invocation{}, fmt.Errorf("unknown command %q", args[0])
|
||||
}
|
||||
|
||||
@@ -26,14 +26,21 @@ func TestParse(t *testing.T) {
|
||||
if check.Command != CheckAction || check.Repository != "repository with spaces" || check.ConfigPath != "profiles/release config.json" || check.Version != "v1.2.3" {
|
||||
t.Fatalf("Parse(check) = %#v", check)
|
||||
}
|
||||
publish, err := Parse([]string{"publish", "--repo", "candidate", "--config", "releasekit.json", "v1.2.4"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if publish.Command != PublishAction || publish.Repository != "candidate" || publish.ConfigPath != "releasekit.json" || publish.Version != "v1.2.4" {
|
||||
t.Fatalf("Parse(publish) = %#v", publish)
|
||||
}
|
||||
if _, err := Parse([]string{"check", "v1.2.3", "--repo", "repository"}); err == nil {
|
||||
t.Fatal("Parse accepted a flag after the version")
|
||||
}
|
||||
if _, err := Parse(nil); err == nil || !strings.Contains(err.Error(), "command is required") {
|
||||
t.Fatalf("Parse(nil) error = %v, want missing-command error", err)
|
||||
}
|
||||
if _, err := Parse([]string{"publish"}); err == nil || !strings.Contains(err.Error(), "unknown command") {
|
||||
t.Fatalf("Parse(publish) error = %v, want unknown-command error", err)
|
||||
if _, err := Parse([]string{"unknown"}); err == nil || !strings.Contains(err.Error(), "unknown command") {
|
||||
t.Fatalf("Parse(unknown) error = %v, want unknown-command error", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ func run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
|
||||
case cli.VersionCommand:
|
||||
fmt.Fprintf(stdout, "releasekit %s\n", buildinfo.Version())
|
||||
return 0
|
||||
case cli.CheckAction:
|
||||
case cli.CheckAction, cli.PublishAction:
|
||||
settings, err := cli.LoadSettings(invocation.Repository, invocation.ConfigPath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "load profile: %v\n", err)
|
||||
@@ -54,6 +54,22 @@ func run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
|
||||
}, stderr, stderr)
|
||||
}
|
||||
}
|
||||
if invocation.Command == cli.PublishAction {
|
||||
fmt.Fprintf(stderr, "validating and publishing %s\n", invocation.Version)
|
||||
result, err := releasekit.Publish(ctx, request)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "publication state=%s phase=%s version=%s commit=%s tag-object=%s: %v\n", result.State, result.Phase, result.Version, result.CandidateCommit, result.TagObject, err)
|
||||
if errors.Is(err, releasekit.ErrInvalidVersion) {
|
||||
return 2
|
||||
}
|
||||
if result.State == releasekit.PublicationUnknown {
|
||||
return 3
|
||||
}
|
||||
return 1
|
||||
}
|
||||
fmt.Fprintf(stdout, "published %s at %s (tag object %s)\n", result.Version, result.CandidateCommit, result.TagObject)
|
||||
return 0
|
||||
}
|
||||
candidate, err := releasekit.Check(ctx, request)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "check failed: %v\n", err)
|
||||
|
||||
@@ -30,13 +30,13 @@ func TestVersionCommand(t *testing.T) {
|
||||
|
||||
func TestUnknownCommand(t *testing.T) {
|
||||
var stdout, stderr bytes.Buffer
|
||||
if status := run(context.Background(), []string{"publish"}, &stdout, &stderr); status != 2 {
|
||||
if status := run(context.Background(), []string{"unknown"}, &stdout, &stderr); status != 2 {
|
||||
t.Fatalf("run() status = %d, want 2", status)
|
||||
}
|
||||
if stdout.Len() != 0 {
|
||||
t.Fatalf("unknown command wrote to stdout: %q", stdout.String())
|
||||
}
|
||||
if want := "unknown command \"publish\"\n" + cli.Usage + "\n"; stderr.String() != want {
|
||||
if want := "unknown command \"unknown\"\n" + cli.Usage + "\n"; stderr.String() != want {
|
||||
t.Fatalf("usage output = %q, want %q", stderr.String(), want)
|
||||
}
|
||||
}
|
||||
@@ -82,6 +82,52 @@ func TestCheckCommandBindsConfiguredChecksToCapturedCandidate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishCommandPublishesConfiguredCandidate(t *testing.T) {
|
||||
repository := newCLIRepository(t)
|
||||
settings := cli.Settings{
|
||||
Product: "Example Product",
|
||||
Remote: "origin",
|
||||
Checks: []cli.CheckCommand{{
|
||||
Args: []string{"go", "test", "-mod=readonly", "-count=1", "./..."},
|
||||
Env: map[string]string{
|
||||
"GOTOOLCHAIN": "local",
|
||||
"GOPROXY": "off",
|
||||
"GOSUMDB": "off",
|
||||
},
|
||||
}},
|
||||
}
|
||||
contents, err := json.Marshal(settings)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(repository, "releasekit.json"), contents, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cliGitRun(t, repository, "add", "releasekit.json")
|
||||
cliGitRun(t, repository, "commit", "-m", "configure source release")
|
||||
remote := filepath.Join(t.TempDir(), "origin.git")
|
||||
cliGitRun(t, repository, "init", "--bare", remote)
|
||||
cliGitRun(t, repository, "remote", "add", "origin", remote)
|
||||
cliGitRun(t, repository, "push", "--set-upstream", "origin", "main")
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
args := []string{"publish", "--repo", repository, "v1.2.3"}
|
||||
if status := run(context.Background(), args, &stdout, &stderr); status != 0 {
|
||||
t.Fatalf("run() status = %d; stdout=%q stderr=%q", status, stdout.String(), stderr.String())
|
||||
}
|
||||
commit := cliGitOutput(t, repository, "rev-parse", "HEAD")
|
||||
tagObject := cliGitOutput(t, repository, "rev-parse", "refs/tags/v1.2.3")
|
||||
if want := fmt.Sprintf("published v1.2.3 at %s (tag object %s)\n", commit, tagObject); stdout.String() != want {
|
||||
t.Fatalf("stdout = %q, want %q", stdout.String(), want)
|
||||
}
|
||||
if !bytes.Contains(stderr.Bytes(), []byte("validating and publishing v1.2.3")) || !bytes.Contains(stderr.Bytes(), []byte("example.com/cli-candidate")) {
|
||||
t.Fatalf("stderr does not show publication progress and validation: %q", stderr.String())
|
||||
}
|
||||
if got := cliGitOutput(t, remote, "rev-parse", "refs/tags/v1.2.3"); got != tagObject {
|
||||
t.Fatalf("remote tag object = %s, want %s", got, tagObject)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCandidateCheckHelper(t *testing.T) {
|
||||
if os.Getenv("RELEASEKIT_CHECK_HELPER") != "1" {
|
||||
return
|
||||
|
||||
31
docs/cli.md
31
docs/cli.md
@@ -1,6 +1,6 @@
|
||||
# Command line
|
||||
|
||||
ReleaseKit currently provides two commands.
|
||||
ReleaseKit currently provides three commands.
|
||||
|
||||
Print the executable version:
|
||||
|
||||
@@ -24,7 +24,28 @@ captured local commit and version. It checks the committed release note, local
|
||||
Git state, and configured validation, but does not inspect remote availability
|
||||
or publish a tag.
|
||||
|
||||
Both commands write errors and diagnostic output to standard error. `check`
|
||||
returns status 0 after local validation, 1 after a candidate validation failure,
|
||||
and 2 for usage, profile, or invalid-version errors. Unsupported argument
|
||||
sequences print usage to standard error.
|
||||
`check` writes errors and diagnostics to standard error. It returns status 0
|
||||
after local validation, 1 after a candidate validation failure, and 2 for usage,
|
||||
profile, or invalid-version errors. Unsupported argument sequences print usage
|
||||
to standard error.
|
||||
|
||||
Publish a source tag:
|
||||
|
||||
```sh
|
||||
go run ./cmd/releasekit publish [--repo DIR] [--config FILE] VERSION
|
||||
```
|
||||
|
||||
`publish` reads the same product, remote, and validation settings as `check`.
|
||||
It validates the candidate once, checks the authoritative remote, creates an
|
||||
annotated local tag, and pushes only its exact tag object. It prints the
|
||||
confirmed version, candidate commit, and tag object on success. Validation
|
||||
progress and failed publication state are written to standard error. A signal
|
||||
cancels the active operation; if it arrives during a push, the library's
|
||||
bounded reconciliation determines whether the exact tag was accepted.
|
||||
|
||||
The command returns status 0 for confirmed publication, 1 for a known
|
||||
publication failure or conflict, 2 for usage, profile, or invalid-version
|
||||
errors, and 3 when the push outcome remains unknown. Unknown status must be
|
||||
resolved against the authoritative remote before retrying. The
|
||||
[maintainer procedure](release.md) selects the repository profile and gives
|
||||
the source-release workflow.
|
||||
|
||||
@@ -20,10 +20,12 @@ The overlay does not modify the ReleaseKit process environment.
|
||||
|
||||
Unknown fields are rejected so a setting cannot be silently ignored. Build and
|
||||
delivery fields will be added when those operations are implemented. The `check`
|
||||
command uses `product`, `remote`, and `checks`. If `checks` is omitted or empty,
|
||||
it runs `go test -mod=readonly -count=1 ./...` with Go module and toolchain
|
||||
network access disabled. If checks are configured, they replace that default and
|
||||
run in order.
|
||||
and `publish` commands use `product`, `remote`, and `checks`. If `checks` is
|
||||
omitted or empty, it runs `go test -mod=readonly -count=1 ./...` with Go module
|
||||
and toolchain network access disabled. If checks are configured, they replace
|
||||
that default and run in order.
|
||||
|
||||
ReleaseKit's source-only publication profile is
|
||||
[releasekit.json](../releasekit.json).
|
||||
See the [profile example](../examples/releasekit.json). The
|
||||
[CLI contract](cli.md) lists the currently available command.
|
||||
|
||||
@@ -65,7 +65,9 @@ git diff --cached --check -- '*.md' COPYRIGHT
|
||||
Verbatim license texts retain their supplied formatting. When changing those
|
||||
texts, compare their bytes with the selected upstream source.
|
||||
|
||||
There is no publication command yet. Add working development commands here as
|
||||
implementation lands. Add `docs/release.md` with the first working publication
|
||||
command; the [policy adoption roadmap](roadmap/policy.md#4-define-releasekits-own-release-path)
|
||||
records the remaining bootstrap work.
|
||||
Run the source publication command from the candidate repository root with
|
||||
`./scripts/release VERSION`. It uses the local Go toolchain and committed
|
||||
`releasekit.json` profile; prepare module dependencies before offline candidate
|
||||
validation. The [maintainer release procedure](release.md) owns preparation,
|
||||
publication, and recovery. Executable artifacts and delivery remain outside
|
||||
ReleaseKit's initial source-only release.
|
||||
|
||||
@@ -18,10 +18,8 @@ policy and link to it rather than introduce additional release requirements.
|
||||
|
||||
This policy governs releases of ReleaseKit itself. Consumer release capabilities
|
||||
are designed in the [product roadmap](../roadmap/releasekit.md) and acquire exact
|
||||
public contracts when implemented. ReleaseKit currently has no publication
|
||||
command. Create the maintainer runbook alongside the first working command;
|
||||
the [policy adoption roadmap](../roadmap/policy.md#4-define-releasekits-own-release-path)
|
||||
owns that pending work.
|
||||
public contracts when implemented. ReleaseKit's source publication command and
|
||||
maintainer runbook are implemented; no ReleaseKit release has been published.
|
||||
|
||||
## Release Model And Completion
|
||||
|
||||
@@ -33,8 +31,8 @@ The procedure must name the authoritative publication remote.
|
||||
A successful push of the intended annotated tag, with its source commit already
|
||||
published on authoritative `main`, completes the release. The remote branch must
|
||||
identify the validated candidate before the command publishes only the exact
|
||||
intended tag object. The runbook will identify the authoritative endpoint and
|
||||
command when publication is implemented.
|
||||
intended tag object. The [maintainer runbook](../release.md) identifies the
|
||||
authoritative endpoint and command.
|
||||
|
||||
Release commands must finish at successful publication. They must not wait for
|
||||
or poll CI, require successful CI status, inspect downloadable artifacts, or
|
||||
|
||||
93
docs/release.md
Normal file
93
docs/release.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# ReleaseKit release procedure
|
||||
|
||||
ReleaseKit's initial deliverable is source only. The authoritative repository
|
||||
is `origin` at `https://gitea.maximumdirect.net/eric/ReleaseKit.git`, and the
|
||||
release branch is `main`. A release completes when the intended annotated tag
|
||||
is successfully pushed, or when one exact-object recovery query confirms that
|
||||
the push succeeded. CI, hosted artifacts, and consumer installation are not
|
||||
completion checks.
|
||||
|
||||
## Prepare a candidate
|
||||
|
||||
Use a local Go 1.25 toolchain and a clean clone. Start on `main`, choose an
|
||||
unused stable `vMAJOR.MINOR.PATCH` version, and add
|
||||
`docs/releases/<version>.md` with a first heading containing `ReleaseKit` and
|
||||
the exact version. Summarize the change and any compatibility or upgrade impact.
|
||||
End the note with the three license links at the immutable source tag:
|
||||
|
||||
```markdown
|
||||
[COPYRIGHT](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/vX.Y.Z/COPYRIGHT) |
|
||||
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/vX.Y.Z/LICENSE) |
|
||||
[ATTRIBUTION](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/vX.Y.Z/docs/oss/attribution.md)
|
||||
```
|
||||
|
||||
Replace every `vX.Y.Z` with the selected version. These are links to the same
|
||||
release note's immutable source tree and also work when the note is used as a
|
||||
hosted release body.
|
||||
|
||||
Commit the note and all candidate changes on `main`, then publish that commit
|
||||
to `origin/main`:
|
||||
|
||||
```sh
|
||||
git push origin main
|
||||
```
|
||||
|
||||
ReleaseKit checks that the worktree is clean, the candidate is on `main`, the
|
||||
authoritative branch identifies that commit, and the version is unused locally
|
||||
and on `origin`.
|
||||
|
||||
## Prepare dependencies, then publish
|
||||
|
||||
Dependency preparation is separate from the offline candidate validation. Run
|
||||
it from the captured candidate source before the release command:
|
||||
|
||||
```sh
|
||||
GOTOOLCHAIN=local go mod download
|
||||
```
|
||||
|
||||
Then run the single publication command from the repository root:
|
||||
|
||||
```sh
|
||||
./scripts/release vX.Y.Z
|
||||
```
|
||||
|
||||
The committed `releasekit.json` selects the offline default test suite:
|
||||
`go test -mod=readonly -count=1 ./...`, with toolchain and module network
|
||||
access disabled for validation. The command validates once, checks the
|
||||
authoritative remote state, creates a local annotated tag from the captured
|
||||
candidate and checked-in note, rechecks the tag and remote guards, and pushes
|
||||
only that tag object. It prints the published version, commit, and tag object
|
||||
on success. Exit status 0 means publication is confirmed; status 1 means a
|
||||
known failure or conflict; status 2 means invalid input or profile; status 3
|
||||
means the push outcome remains unknown and requires resolution.
|
||||
|
||||
The CLI runs from the source tree being published, so this command also works
|
||||
for ReleaseKit's first release before any released ReleaseKit executable
|
||||
exists. It uses the local Go toolchain. Preparation must finish before the
|
||||
offline validation begins.
|
||||
|
||||
## Resolve failures
|
||||
|
||||
A failed push triggers one exact authoritative tag query. An exact tag-object
|
||||
match confirms publication even when Git reported an error. A proven absent tag
|
||||
is `not_published`; a different object is a conflict; an unreadable query is
|
||||
`unknown`. The command retains its local tag and reports the state, phase,
|
||||
candidate commit, and tag object when available. Do not retry an unknown result
|
||||
until you resolve the authoritative ref:
|
||||
|
||||
```sh
|
||||
git ls-remote --refs origin "refs/tags/vX.Y.Z"
|
||||
```
|
||||
|
||||
Compare the returned object ID with the tag object reported by the command.
|
||||
An exact match confirms publication. If the ref is absent, the version was not
|
||||
published; only then may you deliberately remove the unpublished local tag
|
||||
with `git tag -d vX.Y.Z` before correcting the candidate or retrying. Do not
|
||||
move, overwrite, or delete a tag that exists remotely. If a different object
|
||||
uses the version, choose a new version after resolving the conflict.
|
||||
|
||||
If validation or a guard fails before the push, the local tag has not been
|
||||
published. Correct and commit the candidate, publish `main`, and run the
|
||||
command again. ReleaseKit does not publish executable artifacts or wait for
|
||||
asynchronous delivery; any future deliverables require a separate policy and
|
||||
procedure update.
|
||||
@@ -649,7 +649,7 @@ local tag before push prevent publication.
|
||||
|
||||
## Stage 9: Expose publication and document ReleaseKit bootstrap
|
||||
|
||||
Status: Pending. Depends on Stage 8.
|
||||
Status: Complete. Depends on Stage 8.
|
||||
|
||||
1. Wire the complete public publisher into `releasekit publish`, with selected
|
||||
progress output, final result, exit classification, and signal cancellation.
|
||||
@@ -672,6 +672,15 @@ committed profile and returns the expected exit/output behavior. Runbook command
|
||||
are exercised using a temporary repository configured like ReleaseKit. This
|
||||
stage prepares self-publication and does not publish a real ReleaseKit release.
|
||||
|
||||
Evidence: `publish` runs the public publisher with the CLI signal context,
|
||||
selected progress output, final commit and tag-object output, and separate exit
|
||||
status for unresolved outcomes. A temporary committed profile runs the offline
|
||||
test command and publishes to a local bare remote. ReleaseKit's root profile,
|
||||
entry script, CLI and configuration guides, development guide, and maintainer
|
||||
runbook describe source-only publication and exact-object recovery. The
|
||||
runbook's dependency preparation is separate from offline validation. No real
|
||||
ReleaseKit release was published.
|
||||
|
||||
## Stage 10: Build selected targets with shared version injection
|
||||
|
||||
Status: Pending. Depends on Stage 9.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Adopt the policy framework
|
||||
|
||||
Status: Policy adoption complete. Release publication implementation is pending.
|
||||
Status: Policy adoption complete. Source publication and its maintainer runbook
|
||||
are implemented; no ReleaseKit release has been published. Executable delivery
|
||||
remains pending.
|
||||
|
||||
Date: 2026-10-05
|
||||
|
||||
@@ -130,20 +132,21 @@ policy has separate defaults for applications and libraries.
|
||||
successful-tag-push completion rules.
|
||||
- [x] Select source only as ReleaseKit's initial deliverable in the release
|
||||
policy. Supporting downstream cross-builds does not declare ReleaseKit binaries.
|
||||
- [ ] Add `docs/release.md` alongside the first working publication command,
|
||||
- [x] Add `docs/release.md` alongside the first working publication command,
|
||||
documenting real prerequisites, authoritative remote, branch, validation,
|
||||
publication, and failure recovery.
|
||||
- [x] Account for first-release bootstrap: the initial publication command must
|
||||
run from the captured candidate source with dependencies prepared separately.
|
||||
The first release uses that source execution path before a released ReleaseKit
|
||||
tool exists. Document and verify the actual command when it is implemented.
|
||||
tool exists. The maintainer procedure documents the command and the temporary
|
||||
repository integration test exercises the same CLI workflow.
|
||||
- [ ] Add executable delivery declarations and target checks when corresponding
|
||||
deliverables exist. Keep source completion and asynchronous delivery status
|
||||
separate. This task is deferred unless executable deliverables are selected.
|
||||
|
||||
The publication command, its automated guards and offline candidate validation,
|
||||
and the executable maintainer runbook remain product implementation work. This
|
||||
adoption does not claim an available release command or perform publication.
|
||||
The publication command, its automated guards, offline candidate validation,
|
||||
and executable maintainer runbook are implemented. This adoption does not claim
|
||||
that a ReleaseKit version has been published.
|
||||
|
||||
## Validation and completion
|
||||
|
||||
@@ -165,14 +168,14 @@ approval, and CI polling are not additional adoption or release gates.
|
||||
## Adoption result
|
||||
|
||||
The seven policies, root agent orientation, developer reading guide, documentation
|
||||
ownership, project grant, attribution, and license texts are in place. The product
|
||||
proposal lives at `docs/roadmap/releasekit.md`; `ideas.md` remains a navigation
|
||||
pointer. Future capabilities retain their proposed status, and facade
|
||||
implementation remains pending in the product roadmap.
|
||||
ownership, project grant, attribution, license texts, source publication command,
|
||||
and maintainer runbook are in place. The product proposal lives at
|
||||
`docs/roadmap/releasekit.md`; `ideas.md` remains a navigation pointer. Executable
|
||||
delivery remains pending, and no ReleaseKit release has been published.
|
||||
|
||||
Verification covers local file and fragment links, per-policy source revision and
|
||||
base version, removed template adoption sections, attribution scope and pinned
|
||||
notice destinations, verbatim license bytes, and prose whitespace. The preserved
|
||||
ADR decision and relocated proposal are checked against their pre-adoption source.
|
||||
Release automation and its runbook remain pending under stage 4 as permitted by
|
||||
this roadmap's completion criteria.
|
||||
ReleaseKit's source publication command and runbook are implemented; executable
|
||||
delivery declarations remain pending under stage 4.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# ReleaseKit: shared release process
|
||||
|
||||
This is a proposal based on a review of PromptKit, ConfigKit, Audita, Notarius,
|
||||
Narratio, and Scriptorium on 2026-09-29. Product capabilities remain proposed.
|
||||
The public facade architecture is accepted in
|
||||
[ADR 0001](../adr/0001-public-facade.md), with implementation pending.
|
||||
Narratio, and Scriptorium on 2026-09-29. The implementation plan records the
|
||||
current implemented boundary; builds, delivery, and broader integrations remain
|
||||
proposed. The public facade architecture is accepted in
|
||||
[ADR 0001](../adr/0001-public-facade.md) and is implemented for runtime version,
|
||||
candidate validation, and source publication.
|
||||
The [implementation plan](implementation.md) owns ordered stages, execution
|
||||
instructions, acceptance checks, and progress toward this target state.
|
||||
|
||||
@@ -50,12 +52,11 @@ cleanup.
|
||||
## Architecture
|
||||
|
||||
[ADR 0001](../adr/0001-public-facade.md) owns the accepted facade decision.
|
||||
The [architecture policy](../policy/architecture.md) owns the adopted responsibility
|
||||
and dependency rules, including the runtime version boundary. The facades remain
|
||||
unimplemented.
|
||||
The root `releasekit` package will provide the public facade for publication,
|
||||
builds, and delivery. A separate public `buildinfo` package will provide the
|
||||
lightweight facade for runtime version information.
|
||||
The [architecture policy](../policy/architecture.md) owns the adopted
|
||||
responsibility and dependency rules, including the runtime version boundary.
|
||||
The root `releasekit` package provides the public facade for candidate
|
||||
validation and source publication; builds and delivery remain planned. The
|
||||
separate public `buildinfo` package provides lightweight runtime version access.
|
||||
|
||||
Each facade owns its public named types and documented contracts. Public
|
||||
operations, inputs, outcomes, errors, and callbacks express deliberately
|
||||
|
||||
14
releasekit.json
Normal file
14
releasekit.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"product": "ReleaseKit",
|
||||
"remote": "origin",
|
||||
"checks": [
|
||||
{
|
||||
"args": ["go", "test", "-mod=readonly", "-count=1", "./..."],
|
||||
"env": {
|
||||
"GOTOOLCHAIN": "local",
|
||||
"GOPROXY": "off",
|
||||
"GOSUMDB": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
9
scripts/release
Executable file
9
scripts/release
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
printf '%s\n' 'usage: ./scripts/release VERSION' >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
GOTOOLCHAIN=local exec go run ./cmd/releasekit publish "$1"
|
||||
Reference in New Issue
Block a user