feat(gitutil): release v1.9.0 — detached HEAD support in CI
- CurrentBranch falls back to CI_COMMIT_BRANCH, CI_COMMIT_REF_NAME, then GITHUB_REF_NAME when HEAD is detached, so --branch is no longer required in GitLab CI / GitHub Actions jobs - go-git push paths (token and SSH agent) now push HEAD's commit hash to the branch instead of refs/heads/<branch>, which never exists in a detached CI checkout — go-git silently skipped the branch update and pushed only the tag - .releaser.gitlab-ci.yml template drops the redundant --branch flag - docs: README, usage, ci-integration, changelog, ROADMAP updated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -245,7 +245,7 @@ func newRootCmd() *cobra.Command {
|
||||
root.Flags().BoolVar(&noRelease, "no-release", false, "push commit and tag but skip creating the release")
|
||||
root.Flags().BoolVar(&noCommit, "no-commit", false, "update files but do not commit, tag, or push")
|
||||
root.Flags().BoolVar(&tagOnly, "tag-only", false, "tag HEAD without updating files (assumes version was already committed)")
|
||||
root.Flags().StringVar(&branchOverride, "branch", "", "override branch name detection (required in detached HEAD)")
|
||||
root.Flags().StringVar(&branchOverride, "branch", "", "override branch name detection (detached HEAD falls back to CI_COMMIT_BRANCH, CI_COMMIT_REF_NAME, GITHUB_REF_NAME)")
|
||||
root.Flags().StringVar(&repoPath, "repo", ".", "path to git repository")
|
||||
root.Flags().StringVar(&pomOverride, "pom", "", "override maven.pom_path from config")
|
||||
root.Flags().StringVar(&gradleOverride, "gradle", "", "override gradle.build_file from config")
|
||||
|
||||
@@ -150,6 +150,9 @@ func TestRunDetachedHead(t *testing.T) {
|
||||
// Detach HEAD
|
||||
head, _ := repo.Head()
|
||||
repo.Storer.SetReference(plumbing.NewHashReference(plumbing.HEAD, head.Hash()))
|
||||
for _, name := range []string{"CI_COMMIT_BRANCH", "CI_COMMIT_REF_NAME", "GITHUB_REF_NAME"} {
|
||||
t.Setenv(name, "")
|
||||
}
|
||||
|
||||
err := execCmd(t, "--dry-run", "--repo", dir) // no --branch
|
||||
if err == nil {
|
||||
@@ -157,6 +160,24 @@ func TestRunDetachedHead(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunDetachedHeadCIBranchEnv(t *testing.T) {
|
||||
repo, dir := setupRepo(t)
|
||||
addFile(t, dir, "src.go", "// fix")
|
||||
w, _ := repo.Worktree()
|
||||
w.Add("src.go")
|
||||
w.Commit("fix: patch something", &gogit.CommitOptions{Author: testSig()})
|
||||
head, _ := repo.Head()
|
||||
repo.Storer.SetReference(plumbing.NewHashReference(plumbing.HEAD, head.Hash()))
|
||||
for _, name := range []string{"CI_COMMIT_REF_NAME", "GITHUB_REF_NAME"} {
|
||||
t.Setenv(name, "")
|
||||
}
|
||||
t.Setenv("CI_COMMIT_BRANCH", "release/1.2")
|
||||
|
||||
if err := execCmd(t, "--dry-run", "--repo", dir); err != nil {
|
||||
t.Fatalf("detached HEAD with CI_COMMIT_BRANCH should succeed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunBadConfig(t *testing.T) {
|
||||
_, dir := setupRepo(t)
|
||||
if err := os.WriteFile(filepath.Join(dir, ".releaser.yml"), []byte("{[invalid"), 0644); err != nil {
|
||||
@@ -484,6 +505,42 @@ func TestRunNoRelease(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCIDetachedHeadPush(t *testing.T) {
|
||||
repo, dir := setupRepoWithRemote(t)
|
||||
addFile(t, dir, "x.go", "// fix")
|
||||
w, _ := repo.Worktree()
|
||||
w.Add("x.go")
|
||||
w.Commit("fix: patch something", &gogit.CommitOptions{Author: testSig()})
|
||||
|
||||
// Simulate a GitLab CI checkout: detached HEAD, no local branch ref,
|
||||
// branch name only available through the environment.
|
||||
head, _ := repo.Head()
|
||||
repo.Storer.SetReference(plumbing.NewHashReference(plumbing.HEAD, head.Hash()))
|
||||
if err := repo.Storer.RemoveReference(plumbing.NewBranchReferenceName("master")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("CI_COMMIT_BRANCH", "release/1.2")
|
||||
t.Setenv("CI_COMMIT_REF_NAME", "")
|
||||
t.Setenv("GITHUB_REF_NAME", "")
|
||||
t.Setenv("GITLAB_TOKEN", "test-token")
|
||||
|
||||
if err := execCmd(t, "--no-release", "--repo", dir); err != nil {
|
||||
t.Fatalf("CI-style detached run: %v", err)
|
||||
}
|
||||
|
||||
remote, err := repo.Remote("origin")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bare, err := gogit.PlainOpen(remote.Config().URLs[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := bare.Reference(plumbing.NewBranchReferenceName("release/1.2"), false); err != nil {
|
||||
t.Errorf("release commit was not pushed to the remote branch: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunMissingToken(t *testing.T) {
|
||||
_, dir := setupRepoWithRemote(t)
|
||||
addFile(t, dir, "x.go", "// fix")
|
||||
|
||||
Reference in New Issue
Block a user