diff --git a/.deadcode-out b/.deadcode-out
index dc4aa0e498..c728ea81a0 100644
--- a/.deadcode-out
+++ b/.deadcode-out
@@ -271,13 +271,19 @@ package "code.gitea.io/gitea/modules/sync"
package "code.gitea.io/gitea/modules/testlogger"
func (*testLoggerWriterCloser).pushT
- func (*testLoggerWriterCloser).Write
+ func (*testLoggerWriterCloser).Log
+ func (*testLoggerWriterCloser).recordError
+ func (*testLoggerWriterCloser).printMsg
func (*testLoggerWriterCloser).popT
- func (*testLoggerWriterCloser).Close
func (*testLoggerWriterCloser).Reset
func PrintCurrentTest
func Printf
func NewTestLoggerWriter
+ func (*TestLogEventWriter).Base
+ func (*TestLogEventWriter).GetLevel
+ func (*TestLogEventWriter).GetWriterName
+ func (*TestLogEventWriter).GetWriterType
+ func (*TestLogEventWriter).Run
package "code.gitea.io/gitea/modules/timeutil"
func GetExecutableModTime
diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml
index af9ce93ba5..b2febb4ed8 100644
--- a/models/fixtures/action.yml
+++ b/models/fixtures/action.yml
@@ -6,6 +6,7 @@
repo_id: 2 # private
is_private: true
created_unix: 1603228283
+ content: '1|' # issueId 4
-
id: 2
diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml
index a42ab77ca5..405de2c548 100644
--- a/models/fixtures/action_run.yml
+++ b/models/fixtures/action_run.yml
@@ -17,6 +17,195 @@
updated: 1683636626
need_approval: 0
approved_by: 0
+ event_payload: |
+ {
+ "after": "7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "before": "0000000000000000000000000000000000000000",
+ "commits": [
+ {
+ "added": [
+ ".forgejo/workflows/test.yml"
+ ],
+ "author": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "committer": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "id": "7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "message": "initial commit\n",
+ "modified": [],
+ "removed": [],
+ "timestamp": "2024-01-24T18:59:25Z",
+ "url": "http://10.201.14.40:3000/root/example-push/commit/7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "verification": null
+ }
+ ],
+ "compare_url": "http://10.201.14.40:3000/",
+ "head_commit": {
+ "added": [
+ ".forgejo/workflows/test.yml"
+ ],
+ "author": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "committer": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "id": "7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "message": "initial commit\n",
+ "modified": [],
+ "removed": [],
+ "timestamp": "2024-01-24T18:59:25Z",
+ "url": "http://10.201.14.40:3000/root/example-push/commit/7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "verification": null
+ },
+ "pusher": {
+ "active": false,
+ "avatar_url": "http://10.201.14.40:3000/avatars/04edfc0ef6c6cf6d6b88fbc69f9f9071",
+ "created": "2024-01-24T18:57:32Z",
+ "description": "",
+ "email": "root@noreply.10.201.14.40",
+ "followers_count": 0,
+ "following_count": 0,
+ "full_name": "",
+ "id": 1,
+ "is_admin": false,
+ "language": "",
+ "last_login": "0001-01-01T00:00:00Z",
+ "location": "",
+ "login": "root",
+ "login_name": "",
+ "prohibit_login": false,
+ "restricted": false,
+ "starred_repos_count": 0,
+ "username": "root",
+ "visibility": "public",
+ "website": ""
+ },
+ "ref": "refs/heads/main",
+ "repository": {
+ "allow_merge_commits": true,
+ "allow_rebase": true,
+ "allow_rebase_explicit": true,
+ "allow_rebase_update": true,
+ "allow_squash_merge": true,
+ "archived": false,
+ "archived_at": "1970-01-01T00:00:00Z",
+ "avatar_url": "",
+ "clone_url": "http://10.201.14.40:3000/root/example-push.git",
+ "created_at": "2024-01-24T18:59:25Z",
+ "default_allow_maintainer_edit": false,
+ "default_branch": "main",
+ "default_delete_branch_after_merge": false,
+ "default_merge_style": "merge",
+ "description": "",
+ "empty": false,
+ "fork": false,
+ "forks_count": 0,
+ "full_name": "root/example-push",
+ "has_actions": true,
+ "has_issues": true,
+ "has_packages": true,
+ "has_projects": true,
+ "has_pull_requests": true,
+ "has_releases": true,
+ "has_wiki": true,
+ "html_url": "http://10.201.14.40:3000/root/example-push",
+ "id": 2,
+ "ignore_whitespace_conflicts": false,
+ "internal": false,
+ "internal_tracker": {
+ "allow_only_contributors_to_track_time": true,
+ "enable_issue_dependencies": true,
+ "enable_time_tracker": true
+ },
+ "language": "",
+ "languages_url": "http://10.201.14.40:3000/api/v1/repos/root/example-push/languages",
+ "link": "",
+ "mirror": false,
+ "mirror_interval": "",
+ "mirror_updated": "0001-01-01T00:00:00Z",
+ "name": "example-push",
+ "object_format_name": "",
+ "open_issues_count": 0,
+ "open_pr_counter": 0,
+ "original_url": "",
+ "owner": {
+ "active": false,
+ "avatar_url": "http://10.201.14.40:3000/avatars/04edfc0ef6c6cf6d6b88fbc69f9f9071",
+ "created": "2024-01-24T18:57:32Z",
+ "description": "",
+ "email": "root@example.com",
+ "followers_count": 0,
+ "following_count": 0,
+ "full_name": "",
+ "id": 1,
+ "is_admin": false,
+ "language": "",
+ "last_login": "0001-01-01T00:00:00Z",
+ "location": "",
+ "login": "root",
+ "login_name": "",
+ "prohibit_login": false,
+ "restricted": false,
+ "starred_repos_count": 0,
+ "username": "root",
+ "visibility": "public",
+ "website": ""
+ },
+ "parent": null,
+ "permissions": {
+ "admin": true,
+ "pull": true,
+ "push": true
+ },
+ "private": false,
+ "release_counter": 0,
+ "repo_transfer": null,
+ "size": 25,
+ "ssh_url": "forgejo@10.201.14.40:root/example-push.git",
+ "stars_count": 0,
+ "template": false,
+ "updated_at": "2024-01-24T18:59:25Z",
+ "url": "http://10.201.14.40:3000/api/v1/repos/root/example-push",
+ "watchers_count": 1,
+ "website": ""
+ },
+ "sender": {
+ "active": false,
+ "avatar_url": "http://10.201.14.40:3000/avatars/04edfc0ef6c6cf6d6b88fbc69f9f9071",
+ "created": "2024-01-24T18:57:32Z",
+ "description": "",
+ "email": "root@noreply.10.201.14.40",
+ "followers_count": 0,
+ "following_count": 0,
+ "full_name": "",
+ "id": 1,
+ "is_admin": false,
+ "language": "",
+ "last_login": "0001-01-01T00:00:00Z",
+ "location": "",
+ "login": "root",
+ "login_name": "",
+ "prohibit_login": false,
+ "restricted": false,
+ "starred_repos_count": 0,
+ "username": "root",
+ "visibility": "public",
+ "website": ""
+ },
+ "total_commits": 0
+ }
+
-
id: 792
title: "update actions"
@@ -36,3 +225,191 @@
updated: 1683636626
need_approval: 0
approved_by: 0
+ event_payload: |
+ {
+ "after": "7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "before": "0000000000000000000000000000000000000000",
+ "commits": [
+ {
+ "added": [
+ ".forgejo/workflows/test.yml"
+ ],
+ "author": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "committer": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "id": "7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "message": "initial commit\n",
+ "modified": [],
+ "removed": [],
+ "timestamp": "2024-01-24T18:59:25Z",
+ "url": "http://10.201.14.40:3000/root/example-push/commit/7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "verification": null
+ }
+ ],
+ "compare_url": "http://10.201.14.40:3000/",
+ "head_commit": {
+ "added": [
+ ".forgejo/workflows/test.yml"
+ ],
+ "author": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "committer": {
+ "email": "root@example.com",
+ "name": "username",
+ "username": "root"
+ },
+ "id": "7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "message": "initial commit\n",
+ "modified": [],
+ "removed": [],
+ "timestamp": "2024-01-24T18:59:25Z",
+ "url": "http://10.201.14.40:3000/root/example-push/commit/7a3858dc7f059543a8807a8b551304b7e362a7ef",
+ "verification": null
+ },
+ "pusher": {
+ "active": false,
+ "avatar_url": "http://10.201.14.40:3000/avatars/04edfc0ef6c6cf6d6b88fbc69f9f9071",
+ "created": "2024-01-24T18:57:32Z",
+ "description": "",
+ "email": "root@noreply.10.201.14.40",
+ "followers_count": 0,
+ "following_count": 0,
+ "full_name": "",
+ "id": 1,
+ "is_admin": false,
+ "language": "",
+ "last_login": "0001-01-01T00:00:00Z",
+ "location": "",
+ "login": "root",
+ "login_name": "",
+ "prohibit_login": false,
+ "restricted": false,
+ "starred_repos_count": 0,
+ "username": "root",
+ "visibility": "public",
+ "website": ""
+ },
+ "ref": "refs/heads/main",
+ "repository": {
+ "allow_merge_commits": true,
+ "allow_rebase": true,
+ "allow_rebase_explicit": true,
+ "allow_rebase_update": true,
+ "allow_squash_merge": true,
+ "archived": false,
+ "archived_at": "1970-01-01T00:00:00Z",
+ "avatar_url": "",
+ "clone_url": "http://10.201.14.40:3000/root/example-push.git",
+ "created_at": "2024-01-24T18:59:25Z",
+ "default_allow_maintainer_edit": false,
+ "default_branch": "main",
+ "default_delete_branch_after_merge": false,
+ "default_merge_style": "merge",
+ "description": "",
+ "empty": false,
+ "fork": false,
+ "forks_count": 0,
+ "full_name": "root/example-push",
+ "has_actions": true,
+ "has_issues": true,
+ "has_packages": true,
+ "has_projects": true,
+ "has_pull_requests": true,
+ "has_releases": true,
+ "has_wiki": true,
+ "html_url": "http://10.201.14.40:3000/root/example-push",
+ "id": 2,
+ "ignore_whitespace_conflicts": false,
+ "internal": false,
+ "internal_tracker": {
+ "allow_only_contributors_to_track_time": true,
+ "enable_issue_dependencies": true,
+ "enable_time_tracker": true
+ },
+ "language": "",
+ "languages_url": "http://10.201.14.40:3000/api/v1/repos/root/example-push/languages",
+ "link": "",
+ "mirror": false,
+ "mirror_interval": "",
+ "mirror_updated": "0001-01-01T00:00:00Z",
+ "name": "example-push",
+ "object_format_name": "",
+ "open_issues_count": 0,
+ "open_pr_counter": 0,
+ "original_url": "",
+ "owner": {
+ "active": false,
+ "avatar_url": "http://10.201.14.40:3000/avatars/04edfc0ef6c6cf6d6b88fbc69f9f9071",
+ "created": "2024-01-24T18:57:32Z",
+ "description": "",
+ "email": "root@example.com",
+ "followers_count": 0,
+ "following_count": 0,
+ "full_name": "",
+ "id": 1,
+ "is_admin": false,
+ "language": "",
+ "last_login": "0001-01-01T00:00:00Z",
+ "location": "",
+ "login": "root",
+ "login_name": "",
+ "prohibit_login": false,
+ "restricted": false,
+ "starred_repos_count": 0,
+ "username": "root",
+ "visibility": "public",
+ "website": ""
+ },
+ "parent": null,
+ "permissions": {
+ "admin": true,
+ "pull": true,
+ "push": true
+ },
+ "private": false,
+ "release_counter": 0,
+ "repo_transfer": null,
+ "size": 25,
+ "ssh_url": "forgejo@10.201.14.40:root/example-push.git",
+ "stars_count": 0,
+ "template": false,
+ "updated_at": "2024-01-24T18:59:25Z",
+ "url": "http://10.201.14.40:3000/api/v1/repos/root/example-push",
+ "watchers_count": 1,
+ "website": ""
+ },
+ "sender": {
+ "active": false,
+ "avatar_url": "http://10.201.14.40:3000/avatars/04edfc0ef6c6cf6d6b88fbc69f9f9071",
+ "created": "2024-01-24T18:57:32Z",
+ "description": "",
+ "email": "root@noreply.10.201.14.40",
+ "followers_count": 0,
+ "following_count": 0,
+ "full_name": "",
+ "id": 1,
+ "is_admin": false,
+ "language": "",
+ "last_login": "0001-01-01T00:00:00Z",
+ "location": "",
+ "login": "root",
+ "login_name": "",
+ "prohibit_login": false,
+ "restricted": false,
+ "starred_repos_count": 0,
+ "username": "root",
+ "visibility": "public",
+ "website": ""
+ },
+ "total_commits": 0
+ }
diff --git a/models/fixtures/webhook.yml b/models/fixtures/webhook.yml
index f62bae1f31..989bb5657a 100644
--- a/models/fixtures/webhook.yml
+++ b/models/fixtures/webhook.yml
@@ -1,15 +1,17 @@
-
id: 1
repo_id: 1
- url: www.example.com/url1
+ url: http://www.example.com/url1
+ http_method: POST
content_type: 1 # json
events: '{"push_only":true,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":false}}'
- is_active: true
+ is_active: false # disable to prevent sending hook task during unrelated tests
-
id: 2
repo_id: 1
- url: www.example.com/url2
+ url: http://www.example.com/url2
+ http_method: POST
content_type: 1 # json
events: '{"push_only":false,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":true}}'
is_active: false
@@ -18,14 +20,16 @@
id: 3
owner_id: 3
repo_id: 3
- url: www.example.com/url3
+ url: http://www.example.com/url3
+ http_method: POST
content_type: 1 # json
events: '{"push_only":false,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":true}}'
- is_active: true
+ is_active: false
-
id: 4
repo_id: 2
- url: www.example.com/url4
+ url: http://www.example.com/url4
+ http_method: POST
content_type: 1 # json
events: '{"push_only":true,"branch_filter":"{master,feature*}"}'
- is_active: true
+ is_active: false
diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index 2d1d1bcb06..d204d11c28 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -199,22 +199,17 @@ func (status *CommitStatus) LocaleString(lang translation.Locale) string {
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
- var lastStatus *CommitStatus
- state := api.CommitStatusSuccess
- for _, status := range statuses {
- if status.State.NoBetterThan(state) {
- state = status.State
- lastStatus = status
+ if len(statuses) == 0 {
+ return nil
+ }
+
+ latestWorstStatus := statuses[0]
+ for _, status := range statuses[1:] {
+ if status.State.NoBetterThan(latestWorstStatus.State) {
+ latestWorstStatus = status
}
}
- if lastStatus == nil {
- if len(statuses) > 0 {
- lastStatus = statuses[0]
- } else {
- lastStatus = &CommitStatus{}
- }
- }
- return lastStatus
+ return latestWorstStatus
}
// CommitStatusOptions holds the options for query commit statuses
diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go
index 74ba4a1006..94c8d3776c 100644
--- a/models/git/commit_status_test.go
+++ b/models/git/commit_status_test.go
@@ -141,16 +141,20 @@ func Test_CalcCommitStatus(t *testing.T) {
statuses: []*git_model.CommitStatus{
{
State: structs.CommitStatusSuccess,
+ ID: 1,
},
{
State: structs.CommitStatusSuccess,
+ ID: 2,
},
{
State: structs.CommitStatusSuccess,
+ ID: 3,
},
},
expected: &git_model.CommitStatus{
State: structs.CommitStatusSuccess,
+ ID: 3,
},
},
{
@@ -169,6 +173,10 @@ func Test_CalcCommitStatus(t *testing.T) {
State: structs.CommitStatusError,
},
},
+ {
+ statuses: []*git_model.CommitStatus{},
+ expected: nil,
+ },
}
for _, kase := range kases {
diff --git a/models/issues/issue.go b/models/issues/issue.go
index baa79b30d1..54ef5cec7a 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -500,7 +500,7 @@ func (issue *Issue) GetLastEventLabelFake() string {
// GetIssueByIndex returns raw issue without loading attributes by index in a repository.
func GetIssueByIndex(ctx context.Context, repoID, index int64) (*Issue, error) {
if index < 1 {
- return nil, ErrIssueNotExist{}
+ return nil, ErrIssueNotExist{0, repoID, index}
}
issue := &Issue{
RepoID: repoID,
diff --git a/models/migrations/base/tests.go b/models/migrations/base/tests.go
index 85cafc1ab9..0726211ea8 100644
--- a/models/migrations/base/tests.go
+++ b/models/migrations/base/tests.go
@@ -160,6 +160,10 @@ func MainTest(m *testing.M) {
exitStatus := m.Run()
+ if err := testlogger.WriterCloser.Reset(); err != nil && exitStatus == 0 {
+ fmt.Printf("testlogger.WriterCloser.Reset: %v\n", err)
+ os.Exit(1)
+ }
if err := removeAllWithRetry(setting.RepoRootPath); err != nil {
fmt.Fprintf(os.Stderr, "os.RemoveAll: %v\n", err)
}
diff --git a/models/migrations/v1_11/v111.go b/models/migrations/v1_11/v111.go
index d757acb7d2..c18d7adae1 100644
--- a/models/migrations/v1_11/v111.go
+++ b/models/migrations/v1_11/v111.go
@@ -23,9 +23,9 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
Type int
// Permissions
- IsAdmin bool
- IsRestricted bool `xorm:"NOT NULL DEFAULT false"`
- Visibility int `xorm:"NOT NULL DEFAULT 0"`
+ IsAdmin bool
+ // IsRestricted bool `xorm:"NOT NULL DEFAULT false"` glitch: this column was added in v1_12/v121.go
+ // Visibility int `xorm:"NOT NULL DEFAULT 0"` glitch: this column was added in v1_12/v124.go
}
type Review struct {
@@ -51,9 +51,9 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
ReviewTypeReject int = 3
// VisibleTypePublic Visible for everyone
- VisibleTypePublic int = 0
+ // VisibleTypePublic int = 0
// VisibleTypePrivate Visible only for organization's members
- VisibleTypePrivate int = 2
+ // VisibleTypePrivate int = 2
// unit.UnitTypeCode is unit type code
UnitTypeCode int = 1
@@ -145,9 +145,9 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
hasOrgVisible := true
// Not SignedUser
if user == nil {
- hasOrgVisible = repoOwner.Visibility == VisibleTypePublic
+ // hasOrgVisible = repoOwner.Visibility == VisibleTypePublic // VisibleTypePublic is the default
} else if !user.IsAdmin {
- hasMemberWithUserID, err := sess.
+ _, err := sess.
Where("uid=?", user.ID).
And("org_id=?", repoOwner.ID).
Table("org_user").
@@ -155,9 +155,10 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
if err != nil {
hasOrgVisible = false
}
- if (repoOwner.Visibility == VisibleTypePrivate || user.IsRestricted) && !hasMemberWithUserID {
- hasOrgVisible = false
- }
+ // VisibleTypePublic is the default so the condition below is always false
+ // if (repoOwner.Visibility == VisibleTypePrivate) && !hasMemberWithUserID {
+ // hasOrgVisible = false
+ // }
}
isCollaborator, err := sess.Get(&Collaboration{RepoID: repo.ID, UserID: user.ID})
@@ -195,7 +196,7 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
if user != nil {
userID = user.ID
- restricted = user.IsRestricted
+ restricted = false
}
if !restricted && !repo.IsPrivate {
@@ -284,7 +285,7 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
}
// for a public repo on an organization, a non-restricted user has read permission on non-team defined units.
- if !found && !repo.IsPrivate && !user.IsRestricted {
+ if !found && !repo.IsPrivate {
if _, ok := perm.UnitsMode[u.Type]; !ok {
perm.UnitsMode[u.Type] = AccessModeRead
}
diff --git a/models/migrations/v1_12/v128.go b/models/migrations/v1_12/v128.go
index 44d44a26c5..6eea1337ef 100644
--- a/models/migrations/v1_12/v128.go
+++ b/models/migrations/v1_12/v128.go
@@ -94,7 +94,7 @@ func FixMergeBase(x *xorm.Engine) error {
} else {
parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
- log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
+ log.Warn("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue
}
parents := strings.Split(strings.TrimSpace(parentsString), " ")
diff --git a/models/migrations/v1_12/v134.go b/models/migrations/v1_12/v134.go
index 3d1c82f09e..23c2916ba8 100644
--- a/models/migrations/v1_12/v134.go
+++ b/models/migrations/v1_12/v134.go
@@ -81,7 +81,7 @@ func RefixMergeBase(x *xorm.Engine) error {
parentsString, _, err := git.NewCommand(git.DefaultContext, "rev-list", "--parents", "-n", "1").AddDynamicArguments(pr.MergedCommitID).RunStdString(&git.RunOpts{Dir: repoPath})
if err != nil {
- log.Error("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
+ log.Warn("Unable to get parents for merged PR ID %d, Index %d in %s/%s. Error: %v", pr.ID, pr.Index, baseRepo.OwnerName, baseRepo.Name, err)
continue
}
parents := strings.Split(strings.TrimSpace(parentsString), " ")
diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go
index f4403776ce..b4f6ffa189 100644
--- a/models/webhook/webhook_test.go
+++ b/models/webhook/webhook_test.go
@@ -124,6 +124,9 @@ func TestGetWebhookByOwnerID(t *testing.T) {
func TestGetActiveWebhooksByRepoID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
+
+ activateWebhook(t, 1)
+
hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{RepoID: 1, IsActive: optional.Some(true)})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
@@ -144,6 +147,9 @@ func TestGetWebhooksByRepoID(t *testing.T) {
func TestGetActiveWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
+
+ activateWebhook(t, 3)
+
hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3, IsActive: optional.Some(true)})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
@@ -152,8 +158,18 @@ func TestGetActiveWebhooksByOwnerID(t *testing.T) {
}
}
+func activateWebhook(t *testing.T, hookID int64) {
+ t.Helper()
+ updated, err := db.GetEngine(db.DefaultContext).ID(hookID).Cols("is_active").Update(Webhook{IsActive: true})
+ assert.Equal(t, int64(1), updated)
+ assert.NoError(t, err)
+}
+
func TestGetWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
+
+ activateWebhook(t, 3)
+
hooks, err := db.Find[Webhook](db.DefaultContext, ListWebhookOptions{OwnerID: 3})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
diff --git a/modules/queue/workergroup.go b/modules/queue/workergroup.go
index 8c9dd274f0..ea4c0020c5 100644
--- a/modules/queue/workergroup.go
+++ b/modules/queue/workergroup.go
@@ -334,7 +334,10 @@ func (q *WorkerPoolQueue[T]) doRun() {
// since we are already in a "flush" operation, so the dispatching function shouldn't read the flush chan.
q.doDispatchBatchToWorker(wg, skipFlushChan)
q.doFlush(wg, flush)
- case err := <-wg.popItemErr:
+ case err, errOk := <-wg.popItemErr:
+ if !errOk {
+ return
+ }
if !q.isCtxRunCanceled() {
log.Error("Failed to pop item from queue %q (doRun): %v", q.GetName(), err)
}
diff --git a/modules/testlogger/testlogger.go b/modules/testlogger/testlogger.go
index 4215567c00..908885554d 100644
--- a/modules/testlogger/testlogger.go
+++ b/modules/testlogger/testlogger.go
@@ -4,8 +4,11 @@
package testlogger
import (
+ "bytes"
"context"
+ "errors"
"fmt"
+ "io"
"os"
"runtime"
"strings"
@@ -27,53 +30,146 @@ var WriterCloser = &testLoggerWriterCloser{}
type testLoggerWriterCloser struct {
sync.RWMutex
- t []testing.TB
+ t []testing.TB
+ errs []error // stack of error, parallel to the stack of testing.TB
+ err error // fallback if the stack is empty
}
func (w *testLoggerWriterCloser) pushT(t testing.TB) {
w.Lock()
w.t = append(w.t, t)
+ w.errs = append(w.errs, nil)
w.Unlock()
}
-func (w *testLoggerWriterCloser) Write(p []byte) (int, error) {
+func (w *testLoggerWriterCloser) Log(level log.Level, msg string) {
+ if len(msg) > 0 && msg[len(msg)-1] == '\n' {
+ msg = msg[:len(msg)-1]
+ }
+
+ w.printMsg(msg)
+ if level >= log.ERROR {
+ w.recordError(msg)
+ }
+}
+
+// list of error message which will not fail the test
+// ideally this list should be empty, however ensuring that it does not grow
+// is already a good first step.
+var ignoredErrorMessageSuffixes = []string{
+ // only seen on mysql tests https://codeberg.org/forgejo/forgejo/pulls/2657#issuecomment-1693055
+ `table columns using inconsistent collation, they should use "utf8mb4_0900_ai_ci". Please go to admin panel Self Check page`,
+
+ // TestAPIDeleteReleaseByTagName
+ // action notification were a commit cannot be computed (because the commit got deleted)
+ `Notify() [E] an error occurred while executing the DeleteRelease actions method: gitRepo.GetCommit: object does not exist [id: refs/tags/release-tag, rel_path: ]`,
+ `Notify() [E] an error occurred while executing the PushCommits actions method: gitRepo.GetCommit: object does not exist [id: refs/tags/release-tag, rel_path: ]`,
+
+ // TestAPIRepoTags
+ `Notify() [E] an error occurred while executing the DeleteRelease actions method: gitRepo.GetCommit: object does not exist [id: refs/tags/gitea/22, rel_path: ]`,
+ `Notify() [E] an error occurred while executing the PushCommits actions method: gitRepo.GetCommit: object does not exist [id: refs/tags/gitea/22, rel_path: ]`,
+
+ // TestAPIDeleteTagByName
+ `Notify() [E] an error occurred while executing the DeleteRelease actions method: gitRepo.GetCommit: object does not exist [id: refs/tags/delete-tag, rel_path: ]`,
+ `Notify() [E] an error occurred while executing the PushCommits actions method: gitRepo.GetCommit: object does not exist [id: refs/tags/delete-tag, rel_path: ]`,
+
+ // TestAPIGenerateRepo
+ `Notify() [E] an error occurred while executing the CreateRepository actions method: gitRepo.GetCommit: object does not exist [id: , rel_path: ]`,
+
+ // TestAPIPullReview
+ `PullRequestReview() [E] Unsupported review webhook type`,
+
+ // TestAPIPullReviewRequest
+ `ToAPIPullRequest() [E] unable to resolve PR head ref`,
+
+ // TestAPILFSUpload
+ `Put() [E] Whilst putting LFS OID[ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb]: Failed to copy to tmpPath: ca/97/8112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb Error: content size does not match`,
+ `[E] Error putting LFS MetaObject [ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb] into content store. Error: content size does not match`,
+ `UploadHandler() [E] Upload does not match LFS MetaObject [ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb]. Error: content size does not match`,
+ `Put() [E] Whilst putting LFS OID[2581dd7bbc1fe44726de4b7dd806a087a978b9c5aec0a60481259e34be09b06a]: Failed to copy to tmpPath: 25/81/dd7bbc1fe44726de4b7dd806a087a978b9c5aec0a60481259e34be09b06a Error: content hash does not match OID`,
+ `[E] Error putting LFS MetaObject [2581dd7bbc1fe44726de4b7dd806a087a978b9c5aec0a60481259e34be09b06a] into content store. Error: content hash does not match OID`,
+ `UploadHandler() [E] Upload does not match LFS MetaObject [2581dd7bbc1fe44726de4b7dd806a087a978b9c5aec0a60481259e34be09b06a]. Error: content hash does not match OID`,
+ `UploadHandler() [E] Upload does not match LFS MetaObject [83de2e488b89a0aa1c97496b888120a28b0c1e15463a4adb8405578c540f36d4]. Error: content size does not match`,
+
+ // TestAPILFSVerify
+ `getAuthenticatedMeta() [E] Unable to get LFS OID[fb8f7d8435968c4f82a726a92395be4d16f2f63116caf36c8ad35c60831ab042] Error: LFS Meta object does not exist`,
+
+ // TestAPIUpdateOrgAvatar
+ `UpdateAvatar() [E] UploadAvatar: image.DecodeConfig: image: unknown format`,
+
+ // TestGetAttachment
+ `/data/attachments/a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18: no such file or directory`,
+
+ // TestBlockUser
+ `BlockedUsersUnblock() [E] IsOrganization: org3 is an organization not a user`,
+ `BlockedUsersBlock() [E] IsOrganization: org3 is an organization not a user`,
+ `Action() [E] Cannot perform this action on an organization "unblock"`,
+ `Action() [E] Cannot perform this action on an organization "block"`,
+
+ // TestBlockActions
+ `/gitea-repositories/user10/repo7.git Error: no such file or directory`,
+
+ // TestE2e/explore.test.e2e
+ `TrString() [E] Missing translation "more_items"`,
+
+ // TestRebuildCargo
+ `RebuildCargoIndex() [E] RebuildIndex failed: GetRepositoryByOwnerAndName: repository does not exist [id: 0, uid: 0, owner_name: user2, name: _cargo-index]`,
+}
+
+func (w *testLoggerWriterCloser) recordError(msg string) {
+ for _, s := range ignoredErrorMessageSuffixes {
+ if strings.HasSuffix(msg, s) {
+ return
+ }
+ }
+
+ w.Lock()
+ defer w.Unlock()
+
+ err := w.err
+ if len(w.errs) > 0 {
+ err = w.errs[len(w.errs)-1]
+ }
+
+ err = errors.Join(err, errors.New(msg))
+
+ if len(w.errs) > 0 {
+ w.errs[len(w.errs)-1] = err
+ } else {
+ w.err = err
+ }
+}
+
+func (w *testLoggerWriterCloser) printMsg(msg string) {
// There was a data race problem: the logger system could still try to output logs after the runner is finished.
// So we must ensure that the "t" in stack is still valid.
w.RLock()
defer w.RUnlock()
- var t testing.TB
if len(w.t) > 0 {
- t = w.t[len(w.t)-1]
- }
-
- if len(p) > 0 && p[len(p)-1] == '\n' {
- p = p[:len(p)-1]
- }
-
- if t == nil {
+ t := w.t[len(w.t)-1]
+ t.Log(msg)
+ } else {
// if there is no running test, the log message should be outputted to console, to avoid losing important information.
// the "???" prefix is used to match the "===" and "+++" in PrintCurrentTest
- return fmt.Fprintf(os.Stdout, "??? [TestLogger] %s\n", p)
+ fmt.Fprintln(os.Stdout, "??? [TestLogger]", msg)
}
-
- t.Log(string(p))
- return len(p), nil
}
-func (w *testLoggerWriterCloser) popT() {
+func (w *testLoggerWriterCloser) popT() error {
w.Lock()
+ defer w.Unlock()
+
if len(w.t) > 0 {
w.t = w.t[:len(w.t)-1]
+ err := w.errs[len(w.errs)-1]
+ w.errs = w.errs[:len(w.errs)-1]
+ return err
}
- w.Unlock()
+ return w.err
}
-func (w *testLoggerWriterCloser) Close() error {
- return nil
-}
-
-func (w *testLoggerWriterCloser) Reset() {
+func (w *testLoggerWriterCloser) Reset() error {
w.Lock()
if len(w.t) > 0 {
for _, t := range w.t {
@@ -84,8 +180,12 @@ func (w *testLoggerWriterCloser) Reset() {
t.Errorf("Unclosed logger writer in test: %s", t.Name())
}
w.t = nil
+ w.errs = nil
}
+ err := w.err
+ w.err = nil
w.Unlock()
+ return err
}
// PrintCurrentTest prints the current test to os.Stdout
@@ -132,7 +232,10 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() {
_, _ = fmt.Fprintf(os.Stdout, "+++ %s had a slow clean-up flush (took %v)\n", t.Name(), flushTook)
}
}
- WriterCloser.popT()
+
+ if err := WriterCloser.popT(); err != nil {
+ t.Errorf("testlogger.go:recordError() FATAL ERROR: log.Error has been called: %v", err)
+ }
}
}
@@ -146,19 +249,72 @@ func Printf(format string, args ...any) {
_, _ = fmt.Fprintf(os.Stdout, "\t"+format, args...)
}
-// TestLogEventWriter is a logger which will write to the testing log
-type TestLogEventWriter struct {
- *log.EventWriterBaseImpl
-}
-
// NewTestLoggerWriter creates a TestLogEventWriter as a log.LoggerProvider
func NewTestLoggerWriter(name string, mode log.WriterMode) log.EventWriter {
w := &TestLogEventWriter{}
- w.EventWriterBaseImpl = log.NewEventWriterBase(name, "test-log-writer", mode)
- w.OutputWriteCloser = WriterCloser
+ w.base = log.NewEventWriterBase(name, "test-log-writer", mode)
+ w.writer = WriterCloser
return w
}
+// TestLogEventWriter is a logger which will write to the testing log
+type TestLogEventWriter struct {
+ base *log.EventWriterBaseImpl
+ writer *testLoggerWriterCloser
+}
+
+// Base implements log.EventWriter.
+func (t *TestLogEventWriter) Base() *log.EventWriterBaseImpl {
+ return t.base
+}
+
+// GetLevel implements log.EventWriter.
+func (t *TestLogEventWriter) GetLevel() log.Level {
+ return t.base.GetLevel()
+}
+
+// GetWriterName implements log.EventWriter.
+func (t *TestLogEventWriter) GetWriterName() string {
+ return t.base.GetWriterName()
+}
+
+// GetWriterType implements log.EventWriter.
+func (t *TestLogEventWriter) GetWriterType() string {
+ return t.base.GetWriterType()
+}
+
+// Run implements log.EventWriter.
+func (t *TestLogEventWriter) Run(ctx context.Context) {
+ for {
+ select {
+ case <-ctx.Done():
+ return
+ case event, ok := <-t.base.Queue:
+ if !ok {
+ return
+ }
+
+ var errorMsg string
+
+ switch msg := event.Msg.(type) {
+ case string:
+ errorMsg = msg
+ case []byte:
+ errorMsg = string(msg)
+ case io.WriterTo:
+ var buf bytes.Buffer
+ if _, err := msg.WriteTo(&buf); err != nil {
+ panic(err)
+ }
+ errorMsg = buf.String()
+ default:
+ errorMsg = fmt.Sprint(msg)
+ }
+ t.writer.Log(event.Origin.Level, errorMsg)
+ }
+ }
+}
+
func init() {
const relFilePath = "modules/testlogger/testlogger.go"
_, filename, _, _ := runtime.Caller(0)
diff --git a/modules/translation/i18n/localestore.go b/modules/translation/i18n/localestore.go
index 44c3fb0c88..0e6ddab401 100644
--- a/modules/translation/i18n/localestore.go
+++ b/modules/translation/i18n/localestore.go
@@ -114,16 +114,22 @@ func (l *locale) TrString(trKey string, trArgs ...any) string {
format := trKey
idx, ok := l.store.trKeyToIdxMap[trKey]
+ found := false
if ok {
if msg, ok := l.idxToMsgMap[idx]; ok {
format = msg // use the found translation
+ found = true
} else if def, ok := l.store.localeMap[l.store.defaultLang]; ok {
// try to use default locale's translation
if msg, ok := def.idxToMsgMap[idx]; ok {
format = msg
+ found = true
}
}
}
+ if !found {
+ log.Error("Missing translation %q", trKey)
+ }
msg, err := Format(format, trArgs...)
if err != nil {
diff --git a/options/locale/locale_ar.ini b/options/locale/locale_ar.ini
index 0e27147e10..375d681c7c 100644
--- a/options/locale/locale_ar.ini
+++ b/options/locale/locale_ar.ini
@@ -1655,6 +1655,7 @@ config.default_keep_email_private = أخفِ عناوين البريد الإل
config.default_allow_create_organization = اسمح بإنشاء المنظمات مبدئيا
config.enable_timetracking = فعّل تتبع الوقت
config.default_enable_timetracking = فعّل تتبع الوقت مبدئيا
+config.allow_dots_in_usernames = السماح للمستخدمين بوضع نقاط في أسمائهم. لا يؤثر على الحسابات الموجودة.
config.default_allow_only_contributors_to_track_time = اسمح للمشتركين في المستودع موحدهم بتتبع الوقت
[form]
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index cb984aad07..6697ba4b3f 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -3224,6 +3224,7 @@ config.default_keep_email_private=Ve výchozím nastavení skrýt e-mailové adr
config.default_allow_create_organization=Povolit ve výchozím nastavení vytvářet organizace
config.enable_timetracking=Povolit sledování času
config.default_enable_timetracking=Povolit ve výchozím nastavení sledování času
+config.allow_dots_in_usernames = Povolit uživatelům používat tečky ve svých uživatelských jménech. Neovlivní stávající účty.
config.default_allow_only_contributors_to_track_time=Povolit sledování času pouze přispěvatelům
config.no_reply_address=Skrytá e-mailová doména
config.default_visibility_organization=Výchozí viditelnost nových organizací
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index 983580598e..cb9c2fe725 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -3204,6 +3204,7 @@ config.default_keep_email_private=E-Mail-Adressen standardmäßig verbergen
config.default_allow_create_organization=Erstellen von Organisationen standardmäßig erlauben
config.enable_timetracking=Zeiterfassung aktivieren
config.default_enable_timetracking=Zeiterfassung standardmäßig aktivieren
+config.allow_dots_in_usernames = Erlaubt Benutzern die Verwendung von Punkten in ihren Benutzernamen. Hat keine Auswirkungen auf bestehende Konten.
config.default_allow_only_contributors_to_track_time=Nur Mitarbeitern erlauben, die Zeiterfassung zu nutzen
config.no_reply_address=Versteckte E-Mail-Domain
config.default_visibility_organization=Standard-Sichtbarkeit für neue Organisationen
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index 7d43c83cc3..36b7518c62 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -3192,6 +3192,7 @@ config.default_keep_email_private=Να αποκρύπτονται οι διευ
config.default_allow_create_organization=Να επιτρέπεται η δημιουργία οργανισμών από προεπιλογή
config.enable_timetracking=Ενεργοποίηση καταγραφής χρόνου
config.default_enable_timetracking=Ενεργοποίηση καταγραφής χρόνου από προεπιλογή
+config.allow_dots_in_usernames = Επιτρέπει την χρήση τελείων σε ονόματα χρηστών. Δεν θα επηρεαστούν λογαριασμοί που ήδη υπάρχουν.
config.default_allow_only_contributors_to_track_time=Να επιτρέπεται η καταγραφή χρόνου μόνο από συνεισφέροντες
config.no_reply_address=Κρυφό email domain
config.default_visibility_organization=Προεπιλεγμένη ορατότητα νέων οργανισμών
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 79f757ee66..86a7ebcf82 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -3215,6 +3215,7 @@ config.default_keep_email_private = Hide email addresses by default
config.default_allow_create_organization = Allow creation of organizations by default
config.enable_timetracking = Enable time tracking
config.default_enable_timetracking = Enable time tracking by default
+config.allow_dots_in_usernames = Allow users to use dots in their usernames. Doesn't affect existing accounts.
config.default_allow_only_contributors_to_track_time = Let only contributors track time
config.no_reply_address = Hidden email domain
config.default_visibility_organization = Default visibility of new organizations
diff --git a/options/locale/locale_eo.ini b/options/locale/locale_eo.ini
index 0f03a1b9ba..dfc842da19 100644
--- a/options/locale/locale_eo.ini
+++ b/options/locale/locale_eo.ini
@@ -303,6 +303,7 @@ smtp_from_invalid = La «Sendu retleterojn kiel» adreso malvalidas
[admin]
config.app_data_path = Programdatuja doseiervojo
+config.allow_dots_in_usernames = Permesi ĉeeston de punktoj en uzantonomoj. Ne efikas je jamaj kontoj.
[home]
filter = Aliaj filtriloj
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 0b4f0bef33..3dbca87381 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -3107,6 +3107,7 @@ config.default_keep_email_private=Ocultar direcciones de correo electrónico por
config.default_allow_create_organization=Permitir la creación de organizaciones por defecto
config.enable_timetracking=Habilitar seguimiento de tiempo
config.default_enable_timetracking=Habilitar seguimiento de tiempo por defecto
+config.allow_dots_in_usernames = Permite utilizar puntos en los nombres de usuario. No tiene efecto sobre cuentas existentes.
config.default_allow_only_contributors_to_track_time=Deje que solo los colaboradores hagan un seguimiento del tiempo
config.no_reply_address=Dominio de correos electrónicos ocultos
config.default_visibility_organization=Visibilidad por defecto para nuevas organizaciones
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index 36c849bd7b..bdedee0e81 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -3229,6 +3229,7 @@ config.default_keep_email_private=Masquer les adresses courriel par défaut
config.default_allow_create_organization=Autoriser la création d'organisations par défaut
config.enable_timetracking=Activer le suivi du temps
config.default_enable_timetracking=Activer le suivi de temps par défaut
+config.allow_dots_in_usernames = Les points sont autorisés dans les noms d'utilisateurs. Sans effet sur les comptes existants.
config.default_allow_only_contributors_to_track_time=Restreindre le suivi de temps aux contributeurs
config.no_reply_address=Domaine pour les courriels cachés
config.default_visibility_organization=Visibilité par défaut des nouvelles organisations
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index 2d41edf59d..8811a12810 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -3145,6 +3145,7 @@ config.default_keep_email_private=Nascondi indirizzo email in modo predefinito
config.default_allow_create_organization=Consenti la creazione di organizzazioni in modo predefinito
config.enable_timetracking=Abilita il cronografo
config.default_enable_timetracking=Attiva il cronografo di default
+config.allow_dots_in_usernames = Consenti l'uso del punto nel nome utente. Non impatta gli account già esistenti.
config.default_allow_only_contributors_to_track_time=Consenti soltanto ai contributori di utilizzare il cronografo
config.no_reply_address=Dominio email nascosto
config.default_visibility_organization=Visibilità predefinita per le nuove organizzazioni
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index 1aa00440d9..7f3e1ded36 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -3184,6 +3184,7 @@ config.default_keep_email_private=デフォルトでメールアドレスを隠
config.default_allow_create_organization=デフォルトで組織の作成を許可
config.enable_timetracking=タイムトラッキング有効
config.default_enable_timetracking=デフォルトでタイムトラッキング有効
+config.allow_dots_in_usernames = ユーザー名にドットを使用できるようにします。既存のアカウントには影響しません。
config.default_allow_only_contributors_to_track_time=コントリビューターだけタイムトラッキングする
config.no_reply_address=メールを隠すときのドメイン
config.default_visibility_organization=新しい組織のデフォルトの表示設定
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index 95d370661d..e2a3dc694e 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -3096,6 +3096,7 @@ config.default_keep_email_private=Verberg standaard alle e-mailadressen
config.default_allow_create_organization=Standaard toestaan om organisaties aan te maken
config.enable_timetracking=Tijdregistratie inschakelen
config.default_enable_timetracking=Tijdregistratie standaard inschakelen
+config.allow_dots_in_usernames = Sta gebruikers toe om punten te gebruiken in hun gebruikersnaam. Heeft geen invloed op bestaande accounts.
config.default_allow_only_contributors_to_track_time=Sta alleen bijdragers toe tijdregistratie te gebruiken
config.no_reply_address=Verborgen e-maildomein
config.default_visibility_organization=Standaard zichtbaarheid voor nieuwe organisaties
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index ade7c6c704..086cea74fa 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -3096,6 +3096,7 @@ config.default_keep_email_private=Ocultar endereços de e-mail por padrão
config.default_allow_create_organization=Permitir a criação de organizações por padrão
config.enable_timetracking=Habilitar Cronômetro
config.default_enable_timetracking=Habilitar o Cronômetro por Padrão
+config.allow_dots_in_usernames = Permitir pontos em nomes de usuário. Esta opção não afeta contas já existentes.
config.default_allow_only_contributors_to_track_time=Permitir que apenas os colaboradores acompanhem o contador de tempo
config.no_reply_address=Ocultar domínio de e-mail
config.default_visibility_organization=Visibilidade padrão para novas organizações
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index e355d4c9c9..a6f861ba68 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -3189,6 +3189,7 @@ config.default_keep_email_private=Скрывать адреса эл. почты
config.default_allow_create_organization=Разрешить создание организаций по умолчанию
config.enable_timetracking=Отслеживание времени
config.default_enable_timetracking=Включить отслеживание времени по умолчанию
+config.allow_dots_in_usernames = Разрешить точки в логинах пользователей. Это не повлияет на уже созданные учётные записи.
config.default_allow_only_contributors_to_track_time=Подсчитывать время могут только соавторы
config.no_reply_address=Домен скрытых адресов почты
config.default_visibility_organization=Видимость новых организаций по умолчанию
diff --git a/options/locale/locale_sl.ini b/options/locale/locale_sl.ini
index 01404dd0b4..d555f3fe19 100644
--- a/options/locale/locale_sl.ini
+++ b/options/locale/locale_sl.ini
@@ -267,6 +267,7 @@ config.git_config = Konfiguracija Git
config.git_max_diff_line_characters = Največ različnih znakov na vrstico
notices.view_detail_header = Podrobnosti obvestila
config.log_config = Konfiguracija dnevnika
+config.allow_dots_in_usernames = Uporabnikom dovolite uporabo pik v uporabniških imenih. Ne vpliva na obstoječe račune.
[repo]
migrate.github_token_desc = Tu lahko vstavite enega ali več žetonov, ločenih z vejico, da bo selitev hitrejša zaradi omejitve hitrosti GitHub API. OPOZORILO: Zloraba te funkcije lahko krši pravila ponudnika storitev in povzroči blokado računa.
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index bc768afc6f..4ca2e70f21 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -3224,6 +3224,7 @@ config.default_keep_email_private=默认情况下隐藏电子邮件地址
config.default_allow_create_organization=默认情况下允许创建组织
config.enable_timetracking=启用时间跟踪
config.default_enable_timetracking=默认情况下启用时间跟踪
+config.allow_dots_in_usernames = 允许用户在用户名中使用英文句号。不影响已有的帐户。
config.default_allow_only_contributors_to_track_time=仅允许成员跟踪时间
config.no_reply_address=隐藏电子邮件域
config.default_visibility_organization=新组织的默认可见性
diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go
index d530e9cee5..2f8b3d0210 100644
--- a/routers/api/actions/artifacts.go
+++ b/routers/api/actions/artifacts.go
@@ -311,7 +311,7 @@ func (ar artifactRoutes) comfirmUploadArtifact(ctx *ArtifactContext) {
}
artifactName := ctx.Req.URL.Query().Get("artifactName")
if artifactName == "" {
- log.Error("Error artifact name is empty")
+ log.Warn("Error artifact name is empty")
ctx.Error(http.StatusBadRequest, "Error artifact name is empty")
return
}
diff --git a/routers/api/actions/artifacts_utils.go b/routers/api/actions/artifacts_utils.go
index aaf89ef40e..d2e7ccaea1 100644
--- a/routers/api/actions/artifacts_utils.go
+++ b/routers/api/actions/artifacts_utils.go
@@ -61,7 +61,7 @@ func validateArtifactHash(ctx *ArtifactContext, artifactName string) bool {
if paramHash == artifactHash {
return true
}
- log.Error("Invalid artifact hash: %s", paramHash)
+ log.Warn("Invalid artifact hash: %s", paramHash)
ctx.Error(http.StatusBadRequest, "Invalid artifact hash")
return false
}
diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go
index 8300989c75..5a251e2ef9 100644
--- a/routers/api/actions/artifactsv4.go
+++ b/routers/api/actions/artifactsv4.go
@@ -359,7 +359,7 @@ func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
checksum = req.Hash.Value
}
if err := mergeChunksForArtifact(ctx, chunks, r.fs, artifact, checksum); err != nil {
- log.Error("Error merge chunks: %v", err)
+ log.Warn("Error merge chunks: %v", err)
ctx.Error(http.StatusInternalServerError, "Error merge chunks")
return
}
diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go
index 27f0578db7..7571797593 100644
--- a/routers/api/packages/maven/maven.go
+++ b/routers/api/packages/maven/maven.go
@@ -49,7 +49,10 @@ var (
func apiError(ctx *context.Context, status int, obj any) {
helper.LogAndProcessError(ctx, status, obj, func(message string) {
// The maven client does not present the error message to the user. Log it for users with access to server logs.
- if status == http.StatusBadRequest || status == http.StatusInternalServerError {
+ switch status {
+ case http.StatusBadRequest:
+ log.Warn(message)
+ case http.StatusInternalServerError:
log.Error(message)
}
diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go
index 59ebc74b89..6003f664a0 100644
--- a/routers/api/v1/activitypub/reqsignature.go
+++ b/routers/api/v1/activitypub/reqsignature.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/activitypub"
"code.gitea.io/gitea/modules/httplib"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
gitea_context "code.gitea.io/gitea/services/context"
@@ -89,7 +90,8 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, er
func ReqHTTPSignature() func(ctx *gitea_context.APIContext) {
return func(ctx *gitea_context.APIContext) {
if authenticated, err := verifyHTTPSignatures(ctx); err != nil {
- ctx.ServerError("verifyHttpSignatures", err)
+ log.Warn("verifyHttpSignatures failed: %v", err)
+ ctx.Error(http.StatusBadRequest, "reqSignature", "request signature verification failed")
} else if !authenticated {
ctx.Error(http.StatusForbidden, "reqSignature", "request signature verification failed")
}
diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go
index 8d97e8a3f8..1744426ee8 100644
--- a/routers/api/v1/notify/repo.go
+++ b/routers/api/v1/notify/repo.go
@@ -10,7 +10,6 @@ import (
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/convert"
@@ -201,7 +200,6 @@ func ReadRepoNotifications(ctx *context.APIContext) {
if !ctx.FormBool("all") {
statuses := ctx.FormStrings("status-types")
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
- log.Error("%v", opts.Status)
}
nl, err := db.Find[activities_model.Notification](ctx, opts)
if err != nil {
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 7c01226c95..99f2dd07dc 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -6,6 +6,7 @@ package actions
import (
"bytes"
"context"
+ "errors"
"fmt"
"slices"
"strings"
@@ -25,6 +26,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
webhook_module "code.gitea.io/gitea/modules/webhook"
"code.gitea.io/gitea/services/convert"
@@ -190,6 +192,12 @@ func notify(ctx context.Context, input *notifyInput) error {
baseRef := git.BranchPrefix + input.PullRequest.BaseBranch
baseCommit, err := gitRepo.GetCommit(baseRef)
if err != nil {
+ if prp, ok := input.Payload.(*api.PullRequestPayload); ok && errors.Is(err, util.ErrNotExist) {
+ // the baseBranch was deleted and the PR closed: the action can be skipped
+ if prp.Action == api.HookIssueClosed {
+ return nil
+ }
+ }
return fmt.Errorf("gitRepo.GetCommit: %w", err)
}
baseWorkflows, _, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload)
diff --git a/services/packages/packages.go b/services/packages/packages.go
index 64b1ddd869..8f688a74f4 100644
--- a/services/packages/packages.go
+++ b/services/packages/packages.go
@@ -165,11 +165,15 @@ func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, all
if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
if err == packages_model.ErrDuplicatePackageVersion {
versionCreated = false
- }
- if err != packages_model.ErrDuplicatePackageVersion || !allowDuplicate {
+ } else {
log.Error("Error inserting package: %v", err)
return nil, false, err
}
+
+ if !allowDuplicate {
+ // no need to log an error
+ return nil, false, err
+ }
}
if versionCreated {
diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go
index 514bcee8f1..cb63123463 100644
--- a/services/pull/commit_status.go
+++ b/services/pull/commit_status.go
@@ -65,7 +65,7 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus,
if status != nil {
return status.State
}
- return structs.CommitStatusSuccess
+ return ""
}
return returnedStatus
diff --git a/services/repository/commitstatus/commitstatus.go b/services/repository/commitstatus/commitstatus.go
index 145fc7d53c..0bb738e2ad 100644
--- a/services/repository/commitstatus/commitstatus.go
+++ b/services/repository/commitstatus/commitstatus.go
@@ -123,7 +123,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(ctx, repo.ID, repo.DefaultBranch, results[i].State); err != nil {
log.Error("updateCommitStatusCache[%d:%s] failed: %v", repo.ID, repo.DefaultBranch, err)
}
diff --git a/services/webhook/webhook_test.go b/services/webhook/webhook_test.go
index 5f5c146232..1ef152838d 100644
--- a/services/webhook/webhook_test.go
+++ b/services/webhook/webhook_test.go
@@ -28,10 +28,19 @@ func TestWebhook_GetSlackHook(t *testing.T) {
})
}
+func activateWebhook(t *testing.T, hookID int64) {
+ t.Helper()
+ updated, err := db.GetEngine(db.DefaultContext).ID(hookID).Cols("is_active").Update(webhook_model.Webhook{IsActive: true})
+ assert.Equal(t, int64(1), updated)
+ assert.NoError(t, err)
+}
+
func TestPrepareWebhooks(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ activateWebhook(t, 1)
+
hookTasks := []*webhook_model.HookTask{
{HookID: 1, EventType: webhook_module.HookEventPush},
}
@@ -48,6 +57,8 @@ func TestPrepareWebhooksBranchFilterMatch(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+ activateWebhook(t, 4)
+
hookTasks := []*webhook_model.HookTask{
{HookID: 4, EventType: webhook_module.HookEventPush},
}
diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go
index df4fe95fdb..12681ab0f9 100644
--- a/tests/e2e/e2e_test.go
+++ b/tests/e2e/e2e_test.go
@@ -59,8 +59,10 @@ func TestMain(m *testing.M) {
exitVal := m.Run()
- testlogger.WriterCloser.Reset()
-
+ if err := testlogger.WriterCloser.Reset(); err != nil {
+ fmt.Printf("testlogger.WriterCloser.Reset: %v\n", err)
+ os.Exit(1)
+ }
if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil {
fmt.Printf("util.RemoveAll: %v\n", err)
os.Exit(1)
diff --git a/tests/integration/api_activitypub_person_test.go b/tests/integration/api_activitypub_person_test.go
index 42a2a09072..eb00d6031c 100644
--- a/tests/integration/api_activitypub_person_test.go
+++ b/tests/integration/api_activitypub_person_test.go
@@ -108,6 +108,6 @@ func TestActivityPubPersonInbox(t *testing.T) {
// Unsigned request fails
req := NewRequest(t, "POST", user2inboxurl)
- MakeRequest(t, req, http.StatusInternalServerError)
+ MakeRequest(t, req, http.StatusBadRequest)
})
}
diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go
index 0a2003447a..76b36a7349 100644
--- a/tests/integration/integration_test.go
+++ b/tests/integration/integration_test.go
@@ -145,7 +145,10 @@ func TestMain(m *testing.M) {
// Instead, "No tests were found", last nonsense log is "According to the configuration, subsequent logs will not be printed to the console"
exitCode := m.Run()
- testlogger.WriterCloser.Reset()
+ if err := testlogger.WriterCloser.Reset(); err != nil {
+ fmt.Printf("testlogger.WriterCloser.Reset: %v\n", err)
+ os.Exit(1)
+ }
if err = util.RemoveAll(setting.Indexer.IssuePath); err != nil {
fmt.Printf("util.RemoveAll: %v\n", err)
diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go
index ee13a4bc57..e79d99b052 100644
--- a/tests/integration/pull_merge_test.go
+++ b/tests/integration/pull_merge_test.go
@@ -80,10 +80,22 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
return resp
}
+func retrieveHookTasks(t *testing.T, hookID int64, activateWebhook bool) []*webhook.HookTask {
+ t.Helper()
+ if activateWebhook {
+ updated, err := db.GetEngine(db.DefaultContext).ID(hookID).Cols("is_active").Update(webhook.Webhook{IsActive: true})
+ assert.Equal(t, int64(1), updated)
+ assert.NoError(t, err)
+ }
+
+ hookTasks, err := webhook.HookTasks(db.DefaultContext, hookID, 1)
+ assert.NoError(t, err)
+ return hookTasks
+}
+
func TestPullMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
- hookTasks, err := webhook.HookTasks(db.DefaultContext, 1, 1) // Retrieve previous hook number
- assert.NoError(t, err)
+ hookTasks := retrieveHookTasks(t, 1, true)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
@@ -96,16 +108,14 @@ func TestPullMerge(t *testing.T) {
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleMerge, false)
- hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
- assert.NoError(t, err)
+ hookTasks = retrieveHookTasks(t, 1, false)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullRebase(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
- hookTasks, err := webhook.HookTasks(db.DefaultContext, 1, 1) // Retrieve previous hook number
- assert.NoError(t, err)
+ hookTasks := retrieveHookTasks(t, 1, true)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
@@ -118,16 +128,14 @@ func TestPullRebase(t *testing.T) {
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebase, false)
- hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
- assert.NoError(t, err)
+ hookTasks = retrieveHookTasks(t, 1, false)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullRebaseMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
- hookTasks, err := webhook.HookTasks(db.DefaultContext, 1, 1) // Retrieve previous hook number
- assert.NoError(t, err)
+ hookTasks := retrieveHookTasks(t, 1, true)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
@@ -140,16 +148,14 @@ func TestPullRebaseMerge(t *testing.T) {
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleRebaseMerge, false)
- hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
- assert.NoError(t, err)
+ hookTasks = retrieveHookTasks(t, 1, false)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullSquash(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
- hookTasks, err := webhook.HookTasks(db.DefaultContext, 1, 1) // Retrieve previous hook number
- assert.NoError(t, err)
+ hookTasks := retrieveHookTasks(t, 1, true)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
@@ -163,8 +169,7 @@ func TestPullSquash(t *testing.T) {
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], repo_model.MergeStyleSquash, false)
- hookTasks, err = webhook.HookTasks(db.DefaultContext, 1, 1)
- assert.NoError(t, err)
+ hookTasks = retrieveHookTasks(t, 1, false)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue
index d6b7d6c96f..825803d939 100644
--- a/web_src/js/components/DashboardRepoList.vue
+++ b/web_src/js/components/DashboardRepoList.vue
@@ -251,9 +251,8 @@ const sfc = {
this.repos = json.data.map((webSearchRepo) => {
return {
...webSearchRepo.repository,
- latest_commit_status_state: webSearchRepo.latest_commit_status.State,
- locale_latest_commit_status_state: webSearchRepo.locale_latest_commit_status,
- latest_commit_status_state_link: webSearchRepo.latest_commit_status.TargetURL
+ latest_commit_status: webSearchRepo.latest_commit_status,
+ locale_latest_commit_status_state: webSearchRepo.locale_latest_commit_status
};
});
const count = response.headers.get('X-Total-Count');
@@ -416,9 +415,9 @@ export default sfc; // activate the IDE's Vue plugin
-
+
-
+