Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions pkg/cmd/ci/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ patch is relative to the default branch.`,
if headOK {
fmt.Printf("HEAD: %s\n", headSHA)
}
// Forward the local branch as a git ref so GITHUB_REF / GITHUB_REF_NAME are set in the
// sandbox. Without this the run is tied to a bare SHA, GITHUB_REF is empty, and
// ref-dependent actions like actions/cache silently no-op. The ref only carries branch
// identity for the GitHub context — the checked-out commit is still driven by the SHA.
gitRef := resolveBranchRef(workflowDir)
if gitRef != "" {
fmt.Printf("Ref: %s\n", gitRef)
}
fmt.Println()

// Serialize workflow back to YAML
Expand All @@ -227,6 +235,9 @@ patch is relative to the default branch.`,
WorkflowContent: []string{string(yamlBytes)},
}
setRunRequestGitContext(req, patch, headSHA, headOK, workspacePatchKey)
if gitRef != "" {
req.Ref = &gitRef
}

resp, err := api.CIRun(ctx, tokenVal, orgID, req)
if err != nil {
Expand Down Expand Up @@ -309,6 +320,28 @@ func resolveHEAD(workflowDir string) (string, error) {
return strings.TrimSpace(string(out)), nil
}

// resolveBranchRef returns the fully-qualified ref (refs/heads/<branch>) for the
// current local branch, or "" when HEAD is detached or the branch can't be
// determined (e.g. not a git repo). This is sent to the server to populate
// GITHUB_REF / GITHUB_REF_NAME in the sandbox so ref-dependent actions such as
// actions/cache work. It carries branch identity only; it does not affect which
// commit is checked out (that is the SHA on the request).
func resolveBranchRef(workflowDir string) string {
// symbolic-ref returns the fully-qualified ref (e.g. "refs/heads/feature/x") and exits
// non-zero on a detached HEAD or outside a repo. Prefer it over `rev-parse --abbrev-ref`,
// which can emit "heads/<branch>" when the short name is ambiguous with a tag and would
// otherwise double-prefix to "refs/heads/heads/<branch>".
out, err := exec.Command("git", "-C", workflowDir, "symbolic-ref", "--quiet", "HEAD").Output()
if err != nil {
return ""
}
ref := strings.TrimSpace(string(out))
if !strings.HasPrefix(ref, "refs/heads/") { // not on a branch
return ""
}
return ref
}

type patchInfo struct {
baseBranch string
mergeBase string
Expand Down
40 changes: 40 additions & 0 deletions pkg/cmd/ci/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,46 @@ func TestSetRunRequestGitContext_noPatch_headUnresolved(t *testing.T) {
}
}

func TestResolveBranchRef_OnDefaultBranch(t *testing.T) {
bare := initBareRemote(t)
clone := cloneRepo(t, bare)

branch := run(t, clone, "git", "rev-parse", "--abbrev-ref", "HEAD")
want := "refs/heads/" + branch
if got := resolveBranchRef(clone); got != want {
t.Fatalf("resolveBranchRef = %q, want %q", got, want)
}
}

func TestResolveBranchRef_FeatureBranch(t *testing.T) {
bare := initBareRemote(t)
clone := cloneRepo(t, bare)

run(t, clone, "git", "checkout", "-b", "feature/test")
if got := resolveBranchRef(clone); got != "refs/heads/feature/test" {
t.Fatalf("resolveBranchRef = %q, want refs/heads/feature/test", got)
}
}

func TestResolveBranchRef_DetachedHEAD(t *testing.T) {
bare := initBareRemote(t)
clone := cloneRepo(t, bare)

headSHA := run(t, clone, "git", "rev-parse", "HEAD")
run(t, clone, "git", "checkout", headSHA)

if got := resolveBranchRef(clone); got != "" {
t.Fatalf("resolveBranchRef on detached HEAD = %q, want empty", got)
}
}

func TestResolveBranchRef_NotAGitRepo(t *testing.T) {
dir := t.TempDir()
if got := resolveBranchRef(dir); got != "" {
t.Fatalf("resolveBranchRef in non-git dir = %q, want empty", got)
}
}

func TestFindUntrackedDepotFiles_includesNewActions(t *testing.T) {
bare := initBareRemote(t)
clone := cloneRepo(t, bare)
Expand Down
Loading
Loading