Compare commits
1 Commits
main
...
submodulem
Author | SHA256 | Date | |
---|---|---|---|
b6bb7f9968 |
296
common/git_parser.go
Normal file
296
common/git_parser.go
Normal file
@@ -0,0 +1,296 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
GitStatus_Untracked = 0
|
||||
GitStatus_Modified = 1
|
||||
GitStatus_Ignored = 2
|
||||
GitStatus_Unmerged = 3 // States[0..3] -- Stage1, Stage2, Stage3 of merge objects
|
||||
GitStatus_Renamed = 4 // orig name in States[0]
|
||||
)
|
||||
|
||||
type GitStatusData struct {
|
||||
Path string
|
||||
Status int
|
||||
States [3]string
|
||||
|
||||
/*
|
||||
<sub> A 4 character field describing the submodule state.
|
||||
"N..." when the entry is not a submodule.
|
||||
"S<c><m><u>" when the entry is a submodule.
|
||||
<c> is "C" if the commit changed; otherwise ".".
|
||||
<m> is "M" if it has tracked changes; otherwise ".".
|
||||
<u> is "U" if there are untracked changes; otherwise ".".
|
||||
*/
|
||||
SubmoduleChanges string
|
||||
}
|
||||
|
||||
func parseGit_HexString(data io.ByteReader) (string, error) {
|
||||
str := make([]byte, 0, 32)
|
||||
for {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch {
|
||||
case c == 0 || c == ' ':
|
||||
return string(str), nil
|
||||
case c >= 'a' && c <= 'f':
|
||||
case c >= 'A' && c <= 'F':
|
||||
case c >= '0' && c <= '9':
|
||||
default:
|
||||
return "", errors.New("Invalid character in hex string:" + string(c))
|
||||
}
|
||||
str = append(str, c)
|
||||
}
|
||||
}
|
||||
func parseGit_String(data io.ByteReader) (string, error) {
|
||||
str := make([]byte, 0, 100)
|
||||
for {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return "", errors.New("Unexpected EOF. Expected NUL string term")
|
||||
}
|
||||
if c == 0 || c == ' ' {
|
||||
return string(str), nil
|
||||
}
|
||||
str = append(str, c)
|
||||
}
|
||||
}
|
||||
|
||||
func parseGit_StringWithSpace(data io.ByteReader) (string, error) {
|
||||
str := make([]byte, 0, 100)
|
||||
for {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return "", errors.New("Unexpected EOF. Expected NUL string term")
|
||||
}
|
||||
if c == 0 {
|
||||
return string(str), nil
|
||||
}
|
||||
str = append(str, c)
|
||||
}
|
||||
}
|
||||
|
||||
func skipGitStatusEntry(data io.ByteReader, skipSpaceLen int) error {
|
||||
for skipSpaceLen > 0 {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == ' ' {
|
||||
skipSpaceLen--
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
||||
ret := GitStatusData{}
|
||||
statusType, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch statusType {
|
||||
case '1':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 8); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Modified
|
||||
ret.Path, err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case '2':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 9); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Renamed
|
||||
ret.Path, err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.States[0], err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case '?':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Untracked
|
||||
ret.Path, err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case '!':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Ignored
|
||||
ret.Path, err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 'u':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.SubmoduleChanges, err = parseGit_String(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = skipGitStatusEntry(data, 4); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ret.States[0], err = parseGit_HexString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.States[1], err = parseGit_HexString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.States[2], err = parseGit_HexString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Unmerged
|
||||
ret.Path, err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("Invalid status type" + string(statusType))
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func parseGitStatusData(data io.ByteReader) (Data, error) {
|
||||
ret := make([]GitStatusData, 0, 10)
|
||||
for {
|
||||
data, err := parseSingleStatusEntry(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if data == nil {
|
||||
break
|
||||
}
|
||||
|
||||
ret = append(ret, *data)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
type Data interface{}
|
||||
|
||||
type CommitStatus int
|
||||
|
||||
const (
|
||||
Add CommitStatus = iota
|
||||
Rm
|
||||
Copy
|
||||
Modify
|
||||
Rename
|
||||
TypeChange
|
||||
Unmerged
|
||||
Unknown
|
||||
)
|
||||
|
||||
type GitDiffRawData struct {
|
||||
SrcMode, DstMode string
|
||||
SrcCommit, DstCommit string
|
||||
Status CommitStatus
|
||||
Src, Dst string
|
||||
}
|
||||
|
||||
func parseGit_DiffIndexStatus(data io.ByteReader, d *GitDiffRawData) error {
|
||||
b, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch b {
|
||||
case 'A':
|
||||
d.Status = Add
|
||||
case 'C':
|
||||
d.Status = Copy
|
||||
case 'D':
|
||||
d.Status = Rm
|
||||
case 'M':
|
||||
d.Status = Modify
|
||||
case 'R':
|
||||
d.Status = Rename
|
||||
case 'T':
|
||||
d.Status = TypeChange
|
||||
case 'U':
|
||||
d.Status = Unmerged
|
||||
case 'X':
|
||||
return fmt.Errorf("Unexpected unknown change type. This is a git bug")
|
||||
}
|
||||
_, err = parseGit_StringWithSpace(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseSingleGitDiffIndexRawData(data io.ByteReader) (*GitDiffRawData, error) {
|
||||
var ret GitDiffRawData
|
||||
|
||||
b, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b != ':' {
|
||||
return nil, fmt.Errorf("Expected ':' but got '%s'", string(b))
|
||||
}
|
||||
|
||||
if ret.SrcMode, err = parseGit_String(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.DstMode, err = parseGit_String(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.Src, err = parseGit_String(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.Dst, err = parseGit_String(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = parseGit_DiffIndexStatus(data, &ret); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Dst = ret.Src
|
||||
switch ret.Status {
|
||||
case Copy, Rename:
|
||||
if ret.Src, err = parseGit_StringWithSpace(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func parseGitDiffIndexRawData(data io.ByteReader) (Data, error) {
|
||||
ret := make([]GitDiffRawData, 0, 10)
|
||||
for {
|
||||
data, err := parseSingleGitDiffIndexRawData(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if data == nil {
|
||||
break
|
||||
}
|
||||
|
||||
ret = append(ret, *data)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
@@ -19,9 +19,7 @@ package common
|
||||
*/
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -40,6 +38,10 @@ type GitSubmoduleLister interface {
|
||||
GitSubmoduleCommitId(cwd, packageName, commitId string) (subCommitId string, valid bool)
|
||||
}
|
||||
|
||||
type GitSubmoduleFileConflictResolver interface {
|
||||
GitResolveSubmoduleFileConflict(cwd string) error
|
||||
}
|
||||
|
||||
type GitStatusLister interface {
|
||||
GitStatus(cwd string) ([]GitStatusData, error)
|
||||
}
|
||||
@@ -70,6 +72,7 @@ type Git interface {
|
||||
GitExecQuietOrPanic(cwd string, params ...string)
|
||||
|
||||
GitDiffLister
|
||||
GitSubmoduleFileConflictResolver
|
||||
}
|
||||
|
||||
type GitHandlerImpl struct {
|
||||
@@ -247,7 +250,7 @@ func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) (string, error
|
||||
|
||||
e.GitExecOrPanic(repo, "fetch", "--prune", remoteName, remoteBranch)
|
||||
}
|
||||
/*
|
||||
/*
|
||||
refsBytes, err := os.ReadFile(path.Join(e.GitPath, repo, ".git/refs/remotes", remoteName, "HEAD"))
|
||||
if err != nil {
|
||||
LogError("Cannot read HEAD of remote", remoteName)
|
||||
@@ -266,7 +269,7 @@ func (e *GitHandlerImpl) GitClone(repo, branch, remoteUrl string) (string, error
|
||||
LogDebug("remoteRef", remoteRef)
|
||||
LogDebug("branch", branch)
|
||||
}
|
||||
*/
|
||||
*/
|
||||
args := []string{"fetch", "--prune", remoteName, branch}
|
||||
if strings.TrimSpace(e.GitExecWithOutputOrPanic(repo, "rev-parse", "--is-shallow-repository")) == "true" {
|
||||
args = slices.Insert(args, 1, "--unshallow")
|
||||
@@ -923,193 +926,10 @@ func (e *GitHandlerImpl) GitSubmoduleCommitId(cwd, packageName, commitId string)
|
||||
return subCommitId, len(subCommitId) > 0
|
||||
}
|
||||
|
||||
const (
|
||||
GitStatus_Untracked = 0
|
||||
GitStatus_Modified = 1
|
||||
GitStatus_Ignored = 2
|
||||
GitStatus_Unmerged = 3 // States[0..3] -- Stage1, Stage2, Stage3 of merge objects
|
||||
GitStatus_Renamed = 4 // orig name in States[0]
|
||||
)
|
||||
|
||||
type GitStatusData struct {
|
||||
Path string
|
||||
Status int
|
||||
States [3]string
|
||||
|
||||
/*
|
||||
<sub> A 4 character field describing the submodule state.
|
||||
"N..." when the entry is not a submodule.
|
||||
"S<c><m><u>" when the entry is a submodule.
|
||||
<c> is "C" if the commit changed; otherwise ".".
|
||||
<m> is "M" if it has tracked changes; otherwise ".".
|
||||
<u> is "U" if there are untracked changes; otherwise ".".
|
||||
*/
|
||||
SubmoduleChanges string
|
||||
}
|
||||
|
||||
func parseGitStatusHexString(data io.ByteReader) (string, error) {
|
||||
str := make([]byte, 0, 32)
|
||||
for {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch {
|
||||
case c == 0 || c == ' ':
|
||||
return string(str), nil
|
||||
case c >= 'a' && c <= 'f':
|
||||
case c >= 'A' && c <= 'F':
|
||||
case c >= '0' && c <= '9':
|
||||
default:
|
||||
return "", errors.New("Invalid character in hex string:" + string(c))
|
||||
}
|
||||
str = append(str, c)
|
||||
}
|
||||
}
|
||||
func parseGitStatusString(data io.ByteReader) (string, error) {
|
||||
str := make([]byte, 0, 100)
|
||||
for {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return "", errors.New("Unexpected EOF. Expected NUL string term")
|
||||
}
|
||||
if c == 0 || c == ' ' {
|
||||
return string(str), nil
|
||||
}
|
||||
str = append(str, c)
|
||||
}
|
||||
}
|
||||
|
||||
func parseGitStatusStringWithSpace(data io.ByteReader) (string, error) {
|
||||
str := make([]byte, 0, 100)
|
||||
for {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return "", errors.New("Unexpected EOF. Expected NUL string term")
|
||||
}
|
||||
if c == 0 {
|
||||
return string(str), nil
|
||||
}
|
||||
str = append(str, c)
|
||||
}
|
||||
}
|
||||
|
||||
func skipGitStatusEntry(data io.ByteReader, skipSpaceLen int) error {
|
||||
for skipSpaceLen > 0 {
|
||||
c, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == ' ' {
|
||||
skipSpaceLen--
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseSingleStatusEntry(data io.ByteReader) (*GitStatusData, error) {
|
||||
ret := GitStatusData{}
|
||||
statusType, err := data.ReadByte()
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
switch statusType {
|
||||
case '1':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 8); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Modified
|
||||
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case '2':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 9); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Renamed
|
||||
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.States[0], err = parseGitStatusStringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case '?':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Untracked
|
||||
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case '!':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Ignored
|
||||
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 'u':
|
||||
var err error
|
||||
if err = skipGitStatusEntry(data, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.SubmoduleChanges, err = parseGitStatusString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = skipGitStatusEntry(data, 4); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ret.States[0], err = parseGitStatusHexString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.States[1], err = parseGitStatusHexString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ret.States[2], err = parseGitStatusHexString(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Status = GitStatus_Unmerged
|
||||
ret.Path, err = parseGitStatusStringWithSpace(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("Invalid status type" + string(statusType))
|
||||
}
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
func parseGitStatusData(data io.ByteReader) ([]GitStatusData, error) {
|
||||
ret := make([]GitStatusData, 0, 10)
|
||||
for {
|
||||
data, err := parseSingleStatusEntry(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if data == nil {
|
||||
break
|
||||
}
|
||||
|
||||
ret = append(ret, *data)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (e *GitHandlerImpl) GitStatus(cwd string) (ret []GitStatusData, err error) {
|
||||
LogDebug("getting git-status()")
|
||||
|
||||
cmd := exec.Command("/usr/bin/git", "status", "--porcelain=2", "-z")
|
||||
func (e *GitHandlerImpl) GitExecWithDataParse(cwd string, dataprocessor func(io.ByteReader) (Data, error), gitcmd string, args ...string) (Data, error) {
|
||||
LogDebug("getting", gitcmd)
|
||||
args = append([]string{gitcmd}, args...)
|
||||
cmd := exec.Command("/usr/bin/git", args...)
|
||||
cmd.Env = []string{
|
||||
"GIT_CEILING_DIRECTORIES=" + e.GitPath,
|
||||
"GIT_LFS_SKIP_SMUDGE=1",
|
||||
@@ -1126,7 +946,12 @@ func (e *GitHandlerImpl) GitStatus(cwd string) (ret []GitStatusData, err error)
|
||||
LogError("Error running command", cmd.Args, err)
|
||||
}
|
||||
|
||||
return parseGitStatusData(bufio.NewReader(bytes.NewReader(out)))
|
||||
return dataprocessor(bytes.NewReader(out))
|
||||
}
|
||||
|
||||
func (e *GitHandlerImpl) GitStatus(cwd string) (ret []GitStatusData, err error) {
|
||||
data, err := e.GitExecWithDataParse(cwd, parseGitStatusData, "status", "--porcelain=2", "-z")
|
||||
return data.([]GitStatusData), err
|
||||
}
|
||||
|
||||
func (e *GitHandlerImpl) GitDiff(cwd, base, head string) (string, error) {
|
||||
@@ -1151,3 +976,94 @@ func (e *GitHandlerImpl) GitDiff(cwd, base, head string) (string, error) {
|
||||
|
||||
return string(out), nil
|
||||
}
|
||||
|
||||
func (e *GitHandlerImpl) GitDiffIndex(cwd, commit string) ([]GitDiffRawData, error) {
|
||||
data, err := e.GitExecWithDataParse("diff-index", parseGitDiffIndexRawData, cwd, "diff-index", "-z", "--raw", "--full-index", "--submodule=short", "HEAD")
|
||||
return data.([]GitDiffRawData), err
|
||||
}
|
||||
|
||||
func (git *GitHandlerImpl) GitResolveSubmoduleFileConflict(cwd string) error {
|
||||
status, err := git.GitStatus(cwd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Status failed: %w", err)
|
||||
}
|
||||
|
||||
// we can only resolve conflicts with .gitmodules
|
||||
for _, s := range status {
|
||||
if s.Status == GitStatus_Unmerged {
|
||||
if s.Path != ".gitmodules" {
|
||||
return err
|
||||
}
|
||||
|
||||
submodules, err := git.GitSubmoduleList(cwd, "HEAD")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch submodules during merge resolution: %w", err)
|
||||
}
|
||||
|
||||
// We need to adjust the `submodules` list by the pending changes to the index
|
||||
|
||||
s1, err := git.GitExecWithOutput(cwd, "cat-file", "blob", s.States[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching data during .gitmodules merge resoulution: %w", err)
|
||||
}
|
||||
s2, err := git.GitExecWithOutput(cwd, "cat-file", "blob", s.States[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching data during .gitmodules merge resoulution: %w", err)
|
||||
}
|
||||
s3, err := git.GitExecWithOutput(cwd, "cat-file", "blob", s.States[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching data during .gitmodules merge resoulution: %w", err)
|
||||
}
|
||||
|
||||
subs1, err := ParseSubmodulesFile(strings.NewReader(s1))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing submodule file [%s] in merge: %w", s.States[0], err)
|
||||
}
|
||||
subs2, err := ParseSubmodulesFile(strings.NewReader(s2))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing submodule file [%s] in merge: %w", s.States[0], err)
|
||||
}
|
||||
subs3, err := ParseSubmodulesFile(strings.NewReader(s3))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing submodule file [%s] in merge: %w", s.States[0], err)
|
||||
}
|
||||
|
||||
for r := range submodules {
|
||||
LogError(r)
|
||||
}
|
||||
|
||||
// merge from subs3 (target), subs1 (orig), subs2 (2-nd base that is missing from target base)
|
||||
// this will update submodules
|
||||
mergedSubs := slices.Concat(subs1, subs2, subs3)
|
||||
|
||||
var filteredSubs []Submodule = make([]Submodule, 0, max(len(subs1), len(subs2), len(subs3)))
|
||||
nextSub:
|
||||
for subName := range submodules {
|
||||
|
||||
for i := range mergedSubs {
|
||||
if path.Base(mergedSubs[i].Path) == subName {
|
||||
filteredSubs = append(filteredSubs, mergedSubs[i])
|
||||
continue nextSub
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Cannot find submodule for path: %s", subName)
|
||||
}
|
||||
|
||||
out, err := os.Create(path.Join(git.GetPath(), cwd, ".gitmodules"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can't open .gitmodules for writing: %w", err)
|
||||
}
|
||||
if err = WriteSubmodules(filteredSubs, out); err != nil {
|
||||
return fmt.Errorf("Can't write .gitmodules: %w", err)
|
||||
}
|
||||
if out.Close(); err != nil {
|
||||
return fmt.Errorf("Can't close .gitmodules: %w", err)
|
||||
}
|
||||
|
||||
git.GitExecOrPanic(cwd, "add", ".gitmodules")
|
||||
git.GitExecOrPanic(cwd, "-c", "core.editor=true", "merge", "--continue")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime/debug"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -93,6 +94,93 @@ func TestGitClone(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubmoduleConflictResolution(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
checkout, merge string
|
||||
result string
|
||||
}{
|
||||
{
|
||||
name: "adding two submodules",
|
||||
checkout: "base_add_b1",
|
||||
merge: "base_add_b2",
|
||||
result: `[submodule "pkgA"]
|
||||
path = pkgA
|
||||
url = ../pkgA
|
||||
[submodule "pkgB"]
|
||||
path = pkgB
|
||||
url = ../pkgB
|
||||
[submodule "pkgC"]
|
||||
path = pkgC
|
||||
url = ../pkgC
|
||||
[submodule "pkgB1"]
|
||||
path = pkgB1
|
||||
url = ../pkgB1
|
||||
[submodule "pkgB2"]
|
||||
path = pkgB2
|
||||
url = ../pkgB2
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
d, err := os.MkdirTemp(os.TempDir(), "submoduletests")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := exec.Command(cwd + "/test_repo_setup.sh")
|
||||
cmd.Dir = d
|
||||
_, err = cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
gh, err := AllocateGitWorkTree(d, "test", "foo@example.com")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
success := true
|
||||
noErrorOrFail := func(t *testing.T, err error) {
|
||||
if err != nil {
|
||||
t.Fatal(string(debug.Stack()), err)
|
||||
}
|
||||
}
|
||||
for _, test := range tests {
|
||||
success = t.Run(test.name, func(t *testing.T) {
|
||||
git, err := gh.ReadExistingPath("prjgit")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
noErrorOrFail(t, git.GitExec("", "checkout", "-B", "test", "main"))
|
||||
noErrorOrFail(t, git.GitExec("", "merge", "base_add_b1"))
|
||||
err = git.GitExec("", "merge", "base_add_b2")
|
||||
if err == nil {
|
||||
t.Fatal("expected a conflict")
|
||||
}
|
||||
err = git.GitResolveSubmoduleFileConflict("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
data, err := os.ReadFile(git.GetPath() + "/.gitmodules")
|
||||
if err != nil {
|
||||
t.Fatal("Cannot read .gitmodules.", err)
|
||||
}
|
||||
|
||||
if string(data) != test.result {
|
||||
t.Error("Expected", test.result, "but have", string(data))
|
||||
}
|
||||
}) && success
|
||||
}
|
||||
|
||||
if success {
|
||||
os.RemoveAll(d)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGitMsgParsing(t *testing.T) {
|
||||
t.Run("tree message with size 56", func(t *testing.T) {
|
||||
const hdr = "f40888ea4515fe2e8eea617a16f5f50a45f652d894de3ad181d58de3aafb8f98 tree 56\x00"
|
||||
|
@@ -24,13 +24,11 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
transport "github.com/go-openapi/runtime/client"
|
||||
@@ -184,6 +182,7 @@ type Gitea interface {
|
||||
GiteaCommitStatusGetter
|
||||
GiteaCommitStatusSetter
|
||||
GiteaSetRepoOptions
|
||||
GiteaTimelineFetcher
|
||||
|
||||
GetNotifications(Type string, since *time.Time) ([]*models.NotificationThread, error)
|
||||
GetDoneNotifications(Type string, page int64) ([]*models.NotificationThread, error)
|
||||
@@ -200,32 +199,7 @@ type Gitea interface {
|
||||
GetCurrentUser() (*models.User, error)
|
||||
}
|
||||
|
||||
type GiteaHeaderInterceptor struct {
|
||||
Length int
|
||||
http.RoundTripper
|
||||
}
|
||||
|
||||
func (i *GiteaHeaderInterceptor) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
resp, err := i.RoundTripper.RoundTrip(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count_header := resp.Header["X-Total-Count"]
|
||||
if len(count_header) == 1 {
|
||||
i.Length, err = strconv.Atoi(resp.Header["X-Total-Count"][0])
|
||||
if err != nil {
|
||||
LogError("Converting X-Total-Count response header error", err)
|
||||
i.Length = -1
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
i.Length = -1
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
type GiteaTransport struct {
|
||||
headers *GiteaHeaderInterceptor
|
||||
transport *transport.Runtime
|
||||
client *apiclient.GiteaAPI
|
||||
}
|
||||
@@ -238,9 +212,7 @@ func AllocateGiteaTransport(giteaUrl string) Gitea {
|
||||
log.Panicln("Failed to parse gitea url:", err)
|
||||
}
|
||||
|
||||
r.headers = &GiteaHeaderInterceptor{RoundTripper: http.DefaultTransport}
|
||||
r.transport = transport.New(url.Host, apiclient.DefaultBasePath, [](string){url.Scheme})
|
||||
r.transport.Transport = r.headers
|
||||
r.transport.DefaultAuthentication = transport.BearerToken(giteaToken)
|
||||
|
||||
r.client = apiclient.New(r.transport, nil)
|
||||
@@ -315,9 +287,10 @@ func (gitea *GiteaTransport) ManualMergePR(org, repo string, num int64, commitid
|
||||
}
|
||||
|
||||
func (gitea *GiteaTransport) GetPullRequests(org, repo string) ([]*models.PullRequest, error) {
|
||||
var page int64
|
||||
var page, limit int64
|
||||
|
||||
prs := make([]*models.PullRequest, 0)
|
||||
limit = 20
|
||||
state := "open"
|
||||
|
||||
for {
|
||||
@@ -329,18 +302,16 @@ func (gitea *GiteaTransport) GetPullRequests(org, repo string) ([]*models.PullRe
|
||||
WithOwner(org).
|
||||
WithRepo(repo).
|
||||
WithState(&state).
|
||||
WithPage(&page),
|
||||
WithPage(&page).
|
||||
WithLimit(&limit),
|
||||
gitea.transport.DefaultAuthentication)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot fetch PR list for %s / %s : %w", org, repo, err)
|
||||
}
|
||||
|
||||
if len(req.Payload) == 0 {
|
||||
break
|
||||
}
|
||||
prs = slices.Concat(prs, req.Payload)
|
||||
if len(prs) >= gitea.headers.Length {
|
||||
if len(req.Payload) < int(limit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -349,23 +320,21 @@ func (gitea *GiteaTransport) GetPullRequests(org, repo string) ([]*models.PullRe
|
||||
}
|
||||
|
||||
func (gitea *GiteaTransport) GetCommitStatus(org, repo, hash string) ([]*models.CommitStatus, error) {
|
||||
var page int64
|
||||
page := int64(1)
|
||||
limit := int64(10)
|
||||
var res []*models.CommitStatus
|
||||
|
||||
for {
|
||||
page++
|
||||
r, err := gitea.client.Repository.RepoListStatuses(
|
||||
repository.NewRepoListStatusesParams().WithDefaults().WithOwner(org).WithRepo(repo).WithSha(hash).WithPage(&page),
|
||||
repository.NewRepoListStatusesParams().WithDefaults().WithOwner(org).WithRepo(repo).WithSha(hash).WithPage(&page).WithLimit(&limit),
|
||||
gitea.transport.DefaultAuthentication)
|
||||
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if len(r.Payload) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
res = append(res, r.Payload...)
|
||||
if len(res) >= gitea.headers.Length {
|
||||
if len(r.Payload) < int(limit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -408,18 +377,19 @@ func (gitea *GiteaTransport) GetRepository(org, pkg string) (*models.Repository,
|
||||
}
|
||||
|
||||
func (gitea *GiteaTransport) GetPullRequestReviews(org, project string, PRnum int64) ([]*models.PullReview, error) {
|
||||
limit := int64(20)
|
||||
var page int64
|
||||
var allReviews []*models.PullReview
|
||||
|
||||
for {
|
||||
page++
|
||||
reviews, err := gitea.client.Repository.RepoListPullReviews(
|
||||
repository.NewRepoListPullReviewsParams().
|
||||
WithDefaults().
|
||||
WithOwner(org).
|
||||
WithRepo(project).
|
||||
WithIndex(PRnum).
|
||||
WithPage(&page),
|
||||
WithPage(&page).
|
||||
WithLimit(&limit),
|
||||
gitea.transport.DefaultAuthentication,
|
||||
)
|
||||
|
||||
@@ -427,13 +397,11 @@ func (gitea *GiteaTransport) GetPullRequestReviews(org, project string, PRnum in
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(reviews.Payload) == 0 {
|
||||
break
|
||||
}
|
||||
allReviews = slices.Concat(allReviews, reviews.Payload)
|
||||
if len(allReviews) >= gitea.headers.Length {
|
||||
if len(reviews.Payload) < int(limit) {
|
||||
break
|
||||
}
|
||||
page++
|
||||
}
|
||||
|
||||
return allReviews, nil
|
||||
@@ -501,6 +469,7 @@ const (
|
||||
)
|
||||
|
||||
func (gitea *GiteaTransport) GetNotifications(Type string, since *time.Time) ([]*models.NotificationThread, error) {
|
||||
bigLimit := int64(20)
|
||||
ret := make([]*models.NotificationThread, 0, 100)
|
||||
|
||||
for page := int64(1); ; page++ {
|
||||
@@ -508,6 +477,7 @@ func (gitea *GiteaTransport) GetNotifications(Type string, since *time.Time) ([]
|
||||
WithDefaults().
|
||||
WithSubjectType([]string{Type}).
|
||||
WithStatusTypes([]string{"unread"}).
|
||||
WithLimit(&bigLimit).
|
||||
WithPage(&page)
|
||||
|
||||
if since != nil {
|
||||
@@ -520,11 +490,8 @@ func (gitea *GiteaTransport) GetNotifications(Type string, since *time.Time) ([]
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(list.Payload) == 0 {
|
||||
break
|
||||
}
|
||||
ret = slices.Concat(ret, list.Payload)
|
||||
if len(ret) >= gitea.headers.Length {
|
||||
if len(list.Payload) < int(bigLimit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -533,6 +500,7 @@ func (gitea *GiteaTransport) GetNotifications(Type string, since *time.Time) ([]
|
||||
}
|
||||
|
||||
func (gitea *GiteaTransport) GetDoneNotifications(Type string, page int64) ([]*models.NotificationThread, error) {
|
||||
limit := int64(20)
|
||||
t := true
|
||||
|
||||
if page <= 0 {
|
||||
@@ -543,6 +511,7 @@ func (gitea *GiteaTransport) GetDoneNotifications(Type string, page int64) ([]*m
|
||||
WithAll(&t).
|
||||
WithSubjectType([]string{Type}).
|
||||
WithStatusTypes([]string{"read"}).
|
||||
WithLimit(&limit).
|
||||
WithPage(&page),
|
||||
gitea.transport.DefaultAuthentication)
|
||||
if err != nil {
|
||||
@@ -595,12 +564,9 @@ func (gitea *GiteaTransport) GetOrganizationRepositories(orgName string) ([]*mod
|
||||
if len(ret.Payload) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
repos = append(repos, ret.Payload...)
|
||||
page++
|
||||
|
||||
if len(repos) >= gitea.headers.Length {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
@@ -814,18 +780,15 @@ func (gitea *GiteaTransport) GetTimeline(org, repo string, idx int64) ([]*models
|
||||
|
||||
resCount = len(res.Payload)
|
||||
LogDebug("page:", page, "len:", resCount)
|
||||
if resCount == 0 {
|
||||
break
|
||||
}
|
||||
page++
|
||||
|
||||
retData = append(retData, res.Payload...)
|
||||
if len(retData) >= gitea.headers.Length {
|
||||
break
|
||||
for _, d := range res.Payload {
|
||||
if d != nil {
|
||||
retData = append(retData, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
LogDebug("total results:", len(retData))
|
||||
retData = slices.DeleteFunc(retData, func(a *models.TimelineComment) bool { return a == nil })
|
||||
slices.SortFunc(retData, func(a, b *models.TimelineComment) int {
|
||||
return time.Time(b.Created).Compare(time.Time(a.Created))
|
||||
})
|
||||
|
78
common/pr.go
78
common/pr.go
@@ -4,8 +4,6 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
@@ -407,80 +405,8 @@ func (rs *PRSet) Merge(gitea GiteaReviewUnrequester, git Git) error {
|
||||
|
||||
err = git.GitExec(DefaultGitPrj, "merge", "--no-ff", "-m", msg, prjgit.Head.Sha)
|
||||
if err != nil {
|
||||
status, statusErr := git.GitStatus(DefaultGitPrj)
|
||||
if statusErr != nil {
|
||||
return fmt.Errorf("Failed to merge: %w . Status also failed: %w", err, statusErr)
|
||||
}
|
||||
|
||||
// we can only resolve conflicts with .gitmodules
|
||||
for _, s := range status {
|
||||
if s.Status == GitStatus_Unmerged {
|
||||
panic("Can't handle conflicts yet")
|
||||
if s.Path != ".gitmodules" {
|
||||
return err
|
||||
}
|
||||
|
||||
submodules, err := git.GitSubmoduleList(DefaultGitPrj, "MERGE_HEAD")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to fetch submodules during merge resolution: %w", err)
|
||||
}
|
||||
s1, err := git.GitExecWithOutput(DefaultGitPrj, "cat-file", "blob", s.States[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching data during .gitmodules merge resoulution: %w", err)
|
||||
}
|
||||
s2, err := git.GitExecWithOutput(DefaultGitPrj, "cat-file", "blob", s.States[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching data during .gitmodules merge resoulution: %w", err)
|
||||
}
|
||||
s3, err := git.GitExecWithOutput(DefaultGitPrj, "cat-file", "blob", s.States[2])
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed fetching data during .gitmodules merge resoulution: %w", err)
|
||||
}
|
||||
|
||||
subs1, err := ParseSubmodulesFile(strings.NewReader(s1))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing submodule file [%s] in merge: %w", s.States[0], err)
|
||||
}
|
||||
subs2, err := ParseSubmodulesFile(strings.NewReader(s2))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing submodule file [%s] in merge: %w", s.States[0], err)
|
||||
}
|
||||
subs3, err := ParseSubmodulesFile(strings.NewReader(s3))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed parsing submodule file [%s] in merge: %w", s.States[0], err)
|
||||
}
|
||||
|
||||
// merge from subs3 (target), subs1 (orig), subs2 (2-nd base that is missing from target base)
|
||||
// this will update submodules
|
||||
mergedSubs := slices.Concat(subs1, subs2, subs3)
|
||||
|
||||
var filteredSubs []Submodule = make([]Submodule, 0, max(len(subs1), len(subs2), len(subs3)))
|
||||
nextSub:
|
||||
for subName := range submodules {
|
||||
|
||||
for i := range mergedSubs {
|
||||
if path.Base(mergedSubs[i].Path) == subName {
|
||||
filteredSubs = append(filteredSubs, mergedSubs[i])
|
||||
continue nextSub
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("Cannot find submodule for path: %s", subName)
|
||||
}
|
||||
|
||||
out, err := os.Create(path.Join(git.GetPath(), DefaultGitPrj, ".gitmodules"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can't open .gitmodules for writing: %w", err)
|
||||
}
|
||||
if err = WriteSubmodules(filteredSubs, out); err != nil {
|
||||
return fmt.Errorf("Can't write .gitmodules: %w", err)
|
||||
}
|
||||
if out.Close(); err != nil {
|
||||
return fmt.Errorf("Can't close .gitmodules: %w", err)
|
||||
}
|
||||
|
||||
git.GitExecOrPanic(DefaultGitPrj, "add", ".gitmodules")
|
||||
git.GitExecOrPanic(DefaultGitPrj, "-c", "core.editor=true", "merge", "--continue")
|
||||
}
|
||||
if resolveError := git.GitResolveSubmoduleFileConflict(DefaultGitPrj); resolveError != nil {
|
||||
return fmt.Errorf("Merge failed. (%w): %w", err, resolveError)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,8 +15,9 @@ import (
|
||||
"src.opensuse.org/autogits/common/gitea-generated/models"
|
||||
mock_common "src.opensuse.org/autogits/common/mock"
|
||||
)
|
||||
|
||||
/*
|
||||
func TestCockpit(t *testing.T) {
|
||||
func TestCockpit(t *testing.T) {
|
||||
common.SetLoggingLevel(common.LogLevelDebug)
|
||||
gitea := common.AllocateGiteaTransport("https://src.opensuse.org")
|
||||
tl, err := gitea.GetTimeline("cockpit", "cockpit", 29)
|
||||
@@ -30,7 +31,7 @@ func TestCockpit(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Error(r)
|
||||
}
|
||||
}
|
||||
*/
|
||||
func reviewsToTimeline(reviews []*models.PullReview) []*models.TimelineComment {
|
||||
timeline := make([]*models.TimelineComment, len(reviews))
|
||||
@@ -939,6 +940,7 @@ func TestPRMerge(t *testing.T) {
|
||||
pr: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Sha: "e8b0de43d757c96a9d2c7101f4bff404e322f53a1fa4041fb85d646110c38ad4", // "base_add_b1"
|
||||
Name: "master",
|
||||
Repo: &models.Repository{
|
||||
Name: "prj",
|
||||
Owner: &models.User{
|
||||
@@ -959,6 +961,7 @@ func TestPRMerge(t *testing.T) {
|
||||
pr: &models.PullRequest{
|
||||
Base: &models.PRBranchInfo{
|
||||
Sha: "4fbd1026b2d7462ebe9229a49100c11f1ad6555520a21ba515122d8bc41328a8",
|
||||
Name: "master",
|
||||
Repo: &models.Repository{
|
||||
Name: "prj",
|
||||
Owner: &models.User{
|
||||
@@ -978,6 +981,7 @@ func TestPRMerge(t *testing.T) {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
ctl := gomock.NewController(t)
|
||||
mock := mock_common.NewMockGiteaPRTimelineFetcher(ctl)
|
||||
|
||||
reviewUnrequestMock := mock_common.NewMockGiteaReviewUnrequester(ctl)
|
||||
|
||||
reviewUnrequestMock.EXPECT().UnrequestReview(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
|
||||
|
@@ -20,7 +20,6 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -269,32 +268,6 @@ func main() {
|
||||
|
||||
res.Write(BuildStatusSvg(nil, &common.PackageBuildStatus{Package: pkg, Code: "unknown"}))
|
||||
})
|
||||
http.HandleFunc("GET /search", func(res http.ResponseWriter, req *http.Request) {
|
||||
common.LogInfo("GET /serach?" + req.URL.RawQuery)
|
||||
queries := req.URL.Query()
|
||||
if !queries.Has("q") {
|
||||
res.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
|
||||
names := queries["q"]
|
||||
if len(names) < 1 || len(names) > 10 {
|
||||
res.WriteHeader(400)
|
||||
return
|
||||
}
|
||||
|
||||
packages := FindPackages(names)
|
||||
data, err := json.MarshalIndent(packages, "", " ")
|
||||
if err != nil {
|
||||
res.WriteHeader(500)
|
||||
common.LogError("Error in marshalling data.", err)
|
||||
return
|
||||
}
|
||||
|
||||
res.Write(data)
|
||||
res.WriteHeader(200)
|
||||
})
|
||||
|
||||
http.HandleFunc("GET /buildlog/{Project}/{Package}/{Repository}/{Arch}", func(res http.ResponseWriter, req *http.Request) {
|
||||
prj := req.PathValue("Project")
|
||||
pkg := req.PathValue("Package")
|
||||
|
@@ -110,33 +110,6 @@ func FindRepoResults(project, repo string) []*common.BuildResult {
|
||||
return ret
|
||||
}
|
||||
|
||||
func FindPackages(search_terms []string) []string {
|
||||
RepoStatusLock.RLock()
|
||||
defer RepoStatusLock.RUnlock()
|
||||
|
||||
data := make([]string, 0, 100)
|
||||
for _, repo := range RepoStatus {
|
||||
for _, status := range repo.Status {
|
||||
pkg := status.Package
|
||||
match := true
|
||||
for _, term := range search_terms {
|
||||
match = match && strings.Contains(pkg, term)
|
||||
}
|
||||
|
||||
if match {
|
||||
entry := repo.Project + "/" + repo.Status[0].Package
|
||||
if idx, found := slices.BinarySearch(data, entry); !found {
|
||||
data = slices.Insert(data, idx, entry)
|
||||
if len(data) >= 100 {
|
||||
return data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func FindAndUpdateProjectResults(project string) []*common.BuildResult {
|
||||
res := FindProjectResults(project)
|
||||
wg := &sync.WaitGroup{}
|
||||
|
@@ -317,15 +317,10 @@ func (pr *PRProcessor) UpdatePrjGitPR(prset *common.PRSet) error {
|
||||
}
|
||||
|
||||
PrjGitTitle, PrjGitBody := PrjGitDescription(prset)
|
||||
if PrjGitPR.PR.User.UserName == CurrentUser.UserName {
|
||||
if PrjGitPR.PR.Title != PrjGitTitle || PrjGitPR.PR.Body != PrjGitBody {
|
||||
common.LogDebug("New title:", PrjGitTitle)
|
||||
common.LogDebug(PrjGitBody)
|
||||
}
|
||||
} else {
|
||||
// TODO: find our first comment in timeline
|
||||
|
||||
}
|
||||
|
||||
if !common.IsDryRun {
|
||||
if headCommit != newHeadCommit {
|
||||
|
Reference in New Issue
Block a user