Skip to content

Commit a31d1b3

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Deduplicate lfs common code (go-gitea#30704) Improve job commit description (go-gitea#30579) Improve test for TestPullCompare (go-gitea#30699) Allow to save empty comment (go-gitea#30706) [skip ci] Updated translations via Crowdin Refactor imagediff and fix regression bug (go-gitea#30694) Improve oauth2 client "preferred username field" logic and the error handling (go-gitea#30622) Fix active item in tab menu (go-gitea#30690)
2 parents e9392c1 + ed8c63c commit a31d1b3

File tree

29 files changed

+403
-268
lines changed

29 files changed

+403
-268
lines changed

custom/conf/app.example.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,8 +1558,8 @@ LEVEL = Info
15581558
;; email = use the username part of the email attribute
15591559
;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
15601560
;; - diacritics are removed
1561-
;; - the characters in the set `['´\x60]` are removed
1562-
;; - the characters in the set `[\s~+]` are replaced with `-`
1561+
;; - the characters in the set ['´`] are removed
1562+
;; - the characters in the set [\s~+] are replaced with "-"
15631563
;USERNAME = nickname
15641564
;;
15651565
;; Update avatar if available from oauth2 provider.

docs/content/administration/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ And the following unique queues:
612612
- `email` - use the username part of the email attribute
613613
- Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria:
614614
- diacritics are removed
615-
- the characters in the set `['´\x60]` are removed
615+
- the characters in the set ```['´`]``` are removed
616616
- the characters in the set `[\s~+]` are replaced with `-`
617617
- `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login.
618618
- `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists:

models/actions/run.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ func (run *ActionRun) Link() string {
7474
return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.Index)
7575
}
7676

77+
func (run *ActionRun) WorkflowLink() string {
78+
if run.Repo == nil {
79+
return ""
80+
}
81+
return fmt.Sprintf("%s/actions/?workflow=%s", run.Repo.Link(), run.WorkflowID)
82+
}
83+
7784
// RefLink return the url of run's ref
7885
func (run *ActionRun) RefLink() string {
7986
refName := git.RefName(run.Ref)
@@ -156,6 +163,10 @@ func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, err
156163
return nil, fmt.Errorf("event %s is not a pull request event", run.Event)
157164
}
158165

166+
func (run *ActionRun) IsSchedule() bool {
167+
return run.ScheduleID > 0
168+
}
169+
159170
func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error {
160171
_, err := db.GetEngine(ctx).ID(repo.ID).
161172
SetExpr("num_action_runs",

models/unittest/testdb.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"code.gitea.io/gitea/models/system"
1717
"code.gitea.io/gitea/modules/auth/password/hash"
1818
"code.gitea.io/gitea/modules/base"
19+
"code.gitea.io/gitea/modules/cache"
1920
"code.gitea.io/gitea/modules/git"
2021
"code.gitea.io/gitea/modules/setting"
2122
"code.gitea.io/gitea/modules/setting/config"
@@ -106,6 +107,7 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) {
106107
fatalTestError("Error creating test engine: %v\n", err)
107108
}
108109

110+
setting.IsInTesting = true
109111
setting.AppURL = "https://try.gitea.io/"
110112
setting.RunUser = "runuser"
111113
setting.SSH.User = "sshuser"
@@ -148,6 +150,9 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) {
148150

149151
config.SetDynGetter(system.NewDatabaseDynKeyGetter())
150152

153+
if err = cache.Init(); err != nil {
154+
fatalTestError("cache.Init: %v\n", err)
155+
}
151156
if err = storage.Init(); err != nil {
152157
fatalTestError("storage.Init: %v\n", err)
153158
}

models/user/user.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -501,19 +501,19 @@ func GetUserSalt() (string, error) {
501501
// Note: The set of characters here can safely expand without a breaking change,
502502
// but characters removed from this set can cause user account linking to break
503503
var (
504-
customCharsReplacement = strings.NewReplacer("Æ", "AE")
505-
removeCharsRE = regexp.MustCompile(`['´\x60]`)
506-
removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
507-
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
504+
customCharsReplacement = strings.NewReplacer("Æ", "AE")
505+
removeCharsRE = regexp.MustCompile("['`´]")
506+
transformDiacritics = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
507+
replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`)
508508
)
509509

510-
// normalizeUserName returns a string with single-quotes and diacritics
511-
// removed, and any other non-supported username characters replaced with
512-
// a `-` character
510+
// NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters.
511+
// It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character
513512
func NormalizeUserName(s string) (string, error) {
514-
strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, customCharsReplacement.Replace(s))
513+
s, _, _ = strings.Cut(s, "@")
514+
strDiacriticsRemoved, n, err := transform.String(transformDiacritics, customCharsReplacement.Replace(s))
515515
if err != nil {
516-
return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s)
516+
return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n)
517517
}
518518
return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil
519519
}

models/user/user_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,15 +506,16 @@ func Test_NormalizeUserFromEmail(t *testing.T) {
506506
Expected string
507507
IsNormalizedValid bool
508508
}{
509-
{"test", "test", true},
509+
{"[email protected]", "name", true},
510+
{"test'`´name", "testname", true},
510511
{"Sinéad.O'Connor", "Sinead.OConnor", true},
511512
{"Æsir", "AEsir", true},
512-
// \u00e9\u0065\u0301
513-
{"éé", "ee", true},
513+
{"éé", "ee", true}, // \u00e9\u0065\u0301
514514
{"Awareness Hub", "Awareness-Hub", true},
515515
{"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters
516516
{".bad.", ".bad.", false},
517517
{"new😀user", "new😀user", false}, // No plans to support
518+
{`"quoted"`, `"quoted"`, false}, // No plans to support
518519
}
519520
for _, testCase := range testCases {
520521
normalizedName, err := user_model.NormalizeUserName(testCase.Input)

modules/git/pipeline/lfs_common.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package pipeline
5+
6+
import (
7+
"fmt"
8+
"time"
9+
10+
"code.gitea.io/gitea/modules/git"
11+
)
12+
13+
// LFSResult represents commits found using a provided pointer file hash
14+
type LFSResult struct {
15+
Name string
16+
SHA string
17+
Summary string
18+
When time.Time
19+
ParentHashes []git.ObjectID
20+
BranchName string
21+
FullCommitName string
22+
}
23+
24+
type lfsResultSlice []*LFSResult
25+
26+
func (a lfsResultSlice) Len() int { return len(a) }
27+
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
28+
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
29+
30+
func lfsError(msg string, err error) error {
31+
return fmt.Errorf("LFS error occurred, %s: err: %w", msg, err)
32+
}

modules/git/pipeline/lfs.go renamed to modules/git/pipeline/lfs_gogit.go

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ package pipeline
77

88
import (
99
"bufio"
10-
"fmt"
1110
"io"
1211
"sort"
1312
"strings"
1413
"sync"
15-
"time"
1614

1715
"code.gitea.io/gitea/modules/git"
1816

@@ -21,23 +19,6 @@ import (
2119
"github.com/go-git/go-git/v5/plumbing/object"
2220
)
2321

24-
// LFSResult represents commits found using a provided pointer file hash
25-
type LFSResult struct {
26-
Name string
27-
SHA string
28-
Summary string
29-
When time.Time
30-
ParentHashes []git.ObjectID
31-
BranchName string
32-
FullCommitName string
33-
}
34-
35-
type lfsResultSlice []*LFSResult
36-
37-
func (a lfsResultSlice) Len() int { return len(a) }
38-
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
39-
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
40-
4122
// FindLFSFile finds commits that contain a provided pointer file hash
4223
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
4324
resultsMap := map[string]*LFSResult{}
@@ -51,7 +32,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
5132
All: true,
5233
})
5334
if err != nil {
54-
return nil, fmt.Errorf("Failed to get GoGit CommitsIter. Error: %w", err)
35+
return nil, lfsError("failed to get GoGit CommitsIter", err)
5536
}
5637

5738
err = commitsIter.ForEach(func(gitCommit *object.Commit) error {
@@ -85,7 +66,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
8566
return nil
8667
})
8768
if err != nil && err != io.EOF {
88-
return nil, fmt.Errorf("Failure in CommitIter.ForEach: %w", err)
69+
return nil, lfsError("failure in CommitIter.ForEach", err)
8970
}
9071

9172
for _, result := range resultsMap {
@@ -156,7 +137,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
156137
select {
157138
case err, has := <-errChan:
158139
if has {
159-
return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
140+
return nil, lfsError("unable to obtain name for LFS files", err)
160141
}
161142
default:
162143
}

modules/git/pipeline/lfs_nogogit.go

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,14 @@ package pipeline
88
import (
99
"bufio"
1010
"bytes"
11-
"fmt"
1211
"io"
1312
"sort"
1413
"strings"
1514
"sync"
16-
"time"
1715

1816
"code.gitea.io/gitea/modules/git"
1917
)
2018

21-
// LFSResult represents commits found using a provided pointer file hash
22-
type LFSResult struct {
23-
Name string
24-
SHA string
25-
Summary string
26-
When time.Time
27-
ParentIDs []git.ObjectID
28-
BranchName string
29-
FullCommitName string
30-
}
31-
32-
type lfsResultSlice []*LFSResult
33-
34-
func (a lfsResultSlice) Len() int { return len(a) }
35-
func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
36-
func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) }
37-
3819
// FindLFSFile finds commits that contain a provided pointer file hash
3920
func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) {
4021
resultsMap := map[string]*LFSResult{}
@@ -137,11 +118,11 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
137118
n += int64(count)
138119
if bytes.Equal(binObjectID, objectID.RawValue()) {
139120
result := LFSResult{
140-
Name: curPath + string(fname),
141-
SHA: curCommit.ID.String(),
142-
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
143-
When: curCommit.Author.When,
144-
ParentIDs: curCommit.Parents,
121+
Name: curPath + string(fname),
122+
SHA: curCommit.ID.String(),
123+
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
124+
When: curCommit.Author.When,
125+
ParentHashes: curCommit.Parents,
145126
}
146127
resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result
147128
} else if string(mode) == git.EntryModeTree.String() {
@@ -183,7 +164,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
183164

184165
for _, result := range resultsMap {
185166
hasParent := false
186-
for _, parentID := range result.ParentIDs {
167+
for _, parentID := range result.ParentHashes {
187168
if _, hasParent = resultsMap[parentID.String()+":"+result.Name]; hasParent {
188169
break
189170
}
@@ -240,7 +221,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err
240221
select {
241222
case err, has := <-errChan:
242223
if has {
243-
return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err)
224+
return nil, lfsError("unable to obtain name for LFS files", err)
244225
}
245226
default:
246227
}

modules/session/mock.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package session
5+
6+
import (
7+
"net/http"
8+
9+
"gitea.com/go-chi/session"
10+
)
11+
12+
type MockStore struct {
13+
*session.MemStore
14+
}
15+
16+
func (m *MockStore) Destroy(writer http.ResponseWriter, request *http.Request) error {
17+
return nil
18+
}
19+
20+
type mockStoreContextKeyStruct struct{}
21+
22+
var MockStoreContextKey = mockStoreContextKeyStruct{}
23+
24+
func NewMockStore(sid string) *MockStore {
25+
return &MockStore{session.NewMemStore(sid)}
26+
}

modules/session/store.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ package session
66
import (
77
"net/http"
88

9+
"code.gitea.io/gitea/modules/setting"
10+
911
"gitea.com/go-chi/session"
1012
)
1113

@@ -14,15 +16,32 @@ type Store interface {
1416
Get(any) any
1517
Set(any, any) error
1618
Delete(any) error
19+
ID() string
20+
Release() error
21+
Flush() error
22+
Destroy(http.ResponseWriter, *http.Request) error
1723
}
1824

1925
// RegenerateSession regenerates the underlying session and returns the new store
2026
func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, error) {
2127
for _, f := range BeforeRegenerateSession {
2228
f(resp, req)
2329
}
24-
s, err := session.RegenerateSession(resp, req)
25-
return s, err
30+
if setting.IsInTesting {
31+
if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok {
32+
return store, nil
33+
}
34+
}
35+
return session.RegenerateSession(resp, req)
36+
}
37+
38+
func GetContextSession(req *http.Request) Store {
39+
if setting.IsInTesting {
40+
if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok {
41+
return store
42+
}
43+
}
44+
return session.GetSession(req)
2645
}
2746

2847
// BeforeRegenerateSession is a list of functions that are called before a session is regenerated.

modules/setting/oauth2.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,10 @@ import (
1616
type OAuth2UsernameType string
1717

1818
const (
19-
// OAuth2UsernameUserid oauth2 userid field will be used as gitea name
20-
OAuth2UsernameUserid OAuth2UsernameType = "userid"
21-
// OAuth2UsernameNickname oauth2 nickname field will be used as gitea name
22-
OAuth2UsernameNickname OAuth2UsernameType = "nickname"
23-
// OAuth2UsernameEmail username of oauth2 email field will be used as gitea name
24-
OAuth2UsernameEmail OAuth2UsernameType = "email"
25-
// OAuth2UsernameEmail username of oauth2 preferred_username field will be used as gitea name
26-
OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username"
19+
OAuth2UsernameUserid OAuth2UsernameType = "userid" // use user id (sub) field as gitea's username
20+
OAuth2UsernameNickname OAuth2UsernameType = "nickname" // use nickname field
21+
OAuth2UsernameEmail OAuth2UsernameType = "email" // use email field
22+
OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" // use preferred_username field
2723
)
2824

2925
func (username OAuth2UsernameType) isValid() bool {
@@ -71,8 +67,8 @@ func loadOAuth2ClientFrom(rootCfg ConfigProvider) {
7167
OAuth2Client.EnableAutoRegistration = sec.Key("ENABLE_AUTO_REGISTRATION").MustBool()
7268
OAuth2Client.Username = OAuth2UsernameType(sec.Key("USERNAME").MustString(string(OAuth2UsernameNickname)))
7369
if !OAuth2Client.Username.isValid() {
74-
log.Warn("Username setting is not valid: '%s', will fallback to '%s'", OAuth2Client.Username, OAuth2UsernameNickname)
7570
OAuth2Client.Username = OAuth2UsernameNickname
71+
log.Warn("[oauth2_client].USERNAME setting is invalid, falls back to %q", OAuth2Client.Username)
7672
}
7773
OAuth2Client.UpdateAvatar = sec.Key("UPDATE_AVATAR").MustBool()
7874
OAuth2Client.AccountLinking = OAuth2AccountLinkingType(sec.Key("ACCOUNT_LINKING").MustString(string(OAuth2AccountLinkingLogin)))

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ oauth_signin_submit = Link Account
436436
oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator.
437437
oauth.signin.error.access_denied = The authorization request was denied.
438438
oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later.
439+
oauth_callback_unable_auto_reg = Auto Registration is enabled, but OAuth2 Provider %[1]s returned missing fields: %[2]s, unable to create an account automatically, please create or link to an account, or contact the site administrator.
439440
openid_connect_submit = Connect
440441
openid_connect_title = Connect to an existing account
441442
openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here.

0 commit comments

Comments
 (0)