From b698b256f1f687ae357d07b36e66931247bab22f Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Mon, 16 Dec 2024 15:34:41 +0100 Subject: [PATCH 01/35] fix: Ignore self review request notification A notification would be trigger if a user request itself as review of a PR. --- services/issue/assignee.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 9c2ef74bb0..3d6d0b881a 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -72,7 +72,8 @@ func ReviewRequest(ctx context.Context, issue *issues_model.Issue, doer, reviewe return nil, err } - if comment != nil { + // don't notify if the user is requesting itself as reviewer + if comment != nil && doer.ID != reviewer.ID { notify_service.PullRequestReviewRequest(ctx, doer, issue, reviewer, isAdd, comment) } From d7fa527605b32359d7956d22d5dc28bf209805e1 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Tue, 17 Dec 2024 17:51:41 +0100 Subject: [PATCH 02/35] test: Test notification count for self review This tests the case where the user adds itself as reviewer and it shouldn't get a notification. --- tests/integration/pull_review_test.go | 98 +++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index b3380cc6b8..1319db29bf 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -5,6 +5,7 @@ package integration import ( "context" + "fmt" "net/http" "net/http/httptest" "net/url" @@ -19,6 +20,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/gitrepo" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/test" issue_service "code.gitea.io/gitea/services/issue" repo_service "code.gitea.io/gitea/services/repository" @@ -62,6 +64,74 @@ func loadComment(t *testing.T, commentID string) *issues_model.Comment { return unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: id}) } +func TestPullView_SelfReviewNotification(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + user1Session := loginUser(t, "user1") + user2Session := loginUser(t, "user2") + + user1csrf := GetCSRF(t, user1Session, "/") + oldUser1NotificationCount := getUserNotificationCount(t, user1Session, user1csrf) + + user2csrf := GetCSRF(t, user2Session, "/") + oldUser2NotificationCount := getUserNotificationCount(t, user2Session, user2csrf) + + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + repo, _, f := tests.CreateDeclarativeRepo(t, user2, "test_reviewer", nil, nil, []*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: "CODEOWNERS", + ContentReader: strings.NewReader("README.md @user5\n"), + }, + }) + defer f() + + // we need to add user1 as collaborator so it can be added as reviewer + err := repo_module.AddCollaborator(db.DefaultContext, repo, user1) + require.NoError(t, err) + + // create a new branch to prepare for pull request + _, err = files_service.ChangeRepoFiles(db.DefaultContext, repo, user2, &files_service.ChangeRepoFilesOptions{ + NewBranch: "codeowner-basebranch", + Files: []*files_service.ChangeRepoFile{ + { + Operation: "update", + TreePath: "README.md", + ContentReader: strings.NewReader("# This is a new project\n"), + }, + }, + }) + require.NoError(t, err) + + // Create a pull request. + resp := testPullCreate(t, user2Session, "user2", "test_reviewer", false, repo.DefaultBranch, "codeowner-basebranch", "Test Pull Request") + prURL := test.RedirectURL(resp) + elem := strings.Split(prURL, "/") + assert.EqualValues(t, "pulls", elem[3]) + + req := NewRequest(t, http.MethodGet, prURL) + resp = MakeRequest(t, req, http.StatusOK) + doc := NewHTMLParser(t, resp.Body) + attributeFilter := fmt.Sprintf("[data-update-url='/%s/%s/issues/request_review']", user2.Name, repo.Name) + issueID, ok := doc.Find(attributeFilter).Attr("data-issue-id") + assert.True(t, ok, "doc must contain data-issue-id") + + user1csrf = GetCSRF(t, user1Session, "/") + testAssignReviewer(t, user1Session, user1csrf, user2.Name, repo.Name, issueID, "1", http.StatusOK) + + // both user notification should keep the same notification count since + // user2 added itself as reviewer. + user1csrf = GetCSRF(t, user1Session, "/") + notificationCount := getUserNotificationCount(t, user1Session, user1csrf) + assert.Equal(t, oldUser1NotificationCount, notificationCount) + + user2csrf = GetCSRF(t, user2Session, "/") + notificationCount = getUserNotificationCount(t, user2Session, user2csrf) + assert.Equal(t, oldUser2NotificationCount, notificationCount) + }) +} + func TestPullView_ResolveInvalidatedReviewComment(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") @@ -474,6 +544,28 @@ func TestPullView_GivenApproveOrRejectReviewOnClosedPR(t *testing.T) { }) } +func testNofiticationCount(t *testing.T, session *TestSession, csrf string, expectedSubmitStatus int) *httptest.ResponseRecorder { + options := map[string]string{ + "_csrf": csrf, + } + + req := NewRequestWithValues(t, "GET", "/", options) + return session.MakeRequest(t, req, expectedSubmitStatus) +} + +func testAssignReviewer(t *testing.T, session *TestSession, csrf, owner, repo, pullID, reviewer string, expectedSubmitStatus int) *httptest.ResponseRecorder { + options := map[string]string{ + "_csrf": csrf, + "action": "attach", + "issue_ids": pullID, + "id": reviewer, + } + + submitURL := path.Join(owner, repo, "issues", "request_review") + req := NewRequestWithValues(t, "POST", submitURL, options) + return session.MakeRequest(t, req, expectedSubmitStatus) +} + func testSubmitReview(t *testing.T, session *TestSession, csrf, owner, repo, pullNumber, commitID, reviewType string, expectedSubmitStatus int) *httptest.ResponseRecorder { options := map[string]string{ "_csrf": csrf, @@ -502,3 +594,9 @@ func testIssueClose(t *testing.T, session *TestSession, owner, repo, issueNumber req = NewRequestWithValues(t, "POST", closeURL, options) return session.MakeRequest(t, req, http.StatusOK) } + +func getUserNotificationCount(t *testing.T, session *TestSession, csrf string) string { + resp := testNofiticationCount(t, session, csrf, http.StatusOK) + doc := NewHTMLParser(t, resp.Body) + return doc.Find(`.notification_count`).Text() +} From cd2c1361c56d9bba0527ea3308015aa301b9ca4a Mon Sep 17 00:00:00 2001 From: emilylange Date: Sat, 21 Dec 2024 16:03:52 +0100 Subject: [PATCH 03/35] fix: keep commit count limit in file history pagination static and not increase with every page This fixes a regression introduced by 58a4407acb04b329e94e92977b1414feb309d5de from 2022 which reintroduced passing `--skip` to `git rev-list` in favor of the custom skipping reader based on `io.CopyN` from 59d1cc49f1d7c63d25e2a139befc8c02b830ba09 and then forgetting to also revert the `--max-count=CommitsRangeSize*Page` math. Before this commit: ~~~bash # curl -s "http://localhost:3000/api/v1/repos/forgejo/forgejo/commits?path=templates&page=1" | jq length 50 # curl -s "http://localhost:3000/api/v1/repos/forgejo/forgejo/commits?path=templates&page=2" | jq length 100 # curl -s "http://localhost:3000/api/v1/repos/forgejo/forgejo/commits?path=templates&page=10" | jq length 500 ~~~ With this commit applied: ~~~bash # curl -s "http://localhost:3000/api/v1/repos/forgejo/forgejo/commits?path=templates&page=1" | jq length 50 # curl -s "http://localhost:3000/api/v1/repos/forgejo/forgejo/commits?path=templates&page=2" | jq length 50 # curl -s "http://localhost:3000/api/v1/repos/forgejo/forgejo/commits?path=templates&page=10" | jq length 50 ~~~ --- modules/git/repo_commit.go | 2 +- modules/git/repo_commit_test.go | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index a2bfa43c09..e8c24eaa07 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -230,7 +230,7 @@ func (repo *Repository) CommitsByFileAndRange(opts CommitsByFileAndRangeOptions) go func() { stderr := strings.Builder{} gitCmd := NewCommand(repo.Ctx, "rev-list"). - AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize*opts.Page). + AddOptionFormat("--max-count=%d", setting.Git.CommitsRangeSize). AddOptionFormat("--skip=%d", skip) gitCmd.AddDynamicArguments(opts.Revision) diff --git a/modules/git/repo_commit_test.go b/modules/git/repo_commit_test.go index 6a8874fd74..f9f7d0edc7 100644 --- a/modules/git/repo_commit_test.go +++ b/modules/git/repo_commit_test.go @@ -7,6 +7,9 @@ import ( "path/filepath" "testing" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -138,3 +141,61 @@ func TestGetTagCommit(t *testing.T) { require.NoError(t, err) assert.EqualValues(t, lTagCommitID, lTag.ID.String()) } + +func TestCommitsByRange(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + bareRepo1, err := openRepositoryWithDefaultContext(bareRepo1Path) + require.NoError(t, err) + defer bareRepo1.Close() + + baseCommit, err := bareRepo1.GetBranchCommit("master") + require.NoError(t, err) + + testCases := []struct { + Page int + ExpectedCommitCount int + }{ + {1, 3}, + {2, 3}, + {3, 1}, + {4, 0}, + } + for _, testCase := range testCases { + commits, err := baseCommit.CommitsByRange(testCase.Page, 3, "") + require.NoError(t, err) + assert.Len(t, commits, testCase.ExpectedCommitCount, "page: %d", testCase.Page) + } +} + +func TestCommitsByFileAndRange(t *testing.T) { + bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") + bareRepo1, err := openRepositoryWithDefaultContext(bareRepo1Path) + require.NoError(t, err) + defer bareRepo1.Close() + defer test.MockVariableValue(&setting.Git.CommitsRangeSize, 2)() + + testCases := []struct { + File string + Page int + ExpectedCommitCount int + }{ + {"file1.txt", 1, 1}, + {"file2.txt", 1, 1}, + {"file*.txt", 1, 2}, + {"foo", 1, 2}, + {"foo", 2, 1}, + {"foo", 3, 0}, + {"f*", 1, 2}, + {"f*", 2, 2}, + {"f*", 3, 1}, + } + for _, testCase := range testCases { + commits, err := bareRepo1.CommitsByFileAndRange(CommitsByFileAndRangeOptions{ + Revision: "master", + File: testCase.File, + Page: testCase.Page, + }) + require.NoError(t, err) + assert.Len(t, commits, testCase.ExpectedCommitCount, "file: '%s', page: %d", testCase.File, testCase.Page) + } +} From 967e04534e815b2e1166f928fefce63cb3d2ee9c Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 15 Dec 2024 13:38:39 -0800 Subject: [PATCH 04/35] Fix bug on action list deleted branch (#32848) Fix https://github.com/go-gitea/gitea/issues/32761#issuecomment-2540946064 --------- Co-authored-by: wxiaoguang (cherry picked from commit 42090844ed2de5e615abc6ece351c152d3344295) Conflicts: models/fixtures/action_run.yml models/fixtures/branch.yml routers/web/repo/actions/actions_test.go trivial context conflict --- models/fixtures/action_run.yml | 19 ++++++++++++++ models/fixtures/branch.yml | 12 +++++++++ routers/web/repo/actions/actions.go | 9 ++++--- routers/web/repo/actions/actions_test.go | 33 ++++++++++++++++++++++++ routers/web/repo/actions/main_test.go | 14 ++++++++++ 5 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 routers/web/repo/actions/actions_test.go create mode 100644 routers/web/repo/actions/main_test.go diff --git a/models/fixtures/action_run.yml b/models/fixtures/action_run.yml index 2fe9094d13..7a7bf34197 100644 --- a/models/fixtures/action_run.yml +++ b/models/fixtures/action_run.yml @@ -432,6 +432,25 @@ updated: 1683636626 need_approval: 0 approved_by: 0 +- + id: 794 + title: "job output" + repo_id: 4 + owner_id: 1 + workflow_id: "test.yaml" + index: 190 + trigger_user_id: 1 + ref: "refs/heads/test" + commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0" + event: "push" + is_fork_pull_request: 0 + status: 1 + started: 1683636528 + stopped: 1683636626 + created: 1683636108 + updated: 1683636626 + need_approval: 0 + approved_by: 0 - id: 891 title: "update actions" diff --git a/models/fixtures/branch.yml b/models/fixtures/branch.yml index 93003049c6..b75d3706cc 100644 --- a/models/fixtures/branch.yml +++ b/models/fixtures/branch.yml @@ -45,3 +45,15 @@ is_deleted: false deleted_by_id: 0 deleted_unix: 0 + +- + id: 15 + repo_id: 4 + name: 'master' + commit_id: 'c7cd3cd144e6d23c9d6f3d07e52b2c1a956e0338' + commit_message: 'add Readme' + commit_time: 1588147171 + pusher_id: 13 + is_deleted: false + deleted_by_id: 0 + deleted_unix: 0 diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index 283d476df1..e5134c1f62 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -5,6 +5,7 @@ package actions import ( "bytes" + stdCtx "context" "fmt" "net/http" "slices" @@ -224,7 +225,7 @@ func List(ctx *context.Context) { return } - if err := loadIsRefDeleted(ctx, runs); err != nil { + if err := loadIsRefDeleted(ctx, ctx.Repo.Repository.ID, runs); err != nil { log.Error("LoadIsRefDeleted", err) } @@ -254,7 +255,7 @@ func List(ctx *context.Context) { // loadIsRefDeleted loads the IsRefDeleted field for each run in the list. // TODO: move this function to models/actions/run_list.go but now it will result in a circular import. -func loadIsRefDeleted(ctx *context.Context, runs actions_model.RunList) error { +func loadIsRefDeleted(ctx stdCtx.Context, repoID int64, runs actions_model.RunList) error { branches := make(container.Set[string], len(runs)) for _, run := range runs { refName := git.RefName(run.Ref) @@ -266,14 +267,14 @@ func loadIsRefDeleted(ctx *context.Context, runs actions_model.RunList) error { return nil } - branchInfos, err := git_model.GetBranches(ctx, ctx.Repo.Repository.ID, branches.Values(), false) + branchInfos, err := git_model.GetBranches(ctx, repoID, branches.Values(), false) if err != nil { return err } branchSet := git_model.BranchesToNamesSet(branchInfos) for _, run := range runs { refName := git.RefName(run.Ref) - if refName.IsBranch() && !branchSet.Contains(run.Ref) { + if refName.IsBranch() && !branchSet.Contains(refName.ShortName()) { run.IsRefDeleted = true } } diff --git a/routers/web/repo/actions/actions_test.go b/routers/web/repo/actions/actions_test.go new file mode 100644 index 0000000000..939c4aaf57 --- /dev/null +++ b/routers/web/repo/actions/actions_test.go @@ -0,0 +1,33 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + actions_model "code.gitea.io/gitea/models/actions" + "code.gitea.io/gitea/models/db" + unittest "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_loadIsRefDeleted(t *testing.T) { + unittest.PrepareTestEnv(t) + + runs, total, err := db.FindAndCount[actions_model.ActionRun](db.DefaultContext, + actions_model.FindRunOptions{RepoID: 4, Ref: "refs/heads/test"}) + require.NoError(t, err) + assert.Len(t, runs, 1) + assert.EqualValues(t, 1, total) + for _, run := range runs { + assert.False(t, run.IsRefDeleted) + } + + require.NoError(t, loadIsRefDeleted(db.DefaultContext, 4, runs)) + for _, run := range runs { + assert.True(t, run.IsRefDeleted) + } +} diff --git a/routers/web/repo/actions/main_test.go b/routers/web/repo/actions/main_test.go new file mode 100644 index 0000000000..a82f9c6672 --- /dev/null +++ b/routers/web/repo/actions/main_test.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m) +} From 5c1983644e3d81140521793d65016468734f3570 Mon Sep 17 00:00:00 2001 From: hiifong Date: Mon, 16 Dec 2024 10:22:49 +0800 Subject: [PATCH 05/35] Do not display `attestation-manifest` and use short sha256 instead of full sha256 (#32851) Related: #24973 Before: ![image](https://github.com/user-attachments/assets/bca17900-5075-4d15-af7a-c71bf8979c04) After: ![image](https://github.com/user-attachments/assets/c5a24e3b-763b-4463-80db-d4dbd89f7dc4) Index: ```json { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": [ { "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:5967afffdfde104ca1459286a72346baaef8b70ac153325d7a6cd85c7734ac6e", "size": 672, "platform": { "architecture": "amd64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:f9abfcc55320f9ff1f38eeb7dbb4bea10b29c7febfa49ccd7aab9fa02403b9f0", "size": 672, "platform": { "architecture": "arm64", "os": "linux" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:d70ad19d00c19e40691045cbddc3e8a5a4454c31cc454d1132b13bcaf35b6d46", "size": 566, "annotations": { "vnd.docker.reference.digest": "sha256:5967afffdfde104ca1459286a72346baaef8b70ac153325d7a6cd85c7734ac6e", "vnd.docker.reference.type": "attestation-manifest" }, "platform": { "architecture": "unknown", "os": "unknown" } }, { "mediaType": "application/vnd.oci.image.manifest.v1+json", "digest": "sha256:73bc233bf4eac96a404ce3e0430b698831a4ea7050c878d5f76d1d1f133751dd", "size": 566, "annotations": { "vnd.docker.reference.digest": "sha256:f9abfcc55320f9ff1f38eeb7dbb4bea10b29c7febfa49ccd7aab9fa02403b9f0", "vnd.docker.reference.type": "attestation-manifest" }, "platform": { "architecture": "unknown", "os": "unknown" } } ] } ``` --------- Co-authored-by: silverwind (cherry picked from commit 276f43330cb86e2ce6bc5a902a43f02727e009e9) Conflicts: templates/package/content/container.tmpl simplify to only skip unknown/unknown and not change the display --- templates/package/content/container.tmpl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/templates/package/content/container.tmpl b/templates/package/content/container.tmpl index 78fdac3bad..dd1c24269b 100644 --- a/templates/package/content/container.tmpl +++ b/templates/package/content/container.tmpl @@ -36,11 +36,13 @@ {{range .PackageDescriptor.Metadata.Manifests}} - + {{if ne .Platform "unknown/unknown"}} + {{.Digest}} {{.Platform}} {{ctx.Locale.TrSize .Size}} - + + {{end}} {{end}} From 90b65da7e48d2aa548092a7e3149f65ba39f1b02 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 16 Dec 2024 11:18:00 +0800 Subject: [PATCH 06/35] Fix incomplete Actions status aggregations (#32859) fix #32857 (cherry picked from commit d28a4843b8de5d5e01ef3d7b2ad25f22853247ad) Conflicts: web_src/js/components/ActionRunStatus.vue remove the refactoring, keep the additional cancelled status --- models/actions/run_job.go | 43 ++++++++------- models/actions/run_job_status_test.go | 64 +++++++++++++++++++++++ templates/repo/actions/status.tmpl | 4 +- web_src/js/components/ActionRunStatus.vue | 5 +- web_src/js/components/RepoActionView.vue | 4 +- web_src/js/svg.js | 2 + 6 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 models/actions/run_job_status_test.go diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 2319af8e08..8c131351d5 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -153,28 +153,33 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col } func AggregateJobStatus(jobs []*ActionRunJob) Status { - allDone := true - allWaiting := true - hasFailure := false + allSuccessOrSkipped := true + var hasFailure, hasCancelled, hasSkipped, hasWaiting, hasRunning, hasBlocked bool for _, job := range jobs { - if !job.Status.IsDone() { - allDone = false - } - if job.Status != StatusWaiting && !job.Status.IsDone() { - allWaiting = false - } - if job.Status == StatusFailure || job.Status == StatusCancelled { - hasFailure = true - } + allSuccessOrSkipped = allSuccessOrSkipped && (job.Status == StatusSuccess || job.Status == StatusSkipped) + hasFailure = hasFailure || job.Status == StatusFailure + hasCancelled = hasCancelled || job.Status == StatusCancelled + hasSkipped = hasSkipped || job.Status == StatusSkipped + hasWaiting = hasWaiting || job.Status == StatusWaiting + hasRunning = hasRunning || job.Status == StatusRunning + hasBlocked = hasBlocked || job.Status == StatusBlocked } - if allDone { - if hasFailure { - return StatusFailure - } + switch { + case allSuccessOrSkipped: return StatusSuccess - } - if allWaiting { + case hasFailure: + return StatusFailure + case hasRunning: + return StatusRunning + case hasWaiting: return StatusWaiting + case hasBlocked: + return StatusBlocked + case hasCancelled: + return StatusCancelled + case hasSkipped: + return StatusSkipped + default: + return StatusUnknown // it shouldn't happen } - return StatusRunning } diff --git a/models/actions/run_job_status_test.go b/models/actions/run_job_status_test.go new file mode 100644 index 0000000000..bac480a96b --- /dev/null +++ b/models/actions/run_job_status_test.go @@ -0,0 +1,64 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package actions + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAggregateJobStatus(t *testing.T) { + testStatuses := func(expected Status, statuses []Status) { + var jobs []*ActionRunJob + for _, v := range statuses { + jobs = append(jobs, &ActionRunJob{Status: v}) + } + actual := AggregateJobStatus(jobs) + if !assert.Equal(t, expected, actual) { + var statusStrings []string + for _, s := range statuses { + statusStrings = append(statusStrings, s.String()) + } + t.Errorf("AggregateJobStatus(%v) = %v, want %v", statusStrings, statusNames[actual], statusNames[expected]) + } + } + + cases := []struct { + statuses []Status + expected Status + }{ + // success with other status + {[]Status{StatusSuccess}, StatusSuccess}, + {[]Status{StatusSuccess, StatusSkipped}, StatusSuccess}, // skipped doesn't affect success + {[]Status{StatusSuccess, StatusFailure}, StatusFailure}, + {[]Status{StatusSuccess, StatusCancelled}, StatusCancelled}, + {[]Status{StatusSuccess, StatusWaiting}, StatusWaiting}, + {[]Status{StatusSuccess, StatusRunning}, StatusRunning}, + {[]Status{StatusSuccess, StatusBlocked}, StatusBlocked}, + + // failure with other status, fail fast + // Should "running" win? Maybe no: old code does make "running" win, but GitHub does fail fast. + {[]Status{StatusFailure}, StatusFailure}, + {[]Status{StatusFailure, StatusSuccess}, StatusFailure}, + {[]Status{StatusFailure, StatusSkipped}, StatusFailure}, + {[]Status{StatusFailure, StatusCancelled}, StatusFailure}, + {[]Status{StatusFailure, StatusWaiting}, StatusFailure}, + {[]Status{StatusFailure, StatusRunning}, StatusFailure}, + {[]Status{StatusFailure, StatusBlocked}, StatusFailure}, + + // skipped with other status + {[]Status{StatusSkipped}, StatusSuccess}, + {[]Status{StatusSkipped, StatusSuccess}, StatusSuccess}, + {[]Status{StatusSkipped, StatusFailure}, StatusFailure}, + {[]Status{StatusSkipped, StatusCancelled}, StatusCancelled}, + {[]Status{StatusSkipped, StatusWaiting}, StatusWaiting}, + {[]Status{StatusSkipped, StatusRunning}, StatusRunning}, + {[]Status{StatusSkipped, StatusBlocked}, StatusBlocked}, + } + + for _, c := range cases { + testStatuses(c.expected, c.statuses) + } +} diff --git a/templates/repo/actions/status.tmpl b/templates/repo/actions/status.tmpl index a0e02cf8d7..99fa74ac17 100644 --- a/templates/repo/actions/status.tmpl +++ b/templates/repo/actions/status.tmpl @@ -17,13 +17,15 @@ {{svg "octicon-check-circle-fill" $size (printf "text green %s" $className)}} {{else if eq .status "skipped"}} {{svg "octicon-skip" $size (printf "text grey %s" $className)}} +{{else if eq .status "cancelled"}} + {{svg "octicon-stop" $size (printf "text grey %s" $className)}} {{else if eq .status "waiting"}} {{svg "octicon-clock" $size (printf "text yellow %s" $className)}} {{else if eq .status "blocked"}} {{svg "octicon-blocked" $size (printf "text yellow %s" $className)}} {{else if eq .status "running"}} {{svg "octicon-meter" $size (printf "text yellow job-status-rotate %s" $className)}} -{{else if or (eq .status "failure") or (eq .status "cancelled") or (eq .status "unknown")}} +{{else}}{{/*failure, unknown*/}} {{svg "octicon-x-circle-fill" $size (printf "text red %s" $className)}} {{end}} diff --git a/web_src/js/components/ActionRunStatus.vue b/web_src/js/components/ActionRunStatus.vue index 7ada543fea..eb7f780fbe 100644 --- a/web_src/js/components/ActionRunStatus.vue +++ b/web_src/js/components/ActionRunStatus.vue @@ -28,12 +28,13 @@ export default { }; diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index 13ac9427f3..136ad3693d 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -570,11 +570,13 @@ export function initRepositoryActionView() { .action-info-summary-title { display: flex; + align-items: center; + gap: 0.5em; } .action-info-summary-title-text { font-size: 20px; - margin: 0 0 0 8px; + margin: 0; flex: 1; overflow-wrap: anywhere; } diff --git a/web_src/js/svg.js b/web_src/js/svg.js index 9ef5f28e2f..76df7ff211 100644 --- a/web_src/js/svg.js +++ b/web_src/js/svg.js @@ -64,6 +64,7 @@ import octiconSidebarCollapse from '../../public/assets/img/svg/octicon-sidebar- import octiconSidebarExpand from '../../public/assets/img/svg/octicon-sidebar-expand.svg'; import octiconSkip from '../../public/assets/img/svg/octicon-skip.svg'; import octiconStar from '../../public/assets/img/svg/octicon-star.svg'; +import octiconStop from '../../public/assets/img/svg/octicon-stop.svg'; import octiconStrikethrough from '../../public/assets/img/svg/octicon-strikethrough.svg'; import octiconSync from '../../public/assets/img/svg/octicon-sync.svg'; import octiconTable from '../../public/assets/img/svg/octicon-table.svg'; @@ -138,6 +139,7 @@ const svgs = { 'octicon-sidebar-expand': octiconSidebarExpand, 'octicon-skip': octiconSkip, 'octicon-star': octiconStar, + 'octicon-stop': octiconStop, 'octicon-strikethrough': octiconStrikethrough, 'octicon-sync': octiconSync, 'octicon-table': octiconTable, From 1e7b2cb6c95701afd18a791fa879e5a3e45dcff5 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 16 Dec 2024 21:49:53 +0800 Subject: [PATCH 07/35] Improve Actions status aggregations (#32860) Make the result the same as GitHub: * all skipped, then result is skipped * any cancelled, then result cancelled (cherry picked from commit 22c4599542ee3e10bcab4c9136467bbac8e90ba0) --- models/actions/run_job.go | 15 ++++++++------- models/actions/run_job_status_test.go | 25 +++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/models/actions/run_job.go b/models/actions/run_job.go index 8c131351d5..de4b6aab66 100644 --- a/models/actions/run_job.go +++ b/models/actions/run_job.go @@ -153,20 +153,25 @@ func UpdateRunJob(ctx context.Context, job *ActionRunJob, cond builder.Cond, col } func AggregateJobStatus(jobs []*ActionRunJob) Status { - allSuccessOrSkipped := true - var hasFailure, hasCancelled, hasSkipped, hasWaiting, hasRunning, hasBlocked bool + allSuccessOrSkipped := len(jobs) != 0 + allSkipped := len(jobs) != 0 + var hasFailure, hasCancelled, hasWaiting, hasRunning, hasBlocked bool for _, job := range jobs { allSuccessOrSkipped = allSuccessOrSkipped && (job.Status == StatusSuccess || job.Status == StatusSkipped) + allSkipped = allSkipped && job.Status == StatusSkipped hasFailure = hasFailure || job.Status == StatusFailure hasCancelled = hasCancelled || job.Status == StatusCancelled - hasSkipped = hasSkipped || job.Status == StatusSkipped hasWaiting = hasWaiting || job.Status == StatusWaiting hasRunning = hasRunning || job.Status == StatusRunning hasBlocked = hasBlocked || job.Status == StatusBlocked } switch { + case allSkipped: + return StatusSkipped case allSuccessOrSkipped: return StatusSuccess + case hasCancelled: + return StatusCancelled case hasFailure: return StatusFailure case hasRunning: @@ -175,10 +180,6 @@ func AggregateJobStatus(jobs []*ActionRunJob) Status { return StatusWaiting case hasBlocked: return StatusBlocked - case hasCancelled: - return StatusCancelled - case hasSkipped: - return StatusSkipped default: return StatusUnknown // it shouldn't happen } diff --git a/models/actions/run_job_status_test.go b/models/actions/run_job_status_test.go index bac480a96b..04fd9ceba7 100644 --- a/models/actions/run_job_status_test.go +++ b/models/actions/run_job_status_test.go @@ -11,6 +11,7 @@ import ( func TestAggregateJobStatus(t *testing.T) { testStatuses := func(expected Status, statuses []Status) { + t.Helper() var jobs []*ActionRunJob for _, v := range statuses { jobs = append(jobs, &ActionRunJob{Status: v}) @@ -29,6 +30,16 @@ func TestAggregateJobStatus(t *testing.T) { statuses []Status expected Status }{ + // unknown cases, maybe it shouldn't happen in real world + {[]Status{}, StatusUnknown}, + {[]Status{StatusUnknown, StatusSuccess}, StatusUnknown}, + {[]Status{StatusUnknown, StatusSkipped}, StatusUnknown}, + {[]Status{StatusUnknown, StatusFailure}, StatusFailure}, + {[]Status{StatusUnknown, StatusCancelled}, StatusCancelled}, + {[]Status{StatusUnknown, StatusWaiting}, StatusWaiting}, + {[]Status{StatusUnknown, StatusRunning}, StatusRunning}, + {[]Status{StatusUnknown, StatusBlocked}, StatusBlocked}, + // success with other status {[]Status{StatusSuccess}, StatusSuccess}, {[]Status{StatusSuccess, StatusSkipped}, StatusSuccess}, // skipped doesn't affect success @@ -38,18 +49,28 @@ func TestAggregateJobStatus(t *testing.T) { {[]Status{StatusSuccess, StatusRunning}, StatusRunning}, {[]Status{StatusSuccess, StatusBlocked}, StatusBlocked}, + // any cancelled, then cancelled + {[]Status{StatusCancelled}, StatusCancelled}, + {[]Status{StatusCancelled, StatusSuccess}, StatusCancelled}, + {[]Status{StatusCancelled, StatusSkipped}, StatusCancelled}, + {[]Status{StatusCancelled, StatusFailure}, StatusCancelled}, + {[]Status{StatusCancelled, StatusWaiting}, StatusCancelled}, + {[]Status{StatusCancelled, StatusRunning}, StatusCancelled}, + {[]Status{StatusCancelled, StatusBlocked}, StatusCancelled}, + // failure with other status, fail fast // Should "running" win? Maybe no: old code does make "running" win, but GitHub does fail fast. {[]Status{StatusFailure}, StatusFailure}, {[]Status{StatusFailure, StatusSuccess}, StatusFailure}, {[]Status{StatusFailure, StatusSkipped}, StatusFailure}, - {[]Status{StatusFailure, StatusCancelled}, StatusFailure}, + {[]Status{StatusFailure, StatusCancelled}, StatusCancelled}, {[]Status{StatusFailure, StatusWaiting}, StatusFailure}, {[]Status{StatusFailure, StatusRunning}, StatusFailure}, {[]Status{StatusFailure, StatusBlocked}, StatusFailure}, // skipped with other status - {[]Status{StatusSkipped}, StatusSuccess}, + // TODO: need to clarify whether a PR with "skipped" job status is considered as "mergeable" or not. + {[]Status{StatusSkipped}, StatusSkipped}, {[]Status{StatusSkipped, StatusSuccess}, StatusSuccess}, {[]Status{StatusSkipped, StatusFailure}, StatusFailure}, {[]Status{StatusSkipped, StatusCancelled}, StatusCancelled}, From a5399b473f7111c92b2645076d02a7f427e16f08 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 18 Dec 2024 22:10:08 -0800 Subject: [PATCH 08/35] Add more load functions to make sure the reference object loaded (#32901) Fix #32897 (cherry picked from commit dc8f59baa54d4f47edab6feb76a6903947584326) --- services/convert/pull.go | 5 +++++ services/webhook/notifier.go | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/services/convert/pull.go b/services/convert/pull.go index 4ec24a8276..70dc22445a 100644 --- a/services/convert/pull.go +++ b/services/convert/pull.go @@ -29,6 +29,11 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u err error ) + if err = pr.LoadIssue(ctx); err != nil { + log.Error("pr.LoadIssue[%d]: %v", pr.ID, err) + return nil + } + if err = pr.Issue.LoadRepo(ctx); err != nil { log.Error("pr.Issue.LoadRepo[%d]: %v", pr.ID, err) return nil diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index 8bfd03024f..fed33d8008 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -409,6 +409,10 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod var pullRequest *api.PullRequest if issue.IsPull { eventType = webhook_module.HookEventPullRequestComment + if err := issue.LoadPullRequest(ctx); err != nil { + log.Error("LoadPullRequest: %v", err) + return + } pullRequest = convert.ToAPIPullRequest(ctx, issue.PullRequest, doer) } else { eventType = webhook_module.HookEventIssueComment From fcb98c6d3c551de612331dcd54976339b14bbc85 Mon Sep 17 00:00:00 2001 From: Snoweuph Date: Sat, 21 Dec 2024 02:08:34 +0100 Subject: [PATCH 09/35] fix: template config path (#2836) --- services/repository/generate.go | 30 ++++++---- tests/integration/repo_generate_test.go | 80 +++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 16 deletions(-) diff --git a/services/repository/generate.go b/services/repository/generate.go index 8bd14ace8d..4a312a33c3 100644 --- a/services/repository/generate.go +++ b/services/repository/generate.go @@ -126,24 +126,32 @@ func (gt *GiteaTemplate) Globs() []glob.Glob { } func checkGiteaTemplate(tmpDir string) (*GiteaTemplate, error) { - gtPath := filepath.Join(tmpDir, ".gitea", "template") - if _, err := os.Stat(gtPath); os.IsNotExist(err) { - return nil, nil - } else if err != nil { - return nil, err + configDirs := []string{".forgejo", ".gitea"} + var templateFilePath string + + for _, dir := range configDirs { + candidatePath := filepath.Join(tmpDir, dir, "template") + if _, err := os.Stat(candidatePath); err == nil { + templateFilePath = candidatePath + break + } else if !os.IsNotExist(err) { + return nil, err + } } - content, err := os.ReadFile(gtPath) + if templateFilePath == "" { + return nil, nil + } + + content, err := os.ReadFile(templateFilePath) if err != nil { return nil, err } - gt := &GiteaTemplate{ - Path: gtPath, + return &GiteaTemplate{ + Path: templateFilePath, Content: content, - } - - return gt, nil + }, nil } func generateRepoCommit(ctx context.Context, repo, templateRepo, generateRepo *repo_model.Repository, tmpDir string) error { diff --git a/tests/integration/repo_generate_test.go b/tests/integration/repo_generate_test.go index 0b2870ad56..4bd9f32119 100644 --- a/tests/integration/repo_generate_test.go +++ b/tests/integration/repo_generate_test.go @@ -7,6 +7,7 @@ package integration import ( "fmt" "net/http" + "net/url" "strconv" "strings" "testing" @@ -14,9 +15,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation" + files_service "code.gitea.io/gitea/services/repository/files" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" @@ -76,10 +79,14 @@ func testRepoGenerate(t *testing.T, session *TestSession, templateID, templateOw // Step4: check the existence of the generated repo req = NewRequestf(t, "GET", "/%s/%s", generateOwner.Name, generateRepoName) session.MakeRequest(t, req, http.StatusOK) +} - // Step5: check substituted values in Readme - req = NewRequestf(t, "GET", "/%s/%s/raw/branch/master/README.md", generateOwner.Name, generateRepoName) - resp = session.MakeRequest(t, req, http.StatusOK) +func testRepoGenerateWithFixture(t *testing.T, session *TestSession, templateID, templateOwnerName, templateRepoName string, user, generateOwner *user_model.User, generateRepoName string) { + testRepoGenerate(t, session, templateID, templateOwnerName, templateRepoName, user, generateOwner, generateRepoName) + + // check substituted values in Readme + req := NewRequestf(t, "GET", "/%s/%s/raw/branch/master/README.md", generateOwner.Name, generateRepoName) + resp := session.MakeRequest(t, req, http.StatusOK) body := fmt.Sprintf(`# %s Readme Owner: %s Link: /%s/%s @@ -125,7 +132,7 @@ func TestRepoGenerate(t *testing.T) { session := loginUser(t, userName) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) - testRepoGenerate(t, session, "44", "user27", "template1", user, user, "generated1") + testRepoGenerateWithFixture(t, session, "44", "user27", "template1", user, user, "generated1") } func TestRepoGenerateToOrg(t *testing.T) { @@ -135,7 +142,7 @@ func TestRepoGenerateToOrg(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) org := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "org3"}) - testRepoGenerate(t, session, "44", "user27", "template1", user, org, "generated2") + testRepoGenerateWithFixture(t, session, "44", "user27", "template1", user, org, "generated2") } func TestRepoCreateFormTrimSpace(t *testing.T) { @@ -153,3 +160,66 @@ func TestRepoCreateFormTrimSpace(t *testing.T) { assert.EqualValues(t, "/user2/spaced-name", test.RedirectURL(resp)) unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: 2, Name: "spaced-name"}) } + +func TestRepoGenerateTemplating(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + input := `# $REPO_NAME + This is a Repo By $REPO_OWNER + ThisIsThe${REPO_NAME}InAnInlineWay` + expected := `# %s + This is a Repo By %s + ThisIsThe%sInAnInlineWay` + templateName := "my_template" + generatedName := "my_generated" + + userName := "user1" + session := loginUser(t, userName) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) + + template, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ + Name: optional.Some(templateName), + IsTemplate: optional.Some(true), + Files: optional.Some([]*files_service.ChangeRepoFile{ + { + Operation: "create", + TreePath: ".forgejo/template", + ContentReader: strings.NewReader("Readme.md"), + }, + { + Operation: "create", + TreePath: "Readme.md", + ContentReader: strings.NewReader(input), + }, + }), + }) + defer f() + + // The repo.TemplateID field is not initalized. Luckly the ID field holds the expected value + templateID := strconv.FormatInt(template.ID, 10) + + testRepoGenerate( + t, + session, + templateID, + user.Name, + templateName, + user, + user, + generatedName, + ) + + req := NewRequestf( + t, + "GET", "/%s/%s/raw/branch/%s/Readme.md", + user.Name, + generatedName, + template.DefaultBranch, + ) + resp := session.MakeRequest(t, req, http.StatusOK) + body := fmt.Sprintf(expected, + generatedName, + user.Name, + generatedName) + assert.Equal(t, body, resp.Body.String()) + }) +} From ee214cb886b81acb7c9cb277809d19aae42f3c7f Mon Sep 17 00:00:00 2001 From: Shiny Nematoda Date: Sun, 22 Dec 2024 12:24:29 +0000 Subject: [PATCH 10/35] feat: filepath filter for code search (#6143) Added support for searching content in a specific directory or file. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6143 Reviewed-by: Gusted Reviewed-by: 0ko <0ko@noreply.codeberg.org> Co-authored-by: Shiny Nematoda Co-committed-by: Shiny Nematoda --- modules/git/grep.go | 42 +++++++++-- modules/git/grep_test.go | 14 ++++ modules/indexer/code/bleve/bleve.go | 42 ++++++++--- .../bleve/tokenizer/hierarchy/hierarchy.go | 69 +++++++++++++++++++ .../tokenizer/hierarchy/hierarchy_test.go | 59 ++++++++++++++++ .../code/elasticsearch/elasticsearch.go | 35 ++++++++-- modules/indexer/code/indexer_test.go | 24 +++++-- modules/indexer/code/internal/indexer.go | 1 + modules/indexer/code/internal/util.go | 24 +------ modules/indexer/code/search.go | 2 + routers/web/explore/code.go | 2 + routers/web/repo/search.go | 12 +++- routers/web/repo/view.go | 7 ++ routers/web/user/code.go | 2 + templates/repo/home.tmpl | 22 ++++-- templates/shared/search/code/results.tmpl | 4 +- templates/shared/search/code/search.tmpl | 18 +++++ tests/integration/repo_test.go | 19 ++++- web_src/css/repo.css | 5 ++ 19 files changed, 342 insertions(+), 61 deletions(-) create mode 100644 modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy.go create mode 100644 modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy_test.go diff --git a/modules/git/grep.go b/modules/git/grep.go index 1daa3e8fb9..c3d4de49bd 100644 --- a/modules/git/grep.go +++ b/modules/git/grep.go @@ -36,13 +36,15 @@ const ( RegExpGrepMode ) +var GrepSearchOptions = [3]string{"exact", "union", "regexp"} + type GrepOptions struct { RefName string MaxResultLimit int MatchesPerFile int // >= git 2.38 ContextLineNumber int Mode grepMode - PathSpec []setting.Glob + Filename string } func (opts *GrepOptions) ensureDefaults() { @@ -112,12 +114,38 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO } // pathspec - files := make([]string, 0, - len(setting.Indexer.IncludePatterns)+ - len(setting.Indexer.ExcludePatterns)+ - len(opts.PathSpec)) - for _, expr := range append(setting.Indexer.IncludePatterns, opts.PathSpec...) { - files = append(files, ":"+expr.Pattern()) + includeLen := len(setting.Indexer.IncludePatterns) + if len(opts.Filename) > 0 { + includeLen = 1 + } + files := make([]string, 0, len(setting.Indexer.ExcludePatterns)+includeLen) + if len(opts.Filename) > 0 && len(setting.Indexer.IncludePatterns) > 0 { + // if the both a global include pattern and the per search path is defined + // we only include results where the path matches the globally set pattern + // (eg, global pattern = "src/**" and path = "node_modules/") + + // FIXME: this is a bit too restrictive, and fails to consider cases where the + // gloabally set include pattern refers to a file than a directory + // (eg, global pattern = "**.go" and path = "modules/git") + exprMatched := false + for _, expr := range setting.Indexer.IncludePatterns { + if expr.Match(opts.Filename) { + files = append(files, ":(literal)"+opts.Filename) + exprMatched = true + break + } + } + if !exprMatched { + log.Warn("git-grep: filepath %s does not match any include pattern", opts.Filename) + } + } else if len(opts.Filename) > 0 { + // if the path is only set we just include results that matches it + files = append(files, ":(literal)"+opts.Filename) + } else { + // otherwise if global include patterns are set include results that strictly match them + for _, expr := range setting.Indexer.IncludePatterns { + files = append(files, ":"+expr.Pattern()) + } } for _, expr := range setting.Indexer.ExcludePatterns { files = append(files, ":^"+expr.Pattern()) diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go index 835f441b19..c40b33664a 100644 --- a/modules/git/grep_test.go +++ b/modules/git/grep_test.go @@ -89,6 +89,20 @@ func TestGrepSearch(t *testing.T) { }, }, res) + res, err = GrepSearch(context.Background(), repo, "world", GrepOptions{ + MatchesPerFile: 1, + Filename: "java-hello/", + }) + require.NoError(t, err) + assert.Equal(t, []*GrepResult{ + { + Filename: "java-hello/main.java", + LineNumbers: []int{1}, + LineCodes: []string{"public class HelloWorld"}, + HighlightedRanges: [][3]int{{0, 18, 23}}, + }, + }, res) + res, err = GrepSearch(context.Background(), repo, "no-such-content", GrepOptions{}) require.NoError(t, err) assert.Empty(t, res) diff --git a/modules/indexer/code/bleve/bleve.go b/modules/indexer/code/bleve/bleve.go index ad854094e5..9dc915499b 100644 --- a/modules/indexer/code/bleve/bleve.go +++ b/modules/indexer/code/bleve/bleve.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" + tokenizer_hierarchy "code.gitea.io/gitea/modules/indexer/code/bleve/tokenizer/hierarchy" "code.gitea.io/gitea/modules/indexer/code/internal" indexer_internal "code.gitea.io/gitea/modules/indexer/internal" inner_bleve "code.gitea.io/gitea/modules/indexer/internal/bleve" @@ -56,6 +57,7 @@ func addUnicodeNormalizeTokenFilter(m *mapping.IndexMappingImpl) error { type RepoIndexerData struct { RepoID int64 CommitID string + Filename string Content string Language string UpdatedAt time.Time @@ -69,7 +71,8 @@ func (d *RepoIndexerData) Type() string { const ( repoIndexerAnalyzer = "repoIndexerAnalyzer" repoIndexerDocType = "repoIndexerDocType" - repoIndexerLatestVersion = 6 + pathHierarchyAnalyzer = "pathHierarchyAnalyzer" + repoIndexerLatestVersion = 7 ) // generateBleveIndexMapping generates a bleve index mapping for the repo indexer @@ -89,6 +92,11 @@ func generateBleveIndexMapping() (mapping.IndexMapping, error) { docMapping.AddFieldMappingsAt("Language", termFieldMapping) docMapping.AddFieldMappingsAt("CommitID", termFieldMapping) + pathFieldMapping := bleve.NewTextFieldMapping() + pathFieldMapping.IncludeInAll = false + pathFieldMapping.Analyzer = pathHierarchyAnalyzer + docMapping.AddFieldMappingsAt("Filename", pathFieldMapping) + timeFieldMapping := bleve.NewDateTimeFieldMapping() timeFieldMapping.IncludeInAll = false docMapping.AddFieldMappingsAt("UpdatedAt", timeFieldMapping) @@ -103,6 +111,13 @@ func generateBleveIndexMapping() (mapping.IndexMapping, error) { "token_filters": []string{unicodeNormalizeName, camelcase.Name, lowercase.Name}, }); err != nil { return nil, err + } else if err := mapping.AddCustomAnalyzer(pathHierarchyAnalyzer, map[string]any{ + "type": analyzer_custom.Name, + "char_filters": []string{}, + "tokenizer": tokenizer_hierarchy.Name, + "token_filters": []string{unicodeNormalizeName}, + }); err != nil { + return nil, err } mapping.DefaultAnalyzer = repoIndexerAnalyzer mapping.AddDocumentMapping(repoIndexerDocType, docMapping) @@ -178,6 +193,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro return batch.Index(id, &RepoIndexerData{ RepoID: repo.ID, CommitID: commitSha, + Filename: update.Filename, Content: string(charset.ToUTF8DropErrors(fileContents, charset.ConvertOpts{})), Language: analyze.GetCodeLanguage(update.Filename, fileContents), UpdatedAt: time.Now().UTC(), @@ -266,22 +282,30 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int indexerQuery = keywordQuery } + opts.Filename = strings.Trim(opts.Filename, "/") + if len(opts.Filename) > 0 { + // we use a keyword analyzer for the query than path hierarchy analyzer + // to match only the exact path + // eg, a query for modules/indexer/code + // should not provide results for modules/ nor modules/indexer + indexerQuery = bleve.NewConjunctionQuery( + indexerQuery, + inner_bleve.MatchQuery(opts.Filename, "Filename", analyzer_keyword.Name, 0), + ) + } + // Save for reuse without language filter facetQuery := indexerQuery if len(opts.Language) > 0 { - languageQuery := bleve.NewMatchQuery(opts.Language) - languageQuery.FieldVal = "Language" - languageQuery.Analyzer = analyzer_keyword.Name - indexerQuery = bleve.NewConjunctionQuery( indexerQuery, - languageQuery, + inner_bleve.MatchQuery(opts.Language, "Language", analyzer_keyword.Name, 0), ) } from, pageSize := opts.GetSkipTake() searchRequest := bleve.NewSearchRequestOptions(indexerQuery, pageSize, from, false) - searchRequest.Fields = []string{"Content", "RepoID", "Language", "CommitID", "UpdatedAt"} + searchRequest.Fields = []string{"Content", "RepoID", "Filename", "Language", "CommitID", "UpdatedAt"} searchRequest.IncludeLocations = true if len(opts.Language) == 0 { @@ -320,7 +344,7 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int RepoID: int64(hit.Fields["RepoID"].(float64)), StartIndex: startIndex, EndIndex: endIndex, - Filename: internal.FilenameOfIndexerID(hit.ID), + Filename: hit.Fields["Filename"].(string), Content: hit.Fields["Content"].(string), CommitID: hit.Fields["CommitID"].(string), UpdatedUnix: updatedUnix, @@ -333,7 +357,7 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int if len(opts.Language) > 0 { // Use separate query to go get all language counts facetRequest := bleve.NewSearchRequestOptions(facetQuery, 1, 0, false) - facetRequest.Fields = []string{"Content", "RepoID", "Language", "CommitID", "UpdatedAt"} + facetRequest.Fields = []string{"Content", "RepoID", "Filename", "Language", "CommitID", "UpdatedAt"} facetRequest.IncludeLocations = true facetRequest.AddFacet("languages", bleve.NewFacetRequest("Language", 10)) diff --git a/modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy.go b/modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy.go new file mode 100644 index 0000000000..4cb6a9b038 --- /dev/null +++ b/modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy.go @@ -0,0 +1,69 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package hierarchy + +import ( + "bytes" + + "github.com/blevesearch/bleve/v2/analysis" + "github.com/blevesearch/bleve/v2/registry" +) + +const Name = "path_hierarchy" + +type PathHierarchyTokenizer struct{} + +// Similar to elastic's path_hierarchy tokenizer +// This tokenizes a given path into all the possible hierarchies +// For example, +// modules/indexer/code/search.go => +// +// modules/ +// modules/indexer +// modules/indexer/code +// modules/indexer/code/search.go +func (t *PathHierarchyTokenizer) Tokenize(input []byte) analysis.TokenStream { + // trim any extra slashes + input = bytes.Trim(input, "/") + + // zero allocations until the nested directories exceed a depth of 8 (which is unlikely) + rv := make(analysis.TokenStream, 0, 8) + count, off := 1, 0 + + // iterate till all directory seperators + for i := bytes.IndexRune(input[off:], '/'); i != -1; i = bytes.IndexRune(input[off:], '/') { + // the index is relative to input[offest...] + // add this index to the accumlated offset to get the index of the current seperator in input[0...] + off += i + rv = append(rv, &analysis.Token{ + Term: input[:off], // take the slice, input[0...index of seperator] + Start: 0, + End: off, + Position: count, + Type: analysis.AlphaNumeric, + }) + // increment the offset after considering the seperator + off++ + count++ + } + + // the entire file path should always be the last token + rv = append(rv, &analysis.Token{ + Term: input, + Start: 0, + End: len(input), + Position: count, + Type: analysis.AlphaNumeric, + }) + + return rv +} + +func TokenizerConstructor(config map[string]any, cache *registry.Cache) (analysis.Tokenizer, error) { + return &PathHierarchyTokenizer{}, nil +} + +func init() { + registry.RegisterTokenizer(Name, TokenizerConstructor) +} diff --git a/modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy_test.go b/modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy_test.go new file mode 100644 index 0000000000..0ca3c2941d --- /dev/null +++ b/modules/indexer/code/bleve/tokenizer/hierarchy/hierarchy_test.go @@ -0,0 +1,59 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package hierarchy + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestIndexerBleveHierarchyTokenizer(t *testing.T) { + tokenizer := &PathHierarchyTokenizer{} + keywords := []struct { + Term string + Results []string + }{ + { + Term: "modules/indexer/code/search.go", + Results: []string{ + "modules", + "modules/indexer", + "modules/indexer/code", + "modules/indexer/code/search.go", + }, + }, + { + Term: "/tmp/forgejo/", + Results: []string{ + "tmp", + "tmp/forgejo", + }, + }, + { + Term: "a/b/c/d/e/f/g/h/i/j", + Results: []string{ + "a", + "a/b", + "a/b/c", + "a/b/c/d", + "a/b/c/d/e", + "a/b/c/d/e/f", + "a/b/c/d/e/f/g", + "a/b/c/d/e/f/g/h", + "a/b/c/d/e/f/g/h/i", + "a/b/c/d/e/f/g/h/i/j", + }, + }, + } + + for _, kw := range keywords { + tokens := tokenizer.Tokenize([]byte(kw.Term)) + assert.Len(t, tokens, len(kw.Results)) + for i, token := range tokens { + assert.Equal(t, i+1, token.Position) + assert.Equal(t, kw.Results[i], string(token.Term)) + } + } +} diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go index 311c5fe735..ad58615b30 100644 --- a/modules/indexer/code/elasticsearch/elasticsearch.go +++ b/modules/indexer/code/elasticsearch/elasticsearch.go @@ -30,7 +30,7 @@ import ( ) const ( - esRepoIndexerLatestVersion = 1 + esRepoIndexerLatestVersion = 2 // multi-match-types, currently only 2 types are used // Reference: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/query-dsl-multi-match-query.html#multi-match-types esMultiMatchTypeBestFields = "best_fields" @@ -57,6 +57,21 @@ func NewIndexer(url, indexerName string) *Indexer { const ( defaultMapping = `{ + "settings": { + "analysis": { + "analyzer": { + "custom_path_tree": { + "tokenizer": "custom_hierarchy" + } + }, + "tokenizer": { + "custom_hierarchy": { + "type": "path_hierarchy", + "delimiter": "/" + } + } + } + }, "mappings": { "properties": { "repo_id": { @@ -72,6 +87,15 @@ const ( "type": "keyword", "index": true }, + "filename": { + "type": "text", + "fields": { + "tree": { + "type": "text", + "analyzer": "custom_path_tree" + } + } + }, "language": { "type": "keyword", "index": true @@ -138,6 +162,7 @@ func (b *Indexer) addUpdate(ctx context.Context, batchWriter git.WriteCloserErro "repo_id": repo.ID, "content": string(charset.ToUTF8DropErrors(fileContents, charset.ConvertOpts{})), "commit_id": sha, + "filename": update.Filename, "language": analyze.GetCodeLanguage(update.Filename, fileContents), "updated_at": timeutil.TimeStampNow(), }), @@ -267,7 +292,6 @@ func convertResult(searchResult *elastic.SearchResult, kw string, pageSize int) panic(fmt.Sprintf("2===%#v", hit.Highlight)) } - repoID, fileName := internal.ParseIndexerID(hit.Id) res := make(map[string]any) if err := json.Unmarshal(hit.Source, &res); err != nil { return 0, nil, nil, err @@ -276,8 +300,8 @@ func convertResult(searchResult *elastic.SearchResult, kw string, pageSize int) language := res["language"].(string) hits = append(hits, &internal.SearchResult{ - RepoID: repoID, - Filename: fileName, + RepoID: int64(res["repo_id"].(float64)), + Filename: res["filename"].(string), CommitID: res["commit_id"].(string), Content: res["content"].(string), UpdatedUnix: timeutil.TimeStamp(res["updated_at"].(float64)), @@ -326,6 +350,9 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int repoQuery := elastic.NewTermsQuery("repo_id", repoStrs...) query = query.Must(repoQuery) } + if len(opts.Filename) > 0 { + query = query.Filter(elastic.NewTermsQuery("filename.tree", opts.Filename)) + } var ( start, pageSize = opts.GetSkipTake() diff --git a/modules/indexer/code/indexer_test.go b/modules/indexer/code/indexer_test.go index d474eba174..9ef16f3412 100644 --- a/modules/indexer/code/indexer_test.go +++ b/modules/indexer/code/indexer_test.go @@ -34,10 +34,11 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) { err := index(git.DefaultContext, indexer, repoID) require.NoError(t, err) keywords := []struct { - RepoIDs []int64 - Keyword string - IDs []int64 - Langs int + RepoIDs []int64 + Keyword string + IDs []int64 + Langs int + Filename string }{ { RepoIDs: nil, @@ -51,6 +52,20 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) { IDs: []int64{}, Langs: 0, }, + { + RepoIDs: nil, + Keyword: "Description", + IDs: []int64{}, + Langs: 0, + Filename: "NOT-README.md", + }, + { + RepoIDs: nil, + Keyword: "Description", + IDs: []int64{repoID}, + Langs: 1, + Filename: "README.md", + }, { RepoIDs: nil, Keyword: "Description for", @@ -86,6 +101,7 @@ func testIndexer(name string, t *testing.T, indexer internal.Indexer) { Page: 1, PageSize: 10, }, + Filename: kw.Filename, IsKeywordFuzzy: true, }) require.NoError(t, err) diff --git a/modules/indexer/code/internal/indexer.go b/modules/indexer/code/internal/indexer.go index c259fcd26e..748c9e1bf9 100644 --- a/modules/indexer/code/internal/indexer.go +++ b/modules/indexer/code/internal/indexer.go @@ -24,6 +24,7 @@ type SearchOptions struct { RepoIDs []int64 Keyword string Language string + Filename string IsKeywordFuzzy bool diff --git a/modules/indexer/code/internal/util.go b/modules/indexer/code/internal/util.go index 689c4f4584..1c999fda7d 100644 --- a/modules/indexer/code/internal/util.go +++ b/modules/indexer/code/internal/util.go @@ -3,30 +3,8 @@ package internal -import ( - "strings" - - "code.gitea.io/gitea/modules/indexer/internal" - "code.gitea.io/gitea/modules/log" -) +import "code.gitea.io/gitea/modules/indexer/internal" func FilenameIndexerID(repoID int64, filename string) string { return internal.Base36(repoID) + "_" + filename } - -func ParseIndexerID(indexerID string) (int64, string) { - index := strings.IndexByte(indexerID, '_') - if index == -1 { - log.Error("Unexpected ID in repo indexer: %s", indexerID) - } - repoID, _ := internal.ParseBase36(indexerID[:index]) - return repoID, indexerID[index+1:] -} - -func FilenameOfIndexerID(indexerID string) string { - index := strings.IndexByte(indexerID, '_') - if index == -1 { - log.Error("Unexpected ID in repo indexer: %s", indexerID) - } - return indexerID[index+1:] -} diff --git a/modules/indexer/code/search.go b/modules/indexer/code/search.go index f45907ad90..9f7aa2db60 100644 --- a/modules/indexer/code/search.go +++ b/modules/indexer/code/search.go @@ -35,6 +35,8 @@ type SearchResultLanguages = internal.SearchResultLanguages type SearchOptions = internal.SearchOptions +var CodeSearchOptions = [2]string{"exact", "fuzzy"} + func indices(content string, selectionStartIndex, selectionEndIndex int) (int, int) { startIndex := selectionStartIndex numLinesBefore := 0 diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go index 7992517ad4..76238e80fb 100644 --- a/routers/web/explore/code.go +++ b/routers/web/explore/code.go @@ -35,6 +35,7 @@ func Code(ctx *context.Context) { language := ctx.FormTrim("l") keyword := ctx.FormTrim("q") + path := ctx.FormTrim("path") isFuzzy := ctx.FormOptionalBool("fuzzy").ValueOrDefault(true) if mode := ctx.FormTrim("mode"); len(mode) > 0 { @@ -91,6 +92,7 @@ func Code(ctx *context.Context) { Keyword: keyword, IsKeywordFuzzy: isFuzzy, Language: language, + Filename: path, Paginator: &db.ListOptions{ Page: page, PageSize: setting.UI.RepoSearchPagingNum, diff --git a/routers/web/repo/search.go b/routers/web/repo/search.go index 863a279af0..f2264360ec 100644 --- a/routers/web/repo/search.go +++ b/routers/web/repo/search.go @@ -54,6 +54,7 @@ func Search(ctx *context.Context) { language := ctx.FormTrim("l") keyword := ctx.FormTrim("q") + path := ctx.FormTrim("path") mode := ExactSearchMode if modeStr := ctx.FormString("mode"); len(modeStr) > 0 { mode = searchModeFromString(modeStr) @@ -63,6 +64,7 @@ func Search(ctx *context.Context) { ctx.Data["Keyword"] = keyword ctx.Data["Language"] = language + ctx.Data["CodeSearchPath"] = path ctx.Data["CodeSearchMode"] = mode.String() ctx.Data["PageIsViewCode"] = true @@ -86,6 +88,7 @@ func Search(ctx *context.Context) { Keyword: keyword, IsKeywordFuzzy: mode == FuzzySearchMode, Language: language, + Filename: path, Paginator: &db.ListOptions{ Page: page, PageSize: setting.UI.RepoSearchPagingNum, @@ -100,11 +103,12 @@ func Search(ctx *context.Context) { } else { ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx) } - ctx.Data["CodeSearchOptions"] = []string{"exact", "fuzzy"} + ctx.Data["CodeSearchOptions"] = code_indexer.CodeSearchOptions } else { grepOpt := git.GrepOptions{ ContextLineNumber: 1, RefName: ctx.Repo.RefName, + Filename: path, } switch mode { case FuzzySearchMode: @@ -130,10 +134,12 @@ func Search(ctx *context.Context) { // UpdatedUnix: not supported yet // Language: not supported yet // Color: not supported yet - Lines: code_indexer.HighlightSearchResultCode(r.Filename, r.LineNumbers, r.HighlightedRanges, strings.Join(r.LineCodes, "\n")), + Lines: code_indexer.HighlightSearchResultCode( + r.Filename, r.LineNumbers, r.HighlightedRanges, + strings.Join(r.LineCodes, "\n")), }) } - ctx.Data["CodeSearchOptions"] = []string{"exact", "union", "regexp"} + ctx.Data["CodeSearchOptions"] = git.GrepSearchOptions } ctx.Data["CodeIndexerDisabled"] = !setting.Indexer.RepoIndexerEnabled diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index e177c81902..fd8c1da058 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -39,6 +39,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/highlight" + code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" @@ -1152,6 +1153,12 @@ PostRecentBranchCheck: ctx.Data["TreeNames"] = treeNames ctx.Data["BranchLink"] = branchLink ctx.Data["CodeIndexerDisabled"] = !setting.Indexer.RepoIndexerEnabled + if setting.Indexer.RepoIndexerEnabled { + ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable(ctx) + ctx.Data["CodeSearchOptions"] = code_indexer.CodeSearchOptions + } else { + ctx.Data["CodeSearchOptions"] = git.GrepSearchOptions + } ctx.HTML(http.StatusOK, tplRepoHome) } diff --git a/routers/web/user/code.go b/routers/web/user/code.go index 26e48d1ea6..3e044d7876 100644 --- a/routers/web/user/code.go +++ b/routers/web/user/code.go @@ -39,6 +39,7 @@ func CodeSearch(ctx *context.Context) { language := ctx.FormTrim("l") keyword := ctx.FormTrim("q") + path := ctx.FormTrim("path") isFuzzy := ctx.FormOptionalBool("fuzzy").ValueOrDefault(true) if mode := ctx.FormTrim("mode"); len(mode) > 0 { @@ -88,6 +89,7 @@ func CodeSearch(ctx *context.Context) { Keyword: keyword, IsKeywordFuzzy: isFuzzy, Language: language, + Filename: path, Paginator: &db.ListOptions{ Page: page, PageSize: setting.UI.RepoSearchPagingNum, diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 9cbdef53ca..7bf4ee4a8e 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -11,12 +11,6 @@ {{if $description}}{{$description | RenderCodeBlock}}{{else}}{{ctx.Locale.Tr "repo.no_desc"}}{{end}} {{if .Repository.Website}}{{.Repository.Website}}{{end}} -
-
- - {{template "shared/search/button"}} -
-
{{/* it should match the code in issue-home.js */}} @@ -158,6 +152,22 @@ {{else if .IsBlame}} {{template "repo/blame" .}} {{else}}{{/* IsViewDirectory */}} + {{/* display the search bar only if */}} + {{$isCommit := StringUtils.HasPrefix .BranchNameSubURL "commit"}} + {{if and (not $isCommit) (or .CodeIndexerDisabled (and (not .TagName) (eq .Repository.DefaultBranch .BranchName)))}} + + {{end}} {{template "repo/view_list" .}} {{end}}
diff --git a/templates/shared/search/code/results.tmpl b/templates/shared/search/code/results.tmpl index 98c5430502..5525d0c715 100644 --- a/templates/shared/search/code/results.tmpl +++ b/templates/shared/search/code/results.tmpl @@ -1,7 +1,7 @@ {{else}} + {{if .CodeSearchPath}} +
+ + @ + {{$href := ""}} + {{- range $i, $path := StringUtils.Split .CodeSearchPath "/" -}} + {{if eq $i 0}} + {{$href = $path}} + {{else}} + {{$href = StringUtils.Join (StringUtils.Make $href $path) "/"}} + {{end}} + / + {{$path}} + {{- end -}} + +
+ {{end}} {{if .CodeIndexerDisabled}}

{{ctx.Locale.Tr "search.code_search_by_git_grep"}}

diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go index f165cae539..90fc19c193 100644 --- a/tests/integration/repo_test.go +++ b/tests/integration/repo_test.go @@ -1009,16 +1009,29 @@ func TestRepoCodeSearchForm(t *testing.T) { resp := MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - action, exists := htmlDoc.doc.Find("form[data-test-tag=codesearch]").Attr("action") + formEl := htmlDoc.doc.Find("form[data-test-tag=codesearch]") + + action, exists := formEl.Attr("action") assert.True(t, exists) - branchSubURL := "/branch/master" - if indexer { assert.NotContains(t, action, branchSubURL) } else { assert.Contains(t, action, branchSubURL) } + + filepath, exists := formEl.Find("input[name=path]").Attr("value") + assert.True(t, exists) + assert.Empty(t, filepath) + + req = NewRequest(t, "GET", "/user2/glob/src/branch/master/x/y") + resp = MakeRequest(t, req, http.StatusOK) + + filepath, exists = NewHTMLParser(t, resp.Body).doc. + Find("form[data-test-tag=codesearch] input[name=path]"). + Attr("value") + assert.True(t, exists) + assert.Equal(t, "x/y", filepath) } t.Run("indexer disabled", func(t *testing.T) { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 6568a0de03..1b3ee51e91 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -389,6 +389,11 @@ td .commit-summary { cursor: default; } +.code-search + #repo-files-table { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + .view-raw { display: flex; justify-content: center; From 4e820ff795a60c3f61bc3647bddb19bc609fe1b4 Mon Sep 17 00:00:00 2001 From: 0ko <0ko@noreply.codeberg.org> Date: Sun, 22 Dec 2024 17:05:27 +0000 Subject: [PATCH 11/35] feat(ui): show repo size on mobile (#6344) Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6344 Reviewed-by: Gusted --- templates/repo/sub_menu.tmpl | 4 ++-- web_src/css/repo.css | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index ddf01b33ed..598cfc5c80 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -1,6 +1,6 @@ {{if and (not .HideRepoInfo) (not .IsBlame)}}
- +
+

+ {{ctx.Locale.Tr "repo.settings.default_update_style_desc"}} +

+ +
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index f0a0b86622..1feeebba98 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -23321,6 +23321,11 @@ "type": "string", "x-go-name": "DefaultMergeStyle" }, + "default_update_style": { + "description": "set to a update style to be used by this repository: \"rebase\" or \"merge\"", + "type": "string", + "x-go-name": "DefaultUpdateStyle" + }, "description": { "description": "a short description of the repository.", "type": "string", @@ -26605,6 +26610,10 @@ "type": "string", "x-go-name": "DefaultMergeStyle" }, + "default_update_style": { + "type": "string", + "x-go-name": "DefaultUpdateStyle" + }, "description": { "type": "string", "x-go-name": "Description" diff --git a/tests/integration/pull_update_test.go b/tests/integration/pull_update_test.go index 08041f0717..f36ea88c2b 100644 --- a/tests/integration/pull_update_test.go +++ b/tests/integration/pull_update_test.go @@ -4,6 +4,7 @@ package integration import ( + "fmt" "net/http" "net/url" "strings" @@ -16,6 +17,9 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/test" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" files_service "code.gitea.io/gitea/services/repository/files" @@ -83,6 +87,102 @@ func TestAPIPullUpdateByRebase(t *testing.T) { }) } +func TestAPIViewUpdateSettings(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + defer tests.PrepareTestEnv(t)() + // Create PR to test + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}) + pr := createOutdatedPR(t, user, org26) + + // Test GetDiverging + diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr) + require.NoError(t, err) + assert.EqualValues(t, 1, diffCount.Behind) + assert.EqualValues(t, 1, diffCount.Ahead) + require.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) + require.NoError(t, pr.LoadIssue(db.DefaultContext)) + + session := loginUser(t, "user2") + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) + + defaultUpdateStyle := "rebase" + editOption := api.EditRepoOption{ + DefaultUpdateStyle: &defaultUpdateStyle, + } + + req := NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", pr.BaseRepo.OwnerName, pr.BaseRepo.Name), editOption).AddTokenAuth(token) + session.MakeRequest(t, req, http.StatusOK) + assertViewPullUpdate(t, pr, session, "rebase", true) + + defaultUpdateStyle = "merge" + req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/repos/%s/%s", pr.BaseRepo.OwnerName, pr.BaseRepo.Name), editOption).AddTokenAuth(token) + session.MakeRequest(t, req, http.StatusOK) + assertViewPullUpdate(t, pr, session, "merge", true) + }) +} + +func TestViewPullUpdateByMerge(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + testViewPullUpdate(t, "merge") + }) +} + +func TestViewPullUpdateByRebase(t *testing.T) { + onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { + testViewPullUpdate(t, "rebase") + }) +} + +func testViewPullUpdate(t *testing.T, updateStyle string) { + defer test.MockVariableValue(&setting.Repository.PullRequest.DefaultUpdateStyle, updateStyle)() + defer tests.PrepareTestEnv(t)() + // Create PR to test + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}) + pr := createOutdatedPR(t, user, org26) + + // Test GetDiverging + diffCount, err := pull_service.GetDiverging(git.DefaultContext, pr) + require.NoError(t, err) + assert.EqualValues(t, 1, diffCount.Behind) + assert.EqualValues(t, 1, diffCount.Ahead) + require.NoError(t, pr.LoadBaseRepo(db.DefaultContext)) + require.NoError(t, pr.LoadIssue(db.DefaultContext)) + + session := loginUser(t, "user2") + assertViewPullUpdate(t, pr, session, updateStyle, true) +} + +func assertViewPullUpdate(t *testing.T, pr *issues_model.PullRequest, session *TestSession, expectedStyle string, dropdownExpected bool) { + req := NewRequest(t, "GET", fmt.Sprintf("%s/%s/pulls/%d", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index)) + resp := session.MakeRequest(t, req, http.StatusOK) + + htmlDoc := NewHTMLParser(t, resp.Body) + // Verify that URL of the update button is shown correctly. + var mainExpectedURL string + mergeExpectedURL := fmt.Sprintf("/%s/%s/pulls/%d/update?style=merge", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index) + rebaseExpectedURL := fmt.Sprintf("/%s/%s/pulls/%d/update?style=rebase", pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Issue.Index) + if expectedStyle == "rebase" { + mainExpectedURL = rebaseExpectedURL + if dropdownExpected { + htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .item[data-do=\"%s\"]:not(.active.selected)", mergeExpectedURL), true) + htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .active.selected.item[data-do=\"%s\"]", rebaseExpectedURL), true) + } + } else { + mainExpectedURL = mergeExpectedURL + if dropdownExpected { + htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .active.selected.item[data-do=\"%s\"]", mergeExpectedURL), true) + htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .dropdown .menu .item[data-do=\"%s\"]:not(.active.selected)", rebaseExpectedURL), true) + } + } + if dropdownExpected { + htmlDoc.AssertElement(t, fmt.Sprintf(".update-button .button[data-do=\"%s\"]", mainExpectedURL), true) + } else { + htmlDoc.AssertElement(t, fmt.Sprintf("form[action=\"%s\"]", mainExpectedURL), true) + } +} + func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_model.PullRequest { baseRepo, _, _ := tests.CreateDeclarativeRepo(t, actor, "repo-pr-update", nil, nil, nil) From 7ecd88719e4f2df9337a7ef263e272e503e0c13a Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Dec 2024 00:04:06 +0000 Subject: [PATCH 20/35] Update module google.golang.org/protobuf to v1.36.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4283029877..93cca2eb8d 100644 --- a/go.mod +++ b/go.mod @@ -112,7 +112,7 @@ require ( golang.org/x/text v0.21.0 golang.org/x/tools v0.28.0 google.golang.org/grpc v1.69.2 - google.golang.org/protobuf v1.36.0 + google.golang.org/protobuf v1.36.1 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index d385f5142e..15050f3225 100644 --- a/go.sum +++ b/go.sum @@ -2244,8 +2244,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ= -google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= +google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From f9aaefd107bc6583a348e89fb76f41443224a821 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Dec 2024 00:04:32 +0000 Subject: [PATCH 21/35] Update dependency idiomorph to v0.4.0 --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e615c9114..7de2df6662 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "escape-goat": "4.0.0", "fast-glob": "3.3.2", "htmx.org": "1.9.12", - "idiomorph": "0.3.0", + "idiomorph": "0.4.0", "jquery": "3.7.1", "katex": "0.16.18", "mermaid": "11.4.1", @@ -9312,10 +9312,10 @@ } }, "node_modules/idiomorph": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/idiomorph/-/idiomorph-0.3.0.tgz", - "integrity": "sha512-UhV1Ey5xCxIwR9B+OgIjQa+1Jx99XQ1vQHUsKBU1RpQzCx1u+b+N6SOXgf5mEJDqemUI/ffccu6+71l2mJUsRA==", - "license": "BSD 2-Clause" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/idiomorph/-/idiomorph-0.4.0.tgz", + "integrity": "sha512-VdXFpZOTXhLatJmhCWJR5oQKLXT01O6sFCJqT0/EqG71C4tYZdPJ5etvttwWsT2WKRYWz160XkNr1DUqXNMZHg==", + "license": "BSD-2-Clause" }, "node_modules/ieee754": { "version": "1.2.1", diff --git a/package.json b/package.json index 76798949f6..034edc623a 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "escape-goat": "4.0.0", "fast-glob": "3.3.2", "htmx.org": "1.9.12", - "idiomorph": "0.3.0", + "idiomorph": "0.4.0", "jquery": "3.7.1", "katex": "0.16.18", "mermaid": "11.4.1", From 92b770326fafb0c290c4053bdb77eebb2e510023 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Tue, 24 Dec 2024 06:52:31 +0100 Subject: [PATCH 22/35] chore(docs): explain vars.SKIP_END_TO_END when building a release --- .forgejo/workflows/build-release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.forgejo/workflows/build-release.yml b/.forgejo/workflows/build-release.yml index c6cae8909d..433b085969 100644 --- a/.forgejo/workflows/build-release.yml +++ b/.forgejo/workflows/build-release.yml @@ -14,6 +14,12 @@ # secrets.CASCADE_DESTINATION_TOKEN: scope read:user, write:repository, write:issue # vars.CASCADE_DESTINATION_DOER: forgejo-ci # +# vars.SKIP_END_TO_END: `true` or `false` +# It must be `false` (or absent) so https://code.forgejo.org/forgejo/end-to-end is run +# with the newly built release. +# It must be set to `true` when a release is missing, for instance because it was +# removed and failed to upload. +# on: push: tags: 'v[0-9]+.[0-9]+.*' From 274bc480b41132920e36c1cbee8a0f0e69a4ba0c Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Mon, 23 Dec 2024 08:24:40 +0100 Subject: [PATCH 23/35] fix: Gitea last drop Some database fields were added in the database to facilitate migration from Gitea and do not serve any purpose. Drop them since v1.22 is the last version of the database to allow a transparent migration to Forgejo. --- models/migrations/migrations.go | 3 +++ models/migrations/v1_23/v303.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 models/migrations/v1_23/v303.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 77a97fb3f6..1c55bcd63d 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -362,6 +362,9 @@ func prepareMigrationTasks() []*migration { newMigration(300, "Add force-push branch protection support", v1_23.AddForcePushBranchProtection), newMigration(301, "Add skip_secondary_authorization option to oauth2 application table", v1_23.AddSkipSecondaryAuthColumnToOAuth2ApplicationTable), newMigration(302, "Add index to action_task stopped log_expired", v1_23.AddIndexToActionTaskStoppedLogExpired), + + // Migration to Forgejo v10 + newMigration(303, "Gitea last drop", v1_23.GiteaLastDrop), } return preparedMigrations } diff --git a/models/migrations/v1_23/v303.go b/models/migrations/v1_23/v303.go new file mode 100644 index 0000000000..c1e74c596a --- /dev/null +++ b/models/migrations/v1_23/v303.go @@ -0,0 +1,33 @@ +// Copyright 2024 The Forgejo Authors. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import ( + "code.gitea.io/gitea/models/migrations/base" + + "xorm.io/xorm" +) + +func GiteaLastDrop(x *xorm.Engine) error { + sess := x.NewSession() + defer sess.Close() + + if err := base.DropTableColumns(sess, "badge", "slug"); err != nil { + return err + } + if err := base.DropTableColumns(sess, "oauth2_application", "skip_secondary_authorization"); err != nil { + return err + } + if err := base.DropTableColumns(sess, "repository", "default_wiki_branch"); err != nil { + return err + } + // the migration v297.go that adds everyone_access_mode exists in Gitea >= v1.22 and the column must be dropped + // but it does not exist in Forgejo and a failure to drop the column can be ignored + base.DropTableColumns(sess, "repo_unit", "everyone_access_mode") + if err := base.DropTableColumns(sess, "protected_branch", "can_force_push", "enable_force_push_allowlist", "force_push_allowlist_user_i_ds", "force_push_allowlist_team_i_ds", "force_push_allowlist_deploy_keys"); err != nil { + return err + } + + return sess.Commit() +} From 2dc167cbb96e800b36a2d5c3405051915aeb7ff7 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Sun, 22 Dec 2024 11:39:06 +0100 Subject: [PATCH 24/35] fix: xorm:version default is inconsistent The following message is displayed when upgrading to Forgejo: [W] Table system_setting Column version db default is , struct default is 1 The same message also shows when upgrading from Gitea 1.21 to Gitea 1.22. It is fine for the version field to default to zero or NULL instead of one. --- models/system/setting.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/models/system/setting.go b/models/system/setting.go index 4472b4c228..cda60d1758 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -18,10 +18,10 @@ import ( ) type Setting struct { - ID int64 `xorm:"pk autoincr"` - SettingKey string `xorm:"varchar(255) unique"` // key should be lowercase - SettingValue string `xorm:"text"` - Version int `xorm:"version"` + ID int64 `xorm:"pk autoincr"` + SettingKey string `xorm:"varchar(255) unique"` // key should be lowercase + SettingValue string `xorm:"text"` + Version int Created timeutil.TimeStamp `xorm:"created"` Updated timeutil.TimeStamp `xorm:"updated"` } From 9524d6d43064b3f9ee35d66b4156183d6daf2f7d Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Mon, 23 Dec 2024 10:15:41 +0100 Subject: [PATCH 25/35] fix: keying SQLite migration Also run the keying migration when upgrading from Gitea. Add type change support for SQLite field from TEXT to BLOB. --- models/forgejo_migrations/v25.go | 25 +++++++++++++++++++++++++ models/migrations/migrations.go | 1 + 2 files changed, 26 insertions(+) diff --git a/models/forgejo_migrations/v25.go b/models/forgejo_migrations/v25.go index 2e9641929c..e2316007cf 100644 --- a/models/forgejo_migrations/v25.go +++ b/models/forgejo_migrations/v25.go @@ -20,9 +20,34 @@ import ( func MigrateTwoFactorToKeying(x *xorm.Engine) error { var err error + // When upgrading from Forgejo v9 to v10, this migration will already be + // called from models/migrations/migrations.go migration 304 and must not + // be run twice. + var version int + _, err = x.Table("version").Where("`id` = 1").Select("version").Get(&version) + if err != nil { + // the version table does not exist when a test environment only applies Forgejo migrations + } else if version > 304 { + return nil + } + switch x.Dialect().URI().DBType { case schemas.MYSQL: _, err = x.Exec("ALTER TABLE `two_factor` MODIFY `secret` BLOB") + case schemas.SQLITE: + _, err = x.Exec("ALTER TABLE `two_factor` RENAME COLUMN `secret` TO `secret_backup`") + if err != nil { + return err + } + _, err = x.Exec("ALTER TABLE `two_factor` ADD COLUMN `secret` BLOB") + if err != nil { + return err + } + _, err = x.Exec("UPDATE `two_factor` SET `secret` = `secret_backup`") + if err != nil { + return err + } + _, err = x.Exec("ALTER TABLE `two_factor` DROP COLUMN `secret_backup`") case schemas.POSTGRES: _, err = x.Exec("ALTER TABLE `two_factor` ALTER COLUMN `secret` SET DATA TYPE bytea USING secret::text::bytea") } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 1c55bcd63d..1674af08cd 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -365,6 +365,7 @@ func prepareMigrationTasks() []*migration { // Migration to Forgejo v10 newMigration(303, "Gitea last drop", v1_23.GiteaLastDrop), + newMigration(304, "Migrate `secret` column to store keying material", forgejo_migrations.MigrateTwoFactorToKeying), } return preparedMigrations } From 2a0fad33d61d1d2eba829b71fc653bc23146e079 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Dec 2024 20:03:41 +0000 Subject: [PATCH 26/35] Update github.com/shurcooL/vfsgen digest to 0000e14 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 8b158d6fce..b054802289 100644 --- a/go.mod +++ b/go.mod @@ -90,7 +90,7 @@ require ( github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 github.com/sassoftware/go-rpmutils v0.4.0 github.com/sergi/go-diff v1.3.1 - github.com/shurcooL/vfsgen v0.0.0-00010101000000-000000000000 + github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 github.com/stretchr/testify v1.10.0 github.com/syndtr/goleveldb v1.0.0 github.com/ulikunitz/xz v0.5.12 From 85717dcdd8489e25d191e0c722ba59cc533a9658 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Dec 2024 20:05:17 +0000 Subject: [PATCH 27/35] Update dependency webpack-cli to v6 --- package-lock.json | 93 +++++++++++++++++++++++++---------------------- package.json | 2 +- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7de2df6662..cd947c72d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,7 @@ "vue-loader": "17.4.2", "vue3-calendar-heatmap": "2.0.5", "webpack": "5.97.1", - "webpack-cli": "5.1.4", + "webpack-cli": "6.0.1", "wrap-ansi": "9.0.0" }, "devDependencies": { @@ -2216,12 +2216,12 @@ } }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=14.17.0" } }, "node_modules/@dual-bundle/import-meta-resolve": { @@ -5330,42 +5330,42 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", + "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", + "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", + "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -6385,6 +6385,7 @@ "version": "10.0.1", "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -15306,42 +15307,39 @@ } }, "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", + "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "license": "MIT", "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", + "@discoveryjs/json-ext": "^0.6.1", + "@webpack-cli/configtest": "^3.0.1", + "@webpack-cli/info": "^3.0.1", + "@webpack-cli/serve": "^3.0.1", "colorette": "^2.0.14", - "commander": "^10.0.1", + "commander": "^12.1.0", "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", + "envinfo": "^7.14.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^3.1.1", "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" + "webpack-merge": "^6.0.1" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "5.x.x" + "webpack": "^5.82.0" }, "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -15350,18 +15348,27 @@ } } }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { diff --git a/package.json b/package.json index 034edc623a..5818de4fd1 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "vue-loader": "17.4.2", "vue3-calendar-heatmap": "2.0.5", "webpack": "5.97.1", - "webpack-cli": "5.1.4", + "webpack-cli": "6.0.1", "wrap-ansi": "9.0.0" }, "devDependencies": { From f5d868e2d38471101c39d610cf3b8b984a0fda67 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Dec 2024 23:01:52 +0000 Subject: [PATCH 28/35] Update linters (forgejo) (#6366) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 109 +++++++++++++++++++++++----------------------- package.json | 6 +-- 2 files changed, 58 insertions(+), 57 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd947c72d3..aef68fb581 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,7 +66,7 @@ "@stoplight/spectral-cli": "6.14.2", "@stylistic/eslint-plugin-js": "2.12.1", "@stylistic/stylelint-plugin": "3.1.1", - "@typescript-eslint/parser": "8.18.1", + "@typescript-eslint/parser": "8.18.2", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.8", "@vitest/eslint-plugin": "1.1.16", @@ -74,7 +74,7 @@ "eslint": "9.17.0", "eslint-import-resolver-typescript": "3.7.0", "eslint-plugin-array-func": "5.0.2", - "eslint-plugin-import-x": "4.5.1", + "eslint-plugin-import-x": "4.6.1", "eslint-plugin-no-jquery": "3.1.0", "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.1.0", @@ -96,7 +96,7 @@ "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", "typescript": "5.7.2", - "typescript-eslint": "8.18.1", + "typescript-eslint": "8.18.2", "vite-string-plugin": "1.3.4", "vitest": "2.1.8" }, @@ -4640,17 +4640,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz", - "integrity": "sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz", + "integrity": "sha512-adig4SzPLjeQ0Tm+jvsozSGiCliI2ajeURDGHjZ2llnA+A67HihCQ+a3amtPhUakd1GlwHxSRvzOZktbEvhPPg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/type-utils": "8.18.1", - "@typescript-eslint/utils": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/type-utils": "8.18.2", + "@typescript-eslint/utils": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4670,16 +4670,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz", - "integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.2.tgz", + "integrity": "sha512-y7tcq4StgxQD4mDr9+Jb26dZ+HTZ/SkfqpXSiqeUXZHxOUyjWDKsmwKhJ0/tApR08DgOhrFAoAhyB80/p3ViuA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/typescript-estree": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "debug": "^4.3.4" }, "engines": { @@ -4695,14 +4695,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz", - "integrity": "sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.2.tgz", + "integrity": "sha512-YJFSfbd0CJjy14r/EvWapYgV4R5CHzptssoag2M7y3Ra7XNta6GPAJPPP5KGB9j14viYXyrzRO5GkX7CRfo8/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1" + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4713,14 +4713,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz", - "integrity": "sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.2.tgz", + "integrity": "sha512-AB/Wr1Lz31bzHfGm/jgbFR0VB0SML/hd2P1yxzKDM48YmP7vbyJNHRExUE/wZsQj2wUCvbWH8poNHFuxLqCTnA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.18.1", - "@typescript-eslint/utils": "8.18.1", + "@typescript-eslint/typescript-estree": "8.18.2", + "@typescript-eslint/utils": "8.18.2", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -4737,9 +4737,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz", - "integrity": "sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.2.tgz", + "integrity": "sha512-Z/zblEPp8cIvmEn6+tPDIHUbRu/0z5lqZ+NvolL5SvXWT5rQy7+Nch83M0++XzO0XrWRFWECgOAyE8bsJTl1GQ==", "dev": true, "license": "MIT", "engines": { @@ -4751,14 +4751,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz", - "integrity": "sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.2.tgz", + "integrity": "sha512-WXAVt595HjpmlfH4crSdM/1bcsqh+1weFRWIa9XMTx/XHZ9TCKMcr725tLYqWOgzKdeDrqVHxFotrvWcEsk2Tg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/visitor-keys": "8.18.2", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -4794,16 +4794,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz", - "integrity": "sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.2.tgz", + "integrity": "sha512-Cr4A0H7DtVIPkauj4sTSXVl+VBWewE9/o40KcF3TV9aqDEOWoXF3/+oRXNby3DYzZeCATvbdksYsGZzplwnK/Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/typescript-estree": "8.18.1" + "@typescript-eslint/scope-manager": "8.18.2", + "@typescript-eslint/types": "8.18.2", + "@typescript-eslint/typescript-estree": "8.18.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4818,13 +4818,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz", - "integrity": "sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.2.tgz", + "integrity": "sha512-zORcwn4C3trOWiCqFQP1x6G3xTRyZ1LYydnj51cRnJ6hxBlr/cKPckk+PKPUw/fXmvfKTcw7bwY3w9izgx5jZw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/types": "8.18.2", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -8010,9 +8010,9 @@ } }, "node_modules/eslint-plugin-import-x": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.5.1.tgz", - "integrity": "sha512-Wyut9jDeHdfZSebiWRmmOYDBov33M0ZZ3x9J/lD1v4M3nBgMNC02XH6Kq271pMxJWqctVRCjA+X5AQJZ2FezoQ==", + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.6.1.tgz", + "integrity": "sha512-wluSUifMIb7UfwWXqx7Yx0lE/SGCcGXECLx/9bCmbY2nneLwvAZ4vkd1IXDjPKFvdcdUgr1BaRnaRpx3k2+Pfw==", "dev": true, "license": "MIT", "dependencies": { @@ -8021,6 +8021,7 @@ "@typescript-eslint/utils": "^8.1.0", "debug": "^4.3.4", "doctrine": "^3.0.0", + "enhanced-resolve": "^5.17.1", "eslint-import-resolver-node": "^0.3.9", "get-tsconfig": "^4.7.3", "is-glob": "^4.0.3", @@ -14587,15 +14588,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.1.tgz", - "integrity": "sha512-Mlaw6yxuaDEPQvb/2Qwu3/TfgeBHy9iTJ3mTwe7OvpPmF6KPQjVOfGyEJpPv6Ez2C34OODChhXrzYw/9phI0MQ==", + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.2.tgz", + "integrity": "sha512-KuXezG6jHkvC3MvizeXgupZzaG5wjhU3yE8E7e6viOvAvD9xAWYp8/vy0WULTGe9DYDWcQu7aW03YIV3mSitrQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.18.1", - "@typescript-eslint/parser": "8.18.1", - "@typescript-eslint/utils": "8.18.1" + "@typescript-eslint/eslint-plugin": "8.18.2", + "@typescript-eslint/parser": "8.18.2", + "@typescript-eslint/utils": "8.18.2" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 5818de4fd1..0ba340000b 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@stoplight/spectral-cli": "6.14.2", "@stylistic/eslint-plugin-js": "2.12.1", "@stylistic/stylelint-plugin": "3.1.1", - "@typescript-eslint/parser": "8.18.1", + "@typescript-eslint/parser": "8.18.2", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.8", "@vitest/eslint-plugin": "1.1.16", @@ -73,7 +73,7 @@ "eslint": "9.17.0", "eslint-import-resolver-typescript": "3.7.0", "eslint-plugin-array-func": "5.0.2", - "eslint-plugin-import-x": "4.5.1", + "eslint-plugin-import-x": "4.6.1", "eslint-plugin-no-jquery": "3.1.0", "eslint-plugin-no-use-extend-native": "0.7.2", "eslint-plugin-playwright": "2.1.0", @@ -95,7 +95,7 @@ "stylelint-value-no-unknown-custom-properties": "6.0.1", "svgo": "3.2.0", "typescript": "5.7.2", - "typescript-eslint": "8.18.1", + "typescript-eslint": "8.18.2", "vite-string-plugin": "1.3.4", "vitest": "2.1.8" }, From 6bbc9001e9e56d19eeb28d16a368fb2753d61f46 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 24 Dec 2024 23:02:35 +0000 Subject: [PATCH 29/35] Update dependency @vitest/eslint-plugin to v1.1.20 (forgejo) (#6364) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index aef68fb581..ae637779dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "@typescript-eslint/parser": "8.18.2", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.8", - "@vitest/eslint-plugin": "1.1.16", + "@vitest/eslint-plugin": "1.1.20", "@vue/test-utils": "2.4.6", "eslint": "9.17.0", "eslint-import-resolver-typescript": "3.7.0", @@ -4893,9 +4893,9 @@ } }, "node_modules/@vitest/eslint-plugin": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.16.tgz", - "integrity": "sha512-xecwJYuAp11AFsd2aoSnTWO3Wckgu7rjBz1VOhvsDtZzI4s7z/WerAR4gxnEFy37scdsE8wSlP95/2ry6sLhSg==", + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/@vitest/eslint-plugin/-/eslint-plugin-1.1.20.tgz", + "integrity": "sha512-2eLsgUm+GVOpDfNyH2do//MiNO/WZkXrPi+EjDmXEdUt6Jwnziq4H221L8vJE0aJys+l1FRfSkm4QbaIyDCfBg==", "dev": true, "license": "MIT", "peerDependencies": { diff --git a/package.json b/package.json index 0ba340000b..c674c011dd 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@typescript-eslint/parser": "8.18.2", "@vitejs/plugin-vue": "5.1.5", "@vitest/coverage-v8": "2.1.8", - "@vitest/eslint-plugin": "1.1.16", + "@vitest/eslint-plugin": "1.1.20", "@vue/test-utils": "2.4.6", "eslint": "9.17.0", "eslint-import-resolver-typescript": "3.7.0", From 967603abcce5864212dbe22e0e7a3df9e25313ed Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 25 Dec 2024 00:06:55 +0100 Subject: [PATCH 30/35] feat: harden keying implementation Harden the current checks in place, I doubt these will ever hit (you can prove easily by reading the current source code this cannot happen) but just in case a new Go version does something weird or something else goes catastrophicly wrong, this should add an extra defense-in-depth layer. `n != aeadKeySize` will panic a nil error, don't think it's needed to add more logic to this, a nil error is enough to indicate that that condition failed (given the other condition is `err != nil`). Also move constant integers to being `const`, this helps reducing the amount of instructions being done for the extra check. --- modules/keying/keying.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/keying/keying.go b/modules/keying/keying.go index 6082a91e8f..0b161b39c5 100644 --- a/modules/keying/keying.go +++ b/modules/keying/keying.go @@ -28,13 +28,16 @@ var ( // The hash used for HKDF. hash = sha256.New // The AEAD used for encryption/decryption. - aead = chacha20poly1305.NewX - aeadKeySize = chacha20poly1305.KeySize - aeadNonceSize = chacha20poly1305.NonceSizeX + aead = chacha20poly1305.NewX // The pseudorandom key generated by HKDF-Extract. prk []byte ) +const ( + aeadKeySize = chacha20poly1305.KeySize + aeadNonceSize = chacha20poly1305.NonceSizeX +) + // Set the main IKM for this module. func Init(ikm []byte) { // Salt is intentionally left empty, it's not useful to Forgejo's use case. @@ -55,7 +58,7 @@ var ( // Derive *the* key for a given context, this is a deterministic function. // The same key will be provided for the same context. func DeriveKey(context Context) *Key { - if len(prk) == 0 { + if len(prk) != sha256.Size { panic("keying: not initialized") } @@ -63,7 +66,7 @@ func DeriveKey(context Context) *Key { key := make([]byte, aeadKeySize) // This should never return an error, but if it does, panic. - if _, err := r.Read(key); err != nil { + if n, err := r.Read(key); err != nil || n != aeadKeySize { panic(err) } @@ -92,7 +95,7 @@ func (k *Key) Encrypt(plaintext, additionalData []byte) []byte { // Generate a random nonce. nonce := make([]byte, aeadNonceSize) - if _, err := rand.Read(nonce); err != nil { + if n, err := rand.Read(nonce); err != nil || n != aeadNonceSize { panic(err) } From f9ffc91aceebeef7a59bc214c2d667f240c89f6e Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Wed, 25 Dec 2024 00:37:19 +0000 Subject: [PATCH 31/35] Update dependency djlint to v1.36.4 (forgejo) (#6365) Co-authored-by: Renovate Bot Co-committed-by: Renovate Bot --- poetry.lock | 60 ++++++++++++++++++++++++++++++-------------------- pyproject.toml | 2 +- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3d6f3830ac..f75b2ef8d5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -59,33 +59,33 @@ six = ">=1.13.0" [[package]] name = "djlint" -version = "1.36.3" +version = "1.36.4" description = "HTML Template Linter and Formatter" optional = false python-versions = ">=3.9" files = [ - {file = "djlint-1.36.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ae7c620b58e16d6bf003bd7de3f71376a7a3daa79dc02e77f3726d5a75243f2"}, - {file = "djlint-1.36.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e155ce0970d4a28d0a2e9f2e106733a2ad05910eee90e056b056d48049e4a97b"}, - {file = "djlint-1.36.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e8bb0406e60cc696806aa6226df137618f3889c72f2dbdfa76c908c99151579"}, - {file = "djlint-1.36.3-cp310-cp310-win_amd64.whl", hash = "sha256:76d32faf988ad58ef2e7a11d04046fc984b98391761bf1b61f9a6044da53d414"}, - {file = "djlint-1.36.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:32f7a5834000fff22e94d1d35f95aaf2e06f2af2cae18af0ed2a4e215d60e730"}, - {file = "djlint-1.36.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3eb1b9c0be499e63e8822a051e7e55f188ff1ab8172a85d338a8ae21c872060e"}, - {file = "djlint-1.36.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4c2e0dd1f26eb472b8c84eb70d6482877b6497a1fd031d7534864088f016d5ea"}, - {file = "djlint-1.36.3-cp311-cp311-win_amd64.whl", hash = "sha256:a06b531ab9d049c46ad4d2365d1857004a1a9dd0c23c8eae94aa0d233c6ec00d"}, - {file = "djlint-1.36.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e66361a865e5e5a4bbcb40f56af7f256fd02cbf9d48b763a40172749cc294084"}, - {file = "djlint-1.36.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:36e102b80d83e9ac2e6be9a9ded32fb925945f6dbc7a7156e4415de1b0aa0dba"}, - {file = "djlint-1.36.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ac4b7370d80bd82281e57a470de8923ac494ffb571b89d8787cef57c738c69a"}, - {file = "djlint-1.36.3-cp312-cp312-win_amd64.whl", hash = "sha256:107cc56bbef13d60cc0ae774a4d52881bf98e37c02412e573827a3e549217e3a"}, - {file = "djlint-1.36.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2a9f51971d6e63c41ea9b3831c928e1f21ae6fe57e87a3452cfe672d10232433"}, - {file = "djlint-1.36.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:080c98714b55d8f0fef5c42beaee8247ebb2e3d46b0936473bd6c47808bb6302"}, - {file = "djlint-1.36.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f65a80e0b5cb13d357ea51ca6570b34c2d9d18974c1e57142de760ea27d49ed0"}, - {file = "djlint-1.36.3-cp313-cp313-win_amd64.whl", hash = "sha256:95ef6b67ef7f2b90d9434bba37d572031079001dc8524add85c00ef0386bda1e"}, - {file = "djlint-1.36.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8e2317a32094d525bc41cd11c8dc064bf38d1b442c99cc3f7c4a2616b5e6ce6e"}, - {file = "djlint-1.36.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e82266c28793cd15f97b93535d72bfbc77306eaaf6b210dd90910383a814ee6c"}, - {file = "djlint-1.36.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01b2101c2d1b079e8d545e6d9d03487fcca14d2371e44cbfdedee15b0bf4567c"}, - {file = "djlint-1.36.3-cp39-cp39-win_amd64.whl", hash = "sha256:15cde63ef28beb5194ff4137883025f125676ece1b574b64a3e1c6daed734639"}, - {file = "djlint-1.36.3-py3-none-any.whl", hash = "sha256:0c05cd5b76785de2c41a2420c06ffd112800bfc0f9c0f399cc7cea7c42557f4c"}, - {file = "djlint-1.36.3.tar.gz", hash = "sha256:d85735da34bc7ac93ad8ef9b4822cc2a23d5f0ce33f25438737b8dca1d404f78"}, + {file = "djlint-1.36.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a2dfb60883ceb92465201bfd392291a7597c6752baede6fbb6f1980cac8d6c5c"}, + {file = "djlint-1.36.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4bc6a1320c0030244b530ac200642f883d3daa451a115920ef3d56d08b644292"}, + {file = "djlint-1.36.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3164a048c7bb0baf042387b1e33f9bbbf99d90d1337bb4c3d66eb0f96f5400a1"}, + {file = "djlint-1.36.4-cp310-cp310-win_amd64.whl", hash = "sha256:3196d5277da5934962d67ad6c33a948ba77a7b6eadf064648bef6ee5f216b03c"}, + {file = "djlint-1.36.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d68da0ed10ee9ca1e32e225cbb8e9b98bf7e6f8b48a8e4836117b6605b88cc7"}, + {file = "djlint-1.36.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c0478d5392247f1e6ee29220bbdbf7fb4e1bc0e7e83d291fda6fb926c1787ba7"}, + {file = "djlint-1.36.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:962f7b83aee166e499eff916d631c6dde7f1447d7610785a60ed2a75a5763483"}, + {file = "djlint-1.36.4-cp311-cp311-win_amd64.whl", hash = "sha256:53cbc450aa425c832f09bc453b8a94a039d147b096740df54a3547fada77ed08"}, + {file = "djlint-1.36.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff9faffd7d43ac20467493fa71d5355b5b330a00ade1c4d1e859022f4195223b"}, + {file = "djlint-1.36.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:79489e262b5ac23a8dfb7ca37f1eea979674cfc2d2644f7061d95bea12c38f7e"}, + {file = "djlint-1.36.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e58c5fa8c6477144a0be0a87273706a059e6dd0d6efae01146ae8c29cdfca675"}, + {file = "djlint-1.36.4-cp312-cp312-win_amd64.whl", hash = "sha256:bb6903777bf3124f5efedcddf1f4716aef097a7ec4223fc0fa54b865829a6e08"}, + {file = "djlint-1.36.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ead475013bcac46095b1bbc8cf97ed2f06e83422335734363f8a76b4ba7e47c2"}, + {file = "djlint-1.36.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6c601dfa68ea253311deb4a29a7362b7a64933bdfcfb5a06618f3e70ad1fa835"}, + {file = "djlint-1.36.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bda5014f295002363381969864addeb2db13955f1b26e772657c3b273ed7809f"}, + {file = "djlint-1.36.4-cp313-cp313-win_amd64.whl", hash = "sha256:16ce37e085afe5a30953b2bd87cbe34c37843d94c701fc68a2dda06c1e428ff4"}, + {file = "djlint-1.36.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:89678661888c03d7bc6cadd75af69db29962b5ecbf93a81518262f5c48329f04"}, + {file = "djlint-1.36.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b01a98df3e1ab89a552793590875bc6e954cad661a9304057db75363d519fa0"}, + {file = "djlint-1.36.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dabbb4f7b93223d471d09ae34ed515fef98b2233cbca2449ad117416c44b1351"}, + {file = "djlint-1.36.4-cp39-cp39-win_amd64.whl", hash = "sha256:7a483390d17e44df5bc23dcea29bdf6b63f3ed8b4731d844773a4829af4f5e0b"}, + {file = "djlint-1.36.4-py3-none-any.whl", hash = "sha256:e9699b8ac3057a6ed04fb90835b89bee954ed1959c01541ce4f8f729c938afdd"}, + {file = "djlint-1.36.4.tar.gz", hash = "sha256:17254f218b46fe5a714b224c85074c099bcb74e3b2e1f15c2ddc2cf415a408a1"}, ] [package.dependencies] @@ -99,6 +99,7 @@ pyyaml = ">=6" regex = ">=2023" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} tqdm = ">=4.62.2" +typing-extensions = {version = ">=3.6.6", markers = "python_version < \"3.11\""} [[package]] name = "editorconfig" @@ -388,6 +389,17 @@ notebook = ["ipywidgets (>=6)"] slack = ["slack-sdk"] telegram = ["requests"] +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, +] + [[package]] name = "yamllint" version = "1.35.1" @@ -409,4 +421,4 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "23017e1bfd215dcbb046aaf68d4d2668737e17c687e6655be46e9bfd9a3df4c5" +content-hash = "64588702d556674c109df1bacaac08353a40f0863e7e72513d22f197f0c340c4" diff --git a/pyproject.toml b/pyproject.toml index 39b784b7a6..c30215c556 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ package-mode = false python = "^3.10" [tool.poetry.group.dev.dependencies] -djlint = "1.36.3" +djlint = "1.36.4" yamllint = "1.35.1" codespell = "^2.2.6" From 6836ded397fb7132868fac5a7b1593b932fa46e5 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Wed, 25 Dec 2024 11:21:59 +0100 Subject: [PATCH 32/35] chore(release): first commit of v11.0 --- release-notes-published/10.0.0.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 release-notes-published/10.0.0.md diff --git a/release-notes-published/10.0.0.md b/release-notes-published/10.0.0.md new file mode 100644 index 0000000000..e69de29bb2 From 64deec434a5910a3515d18c5a135848436cc76a7 Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 25 Dec 2024 23:08:03 +0100 Subject: [PATCH 33/35] Revert "Update dependency idiomorph to v0.4.0" This reverts commit f9aaefd107bc6583a348e89fb76f41443224a821. I've not not yet been able to determine what commit caused it, but 0.4.0 is broken for Forgejo's usecase it's not morphing and instead replacing (it seems) elements when there's no need to. --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index ae637779dd..e081796a52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "escape-goat": "4.0.0", "fast-glob": "3.3.2", "htmx.org": "1.9.12", - "idiomorph": "0.4.0", + "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.18", "mermaid": "11.4.1", @@ -9314,10 +9314,10 @@ } }, "node_modules/idiomorph": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/idiomorph/-/idiomorph-0.4.0.tgz", - "integrity": "sha512-VdXFpZOTXhLatJmhCWJR5oQKLXT01O6sFCJqT0/EqG71C4tYZdPJ5etvttwWsT2WKRYWz160XkNr1DUqXNMZHg==", - "license": "BSD-2-Clause" + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/idiomorph/-/idiomorph-0.3.0.tgz", + "integrity": "sha512-UhV1Ey5xCxIwR9B+OgIjQa+1Jx99XQ1vQHUsKBU1RpQzCx1u+b+N6SOXgf5mEJDqemUI/ffccu6+71l2mJUsRA==", + "license": "BSD 2-Clause" }, "node_modules/ieee754": { "version": "1.2.1", diff --git a/package.json b/package.json index c674c011dd..fe7c30471b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "escape-goat": "4.0.0", "fast-glob": "3.3.2", "htmx.org": "1.9.12", - "idiomorph": "0.4.0", + "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.18", "mermaid": "11.4.1", From 5eb08773814513bd688e714c4ee1ebf905c44f55 Mon Sep 17 00:00:00 2001 From: Earl Warren Date: Thu, 26 Dec 2024 09:40:21 +0100 Subject: [PATCH 34/35] chore(i18n): user/label translations in danish/latvian Refs: https://codeberg.org/forgejo/forgejo/pulls/6331 --- build/lint-locale.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/lint-locale.go b/build/lint-locale.go index c49e236938..44d320994c 100644 --- a/build/lint-locale.go +++ b/build/lint-locale.go @@ -59,9 +59,9 @@ func initRemoveTags() { oldnew := []string{} for _, el := range []string{ "email@example.com", "correu@example.com", "epasts@domens.lv", "email@exemplo.com", "eposta@ornek.com", "email@példa.hu", "email@esempio.it", - "user", "utente", "lietotājs", "gebruiker", "usuário", "Benutzer", "Bruker", + "user", "utente", "lietotājs", "gebruiker", "usuário", "Benutzer", "Bruker", "bruger", "server", "servidor", "kiszolgáló", "serveris", - "label", "etichetta", "etiķete", "rótulo", "Label", "utilizador", + "label", "etichetta", "etiķete", "rótulo", "Label", "utilizador", "etiket", "iezīme", } { oldnew = append(oldnew, "<"+el+">", "REPLACED-TAG") } From e94134def63ceaf6b46d5a617b11d4be0f5c1f59 Mon Sep 17 00:00:00 2001 From: Codeberg Translate Date: Thu, 26 Dec 2024 09:26:46 +0000 Subject: [PATCH 35/35] i18n: update of translations from Codeberg Translate (#6331) Co-authored-by: 0ko <0ko@users.noreply.translate.codeberg.org> Co-authored-by: Fjuro Co-authored-by: tacaly Co-authored-by: tacaly Co-authored-by: artnay Co-authored-by: WithLithum Co-authored-by: Wuzzy Co-authored-by: Atalanttore Co-authored-by: Juno Takano Co-authored-by: emansije Co-authored-by: earl-warren Co-authored-by: Edgarsons Co-authored-by: Benedikt Straub Co-authored-by: SomeTr Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6331 Reviewed-by: Earl Warren Co-authored-by: Codeberg Translate Co-committed-by: Codeberg Translate --- options/locale/locale_cs-CZ.ini | 3 +- options/locale/locale_da.ini | 907 ++++++++++++++++++++++++++++++++ options/locale/locale_de-DE.ini | 16 +- options/locale/locale_fi-FI.ini | 119 ++++- options/locale/locale_fr-FR.ini | 18 +- options/locale/locale_lv-LV.ini | 124 +++-- options/locale/locale_nds.ini | 1 + options/locale/locale_pt-BR.ini | 32 +- options/locale/locale_pt-PT.ini | 3 + options/locale/locale_ru-RU.ini | 83 +-- options/locale/locale_uk-UA.ini | 29 +- options/locale/locale_zh-CN.ini | 2 +- 12 files changed, 1173 insertions(+), 164 deletions(-) create mode 100644 options/locale/locale_da.ini diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index bd983164b2..375c4a710f 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -1010,7 +1010,7 @@ remove_account_link=Odstranit propojený účet remove_account_link_desc=Odstraněním propojeného účtu zrušíte jeho přístup k vašemu Forgejo účtu. Pokračovat? remove_account_link_success=Propojený účet byl odstraněn. -hooks.desc=Přidat webhooky, které budou spouštěny pro všechny repozitáře vve vašem vlastnictví. +hooks.desc=Přidejte webhooky, které budou spouštěny pro všechny repozitáře ve vašem vlastnictví. orgs_none=Nejste členem žádné organizace. repos_none=Nevlastníte žádné repozitáře. @@ -2849,6 +2849,7 @@ issues.num_reviews_one = %d kontrola issues.num_reviews_few = %d kontrol issues.summary_card_alt = Souhrn problému s názvem „%s“ v repozitáři %s editor.add_tmpl.filename = nazevsouboru +settings.default_update_style_desc = Výchozí způsob aktualizací používaný pro aktualizace žádostí o sloučení, které jsou pozadu oproti základní větvi. [graphs] component_loading_info = Tohle může chvíli trvat… diff --git a/options/locale/locale_da.ini b/options/locale/locale_da.ini new file mode 100644 index 0000000000..25a3010e05 --- /dev/null +++ b/options/locale/locale_da.ini @@ -0,0 +1,907 @@ + + + +[common] +home = Hjem +dashboard = Instrumentpanel +explore = Udforsk +help = Hjælp +logo = Logo +sign_in = Login +sign_in_with_provider = Login med %s +sign_in_or = eller +sign_out = Logud +sign_up = Register +return_to_forgejo = Vend tilbage til Forgejo +new_repo.title = Ny repository +retry = Prøv igen +link_account = Link konto +register = Register +powered_by = Baseret på %s +version = Version +create_new = Opret… +user_profile_and_more = Profil og indstillinger… +page = Side +template = Skabelon +language = Sprog +notifications = Notifikationer +active_stopwatch = Aktiv tidsregistrering +enable_javascript = Dette websted kræver JavaScript. +toc = Indholdsfortegnelse +licenses = Licenser +more_items = Flere genstande +username = Brugernavn +email = E-mailadresse +password = Adgangskode +access_token = Adgangstoken +re_type = Bekræft adgangskode +captcha = CAPTCHA +twofa = To-faktor autentificering +twofa_scratch = To-faktor skrabekode +webauthn_sign_in = Tryk på knappen på din sikkerhedsnøgle. Hvis din sikkerhedsnøgle ikke har nogen knap, skal du indsætte den igen. +webauthn_use_twofa = Brug en tofaktorkode fra din telefon +webauthn_error = Kunne ikke læse din sikkerhedsnøgle. +webauthn_unsupported_browser = Din browser understøtter i øjeblikket ikke WebAuthn. +webauthn_error_unknown = Der opstod en ukendt fejl. Prøv venligst igen. +webauthn_error_unable_to_process = Serveren kunne ikke behandle din anmodning. +webauthn_error_duplicated = Sikkerhedsnøglen er ikke tilladt for denne anmodning. Sørg for, at nøglen ikke allerede er registreret. +webauthn_error_empty = Du skal angive et navn for denne nøgle. +organization = Organisation +mirror = Mirror +new_mirror = Ny mirror +new_fork = Ny repository fork +new_project = Nyt projekt +new_project_column = Ny kolonne +admin_panel = Side administration +settings = Indstillinger +your_profile = Profil +your_starred = Stjernemarkeret +your_settings = Indstillinger +passcode = Passcode +repository = Repository +new_org.title = Ny organisation +new_repo.link = Nyt repository +new_migrate.link = Ny migration +new_org.link = Ny organisation +all = Alle +sources = Kilder +mirrors = Mirrors +collaborative = Samarbejdende +forks = Forks +activities = Aktiviteter +pull_requests = Pull anmodninger +issues = Problemer +milestones = Milepæle +ok = OK +cancel = Annuller +rerun = Kør igen +rerun_all = Kør alle jobs igen +save = Gem +add = Tilføj +add_all = Tilføj alle +remove = Slet +remove_all = Slet alle +remove_label_str = Slet genstand "%s" +edit = Redigere +view = Se +test = Test +disabled = Deaktiveret +copy = Kopiér +copy_generic = Kopiér til udklipsholder +copy_url = Kopiér URL +copy_path = Kopiér sti +copy_content = Kopier indhold +copy_branch = Kopiér branch navn +copy_success = Kopieret! +copy_error = Kopiering mislykkedes +write = Skriv +preview = Forhåndsvisning +loading = Indlæser… +error = Fejl +error413 = Du har opbrugt din kvote. +go_back = Gå tilbage +never = Aldrig +unknown = Ukendt +rss_feed = RSS feed +pin = Pin +unpin = Frigør +artifacts = Artefakter +archived = Arkiveret +concept_system_global = Global +concept_user_individual = Individuel +concept_code_repository = Repository +concept_user_organization = Organisation +show_timestamps = Vis tidsstempler +show_log_seconds = Vis sekunder +tracked_time_summary = Opsummering af sporet tid baseret på filtre af problemliste +signed_in_as = Logget ind som +webauthn_error_insecure = WebAuthn understøtter kun sikre forbindelser. Til test over HTTP kan du bruge oprindelsen "localhost" eller "127.0.0.1" +invalid_data = Ugyldige data: %v +webauthn_insert_key = Indsæt din sikkerhedsnøgle +webauthn_press_button = Tryk venligst på knappen på din sikkerhedsnøgle… +webauthn_error_timeout = Timeout nået, før din nøgle kunne læses. Genindlæs denne side og prøv igen. +enabled = Aktiveret +locked = Låst +copy_hash = Kopiér hash +error404 = Den side, du forsøger at nå, enten findes ikke eller du er ikke autoriseret til at se den. +confirm_delete_artifact = Er du sikker på, at du vil slette artefakten "%s"? +new_migrate.title = Ny migration +copy_type_unsupported = Denne filtype kan ikke kopieres +toggle_menu = TIl/Fra menu +show_full_screen = Vis fuld skærm +download_logs = Download logs +confirm_delete_selected = Bekræft at slette alle valgte genstande? +name = Navn +value = Værdi +filter = Filter +filter.clear = Ryd filtre +filter.is_archived = Arkiveret +filter.not_archived = Ikke arkiveret +filter.is_fork = Forks +filter.not_fork = Ikke forks +filter.is_mirror = Mirrors +filter.not_mirror = Ikke mirrors +filter.is_template = Skabeloner +filter.not_template = Ikke skabeloner +filter.public = Offentlig +filter.private = Privat + +[search] +search = Søg... +type_tooltip = Søge type +fuzzy = Fuzzy +fuzzy_tooltip = Medtag resultater, der også matcher søgeordet tæt +union = Almindelig +union_tooltip = Inkluder resultater, der matcher et hvilket som helst af de mellemrumsadskilte søgeord +exact = Nøjagtig +exact_tooltip = Medtag kun resultater, der matcher den nøjagtige søgeterm +regexp = RegExp +regexp_tooltip = Fortolk søgetermen som et regulært udtryk +org_kind = Søg i organisationer... +team_kind = Søg efter hold... +code_kind = Søg kode... +code_search_by_git_grep = Aktuelle kodesøgeresultater leveres af "git grep". Der kan være bedre resultater, hvis webstedsadministratoren aktiverer kodeindeksering. +package_kind = Søg pakker... +project_kind = Søg efter projekter... +commit_kind = Søg commits... +branch_kind = Søg branches... +runner_kind = Søg runners... +issue_kind = Søg i problemer... +milestone_kind = Søg milepæle... +pull_kind = Søg pulls... +repo_kind = Søg depoter... +code_search_unavailable = Kodesøgning er ikke tilgængelig i øjeblikket. Kontakt venligst webstedets administrator. +no_results = Ingen matchende resultater fundet. +user_kind = Søg brugere... +keyword_search_unavailable = Søgning efter nøgleord er ikke tilgængelig i øjeblikket. Kontakt venligst webstedets administrator. + +[aria] +navbar = Navigationslinje +footer = Sidefod +footer.software = Omkring dette software +footer.links = Links + +[heatmap] +number_of_contributions_in_the_last_12_months = %s bidrag inden for de sidste 12 måneder +contributions_zero = Ingen bidrag +contributions_format = {contributions} på {month} {day}, {year} +contributions_one = bidrag +contributions_few = bidragene +less = Mindre +more = Mere + +[editor] +buttons.heading.tooltip = Tilføj overskrift +buttons.bold.tooltip = Tilføj fed tekst +buttons.italic.tooltip = Tilføj kursiv tekst +buttons.quote.tooltip = Citat tekst +buttons.code.tooltip = Tilføj kode +buttons.link.tooltip = Tilføj et link +buttons.list.unordered.tooltip = Tilføj en punktliste +buttons.list.task.tooltip = Tilføj en liste over opgaver +buttons.list.ordered.tooltip = Tilføj en nummereret liste +buttons.mention.tooltip = Nævn en bruger eller et hold +buttons.ref.tooltip = Henvis til et problem eller pull-anmodning +buttons.enable_monospace_font = Aktiver monospace-skrifttype +buttons.disable_monospace_font = Deaktiver monospace-skrifttype +buttons.new_table.tooltip = Tilføj tabel +table_modal.header = Tilføj tabel +table_modal.placeholder.header = Hoved +table_modal.placeholder.content = Indhold +table_modal.label.rows = Rækker +table_modal.label.columns = Kolonner +buttons.unindent.tooltip = Udsortere genstande med ét niveau +buttons.indent.tooltip = Indlejring af genstande med ét niveau +buttons.switch_to_legacy.tooltip = Brug den gamle editor i stedet + +[filter] +string.asc = A - Z +string.desc = Z - A + +[error] +occurred = Der opstod en fejl +not_found = Målet kunne ikke findes. +network_error = Netværksfejl +server_internal = Intern serverfejl +report_message = Hvis du mener, at dette er en Forgejo-fejl, skal du søge efter problemer på Codeberg eller åbne et nyt problem, hvis det er nødvendigt. + +[startpage] +app_desc = En smertefri, selv-hostet Git-tjeneste +install = Nem at installere +platform = På tværs af platforme +platform_desc = Det er bekræftet, at Forgejo kører på frie operativsystemer som Linux og FreeBSD, samt forskellige CPU-arkitekturer. Vælg den du elsker! +lightweight = Letvægtig +lightweight_desc = Forgejo har lave minimale krav og kan køre på en billig Raspberry Pi. Spar din maskines energi! +license = Åben kildekode +license_desc = Få Forgejo! Slut dig til os ved at bidrage til at gøre dette projekt endnu bedre. Vær ikke genert over at være en bidragyder! +install_desc = Du skal blot køre binæren for din platform, send den med Docker, eller få det pakket. + +[install] +install = Installation +title = Indledende konfiguration +docker_helper = Hvis du kører Forgejo inde i Docker, skal du læse dokumentationen, før du ændrer nogen indstillinger. +require_db_desc = Forgejo kræver MySQL, PostgreSQL, SQLite3 eller TiDB (MySQL-protokol). +db_title = Database indstillinger +db_type = Database type +host = Vært +user = Brugernavn +password = Adgangskode +db_name = Database navn +db_schema = Schema +db_schema_helper = Lad stå tom for databasestandard ("offentlig"). +ssl_mode = SSL +reinstall_error = Du forsøger at installere i en eksisterende Forgejo-database +reinstall_confirm_check_1 = Dataene krypteret af SECRET_KEY i app.ini kan gå tabt: brugere kan muligvis ikke logge ind med 2FA/OTP, og mirrors fungerer muligvis ikke korrekt. Ved at markere dette felt bekræfter du, at den aktuelle app.ini-fil indeholder den korrekte SECRET_KEY. +reinstall_confirm_check_3 = Du bekræfter, at du er helt sikker på, at denne Forgejo kører med den korrekte app.ini placering, og at du er sikker på, at du skal gen-installere. Du bekræfter, at du anerkender ovenstående risici. +err_empty_db_path = SQLite3-databasestien må ikke være tom. +no_admin_and_disable_registration = Du kan ikke deaktivere brugerens selvregistrering uden at oprette en administratorkonto. +err_empty_admin_password = Administratoradgangskoden må ikke være tom. +err_empty_admin_email = Administrator-e-mailen må ikke være tom. +err_admin_name_is_reserved = Administratorbrugernavnet er ugyldigt, brugernavnet er reserveret +err_admin_name_pattern_not_allowed = Administratorbrugernavnet er ugyldigt, brugernavnet matcher et reserveret mønster +err_admin_name_is_invalid = Administratorbrugernavnet er ugyldigt +general_title = Generelle indstillinger +app_name = Instans titel +app_slogan_helper = Indtast dit instans slogan her. Lad være tom for at deaktivere. +lfs_path_helper = Filer sporet af Git LFS vil blive gemt i denne mappe. Lad være tom for at deaktivere. +run_user = Bruger at køre som +lfs_path = Git LFS rodsti +repo_path = Depot rodsti +domain = Server domæne +domain_helper = Domæne eller værtsadresse for serveren. +ssh_port = SSH server port +ssh_port_helper = Portnummer, der vil blive brugt af SSH-serveren. Lad være tomt for at deaktivere SSH-serveren. +http_port = HTTP lytte port +http_port_helper = Portnummer, der vil blive brugt af Forgejo-webserveren. +app_url = Base URL +log_root_path = Log sti +log_root_path_helper = Logfiler vil blive skrevet til denne mappe. +optional_title = Valgfrie indstillinger +email_title = E-mail-indstillinger +smtp_addr = SMTP vært +smtp_port = SMTP port +smtp_from = Send e-mail som +smtp_from_invalid = "Send e-mail som"-adressen er ugyldig +mailer_user = SMTP brugernavn +mailer_password = SMTP adgangskode +register_confirm = Kræv e-mail-bekræftelse for at registrere +mail_notify = Aktiver e-mailmeddelelser +server_service_title = Server- og tredjeparts tjenesteindstillinger +offline_mode = Aktiver lokal tilstand +disable_gravatar = Deaktiver Gravatar +disable_gravatar.description = Deaktiver brug af Gravatar eller andre tredjeparts avatar kilder. Standardbilleder vil blive brugt til bruger avatarer, medmindre de uploader deres egen avatar til instansen. +federated_avatar_lookup = Aktiver fødererede avatarer +federated_avatar_lookup.description = Slå avatarer op ved hjælp af Libravatar. +disable_registration = Deaktiver selvregistrering +allow_only_external_registration = Tillad kun registrering via eksterne tjenester +allow_only_external_registration.description = Brugere vil kun være i stand til at oprette nye konti ved at bruge konfigurerede eksterne tjenester. +openid_signin = Aktiver OpenID-logon +openid_signin.description = Tillad brugere at logge ind via OpenID. +app_slogan = Instans slogan +repo_path_helper = Fjerne Git depoter vil blive gemt i denne mappe. +smtp_from_helper = E-mailadresse Forgejo vil bruge. Indtast en almindelig e-mailadresse, eller brug formatet "Navn" . +run_user_helper = Operativsystemets brugernavn, som Forgejo kører som. Bemærk, at denne bruger skal have adgang til depotets rodsti. +app_name_helper = Indtast dit instans-navn her. Det vil blive vist på hver side. +offline_mode.description = Deaktiver tredjeparts indholdsleverings netværk og server alle ressourcer lokalt. +disable_registration.description = Kun instans administratoren vil være i stand til at oprette nye brugerkonti. Det anbefales stærkt at holde registreringen deaktiveret, medmindre du har til hensigt at være vært for en offentlig instans for alle og klar til at håndtere store mængder spamkonti. +openid_signup = Aktiver OpenID-selvregistrering +sqlite_helper = Filsti til SQLite3-databasen.
Indtast en absolut sti, hvis du kører Forgejo som en tjeneste. +path = Sti +reinstall_confirm_message = Geninstallation med en eksisterende Forgejo-database kan forårsage flere problemer. I de fleste tilfælde bør du bruge din eksisterende "app.ini" til at køre Forgejo. Hvis du ved, hvad du laver, skal du bekræfte følgende: +reinstall_confirm_check_2 = Depoterne og indstillingerne skal muligvis synkroniseres igen. Ved at markere dette felt bekræfter du, at du vil re-synkronisere hooks for depoter og authorized_keys-filen manuelt. Du bekræfter, at du vil sikre dig, at indstillingerne for depoter og mirror er korrekte. +app_url_helper = Base adresse for HTTP(S)-klone-URL'er og e-mail-meddelelser. +enable_captcha = Aktiver registrering CAPTCHA +enable_captcha.description = Kræv brugere at bestå CAPTCHA for at oprette konti. +require_sign_in_view = Kræv at logge ind for at se instansindhold +default_keep_email_private = Skjul e-mailadresser som standard +default_keep_email_private.description = Aktiver skjulning af e-mail-adresser for nye brugere som standard, så disse oplysninger ikke lækkes umiddelbart efter tilmelding. +default_allow_create_organization = Tillad oprettelse af organisationer som standard +default_enable_timetracking = Aktiver tidsregistrering som standard +default_enable_timetracking.description = Tillad som standard brug af tidssporings-funktion for nye depoter. +admin_title = Indstillinger for administratorkonto +admin_setting.description = Det er valgfrit at oprette en administratorkonto. Den første registrerede bruger bliver automatisk administrator. +admin_name = Administrator brugernavn +admin_password = Adgangskode +confirm_password = Bekræft adgangskode +admin_email = E-mailadresse +config_location_hint = Disse konfigurationsmuligheder vil blive gemt i: +install_btn_confirm = Installer Forgejo +invalid_db_setting = Databaseindstillingerne er ugyldige: %v +invalid_db_table = Databasetabellen "%s" er ugyldig: %v +invalid_repo_path = Depotets rodsti er ugyldig: %v +invalid_app_data_path = Appens datasti er ugyldig: %v +run_user_not_match = Brugernavnet som "bruger det skal køres som" er ikke det aktuelle brugernavn: %s -> %s +internal_token_failed = Kunne ikke generere intern token: %v +secret_key_failed = Kunne ikke generere hemmelig nøgle: %v +save_config_failed = Konfigurationen kunne ikke gemmes: %v +invalid_admin_setting = Administratorkonto indstillingen er ugyldig: %v +invalid_log_root_path = Log stien er ugyldig: %v +allow_dots_in_usernames = Tillad brugere at bruge prikker i deres brugernavne. Påvirker ikke eksisterende konti. +no_reply_address = Skjult e-mail-domæne +invalid_password_algorithm = Ugyldig hash-algoritme for adgangskode +enable_update_checker = Aktiver opdateringskontrol +env_config_keys = Miljøkonfiguration +env_config_keys_prompt = Følgende miljøvariabler vil også blive anvendt på din konfigurationsfil: +test_git_failed = Kunne ikke teste "git" kommandoen: %v +sqlite3_not_available = Denne Forgejo-version understøtter ikke SQLite3. Download venligst den officielle binære version fra %s (ikke "gobuild"-versionen). +no_reply_address_helper = Domænenavn til brugere med en skjult e-mailadresse. For eksempel vil brugernavnet "joe" blive logget i Git som "joe@noreply.example.org", hvis det skjulte e-mail-domæne er sat til "noreply.example.org". +require_sign_in_view.description = Begræns indholdsadgang til ind-loggede brugere. Gæster vil kun kunne besøge autentificerings sider.. +default_allow_create_organization.description = Tillad nye brugere at oprette organisationer som standard. Når denne mulighed er deaktiveret, skal en administrator give tilladelse til at oprette organisationer til nye brugere. +password_algorithm = Adgangskode hash algoritme +enable_update_checker_helper_forgejo = Den vil med jævne mellemrum tjekke for nye Forgejo versioner ved at tjekke en TXT DNS-posten på release.forgejo.org. +password_algorithm_helper = Indstil adgangskode-hash-algoritmen. Algoritmer har forskellige krav og styrke. Argon2-algoritmen er ret sikker, men bruger meget hukommelse og kan være upassende til små systemer. +openid_signup.description = Tillad brugere at oprette konti via OpenID, hvis selvregistrering er aktiveret. + +[home] +uname_holder = Brugernavn eller e-mailadresse +switch_dashboard_context = Skift instrumentpanel-kontekst +my_repos = Depoter +my_orgs = Organisationer +view_home = Se %s +filter = Andre filtre +filter_by_team_repositories = Filtrer efter holddepoter +feed_of = Feed of "%s" +show_archived = Arkiveret +show_both_archived_unarchived = Viser både arkiveret og ikke-arkiveret +show_only_archived = Viser kun arkiverede +show_only_unarchived = Viser kun ikke-arkiveret +show_private = Privat +show_only_private = Viser kun privat +show_only_public = Viser kun offentligt +issues.in_your_repos = I dine depoter +show_both_private_public = Viser både offentlige og private + +[explore] +repos = Depoter +users = Brugere +stars_one = %d stjerne +stars_few = %d stjerner +forks_one = %d fork +forks_few = %d forks +organizations = Organisationer +code = Kode +code_last_indexed_at = Sidst indekseret %s +relevant_repositories = Kun relevante depoter vises, vis ufiltrerede resultater. +go_to = Gå til +relevant_repositories_tooltip = Depoter som er forks, eller som ikke har noget emne, intet ikon og ingen beskrivelse, er skjult. + +[auth] +create_new_account = Registrer konto +disable_register_prompt = Registrering er deaktiveret. Kontakt venligst din side-administrator. +disable_register_mail = E-mailbekræftelse for registrering er deaktiveret. +manual_activation_only = Kontakt din side-administrator for at fuldføre aktiveringen. +remember_me = Husk denne enhed +forgot_password_title = Glemt adgangskode +forgot_password = Glemt adgangskode? +hint_register = Har du brug for en konto? Registrer dig nu. +sign_up_button = Registrer nu. +sign_up_successful = Kontoen blev oprettet. Velkommen! +must_change_password = Opdater din adgangskode +allow_password_change = Kræv, at brugeren ændrer adgangskode (anbefales) +reset_password_mail_sent_prompt = En bekræftelses-e-mail er blevet sendt til %s. For at fuldføre kontogendannelses-processen skal du tjekke din indbakke og følge det medfølgende link inden for de næste %s. +active_your_account = Aktiver din konto +account_activated = Kontoen er blevet aktiveret +prohibit_login = Kontoen er suspenderet +prohibit_login_desc = Din konto er blevet suspenderet fra interaktion med instansen. Kontakt instans-administratoren for at få adgang igen. +change_unconfirmed_email_summary = Skift den e-mailadresse, aktiveringsmail sendes til. +change_unconfirmed_email_error = Kan ikke ændre e-mailadressen: %v +resend_mail = Klik her for at sende din aktiverings-e-mail igen +send_reset_mail = Send gendannelses-e-mail +reset_password = Kontogendannelse +invalid_code = Din bekræftelseskode er ugyldig eller er udløbet. +invalid_code_forgot_password = Din bekræftelseskode er ugyldig eller er udløbet. Klik her for at starte en ny session. +invalid_password = Din adgangskode stemmer ikke overens med den adgangskode, der blev brugt til at oprette kontoen. +reset_password_helper = Gendan konto +resent_limit_prompt = Du har allerede anmodet om en aktiverings-e-mail for nylig. Vent venligst 3 minutter, og prøv igen. +reset_password_wrong_user = Du er logget ind som %s, men linket til kontogendannelse er beregnet til %s +confirmation_mail_sent_prompt = En ny bekræftelses-e-mail er blevet sendt til %s. For at fuldføre registreringsprocessen skal du tjekke din indbakke og følge det medfølgende link inden for de næste %s. Hvis e-mailen er forkert, kan du logge ind og anmode om, at endnu en bekræftelses-e-mail sendes til en anden adresse. +change_unconfirmed_email = Hvis du har opgivet den forkerte e-mailadresse under tilmeldingen, kan du ændre den nedenfor, og der vil i stedet blive sendt en bekræftelse til den nye adresse. +hint_login = Har du allerede en konto? Log ind nu! +has_unconfirmed_mail = Hej %s, du har en ubekræftet e-mailadresse (%s). Hvis du ikke har modtaget en bekræftelses-e-mail eller har brug for at sende en ny, bedes du klikke på knappen nedenfor. +password_too_short = Adgangskodelængden må ikke være mindre end %d tegn. +non_local_account = Ikke-lokale brugere kan ikke opdatere deres adgangskode via Forgejo-webgrænsefladen. +verify = Verificere +unauthorized_credentials = Legitimationsoplysningerne er forkerte eller er udløbet. Prøv din kommando igen, eller se %s for at få flere oplysninger +scratch_code = Skrabekode +use_scratch_code = Brug en skrabekode +use_onetime_code = Brug en engangskode +twofa_scratch_used = Du har brugt din skrabekode. Du er blevet omdirigeret til siden med to-faktorindstillinger, så du kan fjerne din enhedstilmelding eller generere en ny skrabekode. +twofa_passcode_incorrect = Din passcode er forkert. Hvis du har forlagt din enhed, skal du bruge din skrabekode til at logge ind. +twofa_scratch_token_incorrect = Din skrabekode er forkert. +login_userpass = Login +oauth_signup_tab = Registrer ny konto +oauth_signup_title = Fuldfør ny konto +oauth_signup_submit = Gennemfør konto +oauth_signin_tab = Link til en eksisterende konto +oauth_signin_title = Log ind for at godkende linket konto +oauth_signin_submit = Link konto +oauth.signin.error = Der opstod en fejl under behandling af godkendelsesanmodningen. Hvis denne fejl fortsætter, bedes du kontakte webstedets administrator. +oauth.signin.error.access_denied = Godkendelsesanmodningen blev afvist. +oauth.signin.error.temporarily_unavailable = Godkendelse mislykkedes, fordi godkendelsesserveren midlertidigt ikke er tilgængelig. Prøv venligst igen senere. +openid_connect_submit = Forbind +openid_connect_title = Opret forbindelse til en eksisterende konto +openid_register_title = Opret ny konto +openid_register_desc = Den valgte OpenID URI er ukendt. Knyt den til en ny konto her. +disable_forgot_password_mail = Kontogendannelse er deaktiveret, fordi der ikke er konfigureret nogen e-mail. Kontakt venligst din webstedsadministrator. +email_domain_blacklisted = Du kan ikke registrere dig med din e-mailadresse. +authorize_application = Godkend Applikation +authorize_redirect_notice = Du vil blive omdirigeret til %s, hvis du godkender denne applikation. +authorize_application_created_by = Denne applikation blev oprettet af %s. +authorize_application_description = Hvis du giver adgangen, vil den være i stand til at få adgang til og skrive til alle dine kontooplysninger, inklusive private depoter og organisationer. +authorize_title = Tillad "%s" at få adgang til din konto? +authorization_failed = Godkendelse mislykkedes +password_pwned_err = Kunne ikke fuldføre anmodningen til HaveIBeenPwned +last_admin = Du kan ikke fjerne den sidste admin. Der skal være mindst én administrator. +back_to_sign_in = Tilbage til Log ind +sign_in_openid = Fortsæt med OpenID +openid_signin_desc = Indtast din OpenID URI. For eksempel: alice.openid.example.org eller https://openid.example.org/alice. +disable_forgot_password_mail_admin = Kontogendannelse er kun tilgængelig, når e-mail er konfigureret. Konfigurer venligst e-mail for at aktivere kontogendannelse. +password_pwned = Den adgangskode, du valgte, er på en liste over stjålne adgangskoder, der tidligere er blevet afsløret i forbindelse med offentlige databrud. Prøv venligst igen med en anden adgangskode, og overvej også at ændre denne adgangskode et andet sted. +openid_connect_desc = Den valgte OpenID URI er ukendt. Knyt den til en ny konto her. +authorization_failed_desc = Godkendelsen mislykkedes, fordi vi har registreret en ugyldig anmodning. Kontakt venligst vedligeholderen af den app, du har forsøgt at godkende. + +[mail] +view_it_on = Se det på %s +reply = eller svar direkte på denne e-mail +link_not_working_do_paste = Virker linket ikke? Prøv at kopiere og indsætte det i din browsers URL-linje. +hi_user_x = Hej %s, +activate_account = Aktiver venligst din konto +activate_account.text_1 = Hej %[1]s, tak, fordi du registrerede dig hos %[2]s! +activate_account.text_2 = Klik venligst på følgende link for at aktivere din konto inden for %s: +activate_email = Bekræft din e-mailadresse +admin.new_user.subject = Ny bruger %s har lige tilmeldt sig +admin.new_user.user_info = Brugeroplysninger +admin.new_user.text = Venligst klik her for at administrere denne bruger fra administrationspanelet. +register_notify = Velkommen til %s +register_notify.text_1 = dette er din registreringsbekræftelses-e-mail for %s! +register_notify.text_3 = Hvis en anden har lavet denne konto for dig, skal du først indstille din adgangskode. +reset_password = Gendan din konto +password_change.subject = Din adgangskode er blevet ændret +password_change.text_1 = Adgangskoden til din konto er lige blevet ændret. +primary_mail_change.subject = Din primære mail er blevet ændret +totp_disabled.subject = TOTP er blevet deaktiveret +totp_disabled.text_1 = Tidsbaseret engangsadgangskode (TOTP) på din konto er netop blevet deaktiveret. +totp_disabled.no_2fa = Der er ikke længere konfigureret andre 2FA-metoder, hvilket betyder, at det ikke længere er nødvendigt at logge ind på din konto hos 2FA. +removed_security_key.subject = En sikkerhedsnøgle er blevet fjernet +removed_security_key.text_1 = Sikkerhedsnøglen "%[1]s" er lige blevet fjernet fra din konto. +account_security_caution.text_1 = Hvis dette var dig, så kan du roligt ignorere denne mail. +totp_enrolled.subject = Du har aktiveret TOTP som 2FA-metode +totp_enrolled.text_1.has_webauthn = Du har lige aktiveret TOTP for din konto. Dette betyder, at du for alle fremtidige login til din konto kan bruge TOTP som en 2FA-metode eller bruge en af dine sikkerhedsnøgler. +register_success = Registreringen lykkedes +issue_assigned.pull = @%[1]s har tildelt dig at trække anmodning %[2]s i depotet %[3]s. +issue_assigned.issue = @%[1]s har tildelt dig et problem %[2]s i depotet %[3]s. +register_notify.text_2 = Du kan logge ind på din konto med dit brugernavn: %s +primary_mail_change.text_1 = Din kontos primære mail er lige blevet ændret til %[1]s. Det betyder, at denne e-mailadresse ikke længere vil modtage e-mail-meddelelser for din konto. +account_security_caution.text_2 = Hvis dette ikke var dig, er din konto kompromitteret. Kontakt venligst administratorerne af dette websted. +activate_email.text = Klik venligst på følgende link for at bekræfte din e-mailadresse inden for %s: +reset_password.text = Hvis dette var dig, skal du klikke på følgende link for at gendanne din konto inden for %s: +removed_security_key.no_2fa = Der er ikke længere konfigureret andre 2FA-metoder, hvilket betyder, at det ikke længere er nødvendigt at logge ind på din konto hos 2FA. +totp_enrolled.text_1.no_webauthn = Du har lige aktiveret TOTP for din konto. Det betyder, at du for alle fremtidige login til din konto skal bruge TOTP som 2FA-metode. +issue.x_mentioned_you = @%s nævnte dig: +issue.action.force_push = %[1]s tvangs pushed %[2]s fra %[3]s til %[4]s. +issue.action.push_1 = @%[1]s pushed %[3]d commit til %[2]s +issue.action.push_n = @%[1]s pushed %[3]d commits til %[2]s +issue.action.close = @%[1]s lukket #%[2]d. +issue.action.reopen = @%[1]s genåbnet #%[2]d. +issue.action.merge = @%[1]s merged #%[2]d ind i %[3]s. +issue.action.approve = @%[1]s godkendte denne pull-anmodning. +issue.action.reject = @%[1]s anmodede om ændringer på denne pull-anmodning. +issue.action.review = @%[1]s kommenterede denne pull-anmodning. +issue.action.review_dismissed = @%[1]s afviste den seneste kontrol fra %[2]s for denne pull-anmodning. +issue.action.ready_for_review = @%[1]s markerede denne pull-anmodning klar til gennemgang. +issue.action.new = @%[1]s oprettede #%[2]d. +issue.in_tree_path = I %s: +release.new.subject = %s i %s udgivet +release.new.text = @%[1]s udgivet %[2]s i %[3]s +release.title = Title: %s +release.note = Note: +release.downloads = Downloads: +release.download.zip = Kildekode (ZIP) +release.download.targz = Kildekode (TAR.GZ) +repo.transfer.subject_to = %s ønsker at overføre depotet "%s" til %s +repo.transfer.subject_to_you = %s ønsker at overføre depotet "%s" til dig +repo.transfer.to_you = dig +repo.transfer.body = For at acceptere eller afvise det, besøg %s eller ignorer det. +repo.collaborator.added.subject = %s føjede dig til %s som samarbejdspartner +repo.collaborator.added.text = Du er blevet tilføjet som samarbejdspartner til depotet: +team_invite.subject = %[1]s har inviteret dig til at deltage i %[2]s organisationen +team_invite.text_1 = %[1]s har inviteret dig til at deltage i teamet %[2]s i organisationen %[3]s. +team_invite.text_2 = Klik venligst på følgende link for at blive medlem af holdet: +team_invite.text_3 = Note: Denne invitation var beregnet til %[1]s. Hvis du ikke forventede denne invitation, kan du ignorere denne e-mail. + +[modal] +yes = Ja +no = Nej +confirm = Bekærft +cancel = Annuller +modify = Updatere + +[form] +UserName = Brugernavn +FullName = Fulde navn +Description = Beskrivelse +Pronouns = Stedord +Biography = Biografi +Website = Websted +Location = Lokation +RepoName = Depot navn +Email = E-mailadresse +Password = Adgangskode +Retype = Bekræft adgangskode +PayloadUrl = Payload URL +TeamName = Holdnavn +AuthName = Autorisationsnavn +AdminEmail = Admin email +To = Gren navn +AccessToken = Adgangstoken +NewBranchName = Nyt gren navn +CommitSummary = Commit oversigt +CommitMessage = Commit besked +CommitChoice = Commit valg +TreeName = Fil sti +Content = Indhold +SSPISeparatorReplacement = Separator +SSPIDefaultLanguage = Standard sprog +require_error = ` må ikke være tomt.` +alpha_dash_error = ` bør kun indeholde alfanumeriske, bindestreg ("-") og understregningstegn ("_").` +alpha_dash_dot_error = ` bør kun indeholde alfanumeriske tegn, bindestreg ("-"), understregning ("_") og prik ("".").` +git_ref_name_error = ` skal være et veludformet Git-referencenavn.` +size_error = ` skal være størrelse %s.` +min_size_error = ` skal indeholde mindst %s tegn.` +email_error = ` er ikke en gyldig e-mailadresse.` +url_error = `"%s" er ikke en gyldig URL.` +include_error = ` skal indeholde understreng "%s".` +glob_pattern_error = ` globmønster er ugyldigt: %s.` +regex_pattern_error = ` regex-mønster er ugyldigt: %s.` +invalid_group_team_map_error = ` mapping er ugyldig: %s` +unknown_error = Ukendt fejl: +captcha_incorrect = CAPTCHA-koden er forkert. +password_not_match = Adgangskoderne stemmer ikke overens. +lang_select_error = Vælg et sprog fra listen. +username_been_taken = Brugernavnet er allerede taget. +username_change_not_local_user = Ikke-lokale brugere må ikke ændre deres brugernavn. +repo_name_been_taken = Depotnavnet er allerede brugt. +repository_force_private = Tving Privat er aktiveret: private depoter kan ikke gøres offentlige. +repository_files_already_exist = Der findes allerede filer for dette depot. Kontakt systemadministratoren. +repository_files_already_exist.delete = Der findes allerede filer for dette depot. Du skal slette dem. +visit_rate_limit = Fjernbesøg adresseret takstbegrænsning. +2fa_auth_required = Fjernbesøg krævede godkendelse af to faktorer. +org_name_been_taken = Organisationsnavnet er allerede taget. +team_name_been_taken = Holdnavnet er allerede taget. +team_no_units_error = Tillad adgang til mindst én depotsektion. +email_been_used = E-mailadressen er allerede brugt. +email_invalid = E-mailadressen er ugyldig. +openid_been_used = OpenID-adressen "%s" er allerede brugt. +password_complexity = Adgangskoden opfylder ikke kompleksitetskravene: +password_lowercase_one = Mindst ét lille bogstav +password_uppercase_one = Mindst ét stort tegn +password_digit_one = Mindst ét ciffer +enterred_invalid_repo_name = Det depotnavn, du indtastede, er forkert. +enterred_invalid_org_name = Det organisationsnavn, du har indtastet, er forkert. +enterred_invalid_owner_name = Det nye ejernavn er ikke gyldigt. +enterred_invalid_password = Den adgangskode, du indtastede, er forkert. +unset_password = Login-brugeren har ikke angivet adgangskoden. +user_not_exist = Brugeren eksisterer ikke. +team_not_exist = Holdet eksisterer ikke. +last_org_owner = Du kan ikke fjerne den sidste bruger fra "ejere"-teamet. Der skal være mindst én ejer for en organisation. +duplicate_invite_to_team = Brugeren var allerede inviteret som et holdmedlem. +organization_leave_success = Du har forladt organisationen %s. +invalid_ssh_key = Kan ikke bekræfte din SSH-nøgle: %s +invalid_gpg_key = Kan ikke bekræfte din GPG-nøgle: %s +invalid_ssh_principal = Ugyldig principal: %s +unable_verify_ssh_key = Kan ikke bekræfte SSH-nøglen, dobbelttjek den for fejl. +auth_failed = Godkendelse mislykkedes: %v +still_own_repo = Din konto ejer et eller flere depoter, slet eller overfør dem først. +still_has_org = Din konto er medlem af en eller flere organisationer, forlad dem først. +still_own_packages = Din konto ejer en eller flere pakker, slet dem først. +org_still_own_packages = Denne organisation ejer stadig en eller flere pakker, slet dem først. +target_branch_not_exist = Gren målet eksisterer ikke. +admin_cannot_delete_self = Du kan ikke slette dig selv, når du er administrator. Fjern venligst dine administratorrettigheder først. +required_prefix = Input skal starte med "%s" +username_error = ` kan kun indeholde alfanumeriske tegn ("0-9","a-z","A-Z"), bindestreg ("-"), understregning ("_") og prik ("."). Det kan ikke begynde eller slutte med ikke-alfanumeriske tegn, og på hinanden følgende ikke-alfanumeriske tegn er også forbudt.` +max_size_error = ` må højst indeholde %s tegn.` +repository_files_already_exist.adopt_or_delete = Der findes allerede filer for dette depot. Enten adopter dem eller slet dem. +org_still_own_repo = Denne organisation ejer stadig et eller flere depoter, slet eller overfør dem først. +username_error_no_dots = ` kan kun indeholde alfanumeriske tegn ("0-9","a-z","A-Z"), bindestreg ("-") og understregning ("_"). Det kan ikke begynde eller slutte med ikke-alfanumeriske tegn, og på hinanden følgende ikke-alfanumeriske tegn er også forbudt.` +username_password_incorrect = Brugernavn eller adgangskode er forkert. +repository_files_already_exist.adopt = Filer findes allerede for dette depot og kan kun adopteres. +password_special_one = Mindst ét specialtegn (tegnsætning, parenteser, anførselstegn osv.) +unsupported_login_type = Login typen understøttes ikke for at slette kontoen. +cannot_add_org_to_team = En organisation kan ikke tilføjes som et holdmedlem. +must_use_public_key = Nøglen du har angivet er en privat nøgle. Lad være med at uploade din private nøgle nogen steder. Brug din offentlige nøgle i stedet. + +[user] +change_avatar = Skift din avatar… +joined_on = Tilmeldte sig den %s +repositories = Depoter +activity = Offentlig aktivitet +followers.title.one = Følger +followers.title.few = Følgere +following.title.one = Følger +following.title.few = Følger +followers_one = %d følger +followers_few = %d følgere +following_one = %d følger +following_few = %d følger +follow = Følg +unfollow = Fjern følg +block_user = Bloker bruger +block_user.detail = Bemærk venligst, at blokering af en bruger har andre effekter, såsom: +block_user.detail_1 = I vil holde op med at følge hinanden og vil ikke være i stand til at følge hinanden. +block_user.detail_2 = Denne bruger vil ikke være i stand til at interagere med de depoter, du ejer, eller de problemer og kommentarer, du har oprettet. +block_user.detail_3 = I vil ikke være i stand til at tilføje hinanden som depot-samarbejdspartnere. +follow_blocked_user = Du kan ikke følge denne bruger, fordi du har blokeret denne bruger, eller denne bruger har blokeret dig. +starred = Stjernemarkerede depoter +watched = Overvågede depoter +code = Kode +overview = Oversigt +block = Block +user_bio = Biografi +email_visibility.limited = Din e-mailadresse er synlig for alle godkendte brugere +show_on_map = Vis dette sted på et kort +settings = Brugerindstillinger +public_activity.visibility_hint.admin_public = Denne aktivitet er synlig for alle, men som administrator kan du også se interaktioner i private rum. +public_activity.visibility_hint.self_private = Din aktivitet er kun synlig for dig og instans-administratorerne. Konfigurer. +public_activity.visibility_hint.admin_private = Denne aktivitet er synlig for dig, fordi du er administrator, men brugeren ønsker, at den forbliver privat. +form.name_reserved = Brugernavnet "%s" er reserveret. +form.name_pattern_not_allowed = Mønsteret "%s" er ikke tilladt i et brugernavn. +form.name_chars_not_allowed = Brugernavnet "%s" indeholder ugyldige tegn. +unblock = Fjern blokering +projects = Projekter +disabled_public_activity = Denne bruger har deaktiveret den offentlige synlighed af aktiviteten. +public_activity.visibility_hint.self_public = Din aktivitet er synlig for alle, undtagen interaktioner i private rum. Konfigurer. +public_activity.visibility_hint.self_private_profile = Din aktivitet er kun synlig for dig og instans-administratorerne, fordi din profil er privat. Konfigurer. + +[settings] +profile = Profil +account = Konto +appearance = Udseende +password = Adgangskode +security = Sikkerhed +avatar = Avatar +ssh_gpg_keys = SSH / GPG nøgler +applications = Applikationer +orgs = Organisationer +repos = Depoter +delete = Slet konto +twofa = To-faktor-godkendelse (TOTP) +organization = Organisationer +uid = UID +webauthn = To-faktor-godkendelse (sikkerhedsnøgler) +blocked_users = Blokerede brugere +public_profile = Offentlig profil +location_placeholder = Del din omtrentlige placering med andre +password_username_disabled = Ikke-lokale brugere må ikke ændre deres brugernavn. Kontakt venligst din webstedsadministrator for flere detaljer. +full_name = Fulde navn +website = Websted +location = Lokation +pronouns = Stedord +pronouns_custom = Brugerdefineret +pronouns_unspecified = Uspecificeret +update_theme = Skift tema +update_language = Skift sprog +update_language_success = Sproget er blevet opdateret. +update_profile_success = Din profil er blevet opdateret. +change_username = Dit brugernavn er blevet ændret. +change_username_redirect_prompt = Det gamle brugernavn vil omdirigere, indtil nogen gør krav på det. +continue = Fortsæt +cancel = Annuller +language = Sprog +language.title = Standard sprog +language.description = Dette sprog gemmes på din konto og bruges som standard, når du logger ind. +ui = Tema +additional_repo_units_hint = Foreslå at aktivere yderligere depotenheder +additional_repo_units_hint_description = Vis et "Aktiver mere"-tip for depoter, der ikke har alle tilgængelige enheder aktiveret. +update_hints = Opdater tips +hints = Tips +update_hints_success = Tips er blevet opdateret. +hidden_comment_types = Skjulte kommentartyper +hidden_comment_types.ref_tooltip = Kommentarer, hvor dette problem blev refereret fra en anden problem/commit/… +hidden_comment_types.issue_ref_tooltip = Kommentarer, hvor brugeren ændrer grenen/taget, der er knyttet til problemet +comment_type_group_reference = Reference +comment_type_group_label = Etiket +comment_type_group_milestone = Milepæl +comment_type_group_assignee = Udpegningsmodtager +comment_type_group_title = Title +comment_type_group_branch = Gren +comment_type_group_time_tracking = Tidsregistrering +comment_type_group_deadline = Tidsfrist +comment_type_group_dependency = Dependency +comment_type_group_lock = Lås status +comment_type_group_review_request = Gennemgå anmodning +comment_type_group_pull_request_push = Tilføjet commits +comment_type_group_project = Projekt +comment_type_group_issue_ref = Problem henvisning +privacy = Privatliv +keep_activity_private = Skjul aktivitet fra profilsiden +lookup_avatar_by_mail = Slå avatar up efter e-mailadresse +enable_custom_avatar = Brug tilpasset avatar +delete_current_avatar = Slet nuværende avatar +uploaded_avatar_not_a_image = Den uploadede fil er ikke et billede. +update_avatar_success = Din avatar er blevet opdateret. +update_user_avatar_success = Brugerens avatar er blevet opdateret. +change_password = Skift adgangskode +update_password = Opdater adgangskode +old_password = Nuværende adgangskode +new_password = Ny adgangskode +retype_new_password = Bekræft ny adgangskode +password_incorrect = Den aktuelle adgangskode er forkert. +password_change_disabled = Ikke-lokale brugere kan ikke opdatere deres adgangskode via Forgejo-webgrænsefladen. +manage_emails = Administrer e-mailadresser +manage_themes = Standard tema +manage_openid = OpenID-adresser +theme_desc = Dette tema vil blive brugt til webgrænsefladen, når du er logget ind. +primary = Primær +activated = Aktiveret +requires_activation = Kræver aktivering +primary_email = Gør til primær +activate_email = Send aktivering +activations_pending = Aktiveringer afventer +can_not_add_email_activations_pending = Der er en afventende aktivering, prøv igen om et par minutter, hvis du vil tilføje en ny e-mail. +delete_email = Slet +email_deletion = Fjern e-mailadresse +email_deletion_success = E-mailadressen er blevet fjernet. +theme_update_success = Dit tema blev opdateret. +theme_update_error = Det valgte tema findes ikke. +openid_deletion = Fjern OpenID-adresse +openid_deletion_desc = Fjernelse af denne OpenID-adresse fra din konto vil forhindre dig i at logge ind med den. Fortsætte? +openid_deletion_success = OpenID-adressen er blevet fjernet. +add_new_email = Tilføj e-mailadresse +add_new_openid = Tilføj ny OpenID URI +language.localization_project = Hjælp os med at oversætte Forgejo til dit sprog! Få flere oplysninger. +update_language_not_found = Sprog "%s" er ikke tilgængeligt. +hidden_comment_types_description = Kommentartyper, der er markeret her, vil ikke blive vist på problemsider. Hvis du f.eks. markerer "Etiket", fjernes alle " tilføjede/fjernede " kommentarer. +update_profile = Opdater profil +change_username_prompt = Note: Ændring af dit brugernavn ændrer også din konto-URL. +biography_placeholder = Fortæl andre lidt om dig selv! (Markdown understøttes) +profile_desc = Styr, hvordan din profil vises til andre brugere. Din primære e-mailadresse vil blive brugt til meddelelser, gendannelse af adgangskode og webbaserede Git-operationer. +saved_successfully = Dine indstillinger blev gemt. +keep_activity_private.description = Din offentlige aktivitet vil kun være synlig for dig og instans-administratorerne. +email_desc = Din primære e-mailadresse vil blive brugt til meddelelser, gendannelse af adgangskode og, forudsat at den ikke er skjult, webbaserede Git-operationer. +uploaded_avatar_is_too_big = Den uploadede filstørrelse (%d KiB) overstiger den maksimale størrelse (%d KiB). +email_deletion_desc = E-mailadressen og relaterede oplysninger vil blive fjernet fra din konto. Git commits af denne e-mailadresse forbliver uændret. Fortsætte? +choose_new_avatar = Vælg ny avatar +update_avatar = Opdater avatar +change_password_success = Din adgangskode er blevet opdateret. Log ind med din nye adgangskode fra nu af. +add_email = Tilføj e-mailadresse +add_openid = Tilføj OpenID URI +add_email_confirmation_sent = En bekræftelses-e-mail er blevet sendt til "%s". For at bekræfte din e-mailadresse, tjek venligst din indbakke og følg det medfølgende link inden for de næste %s. +add_openid_success = Den nye OpenID-adresse er blevet tilføjet. +keep_email_private = Skjul e-mailadresse +openid_desc = OpenID lader dig uddelegere godkendelse til en ekstern udbyder. +manage_ssh_keys = Administrer SSH-nøgler +manage_ssh_principals = Administrer SSH-certifikatprincippere +manage_gpg_keys = Administrer GPG-nøgler +add_key = Tilføj nøgle +ssh_desc = Disse offentlige SSH-nøgler er knyttet til din konto. De tilsvarende private nøgler giver fuld adgang til dine depoter. SSH-nøgler, der er blevet bekræftet, kan bruges til at bekræfte SSH-signerede Git-commits. +principal_desc = Disse SSH-certifikatprincipper er knyttet til din konto og giver fuld adgang til dine depoter. +ssh_helper = Har du brug for hjælp? Se vejledningen til at oprette dine egne SSH-nøgler eller løse almindelige problemer a> du kan støde på når du bruger SSH. +gpg_helper = Har du brug for hjælp? Se vejledningen om GPG. +key_content_gpg_placeholder = Begynder med "-----BEGIN PGP PUBLIC KEY BLOCK-----" +add_new_principal = Tilføj principal +ssh_key_been_used = Denne SSH-nøgle er allerede blevet tilføjet til serveren. +ssh_key_name_used = En SSH-nøgle med samme navn findes allerede på din konto. +ssh_principal_been_used = Denne principal er allerede blevet tilføjet til serveren. +gpg_key_id_used = Der findes allerede en offentlig GPG-nøgle med samme id. +gpg_no_key_email_found = Denne GPG-nøgle matcher ikke nogen aktiveret e-mail-adresse tilknyttet din konto. Det kan stadig tilføjes, hvis du underskriver det medfølgende token. +gpg_key_matched_identities = Matchede identiteter: +gpg_key_verified = Verificeret nøgle +gpg_key_verified_long = Nøglen er blevet bekræftet med et token og kan bruges til at bekræfte commits, der matcher alle aktiverede e-mailadresser for denne bruger ud over eventuelle matchede identiteter for denne nøgle. +gpg_key_verify = Bekræft +gpg_invalid_token_signature = Den medfølgende GPG-nøgle, signatur og token stemmer ikke overens, eller token er forældet. +gpg_token_required = Du skal angive en underskrift for nedenstående token +gpg_token = Token +gpg_token_signature = Pansret GPG-signatur +key_signature_gpg_placeholder = Begynder med "-----BEGIN PGP SIGNATURE-----" +verify_gpg_key_success = GPG-nøglen "%s" er blevet bekræftet. +ssh_key_verified = Verificeret nøgle +ssh_token_required = Du skal angive en underskrift for nedenstående token +ssh_token = Token +ssh_token_help = Du kan generere en signatur ved at bruge: +ssh_token_signature = Pansret SSH signatur +key_signature_ssh_placeholder = Begynder med "-----BEGIN SSH SIGNATURE-----" +verify_ssh_key_success = SSH-nøglen "%s" er blevet bekræftet. +subkeys = Undernøgler +key_name = Nøglenavn +key_id = Nøgle ID +key_content = Indhold +principal_content = Indhold +add_key_success = SSH-nøglen "%s" er blevet tilføjet. +add_principal_success = SSH-certifikatprincippet "%s" er blevet tilføjet. +delete_key = Slet +ssh_key_deletion = Slet SSH-nøgle +gpg_key_deletion = Slet GPG-nøglen +ssh_principal_deletion = Slet SSH Certificate Principal +gpg_key_deletion_desc = Fjernelse af en GPG-nøgle afbekræfter commits, der er underskrevet af den. Fortsætte? +ssh_principal_deletion_desc = Fjernelse af en SSH Certificate Principal tilbagekalder dens adgang til din konto. Fortsætte? +ssh_key_deletion_success = SSH-nøglen er blevet fjernet. +ssh_principal_deletion_success = Principal er blevet fjernet. +added_on = Tilføjet den %s +valid_until_date = Gyldig indtil %s +last_used = Sidst brugt på +no_activity = Ingen nylig aktivitet +can_read_info = Læs +can_write_info = Skriv +token_state_desc = Dette token er blevet brugt inden for de sidste 7 dage +principal_state_desc = Denne principal er blevet brugt inden for de sidste 7 dage +show_openid = Vis på profil +hide_openid = Skjul fra profil +ssh_externally_managed = Denne SSH-nøgle administreres eksternt for denne bruger +manage_access_token = Adgangstoken +generate_new_token = Generer nyt token +tokens_desc = Disse tokens giver adgang til din konto ved hjælp af Forgejo API. +token_name = Token navn +generate_token = Generer token +generate_token_success = Dit nye token er blevet genereret. Kopier den nu, da den ikke vises igen. +delete_token = Slet +access_token_deletion = Slet adgangstoken +access_token_deletion_desc = Sletning af et token vil tilbagekalde adgangen til din konto for applikationer, der bruger den. Dette kan ikke fortrydes. Fortsætte? +repo_and_org_access = Depot og organisationsadgang +permissions_public_only = Kun offentlig +permissions_access_all = Alle (offentlige, private og begrænsede) +select_permissions = Vælg tilladelser +permission_no_access = Ingen adgang +permission_read = Læs +permission_write = Læs og skriv +permissions_list = Tilladelser: +manage_oauth2_applications = Administrer OAuth2-applikationer +edit_oauth2_application = Rediger OAuth2-applikation +add_email_success = Den nye e-mailadresse er blevet tilføjet. +key_content_ssh_placeholder = Begynder med "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com", eller "sk-ssh-ed25519@openssh.com" +gpg_key_matched_identities_long = De indlejrede identiteter i denne nøgle matcher de følgende aktiverede e-mailadresser for denne bruger. Commits, der matcher disse e-mailadresser, kan bekræftes med denne nøgle. +gpg_key_deletion_success = GPG-nøglen er blevet fjernet. +email_preference_set_success = E-mail-præference er blevet indstillet. +keep_email_private_popup = Dette vil skjule din e-mailadresse fra din profil. Det vil ikke længere være standard for commits foretaget via webgrænsefladen, såsom filupload og redigeringer, og vil ikke blive brugt til merge commits. I stedet kan en speciel adresse %s bruges til at knytte commits til din konto. Bemærk, at ændring af denne mulighed ikke vil påvirke eksisterende commits. +gpg_desc = Disse offentlige GPG-nøgler er knyttet til din konto og bruges til at bekræfte dine commits. Opbevar dine private nøgler sikkert, da de giver dig mulighed for at underskrive commits med din identitet. +gpg_token_help = Du kan generere en signatur ved at bruge: +ssh_key_verified_long = Nøglen er blevet bekræftet med et token og kan bruges til at bekræfte commits, der matcher enhver aktiveret e-mail-adresse for denne bruger. +ssh_key_deletion_desc = Fjernelse af en SSH-nøgle tilbagekalder dens adgang til din konto. Fortsætte? +ssh_signonly = SSH er i øjeblikket deaktiveret, så disse nøgler bruges kun til bekræftelse af commit signatur. +at_least_one_permission = Du skal vælge mindst én tilladelse for at oprette et token +ssh_key_verify = Bekræft +ssh_invalid_token_signature = Den angivne SSH-nøgle, signatur eller token stemmer ikke overens, eller token er forældet. +add_gpg_key_success = GPG-nøglen "%s" er blevet tilføjet. +valid_forever = Gyldig for evigt +ssh_disabled = SSH er deaktiveret +key_state_desc = Denne nøgle er blevet brugt inden for de sidste 7 dage +generate_token_name_duplicate = %s er allerede blevet brugt som applikationsnavn. Brug venligst en ny. +delete_token_success = Tokenet er blevet slettet. Applikationer, der bruger den, har ikke længere adgang til din konto. +access_token_desc = Valgte tokentilladelser begrænser kun autorisation til de tilsvarende API-ruter. Læs dokumentationen for at få flere oplysninger. +oauth2_applications_desc = OAuth2-applikationer gør det muligt for din tredjepartsapplikation at godkende brugere sikkert i denne Forgejo-instans. +remove_oauth2_application = Slet OAuth2-applikation +remove_oauth2_application_desc = Sletning af en OAuth2-applikation vil tilbagekalde adgangen til alle signerede adgangstokens. Vil du fortsætte? +remove_oauth2_application_success = Ansøgningen er blevet slettet. +create_oauth2_application = Opret en ny OAuth2-applikation +create_oauth2_application_button = Opret applikation +create_oauth2_application_success = Du har oprettet en ny OAuth2-applikation. +update_oauth2_application_success = Du har opdateret OAuth2-applikationen. +oauth2_application_name = Applikationsnavn +oauth2_redirect_uris = Omdiriger URI'er. Brug venligst en ny linje for hver URI. +save_application = Gem +oauth2_client_id = Klient ID +oauth2_client_secret = Klient hemmelighed +oauth2_regenerate_secret = Genskab hemmeligheden +oauth2_regenerate_secret_hint = Har du mistet din hemmelighed? +oauth2_client_secret_hint = Hemmeligheden vil ikke blive vist igen, når du forlader eller opdaterer denne side. Sørg for, at du har gemt den. +oauth2_application_edit = Redigere +oauth2_confidential_client = Fortrolig klient. Vælg for apps, der holder hemmeligheden fortrolig, såsom webapps. Vælg ikke for indbyggede apps, herunder desktop- og mobilapps. \ No newline at end of file diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 12c241accc..2b28ab13af 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -814,7 +814,7 @@ manage_emails=E-Mail-Adressen verwalten manage_themes=Standard-Theme manage_openid=OpenID-Adressen email_desc=Deine primäre E-Mail-Adresse wird für Benachrichtigungen, Passwort-Wiederherstellung und, sofern sie nicht versteckt ist, web-basierte Git-Operationen verwendet. -theme_desc=Dies wird dein Standard-Theme auf der Seite sein. +theme_desc=Dieses Thema wird für die Weboberfläche verwendet, wenn du angemeldet bist. primary=Primär activated=Aktiviert requires_activation=Erfordert Aktivierung @@ -1097,7 +1097,7 @@ issue_labels=Labels issue_labels_helper=Wähle eine Label-Sammlung license=Lizenz license_helper=Wähle eine Lizenz -license_helper_desc=Eine Lizenz regelt, was andere mit deinem Code tun (oder nicht tun) können. Unsicher, welches für dein Projekt die Richtige ist? Siehe Choose a license. +license_helper_desc=Eine Lizenz regelt, was andere mit deinem Code tun (oder nicht tun) können. Unsicher, welches für dein Projekt die Richtige ist? Siehe Choose a license. readme=README readme_helper=Wähle eine README-Vorlage readme_helper_desc=Hier kannst du eine komplette Beschreibung für dein Projekt schreiben. @@ -2490,8 +2490,8 @@ settings.archive.text=Durch das Archivieren wird ein Repo vollständig schreibge settings.archive.success=Das Repo wurde erfolgreich archiviert. settings.archive.error=Beim Versuch, das Repository zu archivieren, ist ein Fehler aufgetreten. Weitere Details finden sich im Log. settings.archive.error_ismirror=Du kannst kein gespiegeltes Repo archivieren. -settings.archive.branchsettings_unavailable=Branch-Einstellungen sind nicht verfügbar wenn das Repo archiviert ist. -settings.archive.tagsettings_unavailable=Tag Einstellungen sind nicht verfügbar, wenn das Repo archiviert wurde. +settings.archive.branchsettings_unavailable=Branch-Einstellungen sind nicht verfügbar in archivierten Repos. +settings.archive.tagsettings_unavailable=Tag-Einstellungen sind nicht verfügbar in archivierten Repos. settings.unarchive.button=Archivierung zurücksetzen settings.unarchive.header=Archivierung dieses Repositorys zurücksetzen settings.unarchive.text=Durch das Aufheben der Archivierung kann das Repo wieder Commits und Pushes sowie neue Issues und Pull-Requests empfangen. @@ -2690,7 +2690,7 @@ error.csv.too_large=Diese Datei kann nicht gerendert werden, da sie zu groß ist error.csv.unexpected=Diese Datei kann nicht gerendert werden, da sie ein unerwartetes Zeichen in Zeile %d und Spalte %d enthält. error.csv.invalid_field_count=Diese Datei kann nicht gerendert werden, da sie eine falsche Anzahl an Feldern in Zeile %d hat. rss.must_be_on_branch = Du musst auf einem Branch sein, um einen RSS-Feed zu haben. -new_repo_helper = Ein Repository enthält alle Projektdateien inklusive der Revisionshistorie. Bereits woanders gehostet? Repository migrieren. +new_repo_helper = Ein Repository enthält alle Projektdateien inklusive der Revisionshistorie. Bereits woanders gehostet? Repository migrieren. issues.comment.blocked_by_user = Du kannst kein Kommentar für dieses Issue erstellen, weil du vom Repository-Besitzer oder dem Autoren des Issues blockiert wurdest. clone_in_vscodium = In VSCodium klonen settings.units.add_more = Mehr aktivieren @@ -2704,7 +2704,7 @@ settings.add_collaborator_blocked_them = Der Mitarbeiter konnte nicht hinzugefü settings.wiki_rename_branch_main = Den Wiki-Branch-Namen normalisieren settings.enter_repo_name = Gib den Besitzer- und den Repository-Namen genau wie angezeigt ein: settings.wiki_branch_rename_success = Der Branch-Name des Repository-Wikis wurde erfolgreich normalisiert. -settings.archive.mirrors_unavailable = Spiegel sind nicht verfügbar, wenn das Repo archiviert ist. +settings.archive.mirrors_unavailable = Spiegel sind nicht verfügbar in archivierten Repos. pulls.blocked_by_user = Du kannst keinen Pull-Request in diesem Repository erstellen, weil du vom Repository-Besitzer blockiert wurdest. settings.add_collaborator_blocked_our = Der Mitarbeiter konnte nicht hinzugefügt werden, weil der Repository-Besitzer ihn blockiert hat. issues.blocked_by_user = Du kannst kein Issue in diesem Repository erstellen, weil du vom Repository-Besitzer blockiert wurdest. @@ -3686,12 +3686,12 @@ conan.registry=Diese Registry über die Kommandozeile einrichten: conan.install=Um das Paket mit Conan zu installieren, führe den folgenden Befehl aus: conda.registry=Richte diese Registry als Conda-Repository in deiner .condarc-Datei ein: conda.install=Um das Paket mit Conda zu installieren, führe den folgenden Befehl aus: -container.details.type=Container-Image Typ +container.details.type=Abbildtyp container.details.platform=Plattform container.pull=Downloade das Container-Image aus der Kommandozeile: container.digest=Digest container.multi_arch=Betriebsystem / Architektur -container.layers=Container-Image Ebenen +container.layers=Abbildebenen container.labels=Labels container.labels.key=Schlüssel container.labels.value=Wert diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index b3864d4e83..12f88a5847 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -319,7 +319,7 @@ default_keep_email_private=Piilota sähköpostiosoitteet oletuksena default_keep_email_private.description=Piilota oletusarvoisesti uusien käyttäjätilien sähköpostiosoitteet estääksesi tietojen vuotamisen rekisteröinnin yhteydessä. default_enable_timetracking=Ota ajanseuranta oletusarvoisesti käyttöön default_enable_timetracking.description=Salli uusien repositorioiden aikaseurannan käyttöönotto oletusarvoisesti. -no_reply_address=Piilotettu sähköpostin verkkotunnus +no_reply_address=Piilotetun sähköpostin verkkotunnus no_reply_address_helper=Verkkotunnuksen nimi käyttäjille, joilla on piilotettu sähköpostiosoite. Esimerkiksi käyttäjätunnus 'joe' kirjataan Git-palveluun nimellä 'joe@noreply.example.org' jos piilotetun sähköpostiosoitteen arvoksi on asetettu 'noreply.example.org'. password_algorithm=Salasanan hajautusalgoritmi enable_update_checker_helper_forgejo = Se tarkistaa tietyin väliajoin uusia Forgejo-versioita tutkimalla sen TXT DNS record -tietoja osoitteesta release.forgejo.org . @@ -461,6 +461,9 @@ change_unconfirmed_email = Jos annoit väärän sähköpostiosoitteen rekisterö invalid_code_forgot_password = Vahvistuskoodisi on virheellinen tai vanhentunut. Napsauta tästä aloittaaksesi uuden istunnon. openid_signin_desc = Kirjoita OpenID-URI:si. Esimerkki: alice.openid.example.org tai https://openid.example.org/alice. change_unconfirmed_email_summary = Vaihda sähköpostiosoite, johon aktivointisähköposti lähetetään. +reset_password_wrong_user = Olet kirjautuneena tilillä %s, mutta tilin palautuslinkki on tarkoitettu tilille %s +last_admin = Et voi poistaa viimeistä ylläpitäjää. Ylläpitäjiä tulee olla vähintään yksi. +password_pwned = Valitsemasi salasana on varastettujen salasanojen listalla, eli se on paljastanut jossain julkisessa tietovuodossa. Kokeile asettaa eri salasana, ja jos käytät samaa salasanaa muissa palveluissa, vaihda kyseinen salasana. [mail] view_it_on=Näytä %s @@ -629,6 +632,8 @@ following_one = %d seurataan block_user.detail = Huomaa, että käyttäjän estämisellä on muita vaikutuksia, kuten: show_on_map = Näytä paikka kartalla form.name_chars_not_allowed = Käyttäjätunnus "%s" sisältää virheellisiä merkkejä. +follow_blocked_user = Et voi seurata tätä käyttäjää, koska olet estänyt kyseisen käyttäjän tai kyseinen käyttäjä on estänyt sinut. +disabled_public_activity = Käyttäjä on poistanut käytöstä toiminnan julkisen näkyvyyden. [settings] @@ -684,7 +689,7 @@ keep_activity_private_popup=Tekee toiminnon näkyvän vain sinulle ja ylläpitä lookup_avatar_by_mail=Hae profiilikuva sähköpostin perusteella federated_avatar_lookup=Ulkopuolinen profiilikuvan haku -enable_custom_avatar=Ota käyttöön mukautettu profiilikuva +enable_custom_avatar=Käytä mukautettua profiilikuvaa choose_new_avatar=Valitse uusi profiilikuva update_avatar=Päivitä profiilikuva delete_current_avatar=Poista nykyinen profiilikuva @@ -699,9 +704,9 @@ password_change_disabled=Ei-lokaalit käyttäjät eivät voi päivittää salasa emails=Sähköposti osoitteet manage_emails=Hallitse sähköpostiosoitteita -manage_themes=Valitse oletusteema -manage_openid=Hallitse OpenID osoitteita -theme_desc=Tämä on sivuston oletusteemasi. +manage_themes=Oletusteema +manage_openid=OpenID-osoitteet +theme_desc=Tätä teemaa käytetään verkkosivuston käyttöliittymässä, kun olet sisäänkirjautuneena. primary=Ensisijainen activated=Aktivoitu requires_activation=Vaatii aktivoinnin @@ -717,7 +722,7 @@ theme_update_error=Valittua teemaa ei löydy. openid_deletion=Poista OpenID-osoite openid_deletion_success=OpenID-osoite on poistettu. add_new_email=Lisää uusi sähköpostiosoite -add_new_openid=Lisää uusi OpenID URI +add_new_openid=Lisää uusi OpenID-URI add_email=Lisää sähköpostiosoite add_openid=Lisää OpenID URI add_email_success=Uusi sähköpostiosoite on lisätty. @@ -729,14 +734,14 @@ openid_desc=OpenID mahdollistaa todentamisen delegoinnin ulkopuoliselle palvelun manage_ssh_keys=Hallitse SSH-avaimia manage_gpg_keys=Hallitse GPG-avaimia add_key=Lisää avain -ssh_desc=Nämä julkiset SSH-avaimet on liitetty tiliisi. Vastaavat yksityiset avaimet antavat täyden pääsyn repoihisi. -gpg_desc=Nämä julkiset GPG-avaimet on liitetty tiliisi. Pidä yksityiset avaimet turvassa, koska ne mahdollistavat committien todentamisen. +ssh_desc=Nämä julkiset SSH-avaimet on liitetty tiliisi. Vastaavat yksityiset avaimet antavat täyden pääsyn repoihisi. Vahvistettuja SSH-avaimia voi käyttää SSH-allekirjoitettujen Git-kommittien vahvistamiseen. +gpg_desc=Nämä julkiset GPG-avaimet on liitetty tiliisi, ja niitä käytetään kommittien vahvistamiseen. Pidä yksityiset avaimet turvassa, koska ne mahdollistavat kommittien allekirjoittamisen sinun nimissä. ssh_helper=Tarvitsetko apua? Tutustu GitHubin oppaaseen omien SSH-avainten luonnista tai yleisistä ongelmista, joita voit kohdata SSH:n kanssa. gpg_helper=Tarvitsetko apua? Katso GitHubin opas GPG:stä. add_new_key=Lisää SSH avain add_new_gpg_key=Lisää GPG-avain -key_content_ssh_placeholder=Alkaa sanoilla 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'sk-ecdsa-sha2-nistp256@openssh.com', tai 'sk-ssh-ed25519@openssh.com' -key_content_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP PUBLIC KEY BLOCK-----' +key_content_ssh_placeholder=Alkaa sanoilla "ssh-ed25519", "ssh-rsa", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384", "ecdsa-sha2-nistp521", "sk-ecdsa-sha2-nistp256@openssh.com" tai "sk-ssh-ed25519@openssh.com" +key_content_gpg_placeholder=Alkaa sanoilla "-----BEGIN PGP PUBLIC KEY BLOCK-----" ssh_key_name_used=Samanniminen SSH avain on jo olemassa tililläsi. gpg_key_id_used=Julkinen GPG-avain samalla tunnuksella on jo olemassa. gpg_no_key_email_found=Tämä GPG-avain ei vastaa mitään tiliisi liitettyä aktivoitua sähköpostiosoitetta. Se voidaan silti lisätä, jos allekirjoitat annetun pääsymerkin. @@ -748,7 +753,7 @@ gpg_token=Pääsymerkki gpg_token_help=Voit luoda allekirjoituksen käyttäen: gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig gpg_token_signature=Panssaroitu GPG-allekirjoitus -key_signature_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP SIGNATURE-----' +key_signature_gpg_placeholder=Alkaa sanoilla "-----BEGIN PGP SIGNATURE-----" ssh_key_verified=Vahvistettu avain ssh_key_verified_long=Avain on vahvistettu pääsymerkillä ja sitä voidaan käyttää todentamaan commitit, jotka vastaavat tämän käyttäjän aktivoituja sähköpostiosoitteita. ssh_key_verify=Vahvista @@ -756,7 +761,7 @@ ssh_token_required=Sinun täytyy antaa allekirjoitus alla olevalle pääsymerkil ssh_token=Pääsymerkki ssh_token_help=Voit luoda allekirjoituksen käyttäen: ssh_token_signature=Panssaroitu SSH-allekirjoitus -key_signature_ssh_placeholder=Alkaa sanoilla '-----BEGIN SSH SIGNATURE-----' +key_signature_ssh_placeholder=Alkaa sanoilla "-----BEGIN SSH SIGNATURE-----" subkeys=Aliavaimet key_id=Avain ID key_name=Avaimen nimi @@ -774,7 +779,7 @@ can_read_info=Luku can_write_info=Kirjoitus show_openid=Näytä profiilissa hide_openid=Piilota profiilista -ssh_disabled=SSH pois käytöstä +ssh_disabled=SSH on pois käytöstä manage_social=Hallitse liitettyjä sosiaalisia tilejä manage_access_token=Hallitse pääsymerkkejä @@ -795,7 +800,7 @@ create_oauth2_application=Luo uusi OAuth2-sovellus create_oauth2_application_button=Luo sovellus oauth2_application_name=Sovelluksen nimi save_application=Tallenna -oauth2_regenerate_secret=Luo secret uudelleen +oauth2_regenerate_secret=Luo salaisuus uudelleen oauth2_regenerate_secret_hint=Kadotitko secretin? oauth2_application_edit=Muokkaa @@ -811,10 +816,10 @@ twofa_enrolled=Tiliisi on otettu käyttöön kaksivaiheinen vahvistus. Ota palau webauthn_nickname=Nimimerkki -manage_account_links=Hallitse linkitettyjä tilejä +manage_account_links=Yhdistetyt tilit manage_account_links_desc=Nämä ulkoiset tilit on linkitetty Forgejo tiliisi. link_account=Yhdistä tili -remove_account_link=Poista linkitetty tili +remove_account_link=Poista yhdistetty tili remove_account_link_desc=Linkitetyn tilin poistaminen peruuttaa pääsyn Forgejo-tiliisi linkitetyn tili kautta. Jatketaanko? remove_account_link_success=Linkitetty tili on poistettu. @@ -854,7 +859,7 @@ location_placeholder = Jaa likimääräinen sijaintisi muiden kanssa retype_new_password = Vahvista uusi salasana create_oauth2_application_success = Loit uuden OAuth2-sovelluksen. repos_none = Et omista yhtäkään repositoriota. -visibility.limited_tooltip = Näkyvissä vain tunnistautuneille käyttäjille +visibility.limited_tooltip = Näkyvissä vain kirjautuneille käyttäjille email_notifications.disable = Poista sähköposti-ilmoitukset käytöstä webauthn_register_key = Lisää turva-avain blocked_users = Estetyt käyttäjät @@ -892,6 +897,28 @@ twofa_disable = Poista kaksivaiheinen todennus käytöstä twofa_disable_desc = Kaksivaiheisen todennuksen poistaminen asettaa tilisi aiempaa suurempaan uhkaan. Jatketaanko? update_language_not_found = Kieli "%s" ei ole käytettävissä. change_username_prompt = Huomio: Käyttäjätunnuksen vaihtaminen muuttaa myös tilisi URL-osoitteen. +oauth2_client_secret_hint = Tätä salaisuutta ei näytetä uudelleen, kun olet poistunut sivulta tai päivittänyt sivun. Varmista, että olet ottanut salaisuuden talteen. +blocked_since = Estetty %s lähtien +user_unblock_success = Käyttäjän esto on poistettu. +oauth2_redirect_uris = Uudelleenohjaus-URI:t. Käytä uutta riviä (newline) jokaista URI:a kohden. +oauth2_client_secret = Asiakkaan salaisuus +verify_ssh_key_success = SSH-avain "%s" on vahvistettu. +change_username_redirect_prompt = Vanha käyttäjätunnus uudelleenohjaa, kunnes joku muu ottaa käyttäjätunnuksen käyttönsä. +uploaded_avatar_is_too_big = Lähetetyn tiedoston koko (%d KiB) ylittää enimmäiskoon (%d KiB). +ssh_key_been_used = Tämä SSH-avain on jo lisätty palvelimelle. +verify_gpg_key_success = GPG-avain "%s" on vahvistettu. +add_key_success = SSH-avain "%s" on lisätty. +add_gpg_key_success = GPG-avain "%s" on lisätty. +ssh_key_deletion_success = SSH-avain on poistettu. +valid_until_date = Kelvollinen %s asti +oauth2_client_id = Asiakkaan tunniste +email_notifications.onmention = Ilmoitus vain maininnasta +email_notifications.submit = Aseta valinta +email_notifications.andyourown = Ja omat ilmoitukset +key_state_desc = Tätä avainta on käytetty viimeisen 7 päivän aikana +oauth2_application_create_description = OAuth2-sovellukset mahdollistavat kolmannen osapuolen sovelluksen pääsyn tilillesi tässä instanssissa. +oauth2_confidential_client = Luottamuksellinen sovellus. Valitse sovelluksille, jotka pitävät salaisuuden luottamuksellisena, kuten web-sovelluksille. Älä valitse natiiveille sovelluksille mukaan lukien työpöytä- ja mobiilisovellukset. +ssh_key_deletion_desc = SSH-avaimen poistaminen kumoaa pääsyn tilillesi kyseistä avainta käyttäen. Jatketaanko? [repo] owner=Omistaja @@ -917,7 +944,7 @@ repo_gitignore_helper=Valitse .gitignore-mallit issue_labels=Ongelmien tunnisteet issue_labels_helper=Valitse pohja ongelmien nimilapuille. license=Lisenssi -license_helper=Valitse lisenssitiedosto. +license_helper=Valitse lisenssitiedosto readme=README auto_init=Alusta repo (Luo .gitignore, License ja README) create_repo=Luo repo @@ -1316,7 +1343,7 @@ activity.new_issues_count_1=Uusi ongelma activity.new_issues_count_n=uutta ongelmaa activity.new_issue_label=Avoinna activity.unresolved_conv_label=Auki -activity.published_release_label=Julkaistu +activity.published_release_label=Julkaisu activity.git_stats_pushed_1=on työntänyt activity.git_stats_file_1=%d tiedosto activity.git_stats_file_n=%d tiedostoa @@ -1361,9 +1388,9 @@ settings.transfer.title=Siirrä omistajuus settings.transfer_form_title=Syötä repon nimi vahvistuksena: settings.transfer_notices_3=- Jos arkisto on yksityinen ja se siirretään yksittäiselle käyttäjälle, tämä toiminto varmistaa, että käyttäjällä on ainakin lukuoikeudet (ja muuttaa käyttöoikeuksia tarvittaessa). settings.transfer_owner=Uusi omistaja -settings.wiki_delete=Poista Wiki data +settings.wiki_delete=Poista wikidata settings.wiki_delete_desc=Repon wikin data poistaminen on pysyvä eikä voi peruuttaa. -settings.confirm_wiki_delete=Wiki datan poistaminen +settings.confirm_wiki_delete=Poista wikidata settings.wiki_deletion_success=Repon wiki data on poistettu. settings.delete=Poista tämä repo settings.delete_desc=Repon poistaminen on pysyvä eikä voi peruuttaa. @@ -1384,7 +1411,7 @@ settings.webhook.body=Sisältö settings.githook_edit_desc=Jos koukku ei ole käytössä, esitellään esimerkkisisältö. Sisällön jättäminen tyhjäksi arvoksi poistaa tämän koukun käytöstä. settings.githook_name=Koukun nimi settings.githook_content=Koukun sisältö -settings.update_githook=Päivitys koukku +settings.update_githook=Päivitä koukku settings.payload_url=Kohde URL settings.http_method=HTTP-menetelmä settings.secret=Salaus @@ -1406,7 +1433,7 @@ settings.event_push_desc=Git push repoon. settings.event_repository=Repo settings.event_repository_desc=Repo luotu tai poistettu. settings.event_header_issue=Ongelmien tapahtumat -settings.event_issues=Ongelmat +settings.event_issues=Muokkaus settings.event_issues_desc=Ongelma avattu, suljettu, avattu uudelleen tai muokattu. settings.event_issue_assign=Ongelma määritetty settings.event_issue_assign_desc=Ongelma osoitettu tai osoitus poistettu. @@ -1414,7 +1441,7 @@ settings.event_issue_label_desc=Ongelman tunnisteet päivitetty tai tyhjennetty. settings.event_issue_milestone_desc=Merkkipaalu lisätty, poistettu tai muokattu. settings.event_issue_comment_desc=Ongelman kommentti luotu, muokattu tai poistettu. settings.event_header_pull_request=Vetopyyntöjen tapahtumat -settings.event_pull_request=Vetopyyntö +settings.event_pull_request=Muokkaus settings.event_package_desc=Paketti on luotu tai poistettu repossa. settings.active_helper=Tiedot käynnistetyistä tapahtumista lähetetään tähän webkoukun URL-osoitteeseen. settings.add_hook_success=Uusi webkoukku on lisätty. @@ -1883,7 +1910,7 @@ migrate.gitlab.description = Tee migraatio gitlab.comista tai muista GitLab-inst migrate.gitea.description = Tee migraatio gitea.comista tai muista Gitea-instansseista. repo_gitignore_helper_desc = Valitse mitä tiedostoja ei seurata yleisimpien kielten mallipohjista. Tyypilliset artefaktit, joita eri kielten koostamistyökalut tuottavat, lisätään .gitignore-tiedostoon oletusarvoisesti. milestones.filter_sort.latest_due_date = Kaukaisin määräpäivä -license_helper_desc = Lisenssi määrää, mitä muut voivat ja eivät voi tehdä koodillasi. Etkö ole varma, mikä lisenssi soveltuu projektillesi? Lue ohje lisenssin valinnasta. +license_helper_desc = Lisenssi määrää, mitä muut voivat ja eivät voi tehdä koodillasi. Etkö ole varma, mikä lisenssi soveltuu projektillesi? Lue ohje lisenssin valinnasta. milestones.filter_sort.earliest_due_data = Lähin määräpäivä issues.filter_type.reviewed_by_you = Katselmoitu toimestasi settings.units.overview = Yleisnäkymä @@ -1959,6 +1986,31 @@ editor.must_have_write_access = Sinulla täytyy olla kirjoitusoikeus tehdäksesi issues.re_request_review = Pyydä katselmointia uudelleen pulls.status_checks_details = Yksityiskohdat release.title_empty = Nimi ei voi olla tyhjä. +archive.title = Tämä repo on arkistoitu. Voit katsella sen sisältämiä tiedostoja ja kloonata repon, mutta et voi pushata, avata ongelmia tai luoda vetopyyntöjä. +reactions_more = ja %d lisää +mirror_address = Kloonaa URL-osoitteesta +migrate_items_merge_requests = Yhdistämispyynnöt +stars_remove_warning = Tämä poistaa kaikki tähdet tästä reposta. +archive.issue.nocomment = Tämä repo on arkistoitu. Et voi kommentoida ongelmia. +archive.pull.nocomment = Tämä repo on arkistoitu. Et voi kommentoida vetopyyntöjä. +settings.webhook_deletion_desc = Webkoukun poistaminen poistaa sen asetukset ja toimitushistorian. Jatketaanko? +settings.discord_icon_url.exceeds_max_length = Kuvakkeen URL-osoite voi sisältää enintään 2048 merkkiä +settings.event_wiki_desc = Wiki-sivu luotu, nimetty uudelleen, muokattu tai poistettu. +settings.event_pull_request_desc = Vetopyyntö avattu, suljettu, avattu uudelleen tai muokattu. +settings.protect_branch_name_pattern = Suojatun haaran nimen kaava +issues.dependency.add_error_dep_not_same_repo = Molempien ongelmien tulee olla samassa repossa. +settings.event_release = Julkaisu +pulls.merge_pull_request = Luo yhdistämiskommitti +settings.pull_mirror_sync_quota_exceeded = Kiintiö ylitetty, ei vedetä muutoksia. +settings.wiki_rename_branch_main_notices_1 = Tätä toimintoa EI VOI perua. +settings.webhook.test_delivery_desc_disabled = Aktivoi webkoukku testataksesi sitä tekaistulla tapahtumalla. +settings.discord_icon_url = Kuvakkeen URL-osoite +settings.archive.branchsettings_unavailable = Haaran asetukset eivät ole saatavilla arkistoiduissa repoissa. +pulls.ready_for_review = Valmiina katselmointiin? +issues.time_spent_total = Käytetty kokonaisaika +settings.webhook.test_delivery_desc = Testaa tätä webkoukkua tekaistulla tapahtumalla. +pulls.switch_comparison_type = Vaihda vertailutyyppiä +settings.hooks_desc = Webkoukut tekevät automaattisesti HTTP POST -pyyntöjä palvelimelle, kun jotkin Forgejo-tapahtumat käynnistyvät. Lue lisää webkoukkujen oppaasta. @@ -2102,8 +2154,8 @@ dashboard.operation_switch=Vaihda dashboard.operation_run=Suorita dashboard.delete_inactive_accounts=Poista kaikki aktivoimattomat käyttäjät dashboard.delete_repo_archives=Poista kaikki repojen arkistot (ZIP, TAR.GZ, jne..) -dashboard.server_uptime=Palvelimen Uptime -dashboard.current_goroutine=Nykyiset Goroutinet +dashboard.server_uptime=Palvelimen uptime +dashboard.current_goroutine=Nykyiset goroutinet dashboard.current_memory_usage=Nykyinen muistinkäyttö dashboard.total_memory_allocated=Yhteensä muistia varattu dashboard.memory_obtained=Muistia saatu @@ -2279,7 +2331,7 @@ config.default_visibility_organization=Uuden organisaation oletusnäkyvyys config.webhook_config=Webkoukkujen asetukset config.queue_length=Jonon pituus -config.deliver_timeout=Toimitus aikakatkaisu +config.deliver_timeout=Toimituksen aikakatkaisu config.mailer_enabled=Käytössä config.mailer_name=Nimi @@ -2426,6 +2478,8 @@ dashboard.task.unknown = Tuntematon tehtävä: %[1]s dashboard.cron.error = Virhe Cronissa: %s: %[3]s dashboard.task.started = Käynnistetty tehtävä: %[1]s dashboard.cron.finished = Cron: %[1]s on valmistunut +dashboard.resync_all_sshkeys = Päivitä ".ssh/authorized_keys"-tiedosto Forgejo:n SSH-avaimilla. +dashboard.cleanup_packages = Siivoa vanhentuneet paketit [action] @@ -2601,6 +2655,15 @@ settings.link = Linkitä tämä paketti repositorioon maven.download = Lataa riippuvuus suorittamalla komentorivillä: registry.documentation = Lisätietoja %s-rekisteristä on dokumentaatiossa. owner.settings.chef.keypair.description = Avainpari vaaditaan Chef-rekisteriin tunnistautumista varten. Jos olet luonut avainparin aiemmin, uuden avainparin luominen hylkää aiemman avainparin. +owner.settings.cleanuprules.keep.pattern = Säilytä kaavaa vastaavat versiot +owner.settings.cleanuprules.pattern_full_match = Toteuta kaavio paketin koko nimeen +owner.settings.cleanuprules.keep.title = Näitä sääntöjä vastaavat versiot säilytetään, vaikka ne vastaisivat alla olevaa poistosääntöä. +owner.settings.cleanuprules.keep.count = Säilytä viimeisimmät +owner.settings.cleanuprules.remove.pattern = Poista kaavaa vastaavat versiot +owner.settings.cleanuprules.keep.pattern.container = Viimeisin (latest) versio säilytetään aina Container-paketeista. +owner.settings.cleanuprules.remove.title = Näitä sääntöjä vastaavat versiot poistetaan, ellei sääntö yläpuolella käske säilyttää niitä. +owner.settings.cleanuprules.remove.days = Poista versiot, jotka ovat vanhempia kuin +arch.pacman.helper.gpg = Lisää luottamusvarmenne pacmanille: [secrets] creation.failed = Salaisuuden lisääminen epäonnistui. diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index e45e27e7f0..8285607b1f 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -165,6 +165,7 @@ error413 = Votre quota est épuisé. new_repo.title = Nouveau dépôt new_migrate.link = Nouvelle migration new_org.link = Nouvelle organisation +copy_path = Copier le chemin [aria] navbar=Barre de navigation @@ -811,7 +812,7 @@ manage_emails=Gérer les adresses courriels manage_themes=Thème par défaut manage_openid=Adresses OpenID email_desc=Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et, à condition qu'elle ne soit pas cachée, les opérations Git basées sur le Web. -theme_desc=Ce sera votre thème par défaut sur le site. +theme_desc=Ce thème sera utilisé pour l'interface web lorsque vous êtes authentifié. primary=Principale activated=Activé requires_activation=Nécessite une activation @@ -1055,7 +1056,7 @@ language.localization_project = Aidez-nous à traduire Forgejo dans votre langue language.description = Cette langue sera enregistrée dans votre compte et utilisée comme langue par défaut après votre connexion. [repo] -new_repo_helper=Un dépôt contient tous les fichiers d’un projet, ainsi que l’historique de leurs modifications. Vous avez déjà ça ailleurs ? Migrez-le ici. +new_repo_helper=Un dépôt contient tous les fichiers d’un projet, ainsi que l’historique de leurs modifications. Vous avez déjà ça ailleurs ? Migrez-le ici.. owner=Propriétaire owner_helper=Certaines organisations peuvent ne pas apparaître dans la liste déroulante en raison d'une limite maximale du nombre de dépôts. repo_name=Nom du dépôt @@ -1095,7 +1096,7 @@ issue_labels=Étiquettes issue_labels_helper=Sélectionner un jeu d'étiquettes license=Licence license_helper=Sélectionner une licence -license_helper_desc=Une licence réglemente ce que les autres peuvent ou ne peuvent pas faire avec votre code. Vous ne savez pas laquelle est la bonne pour votre projet ? Comment choisir une licence. +license_helper_desc=Une licence réglemente ce que les autres peuvent ou ne peuvent pas faire avec votre code. Vous ne savez pas laquelle est la bonne pour votre projet ? Comment choisir une licence.. readme=LISEZMOI readme_helper=Choisissez un modèle de fichier LISEZMOI readme_helper_desc=Le README est l'endroit idéal pour décrire votre projet et accueillir des contributeurs. @@ -2508,7 +2509,7 @@ settings.archive.error=Une erreur s'est produite lors de l'archivage du dépôt. settings.archive.error_ismirror=Vous ne pouvez pas archiver un dépôt en miroir. settings.archive.branchsettings_unavailable=Le paramétrage des branches n'est pas disponible quand le dépôt est archivé. settings.archive.tagsettings_unavailable=Le paramétrage des étiquettes n'est pas disponible si le dépôt est archivé. -settings.archive.mirrors_unavailable = Les mirroirs ne sont pas disponibles si le dépôt a été archivé. +settings.archive.mirrors_unavailable = Les miroirs ne sont pas disponibles si le dépôt a été archivé. settings.unarchive.button=Désarchiver ce dépôt settings.unarchive.header=Réhabiliter ce dépôt settings.unarchive.text=Réhabiliter un dépôt dégèle les actions de révisions et de soumissions, la gestion des tickets et des demandes d'ajouts. @@ -2844,6 +2845,10 @@ diff.git-notes.remove-body = Cette note sera supprimée. diff.git-notes.add = Ajouter une note diff.git-notes.remove-header = Supprimer la note issues.summary_card_alt = Fiche de synthèse d'un ticket nommé "%s" dans le dépôt %s +editor.add_tmpl.filename = fichier +issues.num_reviews_one = %d revue +issues.num_reviews_few = %d revues +settings.default_update_style_desc = Style de mise à jour des demandes de fusion qui sont en retard par rapport à la branche de base. [graphs] component_loading = Chargement %s... @@ -3662,7 +3667,7 @@ alpine.registry=Configurez ce registre en ajoutant l’URL dans votre fichier /etc/apk/keys/ pour vérifier la signature de l'index : alpine.registry.info=Choisissez $branch et $repository dans la liste ci-dessous. alpine.install=Pour installer le paquet, exécutez la commande suivante : -alpine.repository=Informations sur le Dépôt +alpine.repository=Informations sur le dépôt alpine.repository.branches=Branches alpine.repository.repositories=Dépôts alpine.repository.architectures=Architectures @@ -3682,7 +3687,7 @@ conda.install=Pour installer le paquet en utilisant Conda, exécutez la commande container.details.type=Type d'image container.details.platform=Plateforme container.pull=Tirez l'image depuis un terminal : -container.digest=Empreinte : +container.digest=Empreinte container.multi_arch=SE / Arch container.layers=Calques d'image container.labels=Labels @@ -3797,6 +3802,7 @@ arch.version.conflicts = Conflits arch.version.replaces = Remplace arch.version.backup = Sauvegarde arch.version.makedepends = Faire des dépendances +container.images.title = Images [secrets] secrets=Secrets diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 397370c883..b44f3f384d 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -765,7 +765,7 @@ cancel=Atcelt language=Valoda ui=Motīvs hidden_comment_types=Slēpjamo piebilžu veidi -hidden_comment_types_description=Šeit atzīmētie piebilžu veidi netiks attēloti pieteikumu lapās. "Iezīme" atzīmēšana, piemēram, noņems visas " pievienoja/noņēma