Skip to content

Commit bd7c555

Browse files
committed
Prevent call of git hooks again inside the remote helper and improve the code to do a single push instead of multiple push calls for each ref update
1 parent 7b7c560 commit bd7c555

File tree

1 file changed

+68
-45
lines changed

1 file changed

+68
-45
lines changed

cmd/git-remote-gitopia/gitopia.go

Lines changed: 68 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -263,47 +263,51 @@ func (h *GitopiaHandler) Push(remote *core.Remote, refsToPush []core.RefToPush)
263263
remoteURL := fmt.Sprintf("%v/%v.git", gitServerHost, h.remoteRepository.Id)
264264
lfsURL := remoteURL // Use same URL for LFS
265265

266-
var newRemoteRefSha string
266+
var pushRefspecs []string
267+
var deleteBranches, deleteTags []string
267268
var setBranches []gitopiatypes.MsgMultiSetBranch_Branch
268269
var setTags []gitopiatypes.MsgMultiSetTag_Tag
269-
var deleteBranches, deleteTags []string
270-
var res []string
271-
270+
isForce := false
271+
var res []string // To return the refs that were processed
272272
var packfileCid string
273+
273274
packfileRes, err := h.storageClient.RepositoryPackfile(context.Background(), &storagetypes.QueryRepositoryPackfileRequest{
274275
RepositoryId: h.remoteRepository.Id,
275276
})
276277
if err == nil {
277278
packfileCid = packfileRes.Packfile.Cid
278279
}
279280

281+
// --- First Pass: Collect refspecs and deletions ---
280282
for _, ref := range refsToPush {
281-
if ref.Local == "" {
283+
if ref.Local == "" { // This is a delete operation
282284
if strings.HasPrefix(ref.Remote, branchPrefix) {
283285
remoteBranchName := strings.TrimPrefix(ref.Remote, branchPrefix)
284-
285-
// Check if it's the default branch
286286
if remoteBranchName == h.remoteRepository.DefaultBranch {
287287
return nil, fmt.Errorf("fatal: cannot delete default branch, %v", remoteBranchName)
288288
}
289-
290289
deleteBranches = append(deleteBranches, remoteBranchName)
291290
res = append(res, ref.Remote)
292-
} else if strings.HasPrefix(refsToPush[0].Remote, tagPrefix) {
293-
remoteTagName := strings.TrimPrefix(refsToPush[0].Remote, tagPrefix)
291+
} else if strings.HasPrefix(ref.Remote, tagPrefix) {
292+
remoteTagName := strings.TrimPrefix(ref.Remote, tagPrefix)
294293
deleteTags = append(deleteTags, remoteTagName)
295294
res = append(res, ref.Remote)
296295
}
297-
298296
continue
299297
}
300298

301-
force := false
302-
if strings.HasPrefix(ref.Local, "+") {
303-
ref.Local = strings.TrimPrefix(ref.Local, "+")
304-
force = true
299+
// This is a create/update operation
300+
localRef := ref.Local
301+
if strings.HasPrefix(localRef, "+") {
302+
localRef = strings.TrimPrefix(localRef, "+")
303+
isForce = true
305304
}
306305

306+
pushRefspecs = append(pushRefspecs, fmt.Sprintf("%s:%s", ref.Local, ref.Remote))
307+
}
308+
309+
// --- Execute a single Git Push if there's anything to push ---
310+
if len(pushRefspecs) > 0 {
307311
if h.wallet.Type() == wallet.LEDGER {
308312
remote.Logger.Println("Please sign the git server request on your ledger device.")
309313
}
@@ -313,63 +317,82 @@ func (h *GitopiaHandler) Push(remote *core.Remote, refsToPush []core.RefToPush)
313317
if err != nil {
314318
return nil, errors.Wrap(err, "error signing data")
315319
}
316-
317320
credential := fmt.Sprintf("%s:%s", h.wallet.Address(), signature)
321+
318322
args := []string{
319-
"-c",
320-
fmt.Sprintf("http.extraheader=Authorization: Basic %s", base64.StdEncoding.EncodeToString([]byte(credential))),
321-
"-c",
322-
"credential.helper=",
323-
"-c",
324-
"credential.helper=gitopia",
325-
"-c",
326-
fmt.Sprintf("lfs.url=%s", lfsURL),
323+
"-c", fmt.Sprintf("http.extraheader=Authorization: Basic %s", base64.StdEncoding.EncodeToString([]byte(credential))),
324+
"-c", "credential.helper=",
325+
"-c", "credential.helper=gitopia",
326+
"-c", fmt.Sprintf("lfs.url=%s", lfsURL),
327327
"push",
328+
"--no-verify", // Keep this to prevent the double-hook call
328329
remoteURL,
329-
fmt.Sprintf("%s:%s", ref.Local, ref.Remote),
330330
}
331-
if force {
331+
332+
// Add all refspecs to the command
333+
args = append(args, pushRefspecs...)
334+
335+
if isForce {
332336
args = append(args, "--force")
333337
}
338+
334339
cmd := core.GitCommand("git", args...)
335340
if err := cmd.Run(); err != nil {
336341
return nil, errors.Wrap(err, "error pushing to remote repository")
337342
}
343+
}
344+
345+
// --- Second Pass: Collect metadata for Gitopia transaction ---
346+
for _, ref := range refsToPush {
347+
if ref.Local == "" {
348+
continue // Deletes already handled
349+
}
350+
351+
localRef := ref.Local
352+
if strings.HasPrefix(localRef, "+") {
353+
localRef = strings.TrimPrefix(localRef, "+")
354+
}
338355

339356
// Update ref on gitopia
340-
if strings.HasPrefix(ref.Local, branchPrefix) {
341-
localCommitHash, err := remote.Repo.ResolveRevision(plumbing.Revision(ref.Local))
357+
if strings.HasPrefix(localRef, branchPrefix) {
358+
localCommitHash, err := remote.Repo.ResolveRevision(plumbing.Revision(localRef))
342359
if err != nil {
343-
return nil, fmt.Errorf("fatal: local branch %s doesn't exist", ref.Local)
360+
return nil, fmt.Errorf("fatal: local branch %s doesn't exist", localRef)
344361
}
345362

346-
newRemoteRefSha = localCommitHash.String()
347363
remoteBranchName := strings.TrimPrefix(ref.Remote, branchPrefix)
348364
branch := gitopiatypes.MsgMultiSetBranch_Branch{
349365
Name: remoteBranchName,
350-
Sha: newRemoteRefSha,
366+
Sha: localCommitHash.String(),
351367
}
352-
353368
setBranches = append(setBranches, branch)
354369
res = append(res, ref.Remote)
355-
} else if strings.HasPrefix(ref.Local, tagPrefix) {
356-
localTagName := strings.TrimPrefix(ref.Local, tagPrefix)
370+
} else if strings.HasPrefix(localRef, tagPrefix) {
371+
localTagName := strings.TrimPrefix(localRef, tagPrefix)
357372
tagRef, err := remote.Repo.Tag(localTagName)
358373
if err != nil {
359-
return nil, fmt.Errorf("fatal: invalid tag name, %v", localTagName)
360-
}
361-
362-
newRemoteRefSha = tagRef.Hash().String()
363-
remoteTagName := strings.TrimPrefix(ref.Remote, tagPrefix)
364-
tag := gitopiatypes.MsgMultiSetTag_Tag{
365-
Name: remoteTagName,
366-
Sha: newRemoteRefSha,
374+
// Could be a lightweight tag, resolve revision instead
375+
commitHash, err := remote.Repo.ResolveRevision(plumbing.Revision(localRef))
376+
if err != nil {
377+
return nil, fmt.Errorf("fatal: invalid tag name or ref, %v", localTagName)
378+
}
379+
tag := gitopiatypes.MsgMultiSetTag_Tag{
380+
Name: strings.TrimPrefix(ref.Remote, tagPrefix),
381+
Sha: commitHash.String(),
382+
}
383+
setTags = append(setTags, tag)
384+
} else {
385+
// Annotated tag
386+
tag := gitopiatypes.MsgMultiSetTag_Tag{
387+
Name: strings.TrimPrefix(ref.Remote, tagPrefix),
388+
Sha: tagRef.Hash().String(),
389+
}
390+
setTags = append(setTags, tag)
367391
}
368392

369-
setTags = append(setTags, tag)
370393
res = append(res, ref.Remote)
371394
} else {
372-
return nil, fmt.Errorf("fatal: not a valid branch/tag, %v", ref.Local)
395+
return nil, fmt.Errorf("fatal: invalid refspec, %v", ref)
373396
}
374397
}
375398

@@ -444,7 +467,7 @@ func (h *GitopiaHandler) havePushPermission(walletAddress string) (havePermissio
444467
DaoId: h.remoteRepository.Owner.Id,
445468
})
446469
if err != nil {
447-
return havePermission, err
470+
return havePermission, errors.Wrap(err, "error querying DAO members")
448471
}
449472

450473
for _, member := range resp.Members {

0 commit comments

Comments
 (0)