Merge pull request '[TESTS] fail when log.Error is called' (#2657) from oliverpool/forgejo:fail_test_on_log_error into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2657
This commit is contained in:
commit
5a18b74632
|
@ -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
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
repo_id: 2 # private
|
||||
is_private: true
|
||||
created_unix: 1603228283
|
||||
content: '1|' # issueId 4
|
||||
|
||||
-
|
||||
id: 2
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ func AddBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
|||
|
||||
// Permissions
|
||||
IsAdmin bool
|
||||
IsRestricted bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Visibility int `xorm:"NOT NULL DEFAULT 0"`
|
||||
// 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
|
||||
}
|
||||
|
|
|
@ -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), " ")
|
||||
|
|
|
@ -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), " ")
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
package testlogger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -28,52 +31,145 @@ var WriterCloser = &testLoggerWriterCloser{}
|
|||
type testLoggerWriterCloser struct {
|
||||
sync.RWMutex
|
||||
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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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í
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=Προεπιλεγμένη ορατότητα νέων οργανισμών
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=新しい組織のデフォルトの表示設定
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=Видимость новых организаций по умолчанию
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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=新组织的默认可见性
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -65,7 +65,7 @@ func MergeRequiredContextsCommitStatus(commitStatuses []*git_model.CommitStatus,
|
|||
if status != nil {
|
||||
return status.State
|
||||
}
|
||||
return structs.CommitStatusSuccess
|
||||
return ""
|
||||
}
|
||||
|
||||
return returnedStatus
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
|||
<svg-icon name="octicon-archive" :size="16"/>
|
||||
</div>
|
||||
</a>
|
||||
<a class="gt-df gt-ac" v-if="repo.latest_commit_status_state" :href="repo.latest_commit_status_state_link" :data-tooltip-content="repo.locale_latest_commit_status_state">
|
||||
<a class="gt-df gt-ac" v-if="repo.latest_commit_status" :href="repo.latest_commit_status.TargetLink" :data-tooltip-content="repo.locale_latest_commit_status.State">
|
||||
<!-- the commit status icon logic is taken from templates/repo/commit_status.tmpl -->
|
||||
<svg-icon :name="statusIcon(repo.latest_commit_status_state)" :class-name="'gt-ml-3 commit-status icon text ' + statusColor(repo.latest_commit_status_state)" :size="16"/>
|
||||
<svg-icon :name="statusIcon(repo.latest_commit_status.State)" :class-name="'gt-ml-3 commit-status icon text ' + statusColor(repo.latest_commit_status.State)" :size="16"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
Loading…
Reference in a new issue