Consolidate Woodpecker delivery templates
This commit is contained in:
@@ -78,22 +78,30 @@ func TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout(t *testing.T) {
|
|||||||
cliGitRun(t, repository, "remote", "set-url", "origin", remote)
|
cliGitRun(t, repository, "remote", "set-url", "origin", remote)
|
||||||
cliGitRun(t, repository, "push", "origin", "HEAD:refs/heads/main", "refs/tags/"+version)
|
cliGitRun(t, repository, "push", "origin", "HEAD:refs/heads/main", "refs/tags/"+version)
|
||||||
|
|
||||||
// Match the maintained workflow: fetch and bind the tag, then build the
|
|
||||||
// executable from that detached tagged checkout before page-only delivery.
|
|
||||||
cliGitRun(t, repository, "fetch", "origin", "refs/tags/"+version+":refs/tags/"+version)
|
|
||||||
if got := cliGitOutput(t, repository, "rev-parse", "refs/tags/"+version+"^{commit}"); got != state.commit {
|
|
||||||
t.Fatalf("fetched tag commit = %s, want %s", got, state.commit)
|
|
||||||
}
|
|
||||||
cliGitRun(t, repository, "checkout", "--detach", state.commit)
|
|
||||||
tool := filepath.Join(repository, ".releasekit", "bin", "releasekit")
|
tool := filepath.Join(repository, ".releasekit", "bin", "releasekit")
|
||||||
if err := os.MkdirAll(filepath.Dir(tool), 0o700); err != nil {
|
template, err := os.ReadFile(filepath.Join(root, "examples", "woodpecker", "releasekit-source-delivery.yml"))
|
||||||
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
build := exec.Command("go", "build", "-o", tool, "./cmd/releasekit")
|
buildBlock, err := extractWoodpeckerCommand(string(template), "build-tool")
|
||||||
build.Dir = repository
|
if err != nil {
|
||||||
build.Env = append(os.Environ(), "GOTOOLCHAIN=local", "GOPROXY=off", "GOSUMDB=off")
|
t.Fatal(err)
|
||||||
if output, err := build.CombinedOutput(); err != nil {
|
}
|
||||||
t.Fatalf("build CLI from tagged checkout: %v\n%s", err, output)
|
deliveryBlock, err := extractWoodpeckerCommand(string(template), "deliver-page")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
env := map[string]string{
|
||||||
|
"CI_WORKSPACE": repository,
|
||||||
|
"CI_COMMIT_SHA": state.commit,
|
||||||
|
"CI_COMMIT_TAG": version,
|
||||||
|
"RELEASEKIT_GITEA_TOKEN": "fixture-token",
|
||||||
|
"GOPROXY": "off",
|
||||||
|
"GOSUMDB": "off",
|
||||||
|
}
|
||||||
|
runWoodpeckerBlock(t, strings.ReplaceAll(buildBlock, "$${", "${"), repository, env)
|
||||||
|
if got := cliGitOutput(t, repository, "rev-parse", "HEAD"); got != state.commit {
|
||||||
|
t.Fatalf("template checkout = %s, want %s", got, state.commit)
|
||||||
}
|
}
|
||||||
|
|
||||||
state.remoteCommit = strings.Repeat("f", 40)
|
state.remoteCommit = strings.Repeat("f", 40)
|
||||||
@@ -109,7 +117,7 @@ func TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout(t *testing.T) {
|
|||||||
state.remoteCommit = ""
|
state.remoteCommit = ""
|
||||||
|
|
||||||
for attempt := 0; attempt < 2; attempt++ {
|
for attempt := 0; attempt < 2; attempt++ {
|
||||||
output := runWoodpeckerCommand(t, tool, repository, true, "deliver", "--repo", repository, version)
|
output := runWoodpeckerBlock(t, strings.ReplaceAll(deliveryBlock, "$${", "${"), repository, env)
|
||||||
if !strings.Contains(output, "state complete") {
|
if !strings.Contains(output, "state complete") {
|
||||||
t.Fatalf("delivery attempt %d output = %q", attempt+1, output)
|
t.Fatalf("delivery attempt %d output = %q", attempt+1, output)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"fmt"
|
||||||
"context"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -13,12 +12,24 @@ import (
|
|||||||
"gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit/internal/cli"
|
"gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit/internal/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWoodpeckerDeliveryCommandSequences(t *testing.T) {
|
func TestWoodpeckerTagDeliveryTemplate(t *testing.T) {
|
||||||
_, sourceFile, _, ok := runtime.Caller(0)
|
root := cliRepositoryRoot(t)
|
||||||
if !ok {
|
templatePath := filepath.Join(root, "examples", "woodpecker", "tag-delivery.yml")
|
||||||
t.Fatal("locate integration test source")
|
contents, err := os.ReadFile(templatePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
root := filepath.Clean(filepath.Join(filepath.Dir(sourceFile), "../.."))
|
pin, err := woodpeckerMatrixValue(string(contents), "RELEASEKIT_VERSION")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block, err := extractWoodpeckerCommand(string(contents), "deliver")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
command := strings.ReplaceAll(block, "${RELEASEKIT_VERSION}", pin)
|
||||||
|
command = strings.ReplaceAll(command, "$${", "${")
|
||||||
|
|
||||||
executable := filepath.Join(t.TempDir(), "releasekit")
|
executable := filepath.Join(t.TempDir(), "releasekit")
|
||||||
build := exec.Command("go", "build", "-o", executable, "./cmd/releasekit")
|
build := exec.Command("go", "build", "-o", executable, "./cmd/releasekit")
|
||||||
build.Dir = root
|
build.Dir = root
|
||||||
@@ -26,8 +37,12 @@ func TestWoodpeckerDeliveryCommandSequences(t *testing.T) {
|
|||||||
t.Fatalf("build local ReleaseKit executable: %v\n%s", err, output)
|
t.Fatalf("build local ReleaseKit executable: %v\n%s", err, output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module := "gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@" + pin
|
||||||
t.Run("source-only", func(t *testing.T) {
|
t.Run("source-only", func(t *testing.T) {
|
||||||
repository := newCLIRepository(t)
|
repository := newCLIRepository(t)
|
||||||
|
writeRepositoryFile(t, repository, "go.mod", "module example.com/cli-candidate\n\ngo 1.25.0\n\nrequire example.com/unavailable/module v1.2.3\n")
|
||||||
|
cliGitRun(t, repository, "add", "go.mod")
|
||||||
|
cliGitRun(t, repository, "commit", "-m", "declare unavailable dependency")
|
||||||
state := &deliveryServerState{}
|
state := &deliveryServerState{}
|
||||||
server := newDeliveryServer(t, state)
|
server := newDeliveryServer(t, state)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
@@ -35,13 +50,22 @@ func TestWoodpeckerDeliveryCommandSequences(t *testing.T) {
|
|||||||
Product: "Example Product",
|
Product: "Example Product",
|
||||||
Delivery: &cli.DeliverySettings{BaseURL: server.URL, Owner: "owner", Repository: "example"},
|
Delivery: &cli.DeliverySettings{BaseURL: server.URL, Owner: "owner", Repository: "example"},
|
||||||
})
|
})
|
||||||
state.commit = cliGitOutput(t, repository, "rev-parse", "HEAD")
|
commit := pushTaggedCLIRepository(t, repository)
|
||||||
cliGitRun(t, repository, "tag", "v1.2.3")
|
state.commit = commit
|
||||||
cliGitRun(t, repository, "checkout", "--detach", "v1.2.3")
|
|
||||||
|
|
||||||
output := runWoodpeckerCommand(t, executable, repository, true, "deliver", "--repo", repository, "v1.2.3")
|
shimDir, goLog := installGoBootstrapShim(t)
|
||||||
if !strings.Contains(output, "state complete") || state.releaseCreates != 1 || state.assetUploads != 0 {
|
env := templateEnvironment(repository, commit, executable, module, shimDir, goLog)
|
||||||
t.Fatalf("source-only workflow output=%q creates=%d uploads=%d", output, state.releaseCreates, state.assetUploads)
|
for attempt := 0; attempt < 2; attempt++ {
|
||||||
|
output := runWoodpeckerBlock(t, command, repository, env)
|
||||||
|
if !strings.Contains(output, "state complete") {
|
||||||
|
t.Fatalf("delivery attempt %d output=%q", attempt+1, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if state.releaseCreates != 1 || state.assetUploads != 0 {
|
||||||
|
t.Fatalf("source-only calls = creates:%d uploads:%d", state.releaseCreates, state.assetUploads)
|
||||||
|
}
|
||||||
|
if log, err := os.ReadFile(goLog); err != nil || strings.Contains(string(log), "mod download") {
|
||||||
|
t.Fatalf("source-only command downloaded application dependencies: log=%q error=%v", log, err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -51,56 +75,163 @@ func TestWoodpeckerDeliveryCommandSequences(t *testing.T) {
|
|||||||
server := newDeliveryServer(t, state)
|
server := newDeliveryServer(t, state)
|
||||||
defer server.Close()
|
defer server.Close()
|
||||||
writeDeliveryProfile(t, repository, cli.Settings{
|
writeDeliveryProfile(t, repository, cli.Settings{
|
||||||
Product: "Example Product",
|
Product: "Example Product",
|
||||||
Build: &cli.BuildSettings{MainPackage: ".", BinaryName: "helper", Targets: []string{"linux/amd64"}},
|
Build: &cli.BuildSettings{
|
||||||
|
MainPackage: ".",
|
||||||
|
BinaryName: "helper",
|
||||||
|
Targets: []string{fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)},
|
||||||
|
},
|
||||||
Delivery: &cli.DeliverySettings{BaseURL: server.URL, Owner: "owner", Repository: "example"},
|
Delivery: &cli.DeliverySettings{BaseURL: server.URL, Owner: "owner", Repository: "example"},
|
||||||
})
|
})
|
||||||
state.commit = cliGitOutput(t, repository, "rev-parse", "HEAD")
|
commit := pushTaggedCLIRepository(t, repository)
|
||||||
cliGitRun(t, repository, "tag", "v1.2.3")
|
state.commit = commit
|
||||||
cliGitRun(t, repository, "checkout", "--detach", "v1.2.3")
|
|
||||||
exclude, err := os.OpenFile(filepath.Join(repository, ".git", "info", "exclude"), os.O_APPEND|os.O_WRONLY, 0)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if _, err := exclude.WriteString("\n/.releasekit/\n"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if err := exclude.Close(); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
assets := filepath.Join(repository, ".releasekit", "assets")
|
|
||||||
if err := os.MkdirAll(filepath.Dir(assets), 0o700); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This follows the binary template's build then delivery commands, with
|
shimDir, goLog := installGoBootstrapShim(t)
|
||||||
// the executable built above replacing its pinned go install step.
|
env := templateEnvironment(repository, commit, executable, module, shimDir, goLog)
|
||||||
runWoodpeckerCommand(t, executable, repository, false, "build", "--repo", repository, "--output", assets, "v1.2.3")
|
for attempt := 0; attempt < 2; attempt++ {
|
||||||
output := runWoodpeckerCommand(t, executable, repository, true, "deliver", "--repo", repository, "--assets", assets, "v1.2.3")
|
output := runWoodpeckerBlock(t, command, repository, env)
|
||||||
if !strings.Contains(output, "state complete") || state.releaseCreates != 1 || state.assetUploads != 2 {
|
if !strings.Contains(output, "state complete") {
|
||||||
t.Fatalf("binary workflow output=%q creates=%d uploads=%d", output, state.releaseCreates, state.assetUploads)
|
t.Fatalf("delivery attempt %d output=%q", attempt+1, output)
|
||||||
|
}
|
||||||
|
if attempt == 1 && !strings.Contains(output, "matching SHA256SUMS") {
|
||||||
|
t.Fatalf("second delivery did not reuse matching assets: %q", output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if _, ok := state.assets["helper-v1.2.3-linux-amd64"]; !ok {
|
if state.releaseCreates != 1 || state.assetUploads != 2 {
|
||||||
|
t.Fatalf("binary calls = creates:%d uploads:%d", state.releaseCreates, state.assetUploads)
|
||||||
|
}
|
||||||
|
if _, ok := state.assets["helper-v1.2.3-"+runtime.GOOS+"-"+runtime.GOARCH]; !ok {
|
||||||
t.Fatalf("binary asset was not delivered: %#v", state.assets)
|
t.Fatalf("binary asset was not delivered: %#v", state.assets)
|
||||||
}
|
}
|
||||||
if _, ok := state.assets["SHA256SUMS"]; !ok {
|
if _, ok := state.assets["SHA256SUMS"]; !ok {
|
||||||
t.Fatalf("checksum manifest was not delivered: %#v", state.assets)
|
t.Fatalf("checksum manifest was not delivered: %#v", state.assets)
|
||||||
}
|
}
|
||||||
|
if log, err := os.ReadFile(goLog); err != nil || !strings.Contains(string(log), "mod download") {
|
||||||
|
t.Fatalf("binary command did not prepare application dependencies: log=%q error=%v", log, err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWoodpeckerCommand(t *testing.T, executable, repository string, credential bool, args ...string) string {
|
func cliRepositoryRoot(t *testing.T) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
command := exec.CommandContext(context.Background(), executable, args...)
|
_, sourceFile, _, ok := runtime.Caller(0)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("locate integration test source")
|
||||||
|
}
|
||||||
|
return filepath.Clean(filepath.Join(filepath.Dir(sourceFile), "../.."))
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractWoodpeckerCommand(contents, stepName string) (string, error) {
|
||||||
|
lines := strings.Split(contents, "\n")
|
||||||
|
stepHeader := " - name: " + stepName
|
||||||
|
for i, line := range lines {
|
||||||
|
if strings.TrimSpace(line) != strings.TrimSpace(stepHeader) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j := i + 1; j < len(lines); j++ {
|
||||||
|
trimmed := strings.TrimSpace(lines[j])
|
||||||
|
if strings.HasPrefix(lines[j], " - name:") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if trimmed != "- |" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var block []string
|
||||||
|
for k := j + 1; k < len(lines); k++ {
|
||||||
|
current := lines[k]
|
||||||
|
if strings.TrimSpace(current) == "" {
|
||||||
|
block = append(block, "")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
indent := len(current) - len(strings.TrimLeft(current, " "))
|
||||||
|
if indent < 8 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
block = append(block, current[8:])
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(strings.Join(block, "\n")), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("step %q has no literal command block", stepName)
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("step %q was not found", stepName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func woodpeckerMatrixValue(contents, key string) (string, error) {
|
||||||
|
for _, line := range strings.Split(contents, "\n") {
|
||||||
|
field, value, ok := strings.Cut(strings.TrimSpace(line), ":")
|
||||||
|
if ok && field == key {
|
||||||
|
return strings.TrimSpace(value), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("matrix value %q was not found", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func installGoBootstrapShim(t *testing.T) (string, string) {
|
||||||
|
t.Helper()
|
||||||
|
shimDir := t.TempDir()
|
||||||
|
goLog := filepath.Join(shimDir, "go-commands")
|
||||||
|
shim := `#!/bin/sh
|
||||||
|
if [ "$1" = "run" ]; then
|
||||||
|
shift
|
||||||
|
[ "$1" = "$RELEASEKIT_EXPECTED_MODULE" ] || { echo "unexpected module: $1" >&2; exit 90; }
|
||||||
|
shift
|
||||||
|
[ "$1" = "ci-deliver" ] || { echo "unexpected command: $1" >&2; exit 91; }
|
||||||
|
[ "$2" = "--repo" ] && [ "$3" = "$CI_WORKSPACE" ] || { echo "unexpected repository arguments" >&2; exit 92; }
|
||||||
|
[ "$4" = "--commit" ] && [ "$5" = "$CI_COMMIT_SHA" ] || { echo "unexpected commit arguments" >&2; exit 93; }
|
||||||
|
[ "$6" = "$CI_COMMIT_TAG" ] && [ "$#" = 6 ] || { echo "unexpected version argument" >&2; exit 94; }
|
||||||
|
printf '%s\n' "run $RELEASEKIT_EXPECTED_MODULE" >> "$RELEASEKIT_GO_LOG"
|
||||||
|
exec "$RELEASEKIT_LOCAL_EXECUTABLE" "$@"
|
||||||
|
fi
|
||||||
|
printf '%s\n' "$*" >> "$RELEASEKIT_GO_LOG"
|
||||||
|
exec "$RELEASEKIT_REAL_GO" "$@"
|
||||||
|
`
|
||||||
|
if err := os.WriteFile(filepath.Join(shimDir, "go"), []byte(shim), 0o700); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return shimDir, goLog
|
||||||
|
}
|
||||||
|
|
||||||
|
func templateEnvironment(repository, commit, executable, module, shimDir, goLog string) map[string]string {
|
||||||
|
realGo, _ := exec.LookPath("go")
|
||||||
|
return map[string]string{
|
||||||
|
"CI_WORKSPACE": repository,
|
||||||
|
"CI_COMMIT_SHA": commit,
|
||||||
|
"CI_COMMIT_TAG": "v1.2.3",
|
||||||
|
"RELEASEKIT_GITEA_TOKEN": "fixture-token",
|
||||||
|
"RELEASEKIT_EXPECTED_MODULE": module,
|
||||||
|
"RELEASEKIT_LOCAL_EXECUTABLE": executable,
|
||||||
|
"RELEASEKIT_REAL_GO": realGo,
|
||||||
|
"RELEASEKIT_GO_LOG": goLog,
|
||||||
|
"GOTOOLCHAIN": "local",
|
||||||
|
"GOPROXY": "off",
|
||||||
|
"GOSUMDB": "off",
|
||||||
|
"GOFLAGS": "",
|
||||||
|
"PATH": shimDir + string(os.PathListSeparator) + os.Getenv("PATH"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runWoodpeckerBlock(t *testing.T, block, repository string, environment map[string]string) string {
|
||||||
|
t.Helper()
|
||||||
|
command := exec.Command("sh", "-e", "-c", block)
|
||||||
command.Dir = repository
|
command.Dir = repository
|
||||||
command.Env = os.Environ()
|
command.Env = os.Environ()
|
||||||
if credential {
|
for key, value := range environment {
|
||||||
command.Env = append(command.Env, "RELEASEKIT_GITEA_TOKEN=fixture-token")
|
command.Env = setEnvironment(command.Env, key, value)
|
||||||
}
|
}
|
||||||
var stdout, stderr bytes.Buffer
|
output, err := command.CombinedOutput()
|
||||||
command.Stdout, command.Stderr = &stdout, &stderr
|
if err != nil {
|
||||||
if err := command.Run(); err != nil {
|
t.Fatalf("Woodpecker command failed: %v\ncommand: %s\noutput: %s", err, block, output)
|
||||||
t.Fatalf("ReleaseKit %v failed: %v\nstdout: %s\nstderr: %s", args, err, stdout.String(), stderr.String())
|
|
||||||
}
|
}
|
||||||
return stdout.String()
|
return string(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setEnvironment(environment []string, key, value string) []string {
|
||||||
|
prefix := key + "="
|
||||||
|
for i, entry := range environment {
|
||||||
|
if strings.HasPrefix(entry, prefix) {
|
||||||
|
environment[i] = prefix + value
|
||||||
|
return environment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append(environment, prefix+value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,31 +148,41 @@ exit codes, and transport behavior.
|
|||||||
|
|
||||||
## Woodpecker tag workflows
|
## Woodpecker tag workflows
|
||||||
|
|
||||||
Maintained workflow examples are available for source-only and binary delivery:
|
Use the maintained [tag-delivery workflow](../../examples/woodpecker/tag-delivery.yml)
|
||||||
|
in the consumer repository's `.woodpecker/` directory. Set `GO_IMAGE` to an
|
||||||
|
image with Go 1.25 or newer, Git, and a Go version compatible with the consumer
|
||||||
|
module. Replace `RELEASEKIT_VERSION` with an immutable ReleaseKit revision or
|
||||||
|
published version. The example deliberately leaves this deployment pin as a
|
||||||
|
placeholder. Configure the Woodpecker repository secret
|
||||||
|
`releasekit_gitea_token`; the template maps it to `RELEASEKIT_GITEA_TOKEN` only
|
||||||
|
for the delivery step. The repository needs a `delivery` profile. Page-only and
|
||||||
|
binary behavior both use this template; the profile's build target list selects
|
||||||
|
whether binaries are built and delivered.
|
||||||
|
|
||||||
- [Source-only tag workflow](../../examples/woodpecker/tag-delivery-source-only.yml)
|
The command runs versioned source directly with `go run`, passing
|
||||||
- [Binary tag workflow](../../examples/woodpecker/tag-delivery-binary.yml)
|
`CI_WORKSPACE`, `CI_COMMIT_SHA`, and `CI_COMMIT_TAG` as command arguments.
|
||||||
|
`ci-deliver` fetches and verifies the event tag against its commit before
|
||||||
|
checking out the commit detached. It then loads the profile from that source,
|
||||||
|
validates the destination and token, and downloads application dependencies
|
||||||
|
only for profiles with build targets. The facade builds and delivers those
|
||||||
|
targets with the note page. Source-only profiles skip dependency downloads and
|
||||||
|
binary work. The workflow does not repeat checkout guards or maintain a
|
||||||
|
separate build/receipt/delivery sequence.
|
||||||
|
|
||||||
Copy one into the consumer repository's `.woodpecker/` directory. In its
|
The normal Go module and build caches are sufficient. Cache mounts may be added
|
||||||
matrix entry, set `GO_IMAGE` to a Go image compatible with the consumer module
|
as deployment configuration when they help the runner; they are not needed by
|
||||||
and replace `RELEASEKIT_SOURCE` with an immutable ReleaseKit commit. The
|
the template. A locally retained executable can be installed with
|
||||||
examples deliberately contain no claimed published ReleaseKit pin. Configure
|
`go install gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@PIN`, then run
|
||||||
the Woodpecker repository secret `releasekit_gitea_token`; the workflow maps it
|
with the same arguments:
|
||||||
to `RELEASEKIT_GITEA_TOKEN` only for the delivery step. The repository also
|
|
||||||
needs a `delivery` profile using the default `RELEASEKIT_GITEA_TOKEN` variable.
|
|
||||||
The binary profile must declare its build targets.
|
|
||||||
|
|
||||||
The tag workflow fetches the event tag, verifies that the tag resolves to
|
```sh
|
||||||
`CI_COMMIT_SHA`, and checks out that commit detached. Woodpecker shares the
|
releasekit ci-deliver --repo "$CI_WORKSPACE" --commit "$CI_COMMIT_SHA" "$CI_COMMIT_TAG"
|
||||||
repository workspace between sequential steps, so the installed executable
|
```
|
||||||
and Go caches remain available. The workflow keeps its `.releasekit/` directory
|
|
||||||
out of Git status using the checkout's local exclude file.
|
|
||||||
|
|
||||||
Preparation can access the Go module proxy to install the pinned ReleaseKit
|
Upgrade by changing the selected immutable
|
||||||
executable. The binary workflow also runs `go mod download` before delivery.
|
`RELEASEKIT_VERSION` (or the `@PIN` used by `go install`) and validating the
|
||||||
The single `releasekit deliver` invocation builds selected targets through the
|
workflow against a tag fixture. The command and profile behavior are documented
|
||||||
facade and uploads them with the release page. The source-only workflow sends
|
in the [CLI contract](../cli.md) and [configuration reference](../config.md).
|
||||||
the committed note page directly. Neither template runs `check` or `publish`.
|
|
||||||
|
|
||||||
Woodpecker runs delivery after the tag event, independently from the source
|
Woodpecker runs delivery after the tag event, independently from the source
|
||||||
publication result. Read its workflow status as delivery status: a delivery
|
publication result. Read its workflow status as delivery status: a delivery
|
||||||
@@ -180,6 +190,6 @@ failure does not undo source publication. A failed, partial, or uncertain run
|
|||||||
can be inspected and retried against the same immutable tag and commit; do not
|
can be inspected and retried against the same immutable tag and commit; do not
|
||||||
move the tag to make a retry pass. See
|
move the tag to make a retry pass. See
|
||||||
[Woodpecker's environment reference](https://woodpecker-ci.org/docs/usage/environment)
|
[Woodpecker's environment reference](https://woodpecker-ci.org/docs/usage/environment)
|
||||||
for the runner-provided tag and commit variables and
|
for runner-provided tag and commit variables and
|
||||||
[workflow syntax](https://woodpecker-ci.org/docs/usage/workflow-syntax) for tag
|
[workflow syntax](https://woodpecker-ci.org/docs/usage/workflow-syntax) for tag
|
||||||
events, sequential steps, and the shared workspace.
|
events, sequential steps, and the shared workspace.
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ not a separate release matrix:
|
|||||||
| Page-only and managed or prebuilt binary delivery | `releasekit.Deliver`, `internal/delivery`, `internal/gitea`, CLI | `TestDeliverPageOnlySkipsBuildAndHostedAssets`, `TestDeliverManagedBuildUploadsArtifactsAndCleansTemporaryOutput`, `TestDeliverPrebuiltArtifactsRemainCallerOwned`, `TestDeliverManagedBuildFailureCleansTemporaryOutputBeforeHostedWrites`, `TestDeliverManagedBuildCancellationCleansTemporaryOutput`, `TestDeliverBuildsTaggedArtifactsAndReusesAssets`, `TestDeliverRejectsTamperedAssetsAndStaleReceiptBeforeRemoteWrites` |
|
| Page-only and managed or prebuilt binary delivery | `releasekit.Deliver`, `internal/delivery`, `internal/gitea`, CLI | `TestDeliverPageOnlySkipsBuildAndHostedAssets`, `TestDeliverManagedBuildUploadsArtifactsAndCleansTemporaryOutput`, `TestDeliverPrebuiltArtifactsRemainCallerOwned`, `TestDeliverManagedBuildFailureCleansTemporaryOutputBeforeHostedWrites`, `TestDeliverManagedBuildCancellationCleansTemporaryOutput`, `TestDeliverBuildsTaggedArtifactsAndReusesAssets`, `TestDeliverRejectsTamperedAssetsAndStaleReceiptBeforeRemoteWrites` |
|
||||||
| Tagged checkout and build dependency preparation | `releasekit.PrepareTaggedCheckout`, `releasekit.PrepareBuildDependencies`, `internal/preparation`, `internal/git`, `internal/gotool` | `TestPrepareTaggedCheckoutFetchesExpectedCommitAndDetaches`, `TestPrepareTaggedCheckoutRejectsWrongCommitBeforeCheckout`, `TestPrepareTaggedCheckoutReportsLocalCheckoutConflict`, `TestPrepareTaggedCheckoutReportsConflictingLocalTag`, `TestPrepareBuildDependenciesPreservesPreparationEnvironment`, `TestPrepareBuildDependenciesPropagatesCommandFailure`, `TestPrepareBuildDependenciesPropagatesCancellation` |
|
| Tagged checkout and build dependency preparation | `releasekit.PrepareTaggedCheckout`, `releasekit.PrepareBuildDependencies`, `internal/preparation`, `internal/git`, `internal/gotool` | `TestPrepareTaggedCheckoutFetchesExpectedCommitAndDetaches`, `TestPrepareTaggedCheckoutRejectsWrongCommitBeforeCheckout`, `TestPrepareTaggedCheckoutReportsLocalCheckoutConflict`, `TestPrepareTaggedCheckoutReportsConflictingLocalTag`, `TestPrepareBuildDependenciesPreservesPreparationEnvironment`, `TestPrepareBuildDependenciesPropagatesCommandFailure`, `TestPrepareBuildDependenciesPropagatesCancellation` |
|
||||||
| Page, manifest, asset comparison, and additive retry outcomes | `internal/gitea` | `TestEnsureReleaseCreatesMissingPageFromCommittedNote`, `TestInspectAssetsDetectsSameNameAndSizeWithDifferentBytes`, `TestUploadMissingPartialFailureThenRerunOnlyMissingAssets` |
|
| Page, manifest, asset comparison, and additive retry outcomes | `internal/gitea` | `TestEnsureReleaseCreatesMissingPageFromCommittedNote`, `TestInspectAssetsDetectsSameNameAndSizeWithDifferentBytes`, `TestUploadMissingPartialFailureThenRerunOnlyMissingAssets` |
|
||||||
| CLI profiles and prepared Woodpecker sequences | `cmd/releasekit`, `cmd/releasekit/internal/cli`, `examples/woodpecker/` | `TestLoadSettingsRejectsInvalidProfiles`, `TestWoodpeckerDeliveryCommandSequences`, `TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout` |
|
| CLI profiles and prepared Woodpecker sequences | `cmd/releasekit`, `cmd/releasekit/internal/cli`, `examples/woodpecker/` | `TestLoadSettingsRejectsInvalidProfiles`, `TestWoodpeckerTagDeliveryTemplate`, `TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout` |
|
||||||
|
|
||||||
Run the complete suite with `go test ./...`. The public API and import boundary
|
Run the complete suite with `go test ./...`. The public API and import boundary
|
||||||
check is `go run ./internal/apicheck`. Local HTTP and Git fixtures exercise
|
check is `go run ./internal/apicheck`. Local HTTP and Git fixtures exercise
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ If validation or a guard fails before this invocation pushes, correct and
|
|||||||
commit the candidate, publish `main`, and run the command again. A retained
|
commit the candidate, publish `main`, and run the command again. A retained
|
||||||
local tag still requires the authoritative-state check above before removal;
|
local tag still requires the authoritative-state check above before removal;
|
||||||
a concurrent publisher may already have published the version. The prepared
|
a concurrent publisher may already have published the version. The prepared
|
||||||
Woodpecker workflow builds the CLI from the tagged
|
Woodpecker workflow builds the CLI from the tagged checkout, then uses
|
||||||
checkout and runs page-only delivery. To activate it after configuring the
|
`ci-deliver` for page-only delivery. To activate it after configuring the
|
||||||
destination and secret, copy it to `.woodpecker/releasekit-source-delivery.yml`
|
destination and secret, copy it to `.woodpecker/releasekit-source-delivery.yml`
|
||||||
and add the Woodpecker repository secret `releasekit_gitea_token`. If page
|
and add the Woodpecker repository secret `releasekit_gitea_token`. If page
|
||||||
delivery fails or is uncertain, inspect the hosted release and retry the same
|
delivery fails or is uncertain, inspect the hosted release and retry the same
|
||||||
|
|||||||
@@ -227,11 +227,12 @@ when needed.
|
|||||||
|
|
||||||
### F6 — Adoption priority: shared deployment still depends on copied mechanics
|
### F6 — Adoption priority: shared deployment still depends on copied mechanics
|
||||||
|
|
||||||
**Evidence.** The [source-only](../../examples/woodpecker/tag-delivery-source-only.yml)
|
**Evidence.** The original source-only and binary templates repeated
|
||||||
and [binary](../../examples/woodpecker/tag-delivery-binary.yml) templates repeat
|
fetch/checkout guards, local exclusions, cache setup, and tool installation;
|
||||||
fetch/checkout guards, local exclusions, cache setup, and tool installation.
|
they are now consolidated in the maintained
|
||||||
The binary template adds an explicit build/receipt/deliver sequence even though
|
[tag-delivery template](../../examples/woodpecker/tag-delivery.yml). The binary
|
||||||
the CLI already supports combined delivery. ReleaseKit's
|
template added an explicit build/receipt/deliver sequence even though the CLI
|
||||||
|
already supports combined delivery. ReleaseKit's
|
||||||
[own workflow](../../examples/woodpecker/releasekit-source-delivery.yml) has a
|
[own workflow](../../examples/woodpecker/releasekit-source-delivery.yml) has a
|
||||||
separate first-release bootstrap. Consumer pins remain placeholders as documented.
|
separate first-release bootstrap. Consumer pins remain placeholders as documented.
|
||||||
|
|
||||||
@@ -249,14 +250,14 @@ Keep dependency preparation separate from offline validation/builds. A split
|
|||||||
build/delivery flow remains useful for an actual credential boundary or artifact
|
build/delivery flow remains useful for an actual credential boundary or artifact
|
||||||
handoff. See Design Choice 4 for packaging alternatives.
|
handoff. See Design Choice 4 for packaging alternatives.
|
||||||
|
|
||||||
`TestWoodpeckerDeliveryCommandSequences` in
|
The original `TestWoodpeckerDeliveryCommandSequences` and the ReleaseKit
|
||||||
[the CLI workflow tests](../../cmd/releasekit/woodpecker_test.go) executes
|
workflow test reconstructed workflow commands, so YAML drift could leave the
|
||||||
equivalent commands;
|
tests green. The maintained tag template and ReleaseKit's bootstrap workflow
|
||||||
[the ReleaseKit workflow test](../../cmd/releasekit/releasekit_delivery_workflow_test.go)
|
are now exercised from their command blocks by local Git/HTTP fixtures. The Go
|
||||||
similarly reconstructs the sequence. Execution of the maintained YAML and
|
bootstrap shim verifies template arguments while mapping the pinned module
|
||||||
installation step remains unverified. A YAML drift can leave these tests green.
|
invocation to the test executable; it does not verify published-module
|
||||||
Validate the selected integration during adoption and keep a small check tied to
|
availability. Real installation and live Woodpecker execution remain
|
||||||
the maintained artifact. Use that evidence to maintain the shared integration.
|
deployment work.
|
||||||
|
|
||||||
### F7 — Medium: delivery asset classifications overlap inconsistently
|
### F7 — Medium: delivery asset classifications overlap inconsistently
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# ReleaseKit audit implementation plan
|
# ReleaseKit audit implementation plan
|
||||||
|
|
||||||
Status: Stages 1–9 complete; Stage 10 next.
|
Status: Stages 1–10 complete; Stage 11 next.
|
||||||
Baseline: `e4be7fa` (2026-10-06). The [audit](audit.md) records the evidence,
|
Baseline: `e4be7fa` (2026-10-06). The [audit](audit.md) records the evidence,
|
||||||
product goals, and selected direction. This document owns implementation order
|
product goals, and selected direction. This document owns implementation order
|
||||||
and completion criteria for that work.
|
and completion criteria for that work.
|
||||||
@@ -510,6 +510,20 @@ matching remote content. The bootstrap shim proves template wiring, not
|
|||||||
published-module availability. Record that distinction and retain real
|
published-module availability. Record that distinction and retain real
|
||||||
installation/live Woodpecker verification as deployment work.
|
installation/live Woodpecker verification as deployment work.
|
||||||
|
|
||||||
|
**Completed:** Source-only and binary consumer delivery now share one
|
||||||
|
profile-driven `tag-delivery.yml` using versioned `go run ... ci-deliver`; the
|
||||||
|
duplicated templates were removed. ReleaseKit's separate first-source workflow
|
||||||
|
still builds its CLI from tagged source and then uses `ci-deliver`. CLI workflow
|
||||||
|
tests extract and execute the maintained command blocks with matrix
|
||||||
|
substitution, Woodpecker dollar escaping, local Git/HTTP fixtures, and a Go
|
||||||
|
bootstrap shim. Both profiles deliver successfully twice, preserving matching
|
||||||
|
pages and binary assets. The shim validates command wiring but does not prove
|
||||||
|
published-module availability. Consumer and maintainer guidance now covers
|
||||||
|
bootstrap requirements, credentials, Go compatibility, caches, dependency
|
||||||
|
preparation, and pin upgrades. Real pins and live integration remain deployment
|
||||||
|
work. The full offline suite, API boundary check, and documentation whitespace
|
||||||
|
checks pass.
|
||||||
|
|
||||||
## Stage 11 — Validate representative adoption and close the sprint
|
## Stage 11 — Validate representative adoption and close the sprint
|
||||||
|
|
||||||
**Covers:** audit-wide acceptance and adoption evidence. **Primary owners:**
|
**Covers:** audit-wide acceptance and adoption evidence. **Primary owners:**
|
||||||
|
|||||||
@@ -211,9 +211,9 @@ infrastructure and one coherent release model.
|
|||||||
- Choose the broader consumer integration test plan and migration sequence.
|
- Choose the broader consumer integration test plan and migration sequence.
|
||||||
Evaluate API clarity, product-specific checks, and the infrastructure removed
|
Evaluate API clarity, product-specific checks, and the infrastructure removed
|
||||||
from each consuming repository.
|
from each consuming repository.
|
||||||
- Select immutable ReleaseKit deployment pins and Go image digests for consumer
|
- Replace the maintained example's ReleaseKit version placeholder with a real
|
||||||
workflows. Provision delivery credentials and activate the prepared Woodpecker
|
immutable revision or published version. Provision delivery credentials and
|
||||||
workflows as part of deployment.
|
activate consumer Woodpecker workflows as part of deployment.
|
||||||
- Verify live Gitea delivery and Woodpecker execution. Existing verification uses
|
- Verify live Gitea delivery and Woodpecker execution. Existing verification uses
|
||||||
local Git and HTTP fixtures; no live deployment has been verified.
|
local Git and HTTP fixtures; no live deployment has been verified.
|
||||||
- Keep ReleaseKit executable binary distribution deferred until deliverables
|
- Keep ReleaseKit executable binary distribution deferred until deliverables
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ when:
|
|||||||
ref: refs/tags/v*
|
ref: refs/tags/v*
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: prepare
|
- name: build-tool
|
||||||
image: golang:1.25.0-bookworm
|
image: golang:1.25.0-bookworm
|
||||||
commands:
|
commands:
|
||||||
- |
|
- |
|
||||||
@@ -14,11 +14,7 @@ steps:
|
|||||||
git checkout --detach "$${CI_COMMIT_SHA}"
|
git checkout --detach "$${CI_COMMIT_SHA}"
|
||||||
test "$(git rev-parse HEAD)" = "$${CI_COMMIT_SHA}"
|
test "$(git rev-parse HEAD)" = "$${CI_COMMIT_SHA}"
|
||||||
mkdir -p "$${CI_WORKSPACE}/.releasekit/bin"
|
mkdir -p "$${CI_WORKSPACE}/.releasekit/bin"
|
||||||
|
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go build -o "$${CI_WORKSPACE}/.releasekit/bin/releasekit" ./cmd/releasekit
|
||||||
- name: build-tool
|
|
||||||
image: golang:1.25.0-bookworm
|
|
||||||
commands:
|
|
||||||
- GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go build -o "$${CI_WORKSPACE}/.releasekit/bin/releasekit" ./cmd/releasekit
|
|
||||||
|
|
||||||
- name: deliver-page
|
- name: deliver-page
|
||||||
image: golang:1.25.0-bookworm
|
image: golang:1.25.0-bookworm
|
||||||
@@ -27,4 +23,7 @@ steps:
|
|||||||
from_secret: releasekit_gitea_token
|
from_secret: releasekit_gitea_token
|
||||||
commands:
|
commands:
|
||||||
- |
|
- |
|
||||||
"$${CI_WORKSPACE}/.releasekit/bin/releasekit" deliver --repo "$${CI_WORKSPACE}" "$${CI_COMMIT_TAG}"
|
"$${CI_WORKSPACE}/.releasekit/bin/releasekit" ci-deliver \
|
||||||
|
--repo "$${CI_WORKSPACE}" \
|
||||||
|
--commit "$${CI_COMMIT_SHA}" \
|
||||||
|
"$${CI_COMMIT_TAG}"
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
matrix:
|
|
||||||
include:
|
|
||||||
- GO_IMAGE: golang:1.25.0-bookworm
|
|
||||||
RELEASEKIT_SOURCE: REPLACE_WITH_IMMUTABLE_COMMIT
|
|
||||||
|
|
||||||
when:
|
|
||||||
- event: tag
|
|
||||||
ref: refs/tags/v*
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: prepare
|
|
||||||
image: ${GO_IMAGE}
|
|
||||||
commands:
|
|
||||||
- |
|
|
||||||
test -n "$${CI_COMMIT_TAG}"
|
|
||||||
test -n "$${CI_COMMIT_SHA}"
|
|
||||||
git fetch origin "refs/tags/$${CI_COMMIT_TAG}:refs/tags/$${CI_COMMIT_TAG}"
|
|
||||||
test "$(git rev-parse "refs/tags/$${CI_COMMIT_TAG}^{commit}")" = "$${CI_COMMIT_SHA}"
|
|
||||||
git checkout --detach "$${CI_COMMIT_SHA}"
|
|
||||||
test "$(git rev-parse HEAD)" = "$${CI_COMMIT_SHA}"
|
|
||||||
printf '\n/.releasekit/\n' >> .git/info/exclude
|
|
||||||
mkdir -p "$${CI_WORKSPACE}/.releasekit/bin" "$${CI_WORKSPACE}/.releasekit/gocache" "$${CI_WORKSPACE}/.releasekit/gomodcache"
|
|
||||||
export GOCACHE="$${CI_WORKSPACE}/.releasekit/gocache"
|
|
||||||
export GOMODCACHE="$${CI_WORKSPACE}/.releasekit/gomodcache"
|
|
||||||
go mod download
|
|
||||||
GOBIN="$${CI_WORKSPACE}/.releasekit/bin" go install gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@${RELEASEKIT_SOURCE}
|
|
||||||
|
|
||||||
- name: deliver
|
|
||||||
image: ${GO_IMAGE}
|
|
||||||
environment:
|
|
||||||
RELEASEKIT_GITEA_TOKEN:
|
|
||||||
from_secret: releasekit_gitea_token
|
|
||||||
commands:
|
|
||||||
- |
|
|
||||||
export GOCACHE="$${CI_WORKSPACE}/.releasekit/gocache"
|
|
||||||
export GOMODCACHE="$${CI_WORKSPACE}/.releasekit/gomodcache"
|
|
||||||
"$${CI_WORKSPACE}/.releasekit/bin/releasekit" deliver --repo "$${CI_WORKSPACE}" "$${CI_COMMIT_TAG}"
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
matrix:
|
|
||||||
include:
|
|
||||||
- GO_IMAGE: golang:1.25.0-bookworm
|
|
||||||
RELEASEKIT_SOURCE: REPLACE_WITH_IMMUTABLE_COMMIT
|
|
||||||
|
|
||||||
when:
|
|
||||||
- event: tag
|
|
||||||
ref: refs/tags/v*
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: prepare
|
|
||||||
image: ${GO_IMAGE}
|
|
||||||
commands:
|
|
||||||
- |
|
|
||||||
test -n "$${CI_COMMIT_TAG}"
|
|
||||||
test -n "$${CI_COMMIT_SHA}"
|
|
||||||
git fetch origin "refs/tags/$${CI_COMMIT_TAG}:refs/tags/$${CI_COMMIT_TAG}"
|
|
||||||
test "$(git rev-parse "refs/tags/$${CI_COMMIT_TAG}^{commit}")" = "$${CI_COMMIT_SHA}"
|
|
||||||
git checkout --detach "$${CI_COMMIT_SHA}"
|
|
||||||
test "$(git rev-parse HEAD)" = "$${CI_COMMIT_SHA}"
|
|
||||||
printf '\n/.releasekit/\n' >> .git/info/exclude
|
|
||||||
mkdir -p "$${CI_WORKSPACE}/.releasekit/bin" "$${CI_WORKSPACE}/.releasekit/gocache" "$${CI_WORKSPACE}/.releasekit/gomodcache"
|
|
||||||
export GOCACHE="$${CI_WORKSPACE}/.releasekit/gocache"
|
|
||||||
export GOMODCACHE="$${CI_WORKSPACE}/.releasekit/gomodcache"
|
|
||||||
GOBIN="$${CI_WORKSPACE}/.releasekit/bin" go install gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@${RELEASEKIT_SOURCE}
|
|
||||||
|
|
||||||
- name: deliver
|
|
||||||
image: ${GO_IMAGE}
|
|
||||||
environment:
|
|
||||||
RELEASEKIT_GITEA_TOKEN:
|
|
||||||
from_secret: releasekit_gitea_token
|
|
||||||
commands:
|
|
||||||
- |
|
|
||||||
export GOCACHE="$${CI_WORKSPACE}/.releasekit/gocache"
|
|
||||||
export GOMODCACHE="$${CI_WORKSPACE}/.releasekit/gomodcache"
|
|
||||||
"$${CI_WORKSPACE}/.releasekit/bin/releasekit" deliver --repo "$${CI_WORKSPACE}" "$${CI_COMMIT_TAG}"
|
|
||||||
21
examples/woodpecker/tag-delivery.yml
Normal file
21
examples/woodpecker/tag-delivery.yml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- GO_IMAGE: golang:1.25.0-bookworm
|
||||||
|
RELEASEKIT_VERSION: REPLACE_WITH_IMMUTABLE_VERSION
|
||||||
|
|
||||||
|
when:
|
||||||
|
- event: tag
|
||||||
|
ref: refs/tags/v*
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: deliver
|
||||||
|
image: ${GO_IMAGE}
|
||||||
|
environment:
|
||||||
|
RELEASEKIT_GITEA_TOKEN:
|
||||||
|
from_secret: releasekit_gitea_token
|
||||||
|
commands:
|
||||||
|
- |
|
||||||
|
go run gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@${RELEASEKIT_VERSION} ci-deliver \
|
||||||
|
--repo "$${CI_WORKSPACE}" \
|
||||||
|
--commit "$${CI_COMMIT_SHA}" \
|
||||||
|
"$${CI_COMMIT_TAG}"
|
||||||
Reference in New Issue
Block a user