This commit is contained in:
Adam Majer
2024-07-15 19:19:34 +02:00
parent 3c4f1d103c
commit fb8e5d5e03
3 changed files with 112 additions and 33 deletions

View File

@@ -251,12 +251,26 @@ type tree_entry struct {
name string name string
mode int mode int
hash string hash string
size int
} }
type tree struct { type tree struct {
items []tree_entry items []tree_entry
} }
func (t *tree_entry) isSubmodule() bool {
return (t.mode & 0170000) == 0160000
}
func (t *tree_entry) isTree() bool {
return (t.mode & 0170000) == 0040000
}
func (t *tree_entry) isBlob() bool {
return !t.isTree() && !t.isSubmodule()
}
func parseGitMsg(data <-chan byte) (gitMsg, error) { func parseGitMsg(data <-chan byte) (gitMsg, error) {
var id []byte = make([]byte, 64) var id []byte = make([]byte, 64)
var msgType []byte = make([]byte, 16) var msgType []byte = make([]byte, 16)
@@ -295,7 +309,7 @@ func parseGitMsg(data <-chan byte) (gitMsg, error) {
if c >= '0' && c <= '9' { if c >= '0' && c <= '9' {
size = size*10 + (int(c) - '0') size = size*10 + (int(c) - '0')
} else { } else {
return gitMsg{}, errors.New("Invalid character during commit size parse") return gitMsg{}, fmt.Errorf("Invalid character during object size parse: '%c'", c)
} }
} }
@@ -366,31 +380,65 @@ func parseGitCommit(data <-chan byte) (commit, error) {
return c, err return c, err
} }
func parseTreeEntry(data <-chan byte) (tree_entry, error) { func parseTreeEntry(data <-chan byte, hashLen int) (tree_entry, error) {
var e tree_entry var e tree_entry
for c:=<-data; c != ' '; c=<-data { for c := <-data; c != ' '; c = <-data {
e.mode = e.mode * 8 + (c - '0') e.mode = e.mode*8 + int(c-'0')
e.size++
} }
for c:=<-data; c != '\x00'; c=<-data { e.size++
e.name = append(e.name, c)
name := make([]byte, 0, 128)
for c := <-data; c != '\x00'; c = <-data {
name = append(name, c)
e.size++
} }
e.size++
e.name = string(name)
const hexBinToAscii = "0123456789abcdef"
hash := make([]byte, 0, hashLen*2)
for range hashLen {
c := <-data
hash = append(hash, hexBinToAscii[((c&0xF0)>>4)], hexBinToAscii[c&0xF])
}
e.hash = string(hash)
e.size += hashLen
return e, nil return e, nil
} }
func parseGitTree(data <-chan byte) (tree, error) { func parseGitTree(data <-chan byte) (tree, error) {
return tree{}, nil hdr, err := parseGitMsg(data)
if err != nil {
return tree{}, err
}
// max capacity to length of hash
t := tree{items: make([]tree_entry, 0, hdr.size/len(hdr.hash))}
for parsedLen := 0; parsedLen+1 < hdr.size; {
entry, err := parseTreeEntry(data, len(hdr.hash)/2)
if err != nil {
return tree{}, nil
}
t.items = append(t.items, entry)
parsedLen += entry.size
}
return t, nil
} }
func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, headId string) (string, bool) { func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, commitId string) (string, bool) {
if e.Error != nil { if e.Error != nil {
return "", false return "", false
} }
data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)} data_in, data_out := ChanIO{make(chan byte, 256)}, ChanIO{make(chan byte, 70)}
var commitId string var subCommitId string
var foundLock sync.Mutex var foundLock sync.Mutex
foundLock.Lock() foundLock.Lock()
@@ -399,7 +447,8 @@ func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, headId string) (
defer foundLock.Unlock() defer foundLock.Unlock()
defer close(data_out.ch) defer close(data_out.ch)
data_out.Write([]byte("HEAD\n")) data_out.Write([]byte(commitId))
data_out.ch <- '\x00'
c, err := parseGitCommit(data_in.ch) c, err := parseGitCommit(data_in.ch)
if err != nil { if err != nil {
e.Error = err e.Error = err
@@ -407,7 +456,7 @@ func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, headId string) (
return return
} }
data_out.Write([]byte(c.Tree)) data_out.Write([]byte(c.Tree))
data_out.ch <- '\n' data_out.ch <- '\x00'
tree, err := parseGitTree(data_in.ch) tree, err := parseGitTree(data_in.ch)
if err != nil { if err != nil {
@@ -417,8 +466,8 @@ func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, headId string) (
} }
for _, te := range tree.items { for _, te := range tree.items {
if te.name == packageName { if te.name == packageName && te.isSubmodule() {
commitId = te.hash subCommitId = te.hash
return return
} }
} }
@@ -431,5 +480,5 @@ func (e *RequestHandler) GitSubmoduleCommitId(cwd, packageName, headId string) (
e.Log("command run: %v", cmd.Run()) e.Log("command run: %v", cmd.Run())
foundLock.Lock() foundLock.Lock()
return commitId, len(commitId) == len(headId) return subCommitId, len(subCommitId) == len(commitId)
} }

View File

@@ -84,13 +84,13 @@ func TestGitMsgParsing(t *testing.T) {
func TestGitCommitParsing(t *testing.T) { func TestGitCommitParsing(t *testing.T) {
t.Run("parse valid commit message", func(t *testing.T) { t.Run("parse valid commit message", func(t *testing.T) {
const commitData = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99 commit 254\000"+ const commitData = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f99 commit 254\000" +
`tree e20033df9f18780756ba4a96dbc7eb1a626253961039cb674156f266ba7a4e53 `tree e20033df9f18780756ba4a96dbc7eb1a626253961039cb674156f266ba7a4e53
parent 429cc2fe02170ca5668f0461928c7e7430c7a17cd64ac298286d7162572a7703 parent 429cc2fe02170ca5668f0461928c7e7430c7a17cd64ac298286d7162572a7703
author Adam Majer <amajer@suse.com> 1720709149 +0200 author Adam Majer <amajer@suse.com> 1720709149 +0200
committer Adam Majer <amajer@suse.com> 1720709149 +0200 committer Adam Majer <amajer@suse.com> 1720709149 +0200
.`+"\000" .` + "\000"
ch := make(chan byte, 5000) ch := make(chan byte, 5000)
for _, b := range []byte(commitData) { for _, b := range []byte(commitData) {
ch <- b ch <- b
@@ -111,8 +111,8 @@ committer Adam Majer <amajer@suse.com> 1720709149 +0200
}) })
t.Run("parse multiline headers", func(t *testing.T) { t.Run("parse multiline headers", func(t *testing.T) {
const commitData = "cae5831ab48470ff060a5aaa12eb6e5a7acaf91e commit 1492\x00" + const commitData = "cae5831ab48470ff060a5aaa12eb6e5a7acaf91e commit 1492\x00" +
`tree 1f9c8fe8099615d6d3921528402ac53f09213b02 `tree 1f9c8fe8099615d6d3921528402ac53f09213b02
parent e08a654fae0ecc91678819e0b62a2e014bad3339 parent e08a654fae0ecc91678819e0b62a2e014bad3339
author Yagiz Nizipli <yagiz@nizipli.com> 1720967314 -0400 author Yagiz Nizipli <yagiz@nizipli.com> 1720967314 -0400
committer GitHub <noreply@github.com> 1720967314 +0200 committer GitHub <noreply@github.com> 1720967314 +0200
@@ -165,7 +165,7 @@ Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"
}) })
t.Run("parse tree object", func(t *testing.T) { t.Run("parse tree object", func(t *testing.T) {
const treeData = "\x31\x31\x34\x31\x32\x39\x32\x30\x34\x38\x36\x38\x62\x30\x38\x65\x35\x36\x65\x39\x61\x66\x30\x64\x32\x39\x66\x37\x38\x36\x33\x34\x34\x37\x64\x32\x31\x36\x61\x62\x31\x35\x37\x32\x31\x30\x66\x65\x64\x37\x63\x36\x32\x37\x31\x64\x64\x35\x31\x30\x66\x35\x36\x62\x20\x74\x72\x65\x65\x20\x32\x30\x35\x0a\x34\x30\x30\x30\x30\x20\x62\x6f\x74\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\x81\xac\x2e\xbd\x40\x77\xcb\x63\xbf\x40\x8c\xf8\xbc\xcd\x6f\xbe\x06\x0d\xfa\xd7\x45\x16\x85\x4f\xd0\xa0\x67\xb4\x21\x39\x11\x84\x34\x30\x30\x30\x30\x20\x6f\x62\x73\x2d\x73\x74\x61\x67\x69\x6e\x67\x2d\x62\x6f\x74\x00\x79\x77\x8b\x28\x7d\x37\x10\x59\xb9\x71\x28\x36\xed\x20\x31\x5f\xfb\xe1\xed\xb5\xba\x4f\x5e\xbb\x65\x65\x68\x23\x77\x32\x58\xfe\x34\x30\x30\x30\x30\x20\x70\x72\x2d\x72\x65\x76\x69\x65\x77\x00\x31\x6a\x4a\x1e\x67\xbb\xdd\x21\x89\xa4\x46\xf7\x62\x75\x60\x84\x73\x28\x6f\xb7\x3c\x51\x7f\x4a\x14\xa2\x28\xf9\x6e\x0b\xa7\x95\x34\x30\x30\x30\x30\x20\x70\x72\x6a\x67\x69\x74\x2d\x75\x70\x64\x61\x74\x65\x72\x00\xb4\x0b\x1c\xf5\xfb\xec\x9a\xb2\x9f\x48\x3e\x21\x18\x0d\x51\xb7\x98\x6e\x21\x99\x74\x84\x67\x71\x41\x24\x42\xfc\xc9\x04\x12\x99\x0a" const treeData = "\x31\x61\x30\x35\x64\x62\x37\x33\x36\x39\x33\x37\x34\x33\x30\x65\x31\x38\x64\x66\x34\x33\x61\x32\x37\x61\x39\x38\x30\x30\x31\x30\x31\x32\x65\x31\x65\x64\x32\x30\x34\x38\x32\x39\x38\x36\x37\x31\x32\x38\x66\x32\x63\x65\x38\x34\x30\x36\x62\x35\x63\x66\x63\x39\x20\x74\x72\x65\x65\x20\x32\x30\x35\x00\x34\x30\x30\x30\x30\x20\x62\x6f\x74\x73\x2d\x63\x6f\x6d\x6d\x6f\x6e\x00\x93\x17\xaa\x47\xf6\xea\x37\xe8\xbc\xe2\x80\x77\x57\x90\xf4\xa8\x01\xd7\xe3\x70\x2f\x84\xfb\xe1\xb0\x0e\x4a\x2c\x1c\x75\x2c\x2b\x34\x30\x30\x30\x30\x20\x6f\x62\x73\x2d\x73\x74\x61\x67\x69\x6e\x67\x2d\x62\x6f\x74\x00\x79\x77\x8b\x28\x7d\x37\x10\x59\xb9\x71\x28\x36\xed\x20\x31\x5f\xfb\xe1\xed\xb5\xba\x4f\x5e\xbb\x65\x65\x68\x23\x77\x32\x58\xfe\x34\x30\x30\x30\x30\x20\x70\x72\x2d\x72\x65\x76\x69\x65\x77\x00\x36\x0d\x45\xcb\x76\xb8\x93\xb3\x21\xba\xfa\xd5\x00\x9d\xfc\x59\xab\x88\xc1\x3c\x81\xcb\x48\x5a\xe0\x29\x29\x0f\xe3\x6b\x3c\x5e\x34\x30\x30\x30\x30\x20\x70\x72\x6a\x67\x69\x74\x2d\x75\x70\x64\x61\x74\x65\x72\x00\xb4\x0b\x1c\xf5\xfb\xec\x9a\xb2\x9f\x48\x3e\x21\x18\x0d\x51\xb7\x98\x6e\x21\x99\x74\x84\x67\x71\x41\x24\x42\xfc\xc9\x04\x12\x99\x00"
ch := make(chan byte, 1000) ch := make(chan byte, 1000)
for _, b := range []byte(treeData) { for _, b := range []byte(treeData) {
@@ -179,9 +179,11 @@ Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"
} }
found := false found := false
t.Log(tree.items)
for _, item := range tree.items { for _, item := range tree.items {
if item.name == "bots-common" && item.hash == "81ac2ebd4077cb63bf408cf8bccd6fbe060dfad74516854fd0a067b421391184" && item.mode == 0o40000 { if item.name == "bots-common" && item.hash == "9317aa47f6ea37e8bce280775790f4a801d7e3702f84fbe1b00e4a2c1c752c2b" && item.isTree() {
found = true found = true
t.Log("found")
break break
} }
} }
@@ -207,7 +209,7 @@ Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com>` + "\x00"
found := false found := false
for _, item := range tree.items { for _, item := range tree.items {
t.Log(item) t.Log(item)
if item.name == "nodejs22" && item.hash == "873a323b262ebb3bd77b2592b2e11bdd08dbc721cbf4ac9f97637e58e1fffce7" { if item.name == "nodejs22" && item.hash == "873a323b262ebb3bd77b2592b2e11bdd08dbc721cbf4ac9f97637e58e1fffce7" && item.isSubmodule() {
found = true found = true
break break
} }

View File

@@ -5,6 +5,7 @@ import (
"path" "path"
"src.opensuse.org/autogits/common" "src.opensuse.org/autogits/common"
"src.opensuse.org/autogits/common/gitea-generated/models"
) )
const ( const (
@@ -24,6 +25,22 @@ func processPrjGitPullRequestSync(h *common.RequestHandler) error {
return nil return nil
} }
func prGitBranchNameForPR(req *common.PullRequestAction) string {
return fmt.Sprintf("PR_%s#%d", req.Repository.Name, req.Pull_Request.Number)
}
func updateOrCreatePRBranch(h *common.RequestHandler, prjGit *models.Repository, commitMsg, branchName string) {
req := h.Data.(*common.PullRequestAction)
h.GitExec("", "clone", "--depth", "1", prjGit.SSHURL, common.DefaultGitPrj)
h.GitExec(common.DefaultGitPrj, "checkout", "-B", branchName, prjGit.DefaultBranch)
h.GitExec(common.DefaultGitPrj, "submodule", "update", "--init", "--checkout", "--depth", "1", req.Repository.Name)
h.GitExec(path.Join(common.DefaultGitPrj, req.Repository.Name), "fetch", "--depth", "1", "origin", req.Pull_Request.Head.Sha)
h.GitExec(path.Join(common.DefaultGitPrj, req.Repository.Name), "checkout", req.Pull_Request.Head.Sha)
h.GitExec(common.DefaultGitPrj, "commit", "-a", "-m", commitMsg)
h.GitExec(common.DefaultGitPrj, "push", "-f", "origin", branchName)
}
func processPullRequestSync(h *common.RequestHandler) error { func processPullRequestSync(h *common.RequestHandler) error {
req := h.Data.(*common.PullRequestAction) req := h.Data.(*common.PullRequestAction)
@@ -36,9 +53,26 @@ func processPullRequestSync(h *common.RequestHandler) error {
prjPr := h.GetAssociatedPrjGitPR(req) prjPr := h.GetAssociatedPrjGitPR(req)
h.GitExec("", "clone", "--branch", prjPr.Head.Name, "--depth", "1", prjPr.Head.Repo.SSHURL, common.DefaultGitPrj) h.GitExec("", "clone", "--branch", prjPr.Head.Name, "--depth", "1", prjPr.Head.Repo.SSHURL, common.DefaultGitPrj)
commitId := h.GitSubmoduleCommitId(common.DefaultGitPrj, req.Repository.Name) commitId, ok := h.GitSubmoduleCommitId(common.DefaultGitPrj, req.Repository.Name, prjPr.Head.Ref)
return nil if !ok {
return fmt.Errorf("Cannot fetch submodule commit id in prjgit for '%s'", req.Repository.Name)
}
// nothing changed, still in sync
if commitId == req.Pull_Request.Head.Ref {
return nil
}
commitMsg := fmt.Sprintf(`Sync PR
Update to %s`, req.Pull_Request.Head.Sha)
// we need to update prjgit PR with the new head hash
branchName := prGitBranchNameForPR(req)
updateOrCreatePRBranch(h, prjPr.Base.Repo, commitMsg, branchName)
return h.Error
} }
func processPullRequestOpened(h *common.RequestHandler) error { func processPullRequestOpened(h *common.RequestHandler) error {
@@ -50,7 +84,7 @@ func processPullRequestOpened(h *common.RequestHandler) error {
} }
// create PrjGit branch for buidling the pull request // create PrjGit branch for buidling the pull request
branchName := fmt.Sprintf("PR_%s#%d", req.Repository.Name, req.Pull_Request.Number) branchName := prGitBranchNameForPR(req)
commitMsg := fmt.Sprintf(`auto-created for %s commitMsg := fmt.Sprintf(`auto-created for %s
This commit was autocreated by %s This commit was autocreated by %s
@@ -64,13 +98,7 @@ PullRequest: %s/%s#%d`, req.Repository.Owner.Username,
return h.Error return h.Error
} }
h.GitExec("", "clone", "--depth", "1", prjGit.SSHURL, common.DefaultGitPrj) updateOrCreatePRBranch(h, prjGit, commitMsg, branchName)
h.GitExec(common.DefaultGitPrj, "checkout", "-B", branchName, prjGit.DefaultBranch)
h.GitExec(common.DefaultGitPrj, "submodule", "update", "--init", "--checkout", "--depth", "1", req.Repository.Name)
h.GitExec(path.Join(common.DefaultGitPrj, req.Repository.Name), "fetch", "--depth", "1", "origin", req.Pull_Request.Head.Sha)
h.GitExec(path.Join(common.DefaultGitPrj, req.Repository.Name), "checkout", req.Pull_Request.Head.Sha)
h.GitExec(common.DefaultGitPrj, "commit", "-a", "-m", commitMsg)
h.GitExec(common.DefaultGitPrj, "push", "-f", "origin", branchName)
PR := h.CreatePullRequest(prjGit, branchName, prjGit.DefaultBranch, PR := h.CreatePullRequest(prjGit, branchName, prjGit.DefaultBranch,
fmt.Sprintf("Forwarded PR: %s", req.Repository.Name), fmt.Sprintf("Forwarded PR: %s", req.Repository.Name),
@@ -88,7 +116,7 @@ referencing the following pull request:
// request build review // request build review
h.RequestReviews(PR, common.Bot_BuildReview) h.RequestReviews(PR, common.Bot_BuildReview)
return nil return h.Error
} }
func processPullRequest(h *common.RequestHandler) error { func processPullRequest(h *common.RequestHandler) error {