Skip to content

Commit 8baccf2

Browse files
committed
Merge branch 'main' into lunny/introduce_combined_status
2 parents 3a2ae5c + 0cec4b8 commit 8baccf2

File tree

40 files changed

+533
-472
lines changed

40 files changed

+533
-472
lines changed

models/git/combined_status.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ func InsertOrUpdateCombinedStatus(ctx context.Context, repoID int64, sha string)
9494
if err != nil {
9595
return err
9696
}
97+
// it guarantees that commitStatuses is not empty because this function is always called after a commit status is created
98+
if len(commitStatuses) == 0 {
99+
setting.PanicInDevOrTesting("no commit statuses found for repo %d and sha %s", repoID, sha)
100+
}
97101
combinedStatus := CalcCombinedStatus(commitStatuses)
98102

99103
// mysql will return 0 when update a record which state hasn't been changed which behaviour is different from other database,

models/user/search.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Sess
137137

138138
// SearchUsers takes options i.e. keyword and part of user name to search,
139139
// it returns results in given range and number of total results.
140-
func SearchUsers(ctx context.Context, opts *SearchUserOptions) (users []*User, _ int64, _ error) {
140+
func SearchUsers(ctx context.Context, opts SearchUserOptions) (users []*User, _ int64, _ error) {
141141
sessCount := opts.toSearchQueryBase(ctx)
142142
defer sessCount.Close()
143143
count, err := sessCount.Count(new(User))
@@ -152,7 +152,7 @@ func SearchUsers(ctx context.Context, opts *SearchUserOptions) (users []*User, _
152152
sessQuery := opts.toSearchQueryBase(ctx).OrderBy(opts.OrderBy.String())
153153
defer sessQuery.Close()
154154
if opts.Page > 0 {
155-
sessQuery = db.SetSessionPagination(sessQuery, opts)
155+
sessQuery = db.SetSessionPagination(sessQuery, &opts)
156156
}
157157

158158
// the sql may contain JOIN, so we must only select User related columns

models/user/user_test.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func TestCanCreateOrganization(t *testing.T) {
8888

8989
func TestSearchUsers(t *testing.T) {
9090
assert.NoError(t, unittest.PrepareTestDatabase())
91-
testSuccess := func(opts *user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
91+
testSuccess := func(opts user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) {
9292
users, _, err := user_model.SearchUsers(db.DefaultContext, opts)
9393
assert.NoError(t, err)
9494
cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts)
@@ -100,61 +100,61 @@ func TestSearchUsers(t *testing.T) {
100100
}
101101

102102
// test orgs
103-
testOrgSuccess := func(opts *user_model.SearchUserOptions, expectedOrgIDs []int64) {
103+
testOrgSuccess := func(opts user_model.SearchUserOptions, expectedOrgIDs []int64) {
104104
opts.Type = user_model.UserTypeOrganization
105105
testSuccess(opts, expectedOrgIDs)
106106
}
107107

108-
testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1, PageSize: 2}},
108+
testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1, PageSize: 2}},
109109
[]int64{3, 6})
110110

111-
testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 2, PageSize: 2}},
111+
testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 2, PageSize: 2}},
112112
[]int64{7, 17})
113113

114-
testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 3, PageSize: 2}},
114+
testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 3, PageSize: 2}},
115115
[]int64{19, 25})
116116

117-
testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}},
117+
testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 4, PageSize: 2}},
118118
[]int64{26, 41})
119119

120-
testOrgSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 5, PageSize: 2}},
120+
testOrgSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 5, PageSize: 2}},
121121
[]int64{42})
122122

123-
testOrgSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 6, PageSize: 2}},
123+
testOrgSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 6, PageSize: 2}},
124124
[]int64{})
125125

126126
// test users
127-
testUserSuccess := func(opts *user_model.SearchUserOptions, expectedUserIDs []int64) {
127+
testUserSuccess := func(opts user_model.SearchUserOptions, expectedUserIDs []int64) {
128128
opts.Type = user_model.UserTypeIndividual
129129
testSuccess(opts, expectedUserIDs)
130130
}
131131

132-
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
132+
testUserSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}},
133133
[]int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
134134

135-
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(false)},
135+
testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(false)},
136136
[]int64{9})
137137

138-
testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
138+
testUserSuccess(user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
139139
[]int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34, 37, 38, 39, 40})
140140

141-
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
141+
testUserSuccess(user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
142142
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
143143

144144
// order by name asc default
145-
testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
145+
testUserSuccess(user_model.SearchUserOptions{Keyword: "user1", ListOptions: db.ListOptions{Page: 1}, IsActive: optional.Some(true)},
146146
[]int64{1, 10, 11, 12, 13, 14, 15, 16, 18})
147147

148-
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: optional.Some(true)},
148+
testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsAdmin: optional.Some(true)},
149149
[]int64{1})
150150

151-
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: optional.Some(true)},
151+
testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsRestricted: optional.Some(true)},
152152
[]int64{29})
153153

154-
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: optional.Some(true)},
154+
testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsProhibitLogin: optional.Some(true)},
155155
[]int64{37})
156156

157-
testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)},
157+
testUserSuccess(user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsTwoFactorEnabled: optional.Some(true)},
158158
[]int64{24})
159159
}
160160

modules/actions/workflows.go

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,23 @@ func IsWorkflow(path string) bool {
4343
return strings.HasPrefix(path, ".gitea/workflows") || strings.HasPrefix(path, ".github/workflows")
4444
}
4545

46-
func ListWorkflows(commit *git.Commit) (git.Entries, error) {
47-
tree, err := commit.SubTree(".gitea/workflows")
46+
func ListWorkflows(commit *git.Commit) (string, git.Entries, error) {
47+
rpath := ".gitea/workflows"
48+
tree, err := commit.SubTree(rpath)
4849
if _, ok := err.(git.ErrNotExist); ok {
49-
tree, err = commit.SubTree(".github/workflows")
50+
rpath = ".github/workflows"
51+
tree, err = commit.SubTree(rpath)
5052
}
5153
if _, ok := err.(git.ErrNotExist); ok {
52-
return nil, nil
54+
return "", nil, nil
5355
}
5456
if err != nil {
55-
return nil, err
57+
return "", nil, err
5658
}
5759

5860
entries, err := tree.ListEntriesRecursiveFast()
5961
if err != nil {
60-
return nil, err
62+
return "", nil, err
6163
}
6264

6365
ret := make(git.Entries, 0, len(entries))
@@ -66,7 +68,7 @@ func ListWorkflows(commit *git.Commit) (git.Entries, error) {
6668
ret = append(ret, entry)
6769
}
6870
}
69-
return ret, nil
71+
return rpath, ret, nil
7072
}
7173

7274
func GetContentFromEntry(entry *git.TreeEntry) ([]byte, error) {
@@ -102,7 +104,7 @@ func DetectWorkflows(
102104
payload api.Payloader,
103105
detectSchedule bool,
104106
) ([]*DetectedWorkflow, []*DetectedWorkflow, error) {
105-
entries, err := ListWorkflows(commit)
107+
_, entries, err := ListWorkflows(commit)
106108
if err != nil {
107109
return nil, nil, err
108110
}
@@ -147,7 +149,7 @@ func DetectWorkflows(
147149
}
148150

149151
func DetectScheduledWorkflows(gitRepo *git.Repository, commit *git.Commit) ([]*DetectedWorkflow, error) {
150-
entries, err := ListWorkflows(commit)
152+
_, entries, err := ListWorkflows(commit)
151153
if err != nil {
152154
return nil, err
153155
}

modules/commitstatus/commit_status.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ const (
1818
CommitStatusFailure CommitStatusState = "failure"
1919
// CommitStatusWarning is for when the CommitStatus is Warning
2020
CommitStatusWarning CommitStatusState = "warning"
21+
// CommitStatusSkipped is for when CommitStatus is Skipped
22+
CommitStatusSkipped CommitStatusState = "skipped"
2123
)
2224

2325
func (css CommitStatusState) String() string {
@@ -49,6 +51,11 @@ func (css CommitStatusState) IsWarning() bool {
4951
return css == CommitStatusWarning
5052
}
5153

54+
// IsSkipped represents if commit status state is skipped
55+
func (css CommitStatusState) IsSkipped() bool {
56+
return css == CommitStatusSkipped
57+
}
58+
5259
type CommitStatusStates []CommitStatusState //nolint
5360

5461
// According to https://docs.github.com/en/rest/commits/statuses?apiVersion=2022-11-28#get-the-combined-status-for-a-specific-reference
@@ -63,7 +70,7 @@ func (css CommitStatusStates) Combine() CombinedStatusState {
6370
case state.IsError() || state.IsFailure():
6471
return CombinedStatusFailure
6572
case state.IsPending():
66-
case state.IsSuccess() || state.IsWarning():
73+
case state.IsSuccess() || state.IsWarning() || state.IsSkipped():
6774
successCnt++
6875
}
6976
}

modules/git/commit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type Commit struct {
3434
// CommitSignature represents a git commit signature part.
3535
type CommitSignature struct {
3636
Signature string
37-
Payload string // TODO check if can be reconstruct from the rest of commit information to not have duplicate data
37+
Payload string
3838
}
3939

4040
// Message returns the commit message. Same as retrieving CommitMessage directly.

modules/git/commit_reader.go

Lines changed: 61 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,44 @@ package git
66
import (
77
"bufio"
88
"bytes"
9+
"fmt"
910
"io"
10-
"strings"
1111
)
1212

13+
const (
14+
commitHeaderGpgsig = "gpgsig"
15+
commitHeaderGpgsigSha256 = "gpgsig-sha256"
16+
)
17+
18+
func assignCommitFields(gitRepo *Repository, commit *Commit, headerKey string, headerValue []byte) error {
19+
if len(headerValue) > 0 && headerValue[len(headerValue)-1] == '\n' {
20+
headerValue = headerValue[:len(headerValue)-1] // remove trailing newline
21+
}
22+
switch headerKey {
23+
case "tree":
24+
objID, err := NewIDFromString(string(headerValue))
25+
if err != nil {
26+
return fmt.Errorf("invalid tree ID %q: %w", string(headerValue), err)
27+
}
28+
commit.Tree = *NewTree(gitRepo, objID)
29+
case "parent":
30+
objID, err := NewIDFromString(string(headerValue))
31+
if err != nil {
32+
return fmt.Errorf("invalid parent ID %q: %w", string(headerValue), err)
33+
}
34+
commit.Parents = append(commit.Parents, objID)
35+
case "author":
36+
commit.Author.Decode(headerValue)
37+
case "committer":
38+
commit.Committer.Decode(headerValue)
39+
case commitHeaderGpgsig, commitHeaderGpgsigSha256:
40+
// if there are duplicate "gpgsig" and "gpgsig-sha256" headers, then the signature must have already been invalid
41+
// so we don't need to handle duplicate headers here
42+
commit.Signature = &CommitSignature{Signature: string(headerValue)}
43+
}
44+
return nil
45+
}
46+
1347
// CommitFromReader will generate a Commit from a provided reader
1448
// We need this to interpret commits from cat-file or cat-file --batch
1549
//
@@ -21,90 +55,46 @@ func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader)
2155
Committer: &Signature{},
2256
}
2357

24-
payloadSB := new(strings.Builder)
25-
signatureSB := new(strings.Builder)
26-
messageSB := new(strings.Builder)
27-
message := false
28-
pgpsig := false
29-
30-
bufReader, ok := reader.(*bufio.Reader)
31-
if !ok {
32-
bufReader = bufio.NewReader(reader)
33-
}
34-
35-
readLoop:
58+
bufReader := bufio.NewReader(reader)
59+
inHeader := true
60+
var payloadSB, messageSB bytes.Buffer
61+
var headerKey string
62+
var headerValue []byte
3663
for {
3764
line, err := bufReader.ReadBytes('\n')
38-
if err != nil {
39-
if err == io.EOF {
40-
if message {
41-
_, _ = messageSB.Write(line)
42-
}
43-
_, _ = payloadSB.Write(line)
44-
break readLoop
45-
}
46-
return nil, err
65+
if err != nil && err != io.EOF {
66+
return nil, fmt.Errorf("unable to read commit %q: %w", objectID.String(), err)
4767
}
48-
if pgpsig {
49-
if len(line) > 0 && line[0] == ' ' {
50-
_, _ = signatureSB.Write(line[1:])
51-
continue
52-
}
53-
pgpsig = false
68+
if len(line) == 0 {
69+
break
5470
}
5571

56-
if !message {
57-
// This is probably not correct but is copied from go-gits interpretation...
58-
trimmed := bytes.TrimSpace(line)
59-
if len(trimmed) == 0 {
60-
message = true
61-
_, _ = payloadSB.Write(line)
62-
continue
63-
}
64-
65-
split := bytes.SplitN(trimmed, []byte{' '}, 2)
66-
var data []byte
67-
if len(split) > 1 {
68-
data = split[1]
72+
if inHeader {
73+
inHeader = !(len(line) == 1 && line[0] == '\n') // still in header if line is not just a newline
74+
k, v, _ := bytes.Cut(line, []byte{' '})
75+
if len(k) != 0 || !inHeader {
76+
if headerKey != "" {
77+
if err = assignCommitFields(gitRepo, commit, headerKey, headerValue); err != nil {
78+
return nil, fmt.Errorf("unable to parse commit %q: %w", objectID.String(), err)
79+
}
80+
}
81+
headerKey = string(k) // it also resets the headerValue to empty string if not inHeader
82+
headerValue = v
83+
} else {
84+
headerValue = append(headerValue, v...)
6985
}
70-
71-
switch string(split[0]) {
72-
case "tree":
73-
commit.Tree = *NewTree(gitRepo, MustIDFromString(string(data)))
86+
if headerKey != commitHeaderGpgsig && headerKey != commitHeaderGpgsigSha256 {
7487
_, _ = payloadSB.Write(line)
75-
case "parent":
76-
commit.Parents = append(commit.Parents, MustIDFromString(string(data)))
77-
_, _ = payloadSB.Write(line)
78-
case "author":
79-
commit.Author = &Signature{}
80-
commit.Author.Decode(data)
81-
_, _ = payloadSB.Write(line)
82-
case "committer":
83-
commit.Committer = &Signature{}
84-
commit.Committer.Decode(data)
85-
_, _ = payloadSB.Write(line)
86-
case "encoding":
87-
_, _ = payloadSB.Write(line)
88-
case "gpgsig":
89-
fallthrough
90-
case "gpgsig-sha256": // FIXME: no intertop, so only 1 exists at present.
91-
_, _ = signatureSB.Write(data)
92-
_ = signatureSB.WriteByte('\n')
93-
pgpsig = true
9488
}
9589
} else {
9690
_, _ = messageSB.Write(line)
9791
_, _ = payloadSB.Write(line)
9892
}
9993
}
94+
10095
commit.CommitMessage = messageSB.String()
101-
commit.Signature = &CommitSignature{
102-
Signature: signatureSB.String(),
103-
Payload: payloadSB.String(),
104-
}
105-
if len(commit.Signature.Signature) == 0 {
106-
commit.Signature = nil
96+
if commit.Signature != nil {
97+
commit.Signature.Payload = payloadSB.String()
10798
}
108-
10999
return commit, nil
110100
}

modules/git/commit_sha256_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ func TestGetFullCommitIDErrorSha256(t *testing.T) {
6060
}
6161

6262
func TestCommitFromReaderSha256(t *testing.T) {
63-
commitString := `9433b2a62b964c17a4485ae180f45f595d3e69d31b786087775e28c6b6399df0 commit 1114
64-
tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
63+
commitString := `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
6564
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
6665
author Adam Majer <[email protected]> 1698676906 +0100
6766
committer Adam Majer <[email protected]> 1698676906 +0100
@@ -112,8 +111,7 @@ VAEUo6ecdDxSpyt2naeg9pKus/BRi7P6g4B1hkk/zZstUX/QP4IQuAJbXjkvsC+X
112111
HKRr3NlRM/DygzTyj0gN74uoa0goCIbyAQhiT42nm0cuhM7uN/W0ayrlZjGF1cbR
113112
8NCJUL2Nwj0ywKIavC99Ipkb8AsFwpVT6U6effs6
114113
=xybZ
115-
-----END PGP SIGNATURE-----
116-
`, commitFromReader.Signature.Signature)
114+
-----END PGP SIGNATURE-----`, commitFromReader.Signature.Signature)
117115
assert.Equal(t, `tree e7f9e96dd79c09b078cac8b303a7d3b9d65ff9b734e86060a4d20409fd379f9e
118116
parent 26e9ccc29fad747e9c5d9f4c9ddeb7eff61cc45ef6a8dc258cbeb181afc055e8
119117
author Adam Majer <[email protected]> 1698676906 +0100

0 commit comments

Comments
 (0)