From c685eefe4a8ff6e32bc859a3457a5090f58ea8c5 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 25 Apr 2024 17:14:23 +0800 Subject: [PATCH 01/19] If a repository return no commitstatus, then still cache it but not query it from database (#30700) The previous repository default branch commit status cache will only store if the commit status has value. So the repository which have no any commit status will always be fetched from database. This PR will store the empty state of commit status of a repository into cache because the cache will be updated once there is a commit status stored. --- .../repository/commitstatus/commitstatus.go | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go index 8a62a603d4..444ae04d0c 100644 --- a/services/repository/commitstatus/commitstatus.go +++ b/services/repository/commitstatus/commitstatus.go @@ -38,12 +38,10 @@ func getCommitStatusCache(repoID int64, branchName string) *commitStatusCacheVal if ok && statusStr != "" { var cv commitStatusCacheValue err := json.Unmarshal([]byte(statusStr), &cv) - if err == nil && cv.State != "" { + if err == nil { return &cv } - if err != nil { - log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err) - } + log.Warn("getCommitStatusCache: json.Unmarshal failed: %v", err) } return nil } @@ -128,15 +126,22 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato // FindReposLastestCommitStatuses loading repository default branch latest combinded commit status with cache func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Repository) ([]*git_model.CommitStatus, error) { results := make([]*git_model.CommitStatus, len(repos)) + allCached := true for i, repo := range repos { if cv := getCommitStatusCache(repo.ID, repo.DefaultBranch); cv != nil { results[i] = &git_model.CommitStatus{ State: api.CommitStatusState(cv.State), TargetURL: cv.TargetURL, } + } else { + allCached = false } } + if allCached { + return results, nil + } + // collect the latest commit of each repo // at most there are dozens of repos (limited by MaxResponseItems), so it's not a big problem at the moment repoBranchNames := make(map[int64]string, len(repos)) @@ -165,10 +170,10 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep for i, repo := range repos { if repo.ID == summary.RepoID { results[i] = summary - _ = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { + repoSHAs = slices.DeleteFunc(repoSHAs, func(repoSHA git_model.RepoSHA) bool { return repoSHA.RepoID == repo.ID }) - if results[i].State != "" { + if results[i] != nil { if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } @@ -177,6 +182,9 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep } } } + if len(repoSHAs) == 0 { + return results, nil + } // call the database O(1) times to get the commit statuses for all repos repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoSHAs) @@ -187,7 +195,7 @@ func FindReposLastestCommitStatuses(ctx context.Context, repos []*repo_model.Rep for i, repo := range repos { if results[i] == nil { results[i] = git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID]) - if results[i].State != "" { + if results[i] != nil { if err := updateCommitStatusCache(repo.ID, repo.DefaultBranch, results[i].State, results[i].TargetURL); err != nil { log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err) } From d0bfc978de802683b9a44720b7f5a8a8394d38be Mon Sep 17 00:00:00 2001 From: silverwind Date: Thu, 25 Apr 2024 12:53:39 +0200 Subject: [PATCH 02/19] Fix active item in tab menu (#30690) Before, item would also resize on hover because of font weight: Screenshot 2024-04-25 at 01 28 53 After: Screenshot 2024-04-25 at 01 28 40 Co-authored-by: Giteabot --- web_src/css/modules/menu.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/css/modules/menu.css b/web_src/css/modules/menu.css index a392ffb5e9..e393ec5186 100644 --- a/web_src/css/modules/menu.css +++ b/web_src/css/modules/menu.css @@ -403,7 +403,7 @@ background: var(--color-body); border-top-width: 1px; border-color: var(--color-secondary); - font-weight: var(--font-weight-medium); + color: var(--color-text-dark); margin-bottom: -1px; border-radius: 0.28571429rem 0.28571429rem 0 0 !important; } From bffbbf547063fa170cc52ae2e757d5badb336632 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 25 Apr 2024 19:22:32 +0800 Subject: [PATCH 03/19] Improve oauth2 client "preferred username field" logic and the error handling (#30622) Follow #30454 And fix #24957 When using "preferred_username", if no such field, `extractUserNameFromOAuth2` (old `getUserName`) shouldn't return an error. All other USERNAME options do not return such error. And fine tune some logic and error messages, make code more stable and more friendly to end users. --- custom/conf/app.example.ini | 4 +- .../config-cheat-sheet.en-us.md | 2 +- models/unittest/testdb.go | 5 +++ models/user/user.go | 18 ++++----- models/user/user_test.go | 7 ++-- modules/session/mock.go | 26 ++++++++++++ modules/session/store.go | 23 ++++++++++- modules/setting/oauth2.go | 14 +++---- options/locale/locale_en-US.ini | 1 + routers/web/auth/auth.go | 14 +++---- routers/web/auth/auth_test.go | 40 +++++++++++++++++++ routers/web/auth/linkaccount.go | 20 ++++++---- routers/web/auth/oauth.go | 37 ++++++++++------- services/context/context.go | 5 +-- services/contexttest/context_tests.go | 14 +++++-- templates/user/auth/link_account.tmpl | 11 ++--- 16 files changed, 173 insertions(+), 68 deletions(-) create mode 100644 modules/session/mock.go diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 12588c1387..62db26fb02 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1558,8 +1558,8 @@ LEVEL = Info ;; email = use the username part of the email attribute ;; Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: ;; - diacritics are removed -;; - the characters in the set `['´\x60]` are removed -;; - the characters in the set `[\s~+]` are replaced with `-` +;; - the characters in the set ['´`] are removed +;; - the characters in the set [\s~+] are replaced with "-" ;USERNAME = nickname ;; ;; Update avatar if available from oauth2 provider. diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index b295ddf53a..14f562fc21 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -612,7 +612,7 @@ And the following unique queues: - `email` - use the username part of the email attribute - Note: `nickname`, `preferred_username` and `email` options will normalize input strings using the following criteria: - diacritics are removed - - the characters in the set `['´\x60]` are removed + - the characters in the set ```['´`]``` are removed - the characters in the set `[\s~+]` are replaced with `-` - `UPDATE_AVATAR`: **false**: Update avatar if available from oauth2 provider. Update will be performed on each login. - `ACCOUNT_LINKING`: **login**: How to handle if an account / email already exists: diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index cb90c12f2b..51de18fa9b 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/auth/password/hash" "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting/config" @@ -106,6 +107,7 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) { fatalTestError("Error creating test engine: %v\n", err) } + setting.IsInTesting = true setting.AppURL = "https://try.gitea.io/" setting.RunUser = "runuser" setting.SSH.User = "sshuser" @@ -148,6 +150,9 @@ func MainTest(m *testing.M, testOpts ...*TestOptions) { config.SetDynGetter(system.NewDatabaseDynKeyGetter()) + if err = cache.Init(); err != nil { + fatalTestError("cache.Init: %v\n", err) + } if err = storage.Init(); err != nil { fatalTestError("storage.Init: %v\n", err) } diff --git a/models/user/user.go b/models/user/user.go index 7056aecab0..a5a5b5bdf6 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -501,19 +501,19 @@ func GetUserSalt() (string, error) { // Note: The set of characters here can safely expand without a breaking change, // but characters removed from this set can cause user account linking to break var ( - customCharsReplacement = strings.NewReplacer("Æ", "AE") - removeCharsRE = regexp.MustCompile(`['´\x60]`) - removeDiacriticsTransform = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) - replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`) + customCharsReplacement = strings.NewReplacer("Æ", "AE") + removeCharsRE = regexp.MustCompile("['`´]") + transformDiacritics = transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) + replaceCharsHyphenRE = regexp.MustCompile(`[\s~+]`) ) -// normalizeUserName returns a string with single-quotes and diacritics -// removed, and any other non-supported username characters replaced with -// a `-` character +// NormalizeUserName only takes the name part if it is an email address, transforms it diacritics to ASCII characters. +// It returns a string with the single-quotes removed, and any other non-supported username characters are replaced with a `-` character func NormalizeUserName(s string) (string, error) { - strDiacriticsRemoved, n, err := transform.String(removeDiacriticsTransform, customCharsReplacement.Replace(s)) + s, _, _ = strings.Cut(s, "@") + strDiacriticsRemoved, n, err := transform.String(transformDiacritics, customCharsReplacement.Replace(s)) if err != nil { - return "", fmt.Errorf("Failed to normalize character `%v` in provided username `%v`", s[n], s) + return "", fmt.Errorf("failed to normalize the string of provided username %q at position %d", s, n) } return replaceCharsHyphenRE.ReplaceAllLiteralString(removeCharsRE.ReplaceAllLiteralString(strDiacriticsRemoved, ""), "-"), nil } diff --git a/models/user/user_test.go b/models/user/user_test.go index a4550fa655..b4ffa1f322 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -506,15 +506,16 @@ func Test_NormalizeUserFromEmail(t *testing.T) { Expected string IsNormalizedValid bool }{ - {"test", "test", true}, + {"name@example.com", "name", true}, + {"test'`´name", "testname", true}, {"Sinéad.O'Connor", "Sinead.OConnor", true}, {"Æsir", "AEsir", true}, - // \u00e9\u0065\u0301 - {"éé", "ee", true}, + {"éé", "ee", true}, // \u00e9\u0065\u0301 {"Awareness Hub", "Awareness-Hub", true}, {"double__underscore", "double__underscore", false}, // We should consider squashing double non-alpha characters {".bad.", ".bad.", false}, {"new😀user", "new😀user", false}, // No plans to support + {`"quoted"`, `"quoted"`, false}, // No plans to support } for _, testCase := range testCases { normalizedName, err := user_model.NormalizeUserName(testCase.Input) diff --git a/modules/session/mock.go b/modules/session/mock.go new file mode 100644 index 0000000000..95231a3655 --- /dev/null +++ b/modules/session/mock.go @@ -0,0 +1,26 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package session + +import ( + "net/http" + + "gitea.com/go-chi/session" +) + +type MockStore struct { + *session.MemStore +} + +func (m *MockStore) Destroy(writer http.ResponseWriter, request *http.Request) error { + return nil +} + +type mockStoreContextKeyStruct struct{} + +var MockStoreContextKey = mockStoreContextKeyStruct{} + +func NewMockStore(sid string) *MockStore { + return &MockStore{session.NewMemStore(sid)} +} diff --git a/modules/session/store.go b/modules/session/store.go index 70988fcdc5..09d1ef44dd 100644 --- a/modules/session/store.go +++ b/modules/session/store.go @@ -6,6 +6,8 @@ package session import ( "net/http" + "code.gitea.io/gitea/modules/setting" + "gitea.com/go-chi/session" ) @@ -14,6 +16,10 @@ type Store interface { Get(any) any Set(any, any) error Delete(any) error + ID() string + Release() error + Flush() error + Destroy(http.ResponseWriter, *http.Request) error } // RegenerateSession regenerates the underlying session and returns the new store @@ -21,8 +27,21 @@ func RegenerateSession(resp http.ResponseWriter, req *http.Request) (Store, erro for _, f := range BeforeRegenerateSession { f(resp, req) } - s, err := session.RegenerateSession(resp, req) - return s, err + if setting.IsInTesting { + if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok { + return store, nil + } + } + return session.RegenerateSession(resp, req) +} + +func GetContextSession(req *http.Request) Store { + if setting.IsInTesting { + if store, ok := req.Context().Value(MockStoreContextKey).(*MockStore); ok { + return store + } + } + return session.GetSession(req) } // BeforeRegenerateSession is a list of functions that are called before a session is regenerated. diff --git a/modules/setting/oauth2.go b/modules/setting/oauth2.go index 34e1a336dc..e59f54420b 100644 --- a/modules/setting/oauth2.go +++ b/modules/setting/oauth2.go @@ -16,14 +16,10 @@ import ( type OAuth2UsernameType string const ( - // OAuth2UsernameUserid oauth2 userid field will be used as gitea name - OAuth2UsernameUserid OAuth2UsernameType = "userid" - // OAuth2UsernameNickname oauth2 nickname field will be used as gitea name - OAuth2UsernameNickname OAuth2UsernameType = "nickname" - // OAuth2UsernameEmail username of oauth2 email field will be used as gitea name - OAuth2UsernameEmail OAuth2UsernameType = "email" - // OAuth2UsernameEmail username of oauth2 preferred_username field will be used as gitea name - OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" + OAuth2UsernameUserid OAuth2UsernameType = "userid" // use user id (sub) field as gitea's username + OAuth2UsernameNickname OAuth2UsernameType = "nickname" // use nickname field + OAuth2UsernameEmail OAuth2UsernameType = "email" // use email field + OAuth2UsernamePreferredUsername OAuth2UsernameType = "preferred_username" // use preferred_username field ) func (username OAuth2UsernameType) isValid() bool { @@ -71,8 +67,8 @@ func loadOAuth2ClientFrom(rootCfg ConfigProvider) { OAuth2Client.EnableAutoRegistration = sec.Key("ENABLE_AUTO_REGISTRATION").MustBool() OAuth2Client.Username = OAuth2UsernameType(sec.Key("USERNAME").MustString(string(OAuth2UsernameNickname))) if !OAuth2Client.Username.isValid() { - log.Warn("Username setting is not valid: '%s', will fallback to '%s'", OAuth2Client.Username, OAuth2UsernameNickname) OAuth2Client.Username = OAuth2UsernameNickname + log.Warn("[oauth2_client].USERNAME setting is invalid, falls back to %q", OAuth2Client.Username) } OAuth2Client.UpdateAvatar = sec.Key("UPDATE_AVATAR").MustBool() OAuth2Client.AccountLinking = OAuth2AccountLinkingType(sec.Key("ACCOUNT_LINKING").MustString(string(OAuth2AccountLinkingLogin))) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4f17b1a6db..fb591be393 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -436,6 +436,7 @@ oauth_signin_submit = Link Account oauth.signin.error = There was an error processing the authorization request. If this error persists, please contact the site administrator. oauth.signin.error.access_denied = The authorization request was denied. oauth.signin.error.temporarily_unavailable = Authorization failed because the authentication server is temporarily unavailable. Please try again later. +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. openid_connect_submit = Connect openid_connect_title = Connect to an existing account openid_connect_desc = The chosen OpenID URI is unknown. Associate it with a new account here. diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 9ef32ebdb1..7c873796fe 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -382,17 +382,17 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe return setting.AppSubURL + "/" } -func getUserName(gothUser *goth.User) (string, error) { +// extractUserNameFromOAuth2 tries to extract a normalized username from the given OAuth2 user. +// It returns ("", nil) if the required field doesn't exist. +func extractUserNameFromOAuth2(gothUser *goth.User) (string, error) { switch setting.OAuth2Client.Username { case setting.OAuth2UsernameEmail: - return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0]) + return user_model.NormalizeUserName(gothUser.Email) case setting.OAuth2UsernamePreferredUsername: - preferredUsername, exists := gothUser.RawData["preferred_username"] - if exists { - return user_model.NormalizeUserName(preferredUsername.(string)) - } else { - return "", fmt.Errorf("preferred_username is missing in received user data but configured as username source for user_id %q. Check if OPENID_CONNECT_SCOPES contains profile", gothUser.UserID) + if preferredUsername, ok := gothUser.RawData["preferred_username"].(string); ok { + return user_model.NormalizeUserName(preferredUsername) } + return "", nil case setting.OAuth2UsernameNickname: return user_model.NormalizeUserName(gothUser.NickName) default: // OAuth2UsernameUserid diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go index c6afbf877c..45525a5c6f 100644 --- a/routers/web/auth/auth_test.go +++ b/routers/web/auth/auth_test.go @@ -8,12 +8,31 @@ import ( "net/url" "testing" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/session" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/auth/source/oauth2" "code.gitea.io/gitea/services/contexttest" + "github.com/markbates/goth" + "github.com/markbates/goth/gothic" "github.com/stretchr/testify/assert" ) +func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) { + cfg.Provider = util.IfZero(cfg.Provider, "gitea") + err := auth_model.CreateSource(db.DefaultContext, &auth_model.Source{ + Type: auth_model.OAuth2, + Name: authName, + IsActive: true, + Cfg: &cfg, + }) + assert.NoError(t, err) +} + func TestUserLogin(t *testing.T) { ctx, resp := contexttest.MockContext(t, "/user/login") SignIn(ctx) @@ -41,3 +60,24 @@ func TestUserLogin(t *testing.T) { SignIn(ctx) assert.Equal(t, "/", test.RedirectURL(resp)) } + +func TestSignUpOAuth2ButMissingFields(t *testing.T) { + defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)() + defer test.MockVariableValue(&gothic.CompleteUserAuth, func(res http.ResponseWriter, req *http.Request) (goth.User, error) { + return goth.User{Provider: "dummy-auth-source", UserID: "dummy-user"}, nil + })() + + addOAuth2Source(t, "dummy-auth-source", oauth2.Source{}) + + mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockStore("dummy-sid")} + ctx, resp := contexttest.MockContext(t, "/user/oauth2/dummy-auth-source/callback?code=dummy-code", mockOpt) + ctx.SetParams("provider", "dummy-auth-source") + SignInOAuthCallback(ctx) + assert.Equal(t, http.StatusSeeOther, resp.Code) + assert.Equal(t, "/user/link_account", test.RedirectURL(resp)) + + // then the user will be redirected to the link account page, and see a message about the missing fields + ctx, _ = contexttest.MockContext(t, "/user/link_account", mockOpt) + LinkAccount(ctx) + assert.EqualValues(t, "auth.oauth_callback_unable_auto_reg:dummy-auth-source,email", ctx.Data["AutoRegistrationFailedPrompt"]) +} diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index f744a57a43..24130df634 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -48,23 +48,27 @@ func LinkAccount(ctx *context.Context) { ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" ctx.Data["SignUpLink"] = setting.AppSubURL + "/user/link_account_signup" - gothUser := ctx.Session.Get("linkAccountGothUser") - if gothUser == nil { - ctx.ServerError("UserSignIn", errors.New("not in LinkAccount session")) + gothUser, ok := ctx.Session.Get("linkAccountGothUser").(goth.User) + if !ok { + // no account in session, so just redirect to the login page, then the user could restart the process + ctx.Redirect(setting.AppSubURL + "/user/login") return } - gu, _ := gothUser.(goth.User) - uname, err := getUserName(&gu) + if missingFields, ok := gothUser.RawData["__giteaAutoRegMissingFields"].([]string); ok { + ctx.Data["AutoRegistrationFailedPrompt"] = ctx.Tr("auth.oauth_callback_unable_auto_reg", gothUser.Provider, strings.Join(missingFields, ",")) + } + + uname, err := extractUserNameFromOAuth2(&gothUser) if err != nil { ctx.ServerError("UserSignIn", err) return } - email := gu.Email + email := gothUser.Email ctx.Data["user_name"] = uname ctx.Data["email"] = email - if len(email) != 0 { + if email != "" { u, err := user_model.GetUserByEmail(ctx, email) if err != nil && !user_model.IsErrUserNotExist(err) { ctx.ServerError("UserSignIn", err) @@ -73,7 +77,7 @@ func LinkAccount(ctx *context.Context) { if u != nil { ctx.Data["user_exists"] = true } - } else if len(uname) != 0 { + } else if uname != "" { u, err := user_model.GetUserByName(ctx, uname) if err != nil && !user_model.IsErrUserNotExist(err) { ctx.ServerError("UserSignIn", err) diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 3189d1372e..c9cb7859cd 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -934,7 +934,7 @@ func SignInOAuthCallback(ctx *context.Context) { if u == nil { if ctx.Doer != nil { - // attach user to already logged in user + // attach user to the current signed-in user err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser) if err != nil { ctx.ServerError("UserLinkAccount", err) @@ -952,23 +952,32 @@ func SignInOAuthCallback(ctx *context.Context) { if gothUser.Email == "" { missingFields = append(missingFields, "email") } - if setting.OAuth2Client.Username == setting.OAuth2UsernameNickname && gothUser.NickName == "" { - missingFields = append(missingFields, "nickname") - } - if len(missingFields) > 0 { - log.Error("OAuth2 Provider %s returned empty or missing fields: %s", authSource.Name, missingFields) - if authSource.IsOAuth2() && authSource.Cfg.(*oauth2.Source).Provider == "openidConnect" { - log.Error("You may need to change the 'OPENID_CONNECT_SCOPES' setting to request all required fields") - } - err = fmt.Errorf("OAuth2 Provider %s returned empty or missing fields: %s", authSource.Name, missingFields) - ctx.ServerError("CreateUser", err) - return - } - uname, err := getUserName(&gothUser) + uname, err := extractUserNameFromOAuth2(&gothUser) if err != nil { ctx.ServerError("UserSignIn", err) return } + if uname == "" { + if setting.OAuth2Client.Username == setting.OAuth2UsernameNickname { + missingFields = append(missingFields, "nickname") + } else if setting.OAuth2Client.Username == setting.OAuth2UsernamePreferredUsername { + missingFields = append(missingFields, "preferred_username") + } // else: "UserID" and "Email" have been handled above separately + } + if len(missingFields) > 0 { + log.Error(`OAuth2 auto registration (ENABLE_AUTO_REGISTRATION) is enabled but OAuth2 provider %q doesn't return required fields: %s. `+ + `Suggest to: disable auto registration, or make OPENID_CONNECT_SCOPES (for OpenIDConnect) / Authentication Source Scopes (for Admin panel) to request all required fields, and the fields shouldn't be empty.`, + authSource.Name, strings.Join(missingFields, ",")) + // The RawData is the only way to pass the missing fields to the another page at the moment, other ways all have various problems: + // by session or cookie: difficult to clean or reset; by URL: could be injected with uncontrollable content; by ctx.Flash: the link_account page is a mess ... + // Since the RawData is for the provider's data, so we need to use our own prefix here to avoid conflict. + if gothUser.RawData == nil { + gothUser.RawData = make(map[string]any) + } + gothUser.RawData["__giteaAutoRegMissingFields"] = missingFields + showLinkingLogin(ctx, gothUser) + return + } u = &user_model.User{ Name: uname, FullName: gothUser.Name, diff --git a/services/context/context.go b/services/context/context.go index 88ab5cae0e..aab0485f1a 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -20,14 +20,13 @@ import ( "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" + "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" web_types "code.gitea.io/gitea/modules/web/types" - - "gitea.com/go-chi/session" ) // Render represents a template render @@ -154,7 +153,7 @@ func Contexter() func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { base, baseCleanUp := NewBaseContext(resp, req) defer baseCleanUp() - ctx := NewWebContext(base, rnd, session.GetSession(req)) + ctx := NewWebContext(base, rnd, session.GetContextSession(req)) ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index 3064c56590..0c1e5ee54f 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -19,7 +19,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" + "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web/middleware" @@ -43,7 +45,8 @@ func mockRequest(t *testing.T, reqPath string) *http.Request { } type MockContextOption struct { - Render context.Render + Render context.Render + SessionStore *session.MockStore } // MockContext mock context for unit tests @@ -62,12 +65,17 @@ func MockContext(t *testing.T, reqPath string, opts ...MockContextOption) (*cont base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} + chiCtx := chi.NewRouteContext() ctx := context.NewWebContext(base, opt.Render, nil) ctx.AppendContextValue(context.WebContextKey, ctx) + ctx.AppendContextValue(chi.RouteCtxKey, chiCtx) + if opt.SessionStore != nil { + ctx.AppendContextValue(session.MockStoreContextKey, opt.SessionStore) + ctx.Session = opt.SessionStore + } + ctx.Cache = cache.GetCache() ctx.PageData = map[string]any{} ctx.Data["PageStartTime"] = time.Now() - chiCtx := chi.NewRouteContext() - ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) return ctx, resp } diff --git a/templates/user/auth/link_account.tmpl b/templates/user/auth/link_account.tmpl index 8dd49ccd60..a99e172d05 100644 --- a/templates/user/auth/link_account.tmpl +++ b/templates/user/auth/link_account.tmpl @@ -17,15 +17,12 @@
-
+
+ {{if .AutoRegistrationFailedPrompt}}
{{.AutoRegistrationFailedPrompt}}
{{end}} {{template "user/auth/signup_inner" .}}
-
- +
+ {{template "user/auth/signin_inner" .}}
From fd63b96f6a4c5b3ea9e53d37af85e0d2d09715b9 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 25 Apr 2024 21:01:38 +0800 Subject: [PATCH 04/19] Refactor imagediff and fix regression bug (#30694) Fix #30683 --- web_src/js/features/imagediff.js | 204 +++++++++++++++---------------- 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/web_src/js/features/imagediff.js b/web_src/js/features/imagediff.js index 192a642834..d1b139ffde 100644 --- a/web_src/js/features/imagediff.js +++ b/web_src/js/features/imagediff.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import {GET} from '../modules/fetch.js'; -import {hideElem, loadElem} from '../utils/dom.js'; +import {hideElem, loadElem, queryElemChildren} from '../utils/dom.js'; import {parseDom} from '../utils.js'; function getDefaultSvgBoundsIfUndefined(text, src) { @@ -38,36 +38,36 @@ function getDefaultSvgBoundsIfUndefined(text, src) { return null; } +function createContext(imageAfter, imageBefore) { + const sizeAfter = { + width: imageAfter?.width || 0, + height: imageAfter?.height || 0, + }; + const sizeBefore = { + width: imageBefore?.width || 0, + height: imageBefore?.height || 0, + }; + const maxSize = { + width: Math.max(sizeBefore.width, sizeAfter.width), + height: Math.max(sizeBefore.height, sizeAfter.height), + }; + + return { + imageAfter, + imageBefore, + sizeAfter, + sizeBefore, + maxSize, + ratio: [ + Math.floor(maxSize.width - sizeAfter.width) / 2, + Math.floor(maxSize.height - sizeAfter.height) / 2, + Math.floor(maxSize.width - sizeBefore.width) / 2, + Math.floor(maxSize.height - sizeBefore.height) / 2, + ], + }; +} + export function initImageDiff() { - function createContext(image1, image2) { - const size1 = { - width: image1 && image1.width || 0, - height: image1 && image1.height || 0, - }; - const size2 = { - width: image2 && image2.width || 0, - height: image2 && image2.height || 0, - }; - const max = { - width: Math.max(size2.width, size1.width), - height: Math.max(size2.height, size1.height), - }; - - return { - $image1: $(image1), - $image2: $(image2), - size1, - size2, - max, - ratio: [ - Math.floor(max.width - size1.width) / 2, - Math.floor(max.height - size1.height) / 2, - Math.floor(max.width - size2.width) / 2, - Math.floor(max.height - size2.height) / 2, - ], - }; - } - $('.image-diff:not([data-image-diff-loaded])').each(async function() { const $container = $(this); this.setAttribute('data-image-diff-loaded', 'true'); @@ -116,94 +116,96 @@ export function initImageDiff() { initOverlay(createContext($imagesAfter[2], $imagesBefore[2])); } - this.querySelector(':scope > .image-diff-tabs')?.classList.remove('is-loading'); + queryElemChildren(this, '.image-diff-tabs', (el) => el.classList.remove('is-loading')); function initSideBySide(container, sizes) { let factor = 1; - if (sizes.max.width > (diffContainerWidth - 24) / 2) { - factor = (diffContainerWidth - 24) / 2 / sizes.max.width; + if (sizes.maxSize.width > (diffContainerWidth - 24) / 2) { + factor = (diffContainerWidth - 24) / 2 / sizes.maxSize.width; } - const widthChanged = sizes.$image1.length !== 0 && sizes.$image2.length !== 0 && sizes.$image1[0].naturalWidth !== sizes.$image2[0].naturalWidth; - const heightChanged = sizes.$image1.length !== 0 && sizes.$image2.length !== 0 && sizes.$image1[0].naturalHeight !== sizes.$image2[0].naturalHeight; - if (sizes.$image1?.length) { + const widthChanged = sizes.imageAfter && sizes.imageBefore && sizes.imageAfter.naturalWidth !== sizes.imageBefore.naturalWidth; + const heightChanged = sizes.imageAfter && sizes.imageBefore && sizes.imageAfter.naturalHeight !== sizes.imageBefore.naturalHeight; + if (sizes.imageAfter) { const boundsInfoAfterWidth = container.querySelector('.bounds-info-after .bounds-info-width'); - boundsInfoAfterWidth.textContent = `${sizes.$image1[0].naturalWidth}px`; - if (widthChanged) boundsInfoAfterWidth.classList.add('green'); - + if (boundsInfoAfterWidth) { + boundsInfoAfterWidth.textContent = `${sizes.imageAfter.naturalWidth}px`; + boundsInfoAfterWidth.classList.toggle('green', widthChanged); + } const boundsInfoAfterHeight = container.querySelector('.bounds-info-after .bounds-info-height'); - boundsInfoAfterHeight.textContent = `${sizes.$image1[0].naturalHeight}px`; - if (heightChanged) boundsInfoAfterHeight.classList.add('green'); + if (boundsInfoAfterHeight) { + boundsInfoAfterHeight.textContent = `${sizes.imageAfter.naturalHeight}px`; + boundsInfoAfterHeight.classList.toggle('green', heightChanged); + } } - if (sizes.$image2?.length) { + if (sizes.imageBefore) { const boundsInfoBeforeWidth = container.querySelector('.bounds-info-before .bounds-info-width'); - boundsInfoBeforeWidth.textContent = `${sizes.$image2[0].naturalWidth}px`; - if (widthChanged) boundsInfoBeforeWidth.classList.add('red'); - + if (boundsInfoBeforeWidth) { + boundsInfoBeforeWidth.textContent = `${sizes.imageBefore.naturalWidth}px`; + boundsInfoBeforeWidth.classList.toggle('red', widthChanged); + } const boundsInfoBeforeHeight = container.querySelector('.bounds-info-before .bounds-info-height'); - boundsInfoBeforeHeight.textContent = `${sizes.$image2[0].naturalHeight}px`; - if (heightChanged) boundsInfoBeforeHeight.classList.add('red'); + if (boundsInfoBeforeHeight) { + boundsInfoBeforeHeight.textContent = `${sizes.imageBefore.naturalHeight}px`; + boundsInfoBeforeHeight.classList.add('red', heightChanged); + } } - const image1 = sizes.$image1[0]; - if (image1) { - const container = image1.parentNode; - image1.style.width = `${sizes.size1.width * factor}px`; - image1.style.height = `${sizes.size1.height * factor}px`; + if (sizes.imageAfter) { + const container = sizes.imageAfter.parentNode; + sizes.imageAfter.style.width = `${sizes.sizeAfter.width * factor}px`; + sizes.imageAfter.style.height = `${sizes.sizeAfter.height * factor}px`; container.style.margin = '10px auto'; - container.style.width = `${sizes.size1.width * factor + 2}px`; - container.style.height = `${sizes.size1.height * factor + 2}px`; + container.style.width = `${sizes.sizeAfter.width * factor + 2}px`; + container.style.height = `${sizes.sizeAfter.height * factor + 2}px`; } - const image2 = sizes.$image2[0]; - if (image2) { - const container = image2.parentNode; - image2.style.width = `${sizes.size2.width * factor}px`; - image2.style.height = `${sizes.size2.height * factor}px`; + if (sizes.imageBefore) { + const container = sizes.imageBefore.parentNode; + sizes.imageBefore.style.width = `${sizes.sizeBefore.width * factor}px`; + sizes.imageBefore.style.height = `${sizes.sizeBefore.height * factor}px`; container.style.margin = '10px auto'; - container.style.width = `${sizes.size2.width * factor + 2}px`; - container.style.height = `${sizes.size2.height * factor + 2}px`; + container.style.width = `${sizes.sizeBefore.width * factor + 2}px`; + container.style.height = `${sizes.sizeBefore.height * factor + 2}px`; } } function initSwipe(sizes) { let factor = 1; - if (sizes.max.width > diffContainerWidth - 12) { - factor = (diffContainerWidth - 12) / sizes.max.width; + if (sizes.maxSize.width > diffContainerWidth - 12) { + factor = (diffContainerWidth - 12) / sizes.maxSize.width; } - const image1 = sizes.$image1[0]; - if (image1) { - const container = image1.parentNode; + if (sizes.imageAfter) { + const container = sizes.imageAfter.parentNode; const swipeFrame = container.parentNode; - image1.style.width = `${sizes.size1.width * factor}px`; - image1.style.height = `${sizes.size1.height * factor}px`; + sizes.imageAfter.style.width = `${sizes.sizeAfter.width * factor}px`; + sizes.imageAfter.style.height = `${sizes.sizeAfter.height * factor}px`; container.style.margin = `0px ${sizes.ratio[0] * factor}px`; - container.style.width = `${sizes.size1.width * factor + 2}px`; - container.style.height = `${sizes.size1.height * factor + 2}px`; + container.style.width = `${sizes.sizeAfter.width * factor + 2}px`; + container.style.height = `${sizes.sizeAfter.height * factor + 2}px`; swipeFrame.style.padding = `${sizes.ratio[1] * factor}px 0 0 0`; - swipeFrame.style.width = `${sizes.max.width * factor + 2}px`; + swipeFrame.style.width = `${sizes.maxSize.width * factor + 2}px`; } - const image2 = sizes.$image2[0]; - if (image2) { - const container = image2.parentNode; + if (sizes.imageBefore) { + const container = sizes.imageBefore.parentNode; const swipeFrame = container.parentNode; - image2.style.width = `${sizes.size2.width * factor}px`; - image2.style.height = `${sizes.size2.height * factor}px`; + sizes.imageBefore.style.width = `${sizes.sizeBefore.width * factor}px`; + sizes.imageBefore.style.height = `${sizes.sizeBefore.height * factor}px`; container.style.margin = `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`; - container.style.width = `${sizes.size2.width * factor + 2}px`; - container.style.height = `${sizes.size2.height * factor + 2}px`; - swipeFrame.style.width = `${sizes.max.width * factor + 2}px`; - swipeFrame.style.height = `${sizes.max.height * factor + 2}px`; + container.style.width = `${sizes.sizeBefore.width * factor + 2}px`; + container.style.height = `${sizes.sizeBefore.height * factor + 2}px`; + swipeFrame.style.width = `${sizes.maxSize.width * factor + 2}px`; + swipeFrame.style.height = `${sizes.maxSize.height * factor + 2}px`; } // extra height for inner "position: absolute" elements const swipe = $container.find('.diff-swipe')[0]; if (swipe) { - swipe.style.width = `${sizes.max.width * factor + 2}px`; - swipe.style.height = `${sizes.max.height * factor + 30}px`; + swipe.style.width = `${sizes.maxSize.width * factor + 2}px`; + swipe.style.height = `${sizes.maxSize.height * factor + 30}px`; } $container.find('.swipe-bar').on('mousedown', function(e) { @@ -229,39 +231,37 @@ export function initImageDiff() { function initOverlay(sizes) { let factor = 1; - if (sizes.max.width > diffContainerWidth - 12) { - factor = (diffContainerWidth - 12) / sizes.max.width; + if (sizes.maxSize.width > diffContainerWidth - 12) { + factor = (diffContainerWidth - 12) / sizes.maxSize.width; } - const image1 = sizes.$image1[0]; - if (image1) { - const container = image1.parentNode; - image1.style.width = `${sizes.size1.width * factor}px`; - image1.style.height = `${sizes.size1.height * factor}px`; + if (sizes.imageAfter) { + const container = sizes.imageAfter.parentNode; + sizes.imageAfter.style.width = `${sizes.sizeAfter.width * factor}px`; + sizes.imageAfter.style.height = `${sizes.sizeAfter.height * factor}px`; container.style.margin = `${sizes.ratio[1] * factor}px ${sizes.ratio[0] * factor}px`; - container.style.width = `${sizes.size1.width * factor + 2}px`; - container.style.height = `${sizes.size1.height * factor + 2}px`; + container.style.width = `${sizes.sizeAfter.width * factor + 2}px`; + container.style.height = `${sizes.sizeAfter.height * factor + 2}px`; } - const image2 = sizes.$image2[0]; - if (image2) { - const container = image2.parentNode; + if (sizes.imageBefore) { + const container = sizes.imageBefore.parentNode; const overlayFrame = container.parentNode; - image2.style.width = `${sizes.size2.width * factor}px`; - image2.style.height = `${sizes.size2.height * factor}px`; + sizes.imageBefore.style.width = `${sizes.sizeBefore.width * factor}px`; + sizes.imageBefore.style.height = `${sizes.sizeBefore.height * factor}px`; container.style.margin = `${sizes.ratio[3] * factor}px ${sizes.ratio[2] * factor}px`; - container.style.width = `${sizes.size2.width * factor + 2}px`; - container.style.height = `${sizes.size2.height * factor + 2}px`; + container.style.width = `${sizes.sizeBefore.width * factor + 2}px`; + container.style.height = `${sizes.sizeBefore.height * factor + 2}px`; // some inner elements are `position: absolute`, so the container's height must be large enough - overlayFrame.style.width = `${sizes.max.width * factor + 2}px`; - overlayFrame.style.height = `${sizes.max.height * factor + 2}px`; + overlayFrame.style.width = `${sizes.maxSize.width * factor + 2}px`; + overlayFrame.style.height = `${sizes.maxSize.height * factor + 2}px`; } const rangeInput = $container[0].querySelector('input[type="range"]'); function updateOpacity() { - if (sizes?.$image1?.[0]) { - sizes.$image1[0].parentNode.style.opacity = `${rangeInput.value / 100}`; + if (sizes.imageAfter) { + sizes.imageAfter.parentNode.style.opacity = `${rangeInput.value / 100}`; } } rangeInput?.addEventListener('input', updateOpacity); From 935330b1b98a232f2928d55e96dc425e09bda593 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Fri, 26 Apr 2024 00:26:00 +0000 Subject: [PATCH 05/19] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 4b7604a5cb..444f784af9 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -2358,7 +2358,7 @@ settings.protected_branch.delete_rule=Eliminar regra settings.protected_branch_can_push=Permitir envios? settings.protected_branch_can_push_yes=Pode enviar settings.protected_branch_can_push_no=Não pode enviar -settings.branch_protection=Salvaguarda do ramo '%s' +settings.branch_protection=Regras de salvaguarda do ramo '%s' settings.protect_this_branch=Habilitar salvaguarda do ramo settings.protect_this_branch_desc=Impede a eliminação e restringe envios e integrações do Git no ramo. settings.protect_disable_push=Desabilitar envios @@ -2402,7 +2402,7 @@ settings.protect_patterns=Padrões settings.protect_protected_file_patterns=Padrões de ficheiros protegidos (separados com ponto e vírgula ';'): settings.protect_protected_file_patterns_desc=Ficheiros protegidos não podem ser modificados imediatamente, mesmo que o utilizador tenha direitos para adicionar, editar ou eliminar ficheiros neste ramo. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação em github.com/gobwas/glob para ver a sintaxe. Exemplos: .drone.yml, /docs/**/*.txt. settings.protect_unprotected_file_patterns=Padrões de ficheiros desprotegidos (separados com ponto e vírgula ';'): -settings.protect_unprotected_file_patterns_desc=Ficheiros desprotegidos que podem ser modificados imediatamente se o utilizador tiver direitos de escrita, contornando a restrição no envio. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação em github.com/gobwas/glob para ver a sintaxe. Exemplos: .drone.yml, /docs/**/*.txt. +settings.protect_unprotected_file_patterns_desc=Ficheiros desprotegidos que podem ser modificados imediatamente se o utilizador tiver direitos de escrita, contornando a restrição no envio. Padrões múltiplos podem ser separados com ponto e vírgula (';'). Veja a documentação em github.com/gobwas/glob para ver a sintaxe. Exemplos: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Habilitar salvaguarda settings.delete_protected_branch=Desabilitar salvaguarda settings.update_protect_branch_success=A salvaguarda do ramo "%s" foi modificada. @@ -2418,7 +2418,7 @@ settings.block_outdated_branch=Bloquear integração se o pedido de integração settings.block_outdated_branch_desc=A integração não será possível quando o ramo de topo estiver abaixo do ramo base. settings.default_branch_desc=Escolha um ramo do repositório como sendo o predefinido para pedidos de integração e cometimentos: settings.merge_style_desc=Estilos de integração -settings.default_merge_style_desc=Tipo de integração predefinido para pedidos de integração: +settings.default_merge_style_desc=Tipo de integração predefinido settings.choose_branch=Escolha um ramo… settings.no_protected_branch=Não existem ramos protegidos. settings.edit_protected_branch=Editar @@ -2788,7 +2788,7 @@ self_check=Auto-verificação identity_access=Identidade e acesso users=Contas de utilizador organizations=Organizações -assets=Recursos de código +assets=Recursos do código-fonte repositories=Repositórios hooks=Automatismos web integrations=Integrações @@ -2869,14 +2869,14 @@ dashboard.mspan_structures_obtained=Estruturas MSpan obtidas dashboard.mcache_structures_usage=Uso das estruturas MCache dashboard.mcache_structures_obtained=Estruturas MCache obtidas dashboard.profiling_bucket_hash_table_obtained=Perfil obtido da tabela de hash do balde -dashboard.gc_metadata_obtained=Metadados da recolha de lixo obtidos +dashboard.gc_metadata_obtained=Metadados obtidos da recolha de lixo dashboard.other_system_allocation_obtained=Outras alocações de sistema obtidas dashboard.next_gc_recycle=Próxima reciclagem da recolha de lixo dashboard.last_gc_time=Tempo decorrido desde a última recolha de lixo dashboard.total_gc_time=Pausa total da recolha de lixo dashboard.total_gc_pause=Pausa total da recolha de lixo dashboard.last_gc_pause=Última pausa da recolha de lixo -dashboard.gc_times=Tempos da recolha de lixo +dashboard.gc_times=N.º de recolhas de lixo dashboard.delete_old_actions=Eliminar todas as operações antigas da base de dados dashboard.delete_old_actions.started=Foi iniciado o processo de eliminação de todas as operações antigas da base de dados. dashboard.update_checker=Verificador de novas versões @@ -3025,7 +3025,7 @@ auths.attribute_surname=Atributo do Sobrenome auths.attribute_mail=Atributo do email auths.attribute_ssh_public_key=Atributo da chave pública SSH auths.attribute_avatar=Atributo do avatar -auths.attributes_in_bind=Buscar os atributos no contexto de Bind DN +auths.attributes_in_bind=Buscar atributos no contexto do Bind DN auths.allow_deactivate_all=Permitir que um resultado de pesquisa vazio desabilite todos os utilizadores auths.use_paged_search=Usar pesquisa paginada auths.search_page_size=Tamanho da página @@ -3224,7 +3224,7 @@ config.session_config=Configuração de sessão config.session_provider=Fornecedor da sessão config.provider_config=Configuração do fornecedor config.cookie_name=Nome do cookie -config.gc_interval_time=Intervalo da recolha do lixo +config.gc_interval_time=Intervalo de tempo entre recolhas do lixo config.session_life_time=Tempo de vida da sessão config.https_only=Apenas HTTPS config.cookie_life_time=Tempo de vida do cookie From 6a0750177fe4c494f828463bc146ea11df08a422 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 26 Apr 2024 09:17:43 +0800 Subject: [PATCH 06/19] Allow to save empty comment (#30706) Fix #29986 --- routers/web/repo/issue.go | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 95f0cf3d71..1bc5f343e7 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -3149,13 +3149,10 @@ func UpdateCommentContent(ctx *context.Context) { } oldContent := comment.Content - comment.Content = ctx.FormString("content") - if len(comment.Content) == 0 { - ctx.JSON(http.StatusOK, map[string]any{ - "content": "", - }) - return - } + newContent := ctx.FormString("content") + + // allow to save empty content + comment.Content = newContent if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { if errors.Is(err, user_model.ErrBlockedUser) { ctx.JSONError(ctx.Tr("repo.issues.comment.blocked_user")) @@ -3178,21 +3175,27 @@ func UpdateCommentContent(ctx *context.Context) { } } - content, err := markdown.RenderString(&markup.RenderContext{ - Links: markup.Links{ - Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ? - }, - Metas: ctx.Repo.Repository.ComposeMetas(ctx), - GitRepo: ctx.Repo.GitRepo, - Ctx: ctx, - }, comment.Content) - if err != nil { - ctx.ServerError("RenderString", err) - return + var renderedContent template.HTML + if comment.Content != "" { + renderedContent, err = markdown.RenderString(&markup.RenderContext{ + Links: markup.Links{ + Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ? + }, + Metas: ctx.Repo.Repository.ComposeMetas(ctx), + GitRepo: ctx.Repo.GitRepo, + Ctx: ctx, + }, comment.Content) + if err != nil { + ctx.ServerError("RenderString", err) + return + } + } else { + contentEmpty := fmt.Sprintf(`%s`, ctx.Tr("repo.issues.no_content")) + renderedContent = template.HTML(contentEmpty) } ctx.JSON(http.StatusOK, map[string]any{ - "content": content, + "content": renderedContent, "attachments": attachmentsHTML(ctx, comment.Attachments, comment.Content), }) } From 2a6418abb1e227f7d0401761a5f68d59a1cea9b2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 26 Apr 2024 09:52:28 +0800 Subject: [PATCH 07/19] Improve test for TestPullCompare (#30699) --- tests/integration/pull_compare_test.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go index b814207b2f..39d9103dfd 100644 --- a/tests/integration/pull_compare_test.go +++ b/tests/integration/pull_compare_test.go @@ -4,11 +4,13 @@ package integration import ( + "fmt" "net/http" "net/url" "testing" "code.gitea.io/gitea/models/db" + issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -46,22 +48,25 @@ func TestPullCompare(t *testing.T) { testRepoFork(t, session, "user2", "repo1", "user1", "repo1") testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusSeeOther) testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n") - resp = testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") + testPullCreate(t, session, "user1", "repo1", false, "master", "master1", "This is a pull title") - // the max value on issue_index.yml for repo_id=1 is 5 - req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files") + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + issueIndex := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueIndex{GroupID: repo1.ID}, unittest.OrderBy("group_id ASC")) + prFilesURL := fmt.Sprintf("/user2/repo1/pulls/%d/files", issueIndex.MaxIndex) + req = NewRequest(t, "GET", prFilesURL) resp = session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) editButtonCount := doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() assert.Greater(t, editButtonCount, 0, "Expected to find a button to edit a file in the PR diff view but there were none") - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repoForked := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: "repo1"}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + // delete the head repository and revisit the PR diff view err := repo_service.DeleteRepositoryDirectly(db.DefaultContext, user2, repoForked.ID) assert.NoError(t, err) - req = NewRequest(t, "GET", "/user2/repo1/pulls/6/files") + req = NewRequest(t, "GET", prFilesURL) resp = session.MakeRequest(t, req, http.StatusOK) doc = NewHTMLParser(t, resp.Body) editButtonCount = doc.doc.Find(".diff-file-header-actions a[href*='/_edit/']").Length() From 2a3906d75532ba8689338247d794f21dceb4d359 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Fri, 26 Apr 2024 11:22:45 +0900 Subject: [PATCH 08/19] Improve job commit description (#30579) Fix https://github.com/go-gitea/gitea/issues/30567 When job is a schedule: ![image](https://github.com/go-gitea/gitea/assets/18380374/b07e9d43-e8b7-4ee2-87b3-a7050c3a8ca5) When it is a normal one: ![image](https://github.com/go-gitea/gitea/assets/18380374/0d58dab9-74bb-421b-8952-0578cdf21a52) also add a 'space' behind `:` ![image](https://github.com/go-gitea/gitea/assets/18380374/4cebece0-bfe6-4ad9-b806-e5c49bb9be43) ![image](https://github.com/go-gitea/gitea/assets/18380374/02da7681-474b-4c0f-9dad-b6558f6cb484) --------- Co-authored-by: wxiaoguang --- models/actions/run.go | 11 ++++++++++ routers/web/repo/actions/view.go | 26 +++++++++++++----------- templates/repo/actions/runs_list.tmpl | 2 +- templates/repo/actions/view.tmpl | 3 +++ web_src/js/components/RepoActionView.vue | 22 +++++++++++++++----- 5 files changed, 46 insertions(+), 18 deletions(-) diff --git a/models/actions/run.go b/models/actions/run.go index b75fa49f3c..d68710f46d 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -74,6 +74,13 @@ func (run *ActionRun) Link() string { return fmt.Sprintf("%s/actions/runs/%d", run.Repo.Link(), run.Index) } +func (run *ActionRun) WorkflowLink() string { + if run.Repo == nil { + return "" + } + return fmt.Sprintf("%s/actions/?workflow=%s", run.Repo.Link(), run.WorkflowID) +} + // RefLink return the url of run's ref func (run *ActionRun) RefLink() string { refName := git.RefName(run.Ref) @@ -156,6 +163,10 @@ func (run *ActionRun) GetPullRequestEventPayload() (*api.PullRequestPayload, err return nil, fmt.Errorf("event %s is not a pull request event", run.Event) } +func (run *ActionRun) IsSchedule() bool { + return run.ScheduleID > 0 +} + func updateRepoRunsNumbers(ctx context.Context, repo *repo_model.Repository) error { _, err := db.GetEngine(ctx).ID(repo.ID). SetExpr("num_action_runs", diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index db2b11a7ed..3909a64be6 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -67,6 +67,9 @@ type ViewResponse struct { CanRerun bool `json:"canRerun"` CanDeleteArtifact bool `json:"canDeleteArtifact"` Done bool `json:"done"` + WorkflowID string `json:"workflowID"` + WorkflowLink string `json:"workflowLink"` + IsSchedule bool `json:"isSchedule"` Jobs []*ViewJob `json:"jobs"` Commit ViewCommit `json:"commit"` } `json:"run"` @@ -90,12 +93,10 @@ type ViewJob struct { } type ViewCommit struct { - LocaleCommit string `json:"localeCommit"` - LocalePushedBy string `json:"localePushedBy"` - ShortSha string `json:"shortSHA"` - Link string `json:"link"` - Pusher ViewUser `json:"pusher"` - Branch ViewBranch `json:"branch"` + ShortSha string `json:"shortSHA"` + Link string `json:"link"` + Pusher ViewUser `json:"pusher"` + Branch ViewBranch `json:"branch"` } type ViewUser struct { @@ -151,6 +152,9 @@ func ViewPost(ctx *context_module.Context) { resp.State.Run.CanRerun = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.CanDeleteArtifact = run.Status.IsDone() && ctx.Repo.CanWrite(unit.TypeActions) resp.State.Run.Done = run.Status.IsDone() + resp.State.Run.WorkflowID = run.WorkflowID + resp.State.Run.WorkflowLink = run.WorkflowLink() + resp.State.Run.IsSchedule = run.IsSchedule() resp.State.Run.Jobs = make([]*ViewJob, 0, len(jobs)) // marshal to '[]' instead fo 'null' in json resp.State.Run.Status = run.Status.String() for _, v := range jobs { @@ -172,12 +176,10 @@ func ViewPost(ctx *context_module.Context) { Link: run.RefLink(), } resp.State.Run.Commit = ViewCommit{ - LocaleCommit: ctx.Locale.TrString("actions.runs.commit"), - LocalePushedBy: ctx.Locale.TrString("actions.runs.pushed_by"), - ShortSha: base.ShortSha(run.CommitSHA), - Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA), - Pusher: pusher, - Branch: branch, + ShortSha: base.ShortSha(run.CommitSHA), + Link: fmt.Sprintf("%s/commit/%s", run.Repo.Link(), run.CommitSHA), + Pusher: pusher, + Branch: branch, } var task *actions_model.ActionTask diff --git a/templates/repo/actions/runs_list.tmpl b/templates/repo/actions/runs_list.tmpl index 20330b5d62..09a25ce8bd 100644 --- a/templates/repo/actions/runs_list.tmpl +++ b/templates/repo/actions/runs_list.tmpl @@ -15,7 +15,7 @@ {{if .Title}}{{.Title}}{{else}}{{ctx.Locale.Tr "actions.runs.empty_commit_message"}}{{end}}
- {{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}: + {{if not $.CurWorkflow}}{{.WorkflowID}} {{end}}#{{.Index}}: {{- if .ScheduleID -}} {{ctx.Locale.Tr "actions.runs.scheduled"}} {{- else -}} diff --git a/templates/repo/actions/view.tmpl b/templates/repo/actions/view.tmpl index f8b106147b..f7b03608ee 100644 --- a/templates/repo/actions/view.tmpl +++ b/templates/repo/actions/view.tmpl @@ -10,6 +10,9 @@ data-locale-cancel="{{ctx.Locale.Tr "cancel"}}" data-locale-rerun="{{ctx.Locale.Tr "rerun"}}" data-locale-rerun-all="{{ctx.Locale.Tr "rerun_all"}}" + data-locale-runs-scheduled="{{ctx.Locale.Tr "actions.runs.scheduled"}}" + data-locale-runs-commit="{{ctx.Locale.Tr "actions.runs.commit"}}" + data-locale-runs-pushed-by="{{ctx.Locale.Tr "actions.runs.pushed_by"}}" data-locale-status-unknown="{{ctx.Locale.Tr "actions.status.unknown"}}" data-locale-status-waiting="{{ctx.Locale.Tr "actions.status.waiting"}}" data-locale-status-running="{{ctx.Locale.Tr "actions.status.running"}}" diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 16ce3fc80d..8b39d0504b 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -44,6 +44,9 @@ const sfc = { canApprove: false, canRerun: false, done: false, + workflowID: '', + workflowLink: '', + isSchedule: false, jobs: [ // { // id: 0, @@ -338,10 +341,13 @@ export function initRepositoryActionView() { approve: el.getAttribute('data-locale-approve'), cancel: el.getAttribute('data-locale-cancel'), rerun: el.getAttribute('data-locale-rerun'), + rerun_all: el.getAttribute('data-locale-rerun-all'), + scheduled: el.getAttribute('data-locale-runs-scheduled'), + commit: el.getAttribute('data-locale-runs-commit'), + pushedBy: el.getAttribute('data-locale-runs-pushed-by'), artifactsTitle: el.getAttribute('data-locale-artifacts-title'), areYouSure: el.getAttribute('data-locale-are-you-sure'), confirmDeleteArtifact: el.getAttribute('data-locale-confirm-delete-artifact'), - rerun_all: el.getAttribute('data-locale-rerun-all'), showTimeStamps: el.getAttribute('data-locale-show-timestamps'), showLogSeconds: el.getAttribute('data-locale-show-log-seconds'), showFullScreen: el.getAttribute('data-locale-show-full-screen'), @@ -382,10 +388,16 @@ export function initRepositoryActionView() {
- {{ run.commit.localeCommit }} - {{ run.commit.shortSHA }} - {{ run.commit.localePushedBy }} - {{ run.commit.pusher.displayName }} + {{ run.workflowID }}: + + {{ run.commit.branch.name }} From ed8c63cea3da0d0ba3cdec58f6c6d61c73205afe Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 26 Apr 2024 10:53:30 +0800 Subject: [PATCH 09/19] Deduplicate lfs common code (#30704) --- modules/git/pipeline/lfs_common.go | 32 ++++++++++++++++++ modules/git/pipeline/{lfs.go => lfs_gogit.go} | 25 ++------------ modules/git/pipeline/lfs_nogogit.go | 33 ++++--------------- 3 files changed, 42 insertions(+), 48 deletions(-) create mode 100644 modules/git/pipeline/lfs_common.go rename modules/git/pipeline/{lfs.go => lfs_gogit.go} (80%) diff --git a/modules/git/pipeline/lfs_common.go b/modules/git/pipeline/lfs_common.go new file mode 100644 index 0000000000..188e7d4d65 --- /dev/null +++ b/modules/git/pipeline/lfs_common.go @@ -0,0 +1,32 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package pipeline + +import ( + "fmt" + "time" + + "code.gitea.io/gitea/modules/git" +) + +// LFSResult represents commits found using a provided pointer file hash +type LFSResult struct { + Name string + SHA string + Summary string + When time.Time + ParentHashes []git.ObjectID + BranchName string + FullCommitName string +} + +type lfsResultSlice []*LFSResult + +func (a lfsResultSlice) Len() int { return len(a) } +func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } + +func lfsError(msg string, err error) error { + return fmt.Errorf("LFS error occurred, %s: err: %w", msg, err) +} diff --git a/modules/git/pipeline/lfs.go b/modules/git/pipeline/lfs_gogit.go similarity index 80% rename from modules/git/pipeline/lfs.go rename to modules/git/pipeline/lfs_gogit.go index 6dfca24f29..adcf8ed09c 100644 --- a/modules/git/pipeline/lfs.go +++ b/modules/git/pipeline/lfs_gogit.go @@ -7,12 +7,10 @@ package pipeline import ( "bufio" - "fmt" "io" "sort" "strings" "sync" - "time" "code.gitea.io/gitea/modules/git" @@ -21,23 +19,6 @@ import ( "github.com/go-git/go-git/v5/plumbing/object" ) -// LFSResult represents commits found using a provided pointer file hash -type LFSResult struct { - Name string - SHA string - Summary string - When time.Time - ParentHashes []git.ObjectID - BranchName string - FullCommitName string -} - -type lfsResultSlice []*LFSResult - -func (a lfsResultSlice) Len() int { return len(a) } -func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } - // FindLFSFile finds commits that contain a provided pointer file hash func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) { resultsMap := map[string]*LFSResult{} @@ -51,7 +32,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err All: true, }) if err != nil { - return nil, fmt.Errorf("Failed to get GoGit CommitsIter. Error: %w", err) + return nil, lfsError("failed to get GoGit CommitsIter", err) } err = commitsIter.ForEach(func(gitCommit *object.Commit) error { @@ -85,7 +66,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err return nil }) if err != nil && err != io.EOF { - return nil, fmt.Errorf("Failure in CommitIter.ForEach: %w", err) + return nil, lfsError("failure in CommitIter.ForEach", err) } for _, result := range resultsMap { @@ -156,7 +137,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err select { case err, has := <-errChan: if has { - return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err) + return nil, lfsError("unable to obtain name for LFS files", err) } default: } diff --git a/modules/git/pipeline/lfs_nogogit.go b/modules/git/pipeline/lfs_nogogit.go index fe320f39f3..349cfbd9ce 100644 --- a/modules/git/pipeline/lfs_nogogit.go +++ b/modules/git/pipeline/lfs_nogogit.go @@ -8,33 +8,14 @@ package pipeline import ( "bufio" "bytes" - "fmt" "io" "sort" "strings" "sync" - "time" "code.gitea.io/gitea/modules/git" ) -// LFSResult represents commits found using a provided pointer file hash -type LFSResult struct { - Name string - SHA string - Summary string - When time.Time - ParentIDs []git.ObjectID - BranchName string - FullCommitName string -} - -type lfsResultSlice []*LFSResult - -func (a lfsResultSlice) Len() int { return len(a) } -func (a lfsResultSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a lfsResultSlice) Less(i, j int) bool { return a[j].When.After(a[i].When) } - // FindLFSFile finds commits that contain a provided pointer file hash func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, error) { resultsMap := map[string]*LFSResult{} @@ -137,11 +118,11 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err n += int64(count) if bytes.Equal(binObjectID, objectID.RawValue()) { result := LFSResult{ - Name: curPath + string(fname), - SHA: curCommit.ID.String(), - Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0], - When: curCommit.Author.When, - ParentIDs: curCommit.Parents, + Name: curPath + string(fname), + SHA: curCommit.ID.String(), + Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0], + When: curCommit.Author.When, + ParentHashes: curCommit.Parents, } resultsMap[curCommit.ID.String()+":"+curPath+string(fname)] = &result } else if string(mode) == git.EntryModeTree.String() { @@ -183,7 +164,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err for _, result := range resultsMap { hasParent := false - for _, parentID := range result.ParentIDs { + for _, parentID := range result.ParentHashes { if _, hasParent = resultsMap[parentID.String()+":"+result.Name]; hasParent { break } @@ -240,7 +221,7 @@ func FindLFSFile(repo *git.Repository, objectID git.ObjectID) ([]*LFSResult, err select { case err, has := <-errChan: if has { - return nil, fmt.Errorf("Unable to obtain name for LFS files. Error: %w", err) + return nil, lfsError("unable to obtain name for LFS files", err) } default: } From 68a3e6b5e64b4035aa0659cb6daa1c4d1eec892a Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Fri, 26 Apr 2024 10:27:34 +0300 Subject: [PATCH 10/19] Bump htmx version to 1.9.12 (#30711) There are no breaking changes. I tested and everything works as before. Signed-off-by: Yarden Shoham --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61d86f6b7c..780689a0a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "esbuild-loader": "4.1.0", "escape-goat": "4.0.0", "fast-glob": "3.3.2", - "htmx.org": "1.9.11", + "htmx.org": "1.9.12", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.10", @@ -6728,9 +6728,9 @@ } }, "node_modules/htmx.org": { - "version": "1.9.11", - "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.11.tgz", - "integrity": "sha512-WlVuICn8dfNOOgYmdYzYG8zSnP3++AdHkMHooQAzGZObWpVXYathpz/I37ycF4zikR6YduzfCvEcxk20JkIUsw==" + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.12.tgz", + "integrity": "sha512-VZAohXyF7xPGS52IM8d1T1283y+X4D+Owf3qY1NZ9RuBypyu9l8cGsxUMAG5fEAb/DhT7rDoJ9Hpu5/HxFD3cw==" }, "node_modules/human-signals": { "version": "5.0.0", diff --git a/package.json b/package.json index ff1ae4d49e..b0cb67ed4a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "esbuild-loader": "4.1.0", "escape-goat": "4.0.0", "fast-glob": "3.3.2", - "htmx.org": "1.9.11", + "htmx.org": "1.9.12", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.10", From 1e749b80d741c3a5c7eff6087d820e4d0d1ba3a2 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 26 Apr 2024 17:09:49 +0800 Subject: [PATCH 11/19] Add route handler info for debugging purpose (#30705) Follow #30519 --- routers/init.go | 6 ++++++ routers/web/web.go | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/routers/init.go b/routers/init.go index aaf95920c2..030ef3c740 100644 --- a/routers/init.go +++ b/routers/init.go @@ -5,6 +5,7 @@ package routers import ( "context" + "net/http" "reflect" "runtime" @@ -25,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/modules/web/routing" actions_router "code.gitea.io/gitea/routers/api/actions" packages_router "code.gitea.io/gitea/routers/api/packages" apiv1 "code.gitea.io/gitea/routers/api/v1" @@ -202,5 +204,9 @@ func NormalRoutes() *web.Route { r.Mount(prefix, actions_router.ArtifactsV4Routes(prefix)) } + r.NotFound(func(w http.ResponseWriter, req *http.Request) { + routing.UpdateFuncInfo(req.Context(), routing.GetFuncInfo(http.NotFound, "GlobalNotFound")) + http.NotFound(w, req) + }) return r } diff --git a/routers/web/web.go b/routers/web/web.go index c6132f0d61..9a6687059b 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1612,7 +1612,7 @@ func registerRoutes(m *web.Route) { m.NotFound(func(w http.ResponseWriter, req *http.Request) { ctx := context.GetWebContext(req) - routing.UpdateFuncInfo(ctx, routing.GetFuncInfo(ctx.NotFound, "GlobalNotFound")) + routing.UpdateFuncInfo(ctx, routing.GetFuncInfo(ctx.NotFound, "WebNotFound")) ctx.NotFound("", nil) }) } From cd70ab31cdee8116055819bf67bcf374e2aa6172 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 26 Apr 2024 17:49:48 +0800 Subject: [PATCH 12/19] Fix incorrect object id hash function (#30708) Great thanks to @oliverpool for figuring out the problem and proposing a fix. Regression of #28138 Incorrect hash causes the user's LFS files get all deleted when running `doctor fix all` (by the way, remove unused/non-standard comments) Co-authored-by: Giteabot --- modules/git/object_format.go | 16 ++++------------ modules/git/object_id.go | 3 --- modules/git/object_id_test.go | 4 ++++ 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/modules/git/object_format.go b/modules/git/object_format.go index a056b20e8a..3de9ff8cf4 100644 --- a/modules/git/object_format.go +++ b/modules/git/object_format.go @@ -33,7 +33,6 @@ type ObjectFormat interface { ComputeHash(t ObjectType, content []byte) ObjectID } -/* SHA1 Type */ type Sha1ObjectFormatImpl struct{} var ( @@ -70,14 +69,10 @@ func (h Sha1ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) ObjectID _, _ = hasher.Write([]byte(" ")) _, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10))) _, _ = hasher.Write([]byte{0}) - - // HashSum generates a SHA1 for the provided hash - var sha1 Sha1Hash - copy(sha1[:], hasher.Sum(nil)) - return &sha1 + _, _ = hasher.Write(content) + return h.MustID(hasher.Sum(nil)) } -/* SHA256 Type */ type Sha256ObjectFormatImpl struct{} var ( @@ -116,11 +111,8 @@ func (h Sha256ObjectFormatImpl) ComputeHash(t ObjectType, content []byte) Object _, _ = hasher.Write([]byte(" ")) _, _ = hasher.Write([]byte(strconv.FormatInt(int64(len(content)), 10))) _, _ = hasher.Write([]byte{0}) - - // HashSum generates a SHA256 for the provided hash - var sha256 Sha1Hash - copy(sha256[:], hasher.Sum(nil)) - return &sha256 + _, _ = hasher.Write(content) + return h.MustID(hasher.Sum(nil)) } var ( diff --git a/modules/git/object_id.go b/modules/git/object_id.go index 4f8c39ee1d..33e5085005 100644 --- a/modules/git/object_id.go +++ b/modules/git/object_id.go @@ -16,7 +16,6 @@ type ObjectID interface { Type() ObjectFormat } -/* SHA1 */ type Sha1Hash [20]byte func (h *Sha1Hash) String() string { @@ -40,7 +39,6 @@ func MustIDFromString(hexHash string) ObjectID { return id } -/* SHA256 */ type Sha256Hash [32]byte func (h *Sha256Hash) String() string { @@ -54,7 +52,6 @@ func (h *Sha256Hash) IsZero() bool { func (h *Sha256Hash) RawValue() []byte { return h[:] } func (*Sha256Hash) Type() ObjectFormat { return Sha256ObjectFormat } -/* utility */ func NewIDFromString(hexHash string) (ObjectID, error) { var theObjectFormat ObjectFormat for _, objectFormat := range SupportedObjectFormats { diff --git a/modules/git/object_id_test.go b/modules/git/object_id_test.go index 1ad40096a0..03d0c85d87 100644 --- a/modules/git/object_id_test.go +++ b/modules/git/object_id_test.go @@ -18,4 +18,8 @@ func TestIsValidSHAPattern(t *testing.T) { assert.False(t, h.IsValid("abc")) assert.False(t, h.IsValid("123g")) assert.False(t, h.IsValid("some random text")) + assert.Equal(t, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", ComputeBlobHash(Sha1ObjectFormat, nil).String()) + assert.Equal(t, "2e65efe2a145dda7ee51d1741299f848e5bf752e", ComputeBlobHash(Sha1ObjectFormat, []byte("a")).String()) + assert.Equal(t, "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813", ComputeBlobHash(Sha256ObjectFormat, nil).String()) + assert.Equal(t, "eb337bcee2061c5313c9a1392116b6c76039e9e30d71467ae359b36277e17dc7", ComputeBlobHash(Sha256ObjectFormat, []byte("a")).String()) } From 993736d838c36e26951b6cfea9c6a549958addd1 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 26 Apr 2024 19:21:04 +0800 Subject: [PATCH 13/19] Fix code search input for different views (#30678) Now only show the "code search" on the repo home page, because it only does global search. So do not show it when viewing file or directory to avoid misleading users (it doesn't search in a directory) --- routers/web/repo/commit.go | 2 -- routers/web/repo/compare.go | 1 - routers/web/repo/pull.go | 1 - templates/repo/home.tmpl | 22 ++++++++++++---------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 8543fa44cc..a2c6ac33e8 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -212,8 +212,6 @@ func SearchCommits(ctx *context.Context) { // FileHistory show a file's reversions func FileHistory(ctx *context.Context) { - ctx.Data["IsRepoToolbarCommits"] = true - fileName := ctx.Repo.TreePath if len(fileName) == 0 { Commits(ctx) diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 035a92f228..a55426dab5 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -800,7 +800,6 @@ func CompareDiff(ctx *context.Context) { } ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + separator + base.ShortSha(afterCommitID) - ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsDiffCompare"] = true _, templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index acdba4bcdc..7f131f2e98 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -1225,7 +1225,6 @@ func CompareAndPullRequestPost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.pulls.compare_changes") ctx.Data["PageIsComparePull"] = true ctx.Data["IsDiffCompare"] = true - ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled upload.AddUploadContext(ctx, "comment") diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 7b37ac1011..eb9eb9c149 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -90,7 +90,16 @@ {{ctx.Locale.Tr "repo.use_template"}} {{end}} - {{if (not $isHomepage)}} + {{if $isHomepage}} + {{/* only show the "code search" on the repo home page, it only does global search, + so do not show it when viewing file or directory to avoid misleading users (it doesn't search in a directory) */}} +
+
+ + {{template "shared/search/button"}} +
+
+ {{else}} {{StringUtils.EllipsisString .Repository.Name 30}} {{- range $i, $v := .TreeNames -}} @@ -103,13 +112,6 @@ {{- end -}} {{end}} - -
-
- - {{template "shared/search/button"}} -
-
@@ -136,7 +138,7 @@
{{template "repo/cite/cite_modal" .}} {{end}} - {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}} + {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}}{{/* IsViewDirectory (not home), TODO: split the templates, avoid using "if" tricks */}} {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} @@ -147,7 +149,7 @@ {{template "repo/view_file" .}} {{else if .IsBlame}} {{template "repo/blame" .}} - {{else}} + {{else}}{{/* IsViewDirectory */}} {{template "repo/view_list" .}} {{end}}
From 852547d0dc70299589c7bf8d00ea462ed709b8e5 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Fri, 26 Apr 2024 21:11:49 +0800 Subject: [PATCH 14/19] feat(api): enhance Actions Secrets Management API for repository (#30656) - Add endpoint to list repository action secrets in API routes - Implement `ListActionsSecrets` function to retrieve action secrets from the database - Update Swagger documentation to include the new `/repos/{owner}/{repo}/actions/secrets` endpoint - Add `actions` package import and define new routes for actions, secrets, variables, and runners in `api.go`. - Refactor action-related API functions into `Action` struct methods in `org/action.go` and `repo/action.go`. - Remove `actionAPI` struct and related functions, replacing them with `NewAction()` calls. - Rename `variables.go` to `action.go` in `org` directory. - Delete `runners.go` and `secrets.go` in both `org` and `repo` directories, consolidating their content into `action.go`. - Update copyright year and add new imports in `org/action.go`. - Implement `API` interface in `services/actions/interface.go` for action-related methods. - Remove individual action-related functions and replace them with methods on the `Action` struct in `repo/action.go`. --------- Signed-off-by: Bo-Yi Wu Signed-off-by: appleboy --- routers/api/v1/api.go | 80 ++++---- .../api/v1/org/{variables.go => action.go} | 192 +++++++++++++++++- routers/api/v1/org/runners.go | 31 --- routers/api/v1/org/secrets.go | 166 --------------- routers/api/v1/repo/action.go | 108 +++++++++- routers/api/v1/repo/runners.go | 34 ---- services/actions/interface.go | 28 +++ templates/swagger/v1_json.tmpl | 48 +++++ tests/integration/api_repo_secrets_test.go | 8 +- 9 files changed, 410 insertions(+), 285 deletions(-) rename routers/api/v1/org/{variables.go => action.go} (58%) delete mode 100644 routers/api/v1/org/runners.go delete mode 100644 routers/api/v1/org/secrets.go delete mode 100644 routers/api/v1/repo/runners.go create mode 100644 services/actions/interface.go diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 5358906f27..73071aa8df 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -93,6 +93,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/settings" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/common" + "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/auth" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -835,6 +836,34 @@ func Routes() *web.Route { SignInRequired: setting.Service.RequireSignInView, })) + addActionsRoutes := func( + m *web.Route, + reqChecker func(ctx *context.APIContext), + act actions.API, + ) { + m.Group("/actions", func() { + m.Group("/secrets", func() { + m.Get("", reqToken(), reqChecker, act.ListActionsSecrets) + m.Combo("/{secretname}"). + Put(reqToken(), reqChecker, bind(api.CreateOrUpdateSecretOption{}), act.CreateOrUpdateSecret). + Delete(reqToken(), reqChecker, act.DeleteSecret) + }) + + m.Group("/variables", func() { + m.Get("", reqToken(), reqChecker, act.ListVariables) + m.Combo("/{variablename}"). + Get(reqToken(), reqChecker, act.GetVariable). + Delete(reqToken(), reqChecker, act.DeleteVariable). + Post(reqToken(), reqChecker, bind(api.CreateVariableOption{}), act.CreateVariable). + Put(reqToken(), reqChecker, bind(api.UpdateVariableOption{}), act.UpdateVariable) + }) + + m.Group("/runners", func() { + m.Get("/registration-token", reqToken(), reqChecker, act.GetRegistrationToken) + }) + }) + } + m.Group("", func() { // Miscellaneous (no scope required) if setting.API.EnableSwagger { @@ -1073,26 +1102,11 @@ func Routes() *web.Route { m.Post("/accept", repo.AcceptTransfer) m.Post("/reject", repo.RejectTransfer) }, reqToken()) - m.Group("/actions", func() { - m.Group("/secrets", func() { - m.Combo("/{secretname}"). - Put(reqToken(), reqOwner(), bind(api.CreateOrUpdateSecretOption{}), repo.CreateOrUpdateSecret). - Delete(reqToken(), reqOwner(), repo.DeleteSecret) - }) - - m.Group("/variables", func() { - m.Get("", reqToken(), reqOwner(), repo.ListVariables) - m.Combo("/{variablename}"). - Get(reqToken(), reqOwner(), repo.GetVariable). - Delete(reqToken(), reqOwner(), repo.DeleteVariable). - Post(reqToken(), reqOwner(), bind(api.CreateVariableOption{}), repo.CreateVariable). - Put(reqToken(), reqOwner(), bind(api.UpdateVariableOption{}), repo.UpdateVariable) - }) - - m.Group("/runners", func() { - m.Get("/registration-token", reqToken(), reqOwner(), repo.GetRegistrationToken) - }) - }) + addActionsRoutes( + m, + reqOwner(), + repo.NewAction(), + ) m.Group("/hooks/git", func() { m.Combo("").Get(repo.ListGitHooks) m.Group("/{id}", func() { @@ -1460,27 +1474,11 @@ func Routes() *web.Route { m.Combo("/{username}").Get(reqToken(), org.IsMember). Delete(reqToken(), reqOrgOwnership(), org.DeleteMember) }) - m.Group("/actions", func() { - m.Group("/secrets", func() { - m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets) - m.Combo("/{secretname}"). - Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateSecret). - Delete(reqToken(), reqOrgOwnership(), org.DeleteSecret) - }) - - m.Group("/variables", func() { - m.Get("", reqToken(), reqOrgOwnership(), org.ListVariables) - m.Combo("/{variablename}"). - Get(reqToken(), reqOrgOwnership(), org.GetVariable). - Delete(reqToken(), reqOrgOwnership(), org.DeleteVariable). - Post(reqToken(), reqOrgOwnership(), bind(api.CreateVariableOption{}), org.CreateVariable). - Put(reqToken(), reqOrgOwnership(), bind(api.UpdateVariableOption{}), org.UpdateVariable) - }) - - m.Group("/runners", func() { - m.Get("/registration-token", reqToken(), reqOrgOwnership(), org.GetRegistrationToken) - }) - }) + addActionsRoutes( + m, + reqOrgOwnership(), + org.NewAction(), + ) m.Group("/public_members", func() { m.Get("", org.ListPublicMembers) m.Combo("/{username}").Get(org.IsPublicMember). diff --git a/routers/api/v1/org/variables.go b/routers/api/v1/org/action.go similarity index 58% rename from routers/api/v1/org/variables.go rename to routers/api/v1/org/action.go index eaf7bdc45b..03a1fa8ccc 100644 --- a/routers/api/v1/org/variables.go +++ b/routers/api/v1/org/action.go @@ -9,16 +9,188 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + secret_model "code.gitea.io/gitea/models/secret" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/api/v1/shared" "code.gitea.io/gitea/routers/api/v1/utils" actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" + secret_service "code.gitea.io/gitea/services/secrets" ) +// ListActionsSecrets list an organization's actions secrets +func (Action) ListActionsSecrets(ctx *context.APIContext) { + // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets + // --- + // summary: List an organization's actions secrets + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of the organization + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/SecretList" + // "404": + // "$ref": "#/responses/notFound" + + opts := &secret_model.FindSecretsOptions{ + OwnerID: ctx.Org.Organization.ID, + ListOptions: utils.GetListOptions(ctx), + } + + secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) + if err != nil { + ctx.InternalServerError(err) + return + } + + apiSecrets := make([]*api.Secret, len(secrets)) + for k, v := range secrets { + apiSecrets[k] = &api.Secret{ + Name: v.Name, + Created: v.CreatedUnix.AsTime(), + } + } + + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, apiSecrets) +} + +// create or update one secret of the organization +func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { + // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret + // --- + // summary: Create or Update a secret value in an organization + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of organization + // type: string + // required: true + // - name: secretname + // in: path + // description: name of the secret + // type: string + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/CreateOrUpdateSecretOption" + // responses: + // "201": + // description: response when creating a secret + // "204": + // description: response when updating a secret + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" + + opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) + + _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data) + if err != nil { + if errors.Is(err, util.ErrInvalidArgument) { + ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err) + } else if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err) + } else { + ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err) + } + return + } + + if created { + ctx.Status(http.StatusCreated) + } else { + ctx.Status(http.StatusNoContent) + } +} + +// DeleteSecret delete one secret of the organization +func (Action) DeleteSecret(ctx *context.APIContext) { + // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret + // --- + // summary: Delete a secret in an organization + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of organization + // type: string + // required: true + // - name: secretname + // in: path + // description: name of the secret + // type: string + // required: true + // responses: + // "204": + // description: delete one secret of the organization + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" + + err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname")) + if err != nil { + if errors.Is(err, util.ErrInvalidArgument) { + ctx.Error(http.StatusBadRequest, "DeleteSecret", err) + } else if errors.Is(err, util.ErrNotExist) { + ctx.Error(http.StatusNotFound, "DeleteSecret", err) + } else { + ctx.Error(http.StatusInternalServerError, "DeleteSecret", err) + } + return + } + + ctx.Status(http.StatusNoContent) +} + +// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization +// GetRegistrationToken returns the token to register org runners +func (Action) GetRegistrationToken(ctx *context.APIContext) { + // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken + // --- + // summary: Get an organization's actions runner registration token + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of the organization + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/RegistrationToken" + + shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0) +} + // ListVariables list org-level variables -func ListVariables(ctx *context.APIContext) { +func (Action) ListVariables(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/variables organization getOrgVariablesList // --- // summary: Get an org-level variables list @@ -70,7 +242,7 @@ func ListVariables(ctx *context.APIContext) { } // GetVariable get an org-level variable -func GetVariable(ctx *context.APIContext) { +func (Action) GetVariable(ctx *context.APIContext) { // swagger:operation GET /orgs/{org}/actions/variables/{variablename} organization getOrgVariable // --- // summary: Get an org-level variable @@ -119,7 +291,7 @@ func GetVariable(ctx *context.APIContext) { } // DeleteVariable delete an org-level variable -func DeleteVariable(ctx *context.APIContext) { +func (Action) DeleteVariable(ctx *context.APIContext) { // swagger:operation DELETE /orgs/{org}/actions/variables/{variablename} organization deleteOrgVariable // --- // summary: Delete an org-level variable @@ -163,7 +335,7 @@ func DeleteVariable(ctx *context.APIContext) { } // CreateVariable create an org-level variable -func CreateVariable(ctx *context.APIContext) { +func (Action) CreateVariable(ctx *context.APIContext) { // swagger:operation POST /orgs/{org}/actions/variables/{variablename} organization createOrgVariable // --- // summary: Create an org-level variable @@ -227,7 +399,7 @@ func CreateVariable(ctx *context.APIContext) { } // UpdateVariable update an org-level variable -func UpdateVariable(ctx *context.APIContext) { +func (Action) UpdateVariable(ctx *context.APIContext) { // swagger:operation PUT /orgs/{org}/actions/variables/{variablename} organization updateOrgVariable // --- // summary: Update an org-level variable @@ -289,3 +461,13 @@ func UpdateVariable(ctx *context.APIContext) { ctx.Status(http.StatusNoContent) } + +var _ actions_service.API = new(Action) + +// Action implements actions_service.API +type Action struct{} + +// NewAction creates a new Action service +func NewAction() actions_service.API { + return Action{} +} diff --git a/routers/api/v1/org/runners.go b/routers/api/v1/org/runners.go deleted file mode 100644 index 2a52bd8778..0000000000 --- a/routers/api/v1/org/runners.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package org - -import ( - "code.gitea.io/gitea/routers/api/v1/shared" - "code.gitea.io/gitea/services/context" -) - -// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization - -// GetRegistrationToken returns the token to register org runners -func GetRegistrationToken(ctx *context.APIContext) { - // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken - // --- - // summary: Get an organization's actions runner registration token - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of the organization - // type: string - // required: true - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0) -} diff --git a/routers/api/v1/org/secrets.go b/routers/api/v1/org/secrets.go deleted file mode 100644 index abb6bb26c4..0000000000 --- a/routers/api/v1/org/secrets.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package org - -import ( - "errors" - "net/http" - - "code.gitea.io/gitea/models/db" - secret_model "code.gitea.io/gitea/models/secret" - api "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/routers/api/v1/utils" - "code.gitea.io/gitea/services/context" - secret_service "code.gitea.io/gitea/services/secrets" -) - -// ListActionsSecrets list an organization's actions secrets -func ListActionsSecrets(ctx *context.APIContext) { - // swagger:operation GET /orgs/{org}/actions/secrets organization orgListActionsSecrets - // --- - // summary: List an organization's actions secrets - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of the organization - // type: string - // required: true - // - name: page - // in: query - // description: page number of results to return (1-based) - // type: integer - // - name: limit - // in: query - // description: page size of results - // type: integer - // responses: - // "200": - // "$ref": "#/responses/SecretList" - // "404": - // "$ref": "#/responses/notFound" - - opts := &secret_model.FindSecretsOptions{ - OwnerID: ctx.Org.Organization.ID, - ListOptions: utils.GetListOptions(ctx), - } - - secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) - if err != nil { - ctx.InternalServerError(err) - return - } - - apiSecrets := make([]*api.Secret, len(secrets)) - for k, v := range secrets { - apiSecrets[k] = &api.Secret{ - Name: v.Name, - Created: v.CreatedUnix.AsTime(), - } - } - - ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, apiSecrets) -} - -// create or update one secret of the organization -func CreateOrUpdateSecret(ctx *context.APIContext) { - // swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret - // --- - // summary: Create or Update a secret value in an organization - // consumes: - // - application/json - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of organization - // type: string - // required: true - // - name: secretname - // in: path - // description: name of the secret - // type: string - // required: true - // - name: body - // in: body - // schema: - // "$ref": "#/definitions/CreateOrUpdateSecretOption" - // responses: - // "201": - // description: response when creating a secret - // "204": - // description: response when updating a secret - // "400": - // "$ref": "#/responses/error" - // "404": - // "$ref": "#/responses/notFound" - - opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption) - - _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname"), opt.Data) - if err != nil { - if errors.Is(err, util.ErrInvalidArgument) { - ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err) - } else if errors.Is(err, util.ErrNotExist) { - ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err) - } else { - ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err) - } - return - } - - if created { - ctx.Status(http.StatusCreated) - } else { - ctx.Status(http.StatusNoContent) - } -} - -// DeleteSecret delete one secret of the organization -func DeleteSecret(ctx *context.APIContext) { - // swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret - // --- - // summary: Delete a secret in an organization - // consumes: - // - application/json - // produces: - // - application/json - // parameters: - // - name: org - // in: path - // description: name of organization - // type: string - // required: true - // - name: secretname - // in: path - // description: name of the secret - // type: string - // required: true - // responses: - // "204": - // description: delete one secret of the organization - // "400": - // "$ref": "#/responses/error" - // "404": - // "$ref": "#/responses/notFound" - - err := secret_service.DeleteSecretByName(ctx, ctx.Org.Organization.ID, 0, ctx.Params("secretname")) - if err != nil { - if errors.Is(err, util.ErrInvalidArgument) { - ctx.Error(http.StatusBadRequest, "DeleteSecret", err) - } else if errors.Is(err, util.ErrNotExist) { - ctx.Error(http.StatusNotFound, "DeleteSecret", err) - } else { - ctx.Error(http.StatusInternalServerError, "DeleteSecret", err) - } - return - } - - ctx.Status(http.StatusNoContent) -} diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go index 03321d956d..311cfca6e9 100644 --- a/routers/api/v1/repo/action.go +++ b/routers/api/v1/repo/action.go @@ -9,17 +9,76 @@ import ( actions_model "code.gitea.io/gitea/models/actions" "code.gitea.io/gitea/models/db" + secret_model "code.gitea.io/gitea/models/secret" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/api/v1/shared" "code.gitea.io/gitea/routers/api/v1/utils" actions_service "code.gitea.io/gitea/services/actions" "code.gitea.io/gitea/services/context" secret_service "code.gitea.io/gitea/services/secrets" ) +// ListActionsSecrets list an repo's actions secrets +func (Action) ListActionsSecrets(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/actions/secrets repository repoListActionsSecrets + // --- + // summary: List an repo's actions secrets + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repository + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repository + // type: string + // required: true + // - name: page + // in: query + // description: page number of results to return (1-based) + // type: integer + // - name: limit + // in: query + // description: page size of results + // type: integer + // responses: + // "200": + // "$ref": "#/responses/SecretList" + // "404": + // "$ref": "#/responses/notFound" + + repo := ctx.Repo.Repository + + opts := &secret_model.FindSecretsOptions{ + RepoID: repo.ID, + ListOptions: utils.GetListOptions(ctx), + } + + secrets, count, err := db.FindAndCount[secret_model.Secret](ctx, opts) + if err != nil { + ctx.InternalServerError(err) + return + } + + apiSecrets := make([]*api.Secret, len(secrets)) + for k, v := range secrets { + apiSecrets[k] = &api.Secret{ + Name: v.Name, + Created: v.CreatedUnix.AsTime(), + } + } + + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, apiSecrets) +} + // create or update one secret of the repository -func CreateOrUpdateSecret(ctx *context.APIContext) { +func (Action) CreateOrUpdateSecret(ctx *context.APIContext) { // swagger:operation PUT /repos/{owner}/{repo}/actions/secrets/{secretname} repository updateRepoSecret // --- // summary: Create or Update a secret value in a repository @@ -82,7 +141,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) { } // DeleteSecret delete one secret of the repository -func DeleteSecret(ctx *context.APIContext) { +func (Action) DeleteSecret(ctx *context.APIContext) { // swagger:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secretname} repository deleteRepoSecret // --- // summary: Delete a secret in a repository @@ -133,7 +192,7 @@ func DeleteSecret(ctx *context.APIContext) { } // GetVariable get a repo-level variable -func GetVariable(ctx *context.APIContext) { +func (Action) GetVariable(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/variables/{variablename} repository getRepoVariable // --- // summary: Get a repo-level variable @@ -186,7 +245,7 @@ func GetVariable(ctx *context.APIContext) { } // DeleteVariable delete a repo-level variable -func DeleteVariable(ctx *context.APIContext) { +func (Action) DeleteVariable(ctx *context.APIContext) { // swagger:operation DELETE /repos/{owner}/{repo}/actions/variables/{variablename} repository deleteRepoVariable // --- // summary: Delete a repo-level variable @@ -235,7 +294,7 @@ func DeleteVariable(ctx *context.APIContext) { } // CreateVariable create a repo-level variable -func CreateVariable(ctx *context.APIContext) { +func (Action) CreateVariable(ctx *context.APIContext) { // swagger:operation POST /repos/{owner}/{repo}/actions/variables/{variablename} repository createRepoVariable // --- // summary: Create a repo-level variable @@ -302,7 +361,7 @@ func CreateVariable(ctx *context.APIContext) { } // UpdateVariable update a repo-level variable -func UpdateVariable(ctx *context.APIContext) { +func (Action) UpdateVariable(ctx *context.APIContext) { // swagger:operation PUT /repos/{owner}/{repo}/actions/variables/{variablename} repository updateRepoVariable // --- // summary: Update a repo-level variable @@ -369,7 +428,7 @@ func UpdateVariable(ctx *context.APIContext) { } // ListVariables list repo-level variables -func ListVariables(ctx *context.APIContext) { +func (Action) ListVariables(ctx *context.APIContext) { // swagger:operation GET /repos/{owner}/{repo}/actions/variables repository getRepoVariablesList // --- // summary: Get repo-level variables list @@ -423,3 +482,38 @@ func ListVariables(ctx *context.APIContext) { ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, variables) } + +// GetRegistrationToken returns the token to register repo runners +func (Action) GetRegistrationToken(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken + // --- + // summary: Get a repository's actions runner registration token + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // responses: + // "200": + // "$ref": "#/responses/RegistrationToken" + + shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID) +} + +var _ actions_service.API = new(Action) + +// Action implements actions_service.API +type Action struct{} + +// NewAction creates a new Action service +func NewAction() actions_service.API { + return Action{} +} diff --git a/routers/api/v1/repo/runners.go b/routers/api/v1/repo/runners.go deleted file mode 100644 index fe133b311d..0000000000 --- a/routers/api/v1/repo/runners.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2023 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package repo - -import ( - "code.gitea.io/gitea/routers/api/v1/shared" - "code.gitea.io/gitea/services/context" -) - -// GetRegistrationToken returns the token to register repo runners -func GetRegistrationToken(ctx *context.APIContext) { - // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken - // --- - // summary: Get a repository's actions runner registration token - // produces: - // - application/json - // parameters: - // - name: owner - // in: path - // description: owner of the repo - // type: string - // required: true - // - name: repo - // in: path - // description: name of the repo - // type: string - // required: true - // responses: - // "200": - // "$ref": "#/responses/RegistrationToken" - - shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID) -} diff --git a/services/actions/interface.go b/services/actions/interface.go new file mode 100644 index 0000000000..d4fa782fec --- /dev/null +++ b/services/actions/interface.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import "code.gitea.io/gitea/services/context" + +// API for actions of a repository or organization +type API interface { + // ListActionsSecrets list secrets + ListActionsSecrets(*context.APIContext) + // CreateOrUpdateSecret create or update a secret + CreateOrUpdateSecret(*context.APIContext) + // DeleteSecret delete a secret + DeleteSecret(*context.APIContext) + // ListVariables list variables + ListVariables(*context.APIContext) + // GetVariable get a variable + GetVariable(*context.APIContext) + // DeleteVariable delete a variable + DeleteVariable(*context.APIContext) + // CreateVariable create a variable + CreateVariable(*context.APIContext) + // UpdateVariable update a variable + UpdateVariable(*context.APIContext) + // GetRegistrationToken get registration token + GetRegistrationToken(*context.APIContext) +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index faf57454d7..3ed4e43e6d 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3843,6 +3843,54 @@ } } }, + "/repos/{owner}/{repo}/actions/secrets": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "repository" + ], + "summary": "List an repo's actions secrets", + "operationId": "repoListActionsSecrets", + "parameters": [ + { + "type": "string", + "description": "owner of the repository", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repository", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "page number of results to return (1-based)", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size of results", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "$ref": "#/responses/SecretList" + }, + "404": { + "$ref": "#/responses/notFound" + } + } + } + }, "/repos/{owner}/{repo}/actions/secrets/{secretname}": { "put": { "consumes": [ diff --git a/tests/integration/api_repo_secrets_test.go b/tests/integration/api_repo_secrets_test.go index feb9bae2b2..c3074d9ece 100644 --- a/tests/integration/api_repo_secrets_test.go +++ b/tests/integration/api_repo_secrets_test.go @@ -24,6 +24,12 @@ func TestAPIRepoSecrets(t *testing.T) { session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + t.Run("List", func(t *testing.T) { + req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/actions/secrets", repo.FullName())). + AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + }) + t.Run("Create", func(t *testing.T) { cases := []struct { Name string @@ -31,7 +37,7 @@ func TestAPIRepoSecrets(t *testing.T) { }{ { Name: "", - ExpectedStatus: http.StatusNotFound, + ExpectedStatus: http.StatusMethodNotAllowed, }, { Name: "-", From c93eefb42b535f7a3917149a183f05a8b551ce26 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 26 Apr 2024 21:37:21 +0200 Subject: [PATCH 15/19] Diff color enhancements, add line number background (#30670) 1. Bring back the background on line numbers. This feature was lost a long time ago. Screenshot 2024-04-24 at 01 36 09 Screenshot 2024-04-24 at 01 22 47 Screenshot 2024-04-24 at 02 13 18 Screenshot 2024-04-24 at 01 23 21 2. Expanded lines background is now full-line, including line numbers: Screenshot 2024-04-24 at 01 37 12 3. Sort affected colors alphabetically in the CSS Fixes #14603 --- templates/repo/diff/blob_excerpt.tmpl | 22 +++++++-------- web_src/css/repo.css | 28 ++++++++++++++----- ...eme-gitea-dark-protanopia-deuteranopia.css | 11 ++++---- web_src/css/themes/theme-gitea-dark.css | 16 ++++++----- ...me-gitea-light-protanopia-deuteranopia.css | 7 +++-- web_src/css/themes/theme-gitea-light.css | 14 ++++++---- 6 files changed, 59 insertions(+), 39 deletions(-) diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index 8312b5d913..a80abe263f 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -1,6 +1,6 @@ {{if $.IsSplitStyle}} {{range $k, $line := $.section.Lines}} - + {{if eq .GetType 4}}
@@ -26,17 +26,17 @@ {{else}} {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} - {{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} - {{if $line.LeftIdx}}{{end}} - {{/* + {{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} + {{if $line.LeftIdx}}{{end}} + {{/* */}}{{if $line.LeftIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/* */}}{{/* */}}{{end}}{{/* */}} - {{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} - {{if $line.RightIdx}}{{end}} - {{/* + {{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} + {{if $line.RightIdx}}{{end}} + {{/* */}}{{if $line.RightIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff}}{{else}}{{/* */}}{{/* */}}{{end}}{{/* @@ -46,7 +46,7 @@ {{end}} {{else}} {{range $k, $line := $.section.Lines}} - + {{if eq .GetType 4}}
@@ -72,9 +72,9 @@ {{end}} {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} - {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} - - {{$inlineDiff.Content}} + {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} + + {{$inlineDiff.Content}} {{end}} {{end}} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 62a72abaf9..4de994112f 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -2377,7 +2377,7 @@ tbody.commit-list { .tag-code, .tag-code td, -.tag-code .blob-excerpt { +.tag-code.line-expanded { background-color: var(--color-box-body-highlight); vertical-align: middle; } @@ -2393,8 +2393,8 @@ tbody.commit-list { padding-top: 0 !important; } -.blob-excerpt { - background-color: var(--color-secondary-alpha-30); +.line-expanded { + background-color: var(--color-secondary-alpha-20); } .issue-keyword { @@ -2553,11 +2553,9 @@ tbody.commit-list { .code-diff-unified .add-code, .code-diff-unified .add-code td, -.code-diff-split .add-code .lines-num-new, .code-diff-split .add-code .lines-type-marker-new, .code-diff-split .add-code .lines-escape-new, .code-diff-split .add-code .lines-code-new, -.code-diff-split .del-code .add-code.lines-num-new, .code-diff-split .del-code .add-code.lines-type-marker-new, .code-diff-split .del-code .add-code.lines-escape-new, .code-diff-split .del-code .add-code.lines-code-new { @@ -2565,17 +2563,33 @@ tbody.commit-list { border-color: var(--color-diff-added-row-border); } -.code-diff-split .del-code .lines-num-new, .code-diff-split .del-code .lines-type-marker-new, .code-diff-split .del-code .lines-code-new, .code-diff-split .del-code .lines-escape-new, -.code-diff-split .add-code .lines-num-old, .code-diff-split .add-code .lines-escape-old, .code-diff-split .add-code .lines-type-marker-old, .code-diff-split .add-code .lines-code-old { background: var(--color-diff-inactive); } +.code-diff-split .add-code .lines-num.lines-num-old, +.code-diff-split .del-code .lines-num.lines-num-new { + background: var(--color-diff-inactive); +} + +.code-diff-unified .del-code .lines-num, +.code-diff-split .del-code .lines-num { + background: var(--color-diff-removed-linenum-bg); + color: var(--color-text); +} + +.code-diff-unified .add-code .lines-num, +.code-diff-split .add-code .lines-num, +.code-diff-split .del-code .add-code.lines-num { + background: var(--color-diff-added-linenum-bg); + color: var(--color-text); +} + .code-diff-split tbody tr td:nth-child(5), .code-diff-split tbody tr td.add-comment-right { border-left: 1px solid var(--color-secondary); diff --git a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css index 681aa3b539..c1a6edaf35 100644 --- a/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css +++ b/web_src/css/themes/theme-gitea-dark-protanopia-deuteranopia.css @@ -3,9 +3,10 @@ /* red/green colorblind-friendly colors */ /* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ :root { - --color-diff-added-word-bg: #388bfd66; - --color-diff-added-row-bg: #388bfd26; - - --color-diff-removed-word-bg: #db6d2866; - --color-diff-removed-row-bg: #db6d2826; + --color-diff-added-linenum-bg: #1979fd46; + --color-diff-added-row-bg: #1979fd20; + --color-diff-added-word-bg: #1979fd66; + --color-diff-removed-linenum-bg: #c8622146; + --color-diff-removed-row-bg: #c8622120; + --color-diff-removed-word-bg: #c8622166; } diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 7bf2c982c6..ad9ab5a8c2 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -143,14 +143,16 @@ --color-grey-light: #818f9e; --color-gold: #b1983b; --color-white: #ffffff; - --color-diff-removed-word-bg: #6f3333; - --color-diff-added-word-bg: #3c653c; - --color-diff-removed-row-bg: #3c2626; - --color-diff-moved-row-bg: #818044; - --color-diff-added-row-bg: #283e2d; - --color-diff-removed-row-border: #634343; - --color-diff-moved-row-border: #bcca6f; + --color-diff-added-linenum-bg: #274227; + --color-diff-added-row-bg: #203224; --color-diff-added-row-border: #314a37; + --color-diff-added-word-bg: #3c653c; + --color-diff-moved-row-bg: #818044; + --color-diff-moved-row-border: #bcca6f; + --color-diff-removed-linenum-bg: #482121; + --color-diff-removed-row-bg: #301e1e; + --color-diff-removed-row-border: #634343; + --color-diff-removed-word-bg: #6f3333; --color-diff-inactive: #22282d; --color-error-border: #a04141; --color-error-bg: #522; diff --git a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css index 7e03d90f5c..f42fa1db2c 100644 --- a/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css +++ b/web_src/css/themes/theme-gitea-light-protanopia-deuteranopia.css @@ -3,9 +3,10 @@ /* red/green colorblind-friendly colors */ /* from GitHub: --diffBlob-addition-*, --diffBlob-deletion-*, etc */ :root { - --color-diff-added-word-bg: #54aeff66; + --color-diff-added-linenum-bg: #54aeff4d; --color-diff-added-row-bg: #ddf4ff80; - - --color-diff-removed-word-bg: #ffb77c80; + --color-diff-added-word-bg: #54aeff66; + --color-diff-removed-linenum-bg: #ffb77c4d; --color-diff-removed-row-bg: #fff1e580; + --color-diff-removed-word-bg: #ffb77c80; } diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index dfccd37647..8d4aa6df93 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -143,14 +143,16 @@ --color-grey-light: #7c838a; --color-gold: #a1882b; --color-white: #ffffff; - --color-diff-removed-word-bg: #fdb8c0; - --color-diff-added-word-bg: #acf2bd; - --color-diff-removed-row-bg: #ffeef0; - --color-diff-moved-row-bg: #f1f8d1; + --color-diff-added-linenum-bg: #d1f8d9; --color-diff-added-row-bg: #e6ffed; - --color-diff-removed-row-border: #f1c0c0; - --color-diff-moved-row-border: #d0e27f; --color-diff-added-row-border: #e6ffed; + --color-diff-added-word-bg: #acf2bd; + --color-diff-moved-row-bg: #f1f8d1; + --color-diff-moved-row-border: #d0e27f; + --color-diff-removed-linenum-bg: #ffcecb; + --color-diff-removed-row-bg: #ffeef0; + --color-diff-removed-row-border: #f1c0c0; + --color-diff-removed-word-bg: #fdb8c0; --color-diff-inactive: #f0f2f4; --color-error-border: #e0b4b4; --color-error-bg: #fff6f6; From 27861d711b6284ccc774f974d8a5813ca2c488eb Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sat, 27 Apr 2024 00:24:31 +0000 Subject: [PATCH 16/19] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-PT.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 444f784af9..c711c72045 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -436,6 +436,7 @@ oauth_signin_submit=Vincular conta oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contacte o administrador. oauth.signin.error.access_denied=O pedido de autorização foi negado. oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Tente mais tarde. +oauth_callback_unable_auto_reg=O registo automático está habilitado, mas o fornecedor OAuth2 %[1]s sinalizou campos em falta: %[2]s, por isso não foi possível criar uma conta automaticamente. Crie ou vincule uma conta ou contacte o administrador do sítio. openid_connect_submit=Estabelecer ligação openid_connect_title=Estabelecer ligação a uma conta existente openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o a uma nova conta aqui. From dcc3c17e5c41ad446b71215b095617e066a2e8e1 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 27 Apr 2024 09:21:07 +0200 Subject: [PATCH 17/19] Suppress browserslist warning in webpack target (#30571) 1. Set [`BROWSERSLIST_IGNORE_OLD_DATA`](https://github.com/browserslist/browserslist/blob/c6ddf7b3870a4585822d06ec77e8dd2401b8e1ed/node.js#L400) to avoid warning on outdated browserslist data which the end user can likely not do anything about and which is currently visible in the v1.21 branch. 2. Suppress all command echoing and add a "Running webpack..." message in place. Warning in question was this: ``` Browserslist: caniuse-lite is outdated. Please run: npx update-browserslist-db@latest Why you should do it regularly: https://github.com/browserslist/update-db#readme ``` --- Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2a78c907c0..6477b26664 100644 --- a/Makefile +++ b/Makefile @@ -908,8 +908,9 @@ webpack: $(WEBPACK_DEST) $(WEBPACK_DEST): $(WEBPACK_SOURCES) $(WEBPACK_CONFIGS) package-lock.json @$(MAKE) -s node-check node_modules - rm -rf $(WEBPACK_DEST_ENTRIES) - npx webpack + @rm -rf $(WEBPACK_DEST_ENTRIES) + @echo "Running webpack..." + @BROWSERSLIST_IGNORE_OLD_DATA=true npx webpack @touch $(WEBPACK_DEST) .PHONY: svg From 9b2536b78fdcd3cf444a2f54857d9871e153858f Mon Sep 17 00:00:00 2001 From: silverwind Date: Sat, 27 Apr 2024 10:03:49 +0200 Subject: [PATCH 18/19] Update misspell to 0.5.1 and add `misspellings.csv` (#30573) Misspell 0.5.0 supports passing a csv file to extend the list of misspellings, so I added some common ones from the codebase. There is at least one typo in a API response so we need to decided whether to revert that and then likely remove the dict entry. --- Makefile | 6 +++--- .../config-cheat-sheet.en-us.md | 2 +- models/actions/run.go | 6 +++--- models/actions/task.go | 12 +++++------ models/actions/tasks_version.go | 8 +++---- models/fixtures/pull_request.yml | 20 +++++++++--------- models/issues/pull.go | 2 +- models/issues/tracked_time.go | 12 +++++------ models/migrations/v1_17/v216.go | 2 +- modules/git/ref.go | 2 +- modules/process/manager.go | 6 +++--- modules/templates/helper_test.go | 4 ++-- routers/api/actions/artifacts.go | 2 +- routers/api/actions/runner/interceptor.go | 4 ++-- routers/api/packages/README.md | 2 +- routers/api/v1/shared/runners.go | 2 +- routers/private/hook_pre_receive.go | 2 +- routers/web/admin/orgs.go | 2 +- routers/web/admin/users.go | 2 +- routers/web/repo/compare.go | 2 +- routers/web/repo/issue.go | 4 ++-- services/convert/issue_comment.go | 4 ++-- services/issue/assignee.go | 12 +++++------ services/issue/issue.go | 6 +++--- services/issue/pull.go | 8 +++---- services/org/org.go | 6 +++--- services/pull/check.go | 2 +- services/pull/comment.go | 2 +- services/pull/pull.go | 6 +++--- templates/swagger/v1_json.tmpl | 2 +- tests/integration/api_issue_config_test.go | 4 ++-- tests/integration/compare_test.go | 6 +++--- tools/misspellings.csv | 21 +++++++++++++++++++ web_src/js/bootstrap.js | 2 +- 34 files changed, 103 insertions(+), 82 deletions(-) create mode 100644 tools/misspellings.csv diff --git a/Makefile b/Makefile index 6477b26664..0cd6abb81e 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-che GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.6.0 GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.57.2 GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.11 -MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.4.1 +MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.5.1 SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@db51e79a0e37c572d8b59ae0c58bf2bbbbe53285 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1 @@ -397,11 +397,11 @@ lint-md: node_modules .PHONY: lint-spell lint-spell: - @go run $(MISSPELL_PACKAGE) -error $(SPELLCHECK_FILES) + @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -error $(SPELLCHECK_FILES) .PHONY: lint-spell-fix lint-spell-fix: - @go run $(MISSPELL_PACKAGE) -w $(SPELLCHECK_FILES) + @go run $(MISSPELL_PACKAGE) -dict tools/misspellings.csv -w $(SPELLCHECK_FILES) .PHONY: lint-go lint-go: diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index 14f562fc21..7bf23c9b99 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1322,7 +1322,7 @@ Defaultly every storage has their default base path like below | actions_log | actions_log/ | | actions_artifacts | actions_artifacts/ | -And bucket, basepath or `SERVE_DIRECT` could be special or overrided, if you want to use a different you can: +And bucket, basepath or `SERVE_DIRECT` could be special or overridden, if you want to use a different you can: ```ini [storage.actions_log] diff --git a/models/actions/run.go b/models/actions/run.go index d68710f46d..4f886999e9 100644 --- a/models/actions/run.go +++ b/models/actions/run.go @@ -262,11 +262,11 @@ func CancelPreviousJobs(ctx context.Context, repoID int64, ref, workflowID strin // InsertRun inserts a run func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWorkflow) error { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } - defer commiter.Close() + defer committer.Close() index, err := db.GetNextResourceIndex(ctx, "action_run_index", run.RepoID) if err != nil { @@ -331,7 +331,7 @@ func InsertRun(ctx context.Context, run *ActionRun, jobs []*jobparser.SingleWork } } - return commiter.Commit() + return committer.Commit() } func GetRunByID(ctx context.Context, id int64) (*ActionRun, error) { diff --git a/models/actions/task.go b/models/actions/task.go index 9946cf5233..f2f796a626 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -216,11 +216,11 @@ func GetRunningTaskByToken(ctx context.Context, token string) (*ActionTask, erro } func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask, bool, error) { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, false, err } - defer commiter.Close() + defer committer.Close() e := db.GetEngine(ctx) @@ -322,7 +322,7 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask task.Job = job - if err := commiter.Commit(); err != nil { + if err := committer.Commit(); err != nil { return nil, false, err } @@ -347,11 +347,11 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT stepStates[v.Id] = v } - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } - defer commiter.Close() + defer committer.Close() e := db.GetEngine(ctx) @@ -412,7 +412,7 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT } } - if err := commiter.Commit(); err != nil { + if err := committer.Commit(); err != nil { return nil, err } diff --git a/models/actions/tasks_version.go b/models/actions/tasks_version.go index 5c0a86538d..96c5468c1a 100644 --- a/models/actions/tasks_version.go +++ b/models/actions/tasks_version.go @@ -13,7 +13,7 @@ import ( // ActionTasksVersion // If both ownerID and repoID is zero, its scope is global. -// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currrently). +// If ownerID is not zero and repoID is zero, its scope is org (there is no user-level runner currently). // If ownerID is zero and repoID is not zero, its scope is repo. type ActionTasksVersion struct { ID int64 `xorm:"pk autoincr"` @@ -73,11 +73,11 @@ func increaseTasksVersionByScope(ctx context.Context, ownerID, repoID int64) err } func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } - defer commiter.Close() + defer committer.Close() // 1. increase global if err := increaseTasksVersionByScope(ctx, 0, 0); err != nil { @@ -101,5 +101,5 @@ func IncreaseTaskVersion(ctx context.Context, ownerID, repoID int64) error { } } - return commiter.Commit() + return committer.Commit() } diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index 3fc8ce630d..9a16316e5a 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -1,7 +1,7 @@ - id: 1 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 2 index: 2 head_repo_id: 1 @@ -16,7 +16,7 @@ - id: 2 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 3 index: 3 head_repo_id: 1 @@ -29,7 +29,7 @@ - id: 3 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 8 index: 1 head_repo_id: 11 @@ -42,7 +42,7 @@ - id: 4 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 9 index: 1 head_repo_id: 48 @@ -55,7 +55,7 @@ - id: 5 # this PR is outdated (one commit behind branch1 ) type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 11 index: 5 head_repo_id: 1 @@ -68,7 +68,7 @@ - id: 6 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 12 index: 2 head_repo_id: 3 @@ -81,7 +81,7 @@ - id: 7 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 19 index: 1 head_repo_id: 58 @@ -94,7 +94,7 @@ - id: 8 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 20 index: 1 head_repo_id: 23 @@ -103,7 +103,7 @@ - id: 9 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 21 index: 1 head_repo_id: 60 @@ -112,7 +112,7 @@ - id: 10 type: 0 # gitea pull request - status: 2 # mergable + status: 2 # mergeable issue_id: 22 index: 1 head_repo_id: 61 diff --git a/models/issues/pull.go b/models/issues/pull.go index dc1b1b956a..4194df2e3d 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -807,7 +807,7 @@ func UpdateAllowEdits(ctx context.Context, pr *PullRequest) error { // Mergeable returns if the pullrequest is mergeable. func (pr *PullRequest) Mergeable(ctx context.Context) bool { - // If a pull request isn't mergable if it's: + // If a pull request isn't mergeable if it's: // - Being conflict checked. // - Has a conflict. // - Received a error while being conflict checked. diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 4063ca043b..caa582a9fc 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -187,8 +187,8 @@ func AddTime(ctx context.Context, user *user_model.User, issue *Issue, amount in Issue: issue, Repo: issue.Repo, Doer: user, - // Content before v1.21 did store the formated string instead of seconds, - // so use "|" as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so use "|" as delimiter to mark the new format Content: fmt.Sprintf("|%d", amount), Type: CommentTypeAddTimeManual, TimeID: t.ID, @@ -267,8 +267,8 @@ func DeleteIssueUserTimes(ctx context.Context, issue *Issue, user *user_model.Us Issue: issue, Repo: issue.Repo, Doer: user, - // Content before v1.21 did store the formated string instead of seconds, - // so use "|" as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so use "|" as delimiter to mark the new format Content: fmt.Sprintf("|%d", removedTime), Type: CommentTypeDeleteTimeManual, }); err != nil { @@ -298,8 +298,8 @@ func DeleteTime(ctx context.Context, t *TrackedTime) error { Issue: t.Issue, Repo: t.Issue.Repo, Doer: t.User, - // Content before v1.21 did store the formated string instead of seconds, - // so use "|" as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so use "|" as delimiter to mark the new format Content: fmt.Sprintf("|%d", t.Time), Type: CommentTypeDeleteTimeManual, }); err != nil { diff --git a/models/migrations/v1_17/v216.go b/models/migrations/v1_17/v216.go index 59b21d9b2c..268f472a42 100644 --- a/models/migrations/v1_17/v216.go +++ b/models/migrations/v1_17/v216.go @@ -4,4 +4,4 @@ package v1_17 //nolint // This migration added non-ideal indices to the action table which on larger datasets slowed things down -// it has been superceded by v218.go +// it has been superseded by v218.go diff --git a/modules/git/ref.go b/modules/git/ref.go index ed801f20d5..2db630e2ea 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -184,7 +184,7 @@ func (ref RefName) RefGroup() string { } // RefType returns the simple ref type of the reference, e.g. branch, tag -// It's differrent from RefGroup, which is using the name of the directory under .git/refs +// It's different from RefGroup, which is using the name of the directory under .git/refs // Here we using branch but not heads, using tag but not tags func (ref RefName) RefType() string { var refType string diff --git a/modules/process/manager.go b/modules/process/manager.go index 9c21f62152..bdc4931810 100644 --- a/modules/process/manager.go +++ b/modules/process/manager.go @@ -134,7 +134,7 @@ func (pm *Manager) AddTypedContext(parent context.Context, description, processT // // Most processes will not need to use the cancel function but there will be cases whereby you want to cancel the process but not immediately remove it from the // process table. -func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Duration, description string) (ctx context.Context, cancel context.CancelFunc, finshed FinishedFunc) { +func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Duration, description string) (ctx context.Context, cancel context.CancelFunc, finished FinishedFunc) { if timeout <= 0 { // it's meaningless to use timeout <= 0, and it must be a bug! so we must panic here to tell developers to make the timeout correct panic("the timeout must be greater than zero, otherwise the context will be cancelled immediately") @@ -142,9 +142,9 @@ func (pm *Manager) AddContextTimeout(parent context.Context, timeout time.Durati ctx, cancel = context.WithTimeout(parent, timeout) - ctx, _, finshed = pm.Add(ctx, description, cancel, NormalProcessType, true) + ctx, _, finished = pm.Add(ctx, description, cancel, NormalProcessType, true) - return ctx, cancel, finshed + return ctx, cancel, finished } // Add create a new process diff --git a/modules/templates/helper_test.go b/modules/templates/helper_test.go index 64f29d033e..0cefb7a6b2 100644 --- a/modules/templates/helper_test.go +++ b/modules/templates/helper_test.go @@ -49,9 +49,9 @@ func TestSubjectBodySeparator(t *testing.T) { test("Multiple\n---\n-------\n---\nSeparators", "Multiple\n", "\n-------\n---\nSeparators") - test("Insuficient\n--\nSeparators", + test("Insufficient\n--\nSeparators", "", - "Insuficient\n--\nSeparators") + "Insufficient\n--\nSeparators") } func TestJSEscapeSafe(t *testing.T) { diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go index 8198abb8a0..3e717b8d8f 100644 --- a/routers/api/actions/artifacts.go +++ b/routers/api/actions/artifacts.go @@ -301,7 +301,7 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) { }) } -// comfirmUploadArtifact comfirm upload artifact. +// comfirmUploadArtifact confirm upload artifact. // if all chunks are uploaded, merge them to one file. func (ar artifactRoutes) comfirmUploadArtifact(ctx *ArtifactContext) { _, runID, ok := validateRunID(ctx) diff --git a/routers/api/actions/runner/interceptor.go b/routers/api/actions/runner/interceptor.go index c2f4ade174..0e99f3deda 100644 --- a/routers/api/actions/runner/interceptor.go +++ b/routers/api/actions/runner/interceptor.go @@ -36,7 +36,7 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar uuid := request.Header().Get(uuidHeaderKey) token := request.Header().Get(tokenHeaderKey) // TODO: version will be removed from request header after Gitea 1.20 released. - // And Gitea will not try to read version from reuqest header + // And Gitea will not try to read version from request header version := request.Header().Get(versionHeaderKey) runner, err := actions_model.GetRunnerByUUID(ctx, uuid) @@ -53,7 +53,7 @@ var withRunner = connect.WithInterceptors(connect.UnaryInterceptorFunc(func(unar cols := []string{"last_online"} // TODO: version will be removed from request header after Gitea 1.20 released. - // And Gitea will not try to read version from reuqest header + // And Gitea will not try to read version from request header version, _ = util.SplitStringAtByteN(version, 64) if !util.IsEmptyString(version) && runner.Version != version { runner.Version = version diff --git a/routers/api/packages/README.md b/routers/api/packages/README.md index 533a0d32f0..74d14922cb 100644 --- a/routers/api/packages/README.md +++ b/routers/api/packages/README.md @@ -19,7 +19,7 @@ The package registry code is divided into multiple modules to split the function ## Models -Every package registry implementation uses the same underlaying models: +Every package registry implementation uses the same underlying models: | Model | Description | | - | - | diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go index c850ad7866..f088e9a2d4 100644 --- a/routers/api/v1/shared/runners.go +++ b/routers/api/v1/shared/runners.go @@ -12,7 +12,7 @@ import ( "code.gitea.io/gitea/services/context" ) -// RegistrationToken is response related to registeration token +// RegistrationToken is response related to registration token // swagger:response RegistrationToken type RegistrationToken struct { Token string `json:"token"` diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index caab6b4c81..f35eb77d42 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -359,7 +359,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r }) return } - log.Error("Unable to check if mergable: protected branch %s in %-v and pr #%d. Error: %v", ctx.opts.UserID, branchName, repo, pr.Index, err) + log.Error("Unable to check if mergeable: protected branch %s in %-v and pr #%d. Error: %v", ctx.opts.UserID, branchName, repo, pr.Index, err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to get status of pull request %d. Error: %v", ctx.opts.PullRequestID, err), }) diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index c5454db71e..cea28f8220 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -30,7 +30,7 @@ func Organizations(ctx *context.Context) { explore.RenderUserSearch(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Type: user_model.UserTypeOrganization, - IncludeReserved: true, // administrator needs to list all acounts include reserved + IncludeReserved: true, // administrator needs to list all accounts include reserved ListOptions: db.ListOptions{ PageSize: setting.UI.Admin.OrgPagingNum, }, diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index ea9d6f4c9c..d2330d5fa1 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -81,7 +81,7 @@ func Users(ctx *context.Context) { IsRestricted: util.OptionalBoolParse(statusFilterMap["is_restricted"]), IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]), IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]), - IncludeReserved: true, // administrator needs to list all acounts include reserved, bot, remote ones + IncludeReserved: true, // administrator needs to list all accounts include reserved, bot, remote ones ExtraParamStrings: extraParamStrings, }, tplUsers) } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index a55426dab5..8c0fee71a0 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -812,7 +812,7 @@ func CompareDiff(ctx *context.Context) { // applicable if you have one commit to compare and that commit has a message. // In that case the commit message will be prepend to the template body. if templateContent, ok := ctx.Data[pullRequestTemplateKey].(string); ok && templateContent != "" { - // Re-use the same key as that's priortized over the "content" key. + // Re-use the same key as that's prioritized over the "content" key. // Add two new lines between the content to ensure there's always at least // one empty line between them. ctx.Data[pullRequestTemplateKey] = content + "\n\n" + templateContent diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 1bc5f343e7..de6ef9e93b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -1760,8 +1760,8 @@ func ViewIssue(ctx *context.Context) { // drop error since times could be pruned from DB.. _ = comment.LoadTime(ctx) if comment.Content != "" { - // Content before v1.21 did store the formated string instead of seconds, - // so "|" is used as delimeter to mark the new format + // Content before v1.21 did store the formatted string instead of seconds, + // so "|" is used as delimiter to mark the new format if comment.Content[0] != '|' { // handle old time comments that have formatted text stored comment.RenderedContent = templates.SanitizeHTML(comment.Content) diff --git a/services/convert/issue_comment.go b/services/convert/issue_comment.go index 9ffaf1e84c..9ec9ac7684 100644 --- a/services/convert/issue_comment.go +++ b/services/convert/issue_comment.go @@ -72,8 +72,8 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu c.Type == issues_model.CommentTypeStopTracking || c.Type == issues_model.CommentTypeDeleteTimeManual) && c.Content[0] == '|' { - // TimeTracking Comments from v1.21 on store the seconds instead of an formated string - // so we check for the "|" delimeter and convert new to legacy format on demand + // TimeTracking Comments from v1.21 on store the seconds instead of an formatted string + // so we check for the "|" delimiter and convert new to legacy format on demand c.Content = util.SecToTime(c.Content[1:]) } } diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 8740a6664a..a0aa5a339b 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -229,12 +229,12 @@ func TeamReviewRequest(ctx context.Context, issue *issues_model.Issue, doer *use return comment, teamReviewRequestNotify(ctx, issue, doer, reviewer, isAdd, comment) } -func ReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewNotifers []*ReviewRequestNotifier) { - for _, reviewNotifer := range reviewNotifers { - if reviewNotifer.Reviwer != nil { - notify_service.PullRequestReviewRequest(ctx, issue.Poster, issue, reviewNotifer.Reviwer, reviewNotifer.IsAdd, reviewNotifer.Comment) - } else if reviewNotifer.ReviewTeam != nil { - if err := teamReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifer.ReviewTeam, reviewNotifer.IsAdd, reviewNotifer.Comment); err != nil { +func ReviewRequestNotify(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, reviewNotifiers []*ReviewRequestNotifier) { + for _, reviewNotifier := range reviewNotifiers { + if reviewNotifier.Reviewer != nil { + notify_service.PullRequestReviewRequest(ctx, issue.Poster, issue, reviewNotifier.Reviewer, reviewNotifier.IsAdd, reviewNotifier.Comment) + } else if reviewNotifier.ReviewTeam != nil { + if err := teamReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifier.ReviewTeam, reviewNotifier.IsAdd, reviewNotifier.Comment); err != nil { log.Error("teamReviewRequestNotify: %v", err) } } diff --git a/services/issue/issue.go b/services/issue/issue.go index c7fa9f3300..b0e50f2b89 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -90,17 +90,17 @@ func ChangeTitle(ctx context.Context, issue *issues_model.Issue, doer *user_mode return err } - var reviewNotifers []*ReviewRequestNotifier + var reviewNotifiers []*ReviewRequestNotifier if issue.IsPull && issues_model.HasWorkInProgressPrefix(oldTitle) && !issues_model.HasWorkInProgressPrefix(title) { var err error - reviewNotifers, err = PullRequestCodeOwnersReview(ctx, issue, issue.PullRequest) + reviewNotifiers, err = PullRequestCodeOwnersReview(ctx, issue, issue.PullRequest) if err != nil { log.Error("PullRequestCodeOwnersReview: %v", err) } } notify_service.IssueChangeTitle(ctx, doer, issue, oldTitle) - ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifers) + ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifiers) return nil } diff --git a/services/issue/pull.go b/services/issue/pull.go index 4a0009e82f..896802108d 100644 --- a/services/issue/pull.go +++ b/services/issue/pull.go @@ -36,7 +36,7 @@ func getMergeBase(repo *git.Repository, pr *issues_model.PullRequest, baseBranch type ReviewRequestNotifier struct { Comment *issues_model.Comment IsAdd bool - Reviwer *user_model.User + Reviewer *user_model.User ReviewTeam *org_model.Team } @@ -124,9 +124,9 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, return nil, err } notifiers = append(notifiers, &ReviewRequestNotifier{ - Comment: comment, - IsAdd: true, - Reviwer: u, + Comment: comment, + IsAdd: true, + Reviewer: u, }) } } diff --git a/services/org/org.go b/services/org/org.go index dca7794b47..c19572a123 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -20,11 +20,11 @@ import ( // DeleteOrganization completely and permanently deletes everything of organization. func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge bool) error { - ctx, commiter, err := db.TxContext(ctx) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } - defer commiter.Close() + defer committer.Close() if purge { err := repo_service.DeleteOwnerRepositoriesDirectly(ctx, org.AsUser()) @@ -52,7 +52,7 @@ func DeleteOrganization(ctx context.Context, org *org_model.Organization, purge return fmt.Errorf("DeleteOrganization: %w", err) } - if err := commiter.Commit(); err != nil { + if err := committer.Commit(); err != nil { return err } diff --git a/services/pull/check.go b/services/pull/check.go index f4dd332b14..9495e8ad5f 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -66,7 +66,7 @@ const ( MergeCheckTypeAuto // Auto Merge (Scheduled Merge) After Checks Succeed ) -// CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...) +// CheckPullMergable check if the pull mergeable based on all conditions (branch protection, merge options, ...) func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, adminSkipProtectionCheck bool) error { return db.WithTx(stdCtx, func(ctx context.Context) error { if pr.HasMerged { diff --git a/services/pull/comment.go b/services/pull/comment.go index d538b118d5..53587d4f54 100644 --- a/services/pull/comment.go +++ b/services/pull/comment.go @@ -46,7 +46,7 @@ func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldC return commitIDs, isForcePush, err } - // Find commits between new and old commit exclusing base branch commits + // Find commits between new and old commit excluding base branch commits commits, err := gitRepo.CommitsBetweenNotBase(newCommit, oldCommit, baseBranch) if err != nil { return nil, false, err diff --git a/services/pull/pull.go b/services/pull/pull.go index 764be5c6e3..5c0ea42d77 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -77,7 +77,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss } defer baseGitRepo.Close() - var reviewNotifers []*issue_service.ReviewRequestNotifier + var reviewNotifiers []*issue_service.ReviewRequestNotifier if err := db.WithTx(ctx, func(ctx context.Context) error { if err := issues_model.NewPullRequest(ctx, repo, issue, labelIDs, uuids, pr); err != nil { return err @@ -137,7 +137,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss } if !pr.IsWorkInProgress(ctx) { - reviewNotifers, err = issue_service.PullRequestCodeOwnersReview(ctx, issue, pr) + reviewNotifiers, err = issue_service.PullRequestCodeOwnersReview(ctx, issue, pr) if err != nil { return err } @@ -152,7 +152,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, issue *iss } baseGitRepo.Close() // close immediately to avoid notifications will open the repository again - issue_service.ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifers) + issue_service.ReviewRequestNotify(ctx, issue, issue.Poster, reviewNotifiers) mentions, err := issues_model.FindAndUpdateIssueMentions(ctx, issue, issue.Poster, issue.Content) if err != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 3ed4e43e6d..362a847332 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -25282,7 +25282,7 @@ } }, "RegistrationToken": { - "description": "RegistrationToken is response related to registeration token", + "description": "RegistrationToken is response related to registration token", "headers": { "token": { "type": "string" diff --git a/tests/integration/api_issue_config_test.go b/tests/integration/api_issue_config_test.go index b9125438b6..745d0cb2a2 100644 --- a/tests/integration/api_issue_config_test.go +++ b/tests/integration/api_issue_config_test.go @@ -119,9 +119,9 @@ func TestAPIRepoIssueConfigPaths(t *testing.T) { ".github/issue_template/config", } - for _, canidate := range templateConfigCandidates { + for _, candidate := range templateConfigCandidates { for _, extension := range []string{".yaml", ".yml"} { - fullPath := canidate + extension + fullPath := candidate + extension t.Run(fullPath, func(t *testing.T) { configMap := make(map[string]any) configMap["blank_issues_enabled"] = false diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go index 509524ca56..27b2920cc1 100644 --- a/tests/integration/compare_test.go +++ b/tests/integration/compare_test.go @@ -67,7 +67,7 @@ func TestCompareBranches(t *testing.T) { session := loginUser(t, "user2") - // Inderect compare remove-files-b (head) with add-csv (base) branch + // Indirect compare remove-files-b (head) with add-csv (base) branch // // 'link_hi' and 'test.csv' are deleted, 'test.txt' is added req := NewRequest(t, "GET", "/user2/repo20/compare/add-csv...remove-files-b") @@ -79,7 +79,7 @@ func TestCompareBranches(t *testing.T) { inspectCompare(t, htmlDoc, diffCount, diffChanges) - // Inderect compare remove-files-b (head) with remove-files-a (base) branch + // Indirect compare remove-files-b (head) with remove-files-a (base) branch // // 'link_hi' and 'test.csv' are deleted, 'test.txt' is added @@ -92,7 +92,7 @@ func TestCompareBranches(t *testing.T) { inspectCompare(t, htmlDoc, diffCount, diffChanges) - // Inderect compare remove-files-a (head) with remove-files-b (base) branch + // Indirect compare remove-files-a (head) with remove-files-b (base) branch // // 'link_hi' and 'test.csv' are deleted diff --git a/tools/misspellings.csv b/tools/misspellings.csv new file mode 100644 index 0000000000..645fb7853b --- /dev/null +++ b/tools/misspellings.csv @@ -0,0 +1,21 @@ +acounts,accounts +canidate,candidate +comfirm,confirm +converage,coverage +currrently,currently +delimeter,delimiter +differrent,different +exclusing,excluding +finshed,finished +formated,formatted +inderect,indirect +insuficient,insufficient +likly,likely +mergable,mergeable +overrided,overridden +priortized,prioritized +registeration,registration +reuqest,request +reviwer,reviewer +superceded,superseded +underlaying,underlying diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js index 3034478190..6cca37f7ca 100644 --- a/web_src/js/bootstrap.js +++ b/web_src/js/bootstrap.js @@ -50,7 +50,7 @@ function processWindowErrorEvent({error, reason, message, type, filename, lineno const assetBaseUrl = String(new URL(__webpack_public_path__, window.location.origin)); const {runModeIsProd} = window.config ?? {}; - // `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likly a + // `error` and `reason` are not guaranteed to be errors. If the value is falsy, it is likely a // non-critical event from the browser. We log them but don't show them to users. Examples: // - https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors // - https://github.com/mozilla-mobile/firefox-ios/issues/10817 From 4ae6b1a5534e4cc85602e990054c66a08b11852e Mon Sep 17 00:00:00 2001 From: Chongyi Zheng Date: Sat, 27 Apr 2024 06:44:49 -0400 Subject: [PATCH 19/19] Remove unused parameter for some functions in `services/mirror` (#30724) Suggested by gopls `unusedparams` --- services/mirror/mirror.go | 6 +++--- services/mirror/mirror_pull.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 72e545581a..0270f87039 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -40,7 +40,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { } log.Trace("Doing: Update") - handler := func(idx int, bean any) error { + handler := func(bean any) error { var repo *repo_model.Repository var mirrorType SyncType var referenceID int64 @@ -91,7 +91,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { pullMirrorsRequested := 0 if pullLimit != 0 { if err := repo_model.MirrorsIterate(ctx, pullLimit, func(idx int, bean any) error { - if err := handler(idx, bean); err != nil { + if err := handler(bean); err != nil { return err } pullMirrorsRequested++ @@ -105,7 +105,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { pushMirrorsRequested := 0 if pushLimit != 0 { if err := repo_model.PushMirrorsIterate(ctx, pushLimit, func(idx int, bean any) error { - if err := handler(idx, bean); err != nil { + if err := handler(bean); err != nil { return err } pushMirrorsRequested++ diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index f5eaeaf091..9f7ffb29c9 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -466,7 +466,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) if len(results) > 0 { - if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok { + if ok := checkAndUpdateEmptyRepository(ctx, m, results); !ok { log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err) return false } @@ -564,7 +564,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return true } -func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, gitRepo *git.Repository, results []*mirrorSyncResult) bool { +func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, results []*mirrorSyncResult) bool { if !m.Repo.IsEmpty { return true }