Integrate selected builds with candidate workflows

This commit is contained in:
2026-10-05 19:38:50 +00:00
parent 5d6a6d10bd
commit e98ee0f7b9
21 changed files with 848 additions and 31 deletions

View File

@@ -333,6 +333,77 @@ func TestBuildCancellationReturnsCompletedArtifacts(t *testing.T) {
}
}
func TestCheckBuildsAfterValidationAndKeepsOutputOutsideWorktree(t *testing.T) {
repository := newPublishFixture(t)
prepareCandidateBuild(t, repository.work, `package main
import (
"fmt"
"os"
"gitea.maximumdirect.net/eric/ReleaseKit/buildinfo"
)
func main() { if len(os.Args) == 2 && os.Args[1] == "version" { fmt.Printf("fixture %s\n", buildinfo.Version()) } }
`)
var validations int
candidate, err := releasekit.Check(context.Background(), releasekit.ReleaseRequest{
RepositoryDir: repository.work,
Product: "Sample App",
Version: "v1.2.3",
Validate: func(context.Context, releasekit.Candidate) error {
validations++
return nil
},
Build: &releasekit.BuildSpec{
MainPackage: "./cmd/app",
BinaryName: "fixture",
Targets: []releasekit.Target{{OS: runtime.GOOS, Arch: runtime.GOARCH}},
},
})
if err != nil {
t.Fatalf("Check() error = %v", err)
}
if validations != 1 || candidate.Commit != gitText(t, repository.work, "rev-parse", "HEAD") {
t.Fatalf("candidate = %#v, validation calls = %d", candidate, validations)
}
if got := gitText(t, repository.work, "status", "--porcelain"); got != "" {
t.Fatalf("candidate build dirtied worktree: %s", got)
}
if paths, err := filepath.Glob(filepath.Join(filepath.Dir(repository.work), ".releasekit-candidate-build-*")); err != nil || len(paths) != 0 {
t.Fatalf("temporary candidate output remains: %v, error=%v", paths, err)
}
}
func TestPublishBuildFailurePreventsTagCreation(t *testing.T) {
repository := newPublishFixture(t)
prepareCandidateBuild(t, repository.work, "package main\nfunc main() {}\n")
var validations int
result, err := releasekit.Publish(context.Background(), releasekit.ReleaseRequest{
RepositoryDir: repository.work,
Product: "Sample App",
Version: "v1.2.3",
Validate: func(context.Context, releasekit.Candidate) error {
validations++
return nil
},
Build: &releasekit.BuildSpec{
MainPackage: "./cmd/missing",
BinaryName: "fixture",
Targets: []releasekit.Target{{OS: runtime.GOOS, Arch: runtime.GOARCH}},
},
})
if err == nil || !strings.Contains(err.Error(), "build candidate") || result.TagObject != "" {
t.Fatalf("Publish() result=%#v error=%v; want build failure before tag creation", result, err)
}
if validations != 1 {
t.Fatalf("validation calls = %d, want 1", validations)
}
if _, err := exec.Command("git", "--git-dir", repository.bare, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3").CombinedOutput(); err == nil {
t.Fatal("build failure published the release tag")
}
if _, err := exec.Command("git", "-C", repository.work, "show-ref", "--verify", "--quiet", "refs/tags/v1.2.3").CombinedOutput(); err == nil {
t.Fatal("build failure created a local release tag")
}
}
func newBuildConsumer(t *testing.T, mainSource string) string {
t.Helper()
repository, err := os.MkdirTemp("", "releasekit-build-consumer-")
@@ -355,6 +426,22 @@ func newBuildConsumer(t *testing.T, mainSource string) string {
return repository
}
func prepareCandidateBuild(t *testing.T, repository, mainSource string) {
t.Helper()
root, err := filepath.Abs(".")
if err != nil {
t.Fatal(err)
}
module := fmt.Sprintf("module example.com/candidatebuild\n\ngo 1.25.0\n\nrequire gitea.maximumdirect.net/eric/ReleaseKit v0.0.0\n\nreplace gitea.maximumdirect.net/eric/ReleaseKit => %s\n", filepath.ToSlash(root))
writeFile(t, repository, "go.mod", module)
writeFile(t, repository, ".gitignore", "dist/\n")
writeFile(t, repository, "cmd/app/main.go", mainSource)
gitRun(t, repository, "add", "--all")
gitRun(t, repository, "commit", "-m", "add buildable candidate")
gitRun(t, repository, "config", "remote.origin.mirror", "false")
gitRun(t, repository, "push", "origin", "HEAD:refs/heads/main")
}
func writeBuildFixture(t *testing.T, directory, name, contents string) {
t.Helper()
path := filepath.Join(directory, filepath.FromSlash(name))