Adopt ReleaseKit module publishing
This commit is contained in:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user