feat(release): archive an arbitrary ref, decoupled from the version
bbac80daf500efc7f54a4e0662c9bd4cc51b6963
humdrum <me@humdrum.me> · 2026-06-19 08:24
parent 1dd04bc8
2 files changed
internal/release/release.go +8 −3
@@ -113,7 +113,8 @@ DLPath string // tarball output dir
TapRepo string // tap bare repo name (e.g. homebrew-tap)
BaseURL string // e.g. https://codex.humdrum.me
Repo string // repo name
- Tag string // vX.Y.Z
+ Ref string // git ref to archive (tag or release branch); defaults to Tag
+ Tag string // vX.Y.Z — the version (tarball name, formula, commit msg)
Desc string // repo description (from webhook payload)
Package string // go build path; default "."
}
@@ -122,6 +123,10 @@ // Publish archives the tag, writes the tarball, renders the formula, and commits
// it to the tap. Returns the published version on success.
func Publish(o Options) (string, error) {
ver := strings.TrimPrefix(o.Tag, "v")
+ archiveRef := o.Ref
+ if archiveRef == "" {
+ archiveRef = o.Tag
+ }
pkg := o.Package
if pkg == "" {
pkg = "."
@@ -133,7 +138,7 @@ if err := os.MkdirAll(o.DLPath, 0o755); err != nil {
return "", err
}
tarPath := filepath.Join(o.DLPath, tarName)
- if err := gitArchive(bare, o.Repo+"-"+ver, o.Tag, tarPath); err != nil {
+ if err := gitArchive(bare, o.Repo+"-"+ver, archiveRef, tarPath); err != nil {
return "", err
}
sha, err := sha256File(tarPath)
@@ -148,7 +153,7 @@ Desc: formulaDesc(o.Desc),
Homepage: o.BaseURL + "/r/" + o.Repo,
URL: o.BaseURL + "/dl/" + tarName,
SHA: sha,
- License: detectLicense(o.Store, o.Repo, o.Tag),
+ License: detectLicense(o.Store, o.Repo, archiveRef),
Package: pkg,
}
rendered, err := f.render()
internal/release/release_test.go +88 −1
@@ -1,6 +1,14 @@
package release
-import "testing"
+import (
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "custard/internal/gitread"
+)
func TestReleaseSourceAndPrefix(t *testing.T) {
var c RepoConfig
@@ -39,3 +47,82 @@ t.Errorf("BookmarkVersion(%q,%q) = %q,%v; want %q,%v", c.short, c.prefix, got, ok, c.want, c.ok)
}
}
}
+
+func gitRun(t *testing.T, dir string, args ...string) {
+ t.Helper()
+ c := exec.Command("git", args...)
+ c.Dir = dir
+ c.Env = append(c.Environ(),
+ "GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@x", "GIT_AUTHOR_DATE=2026-01-01T00:00:00",
+ "GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@x", "GIT_COMMITTER_DATE=2026-01-01T00:00:00")
+ if out, err := c.CombinedOutput(); err != nil {
+ t.Fatalf("git %v: %v: %s", args, err, out)
+ }
+}
+
+// TestPublishArchivesBranchRef verifies bookmark mode: archive the release
+// BRANCH while naming the tarball/formula by the VERSION.
+func TestPublishArchivesBranchRef(t *testing.T) {
+ root := t.TempDir()
+ work := filepath.Join(root, "work")
+ gitRun(t, root, "init", "-q", "-b", "main", "work")
+ if err := os.WriteFile(filepath.Join(work, "go.mod"), []byte("module proj\n"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ gitRun(t, work, "add", ".")
+ gitRun(t, work, "commit", "-q", "-m", "init")
+ gitRun(t, work, "checkout", "-q", "-b", "release/v1.2.3")
+ gitRun(t, work, "commit", "-q", "--allow-empty", "-m", "ship v1.2.3")
+ gitRun(t, work, "checkout", "-q", "main")
+ gitRun(t, work, "clone", "-q", "--bare", work, filepath.Join(root, "proj.git"))
+
+ // A bare tap repo to receive the formula.
+ tap := filepath.Join(root, "homebrew-tap.git")
+ gitRun(t, root, "init", "-q", "--bare", "homebrew-tap.git")
+ // Seed the tap with one commit so HEAD exists for cloning.
+ tapWork := filepath.Join(root, "tapwork")
+ gitRun(t, root, "clone", "-q", "homebrew-tap.git", "tapwork")
+ if err := os.WriteFile(filepath.Join(tapWork, "README"), []byte("tap\n"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ gitRun(t, tapWork, "add", ".")
+ gitRun(t, tapWork, "commit", "-q", "-m", "seed")
+ gitRun(t, tapWork, "push", "-q", "origin", "HEAD:master")
+
+ dl := filepath.Join(root, "dl")
+ ver, err := Publish(Options{
+ Store: gitread.New(root),
+ ReposPath: root,
+ DLPath: dl,
+ TapRepo: "homebrew-tap",
+ BaseURL: "https://example.test",
+ Repo: "proj",
+ Ref: "release/v1.2.3", // archive the branch
+ Tag: "v1.2.3", // version
+ Desc: "a thing",
+ Package: ".",
+ })
+ if err != nil {
+ t.Fatalf("Publish: %v", err)
+ }
+ if ver != "1.2.3" {
+ t.Errorf("ver = %q, want 1.2.3", ver)
+ }
+ if _, err := os.Stat(filepath.Join(dl, "proj-1.2.3.tar.gz")); err != nil {
+ t.Errorf("tarball not written: %v", err)
+ }
+ _ = tap
+}
+
+func TestPublishDefaultsRefToTag(t *testing.T) {
+ // With Ref empty, Publish must archive Tag (tag-mode back-compat). A bogus
+ // repo path makes git archive fail; assert the error names the tag, proving
+ // Tag was used as the archive ref.
+ _, err := Publish(Options{
+ Store: gitread.New(t.TempDir()), ReposPath: t.TempDir(), DLPath: t.TempDir(),
+ Repo: "nope", Tag: "v9.9.9",
+ })
+ if err == nil || !strings.Contains(err.Error(), "v9.9.9") {
+ t.Fatalf("expected archive error naming v9.9.9, got %v", err)
+ }
+}