Adopt ReleaseKit module publishing

This commit is contained in:
2026-10-11 01:54:04 +00:00
parent e89cc2220f
commit 18e81a5579
9 changed files with 254 additions and 131 deletions

View File

@@ -1,6 +1,6 @@
# Implement the optional integration modules and captured registration API
Status: implementation in progress. Stages 1 through 13 are complete; subsequent work follows the ordered roadmap.
Status: implementation in progress. Stages 1 through 14 are complete; subsequent work follows the ordered roadmap.
Execute the stages in order. Each stage is sized as a separate Luna coding-agent
assignment. This document authorizes no publication or changes to sibling
repositories.
@@ -687,10 +687,16 @@ required.
exercise to include a nested module with a distinct prefixed tag and module
note. Default tests remain offline and do not publish.
**Completion evidence:** ordinary launcher tests pass without network/publication.
The optional disposable exercise demonstrates one root and one nested module;
run it only when its dependencies are prepared. A sibling checkout or ad hoc
ReleaseKit source build is not the selected consumer tool.
**Completion evidence — complete:** offline launcher tests pass for all three
selectors, usage failures before bootstrap, paths containing spaces, exact
profile/module routing, delegated environment settings, and delegated exit
statuses. The opt-in disposable exercise passed for both a root module tag and
the prefixed `integrations/ckconfig/v0.0.1` tag with its module release note;
the endpoint guard also stopped a later publication before validation. ReleaseKit
v0.4.0 was resolved from its tagged module, and the workspace-off root module
graph contains no ConfigKit or PromptKit dependency. No publication occurred.
A sibling checkout or ad hoc ReleaseKit source build is not the selected
consumer tool.
## Stage 15: Reconcile documentation, licensing, and release preparation

2
go.mod
View File

@@ -9,7 +9,7 @@ require (
)
require (
gitea.maximumdirect.net/eric/ReleaseKit v0.3.0 // indirect
gitea.maximumdirect.net/eric/ReleaseKit v0.4.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/yuin/goldmark/v2 v2.1.6 // indirect
golang.org/x/mod v0.40.0 // indirect

4
go.sum
View File

@@ -1,5 +1,5 @@
gitea.maximumdirect.net/eric/ReleaseKit v0.3.0 h1:aTMn+50MEpHpHI2RoCCmJYsy7Ohrpa+RSva63Kq0/tU=
gitea.maximumdirect.net/eric/ReleaseKit v0.3.0/go.mod h1:LVodqNQ3OIKv9NBq+fFeyMByd1lHY25YOmmpah/NaNI=
gitea.maximumdirect.net/eric/ReleaseKit v0.4.0 h1:0FDgysQAA8FJSB57x6kjLtcZexb3sUjRGIuo2OuGI6Q=
gitea.maximumdirect.net/eric/ReleaseKit v0.4.0/go.mod h1:LVodqNQ3OIKv9NBq+fFeyMByd1lHY25YOmmpah/NaNI=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=

View File

@@ -0,0 +1,13 @@
{
"product": "CommandKit ckconfig",
"module_dir": "integrations/ckconfig",
"remote": "origin",
"expected_push_url": "https://gitea.maximumdirect.net/eric/CommandKit.git",
"validation": {
"shared_files": [
"COPYRIGHT",
"LICENSE",
"docs/oss/attribution.md"
]
}
}

View File

@@ -0,0 +1,13 @@
{
"product": "CommandKit ckprompt",
"module_dir": "integrations/ckprompt",
"remote": "origin",
"expected_push_url": "https://gitea.maximumdirect.net/eric/CommandKit.git",
"validation": {
"shared_files": [
"COPYRIGHT",
"LICENSE",
"docs/oss/attribution.md"
]
}
}

View File

@@ -1,5 +1,13 @@
{
"product": "CommandKit",
"module_dir": ".",
"remote": "origin",
"expected_push_url": "https://gitea.maximumdirect.net/eric/CommandKit.git"
"expected_push_url": "https://gitea.maximumdirect.net/eric/CommandKit.git",
"validation": {
"shared_files": [
"COPYRIGHT",
"LICENSE",
"docs/oss/attribution.md"
]
}
}

View File

@@ -1,16 +1,35 @@
#!/bin/sh
set -eu
if [ "$#" -ne 1 ]; then
printf '%s\n' 'usage: ./scripts/release VERSION' >&2
if [ "$#" -ne 2 ]; then
printf '%s\n' 'usage: ./scripts/release MODULE VERSION' >&2
exit 2
fi
release_version=$1
case "$1" in
core)
commandkit_module_dir=.
commandkit_profile=releasekit.json
;;
ckconfig)
commandkit_module_dir=integrations/ckconfig
commandkit_profile=integrations/ckconfig/releasekit.json
;;
ckprompt)
commandkit_module_dir=integrations/ckprompt
commandkit_profile=integrations/ckprompt/releasekit.json
;;
*)
printf '%s\n' 'usage: ./scripts/release MODULE VERSION' >&2
exit 2
;;
esac
release_version=$2
commandkit_root=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
CDPATH= cd "$commandkit_root"
mkdir -p .releasekit/bin
mkdir -p "$commandkit_root/.releasekit/bin"
commandkit_host_os=$(GOWORK=off GOTOOLCHAIN=local go env GOHOSTOS)
commandkit_host_arch=$(GOWORK=off GOTOOLCHAIN=local go env GOHOSTARCH)
@@ -23,7 +42,8 @@ go build \
-o "$commandkit_root/.releasekit/bin/releasekit" \
gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit
exec "$commandkit_root/.releasekit/bin/releasekit" publish \
GOWORK=off GOTOOLCHAIN=local exec "$commandkit_root/.releasekit/bin/releasekit" publish \
--repo "$commandkit_root" \
--config "$commandkit_root/releasekit.json" \
--config "$commandkit_root/$commandkit_profile" \
--expected-module "$commandkit_module_dir" \
"$release_version"

View File

@@ -9,6 +9,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
"testing"
"time"
@@ -36,15 +37,15 @@ func TestReleaseIntegration(t *testing.T) {
env := fixture.releaseEnv(marker)
candidate := gitRun(t, ctx, git, fixture.worktree, env, "rev-parse", "HEAD")
stdout, stderr, status := runPublisher(t, ctx, shell, fixture, env, "v0.0.1")
stdout, stderr, status := runPublisher(t, ctx, shell, fixture, env, "core", "v0.0.1")
if status != 0 {
t.Fatalf("publish v0.0.1 status = %d\nstdout:\n%s\nstderr:\n%s", status, stdout, stderr)
t.Fatalf("publish core v0.0.1 status = %d\nstdout:\n%s\nstderr:\n%s", status, stdout, stderr)
}
if !strings.Contains(stdout, "v0.0.1") || !strings.Contains(stdout, candidate) {
t.Fatalf("publication output does not identify version and candidate %s:\n%s", candidate, stdout)
}
assertTag(t, ctx, git, fixture, "v0.0.1", candidate)
assertOnlyTag(t, ctx, git, fixture, "v0.0.1")
assertTags(t, ctx, git, fixture, "v0.0.1")
if got := readLines(t, marker); !equalStrings(got, []string{"candidate suite ran"}) {
t.Fatalf("candidate suite marker = %#v, want one run", got)
}
@@ -58,28 +59,41 @@ func TestReleaseIntegration(t *testing.T) {
t.Fatalf("expected ignored bootstrap executable: %v", err)
}
nestedCandidate := gitRun(t, ctx, git, fixture.worktree, env, "rev-parse", "HEAD")
stdout, stderr, status = runPublisher(t, ctx, shell, fixture, env, "ckconfig", "v0.0.1")
if status != 0 {
t.Fatalf("publish ckconfig v0.0.1 status = %d\nstdout:\n%s\nstderr:\n%s", status, stdout, stderr)
}
nestedTag := "integrations/ckconfig/v0.0.1"
if !strings.Contains(stdout, nestedTag) || !strings.Contains(stdout, nestedCandidate) {
t.Fatalf("nested publication output does not identify tag %s and candidate %s:\n%s", nestedTag, nestedCandidate, stdout)
}
assertTag(t, ctx, git, fixture, nestedTag, nestedCandidate)
assertTags(t, ctx, git, fixture, "v0.0.1", nestedTag)
fixture.prepareSecondCandidate(t, ctx, git)
stdout, stderr, status = runPublisher(t, ctx, shell, fixture, env, "v0.0.2")
stdout, stderr, status = runPublisher(t, ctx, shell, fixture, env, "core", "v0.0.2")
if status != 1 {
t.Fatalf("publish with mismatched endpoint status = %d, want 1\nstdout:\n%s\nstderr:\n%s", status, stdout, stderr)
}
if !strings.Contains(strings.ToLower(stderr), "unexpected publication push url") {
t.Fatalf("endpoint mismatch diagnostic not found in stderr:\n%s", stderr)
}
assertOnlyTag(t, ctx, git, fixture, "v0.0.1")
assertTags(t, ctx, git, fixture, "v0.0.1", nestedTag)
if got := readLines(t, marker); !equalStrings(got, []string{"candidate suite ran"}) {
t.Fatalf("candidate suite ran after endpoint preflight failure: %#v", got)
}
}
type publicationFixture struct {
root string
worktree string
bare string
outside string
profile string
gitConfig string
gitEnv []string
root string
worktree string
bare string
outside string
profile string
nestedProfile string
gitConfig string
gitEnv []string
}
func newPublicationFixture(t *testing.T, ctx context.Context, git string) publicationFixture {
@@ -124,6 +138,13 @@ func newPublicationFixture(t *testing.T, ctx context.Context, git string) public
for _, name := range []string{"go.mod", "go.sum", ".gitignore"} {
copyFile(t, filepath.Join(commandkitRoot, name), filepath.Join(worktree, name), 0o644)
}
for _, name := range []string{"COPYRIGHT", "LICENSE", "docs/oss/attribution.md"} {
target := filepath.Join(worktree, name)
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
t.Fatal(err)
}
copyFile(t, filepath.Join(commandkitRoot, name), target, 0o644)
}
script := filepath.Join(worktree, "scripts", "release")
if err := os.MkdirAll(filepath.Dir(script), 0o755); err != nil {
t.Fatal(err)
@@ -147,6 +168,35 @@ func newPublicationFixture(t *testing.T, ctx context.Context, git string) public
t.Fatal(err)
}
writeFile(t, profile, string(profileData)+"\n", 0o644)
nestedModule := filepath.Join(worktree, "integrations", "ckconfig")
if err := os.MkdirAll(nestedModule, 0o755); err != nil {
t.Fatal(err)
}
writeFile(t, filepath.Join(nestedModule, "go.mod"), "module gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig\n\ngo 1.26.0\n", 0o644)
writeFile(t, filepath.Join(nestedModule, "fixture.go"), "package fixture\n\nfunc Ready() bool { return true }\n", 0o644)
writeFile(t, filepath.Join(nestedModule, "fixture_test.go"), "package fixture\n\nimport \"testing\"\n\nfunc TestReady(t *testing.T) { if !Ready() { t.Fatal(\"not ready\") } }\n", 0o644)
if err := os.MkdirAll(filepath.Join(nestedModule, "docs", "releases"), 0o755); err != nil {
t.Fatal(err)
}
writeFile(t, filepath.Join(nestedModule, "docs", "releases", "v0.0.1.md"), releaseNoteFor("CommandKit ckconfig", "v0.0.1"), 0o644)
nestedProfile := filepath.Join(nestedModule, "releasekit.json")
nestedProfileData, err := os.ReadFile(filepath.Join(commandkitRoot, "integrations", "ckconfig", "releasekit.json"))
if err != nil {
t.Fatal(err)
}
var nestedFields map[string]json.RawMessage
if err := json.Unmarshal(nestedProfileData, &nestedFields); err != nil {
t.Fatal(err)
}
nestedFields["expected_push_url"], err = json.Marshal(bare)
if err != nil {
t.Fatal(err)
}
nestedProfileData, err = json.MarshalIndent(nestedFields, "", " ")
if err != nil {
t.Fatal(err)
}
writeFile(t, nestedProfile, string(nestedProfileData)+"\n", 0o644)
writeFile(t, filepath.Join(worktree, "fixture_test.go"), fixtureSuiteTest, 0o644)
if err := os.MkdirAll(filepath.Join(worktree, "docs", "releases"), 0o755); err != nil {
t.Fatal(err)
@@ -158,13 +208,14 @@ func newPublicationFixture(t *testing.T, ctx context.Context, git string) public
gitRun(t, ctx, git, worktree, gitEnv, "push", "origin", "HEAD:refs/heads/main")
return publicationFixture{
root: root,
worktree: worktree,
bare: bare,
outside: outside,
profile: profile,
gitConfig: configPath,
gitEnv: gitEnv,
root: root,
worktree: worktree,
bare: bare,
outside: outside,
profile: profile,
nestedProfile: nestedProfile,
gitConfig: configPath,
gitEnv: gitEnv,
}
}
@@ -209,9 +260,9 @@ func (fixture publicationFixture) prepareSecondCandidate(t *testing.T, ctx conte
gitRun(t, ctx, git, fixture.worktree, fixture.gitEnv, "push", "origin", "HEAD:refs/heads/main")
}
func runPublisher(t *testing.T, ctx context.Context, shell string, fixture publicationFixture, env []string, version string) (string, string, int) {
func runPublisher(t *testing.T, ctx context.Context, shell string, fixture publicationFixture, env []string, module, version string) (string, string, int) {
t.Helper()
cmd := exec.CommandContext(ctx, shell, filepath.Join(fixture.worktree, "scripts", "release"), version)
cmd := exec.CommandContext(ctx, shell, filepath.Join(fixture.worktree, "scripts", "release"), module, version)
cmd.Dir = fixture.outside
cmd.Env = env
var stdout, stderr strings.Builder
@@ -251,11 +302,16 @@ func assertTag(t *testing.T, ctx context.Context, git string, fixture publicatio
}
}
func assertOnlyTag(t *testing.T, ctx context.Context, git string, fixture publicationFixture, version string) {
func assertTags(t *testing.T, ctx context.Context, git string, fixture publicationFixture, versions ...string) {
t.Helper()
local := gitRun(t, ctx, git, fixture.worktree, fixture.gitEnv, "for-each-ref", "--format=%(refname)", "refs/tags")
remote := gitRun(t, ctx, git, fixture.root, fixture.gitEnv, "--git-dir", fixture.bare, "for-each-ref", "--format=%(refname)", "refs/tags")
want := "refs/tags/" + version
wantRefs := make([]string, len(versions))
for i, version := range versions {
wantRefs[i] = "refs/tags/" + version
}
sort.Strings(wantRefs)
want := strings.Join(wantRefs, "\n")
if local != want || remote != want {
t.Fatalf("tag refs local=%q remote=%q, want only %q", local, remote, want)
}
@@ -309,7 +365,11 @@ func isolatedProcessEnv(overrides map[string]string, cleared ...string) []string
}
func releaseNote(version string) string {
return "# CommandKit " + version + "\n\nLocal fixture release candidate.\n"
return releaseNoteFor("CommandKit", version)
}
func releaseNoteFor(product, version string) string {
return "# " + product + " " + version + "\n\nLocal fixture release candidate.\n"
}
const fixtureSuiteTest = `package fixture

View File

@@ -5,9 +5,7 @@ import (
"bytes"
"context"
"errors"
"flag"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
@@ -30,7 +28,9 @@ func TestReleaseLauncherArgumentHandling(t *testing.T) {
args []string
}{
{name: "no arguments"},
{name: "multiple arguments", args: []string{"v1.2.3", "extra"}},
{name: "one argument", args: []string{"core"}},
{name: "multiple arguments", args: []string{"core", "v1.2.3", "extra"}},
{name: "unknown module", args: []string{"unknown", "v1.2.3"}},
} {
t.Run(test.name, func(t *testing.T) {
fixture := newFixture(t)
@@ -42,7 +42,7 @@ func TestReleaseLauncherArgumentHandling(t *testing.T) {
if result.stdout != "" {
t.Fatalf("stdout = %q, want empty", result.stdout)
}
if result.stderr != "usage: ./scripts/release VERSION\n" {
if result.stderr != "usage: ./scripts/release MODULE VERSION\n" {
t.Fatalf("stderr = %q, want usage", result.stderr)
}
if _, err := os.Stat(fixture.goLog); !errors.Is(err, os.ErrNotExist) {
@@ -54,63 +54,43 @@ func TestReleaseLauncherArgumentHandling(t *testing.T) {
func TestReleaseLauncherDelegatesPublication(t *testing.T) {
shell := requirePOSIXShell(t)
for _, status := range []int{0, 1, 2, 3} {
t.Run(fmt.Sprintf("exit status %d", status), func(t *testing.T) {
fixture := newFixture(t)
result := runLauncher(t, shell, fixture, []string{releaseVersion}, map[string]string{
"CDPATH": "/tmp",
"GOOS": "windows",
"GOARCH": "arm64",
"PUBLISH_EXIT": strconv.Itoa(status),
"PUBLISH_STDOUT": "publisher stdout",
"PUBLISH_STDERR": "publisher stderr",
for _, module := range []string{"core", "ckconfig", "ckprompt"} {
for _, status := range []int{0, 1, 2, 3} {
t.Run(fmt.Sprintf("%s exit status %d", module, status), func(t *testing.T) {
fixture := newFixture(t)
result := runLauncher(t, shell, fixture, []string{module, releaseVersion}, map[string]string{
"CDPATH": "/tmp",
"GOOS": "windows",
"GOARCH": "arm64",
"GOWORK": "auto",
"GOTOOLCHAIN": "auto",
"PUBLISH_EXIT": strconv.Itoa(status),
"PUBLISH_STDOUT": "publisher stdout",
"PUBLISH_STDERR": "publisher stderr",
})
if result.status != status {
t.Fatalf("status = %d, want %d; stderr: %q", result.status, status, result.stderr)
}
if result.stdout != "publisher stdout\n" {
t.Fatalf("stdout = %q, want publisher output", result.stdout)
}
if result.stderr != "publisher stderr\n" {
t.Fatalf("stderr = %q, want publisher error output", result.stderr)
}
if err := checkPublication(readLines(t, fixture.publishLog), fixture.repoRoot, module); err != nil {
t.Fatal(err)
}
if got := readLines(t, fixture.publishEnvLog); !equalStrings(got, []string{"GOWORK=off", "GOTOOLCHAIN=local"}) {
t.Fatalf("publisher environment = %#v, want workspace disabled and local toolchain", got)
}
assertNativeBootstrap(t, fixture)
})
if result.status != status {
t.Fatalf("status = %d, want %d; stderr: %q", result.status, status, result.stderr)
}
if result.stdout != "publisher stdout\n" {
t.Fatalf("stdout = %q, want publisher output", result.stdout)
}
if result.stderr != "publisher stderr\n" {
t.Fatalf("stderr = %q, want publisher error output", result.stderr)
}
if err := checkPublication(readLines(t, fixture.publishLog), fixture.repoRoot); err != nil {
t.Fatal(err)
}
assertNativeBootstrap(t, fixture)
})
}
}
}
func TestReleaseLauncherAcceptsEquivalentCommands(t *testing.T) {
shell := requirePOSIXShell(t)
fixture := newFixture(t)
// Change only the fixture script: the production launcher need not be refactored.
writeFile(t, fixture.launcher, `#!/bin/sh
set -eu
version=$1
root=$(CDPATH= cd "$(dirname "$0")/.." && pwd)
CDPATH= cd "$root"
mkdir -p .releasekit/bin
set -- $(GOWORK=off GOTOOLCHAIN=local go env GOHOSTOS GOHOSTARCH)
GOOS="$1" GOARCH="$2" GOWORK=off GOTOOLCHAIN=local go build \
-o=.releasekit/bin/releasekit -mod readonly \
gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit
exec .releasekit/bin/releasekit publish \
--config="$root/releasekit.json" --repo "$root" "$version"
`, 0o755)
result := runLauncher(t, shell, fixture, []string{releaseVersion}, nil)
if result.status != 0 {
t.Fatalf("equivalent launcher failed: status=%d stderr=%q", result.status, result.stderr)
}
if err := checkPublication(readLines(t, fixture.publishLog), fixture.repoRoot); err != nil {
t.Fatal(err)
}
assertNativeBootstrap(t, fixture)
}
func TestLauncherChecksRejectContractViolations(t *testing.T) {
root := filepath.Join(t.TempDir(), "repository with spaces")
output := filepath.Join(root, ".releasekit", "bin", "releasekit")
@@ -136,13 +116,13 @@ func TestLauncherChecksRejectContractViolations(t *testing.T) {
})
}
for _, args := range [][]string{
{"check", "--repo", root, "--config", filepath.Join(root, "releasekit.json"), releaseVersion},
{"publish", "--repo", "wrong", "--config", filepath.Join(root, "releasekit.json"), releaseVersion},
{"publish", "--repo", root, "--config", "wrong", releaseVersion},
{"publish", "--repo", root, "--config", filepath.Join(root, "releasekit.json"), "wrong-version"},
{"publish", releaseVersion, "--repo", root, "--config", filepath.Join(root, "releasekit.json")},
{"check", "--repo", root, "--config", filepath.Join(root, "releasekit.json"), "--expected-module", ".", releaseVersion},
{"publish", "--repo", "wrong", "--config", filepath.Join(root, "releasekit.json"), "--expected-module", ".", releaseVersion},
{"publish", "--repo", root, "--config", "wrong", "--expected-module", ".", releaseVersion},
{"publish", "--repo", root, "--config", filepath.Join(root, "releasekit.json"), "--expected-module", ".", "wrong-version"},
{"publish", "--repo", root, "--config", filepath.Join(root, "releasekit.json"), releaseVersion, "--expected-module", "."},
} {
if err := checkPublication(args, root); err == nil {
if err := checkPublication(args, root, "core"); err == nil {
t.Errorf("invalid publication accepted: %q", args)
}
}
@@ -151,7 +131,7 @@ func TestLauncherChecksRejectContractViolations(t *testing.T) {
func TestReleaseLauncherStopsAfterBootstrapFailure(t *testing.T) {
shell := requirePOSIXShell(t)
fixture := newFixture(t)
result := runLauncher(t, shell, fixture, []string{releaseVersion}, map[string]string{
result := runLauncher(t, shell, fixture, []string{"core", releaseVersion}, map[string]string{
"FAKE_GO_BUILD_EXIT": "23",
})
@@ -173,13 +153,14 @@ type launcherResult struct {
}
type fixture struct {
repoRoot string
launcher string
outside string
fakeBin string
goLog string
publishLog string
publisher string
repoRoot string
launcher string
outside string
fakeBin string
goLog string
publishLog string
publishEnvLog string
publisher string
}
func newFixture(t *testing.T) fixture {
@@ -205,22 +186,34 @@ func newFixture(t *testing.T) fixture {
}
}
copyFile(t, filepath.Join(repo, "scripts", "release"), filepath.Join(repoRoot, "scripts", "release"), 0o755)
copyFile(t, filepath.Join(repo, "releasekit.json"), filepath.Join(repoRoot, "releasekit.json"), 0o644)
for _, profile := range []string{
"releasekit.json",
"integrations/ckconfig/releasekit.json",
"integrations/ckprompt/releasekit.json",
} {
target := filepath.Join(repoRoot, profile)
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
t.Fatal(err)
}
copyFile(t, filepath.Join(repo, profile), target, 0o644)
}
goLog := filepath.Join(root, "go calls.log")
publishLog := filepath.Join(root, "publisher arguments.log")
publishEnvLog := filepath.Join(root, "publisher environment.log")
publisher := filepath.Join(root, "fake publisher")
writeFile(t, publisher, fakePublisher, 0o644)
writeFile(t, filepath.Join(fakeBin, "go"), fakeGo, 0o755)
return fixture{
repoRoot: repoRoot,
launcher: filepath.Join(repoRoot, "scripts", "release"),
outside: outside,
fakeBin: fakeBin,
goLog: goLog,
publishLog: publishLog,
publisher: publisher,
repoRoot: repoRoot,
launcher: filepath.Join(repoRoot, "scripts", "release"),
outside: outside,
fakeBin: fakeBin,
goLog: goLog,
publishLog: publishLog,
publishEnvLog: publishEnvLog,
publisher: publisher,
}
}
@@ -255,6 +248,7 @@ func fixtureEnvironment(fixture fixture, overrides map[string]string) []string {
"PATH": fixture.fakeBin + string(os.PathListSeparator) + os.Getenv("PATH"),
"GO_LOG": fixture.goLog,
"PUBLISH_ARGS_LOG": fixture.publishLog,
"PUBLISH_ENV_LOG": fixture.publishEnvLog,
"FAKE_GOHOSTOS": "linux",
"FAKE_GOHOSTARCH": "amd64",
"FAKE_PUBLISHER_SOURCE": fixture.publisher,
@@ -335,22 +329,30 @@ func argumentValue(args []string, name string) string {
return value
}
func checkPublication(args []string, root string) error {
if len(args) == 0 || args[0] != "publish" {
return fmt.Errorf("incorrect publication command: %q", args)
func checkPublication(args []string, root, selector string) error {
modules := map[string]string{
"core": ".",
"ckconfig": "integrations/ckconfig",
"ckprompt": "integrations/ckprompt",
}
flags := flag.NewFlagSet("publish", flag.ContinueOnError)
flags.SetOutput(io.Discard)
repo := flags.String("repo", "", "")
config := flags.String("config", "", "")
if err := flags.Parse(args[1:]); err != nil {
return err
module, ok := modules[selector]
if !ok {
return fmt.Errorf("unknown module selector %q", selector)
}
if *repo != root || *config != filepath.Join(root, "releasekit.json") {
return fmt.Errorf("incorrect publication paths: repo=%q config=%q", *repo, *config)
profile := map[string]string{
"core": "releasekit.json",
"ckconfig": "integrations/ckconfig/releasekit.json",
"ckprompt": "integrations/ckprompt/releasekit.json",
}[selector]
want := []string{
"publish",
"--repo", root,
"--config", filepath.Join(root, profile),
"--expected-module", module,
releaseVersion,
}
if !equalStrings(flags.Args(), []string{releaseVersion}) {
return fmt.Errorf("incorrect publication operands: %q", flags.Args())
if !equalStrings(args, want) {
return fmt.Errorf("publication arguments = %q, want %q", args, want)
}
return nil
}
@@ -497,6 +499,7 @@ exit 92
const fakePublisher = `#!/bin/sh
set -eu
printf '%s\n' "$@" > "$PUBLISH_ARGS_LOG"
printf 'GOWORK=%s\nGOTOOLCHAIN=%s\n' "${GOWORK-}" "${GOTOOLCHAIN-}" > "$PUBLISH_ENV_LOG"
printf '%s\n' "$PUBLISH_STDOUT"
printf '%s\n' "$PUBLISH_STDERR" >&2
exit "$PUBLISH_EXIT"