Files
ReleaseKit/cmd/releasekit/releasekit_delivery_workflow_test.go

118 lines
5.2 KiB
Go

package main
import (
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit/internal/cli"
)
func TestReleaseKitSourceDeliveryWorkflowFromTaggedCheckout(t *testing.T) {
_, sourceFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatal("locate integration test source")
}
root := filepath.Clean(filepath.Join(filepath.Dir(sourceFile), "../.."))
profile, err := cli.LoadSettings(root, "")
if err != nil {
t.Fatalf("load ReleaseKit source-only profile: %v", err)
}
if profile.Build != nil && len(profile.Build.Targets) != 0 {
t.Fatalf("ReleaseKit profile declares binary targets: %#v", profile.Build.Targets)
}
if profile.Delivery == nil || profile.Delivery.BaseURL != "https://gitea.maximumdirect.net" || profile.Delivery.Owner != "eric" || profile.Delivery.Repository != "ReleaseKit" || profile.Delivery.TokenEnv != "RELEASEKIT_GITEA_TOKEN" {
t.Fatalf("ReleaseKit delivery profile = %#v", profile.Delivery)
}
repository := filepath.Join(t.TempDir(), "tagged ReleaseKit")
clone := exec.Command("git", "clone", "--local", "--no-hardlinks", root, repository)
if output, err := clone.CombinedOutput(); err != nil {
t.Fatalf("clone ReleaseKit source: %v\n%s", err, output)
}
cliGitRun(t, repository, "config", "user.name", "ReleaseKit Test")
cliGitRun(t, repository, "config", "user.email", "releasekit@example.test")
const version = "v1.2.3"
note := "# ReleaseKit v1.2.3\n\nSource-only delivery fixture.\n\n" +
"[COPYRIGHT](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v1.2.3/COPYRIGHT) |\n" +
"[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v1.2.3/LICENSE) |\n" +
"[ATTRIBUTION](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v1.2.3/docs/oss/attribution.md)\n"
notePath := filepath.Join(repository, "docs", "releases", version+".md")
if err := os.MkdirAll(filepath.Dir(notePath), 0o700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(notePath, []byte(note), 0o600); err != nil {
t.Fatal(err)
}
cliGitRun(t, repository, "add", "docs/releases/"+version+".md")
cliGitRun(t, repository, "commit", "-m", "prepare source-only delivery")
state := &deliveryServerState{data: deliveryServerData{product: "ReleaseKit"}}
server := newDeliveryServer(t, state)
defer server.Close()
writeDeliveryProfile(t, repository, cli.Settings{
Product: "ReleaseKit",
Delivery: &cli.DeliverySettings{BaseURL: server.URL, Owner: "owner", Repository: "example"},
})
state.update(func(state *deliveryServerData) { state.commit = cliGitOutput(t, repository, "rev-parse", "HEAD") })
cliGitRun(t, repository, "tag", "-a", version, "-m", "ReleaseKit v1.2.3")
remote := filepath.Join(t.TempDir(), "origin.git")
initRemote := exec.Command("git", "init", "--bare", remote)
if output, err := initRemote.CombinedOutput(); err != nil {
t.Fatalf("initialize local delivery remote: %v\n%s", err, output)
}
cliGitRun(t, repository, "remote", "set-url", "origin", remote)
cliGitRun(t, repository, "push", "origin", "HEAD:refs/heads/main", "refs/tags/"+version)
template, err := os.ReadFile(filepath.Join(root, "examples", "woodpecker", "releasekit-source-delivery.yml"))
if err != nil {
t.Fatal(err)
}
block, err := extractWoodpeckerCommand(string(template), "deliver")
if err != nil {
t.Fatal(err)
}
env := map[string]string{
"CI_WORKSPACE": repository,
"CI_COMMIT_SHA": cliGitOutput(t, repository, "rev-parse", "refs/tags/"+version),
"CI_COMMIT_TAG": version,
"RELEASEKIT_GITEA_TOKEN": "fixture-token",
"GOTOOLCHAIN": "local",
"GOPROXY": "off",
"GOSUMDB": "off",
}
command := strings.ReplaceAll(block, "$${", "${")
state.update(func(state *deliveryServerData) { state.remoteCommit = strings.Repeat("f", 40) })
if output, err := executeWoodpeckerBlock(command, repository, env); err == nil {
t.Fatalf("delivery with a mismatched hosted tag succeeded: %s", output)
}
if state.snapshot().releaseCreates != 0 || cliGitOutput(t, repository, "rev-parse", "refs/tags/"+version+"^{commit}") != state.snapshot().commit {
t.Fatal("delivery failure changed hosted release state or source tag")
}
state.update(func(state *deliveryServerData) { state.remoteCommit = "" })
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.snapshot().releaseCreates != 1 || state.snapshot().assetUploads != 0 || state.snapshot().assetListReads != 0 {
t.Fatalf("page-only workflow calls = creates:%d uploads:%d asset reads:%d", state.snapshot().releaseCreates, state.snapshot().assetUploads, state.snapshot().assetListReads)
}
if state.snapshot().noteBody != note {
t.Fatalf("hosted note body = %q, want complete note %q", state.snapshot().noteBody, note)
}
if got := cliGitOutput(t, repository, "rev-parse", "refs/tags/"+version+"^{commit}"); got != state.snapshot().commit {
t.Fatalf("source tag moved after delivery: %s, want %s", got, state.snapshot().commit)
}
if status := cliGitOutput(t, repository, "status", "--porcelain"); status != "" {
t.Fatalf("tagged checkout became dirty after delivery: %s", status)
}
}