Run consumer release commands through Go tools

This commit is contained in:
2026-11-02 14:46:42 +00:00
parent 6fab30337a
commit 691926d839
9 changed files with 148 additions and 103 deletions

View File

@@ -2,11 +2,13 @@ package main
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"io/fs" "io/fs"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"testing" "testing"
) )
@@ -80,20 +82,13 @@ func TestMultiModuleLauncherUsesSelectedModuleAndProfile(t *testing.T) {
set -eu set -eu
printf 'cwd=%s args=%s\n' "$PWD" "$*" >> "$RELEASEKIT_TEST_GO_LOG" printf 'cwd=%s args=%s\n' "$PWD" "$*" >> "$RELEASEKIT_TEST_GO_LOG"
modfile= modfile=
output=
previous=
for argument in "$@"; do for argument in "$@"; do
case "$argument" in -modfile=*) modfile=${argument#-modfile=} ;; esac case "$argument" in -modfile=*) modfile=${argument#-modfile=} ;; esac
if [ "$previous" = -o ]; then output=$argument; fi
previous=$argument
done done
if [ -n "$modfile" ]; then cat "$modfile" >> "$RELEASEKIT_TEST_GO_LOG"; fi if [ -n "$modfile" ]; then cat "$modfile" >> "$RELEASEKIT_TEST_GO_LOG"; fi
if [ "$1" = build ]; then if [ "$1" = tool ]; then
cat > "$output" <<'TOOL' shift 3
#!/bin/sh printf '<%s>\n' "$@" > "$RELEASEKIT_TEST_TOOL_ARGS"
printf '<%s>\n' "$@" > "$RELEASEKIT_TEST_TOOL_ARGS"
TOOL
chmod +x "$output"
fi fi
` `
if err := os.WriteFile(filepath.Join(shimDir, "go"), []byte(shim), 0o700); err != nil { if err := os.WriteFile(filepath.Join(shimDir, "go"), []byte(shim), 0o700); err != nil {
@@ -134,7 +129,7 @@ fi
} }
} }
func TestMultiModuleLauncherBuildsToolFromSelectedDependency(t *testing.T) { func TestMultiModuleLauncherRunsToolFromSelectedDependency(t *testing.T) {
example := filepath.Join(cliRepositoryRoot(t), "examples", "multi-module") example := filepath.Join(cliRepositoryRoot(t), "examples", "multi-module")
repository := newCLIRepository(t) repository := newCLIRepository(t)
copyExampleTree(t, example, repository) copyExampleTree(t, example, repository)
@@ -161,27 +156,50 @@ func TestMultiModuleLauncherBuildsToolFromSelectedDependency(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
command := exec.Command(filepath.Join(repository, "release.sh"), "ckconfig", "v1.2.3") for _, status := range []int{0, 1, 2, 3} {
output, err := command.CombinedOutput() t.Run(strconv.Itoa(status), func(t *testing.T) {
if err != nil { command := exec.Command(filepath.Join(repository, "release.sh"), "ckconfig", "v1.2.3")
t.Fatalf("launcher error: %v output=%q", err, output) command.Env = setEnvironment(os.Environ(), "RELEASEKIT_TOOL_EXIT", strconv.Itoa(status))
} output, err := command.CombinedOutput()
for _, expected := range []string{ if status == 0 && err != nil {
"tool-version=v0.2.198 helper=tool-only dependency", t.Fatalf("launcher error: %v output=%q", err, output)
`"publish"`, `"--repo"`, `"` + repository + `"`, }
`"--config"`, `"releasekit-ckconfig.json"`, if status != 0 {
`"--expected-module"`, `"integrations/ckconfig"`, `"v1.2.3"`, var exitError *exec.ExitError
} { if !errors.As(err, &exitError) || exitError.ExitCode() != status {
if !strings.Contains(string(output), expected) { t.Fatalf("launcher error = %v, want exit %d; output=%q", err, status, output)
t.Errorf("launcher output %q omits %q", output, expected) }
} }
} for _, expected := range []string{
if strings.Contains(string(output), "tool-version=v0.2.197") { "tool-version=v0.2.198 helper=tool-only dependency",
t.Fatalf("launcher built the root-selected ReleaseKit version: %s", output) `"publish"`, `"--repo"`, `"` + repository + `"`,
} `"--config"`, `"releasekit-ckconfig.json"`,
moduleAfter, err := os.ReadFile(filepath.Join(repository, "integrations", "ckconfig", "go.mod")) `"--expected-module"`, `"integrations/ckconfig"`, `"v1.2.3"`,
if err != nil || !bytes.Equal(moduleAfter, moduleBefore) { } {
t.Fatalf("selected module go.mod changed: got %q want %q error=%v", moduleAfter, moduleBefore, err) if !strings.Contains(string(output), expected) {
t.Errorf("launcher output %q omits %q", output, expected)
}
}
if strings.Contains(string(output), "tool-version=v0.2.197") {
t.Fatalf("launcher ran the root-selected ReleaseKit version: %s", output)
}
moduleAfter, err := os.ReadFile(filepath.Join(repository, "integrations", "ckconfig", "go.mod"))
if err != nil || !bytes.Equal(moduleAfter, moduleBefore) {
t.Fatalf("selected module go.mod changed: got %q want %q error=%v", moduleAfter, moduleBefore, err)
}
if status := cliGitOutput(t, repository, "status", "--porcelain", "--untracked-files=all"); status != "" {
t.Fatalf("launcher changed source: %q", status)
}
entries, err := os.ReadDir(filepath.Dir(repository))
if err != nil {
t.Fatal(err)
}
for _, entry := range entries {
if strings.HasPrefix(entry.Name(), ".releasekit-bootstrap.") {
t.Fatalf("temporary bootstrap directory remains: %s", entry.Name())
}
}
})
} }
} }

View File

@@ -236,6 +236,26 @@ func TestWoodpeckerTagDeliveryUsesTaggedModuleVersion(t *testing.T) {
assertToolOnlyChecksums(t, sumLog) assertToolOnlyChecksums(t, sumLog)
}) })
t.Run("vendored tool dependency", func(t *testing.T) {
goDir, goLog := installGoBootstrapShim(t)
repository := newCLIRepository(t)
const module = "go.maximumdirect.net/releasekit"
writeRepositoryFile(t, repository, "go.mod", "module example.com/cli-candidate\n\ngo 1.25.0\n\nrequire "+module+" v0.2.197\n\ntool "+module+"/cmd/releasekit\n")
env := templateEnvironment(repository, "", goDir, goLog)
useSyntheticModuleProxy(t, env, "file://"+filepath.ToSlash(proxy))
runWoodpeckerBlock(t, "go mod tidy\ngo mod vendor", repository, env)
cliGitRun(t, repository, "add", "go.mod", "go.sum", "vendor")
cliGitRun(t, repository, "commit", "-m", "vendor the selected release tool")
env["CI_COMMIT_SHA"] = pushTaggedCLIRepository(t, repository)
moduleBefore := readWoodpeckerFixtureFile(t, filepath.Join(repository, "go.mod"))
sumBefore := readWoodpeckerFixtureFile(t, filepath.Join(repository, "go.sum"))
output := runWoodpeckerBlock(t, command, repository, env)
if !strings.Contains(output, "tool-version=v0.2.197 helper=tool-only dependency") {
t.Fatalf("vendored tool was not selected: %q", output)
}
assertModuleBootstrap(t, repository, goLog, moduleBefore, sumBefore)
})
t.Run("versioned replacement selects its declared source", func(t *testing.T) { t.Run("versioned replacement selects its declared source", func(t *testing.T) {
goDir, goLog := installGoBootstrapShim(t) goDir, goLog := installGoBootstrapShim(t)
repository := newCLIRepository(t) repository := newCLIRepository(t)
@@ -400,7 +420,7 @@ func installGoBootstrapShim(t *testing.T) (string, string) {
printf 'cwd=%s GOWORK=%s GOTOOLCHAIN=%s %s\n' "$PWD" "$GOWORK" "$GOTOOLCHAIN" "$*" >> "$RELEASEKIT_GO_LOG" printf 'cwd=%s GOWORK=%s GOTOOLCHAIN=%s %s\n' "$PWD" "$GOWORK" "$GOTOOLCHAIN" "$*" >> "$RELEASEKIT_GO_LOG"
"$RELEASEKIT_REAL_GO" "$@" "$RELEASEKIT_REAL_GO" "$@"
status=$? status=$?
if [ "$status" -eq 0 ] && [ "$1" = "build" ] && [ -n "${RELEASEKIT_SUM_LOG:-}" ]; then if [ "$status" -eq 0 ] && [ "$1" = "tool" ] && [ -n "${RELEASEKIT_SUM_LOG:-}" ]; then
modfile= modfile=
for argument in "$@"; do for argument in "$@"; do
case "$argument" in -modfile=*) modfile=${argument#-modfile=} ;; esac case "$argument" in -modfile=*) modfile=${argument#-modfile=} ;; esac
@@ -433,20 +453,12 @@ case "$1" in
list) list)
printf '%s v0.2.0\n' "$RELEASEKIT_MODULE" printf '%s v0.2.0\n' "$RELEASEKIT_MODULE"
;; ;;
build) mod)
output= ;;
previous= tool)
for argument in "$@"; do shift 3
if [ "$previous" = "-o" ]; then output=$argument; break; fi printf '<%s>\n' "$@" > "$RELEASEKIT_TOOL_ARGS_LOG"
previous=$argument exit "${RELEASEKIT_TOOL_EXIT:-0}"
done
[ -n "$output" ] || { echo 'go build omitted output path' >&2; exit 90; }
cat > "$output" <<'TOOL'
#!/bin/sh
printf '<%s>\n' "$@" > "$RELEASEKIT_TOOL_ARGS_LOG"
exit "${RELEASEKIT_TOOL_EXIT:-0}"
TOOL
chmod +x "$output"
;; ;;
*) *)
echo "unexpected Go command: $1" >&2 echo "unexpected Go command: $1" >&2
@@ -532,7 +544,7 @@ func writeReleaseKitModuleProxy(t *testing.T) string {
toolModule := "module " + module + "\n\ngo 1.25.0\n\nrequire " + toolDependency + " v1.0.0\n" toolModule := "module " + module + "\n\ngo 1.25.0\n\nrequire " + toolDependency + " v1.0.0\n"
for _, version := range []string{"v0.2.197", "v0.2.198"} { for _, version := range []string{"v0.2.197", "v0.2.198"} {
files := map[string]string{ files := map[string]string{
"cmd/releasekit/main.go": "package main\n\nimport (\"fmt\"; \"os\"; tooldep \"example.com/releasekit-helper\")\n\nfunc main() {\n\tfmt.Println(\"tool-version=" + version + " helper=\" + tooldep.Version)\n\tfmt.Printf(\"tool-args=%q\\n\", os.Args[1:])\n}\n", "cmd/releasekit/main.go": "package main\n\nimport (\"fmt\"; \"os\"; \"strconv\"; tooldep \"example.com/releasekit-helper\")\n\nfunc main() {\n\tfmt.Println(\"tool-version=" + version + " helper=\" + tooldep.Version)\n\tfmt.Printf(\"tool-args=%q\\n\", os.Args[1:])\n\tstatus, _ := strconv.Atoi(os.Getenv(\"RELEASEKIT_TOOL_EXIT\"))\n\tos.Exit(status)\n}\n",
} }
writeModuleProxyVersion(t, proxyDir, module, version, toolModule, files) writeModuleProxyVersion(t, proxyDir, module, version, toolModule, files)
} }
@@ -633,16 +645,16 @@ func assertGoSelection(t *testing.T, repository, goLog string) {
t.Helper() t.Helper()
log := readWoodpeckerFixtureFile(t, goLog) log := readWoodpeckerFixtureFile(t, goLog)
list := "list -mod=mod -modfile=" list := "list -mod=mod -modfile="
build := "build -mod=mod -modfile=" tool := "tool -modfile="
module := "go.maximumdirect.net/releasekit" module := "go.maximumdirect.net/releasekit"
if !strings.Contains(log, "GOWORK=off GOTOOLCHAIN=local") || !strings.Contains(log, list) || !strings.Contains(log, "-m "+module) { if !strings.Contains(log, "GOWORK=off GOTOOLCHAIN=local") || !strings.Contains(log, list) || !strings.Contains(log, "-m "+module) {
t.Fatalf("Go module selection command is missing required settings: %q", log) t.Fatalf("Go module selection command is missing required settings: %q", log)
} }
if !strings.Contains(log, build) || !strings.Contains(log, module+"/cmd/releasekit") || strings.Contains(log, "@v0.2.0") { if !strings.Contains(log, tool) || !strings.Contains(log, " releasekit ci-deliver ") || strings.Contains(log, "@v0.2.0") {
t.Fatalf("Go build did not use the selected module without a version suffix: %q", log) t.Fatalf("Go tool did not run the module-selected ReleaseKit: %q", log)
} }
if strings.Index(log, list) > strings.Index(log, build) { if strings.Index(log, list) > strings.Index(log, tool) {
t.Fatalf("Go build ran before module selection: %q", log) t.Fatalf("Go tool ran before module selection: %q", log)
} }
var modfile string var modfile string
for _, field := range strings.Fields(log) { for _, field := range strings.Fields(log) {

View File

@@ -275,9 +275,9 @@ status 2. Final delivery uses the same statuses as `deliver`: 0 for complete,
state, including when cancellation prevents reconciliation. state, including when cancellation prevents reconciliation.
The maintained module-based tag workflow verifies and checks out the event tag The maintained module-based tag workflow verifies and checks out the event tag
before resolving the consumer module. It builds the ReleaseKit version already before resolving the consumer module. It runs `go tool releasekit` for the version
selected by that tagged `go.mod`, using temporary alternate module files outside already selected by that tagged `go.mod`, using temporary alternate module files
the source checkout. This tool bootstrap is separate from `ci-deliver`'s outside the source checkout. This tool bootstrap is separate from `ci-deliver`'s
application dependency preparation for binary profiles. ReleaseKit's own application dependency preparation for binary profiles. ReleaseKit's own
source workflow self-bootstraps `./cmd/releasekit`; consumers without a declared source workflow self-bootstraps `./cmd/releasekit`; consumers without a declared
ReleaseKit module dependency can use the separately installed-tool command. ReleaseKit module dependency can use the separately installed-tool command.

View File

@@ -34,8 +34,21 @@ Go minimum. See the
[Go tool dependency reference](https://go.dev/ref/mod#go-mod-file-tool). [Go tool dependency reference](https://go.dev/ref/mod#go-mod-file-tool).
Run `go tool releasekit` from within the consumer module to use its selected Run `go tool releasekit` from within the consumer module to use its selected
version. Follow the [CLI contract](../cli.md) for commands and exit statuses, version. Go builds and caches the executable and preserves its exit status.
and the [configuration reference](../config.md) for the release profile. A launcher invoked from that module can forward commands directly:
```sh
#!/bin/sh
exec go tool releasekit "$@"
```
For a launcher callable from other directories, first change to its consumer
module directory. Follow the [CLI contract](../cli.md) for commands and exit
statuses, and the [configuration reference](../config.md) for the release profile.
For consumers using vendoring, register the CLI before running `go mod vendor`
so the vendor tree includes its dependencies. `go tool` follows Go's normal
vendor selection.
## Go API consumers ## Go API consumers
@@ -89,9 +102,10 @@ Go module identity. The Go consumer minimum remains 1.26.0.
## CI adoption ## CI adoption
The maintained [consumer tag-delivery workflow](delivery.md#woodpecker-tag-workflows) The maintained [consumer tag-delivery workflow](delivery.md#woodpecker-tag-workflows)
supports both tool and ordinary package dependencies. It builds ReleaseKit from supports both tool and ordinary package dependencies. It runs `go tool releasekit`
the tagged consumer's module selection, so the committed module files also with temporary module metadata derived from the tagged consumer's module
govern CI delivery and retries. Registering the CLI as a tool is sufficient for selection, so the committed module files also govern CI delivery and retries.
Registering the CLI as a tool is sufficient for
consumers that use ReleaseKit only for maintainer commands. consumers that use ReleaseKit only for maintainer commands.
Upgrade the module-selected tool and workflow together. For a tag created before Upgrade the module-selected tool and workflow together. For a tag created before

View File

@@ -293,11 +293,13 @@ identify an annotated tag object or a commit. The template requires the resolved
commits to match, checks out that commit detached, and confirms the source tree commits to match, checks out that commit detached, and confirms the source tree
is clean. It then copies the tagged `go.mod` and any `go.sum` to a temporary is clean. It then copies the tagged `go.mod` and any `go.sum` to a temporary
directory outside the checkout. `go list -m` confirms that the module selects directory outside the checkout. `go list -m` confirms that the module selects
ReleaseKit; Go uses ReleaseKit. The template adds its CLI tool declaration to that temporary copy
an alternate `-modfile` to prepare dependencies and build the selected and prepares tool dependencies with `go list -deps`. It then uses
`cmd/releasekit` package without changing the tagged module files. The template `go tool -modfile=... releasekit` to build, cache, and run the selected tool with
invokes that executable with `CI_WORKSPACE`, the resolved event commit, and `CI_WORKSPACE`, the resolved event commit, and `CI_COMMIT_TAG`. The tagged module
`CI_COMMIT_TAG`. A cleanup trap removes the temporary metadata and executable. files stay unchanged, including for consumers with an ordinary package
dependency. A cleanup trap removes the temporary metadata; Go manages the
cached executable. The command preserves the tool's exit status.
Tool bootstrap and application artifact preparation are separate. The bootstrap Tool bootstrap and application artifact preparation are separate. The bootstrap
resolves and builds ReleaseKit from the tagged consumer's module configuration. resolves and builds ReleaseKit from the tagged consumer's module configuration.

View File

@@ -72,11 +72,14 @@ Then select a module and semantic version with the shared launcher:
The launcher copies the selected module's `go.mod` and `go.sum` to temporary The launcher copies the selected module's `go.mod` and `go.sum` to temporary
alternate module files outside the checkout, resolves ReleaseKit from that alternate module files outside the checkout, resolves ReleaseKit from that
module's local dependency selection, and builds the tool there. It invokes module's local dependency selection, adds the CLI tool declaration to that
`publish` with the repository profile and `--expected-module` so the library temporary copy, and prepares its dependencies. It uses `go tool releasekit`
can verify that the profile agrees with the selected table row. The temporary with the alternate module file to invoke `publish` with the repository profile
files and tool are removed on exit. As with any `publish` invocation, commit the and `--expected-module` so the library can verify that the profile agrees with
selected module's release note and prepare its repository before publishing. the selected table row. Go builds and caches the executable and preserves its
exit status; the launcher removes the temporary metadata on exit. As with any
`publish` invocation, commit the selected module's release note and prepare its
repository before publishing.
If an integration depends on a sibling release, publish the dependency first, If an integration depends on a sibling release, publish the dependency first,
then publish the integration with the version that consumes it. For example, then publish the integration with the version that consumes it. For example,
@@ -86,8 +89,9 @@ This declaration does not infer dependency order or rerun the standard suite.
The maintained [Woodpecker example](woodpecker.yml) uses the same map and The maintained [Woodpecker example](woodpecker.yml) uses the same map and
selector for root, `ckconfig`, and major-version tags. It verifies and detaches selector for root, `ckconfig`, and major-version tags. It verifies and detaches
the literal event tag before selecting the module, copies that module's metadata the literal event tag before selecting the module, copies that module's metadata
outside the checkout, and builds the ReleaseKit version selected there. It then outside the checkout, and runs the ReleaseKit version selected there through
uses `ci-deliver --prepared` with the mapped profile and expected physical module. `go tool releasekit`. It then uses `ci-deliver --prepared` with the mapped profile
and expected physical module.
The `core-v2` profile demonstrates binary delivery; the other profiles are The `core-v2` profile demonstrates binary delivery; the other profiles are
page-only. Before enabling the workflow, configure each selected profile's page-only. Before enabling the workflow, configure each selected profile's
`delivery` object with `"forge": "gitea"`, its `base_url`, owner, and repository, `delivery` object with `"forge": "gitea"`, its `base_url`, owner, and repository,

View File

@@ -37,12 +37,11 @@ releasekit_module=go.maximumdirect.net/releasekit
export GOWORK=off export GOWORK=off
export GOTOOLCHAIN=local export GOTOOLCHAIN=local
go list -mod=mod -modfile="$bootstrap_dir/releasekit.mod" -m "$releasekit_module" go list -mod=mod -modfile="$bootstrap_dir/releasekit.mod" -m "$releasekit_module"
go build -mod=mod -modfile="$bootstrap_dir/releasekit.mod" \ go mod edit -modfile="$bootstrap_dir/releasekit.mod" -tool="$releasekit_module/cmd/releasekit"
-o "$bootstrap_dir/releasekit" "$releasekit_module/cmd/releasekit" go list -mod=mod -modfile="$bootstrap_dir/releasekit.mod" -deps "$releasekit_module/cmd/releasekit" > /dev/null
go tool -modfile="$bootstrap_dir/releasekit.mod" releasekit publish \
--repo "$repository_dir" \
--config "$profile_path" \
--expected-module "$module_dir" \
"$version"
) )
"$bootstrap_dir/releasekit" publish \
--repo "$repository_dir" \
--config "$profile_path" \
--expected-module "$module_dir" \
"$version"

View File

@@ -40,14 +40,12 @@ steps:
if [ "$${module_dir}" != . ]; then if [ "$${module_dir}" != . ]; then
module_path="$${CI_WORKSPACE}/$${module_dir}" module_path="$${CI_WORKSPACE}/$${module_dir}"
fi fi
cp "$${module_path}/go.mod" "$${bootstrap_dir}/go.mod" cp "$${module_path}/go.mod" "$${bootstrap_dir}/releasekit.mod"
if [ -f "$${module_path}/go.sum" ]; then if [ -f "$${module_path}/go.sum" ]; then
cp "$${module_path}/go.sum" "$${bootstrap_dir}/go.sum" cp "$${module_path}/go.sum" "$${bootstrap_dir}/releasekit.sum"
else else
: > "$${bootstrap_dir}/go.sum" : > "$${bootstrap_dir}/releasekit.sum"
fi fi
cp "$${bootstrap_dir}/go.mod" "$${bootstrap_dir}/releasekit.mod"
cp "$${bootstrap_dir}/go.sum" "$${bootstrap_dir}/releasekit.sum"
export GOWORK=off export GOWORK=off
export GOTOOLCHAIN=local export GOTOOLCHAIN=local
@@ -55,13 +53,13 @@ steps:
( (
cd "$${module_path}" cd "$${module_path}"
go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -m "$${releasekit_module}" go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -m "$${releasekit_module}"
go build -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" \ go mod edit -modfile="$${bootstrap_dir}/releasekit.mod" -tool="$${releasekit_module}/cmd/releasekit"
-o "$${bootstrap_dir}/releasekit" "$${releasekit_module}/cmd/releasekit" go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -deps "$${releasekit_module}/cmd/releasekit" > /dev/null
go tool -modfile="$${bootstrap_dir}/releasekit.mod" releasekit ci-deliver \
--repo "$${CI_WORKSPACE}" \
--config "$${profile_path}" \
--expected-module "$${module_dir}" \
--prepared \
--commit "$${expected_commit}" \
"$${CI_COMMIT_TAG}"
) )
"$${bootstrap_dir}/releasekit" ci-deliver \
--repo "$${CI_WORKSPACE}" \
--config "$${profile_path}" \
--expected-module "$${module_dir}" \
--prepared \
--commit "$${expected_commit}" \
"$${CI_COMMIT_TAG}"

View File

@@ -32,22 +32,20 @@ steps:
bootstrap_dir=$(mktemp -d "$${CI_WORKSPACE%/*}/.releasekit-bootstrap.XXXXXX") bootstrap_dir=$(mktemp -d "$${CI_WORKSPACE%/*}/.releasekit-bootstrap.XXXXXX")
trap 'rm -rf "$${bootstrap_dir}"' EXIT trap 'rm -rf "$${bootstrap_dir}"' EXIT
cp go.mod "$${bootstrap_dir}/go.mod" cp go.mod "$${bootstrap_dir}/releasekit.mod"
if [ -f go.sum ]; then if [ -f go.sum ]; then
cp go.sum "$${bootstrap_dir}/go.sum" cp go.sum "$${bootstrap_dir}/releasekit.sum"
else else
: > "$${bootstrap_dir}/go.sum" : > "$${bootstrap_dir}/releasekit.sum"
fi fi
cp "$${bootstrap_dir}/go.mod" "$${bootstrap_dir}/releasekit.mod"
cp "$${bootstrap_dir}/go.sum" "$${bootstrap_dir}/releasekit.sum"
export GOWORK=off export GOWORK=off
export GOTOOLCHAIN=local export GOTOOLCHAIN=local
releasekit_module=go.maximumdirect.net/releasekit releasekit_module=go.maximumdirect.net/releasekit
go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -m "$${releasekit_module}" go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -m "$${releasekit_module}"
go build -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" \ go mod edit -modfile="$${bootstrap_dir}/releasekit.mod" -tool="$${releasekit_module}/cmd/releasekit"
-o "$${bootstrap_dir}/releasekit" "$${releasekit_module}/cmd/releasekit" go list -mod=mod -modfile="$${bootstrap_dir}/releasekit.mod" -deps "$${releasekit_module}/cmd/releasekit" > /dev/null
"$${bootstrap_dir}/releasekit" ci-deliver \ go tool -modfile="$${bootstrap_dir}/releasekit.mod" releasekit ci-deliver \
--repo "$${CI_WORKSPACE}" \ --repo "$${CI_WORKSPACE}" \
--prepared \ --prepared \
--commit "$${expected_commit}" \ --commit "$${expected_commit}" \