Skip to content
Merged
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
4 changes: 1 addition & 3 deletions internal/forge/shamhub/change.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

"go.abhg.dev/gs/internal/forge"
"go.abhg.dev/gs/internal/xec"
)

// ListChanges reports all changes known to the forge.
Expand Down Expand Up @@ -222,8 +221,7 @@ type ChangeBranch struct {
}

func (sh *ShamHub) toChangeBranch(b *shamBranch) (*ChangeBranch, error) {
out, err := xec.Command(context.Background(), sh.log, sh.gitExe, "rev-parse", b.Name).
WithDir(sh.repoDir(b.Owner, b.Repo)).
out, err := sh.gitCmd(context.Background(), b.Owner, b.Repo, "rev-parse", b.Name).
Output()
if err != nil {
return nil, fmt.Errorf("get SHA for %v/%v:%v: %w", b.Owner, b.Repo, b.Name, err)
Expand Down
5 changes: 1 addition & 4 deletions internal/forge/shamhub/ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package shamhub
import (
"context"
"fmt"

"go.abhg.dev/gs/internal/xec"
)

type refExistsRequest struct {
Expand Down Expand Up @@ -38,8 +36,7 @@ func (r *forgeRepository) RefExists(ctx context.Context, ref string) (bool, erro
}

func (sh *ShamHub) refExists(ctx context.Context, owner, repo, ref string) bool {
return xec.Command(ctx, sh.log, sh.gitExe, "show-ref", "--verify", "--quiet", ref).
WithDir(sh.repoDir(owner, repo)).
return sh.gitCmd(ctx, owner, repo, "show-ref", "--verify", "--quiet", ref).
Run() == nil
}

Expand Down
3 changes: 1 addition & 2 deletions internal/forge/shamhub/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ func (sh *ShamHub) newRepository(owner, repo string, forkOf *repoID) (string, er
}

// Configure the repository to accept pushes.
if err := xec.Command(ctx, sh.log, sh.gitExe, "config", "http.receivepack", "true").
WithDir(repoDir).
if err := sh.gitCmd(ctx, owner, repo, "config", "http.receivepack", "true").
CaptureStdout().
Run(); err != nil {
return "", fmt.Errorf("configure repository: %w", err)
Expand Down
11 changes: 11 additions & 0 deletions internal/forge/shamhub/shamhub.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package shamhub

import (
"context"
"fmt"
"net/http/cgi"
"net/http/httptest"
Expand Down Expand Up @@ -137,6 +138,16 @@ func (sh *ShamHub) repoDir(owner, repo string) string {
return filepath.Join(sh.gitRoot, owner, repo+".git")
}

// gitCmd builds a git command scoped to the bare repository for owner/repo.
// Use this instead of WithDir(repoDir(...)): git 2.50 no longer discovers a
// bare repo from the current working directory alone, so an explicit
// --git-dir is required for `git config`, `git show-ref`, `git rev-parse`,
// and similar commands.
func (sh *ShamHub) gitCmd(ctx context.Context, owner, repo string, args ...string) *xec.Cmd {
return xec.Command(ctx, sh.log, sh.gitExe,
append([]string{"--git-dir", sh.repoDir(owner, repo)}, args...)...)
}

func (sh *ShamHub) changeURL(owner, repo string, change int) string {
return fmt.Sprintf("%s/%s/%s/change/%d", sh.GitURL(), owner, repo, change)
}
35 changes: 10 additions & 25 deletions internal/forge/shamhub/states.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (

"go.abhg.dev/gs/internal/forge"
"go.abhg.dev/gs/internal/git"
"go.abhg.dev/gs/internal/xec"
)

type statesRequest struct {
Expand Down Expand Up @@ -208,23 +207,17 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {
return fmt.Errorf("change %d (%v/%v) is not open", req.Number, req.Owner, req.Repo)
}

// Determine if this is a cross-fork merge by checking if the head branch
// exists in the target repository or needs to be fetched from a fork
targetRepoDir := sh.repoDir(req.Owner, req.Repo)

baseRef := change.Base
headRef := change.Head

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

if req.Time.IsZero() {
out, err := xec.Command(
ctx, sh.log, sh.gitExe,
out, err := sh.gitCmd(
ctx, headRef.Owner, headRef.Repo,
"log", "-1", "--format=%cI", headRef.Name,
).
WithDir(sh.repoDir(headRef.Owner, headRef.Repo)).
Output()
).Output()
if err != nil {
return fmt.Errorf("read head commit time: %w", err)
}
Expand All @@ -246,10 +239,8 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {

// If a HeadHash is provided, verify the head matches.
if req.HeadHash != "" {
headRepoDir := sh.repoDir(headRef.Owner, headRef.Repo)
out, err := xec.Command(ctx, sh.log, sh.gitExe,
out, err := sh.gitCmd(ctx, headRef.Owner, headRef.Repo,
"rev-parse", headRef.Name).
WithDir(headRepoDir).
Output()
if err != nil {
return fmt.Errorf("resolve head ref: %w", err)
Expand All @@ -267,8 +258,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {
if headRef.Owner != req.Owner || headRef.Repo != req.Repo {
// Fetch the head branch from the fork
forkRepoDir := sh.repoDir(headRef.Owner, headRef.Repo)
if err := xec.Command(ctx, sh.log, sh.gitExe, "fetch", forkRepoDir, headRef.Name+":"+headRef.Name).
WithDir(targetRepoDir).
if err := sh.gitCmd(ctx, req.Owner, req.Repo, "fetch", forkRepoDir, headRef.Name+":"+headRef.Name).
Run(); err != nil {
return fmt.Errorf("fetch from fork: %w", err)
}
Expand All @@ -284,8 +274,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {
//
// This requires at least Git 2.38.
tree, err := func() (string, error) {
out, err := xec.Command(ctx, sh.log, sh.gitExe, "merge-tree", "--write-tree", baseRef.Name, headRef.Name).
WithDir(targetRepoDir).
out, err := sh.gitCmd(ctx, req.Owner, req.Repo, "merge-tree", "--write-tree", baseRef.Name, headRef.Name).
Output()
if err != nil {
return "", fmt.Errorf("merge-tree: %w", err)
Expand Down Expand Up @@ -313,8 +302,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {
}
args = append(args, "-m", msg, tree)

out, err := xec.Command(ctx, sh.log, sh.gitExe, args...).
WithDir(sh.repoDir(req.Owner, req.Repo)).
out, err := sh.gitCmd(ctx, req.Owner, req.Repo, args...).
AppendEnv(commitEnv...).
Output()
if err != nil {
Expand All @@ -328,8 +316,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {
}

headHash, err := func() (string, error) {
out, err := xec.Command(ctx, sh.log, sh.gitExe, "rev-parse", headRef.Name).
WithDir(sh.repoDir(headRef.Owner, headRef.Repo)).
out, err := sh.gitCmd(ctx, headRef.Owner, headRef.Repo, "rev-parse", headRef.Name).
Output()
if err != nil {
return "", fmt.Errorf("rev-parse head: %w", err)
Expand All @@ -344,8 +331,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {
// Update the ref to point to the new commit.
err = func() error {
ref := "refs/heads/" + sh.changes[changeIdx].Base.Name
if err := xec.Command(ctx, sh.log, sh.gitExe, "update-ref", ref, commit).
WithDir(sh.repoDir(req.Owner, req.Repo)).
if err := sh.gitCmd(ctx, req.Owner, req.Repo, "update-ref", ref, commit).
Run(); err != nil {
return fmt.Errorf("update-ref: %w", err)
}
Expand All @@ -358,8 +344,7 @@ func (sh *ShamHub) MergeChange(req MergeChangeRequest) error {

if req.DeleteBranch {
err := func() error {
if err := xec.Command(ctx, sh.log, sh.gitExe, "branch", "-D", change.Head.Name).
WithDir(sh.repoDir(change.Head.Owner, change.Head.Repo)).
if err := sh.gitCmd(ctx, change.Head.Owner, change.Head.Repo, "branch", "-D", change.Head.Name).
Run(); err != nil {
return fmt.Errorf("delete branch: %w", err)
}
Expand Down
9 changes: 3 additions & 6 deletions internal/forge/shamhub/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"go.abhg.dev/gs/internal/forge"
"go.abhg.dev/gs/internal/scanutil"
"go.abhg.dev/gs/internal/xec"
)

var _changeTemplatePaths = []string{
Expand Down Expand Up @@ -49,9 +48,8 @@ func (sh *ShamHub) handleChangeTemplate(ctx context.Context, req *changeTemplate

var res changeTemplateResponse
var matches []matchingTemplatePath
treeCmd := xec.Command(ctx, nil, sh.gitExe,
"ls-tree", "-r", "-z", "--name-only", "HEAD").
WithDir(sh.repoDir(owner, repo))
treeCmd := sh.gitCmd(ctx, owner, repo,
"ls-tree", "-r", "-z", "--name-only", "HEAD")
for treePath, err := range treeCmd.Scan(scanutil.SplitNull) {
if err != nil {
return nil, nil
Expand All @@ -69,9 +67,8 @@ func (sh *ShamHub) handleChangeTemplate(ctx context.Context, req *changeTemplate
})

for _, templatePath := range matches {
out, err := xec.Command(ctx, sh.log, sh.gitExe,
out, err := sh.gitCmd(ctx, owner, repo,
"cat-file", "blob", "HEAD:"+templatePath.filePath).
WithDir(sh.repoDir(owner, repo)).
Output()
if err != nil {
continue
Expand Down
Loading