forked from tangled.org/core
this repo has no description

knotserver: insert change-ids into format-patch output

Changed files
+91 -8
knotserver
types
+1 -1
flake.nix
···
inherit (gitignore.lib) gitignoreSource;
in {
overlays.default = final: prev: let
-
goModHash = "sha256-zcfTNo7QsiihzLa4qHEX8uGGtbcmBn8TlSm0YHBRNw8=";
+
goModHash = "sha256-TwlPge7vhVGmtNvYkHFFnZjJs2DWPUwPhCSBTCUYCtc=";
buildCmdPackage = name:
final.buildGoModule {
pname = name;
+3 -1
go.mod
···
github.com/dustin/go-humanize v1.0.1
github.com/gliderlabs/ssh v0.3.8
github.com/go-chi/chi/v5 v5.2.0
-
github.com/go-git/go-git/v5 v5.14.0
+
github.com/go-git/go-git/v5 v5.0.0-00010101000000-000000000000
github.com/google/uuid v1.6.0
github.com/gorilla/sessions v1.4.0
github.com/haileyok/atproto-oauth-golang v0.0.2
···
replace github.com/sergi/go-diff => github.com/sergi/go-diff v1.1.0
replace github.com/go-git/go-git/v5 => /home/op/code/go-git
+
+
replace github.com/bluekeyes/go-gitdiff => /home/op/code/go-gitdiff
// from bluesky-social/indigo
replace github.com/gocql/gocql => github.com/scylladb/gocql v1.14.4
+85 -6
knotserver/git/diff.go
···
"log"
"os"
"os/exec"
+
"slices"
"strings"
"github.com/bluekeyes/go-gitdiff/gitdiff"
···
// FormatPatch generates a git-format-patch output between two commits,
// and returns the raw format-patch series, a parsed FormatPatch and an error.
-
func (g *GitRepo) FormatPatch(base, commit2 *object.Commit) (string, []patchutil.FormatPatch, error) {
+
func (g *GitRepo) formatSinglePatch(base, commit2 plumbing.Hash, extraArgs ...string) (string, *patchutil.FormatPatch, error) {
var stdout bytes.Buffer
-
cmd := exec.Command(
-
"git",
+
+
args := []string{
"-C",
g.path,
"format-patch",
-
fmt.Sprintf("%s..%s", base.Hash.String(), commit2.Hash.String()),
+
fmt.Sprintf("%s..%s", base.String(), commit2.String()),
"--stdout",
-
)
+
}
+
args = append(args, extraArgs...)
+
+
cmd := exec.Command("git", args...)
cmd.Stdout = &stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
···
return "", nil, err
}
-
return stdout.String(), formatPatch, nil
+
if len(formatPatch) > 1 {
+
return "", nil, fmt.Errorf("running format-patch on single commit produced more than on patch")
+
}
+
+
return stdout.String(), &formatPatch[0], nil
}
func (g *GitRepo) MergeBase(commit1, commit2 *object.Commit) (*object.Commit, error) {
···
return commit, nil
}
+
+
func (g *GitRepo) commitsBetween(newCommit, oldCommit *object.Commit) ([]*object.Commit, error) {
+
var commits []*object.Commit
+
current := newCommit
+
+
for {
+
if current.Hash == oldCommit.Hash {
+
break
+
}
+
+
commits = append(commits, current)
+
+
if len(current.ParentHashes) == 0 {
+
return nil, fmt.Errorf("old commit %s not found in history of new commit %s", oldCommit.Hash, newCommit.Hash)
+
}
+
+
parent, err := current.Parents().Next()
+
if err != nil {
+
return nil, fmt.Errorf("error getting parent: %w", err)
+
}
+
+
current = parent
+
}
+
+
return commits, nil
+
}
+
+
func (g *GitRepo) FormatPatch(base, commit2 *object.Commit) (string, []patchutil.FormatPatch, error) {
+
// get list of commits between commir2 and base
+
commits, err := g.commitsBetween(commit2, base)
+
if err != nil {
+
return "", nil, fmt.Errorf("failed to get commits: %w", err)
+
}
+
+
// reverse the list so we start from the oldest one and go up to the most recent one
+
slices.Reverse(commits)
+
+
var allPatchesContent strings.Builder
+
var allPatches []patchutil.FormatPatch
+
+
for _, commit := range commits {
+
changeId := ""
+
if val, ok := commit.ExtraHeaders["change-id"]; ok {
+
changeId = string(val)
+
}
+
+
var parentHash plumbing.Hash
+
if len(commit.ParentHashes) > 0 {
+
parentHash = commit.ParentHashes[0]
+
} else {
+
parentHash = plumbing.NewHash("4b825dc642cb6eb9a060e54bf8d69288fbee4904") // git empty tree hash
+
}
+
+
var additionalArgs []string
+
if changeId != "" {
+
additionalArgs = append(additionalArgs, "--add-header", fmt.Sprintf("Change-Id: %s", changeId))
+
}
+
+
stdout, patch, err := g.formatSinglePatch(parentHash, commit.Hash, additionalArgs...)
+
if err != nil {
+
return "", nil, fmt.Errorf("failed to format patch for commit %s: %w", commit.Hash.String(), err)
+
}
+
+
allPatchesContent.WriteString(stdout)
+
allPatchesContent.WriteString("\n")
+
+
allPatches = append(allPatches, *patch)
+
}
+
+
return allPatchesContent.String(), allPatches, nil
+
}
+1
knotserver/routes.go
···
Rev1: commit1.Hash.String(),
Rev2: commit2.Hash.String(),
FormatPatch: formatPatch,
+
MergeBase: mergeBase.Hash.String(),
Patch: rawPatch,
})
return
+1
types/repo.go
···
Rev1 string `json:"rev1,omitempty"`
Rev2 string `json:"rev2,omitempty"`
FormatPatch []patchutil.FormatPatch `json:"format_patch,omitempty"`
+
MergeBase string `json:"merge_base,omitempty"`
Patch string `json:"patch,omitempty"`
}