space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
`, reaction, setting.StaticURLPrefix, url.PathEscape(reaction)))
}
-// RenderNote renders the contents of a git-notes file as a commit message.
-func RenderNote(ctx context.Context, msg, urlPrefix string, metas map[string]string) template.HTML {
- cleanMsg := template.HTMLEscapeString(msg)
- fullMessage, err := markup.RenderCommitMessage(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
- Metas: metas,
- }, cleanMsg)
- if err != nil {
- log.Error("RenderNote: %v", err)
- return ""
- }
- return template.HTML(fullMessage)
-}
-
func RenderMarkdownToHtml(ctx context.Context, input string) template.HTML { //nolint:revive
output, err := markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: setting.AppSubURL,
+ Ctx: ctx,
+ Metas: map[string]string{"mode": "document"},
}, input)
if err != nil {
log.Error("RenderString: %v", err)
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index 29d3ed3a56..8648967d38 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -6,17 +6,64 @@ package templates
import (
"context"
"html/template"
+ "os"
"testing"
+ "code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/markup"
+
"github.com/stretchr/testify/assert"
)
+const testInput = ` space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+[local link](file.bin)
+[remote link](https://example.com)
+[[local link|file.bin]]
+[[remote link|https://example.com]]
+
+
+[[local image|image.jpg]]
+[[remote link|https://example.com/image.jpg]]
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+:+1:
+mail@domain.com
+@mention-user test
+#123
+ space
+`
+
+var testMetas = map[string]string{
+ "user": "user13",
+ "repo": "repo11",
+ "repoPath": "../../tests/gitea-repositories-meta/user13/repo11.git/",
+ "mode": "comment",
+}
+
+func TestMain(m *testing.M) {
+ unittest.InitSettings()
+ if err := git.InitSimple(context.Background()); err != nil {
+ log.Fatal("git init failed, err: %v", err)
+ }
+ markup.Init(&markup.ProcessorHelper{
+ IsUsernameMentionable: func(ctx context.Context, username string) bool {
+ return username == "mention-user"
+ },
+ })
+ os.Exit(m.Run())
+}
+
func TestRenderCommitBody(t *testing.T) {
type args struct {
- ctx context.Context
- msg string
- urlPrefix string
- metas map[string]string
+ ctx context.Context
+ msg string
+ metas map[string]string
}
tests := []struct {
name string
@@ -50,7 +97,91 @@ func TestRenderCommitBody(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- assert.Equalf(t, tt.want, RenderCommitBody(tt.args.ctx, tt.args.msg, tt.args.urlPrefix, tt.args.metas), "RenderCommitBody(%v, %v, %v, %v)", tt.args.ctx, tt.args.msg, tt.args.urlPrefix, tt.args.metas)
+ assert.Equalf(t, tt.want, RenderCommitBody(tt.args.ctx, tt.args.msg, tt.args.metas), "RenderCommitBody(%v, %v, %v)", tt.args.ctx, tt.args.msg, tt.args.metas)
})
}
+
+ expected := `/just/a/path.bin
+https://example.com/file.bin
+[local link](file.bin)
+[remote link](https://example.com)
+[[local link|file.bin]]
+[[remote link|https://example.com]]
+
+
+[[local image|image.jpg]]
+[[remote link|https://example.com/image.jpg]]
+88fc37a3c0...12fc37a3c0 (hash)
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+88fc37a3c0
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+ space`
+
+ assert.EqualValues(t, expected, RenderCommitBody(context.Background(), testInput, testMetas))
+}
+
+func TestRenderCommitMessage(t *testing.T) {
+ expected := `space @mention-user `
+
+ assert.EqualValues(t, expected, RenderCommitMessage(context.Background(), testInput, testMetas))
+}
+
+func TestRenderCommitMessageLinkSubject(t *testing.T) {
+ expected := `space @mention-user`
+
+ assert.EqualValues(t, expected, RenderCommitMessageLinkSubject(context.Background(), testInput, "https://example.com/link", testMetas))
+}
+
+func TestRenderIssueTitle(t *testing.T) {
+ expected := ` space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+[local link](file.bin)
+[remote link](https://example.com)
+[[local link|file.bin]]
+[[remote link|https://example.com]]
+
+
+[[local image|image.jpg]]
+[[remote link|https://example.com/image.jpg]]
+https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+https://example.com/user/repo/commit/88fc37a3c0a4dda553bdcfc80c178a58247f42fb
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+ space
+`
+ assert.EqualValues(t, expected, RenderIssueTitle(context.Background(), testInput, testMetas))
+}
+
+func TestRenderMarkdownToHtml(t *testing.T) {
+ expected := `space @mention-user
+/just/a/path.bin
+https://example.com/file.bin
+local link
+remote link
+local link
+remote link
+
+
+
+
+88fc37a3c0...12fc37a3c0 (hash)
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb pare
+88fc37a3c0
+com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
+👍
+mail@domain.com
+@mention-user test
+#123
+space
~/.cargo/config.toml):
cargo.install=Chcete-li nainstalovat balíček pomocí Cargo, spusťte následující příkaz:
-cargo.details.repository_site=Stránka repositáře
-cargo.details.documentation_site=Stránka dokumentace
chef.registry=Nastavit tento registr v souboru ~/.chef/config.rb:
chef.install=Pro instalaci balíčku spusťte následující příkaz:
composer.registry=Nastavit tento registr v souboru ~/.composer/config.json:
@@ -3044,8 +3031,6 @@ conan.registry=Nastavte tento registr z příkazového řádku:
conan.install=Pro instalaci balíčku pomocí Conan spusťte následující příkaz:
conda.registry=Nastavte tento registr jako Conda repozitář ve vašem .condarc:
conda.install=Pro instalaci balíčku pomocí Conda spusťte následující příkaz:
-conda.details.repository_site=Stránka repositáře
-conda.details.documentation_site=Stránka dokumentace
container.details.type=Typ obrazu
container.details.platform=Platforma
container.pull=Stáhněte obraz z příkazové řádky:
@@ -3195,7 +3180,6 @@ runners.version=Verze
runs.all_workflows=Všechny pracovní postupy
runs.commit=Commit
-runs.no_matching_runner_helper=Žádný odpovídající runner: %s
runs.status=Status
@@ -3205,5 +3189,6 @@ runs.status=Status
type-3.display_name=Projekt organizace
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Symbolický odkaz
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index f970fdb666..c24d25b1ac 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -108,9 +108,6 @@ write=Verfassen
preview=Vorschau
loading=Laden…
-step1=Schritt 1:
-step2=Schritt 2:
-
error=Fehler
error404=Die Seite, die Du versuchst aufzurufen, existiert nicht oder Du bist nicht berechtigt, diese anzusehen.
go_back=Zurück
@@ -354,7 +351,6 @@ code_last_indexed_at=Zuletzt indexiert %s
relevant_repositories_tooltip=Repositories, die Forks sind oder die kein Thema, kein Symbol und keine Beschreibung haben, werden ausgeblendet.
relevant_repositories=Es werden nur relevante Repositories angezeigt, ungefilterte Ergebnisse anzeigen.
-
[auth]
create_new_account=Konto anlegen
register_helper_msg=Hast du bereits ein Konto? Jetzt anmelden!
@@ -924,7 +920,6 @@ visibility.private=Privat
visibility.private_tooltip=Sichtbar nur für Mitglieder von Organisationen, denen du beigetreten bist
[repo]
-new_repo_helper=Ein Repository enthält alle Projektdateien, einschließlich des Änderungsverlaufs. Schon woanders vorhanden? Migriere das Repository.
owner=Besitzer
owner_helper=Einige Organisationen könnten in der Dropdown-Liste nicht angezeigt werden, da die Anzahl an Repositories begrenzt ist.
repo_name=Repository-Name
@@ -1029,10 +1024,8 @@ transfer.no_permission_to_reject=Du hast keine Berechtigung, diesen Transfer abz
desc.private=Privat
desc.public=Öffentlich
-desc.private_template=Private Vorlage
-desc.public_template=Vorlage
+desc.template=Template
desc.internal=Intern
-desc.internal_template=Interne Vorlage
desc.archived=Archiviert
template.items=Template-Elemente
@@ -1760,7 +1753,7 @@ pulls.no_merge_desc=Dieser Pull-Request kann nicht gemerged werden, da keine Mer
pulls.no_merge_helper=Aktiviere Mergeoptionen in den Repositoryeinstellungen oder merge den Pull-Request manuell.
pulls.no_merge_wip=Dieser Pull Request kann nicht gemergt werden, da er als Work In Progress gekennzeichnet ist.
pulls.no_merge_not_ready=Dieser Pull-Request kann nicht gemergt werden, überprüfe den Reviewstatus und die Statusprüfungen.
-pulls.no_merge_access=Du bist nicht berechtigt, diesen Pull-Request zu Mergen.
+pulls.no_merge_access=Du bist nicht berechtigt, diesen Pull-Request zu mergen.
pulls.merge_pull_request=Merge Commit erstellen
pulls.rebase_merge_pull_request=Rebasen und dann fast-forwarden
pulls.rebase_merge_commit_pull_request=Rebasen und dann mergen
@@ -1797,9 +1790,6 @@ pulls.outdated_with_base_branch=Dieser Branch enthält nicht die neusten Commits
pulls.close=Pull-Request schließen
pulls.closed_at=`hat diesen Pull-Request %[2]s geschlossen`
pulls.reopened_at=`hat diesen Pull-Request %[2]s wieder geöffnet`
-pulls.merge_instruction_hint=`Siehe auch die Anleitung für die Kommandozeile.`
-pulls.merge_instruction_step1_desc=Wechsle auf einen neuen Branch in deinem lokalen Repository und teste die Änderungen.
-pulls.merge_instruction_step2_desc=Führe die Änderungen zusammen und aktualisiere den Stand online auf Gitea.
pulls.clear_merge_message=Merge-Nachricht löschen
pulls.clear_merge_message_hint=Das Löschen der Merge-Nachricht wird nur den Inhalt der Commit-Nachricht entfernen und generierte Git-Trailer wie "Co-Authored-By …" erhalten.
@@ -2311,7 +2301,6 @@ settings.dismiss_stale_approvals_desc=Wenn neue Commits gepusht werden, die den
settings.require_signed_commits=Signierte Commits erforderlich
settings.require_signed_commits_desc=Pushes auf diesen Branch ablehnen, wenn Commits nicht signiert oder nicht überprüfbar sind.
settings.protect_branch_name_pattern=Muster für geschützte Branchnamen
-settings.protect_branch_name_pattern_desc=Geschützte Branch-Namensmuster. Lies die Dokumentation für die Muster-Syntax. Beispiele: main, release/**
settings.protect_patterns=Muster
settings.protect_protected_file_patterns=Geschützte Dateimuster (durch Semikolon ';' getrennt):
settings.protect_protected_file_patterns_desc=Geschützte Dateien dürfen nicht direkt geändert werden, auch wenn der Benutzer Rechte hat, Dateien in diesem Branch hinzuzufügen, zu bearbeiten oder zu löschen. Mehrere Muster können mit Semikolon (';') getrennt werden. Siehe github.com/gobwas/glob Dokumentation zur Mustersyntax. Beispiele: .drone.yml, /docs/**/*.txt.
@@ -2507,7 +2496,6 @@ release.releases_for=Releases für %s
release.tags_for=Tags für %s
branch.name=Branchname
-branch.search=Branch suchen
branch.already_exists=Ein Branch mit dem Namen "%s" existiert bereits.
branch.delete_head=Löschen
branch.delete=Branch "%s" löschen
@@ -2530,6 +2518,7 @@ branch.default_deletion_failed=Branch "%s" kann nicht gelöscht werden, da diese
branch.restore=Branch "%s" wiederherstellen
branch.download=Branch "%s" herunterladen
branch.rename=Branch "%s" umbenennen
+branch.search=Branch suchen
branch.included_desc=Dieser Branch ist im Standard-Branch enthalten
branch.included=Enthalten
branch.create_new_branch=Branch aus Branch erstellen:
@@ -2857,7 +2846,6 @@ emails.updated=E-Mail aktualisiert
emails.not_updated=Fehler beim Aktualisieren der angeforderten E-Mail-Adresse: %v
emails.duplicate_active=Diese E-Mail-Adresse wird bereits von einem Nutzer verwendet.
emails.change_email_header=E-Mail-Eigenschaften aktualisieren
-emails.change_email_text=Bist du dir sicher, diese E-Mail-Adresse zu aktualisieren?
orgs.org_manage_panel=Organisationsverwaltung
orgs.name=Name
@@ -3075,7 +3063,6 @@ config.enable_openid_signin=OpenID-Anmeldung aktivieren
config.show_registration_button=Schaltfläche zum Registrieren anzeigen
config.require_sign_in_view=Seiten nur für angemeldete Benutzer zugänglich
config.mail_notify=E-Mail-Benachrichtigungen aktivieren
-config.disable_key_size_check=Prüfung der Mindestschlüssellänge deaktiveren
config.enable_captcha=CAPTCHA aktivieren
config.active_code_lives=Aktivierungscode-Lebensdauer
config.reset_password_code_lives=Kontowiederherstellungs-Code Ablaufzeit
@@ -3341,8 +3328,6 @@ alpine.repository.repositories=Repositories
alpine.repository.architectures=Architekturen
cargo.registry=Richte diese Registry in der Cargo-Konfigurationsdatei ein (z.B. ~/.cargo/config.toml):
cargo.install=Um das Paket mit Cargo zu installieren, führe den folgenden Befehl aus:
-cargo.details.repository_site=Repository-Seite
-cargo.details.documentation_site=Dokumentationsseite
chef.registry=Richte diese Registry in deiner ~/.chef/config.rb Datei ein:
chef.install=Nutze folgenden Befehl, um das Paket zu installieren:
composer.registry=Setze diese Paketverwaltung in deiner ~/.composer/config.json Datei auf:
@@ -3354,8 +3339,6 @@ 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:
-conda.details.repository_site=Repository-Seite
-conda.details.documentation_site=Dokumentationsseite
container.details.type=Container-Image Typ
container.details.platform=Plattform
container.pull=Downloade das Container-Image aus der Kommandozeile:
@@ -3525,7 +3508,6 @@ runs.commit=Commit
runs.scheduled=Geplant
runs.pushed_by=gepusht von
runs.invalid_workflow_helper=Die Workflow-Konfigurationsdatei ist ungültig. Bitte überprüfe Deine Konfigurationsdatei: %s
-runs.no_matching_runner_helper=Kein passender Runner: %s
runs.actor=Initiator
runs.status=Status
runs.actors_no_select=Alle Initiatoren
@@ -3564,6 +3546,7 @@ type-3.display_name=Organisationsprojekt
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=Verzeichnis
normal_file=Normale Datei
executable_file=Ausführbare Datei
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index 2dc615a1b3..2424ee3fb6 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -104,9 +104,6 @@ write=Σύνταξη
preview=Προεπισκόπηση
loading=Φόρτωση…
-step1=Βήμα 1:
-step2=Βήμα 2:
-
error=Σφάλμα
error404=Η σελίδα που προσπαθείτε να φτάσετε είτε δεν υπάρχει είτε δεν είστε εξουσιοδοτημένοι για να την δείτε.
@@ -343,7 +340,6 @@ code_last_indexed_at=Τελευταίο δημιουργία ευρετηρίο
relevant_repositories_tooltip=Τα αποθετήρια που είναι forks ή που δεν έχουν θέμα, εικονίδιο και περιγραφή είναι κρυμμένα.
relevant_repositories=Εμφανίζονται μόνο τα σχετικά αποθετήρια, εμφάνιση χωρίς φίλτρο.
-
[auth]
create_new_account=Εγγραφή Λογαριασμού
register_helper_msg=Έχετε ήδη λογαριασμό; Συνδεθείτε τώρα!
@@ -965,10 +961,8 @@ transfer.reject_desc=`Ακύρωση μεταφοράς σε "%s"`
desc.private=Ιδιωτικό
desc.public=Δημόσιο
-desc.private_template=Ιδιωτικό πρότυπο
-desc.public_template=Πρότυπο
+desc.template=Πρότυπο
desc.internal=Εσωτερικό
-desc.internal_template=Εσωτερικό πρότυπο
desc.archived=Αρχειοθετημένο
template.items=Αντικείμενα Προτύπου
@@ -1686,9 +1680,6 @@ pulls.outdated_with_base_branch=Αυτός ο κλάδος δεν είναι ε
pulls.close=Κλείσιμο Pull Request
pulls.closed_at=`έκλεισε αυτό το pull request %[2]s`
pulls.reopened_at=`άνοιξε ξανά αυτό το pull request %[2]s`
-pulls.merge_instruction_hint=`Μπορείτε επίσης να δείτε τις οδηγίες της γραμμής εντολών.`
-pulls.merge_instruction_step1_desc=Από το αποθετήριο του έργου σας, ελέγξτε έναν νέο κλάδο και τεστάρετε τις αλλαγές.
-pulls.merge_instruction_step2_desc=Συγχώνευσε τις αλλαγές και ενημέρωσε στο Gitea.
pulls.clear_merge_message=Εκκαθάριση μηνύματος συγχώνευσης
pulls.clear_merge_message_hint=Η εκκαθάριση του μηνύματος συγχώνευσης θα αφαιρέσει μόνο το περιεχόμενο του μηνύματος υποβολής και θα διατηρήσει τα παραγόμενα git trailers όπως "Co-Authored-By …".
@@ -2688,7 +2679,6 @@ emails.updated=Το email ενημερώθηκε
emails.not_updated=Αποτυχία ενημέρωσης της ζητούμενης διεύθυνσης email: %v
emails.duplicate_active=Αυτή η διεύθυνση email είναι ήδη ενεργή σε διαφορετικό χρήστη.
emails.change_email_header=Ενημέρωση Ιδιοτήτων Email
-emails.change_email_text=Είστε βέβαιοι ότι θέλετε να ενημερώσετε αυτή τη διεύθυνση email;
orgs.org_manage_panel=Διαχείριση Οργανισμού
orgs.name=Όνομα
@@ -2899,7 +2889,6 @@ config.enable_openid_signin=Ενεργοποίηση Σύνδεσης μέσω O
config.show_registration_button=Εμφάνιση Κουμπιού Εγγραφής
config.require_sign_in_view=Απαιτείται Είσοδος για Προβολή Σελίδων
config.mail_notify=Ενεργοποίηση Ειδοποιήσεων Email
-config.disable_key_size_check=Απενεργοποίηση Ελέγχου Ελάχιστου Μεγέθους Κλειδιού
config.enable_captcha=Ενεργοποίηση CAPTCHA
config.active_code_lives=Ζωή Ενεργού Κωδικού
config.reset_password_code_lives=Λήξη Χρόνου Κωδικού Ανάκτησης του Λογαριασμού
@@ -3162,8 +3151,6 @@ alpine.repository.repositories=Αποθετήρια
alpine.repository.architectures=Αρχιτεκτονικές
cargo.registry=Ρυθμίστε αυτό το μητρώο στις ρυθμίσεις του Cargo (για παράδειγμα ~/.cargo/config.toml):
cargo.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το Cargo, εκτελέστε την ακόλουθη εντολή:
-cargo.details.repository_site=Ιστοσελίδα Αποθετηρίου
-cargo.details.documentation_site=Ιστοσελίδα Τεκμηρίωσης
chef.registry=Ρυθμίστε αυτό το μητρώο στο αρχείο ~/.chef/config.rb:
chef.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή:
composer.registry=Ρυθμίστε αυτό το μητρώο στο αρχείο ~/.composer/config.json:
@@ -3175,8 +3162,6 @@ conan.registry=Ρυθμίστε αυτό το μητρώο από τη γραμ
conan.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το Conan, εκτελέστε την ακόλουθη εντολή:
conda.registry=Ρυθμίστε αυτό το μητρώο ως αποθετήριο Conda στο αρχείο .condarc:
conda.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το Conda, εκτελέστε την ακόλουθη εντολή:
-conda.details.repository_site=Ιστοσελίδα Αποθετηρίου
-conda.details.documentation_site=Ιστοσελίδα Τεκμηρίωσης
container.details.type=Τύπος Εικόνας
container.details.platform=Πλατφόρμα
container.pull=Κατεβάστε την εικόνα από τη γραμμή εντολών:
@@ -3335,7 +3320,6 @@ runners.reset_registration_token_success=Επιτυχής επανέκδοση
runs.all_workflows=Όλες Οι Ροές Εργασίας
runs.commit=Υποβολή
runs.invalid_workflow_helper=Το αρχείο ροής εργασίας δεν είναι έγκυρο. Ελέγξτε το αρχείο σας: %s
-runs.no_matching_runner_helper=Δε ταιριάζει εκτελεστής: %s
runs.status=Κατάσταση
@@ -3348,5 +3332,6 @@ type-2.display_name=Έργο Αποθετηρίου
type-3.display_name=Έργο Οργανισμού
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Symbolic link
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index fa7eee9bc5..90e3ac503a 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -423,6 +423,7 @@ authorization_failed_desc = The authorization failed because we detected an inva
sspi_auth_failed = SSPI authentication failed
password_pwned = The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password and consider changing this password elsewhere too.
password_pwned_err = Could not complete request to HaveIBeenPwned
+last_admin = You cannot remove the last admin. There must be at least one admin.
[mail]
view_it_on = View it on %s
@@ -588,6 +589,8 @@ org_still_own_packages = "This organization still owns one or more packages, del
target_branch_not_exist = Target branch does not exist.
+admin_cannot_delete_self = You cannot delete yourself when you are an admin. Please remove your admin privileges first.
+
[user]
change_avatar = Change your avatar…
joined_on = Joined on %s
@@ -626,11 +629,11 @@ applications = Applications
orgs = Manage Organizations
repos = Repositories
delete = Delete Account
-twofa = Two-Factor Authentication
+twofa = Two-Factor Authentication (TOTP)
account_link = Linked Accounts
organization = Organizations
uid = UID
-webauthn = Security Keys
+webauthn = Two-Factor Authentication (Security Keys)
public_profile = Public Profile
biography_placeholder = Tell us a little bit about yourself! (You can use Markdown)
@@ -864,22 +867,23 @@ revoke_oauth2_grant = Revoke Access
revoke_oauth2_grant_description = Revoking access for this third party application will prevent this application from accessing your data. Are you sure?
revoke_oauth2_grant_success = Access revoked successfully.
-twofa_desc = Two-factor authentication enhances the security of your account.
+twofa_desc = To protect your account against password theft, you can use a smartphone or another device for receiving time-based one-time passwords ("TOTP").
+twofa_recovery_tip = If you lose your device, you will be able to use a single-use recovery key to regain access to your account.
twofa_is_enrolled = Your account is currently enrolled in two-factor authentication.
twofa_not_enrolled = Your account is not currently enrolled in two-factor authentication.
twofa_disable = Disable Two-Factor Authentication
-twofa_scratch_token_regenerate = Regenerate Scratch Token
-twofa_scratch_token_regenerated = Your scratch token is now %s. Store it in a safe place, it will never be shown again.
+twofa_scratch_token_regenerate = Regenerate Single-Use Recovery Key
+twofa_scratch_token_regenerated = Your single-use recovery key is now %s. Store it in a safe place, as it will not be shown again.
twofa_enroll = Enroll into Two-Factor Authentication
twofa_disable_note = You can disable two-factor authentication if needed.
twofa_disable_desc = Disabling two-factor authentication will make your account less secure. Continue?
-regenerate_scratch_token_desc = If you misplaced your scratch token or have already used it to sign in you can reset it here.
+regenerate_scratch_token_desc = If you misplaced your recovery key or have already used it to sign in, you can reset it here.
twofa_disabled = Two-factor authentication has been disabled.
scan_this_image = Scan this image with your authentication application:
or_enter_secret = Or enter the secret: %s
then_enter_passcode = And enter the passcode shown in the application:
passcode_invalid = The passcode is incorrect. Try again.
-twofa_enrolled = Your account has been enrolled into two-factor authentication. Store your scratch token (%s) in a safe place as it is only shown once!
+twofa_enrolled = Your account has been successfully enrolled. Store your single-use recovery key (%s) in a safe place, as it will not be shown again.
twofa_failed_get_secret = Failed to get secret.
webauthn_desc = Security keys are hardware devices containing cryptographic keys. They can be used for two-factor authentication. Security keys must support the WebAuthn Authenticator standard.
@@ -887,6 +891,8 @@ webauthn_register_key = Add Security Key
webauthn_nickname = Nickname
webauthn_delete_key = Remove Security Key
webauthn_delete_key_desc = If you remove a security key you can no longer sign in with it. Continue?
+webauthn_key_loss_warning = If you lose your security keys, you will lose access to your account.
+webauthn_alternative_tip = You may want to configure an additional authentication method.
manage_account_links = Manage Linked Accounts
manage_account_links_desc = These external accounts are linked to your Gitea account.
@@ -2309,10 +2315,12 @@ settings.protect_approvals_whitelist_users = Whitelisted reviewers:
settings.protect_approvals_whitelist_teams = Whitelisted teams for reviews:
settings.dismiss_stale_approvals = Dismiss stale approvals
settings.dismiss_stale_approvals_desc = When new commits that change the content of the pull request are pushed to the branch, old approvals will be dismissed.
+settings.ignore_stale_approvals = Ignore stale approvals
+settings.ignore_stale_approvals_desc = Do not count approvals that were made on older commits (stale reviews) towards how many approvals the PR has. Irrelevant if stale reviews are already dismissed.
settings.require_signed_commits = Require Signed Commits
settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable.
settings.protect_branch_name_pattern = Protected Branch Name Pattern
-settings.protect_branch_name_pattern_desc = "Protected branch name patterns. See the documentation for pattern syntax. Examples: main, release/**"
+settings.protect_branch_name_pattern_desc = "Protected branch name patterns. See the documentation for pattern syntax. Examples: main, release/**"
settings.protect_patterns = Patterns
settings.protect_protected_file_patterns = "Protected file patterns (separated using semicolon ';'):"
settings.protect_protected_file_patterns_desc = "Protected files are not allowed to be changed directly even if user has rights to add, edit, or delete files in this branch. Multiple patterns can be separated using semicolon (';'). See github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt."
@@ -2688,6 +2696,7 @@ teams.invite.description = Please click the button below to join the team.
[admin]
dashboard = Dashboard
+self_check = Self Check
identity_access = Identity & Access
users = User Accounts
organizations = Organizations
@@ -3077,7 +3086,6 @@ config.enable_openid_signin = Enable OpenID Sign-In
config.show_registration_button = Show Register Button
config.require_sign_in_view = Require Sign-In to View Pages
config.mail_notify = Enable Email Notifications
-config.disable_key_size_check = Disable Minimum Key Size Check
config.enable_captcha = Enable CAPTCHA
config.active_code_lives = Active Code Lives
config.reset_password_code_lives = Recover Account Code Expiry Time
@@ -3214,6 +3222,13 @@ notices.desc = Description
notices.op = Op.
notices.delete_success = The system notices have been deleted.
+self_check.no_problem_found = No problem found yet.
+self_check.database_collation_mismatch = Expect database to use collation: %s
+self_check.database_collation_case_insensitive = Database is using a collation %s, which is an insensitive collation. Although Gitea could work with it, there might be some rare cases which don't work as expected.
+self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems.
+self_check.database_fix_mysql = For MySQL/MariaDB users, you could use the "gitea doctor convert" command to fix the collation problems, or you could also fix the problem by "ALTER ... COLLATE ..." SQLs manually.
+self_check.database_fix_mssql = For MSSQL users, you could only fix the problem by "ALTER ... COLLATE ..." SQLs manually at the moment.
+
[action]
create_repo = created repository %s
rename_repo = renamed repository from %[1]s to %[3]s
@@ -3523,15 +3538,15 @@ runs.commit = Commit
runs.scheduled = Scheduled
runs.pushed_by = pushed by
runs.invalid_workflow_helper = Workflow config file is invalid. Please check your config file: %s
-runs.no_matching_runner_helper = No matching runner: %s
+runs.no_matching_online_runner_helper = No matching online runner with label: %s
runs.actor = Actor
runs.status = Status
runs.actors_no_select = All actors
runs.status_no_select = All status
runs.no_results = No results matched.
runs.no_workflows = There are no workflows yet.
-runs.no_workflows.quick_start = Don't know how to start with Gitea Action? See the quick start guide.
-runs.no_workflows.documentation = For more information on the Gitea Action, see the documentation.
+runs.no_workflows.quick_start = Don't know how to start with Gitea Actions? See the quick start guide.
+runs.no_workflows.documentation = For more information on Gitea Actions, see the documentation.
runs.no_runs = The workflow has no runs yet.
runs.empty_commit_message = (empty commit message)
@@ -3550,7 +3565,7 @@ variables.none = There are no variables yet.
variables.deletion = Remove variable
variables.deletion.description = Removing a variable is permanent and cannot be undone. Continue?
variables.description = Variables will be passed to certain actions and cannot be read otherwise.
-variables.id_not_exist = Variable with id %d not exists.
+variables.id_not_exist = Variable with ID %d does not exist.
variables.edit = Edit Variable
variables.deletion.failed = Failed to remove variable.
variables.deletion.success = The variable has been removed.
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index 9eb9e856ce..1a82ce5b76 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -108,9 +108,6 @@ write=Escribir
preview=Vista previa
loading=Cargando…
-step1=Paso 1:
-step2=Paso 2:
-
error=Error
error404=La página a la que está intentando acceder o no existe o no está autorizado para verla.
go_back=Volver
@@ -354,7 +351,6 @@ code_last_indexed_at=Indexado por última vez %s
relevant_repositories_tooltip=Repositorios que son bifurcaciones o que no tienen ningún tema, ningún icono, y ninguna descripción están ocultos.
relevant_repositories=Solo se muestran repositorios relevantes, mostrar resultados sin filtrar.
-
[auth]
create_new_account=Registrar una cuenta
register_helper_msg=¿Ya tienes una cuenta? ¡Inicia sesión!
@@ -924,7 +920,6 @@ visibility.private=Privado
visibility.private_tooltip=Visible sólo para los miembros de organizaciones a las que te has unido
[repo]
-new_repo_helper=Un repositorio contiene todos los archivos del proyecto, incluyendo el historial de revisiones. ¿Ya está alojando uno en otro lugar? Migrar repositorio.
owner=Propietario
owner_helper=Algunas organizaciones pueden no aparecer en el menú desplegable debido a un límite máximo de recuento de repositorios.
repo_name=Nombre del repositorio
@@ -1029,10 +1024,8 @@ transfer.no_permission_to_reject=No tienes permiso para rechazar esta transferen
desc.private=Privado
desc.public=Público
-desc.private_template=Plantilla privada
-desc.public_template=Plantilla
+desc.template=Plantilla
desc.internal=Interno
-desc.internal_template=Plantilla interna
desc.archived=Archivado
template.items=Elementos de plantilla
@@ -1797,9 +1790,6 @@ pulls.outdated_with_base_branch=Esta rama está desactualizada con la rama base
pulls.close=Cerrar Pull Request
pulls.closed_at=`cerró este pull request %[2]s`
pulls.reopened_at=`reabrió este pull request %[2]s`
-pulls.merge_instruction_hint=`También puede ver instrucciones de línea de comandos.`
-pulls.merge_instruction_step1_desc=Desde el repositorio de su proyecto, revisa una nueva rama y prueba los cambios.
-pulls.merge_instruction_step2_desc=Combine los cambios y actualice en Gitea.
pulls.clear_merge_message=Borrar mensaje de fusión
pulls.clear_merge_message_hint=Limpiar el mensaje de fusión solo eliminará el contenido del mensaje de commit y mantendrá frases generadas como "Co-Autorizado por …".
@@ -2311,7 +2301,6 @@ settings.dismiss_stale_approvals_desc=Cuando los nuevos commits que cambien el c
settings.require_signed_commits=Requiere commits firmados
settings.require_signed_commits_desc=Rechazar push en esta rama si los commits no están firmados o no son verificables.
settings.protect_branch_name_pattern=Patrón de nombre de la rama protegida
-settings.protect_branch_name_pattern_desc=Patrones de nombre de rama protegidos. Consulte la documentación para la sintaxis de patrones. Ejemplos: principal, lanzamiento/**
settings.protect_patterns=Patrones
settings.protect_protected_file_patterns=Patrones de archivos protegidos (separados con punto y coma ';'):
settings.protect_protected_file_patterns_desc=No está permitido cambiar archivos directamente incluso si el usuario tiene permiso para agregar, editar o borrar archivos en esta rama. Múltiples patrones pueden separarse usando punto y coma (';'). Refvisa la documentación de github.com/gobwas/glob para la sintaxis de patrones. Ejemplos: .drone.yml, /docs/**/*.txt.
@@ -2507,7 +2496,6 @@ release.releases_for=Lanzamientos para %s
release.tags_for=Etiquetas para %s
branch.name=Nombre de la rama
-branch.search=Buscar rama
branch.already_exists=Una rama llamada "%s" ya existe.
branch.delete_head=Eliminar
branch.delete=`Eliminar rama "%s "`
@@ -2530,6 +2518,7 @@ branch.default_deletion_failed=La rama "%s" es la rama por defecto. No se puede
branch.restore=`Restaurar rama "%s"`
branch.download=`Descargar rama "%s"`
branch.rename=`Renombrar rama "%s"`
+branch.search=Buscar rama
branch.included_desc=Esta rama forma parte de la predeterminada
branch.included=Incluida
branch.create_new_branch=Crear rama desde la rama:
@@ -2857,7 +2846,6 @@ emails.updated=Email actualizado
emails.not_updated=Error al actualizar la dirección de correo electrónico solicitada: %v
emails.duplicate_active=Esta dirección de correo está asignada a un usuario diferente.
emails.change_email_header=Actualizar Propiedades de Correo
-emails.change_email_text=¿Realmente quiere actualizar esta dirección de correo electrónico?
orgs.org_manage_panel=Gestión de organizaciones
orgs.name=Nombre
@@ -3075,7 +3063,6 @@ config.enable_openid_signin=Habilitar el inicio de sesión con OpenID
config.show_registration_button=Mostrar Botón de Registro
config.require_sign_in_view=Requerir inicio de sesión obligatorio para ver páginas
config.mail_notify=Habilitar las notificaciones por correo electrónico
-config.disable_key_size_check=Deshabilitar la comprobación de Tamaño Mínimo de Clave
config.enable_captcha=Activar CAPTCHA
config.active_code_lives=Habilitar Vida del Código
config.reset_password_code_lives=Caducidad del código de recuperación de cuenta
@@ -3341,8 +3328,6 @@ alpine.repository.repositories=Repositorios
alpine.repository.architectures=Arquitecturas
cargo.registry=Configurar este registro en el archivo de configuración de Cargo (por ejemplo ~/.cargo/config.toml):
cargo.install=Para instalar el paquete usando Cargo, ejecute el siguiente comando:
-cargo.details.repository_site=Sitio del repositorio
-cargo.details.documentation_site=Sitio de documentación
chef.registry=Configura este registro en tu archivo ~/.chef/config.rb:
chef.install=Para instalar el paquete, ejecute el siguiente comando:
composer.registry=Configura este registro en el archivo ~/.composer/config.json:
@@ -3354,8 +3339,6 @@ conan.registry=Configurar este registro desde la línea de comandos:
conan.install=Para instalar el paquete usando Conan, ejecuta el siguiente comando:
conda.registry=Configura este registro como un repositorio Conda en tu archivo .condarc:
conda.install=Para instalar el paquete usando Conda, ejecute el siguiente comando:
-conda.details.repository_site=Sitio del repositorio
-conda.details.documentation_site=Sitio de documentación
container.details.type=Tipo de imagen
container.details.platform=Plataforma
container.pull=Arrastra la imagen desde la línea de comandos:
@@ -3525,7 +3508,6 @@ runs.commit=Commit
runs.scheduled=Programado
runs.pushed_by=push enviado por
runs.invalid_workflow_helper=El archivo de configuración del trabajo no es válido. Revisa tu archivo de configuración: %s
-runs.no_matching_runner_helper=No hay nodo coincidente: %s
runs.actor=Actor
runs.status=Estado
runs.actors_no_select=Todos los actores
@@ -3564,6 +3546,7 @@ type-3.display_name=Proyecto de organización
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=Directorio
normal_file=Archivo normal
executable_file=Archivo ejecutable
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index b9194c48a5..c9099299a0 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -83,9 +83,6 @@ write=نوشتن
preview=پیش نمایش
loading=بارگذاری…
-step1=مرحله ۱:
-step2=مرحله ۲:
-
error=خطا
error404=صفحه موردنظر شما یا وجود ندارد یا شما دسترسی کافی برای مشاهده آن را ندارید.
@@ -267,7 +264,6 @@ org_no_results=سازمانی مطابق با این مورد یافت نشد.
code_no_results=کد منبعی مطابق با جستجوی شما یافت نشد.
code_last_indexed_at=آخرین به روزرسانی در %s
-
[auth]
create_new_account=نامنویسی حساب کاربری
register_helper_msg=قبلا ثبت نام کردید؟ از اینجا وارد شوید!
@@ -799,10 +795,8 @@ transfer.reject_desc=رد انتقال به %s
desc.private=خصوصی
desc.public=عمومی
-desc.private_template=قالب خصوصی
-desc.public_template=قالب
+desc.template=قالب
desc.internal=داخلی
-desc.internal_template=قالب داخلی
desc.archived=بایگانی شده
template.items=موارد الگو
@@ -1382,9 +1376,6 @@ pulls.update_not_allowed=شما اجازه بروزرسانی شاخه را ند
pulls.outdated_with_base_branch=این شاخه با شاخه پایه منسوخ شده است
pulls.closed_at=`این درخواست pull بسته شده %[2]s`
pulls.reopened_at=`این درخواست pull را بازگشایی کرد %[2]s`
-pulls.merge_instruction_hint=`همچنین میتوانید دستورالعملهای خط فرمان را مشاهده کنید.`
-pulls.merge_instruction_step1_desc=از انبار پروژه خود، یک شاخه جدید را بگیرید و تغییرات را آزمایش کنید.
-pulls.merge_instruction_step2_desc=تغییرات را ادغام کنید و در Gitea به روز کنید.
@@ -2211,7 +2202,6 @@ emails.updated=ایمیل به روز شد
emails.not_updated=آدرس ایمیل درخواستی بهروزرسانی نشد: %v
emails.duplicate_active=این آدرس ایمیل از قبل برای کاربر دیگری فعال است.
emails.change_email_header=به روز رسانی ویژگی های ایمیل
-emails.change_email_text=آیا مطمئن هستید که می خواهید این آدرس ایمیل را به روز کنید؟
orgs.org_manage_panel=مدیریت سازمان
orgs.name=نام
@@ -2398,7 +2388,6 @@ config.enable_openid_signin=فعال کردن ورود با OpenID
config.show_registration_button=نشان دادن دکمه ثبت نام
config.require_sign_in_view=فعالسازی نیازمند به ورود در هنگام مشاهده صفحات
config.mail_notify=فعالسازی اعلانهای ایمیل (رایانامه)
-config.disable_key_size_check=غیر فعال کردن بررسی حداقل اندازه کلید
config.enable_captcha=فعال کردن کپچا
config.active_code_lives=عمر کد فعال سازی
config.reset_password_code_lives=مدت انقضای کد بازیابی حساب کاربری
@@ -2625,5 +2614,6 @@ runs.commit=کامیت
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=پیوند نمادین
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index 640739d5e7..b6abb49a35 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -96,9 +96,6 @@ write=Kirjoita
preview=Esikatselu
loading=Ladataan…
-step1=Vaihe 1:
-step2=Vaihe 2:
-
error=Virhe
error404=Sivu, jota yrität nähdä, joko ei löydy tai et ole oikeutettu katsomaan sitä.
@@ -276,7 +273,6 @@ org_no_results=Ei löytynyt vastaavia organisaatioita.
code_no_results=Hakuehtoasi vastaavaa lähdekoodia ei löytynyt.
code_last_indexed_at=Viimeksi indeksoitu %s
-
[auth]
create_new_account=Rekisteröi tili
register_helper_msg=On jo tili? Kirjaudu sisään nyt!
@@ -684,8 +680,7 @@ delete_preexisting_label=Poista
desc.private=Yksityinen
desc.public=Julkinen
-desc.private_template=Yksityinen malli
-desc.public_template=Malli
+desc.template=Malli
desc.internal=Sisäinen
desc.archived=Arkistoidut
@@ -1591,7 +1586,6 @@ config.db_path=Polku
config.service_config=Palvelu asetukset
config.show_registration_button=Näytä rekisteröidy painike
-config.disable_key_size_check=Poista käytöstä avaimen vähimmäiskoko tarkistus
config.enable_captcha=Ota CAPTCHA käyttöön
config.active_code_lives=Aktiivinen koodi elämät ennen vanhenemista
config.default_keep_email_private=Piilota sähköpostiosoitteet oletuksena
@@ -1750,4 +1744,5 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index 017444cbd0..f3a264c1c8 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -17,6 +17,7 @@ template=Modèle
language=Langue
notifications=Notifications
active_stopwatch=Suivi du temps actif
+tracked_time_summary=Résumé du pointage d’après les filtres de la liste des tickets
create_new=Créer…
user_profile_and_more=Profil et réglages…
signed_in_as=Connecté en tant que
@@ -90,6 +91,7 @@ remove=Retirer
remove_all=Tout Retirer
remove_label_str=Supprimer l’élément « %s »
edit=Éditer
+view=Voir
enabled=Activé
disabled=Désactivé
@@ -108,9 +110,6 @@ write=Écrire
preview=Aperçu
loading=Chargement…
-step1=Étape 1:
-step2=Étape 2:
-
error=Erreur
error404=La page que vous essayez d'atteindre n'existe pas ou vous n'êtes pas autorisé à la voir.
go_back=Retour
@@ -354,7 +353,6 @@ code_last_indexed_at=Dernière indexation %s
relevant_repositories_tooltip=Les dépôts qui sont des forks ou qui n'ont aucun sujet, aucune icône et aucune description sont cachés.
relevant_repositories=Seuls les dépôts pertinents sont affichés, afficher les résultats non filtrés.
-
[auth]
create_new_account=Créer un compte
register_helper_msg=Déjà enregistré ? Connectez-vous !
@@ -655,7 +653,7 @@ cancel=Annuler
language=Langue
ui=Thème
hidden_comment_types=Catégories de commentaires masqués
-hidden_comment_types_description=Les catégories cochées masquent les commentaires respectifs des tickets. Par exemple, « Label » cache les commentaires du genre « Cerise a attribué le label Bug il y a 2 heures. »
+hidden_comment_types_description=Cochez les catégories suivantes pour masquer les commentaires correspondants des fils d'activité. Par exemple, « Label » cache les commentaires du genre « Cerise a attribué le label Bug il y a 2 heures. »
hidden_comment_types.ref_tooltip=Commentaires où ce ticket a été référencé sur un autre ticket, révision, etc.
hidden_comment_types.issue_ref_tooltip=Commentaires où l’utilisateur change la branche/étiquette associée au ticket
comment_type_group_reference=Référence
@@ -866,6 +864,7 @@ revoke_oauth2_grant_description=La révocation de l'accès à cette application
revoke_oauth2_grant_success=Accès révoqué avec succès.
twofa_desc=L'authentification à deux facteurs améliore la sécurité de votre compte.
+twofa_recovery_tip=Si vous perdez votre appareil, vous pourrez utiliser une clé de récupération à usage unique pour obtenir l’accès à votre compte.
twofa_is_enrolled=Votre compte est inscrit à l'authentification à deux facteurs.
twofa_not_enrolled=Votre compte n'est pas inscrit à l'authentification à deux facteurs.
twofa_disable=Désactiver l'authentification à deux facteurs
@@ -888,6 +887,8 @@ webauthn_register_key=Ajouter une clé de sécurité
webauthn_nickname=Pseudonyme
webauthn_delete_key=Retirer la clé de sécurité
webauthn_delete_key_desc=Si vous retirez une clé de sécurité, vous ne pourrez plus l'utiliser pour vous connecter. Continuer ?
+webauthn_key_loss_warning=Si vous perdez vos clés de sécurité, vous perdrez l’accès à votre compte.
+webauthn_alternative_tip=Vous devriez configurer une méthode d’authentification supplémentaire.
manage_account_links=Gérer les comptes liés
manage_account_links_desc=Ces comptes externes sont liés à votre compte Gitea.
@@ -924,7 +925,7 @@ visibility.private=Privé
visibility.private_tooltip=Visible uniquement aux membres des organisations que vous avez rejointes
[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
@@ -1029,10 +1030,8 @@ transfer.no_permission_to_reject=Vous n’êtes pas autorisé à rejeter ce tran
desc.private=Privé
desc.public=Publique
-desc.private_template=Modèle privé
-desc.public_template=Modèle
+desc.template=Modèle
desc.internal=Interne
-desc.internal_template=Modèle interne
desc.archived=Archivé
template.items=Élément du modèle
@@ -1391,7 +1390,7 @@ issues.add_label=a ajouté le label %s %s.
issues.add_labels=a ajouté les labels %s %s.
issues.remove_label=a retiré le label %s %s.
issues.remove_labels=a supprimé les labels %s %s.
-issues.add_remove_labels=a ajouté %s et supprimé %s labels %s.
+issues.add_remove_labels=a ajouté le label %s et supprimé %s %s.
issues.add_milestone_at=`a ajouté ça au jalon %s %s.`
issues.add_project_at=`a ajouté ça au projet %s %s.`
issues.change_milestone_at=`a remplacé le jalon %s vers %s
-push_tag=a poussé l’étiquette %[3]s vers %[4]s
+push_tag=a poussé l’étiquette %[3]s de %[4]s
delete_tag=a supprimé l’étiquette %[2]s de %[3]s
delete_branch=a supprimée la branche %[2]s de %[3]s
compare_branch=Comparer
@@ -3236,12 +3239,12 @@ compare_commits_general=Comparer les révisions
mirror_sync_push=a synchronisé les révisions de %[3]s d’un miroir vers %[4]s.
mirror_sync_create=a synchronisé la nouvelle référence %[3]s d’un miroir vers %[4]s.
mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence %[2]s vers %[3]s depuis le miroir
-approve_pull_request=`a approuvé %[3]s#%[2]s.`
+approve_pull_request=`a approuvé %[3]s#%[2]s`
reject_pull_request=`a suggérés des changements pour %[3]s#%[2]s`
-publish_release=`a publié "%[4]s" à %[3]s`
-review_dismissed=`a révoqué l’évaluation de %[4]s sur %[3]s#%[2]s.`
+publish_release=`a publié "%[4]s" dans %[3]s`
+review_dismissed=`a révoqué l’évaluation de %[4]s dans %[3]s#%[2]s`
review_dismissed_reason=Raison :
-create_branch=a créé la branche %[3]s dans %[4]s.
+create_branch=a créé la branche %[3]s dans %[4]s
starred_repo=aime %[2]s
watched_repo=observe %[2]s
@@ -3341,8 +3344,6 @@ alpine.repository.repositories=Dépôts
alpine.repository.architectures=Architectures
cargo.registry=Configurez ce registre dans le fichier de configuration Cargo (par exemple ~/.cargo/config.toml) :
cargo.install=Pour installer le paquet en utilisant Cargo, exécutez la commande suivante :
-cargo.details.repository_site=Site du dépôt
-cargo.details.documentation_site=Site de documentation
chef.registry=Configurer ce registre dans votre fichier ~/.chef/config.rb:
chef.install=Pour installer le paquet, exécutez la commande suivante :
composer.registry=Configurez ce registre dans votre fichier ~/.composer/config.json :
@@ -3354,8 +3355,6 @@ conan.registry=Configurez ce registre à partir d'un terminal :
conan.install=Pour installer le paquet en utilisant Conan, exécutez la commande suivante :
conda.registry=Configurez ce registre en tant que dépôt Conda dans le fichier .condarc :
conda.install=Pour installer le paquet en utilisant Conda, exécutez la commande suivante :
-conda.details.repository_site=Site du dépôt
-conda.details.documentation_site=Site de documentation
container.details.type=Type d'image
container.details.platform=Plateforme
container.pull=Tirez l'image depuis un terminal :
@@ -3525,13 +3524,17 @@ runs.commit=Révision
runs.scheduled=Planifié
runs.pushed_by=soumis par
runs.invalid_workflow_helper=La configuration du flux de travail est invalide. Veuillez vérifier votre fichier %s.
-runs.no_matching_runner_helper=Aucun exécuteur correspondant : %s
+runs.no_matching_online_runner_helper=Aucun exécuteur en ligne correspondant au libellé %s
runs.actor=Acteur
runs.status=Statut
runs.actors_no_select=Tous les acteurs
runs.status_no_select=Touts les statuts
runs.no_results=Aucun résultat correspondant.
+runs.no_workflows=Il n'y a pas encore de workflows.
+runs.no_workflows.quick_start=Vous ne savez pas comment commencer avec Gitea Action ? Consultez le guide de démarrage rapide.
+runs.no_workflows.documentation=Pour plus d’informations sur les Actions Gitea, voir la documentation.
runs.no_runs=Le flux de travail n'a pas encore d'exécution.
+runs.empty_commit_message=(message de révision vide)
workflow.disable=Désactiver le flux de travail
workflow.disable_success=Le flux de travail « %s » a bien été désactivé.
@@ -3564,6 +3567,7 @@ type-3.display_name=Projet d’organisation
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=Dossier
normal_file=Fichier normal
executable_file=Fichier exécutable
diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini
index c22a049817..aee4b44edf 100644
--- a/options/locale/locale_hu-HU.ini
+++ b/options/locale/locale_hu-HU.ini
@@ -75,9 +75,6 @@ write=Írás
preview=Előnézet
loading=Betöltés…
-step1=1. lépés:
-step2=2. lépés:
-
error404=Az elérni kívánt oldal vagy nem létezik, vagy nincs jogosultsága a megtekintéséhez.
@@ -233,7 +230,6 @@ org_no_results=Nincs ilyen szervezet.
code_no_results=Nincs találat a keresési kifejezésedre.
code_last_indexed_at=Utoljára indexelve: %s
-
[auth]
create_new_account=Regisztráció
register_helper_msg=Van már felhasználói fiókja? Jelentkezzen be!
@@ -613,8 +609,7 @@ delete_preexisting_label=Törlés
desc.private=Privát
desc.public=Nyilvános
-desc.private_template=Privát sablon
-desc.public_template=Sablon
+desc.template=Sablon
desc.internal=Belső
desc.archived=Archivált
@@ -1481,7 +1476,6 @@ config.enable_openid_signin=OpenID bejelentkezés engedélyezése
config.show_registration_button=Regisztráció gomb megjelenítése
config.require_sign_in_view=Bejelentkezés megkövetelése az oldalak megtekintéséhez
config.mail_notify=E-mail értesítés engedélyezése
-config.disable_key_size_check=Minimális kulcsméret ellenőrzés letiltása
config.enable_captcha=CAPTCHA engedélyezése
config.active_code_lives=Aktív kód élettartam
config.reset_password_code_lives=Fiók visszaállítási kód lejárati idő
@@ -1660,5 +1654,6 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Szimbolikus hivatkozás
diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini
index a5efde6d07..4dd7c299df 100644
--- a/options/locale/locale_id-ID.ini
+++ b/options/locale/locale_id-ID.ini
@@ -77,7 +77,6 @@ loading=Memuat…
-
concept_code_repository=Repositori
@@ -153,7 +152,6 @@ user_no_results=Tidak ditemukan pengguna yang cocok.
org_no_results=Tidak ada organisasi yang cocok ditemukan.
code_no_results=Tidak ada kode sumber yang cocok dengan istilah yang anda cari.
-
[auth]
create_new_account=Daftar Akun
register_helper_msg=Sudah memiliki akun? Masuk sekarang!
@@ -534,7 +532,7 @@ delete_preexisting_label=Hapus
desc.private=Pribadi
-desc.public_template=Contoh
+desc.template=Contoh
template.webhooks=Webhooks
template.topics=Topik
@@ -1169,7 +1167,6 @@ config.enable_openid_signin=Aktifkan Login OpenID
config.show_registration_button=Tampilkan tombol mendaftar
config.require_sign_in_view=Harus Login Untuk Melihat Halaman
config.mail_notify=Aktifkan Notifikasi Email
-config.disable_key_size_check=Menonaktifkan memeriksa ukuran kunci minimum
config.enable_captcha=Aktifkan CAPTCHA
config.active_code_lives=Kode aktif hidup
@@ -1346,4 +1343,5 @@ runs.commit=Memperbuat
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini
index 28ce5ae7f7..2ba623dc12 100644
--- a/options/locale/locale_is-IS.ini
+++ b/options/locale/locale_is-IS.ini
@@ -94,9 +94,6 @@ write=Skrifa
preview=Forskoða
loading=Hleður…
-step1=Skref 1:
-step2=Skref 2:
-
error=Villa
error404=Síðan sem þú ert að reyna að fá annað hvort er ekki til eða þú hefur ekki heimild til að skoða hana.
@@ -251,7 +248,6 @@ user_no_results=Engir samsvarandi notendur fundust.
org_no_results=Engar samsvarandi stofnanir fundust.
code_no_results=Enginn samsvarandi frumkóði fannst eftur þínum leitarorðum.
-
[auth]
create_new_account=Skrá Notanda
register_helper_msg=Ertu nú þegar með notanda? Skráðu þig inn núna!
@@ -612,10 +608,8 @@ delete_preexisting_content=Eyða skrám í %s
desc.private=Einka
desc.public=Opinbert
-desc.private_template=Einka sniðmát
-desc.public_template=Sniðmát
+desc.template=Sniðmát
desc.internal=Innra
-desc.internal_template=Innra sniðmát
desc.archived=Safnvistað
template.git_content=Git Innihald (Sjálfgefin Grein)
@@ -1371,4 +1365,5 @@ runs.commit=Framlag
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index e73d063613..a30232dd10 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -97,9 +97,6 @@ write=Scrivi
preview=Anteprima
loading=Caricamento…
-step1=Passo 1:
-step2=Passo 2:
-
error=Errore
error404=La pagina che stai cercando di raggiungere non esiste oppure non sei autorizzato a visualizzarla.
@@ -289,7 +286,6 @@ org_no_results=Nessun'organizzazione corrispondente trovata.
code_no_results=Nessun codice sorgente corrispondente ai termini di ricerca.
code_last_indexed_at=Ultimo indicizzato %s
-
[auth]
create_new_account=Registra un account
register_helper_msg=Hai già un account? Accedi ora!
@@ -858,10 +854,8 @@ transfer.reject_desc=`Annulla il trasferimento a "%s"`
desc.private=Privato
desc.public=Pubblico
-desc.private_template=Modello privato
-desc.public_template=Modello
+desc.template=Template
desc.internal=Interno
-desc.internal_template=Template interno
desc.archived=Archiviato
template.items=Elementi del modello
@@ -1495,9 +1489,6 @@ pulls.update_not_allowed=Non sei abilitato ad aggiornare il branch
pulls.outdated_with_base_branch=Questo brench non è aggiornato con il branch di base
pulls.closed_at=`chiusa questa pull request %[2]s`
pulls.reopened_at=`riaperta questa pull request %[2]s`
-pulls.merge_instruction_hint=`Puoi anche visualizzare le istruzioni da riga di comando.`
-pulls.merge_instruction_step1_desc=Dal repository del tuo progetto, fai il check out di un nuovo branch e verifica le modifiche.
-pulls.merge_instruction_step2_desc=Fai il merge delle modifiche e aggiorna su Gitea.
pulls.auto_merge_button_when_succeed=(Quando i controlli sono superati)
pulls.auto_merge_when_succeed=Unione automatica quando tutti i controlli sono superati
@@ -2388,7 +2379,6 @@ emails.updated=Email aggiornata
emails.not_updated=Impossibile aggiornare l'indirizzo email richiesto: %v
emails.duplicate_active=Questo indirizzo email risulta già attivo per un altro utente.
emails.change_email_header=Aggiorna proprietà email
-emails.change_email_text=Sei sicuro di voler aggiornare questo indirizzo email?
orgs.org_manage_panel=Gestione Organizzazione
orgs.name=Nome
@@ -2592,7 +2582,6 @@ config.enable_openid_signin=Attiva l'accesso tramite OpenID
config.show_registration_button=Mostra Pulsane Registrazione
config.require_sign_in_view=Richiedi l'accesso per visualizzare le pagine
config.mail_notify=Attila le notifiche Email
-config.disable_key_size_check=Disabilita controllo sulle dimensioni minime della chiave
config.enable_captcha=Attiva CAPTCHA
config.active_code_lives=Attiva Vita del Codice
config.reset_password_code_lives=Recupera il codice di scadenza del tempo del tuo account
@@ -2914,5 +2903,6 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Link Simbolico
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index df1cd0a540..9216277955 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -17,6 +17,7 @@ template=テンプレート
language=言語
notifications=通知
active_stopwatch=進行中のタイムトラッカー
+tracked_time_summary=イシューリストのフィルタに基づき集計したトラッキング時間
create_new=作成…
user_profile_and_more=プロフィールと設定…
signed_in_as=サインイン済み
@@ -90,6 +91,7 @@ remove=除去
remove_all=すべて除去
remove_label_str=アイテム「%s」を削除
edit=編集
+view=表示
enabled=有効
disabled=無効
@@ -108,9 +110,6 @@ write=書き込み
preview=プレビュー
loading=読み込み中…
-step1=ステップ 1:
-step2=ステップ 2:
-
error=エラー
error404=アクセスしようとしたページは存在しないか、閲覧が許可されていません。
go_back=戻る
@@ -354,7 +353,6 @@ code_last_indexed_at=最終取得 %s
relevant_repositories_tooltip=フォークリポジトリや、トピック、アイコン、説明のいずれも無いリポジトリは表示されません。
relevant_repositories=妥当と思われるリポジトリのみを表示しています。 フィルタリングしない結果を表示。
-
[auth]
create_new_account=アカウントを登録
register_helper_msg=既にアカウントをお持ちですか? 今すぐサインインしましょう!
@@ -363,6 +361,7 @@ disable_register_prompt=登録は無効になっています。 サイト管理
disable_register_mail=登録でのメール確認は無効になっています。
manual_activation_only=アクティベーションを完了するにはサイト管理者に連絡してください。
remember_me=このデバイスで自動サインイン
+remember_me.compromised=ログイントークンはもう有効ではなく、アカウントが侵害されたことを示している可能性があります。 異常なアクティビティがないかアカウントを確認してください。
forgot_password_title=パスワードを忘れた
forgot_password=パスワードをお忘れですか?
sign_up_now=アカウントが必要ですか? 今すぐ登録しましょう。
@@ -627,11 +626,11 @@ applications=アプリケーション
orgs=組織の管理
repos=リポジトリ
delete=アカウントを削除
-twofa=2要素認証
+twofa=2要素認証 (TOTP)
account_link=連携アカウント
organization=組織
uid=UID
-webauthn=セキュリティキー
+webauthn=2要素認証 (セキュリティキー)
public_profile=公開プロフィール
biography_placeholder=自己紹介してください!(Markdownを使うことができます)
@@ -865,22 +864,23 @@ revoke_oauth2_grant=アクセス権の取り消し
revoke_oauth2_grant_description=このサードパーティ アプリケーションのアクセス権を取り消し、アプリケーションがあなたのデータへアクセスすることを防ぎます。 続行しますか?
revoke_oauth2_grant_success=アクセス権を取り消しました。
-twofa_desc=2要素認証はアカウントのセキュリティを強化します。
+twofa_desc=パスワードの盗難からアカウントを守るために、スマートフォンや他のデバイスを使用して、時間ベースのワンタイムパスワード("TOTP")を受け取ることができます。
+twofa_recovery_tip=デバイスを紛失した場合は、一回限りのリカバリキーを使用してアカウントへのアクセスを回復することができます。
twofa_is_enrolled=このアカウントは2要素認証が有効になっています。
twofa_not_enrolled=このアカウントは2要素認証が設定されていません。
twofa_disable=2要素認証を無効にする
-twofa_scratch_token_regenerate=スクラッチトークンを再生成
-twofa_scratch_token_regenerated=あなたのスクラッチトークンは %s になりました。 安全な場所に保管してください。 二度と表示されません。
+twofa_scratch_token_regenerate=一回限りのリカバリキーを再生成
+twofa_scratch_token_regenerated=あなたの一回限りのリカバリキーは %s になりました。 安全な場所に保管してください。 これは二度と表示されません。
twofa_enroll=2要素認証の開始
twofa_disable_note=2要素認証は必要に応じて無効にできます。
twofa_disable_desc=2要素認証を無効にするとアカウントのセキュリティが低下します。 続行しますか?
-regenerate_scratch_token_desc=スクラッチトークンを紛失した場合やサインインで使用済みとなった場合は、ここでリセットできます。
+regenerate_scratch_token_desc=リカバリキーを紛失した場合や、すでにサインインに使用済みの場合は、ここでリセットできます。
twofa_disabled=2要素認証を無効にしました。
scan_this_image=この画像を認証アプリケーションで読み取ってください。
or_enter_secret=またはシークレット文字列を入力: %s
then_enter_passcode=次に、アプリケーションに表示されているパスコードを入力します。
passcode_invalid=パスコードが間違っています。 再度お試しください。
-twofa_enrolled=あなたのアカウントに2要素認証が設定されました。 スクラッチトークン (%s) は一度しか表示しませんので安全な場所に保存してください!
+twofa_enrolled=あなたのアカウントは正常に登録されました。 一回限りのリカバリキー (%s) は安全な場所に保存してください。 これは二度と表示されません。
twofa_failed_get_secret=シークレットが取得できません。
webauthn_desc=セキュリティキーは暗号化キーを内蔵するハードウェア ・ デバイスです。 2要素認証に使用できます。 セキュリティキーはWebAuthn Authenticator規格をサポートしている必要があります。
@@ -888,6 +888,8 @@ webauthn_register_key=セキュリティキーを追加
webauthn_nickname=ニックネーム
webauthn_delete_key=セキュリティキーの登録解除
webauthn_delete_key_desc=セキュリティキーの登録を解除すると、今後そのセキュリティキーでサインインすることはできなくなります。 続行しますか?
+webauthn_key_loss_warning=セキュリティキーを紛失すると、アカウントへのアクセスを失います。
+webauthn_alternative_tip=もうひとつ別の認証方法も設定しておくと良いでしょう。
manage_account_links=連携アカウントの管理
manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。
@@ -1029,10 +1031,8 @@ transfer.no_permission_to_reject=この移転を拒否する権限がありま
desc.private=プライベート
desc.public=公開
-desc.private_template=プライベートテンプレート
-desc.public_template=テンプレート
+desc.template=テンプレート
desc.internal=組織内
-desc.internal_template=組織内テンプレート
desc.archived=アーカイブ
template.items=テンプレート項目
@@ -1789,6 +1789,8 @@ pulls.status_checks_failure=失敗したステータスチェックがありま
pulls.status_checks_error=ステータスチェックによりエラーが出ています
pulls.status_checks_requested=必須
pulls.status_checks_details=詳細
+pulls.status_checks_hide_all=すべてのチェックを隠す
+pulls.status_checks_show_all=すべてのチェックを表示
pulls.update_branch=マージでブランチを更新
pulls.update_branch_rebase=リベースでブランチを更新
pulls.update_branch_success=ブランチの更新が成功しました
@@ -1797,9 +1799,11 @@ pulls.outdated_with_base_branch=このブランチはベースブランチに対
pulls.close=プルリクエストをクローズ
pulls.closed_at=`がプルリクエストをクローズ %[2]s`
pulls.reopened_at=`がプルリクエストを再オープン %[2]s`
-pulls.merge_instruction_hint=`コマンドラインの手順も確認できます。`
-pulls.merge_instruction_step1_desc=あなたのプロジェクトリポジトリで新しいブランチをチェックアウトし、変更内容をテストします。
-pulls.merge_instruction_step2_desc=変更内容をマージして、Giteaに反映します。
+pulls.cmd_instruction_hint=`コマンドラインの手順を表示します。`
+pulls.cmd_instruction_checkout_title=チェックアウト
+pulls.cmd_instruction_checkout_desc=プロジェクトリポジトリから新しいブランチをチェックアウトし、変更内容をテストします。
+pulls.cmd_instruction_merge_title=マージ
+pulls.cmd_instruction_merge_desc=変更内容をマージして、Giteaに反映します。
pulls.clear_merge_message=マージメッセージをクリア
pulls.clear_merge_message_hint=マージメッセージのクリアは、コミットメッセージの除去だけを行います。 生成されたGitトレーラー("Co-Authored-By …" 等)はそのまま残ります。
@@ -2311,7 +2315,7 @@ settings.dismiss_stale_approvals_desc=プルリクエストの内容を変える
settings.require_signed_commits=コミット署名必須
settings.require_signed_commits_desc=署名されていない場合、または署名が検証できなかった場合は、このブランチへのプッシュを拒否します。
settings.protect_branch_name_pattern=保護ブランチ名のパターン
-settings.protect_branch_name_pattern_desc=保護ブランチ名のパターン。書き方についてはドキュメント を参照してください。例: main, release/**
+settings.protect_branch_name_pattern_desc=保護ブランチ名のパターン。書き方については ドキュメント を参照してください。例: main, release/**
settings.protect_patterns=パターン
settings.protect_protected_file_patterns=保護されるファイルのパターン (セミコロン';'で区切る):
settings.protect_protected_file_patterns_desc=保護されたファイルは、このブランチにファイルを追加・編集・削除する権限を持つユーザーであっても、直接変更することができなくなります。 セミコロン(';')で区切って複数のパターンを指定できます。 パターンの文法については github.com/gobwas/glob を参照してください。 例: .drone.yml, /docs/**/*.txt
@@ -2507,7 +2511,6 @@ release.releases_for=%s のリリース
release.tags_for=%s のタグ
branch.name=ブランチ名
-branch.search=ブランチを検索
branch.already_exists=ブランチ "%s" は既に存在します。
branch.delete_head=削除
branch.delete=ブランチ "%s" の削除
@@ -2530,6 +2533,7 @@ branch.default_deletion_failed=ブランチ "%s" はデフォルトブランチ
branch.restore=ブランチ "%s" の復元
branch.download=ブランチ "%s" をダウンロード
branch.rename=ブランチ名 "%s" を変更
+branch.search=ブランチを検索
branch.included_desc=このブランチはデフォルトブランチに含まれています
branch.included=埋没
branch.create_new_branch=このブランチをもとに作成します:
@@ -2857,7 +2861,7 @@ emails.updated=メール設定を更新しました
emails.not_updated=メール設定の更新に失敗しました: %v
emails.duplicate_active=メールアドレスは別のユーザーが既に使用中です。
emails.change_email_header=メール設定の更新
-emails.change_email_text=このメールアドレスを設定してよろしいですか?
+emails.change_email_text=このメールアドレスで更新してもよろしいですか?
orgs.org_manage_panel=組織の管理
orgs.name=名称
@@ -2882,6 +2886,7 @@ packages.package_manage_panel=パッケージ管理
packages.total_size=合計サイズ: %s
packages.unreferenced_size=非参照サイズ: %s
packages.cleanup=期限切れデータを掃除する
+packages.cleanup.success=期限切れのデータを正常にクリーンアップしました
packages.owner=オーナー
packages.creator=作成者
packages.name=名前
@@ -3075,7 +3080,6 @@ config.enable_openid_signin=OpenIDを使ったサインイン有効
config.show_registration_button=登録ボタンを表示
config.require_sign_in_view=ページ閲覧にサインインが必要
config.mail_notify=メール通知有効
-config.disable_key_size_check=最小キー長のチェックが無効
config.enable_captcha=CAPTCHA有効
config.active_code_lives=アカウント確認リンクの有効時間
config.reset_password_code_lives=アカウント回復リンクの有効時間
@@ -3341,8 +3345,6 @@ alpine.repository.repositories=Repositories
alpine.repository.architectures=Architectures
cargo.registry=Cargo 設定ファイルでこのレジストリをセットアップします。(例 ~/.cargo/config.toml):
cargo.install=Cargo を使用してパッケージをインストールするには、次のコマンドを実行します:
-cargo.details.repository_site=リポジトリサイト
-cargo.details.documentation_site=ドキュメンテーションサイト
chef.registry=あなたの ~/.chef/config.rb ファイルに、このレジストリをセットアップします:
chef.install=パッケージをインストールするには、次のコマンドを実行します:
composer.registry=あなたの ~/.composer/config.json ファイルに、このレジストリをセットアップします:
@@ -3354,8 +3356,6 @@ conan.registry=このレジストリをコマンドラインからセットア
conan.install=Conan を使用してパッケージをインストールするには、次のコマンドを実行します:
conda.registry=あなたの .condarc ファイルに、このレジストリを Conda リポジトリとしてセットアップします:
conda.install=Conda を使用してパッケージをインストールするには、次のコマンドを実行します:
-conda.details.repository_site=リポジトリサイト
-conda.details.documentation_site=ドキュメンテーションサイト
container.details.type=イメージタイプ
container.details.platform=プラットフォーム
container.pull=コマンドラインでイメージを取得します:
@@ -3457,7 +3457,7 @@ owner.settings.chef.keypair.description=Chefレジストリの認証にはキー
[secrets]
secrets=シークレット
description=シークレットは特定のActionsに渡されます。 それ以外で読み出されることはありません。
-none=まだシークレットはありません。
+none=シークレットはまだありません。
creation=シークレットを追加
creation.name_placeholder=大文字小文字の区別なし、英数字とアンダースコアのみ、GITEA_ や GITHUB_ で始まるものは不可
creation.value_placeholder=内容を入力してください。前後の空白は除去されます。
@@ -3525,13 +3525,17 @@ runs.commit=コミット
runs.scheduled=スケジュール済み
runs.pushed_by=pushed by
runs.invalid_workflow_helper=ワークフロー設定ファイルは無効です。あなたの設定ファイルを確認してください: %s
-runs.no_matching_runner_helper=一致するランナーがありません: %s
+runs.no_matching_online_runner_helper=ラベルに一致するオンラインのランナーが見つかりません: %s
runs.actor=アクター
runs.status=ステータス
runs.actors_no_select=すべてのアクター
runs.status_no_select=すべてのステータス
runs.no_results=一致する結果はありません。
+runs.no_workflows=ワークフローはまだありません。
+runs.no_workflows.quick_start=Gitea Action の始め方がわからない? クイックスタートガイドをご覧ください。
+runs.no_workflows.documentation=Gitea Action の詳細については、ドキュメントを参照してください。
runs.no_runs=ワークフローはまだ実行されていません。
+runs.empty_commit_message=(空のコミットメッセージ)
workflow.disable=ワークフローを無効にする
workflow.disable_success=ワークフロー '%s' が無効になりました。
@@ -3564,6 +3568,7 @@ type-3.display_name=組織プロジェクト
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=ディレクトリ
normal_file=ノーマルファイル
executable_file=実行可能ファイル
diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini
index d33bf0f850..1c79ee6bc7 100644
--- a/options/locale/locale_ko-KR.ini
+++ b/options/locale/locale_ko-KR.ini
@@ -77,7 +77,6 @@ loading=불러오는 중...
-
concept_code_repository=저장소
concept_user_organization=조직
@@ -218,7 +217,6 @@ user_no_results=일치하는 사용자가 없습니다.
org_no_results=일치하는 조직이 없습니다.
code_no_results=검색어와 일치하는 소스코드가 없습니다.
-
[auth]
create_new_account=계정 등록
register_helper_msg=이미 계정을 가지고 계신가요? 로그인하세요!
@@ -578,7 +576,7 @@ delete_preexisting_label=삭제
desc.private=비공개
-desc.public_template=템플릿
+desc.template=템플릿
template.topics=토론 주제
template.avatar=아바타
@@ -1433,7 +1431,6 @@ config.enable_openid_signin=OpenID 로그인 활성화
config.show_registration_button=등록 버튼을 표시
config.require_sign_in_view=페이지를 보려면 로그인 필수
config.mail_notify=이메일 알림 활성화
-config.disable_key_size_check=최소 키 크기 검사를 비활성화
config.enable_captcha=CAPTCHA 활성화
config.active_code_lives=코드 만료 기한
config.default_keep_email_private=기본적으로 이메일 주소를 숨김
@@ -1604,4 +1601,5 @@ runs.commit=커밋
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index 1af1cc3685..e275b02ba0 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -3,7 +3,8 @@ dashboard=Infopanelis
explore=Izpētīt
help=Palīdzība
logo=Logo
-sign_in=Pierakstīties
+sign_in=Pieteikties
+sign_in_with_provider=Pieteikties ar %s
sign_in_or=vai
sign_out=Izrakstīties
sign_up=Reģistrēties
@@ -18,7 +19,7 @@ notifications=Paziņojumi
active_stopwatch=Aktīvā laika uzskaite
create_new=Izveidot…
user_profile_and_more=Profils un iestatījumi…
-signed_in_as=Pierakstījies kā
+signed_in_as=Pieteicies kā
enable_javascript=Šai lapas darbībai ir nepieciešams JavaScript.
toc=Satura rādītājs
licenses=Licences
@@ -79,6 +80,7 @@ milestones=Atskaites punkti
ok=Labi
cancel=Atcelt
+retry=Mēģināt vēlreiz
rerun=Palaist atkārtoti
rerun_all=Palaist atkārtoti visus darbus
save=Saglabāt
@@ -94,6 +96,7 @@ disabled=Atspējots
copy=Kopēt
copy_url=Kopēt saiti
+copy_hash=Kopēt jaucējkodu
copy_content=Kopēt saturu
copy_branch=Kopēt atzara nosaukumu
copy_success=Nokopēts!
@@ -104,9 +107,6 @@ write=Rakstīt
preview=Priekšskatītījums
loading=Notiek ielāde…
-step1=Solis 1:
-step2=Solis 2:
-
error=Kļūda
error404=Lapa, ko vēlaties atvērt, neeksistē vai arī Jums nav tiesības to aplūkot.
@@ -131,6 +131,7 @@ show_timestamps=Rādīt laika zīmogus
show_log_seconds=Rādīt sekundes
show_full_screen=Atvērt pilnā logā
+confirm_delete_selected=Apstiprināt, lai izdzēstu visus atlasītos vienumus?
name=Nosaukums
value=Vērtība
@@ -252,14 +253,14 @@ federated_avatar_lookup_popup=Iespējot apvienoto profila bilžu meklētāju, la
disable_registration=Atspējot lietotāju reģistrāciju
disable_registration_popup=Atspējot iespēju reģistrēties. Tikai administratori varēs izveidot jaunus kontus.
allow_only_external_registration_popup=Atļaut reģistrēties tikai ar ārējiem servisiem
-openid_signin=Iespējot OpenID autorizāciju
-openid_signin_popup=Iespējot lietotāju autorizāciju ar OpenID.
+openid_signin=Iespējot pieteikšanos ar OpenID
+openid_signin_popup=Iespējot lietotāju pieteikšanos ar OpenID.
openid_signup=Iespējot reģistrāciju, izmantojot OpenID
openid_signup_popup=Iespējot lietotāju reģistrāciju pirms tam autorizējoties ar OpenID.
enable_captcha=Pieprasīt drošības kodu lietotāju reģistrācijā
enable_captcha_popup=Lietotājam reģistrējoties, pieprasīt ievadīt drošības kodu.
-require_sign_in_view=Iespējot nepieciešamību autorizēties, lai aplūkotu lapas
-require_sign_in_view_popup=Tikai autorizēti lietotāji var aplūkot lapas. Apmeklētāji redzēs tikai autorizācijas un reģistrācijas lapu.
+require_sign_in_view=Pieprasīt pieteikšanos, lai aplūkotu lapas
+require_sign_in_view_popup=Ierobežot piekļuvi lapām tikai lietotājiem, kuri ir pieteikušies. Apmeklētāji redzēs tikai pieteikšanās un reģistrēšanās lapu.
admin_setting_desc=Nav nepieciešams izveidot administratora kontu uzreiz, pirmais reģistrētais lietotājs saņems administratora tiesības automātiski.
admin_title=Administratora konta iestatījumi
admin_name=Administratora lietotājvārds
@@ -342,10 +343,9 @@ code_last_indexed_at=Pēdējo reizi indeksēts %s
relevant_repositories_tooltip=Repozitoriju, kas ir atdalīti vai kuriem nav tēmas, ikonas un apraksta ir paslēpti.
relevant_repositories=Tikai būtiskie repozitoriji tiek rādīti, pārādīt nefiltrētus rezultātus.
-
[auth]
create_new_account=Reģistrēt kontu
-register_helper_msg=Jau ir konts? Pieraksties tagad!
+register_helper_msg=Jau ir konts? Piesakieties tagad!
social_register_helper_msg=Jau ir konts? Piesaisti to!
disable_register_prompt=Reģistrācija ir atspējota. Lūdzu, sazinieties ar vietnes administratoru.
disable_register_mail=Reģistrācijas e-pasta apstiprināšana ir atspējota.
@@ -360,7 +360,8 @@ allow_password_change=Pieprasīt lietotājam mainīt paroli (ieteicams)
reset_password_mail_sent_prompt=Apstiprināšanas e-pasts tika nosūtīts uz %s. Pārbaudiet savu e-pasta kontu tuvāko %s laikā, lai pabeigtu paroles atjaunošanas procesu.
active_your_account=Aktivizēt savu kontu
account_activated=Konts ir aktivizēts
-prohibit_login=Aizliegt pieteikšanos
+prohibit_login=Pieteikšanās liegta
+prohibit_login_desc=Jūsu konts ir bloķēts, sazinieties ar sistēmas administratoru.
resent_limit_prompt=Jūs pieprasījāt aktivizācijas e-pastu pārāk bieži. Lūdzu, uzgaidiet 3 minūtes un mēģiniet vēlreiz.
has_unconfirmed_mail=Sveiki %s, Jums ir neapstiprināta e-pasta adrese (%s). Ja neesat saņēmis apstiprināšanas e-pastu vai Jums ir nepieciešams nosūtīt jaunu, lūdzu, nospiediet pogu, kas atrodas zemāk.
resend_mail=Nospiediet šeit, lai vēlreiz nosūtītu aktivizācijas e-pastu
@@ -370,25 +371,26 @@ reset_password=Paroles atjaunošana
invalid_code=Jūsu apstiprināšanas kodam ir beidzies derīguma termiņš vai arī tas ir nepareizs.
invalid_password=Jūsu parole neatbilst parolei, kas tika ievadīta veidojot so kontu.
reset_password_helper=Atjaunot paroli
+reset_password_wrong_user=Jūs esat pieteicies kā %s, bet konta atkopšanas saite ir paredzēta lietotājam %s
password_too_short=Paroles garums nedrīkst būt mazāks par %d simboliem.
non_local_account=Ārējie konti nevar mainīt paroli, izmantojot, Gitea saskarni.
verify=Pārbaudīt
scratch_code=Vienreizējais kods
use_scratch_code=Izmantot vienreizējo kodu
twofa_scratch_used=Vienreizējais kods tika izmantots. Notika pārvirzīšana uz divfaktoru iestatījumu lapu, lai varētu pārsaistīt jaunu ierīci vai uzģenerēt jaunu vienreizējo kodu.
-twofa_passcode_incorrect=Jūsu kods nav pareizs. Ja esat pazaudējis ierīci, izmantojiet vienreizējo kodu, lai autorizētos.
+twofa_passcode_incorrect=Piekļuves kods nav pareizs. Ja esat pazaudējis ierīci, izmantojiet vienreizējo kodu, lai pieteiktos.
twofa_scratch_token_incorrect=Ievadīts nepareizs vienreizējais kods.
-login_userpass=Pierakstīties
+login_userpass=Pieteikties
login_openid=OpenID
oauth_signup_tab=Reģistrēt jaunu kontu
oauth_signup_title=Pabeigt konta veidošanu
oauth_signup_submit=Pabeigt reģistrāciju
-oauth_signin_tab=Savienot ar esošu kontu
-oauth_signin_title=Pierakstīties, lai autorizētu saistīto kontu
+oauth_signin_tab=Sasaistīt ar esošu kontu
+oauth_signin_title=Pieteikties, lai autorizētu saistīto kontu
oauth_signin_submit=Sasaistīt kontu
-oauth.signin.error=Radās kļūda apstrādājot autorizācijas pieprasījumu. Ja šī kļūda atkārtojas, sazinieties ar lapas administratoru.
+oauth.signin.error=Radās kļūda apstrādājot pieteikšanās pieprasījumu. Ja šī kļūda atkārtojas, sazinieties ar lapas administratoru.
oauth.signin.error.access_denied=Autorizācijas pieprasījums tika noraidīts.
-oauth.signin.error.temporarily_unavailable=Autorizācija neizdevās, jo autentifikācijas serveris ir īslaicīgi nepieejams. Mēģiniet autorizēties vēlāk.
+oauth.signin.error.temporarily_unavailable=Pieteikšanās neizdevās, jo autentifikācijas serveris ir īslaicīgi nepieejams. Mēģiniet autorizēties vēlāk.
openid_connect_submit=Pievienoties
openid_connect_title=Pievienoties jau esošam kontam
openid_connect_desc=Izvēlētais OpenID konts sistēmā netika atpazīts, bet Jūs to varat piesaistīt esošam kontam.
@@ -662,7 +664,7 @@ change_password=Mainīt paroli
old_password=Pašreizējā parole
new_password=Jauna parole
password_incorrect=Ievadīta nepareiza pašreizējā parole.
-change_password_success=Parole tika veiksmīgi nomainīta. Tagad varat autorizēties ar jauno paroli.
+change_password_success=Parole tika veiksmīgi nomainīta. Tagad varat pieteikties ar jauno paroli.
password_change_disabled=Ārējie konti nevar mainīt paroli, izmantojot, Gitea saskarni.
emails=E-pasta adreses
@@ -683,7 +685,7 @@ email_deletion_success=E-pasta adrese ir veiksmīgi izdzēsta.
theme_update_success=Jūsu motīvs tika nomainīts.
theme_update_error=Izvēlētais motīvs neeksistē.
openid_deletion=Dzēst OpenID adresi
-openid_deletion_desc=Dzēšot šo OpenID adresi no Jūsu konta, ar to vairs nebūs iespējams autorizēties. Vai turpināt?
+openid_deletion_desc=Dzēšot šo OpenID adresi no Jūsu konta, ar to vairs nebūs iespējams pieteikties. Vai turpināt?
openid_deletion_success=OpenID adrese tika noņemta.
add_new_email=Pievienot jaunu e-pasta adresi
add_new_openid=Pievienot jaunu OpenID vietrādi
@@ -772,6 +774,7 @@ ssh_disabled=SSH atspējots
ssh_signonly=SSH ir atspējots, līdz ar to šīs atslēgas tiks izmantotas tikai revīziju parakstu pārbaudei.
ssh_externally_managed=Šim lietotājam SSH atslēga tiek pāvaldīta attālināti
manage_social=Pārvaldīt piesaistītos sociālos kontus
+social_desc=Šie sociālo tīklu konti var tikt izmantoti, lai pieteiktos. Pārliecinieties, ka visi ir atpazīstami.
unbind=Atsaistīt
manage_access_token=Pārvaldīt piekļuves pilnvaras
@@ -828,7 +831,7 @@ twofa_scratch_token_regenerate=Ģenerēt jaunu vienreizējo kodu
twofa_enroll=Ieslēgt divfaktoru autentifikāciju
twofa_disable_note=Nepieciešamības gadījumā divfaktoru autentifikāciju ir iespējams atslēgt.
twofa_disable_desc=Atslēdzot divfaktoru autentifikāciju, konts vairs nebūs tik drošs. Vai turpināt?
-regenerate_scratch_token_desc=Ja esat aizmirsis vienreizējo kodu vai jau esat to izmantojis, lai autorizētos, atjaunojiet to šeit.
+regenerate_scratch_token_desc=Ja esat aizmirsis vienreizējo kodu vai esat to jau izmantojis, lai pieteiktos, atjaunojiet to šeit.
twofa_disabled=Divfaktoru autentifikācija tika atslēgta.
scan_this_image=Noskenējiet šo attēlu ar autentifikācijas lietojumprogrammu:
or_enter_secret=Vai ievadiet šo noslēpumu: %s
@@ -841,7 +844,7 @@ webauthn_desc=Drošības atslēgas ir fiziskas ierīces, kas satur kriptogrāfis
webauthn_register_key=Pievienot drošības atslēgu
webauthn_nickname=Segvārds
webauthn_delete_key=Noņemt drošības atslēgu
-webauthn_delete_key_desc=Noņemot drošības atslēgu ar to vairs nebūs iespējams autorizēties. Turpināt?
+webauthn_delete_key_desc=Noņemot drošības atslēgu ar to vairs nebūs iespējams pieteikties. Vai turpināt?
manage_account_links=Pārvaldīt saistītos kontus
manage_account_links_desc=Šādi ārējie konti ir piesaistīti Jūsu Gitea kontam.
@@ -964,10 +967,8 @@ transfer.reject_desc=`Atcelt īpašnieka maiņu uz "%s"`
desc.private=Privāts
desc.public=Publisks
-desc.private_template=Privāta sagatave
-desc.public_template=Sagatave
+desc.template=Sagatave
desc.internal=Iekšējs
-desc.internal_template=Iekšēja sagatave
desc.archived=Arhivēts
template.items=Sagataves ieraksti
@@ -1045,9 +1046,9 @@ mirror_from=spogulis no
forked_from=atdalīts no
generated_from=ģenerēts no
fork_from_self=Nav iespējams atdalīt repozitoriju, kuram esat īpašnieks.
-fork_guest_user=Autorizējieties, lai atdalītu repozitoriju.
-watch_guest_user=Autorizejieties, lai sekotu šim repozitorijam.
-star_guest_user=Autorizejieties, lai atzīmētu ar zvaigznīti šo repozitoriju.
+fork_guest_user=Piesakieties, lai atdalītu repozitoriju.
+watch_guest_user=Piesakieties, lai sekotu šim repozitorijam.
+star_guest_user=Piesakieties, lai atzīmētu šo repozitoriju ar zvaigznīti.
unwatch=Nevērot
watch=Vērot
unstar=Noņemt zvaigznīti
@@ -1293,7 +1294,7 @@ issues.new.clear_assignees=Noņemt atbildīgo
issues.new.no_assignees=Nav atbildīgo
issues.new.no_reviewers=Nav recenzentu
issues.choose.get_started=Sākt darbu
-issues.choose.open_external_link=Aktīvie
+issues.choose.open_external_link=Atvērt
issues.choose.blank=Noklusējuma
issues.choose.blank_about=Izveidot problēmu ar noklusējuma sagatavi.
issues.choose.ignore_invalid_templates=Kļūdainās sagataves tika izlaistas
@@ -1422,7 +1423,7 @@ issues.remove_request_review=Noņemt recenzijas pieprasījumu
issues.remove_request_review_block=Nevar noņemt recenzījas pieprasījumu
issues.dismiss_review=Atmest recenziju
issues.dismiss_review_warning=Vai patiešām vēlaties atmest šo recenziju?
-issues.sign_in_require_desc=Pierakstieties, lai pievienotos šai sarunai.
+issues.sign_in_require_desc=Nepieciešams pieteikties, lai pievienotos šai sarunai.
issues.edit=Labot
issues.cancel=Atcelt
issues.save=Saglabāt
@@ -1685,9 +1686,6 @@ pulls.outdated_with_base_branch=Atzars ir novecojis salīdzinot ar bāzes atzaru
pulls.close=Aizvērt izmaiņu pieprasījumu
pulls.closed_at=`aizvēra šo izmaiņu pieprasījumu %[2]s`
pulls.reopened_at=`atkārtoti atvēra šo izmaiņu pieprasījumu %[2]s`
-pulls.merge_instruction_hint=`Varat aplūkot arī komandrindas instrukcijas.`
-pulls.merge_instruction_step1_desc=Projekta repozitorijā izveidojiet jaunu jaunu atzaru un pārbaudiet savas izmaiņas.
-pulls.merge_instruction_step2_desc=Sapludināt izmaiņas un atjaunot tās Gitea.
pulls.clear_merge_message=Notīrīt sapludināšanas ziņojumu
pulls.clear_merge_message_hint=Notīrot sapludināšanas ziņojumu tiks noņemts tikai pats ziņojums, bet tiks paturēti ģenerētie git ziņojumu, kā "Co-Authored-By …".
@@ -1735,6 +1733,8 @@ milestones.filter_sort.most_complete=Visvairāk pabeigtais
milestones.filter_sort.most_issues=Visvairāk problēmu
milestones.filter_sort.least_issues=Vismazāk problēmu
+signing.wont_sign.error=Notika kļūda pārbaudot vai revīzija var tikt parakstīta.
+signing.wont_sign.not_signed_in=Jūs neesat pieteicies.
ext_wiki=Piekļuve ārējai vikivietnei
ext_wiki.desc=Ārējā vikivietne norāda uz ārējo vikivietnes adresi.
@@ -1865,6 +1865,7 @@ settings.mirror_settings.docs.no_new_mirrors=Šis repozitorijs spoguļo izmaiņa
settings.mirror_settings.docs.can_still_use=Lai arī nav iespējams mainīt esošos vai izveidot jaunus spoguļa repozitorijus, esošie turpinās strādāt.
settings.mirror_settings.docs.pull_mirror_instructions=Lai ietatītu atvilkšanas spoguli, sekojiet instrukcijām:
settings.mirror_settings.docs.doc_link_title=Kā spoguļot repozitorijus?
+settings.mirror_settings.docs.doc_link_pull_section=dokumentācijas nodaļā "Pulling from a remote repository".
settings.mirror_settings.docs.pulling_remote_title=Atvilkt no attāla repozitorija
settings.mirror_settings.mirrored_repository=Spoguļotais repozitorijs
settings.mirror_settings.direction=Virziens
@@ -2632,8 +2633,8 @@ users.restricted=Ierobežots
users.2fa=2FA
users.repos=Repozitoriji
users.created=Izveidots
-users.last_login=Pēdējā autorizācija
-users.never_login=Nekad nav autorizējies
+users.last_login=Pēdējā pieteikšanās
+users.never_login=Pieteikšanās nekad nav veikta
users.send_register_notify=Nosūtīt lietotājam reģistrācijas paziņojumu
users.new_success=Lietotāja konts "%s" tika izveidots.
users.edit=Labot
@@ -2646,7 +2647,7 @@ users.edit_account=Labot lietotāja kontu
users.max_repo_creation=Maksimālais repozitoriju skaits
users.max_repo_creation_desc=(Ievadiet -1 lai izmantotu noklusēto globālo ierobežojumu)
users.is_activated=Lietotāja konts ir aktivizēts
-users.prohibit_login=Atspējota pieslēgšanās
+users.prohibit_login=Atspējota pieteikšanās
users.is_admin=Administratora tiesības
users.is_restricted=Ir ierobežots
users.allow_git_hook=Atļaut veidot git āķus
@@ -2687,7 +2688,6 @@ emails.updated=E-pasts atjaunots
emails.not_updated=Neizdevās atjaunot pieprasīto e-pasta adresi: %v
emails.duplicate_active=E-pasta adrese jau ir aktīva citam lietotājam.
emails.change_email_header=Atjaunot e-pasta rekvizītus
-emails.change_email_text=Vai patiešām vēlaties atjaunot šo e-pasta adresi?
orgs.org_manage_panel=Organizāciju pārvaldība
orgs.name=Nosaukums
@@ -2825,7 +2825,7 @@ auths.tip.github=Reģistrējiet jaunu aplikāciju adresē https://github.com/set
auths.tip.gitlab=Reģistrējiet jaunu aplikāciju adresē https://gitlab.com/profile/applications
auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles adresē https://console.developers.google.com/
auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (~/.cargo/config.toml:
cargo.install=Lai instalētu Cargo pakotni, izpildiet sekojošu komandu:
-cargo.details.repository_site=Repozitorija vietne
-cargo.details.documentation_site=Dokumentācijas lapa
chef.registry=Uzstādiet šo reģistru failā ~/.chef/config.rb:
chef.install=Lai uzstādītu pakotni, ir jāizpilda šī komanda:
composer.registry=Pievienojiet šo reģistru savā ~/.composer/config.json failā:
@@ -3174,8 +3171,6 @@ conan.registry=Konfigurējiet šo reģistru no komandrindas:
conan.install=Lai instalētu Conan pakotni, izpildiet sekojošu komandu:
conda.registry=Uzstādiet šo reģistru kā Conda repozitoriju failā .condarc:
conda.install=Lai instalētu Conda pakotni, izpildiet sekojošu komandu:
-conda.details.repository_site=Repozitorija vietne
-conda.details.documentation_site=Dokumentācijas lapa
container.details.type=Attēla formāts
container.details.platform=Platforma
container.pull=Atgādājiet šo attēlu no komandrindas:
@@ -3334,7 +3329,6 @@ runners.reset_registration_token_success=Izpildītāja reģistrācijas pilnvara
runs.all_workflows=Visas darbaplūsmas
runs.commit=Revīzija
runs.invalid_workflow_helper=Darbaplūsmas konfigurācijas fails ir kļūdains. Pārbaudiet konfiugrācijas failu: %s
-runs.no_matching_runner_helper=Nav atbilstošu izpildītāju: %s
runs.status=Statuss
@@ -3347,5 +3341,6 @@ type-2.display_name=Repozitorija projekts
type-3.display_name=Organizācijas projekts
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Simboliska saite
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index 2440002241..43265c9c31 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -97,9 +97,6 @@ write=Schrijf
preview=Voorbeeld
loading=Laden…
-step1=Stap 1:
-step2=Stap 2:
-
error=Fout
error404=De pagina die u probeert te bereiken bestaat niet of u bent niet gemachtigd om het te bekijken.
@@ -288,7 +285,6 @@ org_no_results=Er zijn geen overeenkomende organisaties gevonden.
code_no_results=Geen broncode gevonden in overeenstemming met uw zoekterm.
code_last_indexed_at=Laatst geïndexeerd %s
-
[auth]
create_new_account=Account registreren
register_helper_msg=Heeft u al een account? Klik hier om in te loggen
@@ -856,10 +852,8 @@ transfer.reject_desc=`Annuleer overdracht naar "%s"`
desc.private=Privé
desc.public=Openbaar
-desc.private_template=Privé sjabloon
-desc.public_template=Sjabloon
+desc.template=Sjabloon
desc.internal=Interne
-desc.internal_template=Intern sjabloon
desc.archived=Gearchiveerd
template.items=Sjabloon items
@@ -1492,9 +1486,6 @@ pulls.update_not_allowed=Je hebt geen toestemming om branch bij te werken
pulls.outdated_with_base_branch=Deze branch is verouderd met de basis branch
pulls.closed_at=`heeft deze pull request gesloten %[2]s`
pulls.reopened_at=`heropende deze pull request %[2]s`
-pulls.merge_instruction_hint=`Je kunt ook command line instructies bekijken.`
-pulls.merge_instruction_step1_desc=Vanuit het project, check een branch uit en test de veranderingen.
-pulls.merge_instruction_step2_desc=Voeg de wijzigingen samen en update ze op Gitea.
pulls.auto_merge_button_when_succeed=(Bij geslaagde controles)
pulls.auto_merge_when_succeed=Automatisch samenvoegen wanneer alle controles gelukt zijn
@@ -2273,7 +2264,6 @@ emails.updated=E-mailadres bijgewerkt
emails.not_updated=Bijwerken van het gevraagde e-mailadres is mislukt: %v
emails.duplicate_active=Dit e-mailadres is al actief voor een andere gebruiker.
emails.change_email_header=Update E-mail Eigenschappen
-emails.change_email_text=Weet je zeker dat je dit e-mailadres wilt bijwerken?
orgs.org_manage_panel=Organisaties beheren
orgs.name=Naam
@@ -2434,7 +2424,6 @@ config.enable_openid_signin=OpenID-inloggen inschakelen
config.show_registration_button=Registeren knop weergeven
config.require_sign_in_view=Vereis inloggen om pagina's te kunnen bekijken
config.mail_notify=Activeer e-mailnotificaties
-config.disable_key_size_check=Controle op key-lengte uitschakelen
config.enable_captcha=CAPTCHA inschakelen
config.active_code_lives=Actieve Code leven
config.reset_password_code_lives=Herstel accountcode vervaltijd
@@ -2641,5 +2630,6 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Symbolic link
diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini
index 8811b21892..d713110a72 100644
--- a/options/locale/locale_pl-PL.ini
+++ b/options/locale/locale_pl-PL.ini
@@ -96,9 +96,6 @@ write=Napisz
preview=Podgląd
loading=Ładowanie…
-step1=Krok 1:
-step2=Krok 2:
-
error=Błąd
error404=Strona, do której próbujesz dotrzeć nie istnieje lub nie jesteś autoryzowany aby go zobaczyć.
@@ -285,7 +282,6 @@ org_no_results=Nie znaleziono pasujących organizacji.
code_no_results=Nie znaleziono kodu źródłowego odpowiadającego Twojej frazie wyszukiwania.
code_last_indexed_at=Ostatnio indeksowane %s
-
[auth]
create_new_account=Zarejestruj konto
register_helper_msg=Masz już konto? Zaloguj się teraz!
@@ -802,10 +798,8 @@ transfer.reject_desc=`Anuluj transfer do "%s"`
desc.private=Prywatne
desc.public=Publiczne
-desc.private_template=Szablon prywatny
-desc.public_template=Szablon
+desc.template=Szablon
desc.internal=Wewnętrzny
-desc.internal_template=Wewnętrzny szablon
desc.archived=Zarchiwizowane
template.items=Elementy szablonu
@@ -1353,9 +1347,6 @@ pulls.update_not_allowed=Nie masz uprawnień do aktualizacji gałęzi
pulls.outdated_with_base_branch=Ta gałąź jest przestarzała w stosunku do gałęzi bazowej
pulls.closed_at=`zamknął(-ęła) ten pull request %[2]s`
pulls.reopened_at=`otworzył(-a) ponownie ten Pull Request %[2]s`
-pulls.merge_instruction_hint=`Możesz także zobaczyć instrukcje wiersza poleceń.`
-pulls.merge_instruction_step1_desc=Z repozytorium twojego projektu, sprawdź nową gałąź i przetestuj zmiany.
-pulls.merge_instruction_step2_desc=Połącz zmiany i zaktualizuj na Gitea.
@@ -2148,7 +2139,6 @@ emails.updated=E-mail zaktualizowany
emails.not_updated=Nie udało się zaktualizować żądanego adresu e-mail: %v
emails.duplicate_active=Ten e-mail jest już aktywny dla innego użytkownika.
emails.change_email_header=Aktualizuj właściwości adresu e-mail
-emails.change_email_text=Czy na pewno chcesz zaktualizować ten adres?
orgs.org_manage_panel=Zarządzanie organizacją
orgs.name=Nazwa
@@ -2323,7 +2313,6 @@ config.enable_openid_signin=Włącz logowanie za pomocą OpenID
config.show_registration_button=Pokazuj przycisk rejestracji
config.require_sign_in_view=Wymagaj zalogowania w celu wyświetlania stron
config.mail_notify=Włącz powiadomienia e-mail
-config.disable_key_size_check=Wyłącz sprawdzanie minimalnego rozmiaru klucza
config.enable_captcha=Włącz CAPTCHA
config.active_code_lives=Ważność kodów aktywacyjnych
config.reset_password_code_lives=Czas wygaśnięcia kodu przywracania konta
@@ -2529,5 +2518,6 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Dowiązanie symboliczne
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index 302ff93466..cf5fd0055c 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -107,9 +107,6 @@ write=Escrever
preview=Pré-visualização
loading=Carregando…
-step1=Passo 1:
-step2=Passo 2:
-
error=Erro
error404=A página que você está tentando acessar não existe ou você não está autorizado a visualizá-la.
@@ -351,7 +348,6 @@ code_last_indexed_at=Última indexação %s
relevant_repositories_tooltip=Repositórios que são forks ou que não possuem tópico, nem ícone e nem descrição estão ocultos.
relevant_repositories=Apenas repositórios relevantes estão sendo mostrados, mostrar resultados não filtrados.
-
[auth]
create_new_account=Cadastrar conta
register_helper_msg=Já tem uma conta? Acesse agora!
@@ -920,7 +916,6 @@ visibility.private=Privada
visibility.private_tooltip=Visível apenas para membros das organizações às quais você se associou
[repo]
-new_repo_helper=Um repositório contém todos os arquivos do projeto, inclusive o histórico de revisões. Já está hospedando um em outro lugar? Migre o repositório.
owner=Proprietário
owner_helper=Algumas organizações podem não aparecer no menu devido a um limite de contagem dos repositórios.
repo_name=Nome do repositório
@@ -1018,10 +1013,8 @@ transfer.no_permission_to_reject=Você não tem permissão para rejeitar essa tr
desc.private=Privado
desc.public=Público
-desc.private_template=Modelo privado
-desc.public_template=Modelo
+desc.template=Template
desc.internal=Interno
-desc.internal_template=Modelo interno
desc.archived=Arquivado
template.items=Itens do modelo
@@ -1773,9 +1766,6 @@ pulls.outdated_with_base_branch=Este branch está desatualizado com o branch bas
pulls.close=Fechar pull request
pulls.closed_at=`fechou este pull request %[2]s`
pulls.reopened_at=`reabriu este pull request %[2]s`
-pulls.merge_instruction_hint=`Você também pode ver as instruções para a linha de comandos.`
-pulls.merge_instruction_step1_desc=No repositório do seu projeto, crie um novo branch e teste as alterações.
-pulls.merge_instruction_step2_desc=Faça merge das alterações e atualize no Gitea.
pulls.clear_merge_message=Limpar mensagem do merge
pulls.clear_merge_message_hint=Limpar a mensagem de merge só irá remover o conteúdo da mensagem de commit e manter trailers git gerados, como "Co-Authored-By …".
@@ -2774,7 +2764,6 @@ emails.updated=E-mail atualizado
emails.not_updated=Falha ao atualizar o endereço de e-mail solicitado: %v
emails.duplicate_active=Este endereço de e-mail já está ativo para um usuário diferente.
emails.change_email_header=Atualizar Propriedades do E-mail
-emails.change_email_text=Você tem certeza que deseja atualizar este endereço de e-mail?
orgs.org_manage_panel=Gerenciamento da organização
orgs.name=Nome
@@ -2988,7 +2977,6 @@ config.enable_openid_signin=Habilitar acesso via OpenID
config.show_registration_button=Mostrar botão de cadastro
config.require_sign_in_view=Exigir acesso do usuário para a visualização de páginas
config.mail_notify=Habilitar notificações de e-mail
-config.disable_key_size_check=Desabilitar verificação de tamanho mínimo da chave
config.enable_captcha=Habilitar o CAPTCHA
config.active_code_lives=Ativar Code Lives
config.reset_password_code_lives=Tempo de expiração do código de recuperação de conta
@@ -3250,8 +3238,6 @@ alpine.repository.repositories=Repositórios
alpine.repository.architectures=Arquiteturas
cargo.registry=Configurar este registro no arquivo de configuração de Cargo (por exemplo ~/.cargo/config.toml):
cargo.install=Para instalar o pacote usando Cargo, execute o seguinte comando:
-cargo.details.repository_site=Site do Repositório
-cargo.details.documentation_site=Site da Documentação
chef.registry=Configure este registro em seu arquivo ~/.chef/config.rb:
chef.install=Para instalar o pacote, execute o seguinte comando:
composer.registry=Configure este registro em seu arquivo ~/.composer/config.json:
@@ -3263,8 +3249,6 @@ conan.registry=Configure este registro pela linha de comando:
conan.install=Para instalar o pacote usando o Conan, execute o seguinte comando:
conda.registry=Configure este registro como um repositório Conda no arquivo .condarc:
conda.install=Para instalar o pacote usando o Conda, execute o seguinte comando:
-conda.details.repository_site=Site do Repositório
-conda.details.documentation_site=Site da Documentação
container.details.type=Tipo de Imagem
container.details.platform=Plataforma
container.pull=Puxe a imagem pela linha de comando:
@@ -3428,7 +3412,6 @@ runs.all_workflows=Todos os Workflows
runs.commit=Commit
runs.pushed_by=push feito por
runs.invalid_workflow_helper=O arquivo de configuração do workflow é inválido. Por favor, verifique seu arquivo de configuração: %s
-runs.no_matching_runner_helper=Nenhum runner correspondente: %s
runs.status=Status
@@ -3441,5 +3424,6 @@ type-2.display_name=Projeto do repositório
type-3.display_name=Projeto da organização
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Link simbólico
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 9d9c5eada1..863a1545c3 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -17,6 +17,7 @@ template=Modelo
language=Idioma
notifications=Notificações
active_stopwatch=Cronómetro em andamento
+tracked_time_summary=Resumo do tempo rastreado com base em filtros da lista de questões
create_new=Criar…
user_profile_and_more=Perfil e configurações…
signed_in_as=Sessão iniciada como
@@ -90,6 +91,7 @@ remove=Remover
remove_all=Remover tudo
remove_label_str=`Remover item "%s"`
edit=Editar
+view=Ver
enabled=Habilitado
disabled=Desabilitado
@@ -108,9 +110,6 @@ write=Escrever
preview=Pré-visualizar
loading=Carregando…
-step1=Passo 1:
-step2=Passo 2:
-
error=Erro
error404=A página que pretende aceder não existe ou não tem autorização para a ver.
go_back=Voltar
@@ -354,7 +353,6 @@ code_last_indexed_at=Última indexação %s
relevant_repositories_tooltip=Repositórios que são derivações ou que não têm tópico, nem ícone, nem descrição, estão escondidos.
relevant_repositories=Apenas estão a ser mostrados os repositórios relevantes. Mostrar resultados não filtrados.
-
[auth]
create_new_account=Fazer inscrição
register_helper_msg=Já tem uma conta? Inicie a sessão agora!
@@ -363,6 +361,7 @@ disable_register_prompt=As inscrições estão desabilitadas. Entre em contacto
disable_register_mail=A confirmação por email da inscrição está desabilitada.
manual_activation_only=Contacte o administrador para completar a habilitação.
remember_me=Memorizar este dispositivo
+remember_me.compromised=O identificador da sessão já não é válido, o que pode indicar uma conta comprometida. Verifique se a sua conta apresenta operações pouco habituais.
forgot_password_title=Esqueci-me da senha
forgot_password=Esqueceu a sua senha?
sign_up_now=Precisa de uma conta? Inscreva-se agora.
@@ -866,6 +865,7 @@ revoke_oauth2_grant_description=Revogar o acesso desta aplicação de terceiros
revoke_oauth2_grant_success=Acesso revogado com sucesso.
twofa_desc=Autenticação em dois passos melhora a segurança da sua conta.
+twofa_recovery_tip=Se perder o seu dispositivo, poderá usar uma chave de recuperação de utilização única para voltar a ter acesso à sua conta.
twofa_is_enrolled=A autenticação em dois passos está neste momento habilitada na sua conta.
twofa_not_enrolled=A autenticação em dois passos não está neste momento habilitada na sua conta.
twofa_disable=Desabilitar autenticação em dois passos
@@ -888,6 +888,8 @@ webauthn_register_key=Adicionar chave de segurança
webauthn_nickname=Apelido
webauthn_delete_key=Remover chave de segurança
webauthn_delete_key_desc=Se remover uma chave de segurança, deixará de poder usá-la para iniciar a sessão. Quer continuar?
+webauthn_key_loss_warning=Se perder as suas chaves de segurança, perderá acesso à sua conta.
+webauthn_alternative_tip=Poderá querer configurar um método de autenticação adicional.
manage_account_links=Gerir contas vinculadas
manage_account_links_desc=Estas contas externas estão vinculadas à sua conta do Gitea.
@@ -1029,10 +1031,8 @@ transfer.no_permission_to_reject=Você não tem permissão para rejeitar esta tr
desc.private=Privado
desc.public=Público
-desc.private_template=Modelo privado
-desc.public_template=Modelo
+desc.template=Modelo
desc.internal=Interno
-desc.internal_template=Modelo interno
desc.archived=Arquivado
template.items=Itens do modelo
@@ -1789,6 +1789,8 @@ pulls.status_checks_failure=Algumas verificações falharam
pulls.status_checks_error=Algumas verificações reportaram erros
pulls.status_checks_requested=Obrigatório
pulls.status_checks_details=Detalhes
+pulls.status_checks_hide_all=Ocultar todas as verificações
+pulls.status_checks_show_all=Mostrar todas as verificações
pulls.update_branch=Modificar ramo executando a integração
pulls.update_branch_rebase=Modificar ramo mudando a base
pulls.update_branch_success=A sincronização do ramo foi bem sucedida
@@ -1797,9 +1799,11 @@ pulls.outdated_with_base_branch=Este ramo é obsoleto em relação ao ramo base
pulls.close=Encerrar pedido de integração
pulls.closed_at=`fechou este pedido de integração %[2]s`
pulls.reopened_at=`reabriu este pedido de integração %[2]s`
-pulls.merge_instruction_hint=`Também pode ver as instruções para a linha de comandos.`
-pulls.merge_instruction_step1_desc=No seu repositório, crie um novo ramo e teste as modificações.
-pulls.merge_instruction_step2_desc=Integre as modificações e envie para o Gitea.
+pulls.cmd_instruction_hint=`Ver instruções para a linha de comandos.`
+pulls.cmd_instruction_checkout_title=Conferir
+pulls.cmd_instruction_checkout_desc=No seu repositório, irá criar um novo ramo para que possa testar as modificações.
+pulls.cmd_instruction_merge_title=Integrar
+pulls.cmd_instruction_merge_desc=Integrar as modificações e enviar para o Gitea.
pulls.clear_merge_message=Apagar mensagem de integração
pulls.clear_merge_message_hint=Apagar a mensagem de integração apenas remove o conteúdo da mensagem de cometimento e mantém os rodapés do git, tais como "Co-Autorado-Por …".
@@ -1993,7 +1997,7 @@ settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=Neste mom
settings.mirror_settings.docs.disabled_push_mirror.info=As réplicas foram desabilitadas pelo administrador deste sítio.
settings.mirror_settings.docs.no_new_mirrors=O seu repositório está a replicar modificações para, ou a partir, de outro repositório. Tenha em mente que não pode criar novas réplicas neste momento.
settings.mirror_settings.docs.can_still_use=Embora não possa modificar réplicas existentes ou criar novas, ainda pode usar a sua réplica existente.
-settings.mirror_settings.docs.pull_mirror_instructions=Para configurar uma réplica de outro repositório, consulte:
+settings.mirror_settings.docs.pull_mirror_instructions=Para configurar uma réplica de outro repositório, consulte
settings.mirror_settings.docs.more_information_if_disabled=Pode aprender mais sobre réplicas de envios e de puxadas aqui:
settings.mirror_settings.docs.doc_link_title=Como é que eu replico repositórios?
settings.mirror_settings.docs.doc_link_pull_section=a parte "Puxar de um repositório remoto" da documentação.
@@ -2050,7 +2054,7 @@ settings.pulls.default_allow_edits_from_maintainers=Permitir, por norma, que os
settings.releases_desc=Habilitar lançamentos no repositório
settings.packages_desc=Habilitar o registo de pacotes do repositório
settings.projects_desc=Habilitar planeamentos no repositório
-settings.actions_desc=Habilitar operações no repositório
+settings.actions_desc=Habilitar operações no repositório (Gitea Actions)
settings.admin_settings=Configurações do administrador
settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório
settings.admin_code_indexer=Indexador de código
@@ -2113,7 +2117,7 @@ settings.delete_notices_2=- Esta operação eliminará permanentemente o reposit
settings.delete_notices_fork_1=- Derivações deste repositório tornar-se-ão independentes, após a eliminação.
settings.deletion_success=O repositório foi eliminado.
settings.update_settings_success=As configurações do repositório foram modificadas.
-settings.update_settings_no_unit=O repositório deverá, ao menos, permitir algum tipo de interacção.
+settings.update_settings_no_unit=O repositório deve permitir pelo menos algum tipo de interoperabilidade.
settings.confirm_delete=Eliminar repositório
settings.add_collaborator=Adicionar colaborador
settings.add_collaborator_success=O colaborador foi adicionado.
@@ -2311,7 +2315,7 @@ settings.dismiss_stale_approvals_desc=Quando novos cometimentos que mudam o cont
settings.require_signed_commits=Exigir cometimentos assinados
settings.require_signed_commits_desc=Rejeitar envios para este ramo que não estejam assinados ou que não sejam validáveis.
settings.protect_branch_name_pattern=Padrão do nome do ramo protegido
-settings.protect_branch_name_pattern_desc=Padrões de nomes de ramos protegidos. Consulte a documentação para ver a sintaxe dos padrões. Exemplos: main, release/**
+settings.protect_branch_name_pattern_desc=Padrões de nomes de ramos protegidos. Consulte a documentação para ver a sintaxe dos padrões. Exemplos: main, release/**
settings.protect_patterns=Padrões
settings.protect_protected_file_patterns=Padrões de ficheiros protegidos (separados com ponto e vírgula ';'):
settings.protect_protected_file_patterns_desc=Ficheiros protegidos não podem ser modificados imediatamente, mesmo que o utilizador tenha direitos para adicionar, editar ou eliminar ficheiros neste ramo. Múltiplos padrões podem ser separados com ponto e vírgula (';'). Veja a documentação em github.com/gobwas/glob para ver a sintaxe. Exemplos: .drone.yml, /docs/**/*.txt.
@@ -2507,7 +2511,6 @@ release.releases_for=Lançamentos para %s
release.tags_for=Etiquetas para %s
branch.name=Nome do ramo
-branch.search=Pesquisar ramo
branch.already_exists=Já existe um ramo com o nome "%s".
branch.delete_head=Eliminar
branch.delete=`Eliminar o ramo "%s"`
@@ -2530,6 +2533,7 @@ branch.default_deletion_failed=O ramo "%s" é o ramo principal, não pode ser el
branch.restore=`Restaurar o ramo "%s"`
branch.download=`Descarregar o ramo "%s"`
branch.rename=`Renomear ramo "%s"`
+branch.search=Pesquisar ramo
branch.included_desc=Este ramo faz parte do ramo principal
branch.included=Incluído
branch.create_new_branch=Criar ramo a partir do ramo:
@@ -2639,7 +2643,7 @@ teams.leave.detail=Sair de %s?
teams.can_create_org_repo=Criar repositórios
teams.can_create_org_repo_helper=Os membros podem criar novos repositórios na organização. O criador terá acesso de administrador ao novo repositório.
teams.none_access=Sem acesso
-teams.none_access_helper=Os membros não podem ver nem fazer qualquer outra operação nesta unidade.
+teams.none_access_helper=Os membros não podem ver nem fazer qualquer outra operação nesta unidade. Não tem qualquer efeito nos repositórios públicos.
teams.general_access=Acesso geral
teams.general_access_helper=As permissões dos membros serão decididas pela tabela de permissões abaixo.
teams.read_access=Ler
@@ -2731,7 +2735,7 @@ dashboard.delete_repo_archives.started=Foi iniciada a tarefa de eliminação de
dashboard.delete_missing_repos=Eliminar todos os repositórios que não tenham os seus ficheiros Git
dashboard.delete_missing_repos.started=Foi iniciada a tarefa de eliminação de todos os repositórios que não têm ficheiros git.
dashboard.delete_generated_repository_avatars=Eliminar avatares gerados do repositório
-dashboard.sync_repo_branches=Sincronizar ramos perdidos dos dados git para bases de dados
+dashboard.sync_repo_branches=Sincronizar ramos perdidos de dados do git para bases de dados
dashboard.update_mirrors=Sincronizar réplicas
dashboard.repo_health_check=Verificar a saúde de todos os repositórios
dashboard.check_repo_stats=Verificar as estatísticas de todos os repositórios
@@ -2746,7 +2750,7 @@ dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git em falta
dashboard.sync_external_users=Sincronizar dados externos do utilizador
dashboard.cleanup_hook_task_table=Limpar tabela hook_task
dashboard.cleanup_packages=Limpar pacotes expirados
-dashboard.cleanup_actions=Registos expirados e artefactos das operações de limpeza
+dashboard.cleanup_actions=Limpar registos e artefactos expirados das operações
dashboard.server_uptime=Tempo em funcionamento contínuo do servidor
dashboard.current_goroutine=Goroutines em execução
dashboard.current_memory_usage=Utilização de memória corrente
@@ -2882,6 +2886,7 @@ packages.package_manage_panel=Gestão de pacotes
packages.total_size=Tamanho total: %s
packages.unreferenced_size=Tamanho não referenciado: %s
packages.cleanup=Limpar dados expirados
+packages.cleanup.success=Limpou os dados expirados com sucesso
packages.owner=Proprietário
packages.creator=Criador
packages.name=Nome
@@ -3075,7 +3080,6 @@ config.enable_openid_signin=Habilitar início de sessão com OpenID
config.show_registration_button=Mostrar botão de registo
config.require_sign_in_view=Exigir sessão iniciada para visualizar páginas
config.mail_notify=Habilitar notificações por email
-config.disable_key_size_check=Desabilitar verificação de tamanho mínimo da chave
config.enable_captcha=Habilitar o CAPTCHA
config.active_code_lives=Duração do código que está em uso
config.reset_password_code_lives=Prazo do código de recuperação da conta
@@ -3182,14 +3186,14 @@ monitor.queue=Fila: %s
monitor.queue.name=Nome
monitor.queue.type=Tipo
monitor.queue.exemplar=Tipo de exemplar
-monitor.queue.numberworkers=Número de trabalhadores
+monitor.queue.numberworkers=N.º de trabalhadores
monitor.queue.activeworkers=Trabalhadores operantes
-monitor.queue.maxnumberworkers=Número máximo de trabalhadores
-monitor.queue.numberinqueue=Número na fila
+monitor.queue.maxnumberworkers=N.º máximo de trabalhadores
+monitor.queue.numberinqueue=N.º na fila
monitor.queue.review_add=Rever / Adicionar trabalhadores
monitor.queue.settings.title=Configurações do agregado
monitor.queue.settings.desc=Agregados crescem dinamicamente em resposta aos bloqueios da sua fila de trabalhadores.
-monitor.queue.settings.maxnumberworkers=Número máximo de trabalhadores
+monitor.queue.settings.maxnumberworkers=N.º máximo de trabalhadores
monitor.queue.settings.maxnumberworkers.placeholder=De momento %[1]d
monitor.queue.settings.maxnumberworkers.error=O número máximo de trabalhadores tem que ser um número
monitor.queue.settings.submit=Modificar configurações
@@ -3305,7 +3309,7 @@ error.unit_not_allowed=Não tem permissão para aceder a esta parte do repositó
title=Pacotes
desc=Gerir pacotes do repositório.
empty=Ainda não há pacotes.
-empty.documentation=Para obter mais informação sobre o registo de pacotes, veja a documentação.
+empty.documentation=Para obter mais informação sobre o registo de pacotes, veja a documentação.
empty.repo=Carregou um pacote mas este não é apresentado aqui? Vá às configurações do pacote e ligue-o a este repositório.
registry.documentation=Para mais informação sobre o registo %s, veja a documentação.
filter.type=Tipo
@@ -3341,8 +3345,6 @@ alpine.repository.repositories=Repositórios
alpine.repository.architectures=Arquitecturas
cargo.registry=Configurar este registo no ficheiro de configuração do Cargo (por exemplo: ~/.cargo/config.toml):
cargo.install=Para instalar o pacote usando o Cargo, execute o seguinte comando:
-cargo.details.repository_site=Página web do repositório
-cargo.details.documentation_site=Página web da documentação
chef.registry=Configure este registo no seu ficheiro ~/.chef/config.rb:
chef.install=Para instalar o pacote, execute o seguinte comando:
composer.registry=Configure este registo no seu ficheiro ~/.composer/config.json:
@@ -3354,8 +3356,6 @@ conan.registry=Configurar este registo usando a linha de comandos:
conan.install=Para instalar o pacote usando o Conan, execute o seguinte comando:
conda.registry=Configure este registo como um repositório Conda no seu ficheiro .condarc:
conda.install=Para instalar o pacote usando o Conda, execute o seguinte comando:
-conda.details.repository_site=Página web do repositório
-conda.details.documentation_site=Página web da documentação
container.details.type=Tipo de imagem
container.details.platform=Plataforma
container.pull=Puxar a imagem usando a linha de comandos:
@@ -3459,7 +3459,7 @@ secrets=Segredos
description=Os segredos serão transmitidos a certas operações e não poderão ser lidos de outra forma.
none=Ainda não há segredos.
creation=Adicionar segredo
-creation.name_placeholder=apenas caracteres sem distinção de maiúsculas, alfanuméricos ou sublinhados, não podem começar com GITEA_ nem com GITHUB_
+creation.name_placeholder=Só sublinhados ou alfanuméricos sem distinguir maiúsculas, sem começar com GITEA_ nem GITHUB_
creation.value_placeholder=Insira um conteúdo qualquer. Espaços em branco no início ou no fim serão omitidos.
creation.success=O segredo "%s" foi adicionado.
creation.failed=Falhou ao adicionar o segredo.
@@ -3479,9 +3479,9 @@ status.waiting=Aguardando
status.running=Em execução
status.success=Sucesso
status.failure=Falha
-status.cancelled=Cancelada
-status.skipped=Ignorada
-status.blocked=Bloqueada
+status.cancelled=Cancelado
+status.skipped=Ignorado
+status.blocked=Bloqueado
runners=Executores
runners.runner_manage_panel=Gestão de executores
@@ -3493,7 +3493,7 @@ runners.name=Nome
runners.owner_type=Tipo
runners.description=Descrição
runners.labels=Rótulos
-runners.last_online=Última vez ligado
+runners.last_online=Última vez que esteve ligado
runners.runner_title=Executor
runners.task_list=Tarefas recentes deste executor
runners.task_list.no_tasks=Ainda não há tarefas.
@@ -3506,16 +3506,16 @@ runners.edit_runner=Editar executor
runners.update_runner=Guardar alterações
runners.update_runner_success=O executor foi modificado com sucesso
runners.update_runner_failed=Falhou ao modificar o executor
-runners.delete_runner=Eliminar o executor
+runners.delete_runner=Eliminar este executor
runners.delete_runner_success=O executor foi eliminado com sucesso
runners.delete_runner_failed=Falhou ao eliminar o executor
runners.delete_runner_header=Confirme que quer eliminar este executor
-runners.delete_runner_notice=Se uma tarefa estiver a correr sob este executor, será terminada e marcada como tendo falhado. Isso poderá quebrar a sequência de trabalho de construção.
+runners.delete_runner_notice=Se uma tarefa estiver a correr neste executor, será terminada e marcada como tendo falhado. Isso poderá quebrar a sequência de trabalho de construção.
runners.none=Não há executores disponíveis
runners.status.unspecified=Desconhecido
-runners.status.idle=Parada
+runners.status.idle=Parado
runners.status.active=Em funcionamento
-runners.status.offline=Desconectada
+runners.status.offline=Desconectado
runners.version=Versão
runners.reset_registration_token=Repor código de registo
runners.reset_registration_token_success=O código de incrição do executor foi reposto com sucesso
@@ -3525,13 +3525,17 @@ runs.commit=Cometimento
runs.scheduled=Agendadas
runs.pushed_by=enviado por
runs.invalid_workflow_helper=O ficheiro de configuração da sequência de trabalho é inválido. Verifique o seu ficheiro de configuração: %s
-runs.no_matching_runner_helper=Não há qualquer executor que corresponda: %s
+runs.no_matching_online_runner_helper=Não existem executores ligados que tenham o rótulo %s
runs.actor=Interveniente
runs.status=Estado
runs.actors_no_select=Todos os intervenientes
runs.status_no_select=Todos os estados
runs.no_results=Nenhum resultado obtido.
+runs.no_workflows=Ainda não há sequências de trabalho.
+runs.no_workflows.quick_start=Não sabe como começar com o Gitea Action? Veja o guia de iniciação rápida.
+runs.no_workflows.documentation=Para mais informação sobre o Gitea Action, veja a documentação.
runs.no_runs=A sequência de trabalho ainda não foi executada.
+runs.empty_commit_message=(mensagem de cometimento vazia)
workflow.disable=Desabilitar sequência de trabalho
workflow.disable_success=A sequência de trabalho '%s' foi desabilitada com sucesso.
@@ -3545,7 +3549,7 @@ variables=Variáveis
variables.management=Gestão de variáveis
variables.creation=Adicionar variável
variables.none=Ainda não há variáveis.
-variables.deletion=Remover variáveis
+variables.deletion=Remover variável
variables.deletion.description=Remover uma variável é permanente e não pode ser revertido. Quer continuar?
variables.description=As variáveis serão transmitidas a certas operações e não poderão ser lidas de outra forma.
variables.id_not_exist=A variável com o id %d não existe.
@@ -3564,6 +3568,7 @@ type-3.display_name=Planeamento da organização
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=Pasta
normal_file=Ficheiro normal
executable_file=Ficheiro executável
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index aad2d86b83..0a466854d0 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -108,9 +108,6 @@ write=Редактирование
preview=Предпросмотр
loading=Загрузка…
-step1=Шаг 1:
-step2=Шаг 2:
-
error=Ошибка
error404=Либо страница, которую вы пытаетесь открыть, не существует, либо у вас недостаточно прав для ее просмотра.
go_back=Назад
@@ -354,7 +351,6 @@ code_last_indexed_at=Последний проиндексированный %s
relevant_repositories_tooltip=Репозитории, являющиеся ответвлениями или не имеющие ни темы, ни значка, ни описания, скрыты.
relevant_repositories=Показаны только релевантные репозитории, показать результаты без фильтрации.
-
[auth]
create_new_account=Регистрация аккаунта
register_helper_msg=Уже есть аккаунт? Авторизуйтесь!
@@ -363,6 +359,7 @@ disable_register_prompt=Извините, возможность регистр
disable_register_mail=Подтверждение регистрации по электронной почте отключено.
manual_activation_only=Обратитесь к администратору сайта для завершения активации.
remember_me=Запомнить это устройство
+remember_me.compromised=Токен входа более не действителен, что может указывать на компрометацию учётной записи. Пожалуйста, проверьте свою учётную запись на необычные действия.
forgot_password_title=Восстановить пароль
forgot_password=Забыли пароль?
sign_up_now=Нужен аккаунт? Зарегистрируйтесь.
@@ -708,6 +705,7 @@ requires_activation=Требуется активация
primary_email=Сделать основным
activate_email=Отправить активацию
activations_pending=Ожидает активации
+can_not_add_email_activations_pending=Ожидается активация. Если хотите добавить новый почтовый ящик, попробуйте еще раз через несколько минут.
delete_email=Удалить
email_deletion=Удалить адрес электронной почты
email_deletion_desc=Адрес электронной почты и вся связанная с ним информация будет удалена из вашего аккаунта. Коммиты, сделанные от имени этого адреса электронной почты, не будут изменены. Продолжить?
@@ -849,6 +847,7 @@ oauth2_client_id=ID клиента
oauth2_client_secret=Клиентский ключ
oauth2_regenerate_secret=Сгенерировать новый ключ
oauth2_regenerate_secret_hint=Потеряли свой ключ?
+oauth2_client_secret_hint=Пожалуйста, сохраните секрет, так как после закрытия или обновления страницы он больше не будет показан.
oauth2_application_edit=Изменить
oauth2_application_create_description=Приложения OAuth2 предоставляет стороннему приложению доступ к учётным записям пользователей данного сервиса.
oauth2_application_remove_description=Удаление приложения OAuth2 приведёт к отмене его доступа к авторизованным учётным записям пользователей в данном экземпляре. Продолжить?
@@ -861,6 +860,7 @@ revoke_oauth2_grant_description=Отзыв доступа у этого стор
revoke_oauth2_grant_success=Доступ был успешно отозван.
twofa_desc=Двухфакторная аутентификация повышает уровень безопасности вашей учётной записи.
+twofa_recovery_tip=В случае утраты устройства можно использовать одноразовый ключ восстановления для получения доступа к учётной записи.
twofa_is_enrolled=Ваша учётная запись в настоящее время использует двухфакторную аутентификацию.
twofa_not_enrolled=Ваша учётная запись в настоящее время не использует двухфакторную аутентификацию.
twofa_disable=Отключить двухфакторную аутентификацию
@@ -882,6 +882,7 @@ webauthn_register_key=Добавить ключ безопасности
webauthn_nickname=Имя пользователя
webauthn_delete_key=Удалить ключ безопасности
webauthn_delete_key_desc=Если вы удалите ключ безопасности, вы больше не сможете войти с его помощью. Продолжить?
+webauthn_key_loss_warning=В случае утраты ключей безопасности вы потеряете доступ к учётной записи.
manage_account_links=Управление привязанными аккаунтами
manage_account_links_desc=Эти внешние аккаунты привязаны к вашему аккаунту Gitea.
@@ -1003,6 +1004,8 @@ delete_preexisting_success=Удалены непринятые файлы в %s
blame_prior=Показать авторство предшествующих изменений
author_search_tooltip=Показывает максимум 30 пользователей
+tree_path_not_found_commit=Путь %[1]s не существует в коммите %[2]s
+tree_path_not_found_branch=Путь %[1]s не существует в ветке %[2]s
transfer.accept=Принять трансфер
transfer.accept_desc=Переместить в «%s»
@@ -1011,10 +1014,8 @@ transfer.reject_desc=Отменить перемещение в «%s»
desc.private=Приватный
desc.public=Публичный
-desc.private_template=Приватный шаблон
-desc.public_template=Шаблон
+desc.template=Шаблон
desc.internal=Внутренний
-desc.internal_template=Внутренний шаблон
desc.archived=Архивировано
template.items=Элементы шаблона
@@ -1146,6 +1147,8 @@ file_view_rendered=Просмотр отрендеренного
file_view_raw=Посмотреть исходник
file_permalink=Постоянная ссылка
file_too_large=Этот файл слишком большой, поэтому он не может быть отображён.
+invisible_runes_header=`Этот файл содержит невидимые символы Юникода`
+ambiguous_runes_header=`Этот файл содержит неоднозначные символы Юникода`
invisible_runes_line=`В этой строке есть невидимые символы Юникода`
ambiguous_runes_line=`В этой строке есть неоднозначные символы Юникода`
ambiguous_character=`%[1]c [U+%04[1]X] можно спутать с %[2]c [U+%04[2]X]`
@@ -1420,6 +1423,7 @@ issues.filter_sort.moststars=Больше звезд
issues.filter_sort.feweststars=Меньше звезд
issues.filter_sort.mostforks=Больше форков
issues.filter_sort.fewestforks=Меньше форков
+issues.keyword_search_unavailable=В настоящее время поиск по ключевым словам недоступен. Обратитесь к администратору сайта.
issues.action_open=Открыть
issues.action_close=Закрыть
issues.action_label=Метка
@@ -1468,9 +1472,15 @@ issues.ref_closed_from=`закрыл этот запрос %[4]s
issues.ref_reopened_from=`переоткрыл эту задачу %[4]s %[2]s`
issues.ref_from=`из %[1]s`
issues.author=Автор
+issues.author_helper=Этот пользователь является автором.
issues.role.owner=Владелец
+issues.role.owner_helper=Этот пользователь является владельцем репозитория.
issues.role.member=Участник
+issues.role.member_helper=Этот пользователь является членом организации, владеющей этим репозиторием.
issues.role.collaborator=Соавтор
+issues.role.collaborator_helper=Этот пользователь был приглашен сотрудничать в репозитории.
+issues.role.first_time_contributor=Новый участник
+issues.role.first_time_contributor_helper=Это первый вклад пользователя в репозиторий.
issues.role.contributor=Участник
issues.re_request_review=Повторить запрос на отзыв
issues.is_stale=Со времени этого обзора в этот PR были внесены некоторые изменения
@@ -1487,6 +1497,8 @@ issues.label_description=Описание метки
issues.label_color=Цвет метки
issues.label_exclusive=Эксклюзивный
issues.label_archive=Метка архива
+issues.label_archived_filter=Показать архивированные метки
+issues.label_archive_tooltip=Архивированные метки исключаются по умолчанию из подсказок при поиске по метке.
issues.label_exclusive_desc=Назовите метку область/элемент, чтобы сделать ее взаимоисключающей с другими метками область/.
issues.label_exclusive_warning=Любые метки с конфликтующей областью будут удалены при редактировании меток задачи или запроса на слияние.
issues.label_count=%d меток
@@ -1541,6 +1553,7 @@ issues.tracking_already_started=`Вы уже начали отслеживать
issues.stop_tracking=Остановить таймер
issues.stop_tracking_history=`перестал(а) работать %s`
issues.cancel_tracking=Отмена
+issues.cancel_tracking_history=`отменил(а) отслеживание времени %s`
issues.add_time=Вручную добавить время
issues.del_time=Удалить этот журнал времени
issues.add_time_short=Добавить время
@@ -1696,6 +1709,7 @@ pulls.is_empty=Изменения из этой ветки уже есть в ц
pulls.required_status_check_failed=Некоторые необходимые проверки не были пройдены.
pulls.required_status_check_missing=Отсутствуют некоторые обязательные проверки.
pulls.required_status_check_administrator=Как администратор, вы все равно можете принять этот запрос на слияние.
+pulls.blocked_by_approvals=Этот запрос на слияние пока не имеет достаточного количества одобрений. Получено %d из %d одобрений.
pulls.blocked_by_rejection=Официальный рецензент запросил изменения к этому запросу на слияние.
pulls.can_auto_merge_desc=Этот запрос на слияние может быть объединён автоматически.
pulls.cannot_auto_merge_desc=Этот запрос на слияние не может быть объединён автоматически.
@@ -1742,6 +1756,8 @@ pulls.status_checks_failure=Некоторые проверки не удали
pulls.status_checks_error=Некоторые проверки сообщили об ошибках
pulls.status_checks_requested=Требуется
pulls.status_checks_details=Информация
+pulls.status_checks_hide_all=Скрыть все проверки
+pulls.status_checks_show_all=Показать все проверки
pulls.update_branch=Обновить ветку посредством слияния
pulls.update_branch_rebase=Обновить ветку через rebase
pulls.update_branch_success=Обновление ветки выполнено успешно
@@ -1750,9 +1766,9 @@ pulls.outdated_with_base_branch=Эта ветка отстает от базов
pulls.close=Закрыть запрос на слияние
pulls.closed_at=`закрыл этот запрос на слияние %[2]s`
pulls.reopened_at=`переоткрыл этот запрос на слияние %[2]s`
-pulls.merge_instruction_hint=`Вы также можете просмотреть инструкции командной строки.`
-pulls.merge_instruction_step1_desc=В репозитории вашего проекта посмотрите новую ветку и протестируйте изменения.
-pulls.merge_instruction_step2_desc=Объединить изменения и обновить на Gitea.
+pulls.cmd_instruction_hint=`Просмотреть инструкции для командной строки.`
+pulls.cmd_instruction_merge_title=Слить
+pulls.cmd_instruction_merge_desc=Слить изменения и обновить в Gitea.
pulls.clear_merge_message=Очистить сообщение о слиянии
pulls.clear_merge_message_hint=Очистка сообщения о слиянии удалит только содержимое сообщения коммита, но сохранит сгенерированные git добавки, такие как "Co-Authored-By …".
@@ -1796,6 +1812,8 @@ milestones.edit_success=Этап «%s» обновлён.
milestones.deletion=Удалить этап
milestones.deletion_desc=Удаление этапа приведет к его удалению из всех связанных задач. Продолжить?
milestones.deletion_success=Этап успешно удалён.
+milestones.filter_sort.earliest_due_data=По возрастанию даты завершения
+milestones.filter_sort.latest_due_date=По убыванию даты завершения
milestones.filter_sort.least_complete=Менее полное
milestones.filter_sort.most_complete=Более полное
milestones.filter_sort.most_issues=Большинство задач
@@ -1806,7 +1824,9 @@ signing.wont_sign.never=Коммиты никогда не подписываю
signing.wont_sign.always=Коммиты всегда подписываются.
signing.wont_sign.pubkey=Этот коммит не будет подписан, поскольку к вашей учётной записи не привязано публичного ключа.
signing.wont_sign.twofa=Для подписания коммитов у вас должна быть включена двухфакторная аутентификация.
+signing.wont_sign.parentsigned=Этот коммит не будет подписан, так как родительский коммит не подписан.
signing.wont_sign.basesigned=Слияние не будет подписано, так как базовый коммит не подписан.
+signing.wont_sign.headsigned=Слияние не будет подписано, так как головной коммит не подписан.
signing.wont_sign.commitssigned=Слияние не будет подписано, так как все связанные коммиты не подписаны.
signing.wont_sign.approved=Слияние не будет подписано, так как запрос на слияние не одобрен.
signing.wont_sign.not_signed_in=Вы не вошли в систему.
@@ -1838,7 +1858,7 @@ wiki.page_already_exists=Страница вики с таким именем у
wiki.reserved_page=Имя страницы вики «%s» зарезервировано.
wiki.pages=Страницы
wiki.last_updated=Последнее обновление %s
-wiki.page_name_desc=Введите имя страницы вики. Некоторые специальные имена: 'Главна', '_Sidebar' и '_Footer'.
+wiki.page_name_desc=Введите имя страницы вики. Некоторые специальные имена: 'Home', '_Sidebar' и '_Footer'.
activity=Активность
activity.period.filter_label=Период:
@@ -1952,6 +1972,7 @@ settings.mirror_settings.push_mirror.add=Добавить Push-зеркало
settings.mirror_settings.push_mirror.edit_sync_time=Изменить интервал синхронизации зеркала
settings.sync_mirror=Синхронизировать
+settings.push_mirror_sync_in_progress=Идёт отправка изменений в удалённый репозиторий %s.
settings.site=Сайт
settings.update_settings=Обновить настройки
settings.update_mirror_settings=Обновить настройки зеркала
@@ -2018,6 +2039,7 @@ settings.transfer.rejected=Трансфер репозитория отменё
settings.transfer.success=Трансфер репозитория успешно выполнен.
settings.transfer_abort=Отменить трансфер
settings.transfer_abort_invalid=Невозможно отменить трансфер несуществующего репозитория.
+settings.transfer_abort_success=Передача репозитория %s успешно отменена.
settings.transfer_desc=Передать репозиторий другому пользователю или организации где у вас есть права администратора.
settings.transfer_form_title=Введите сопутствующую информацию для подтверждения операции:
settings.transfer_in_progress=Трансфер в процессе выполнения. Отмените его, если желаете выполнить трансфер другому пользователю.
@@ -2249,6 +2271,7 @@ settings.dismiss_stale_approvals_desc=Когда новые коммиты, из
settings.require_signed_commits=Требовать подписанные коммиты
settings.require_signed_commits_desc=Отклонить отправку изменений в эту ветку, если они не подписаны или не проверяемы.
settings.protect_branch_name_pattern=Шаблон имени для защищённых веток
+settings.protect_branch_name_pattern_desc=Шаблоны имён защищённых веток. О синтаксисе шаблонов читайте в документации. Примеры: main, release/**
settings.protect_patterns=Шаблоны
settings.protect_protected_file_patterns=Шаблоны защищённых файлов (разделённые точкой с запятой ';'):
settings.protect_protected_file_patterns_desc=Защищенные файлы нельзя изменить напрямую, даже если пользователь имеет право добавлять, редактировать или удалять файлы в этой ветке. Можно указать несколько шаблонов, разделяя их точкой с запятой (';'). О синтаксисе шаблонов читайте в документации github.com/gobwas/glob. Примеры: .drone.yml, /docs/**/*.txt.
@@ -2460,6 +2483,7 @@ branch.default_deletion_failed=Ветка «%s» является веткой
branch.restore=Восстановить ветку «%s»
branch.download=Скачать ветку «%s»
branch.rename=Переименовать ветку «%s»
+branch.search=Поиск ветки
branch.included_desc=Эта ветка является частью ветки по умолчанию
branch.included=Включено
branch.create_new_branch=Создать ветку из ветви:
@@ -2482,6 +2506,7 @@ tag.create_success=Тег «%s» создан.
topic.manage_topics=Редактировать тематические метки
topic.done=Сохранить
topic.count_prompt=Нельзя выбрать более 25 тем
+topic.format_prompt=Темы должны начинаться с буквы или цифры и могут содержать дефисы («-») и точки («.»). Длина темы не должна превышать 35 символов. Все буквы должны быть строчными.
find_file.go_to_file=Перейти к файлу
find_file.no_matching=Совпадающих файлов не найдено
@@ -2609,11 +2634,13 @@ teams.all_repositories_helper=Команда имеет доступ ко все
teams.all_repositories_read_permission_desc=Эта команда предоставляет прочтено доступ к всем репозиториям: участники могут просматривать и клонировать репозитории.
teams.all_repositories_write_permission_desc=Эта команда предоставляет Написать доступ к всем репозиториям: участники могут читать и выполнять push в репозитории.
teams.all_repositories_admin_permission_desc=Эта команда предоставляет администратору доступ к всем репозиториям: участники могут читать, отправлять сообщения и добавлять соавторов в репозитории.
+teams.invite.title=Вас пригласили присоединиться к команде %s организации %s.
teams.invite.by=Приглашен(а) %s
teams.invite.description=Нажмите на кнопку ниже, чтобы присоединиться к команде.
[admin]
dashboard=Панель
+identity_access=Идентификация и доступ
users=Пользователи
organizations=Организации
repositories=Репозитории
@@ -2706,6 +2733,7 @@ dashboard.gc_lfs=Выполнить сборку мусора метаобъек
dashboard.stop_zombie_tasks=Остановить задания-зомби
dashboard.stop_endless_tasks=Остановить бесконечные задания
dashboard.cancel_abandoned_jobs=Отменить брошенные задания
+dashboard.start_schedule_tasks=Запустить запланированные задания
users.user_manage_panel=Панель управления пользователями
users.new_account=Создать новый аккаунт
@@ -2800,6 +2828,7 @@ packages.package_manage_panel=Управление пакетами
packages.total_size=Общий размер: %s
packages.unreferenced_size=Размер по ссылке: %s
packages.cleanup=Очистить устаревшие данные
+packages.cleanup.success=Очистка устаревших данных успешно завершена
packages.owner=Владелец
packages.creator=Автор
packages.name=Наименование
@@ -2989,7 +3018,6 @@ config.enable_openid_signin=Включение входа через OpenID
config.show_registration_button=Показать кнопку регистрации
config.require_sign_in_view=Для просмотра необходима авторизация
config.mail_notify=Почтовые уведомления
-config.disable_key_size_check=Отключить проверку на минимальный размер ключа
config.enable_captcha=Включить CAPTCHA
config.active_code_lives=Время жизни кода для активации
config.reset_password_code_lives=Время действия кода восстановления аккаунта
@@ -3097,6 +3125,7 @@ monitor.queue.name=Имя
monitor.queue.type=Тип
monitor.queue.exemplar=Тип образца
monitor.queue.numberworkers=Количество рабочих
+monitor.queue.activeworkers=Активные рабочие
monitor.queue.maxnumberworkers=Максимальное количество рабочих
monitor.queue.numberinqueue=Позиция в очереди
monitor.queue.settings.title=Настройки пула
@@ -3253,8 +3282,6 @@ alpine.repository.repositories=Репозитории
alpine.repository.architectures=Архитектуры
cargo.registry=Настройте этот реестр в файле конфигурации Cargo (например, ~/.cargo/config.toml):
cargo.install=Чтобы установить пакет с помощью Cargo, выполните следующую команду:
-cargo.details.repository_site=Сайт репозитория
-cargo.details.documentation_site=Сайт документации
chef.registry=Настройте этот реестр в своём файле ~/.chef/config.rb:
chef.install=Чтобы установить пакет, выполните следующую команду:
composer.registry=Настройте этот реестр в файле ~/.composer/config.json:
@@ -3266,8 +3293,6 @@ conan.registry=Настроить реестр из командной стро
conan.install=Чтобы установить пакет с помощью Conan, выполните следующую команду:
conda.registry=Пропишите этот реестр в качестве репозитория Conda в своём файле .condarc:
conda.install=Чтобы установить пакет с помощью Conda, выполните следующую команду:
-conda.details.repository_site=Сайт репозитория
-conda.details.documentation_site=Сайт документации
container.details.type=Тип образа
container.details.platform=Платформа
container.pull=Загрузите образ из командной строки:
@@ -3426,17 +3451,23 @@ runners.status.idle=Простаивает
runners.status.active=Активный
runners.status.offline=Недоступен
runners.version=Версия
+runners.reset_registration_token=Сброс регистрационного токена
runners.reset_registration_token_success=Токен регистрации раннера успешно сброшен
runs.all_workflows=Все рабочие потоки
runs.commit=коммит
+runs.scheduled=Запланировано
runs.pushed_by=отправлено
runs.invalid_workflow_helper=Файл конфигурации рабочего потока некорректен. Пожалуйста, проверьте конфигурационный файл: %s
-runs.no_matching_runner_helper=Нет подходящего раннера: %s
runs.actor=Актор
runs.status=Статус
runs.actors_no_select=Все акторы
+runs.no_results=Ничего не найдено.
+runs.no_workflows=Пока нет рабочих процессов.
+runs.no_workflows.quick_start=Не знаете, как начать использовать Действия Gitea? Читайте руководство по быстрому старту.
+runs.no_workflows.documentation=Чтобы узнать больше о Действиях Gitea, читайте документацию.
runs.no_runs=Рабочий поток ещё не запускался.
+runs.empty_commit_message=(пустое сообщение коммита)
workflow.disable=Выключить рабочий поток
workflow.disable_success=Рабочий поток «%s» успешно выключен.
@@ -3469,6 +3500,7 @@ type-3.display_name=Проект организации
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=Каталог
normal_file=Обычный файл
executable_file=Исполняемый файл
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index 6fdcb34228..6d70bc385a 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -83,9 +83,6 @@ write=ලියන්න
preview=පෙරදසුන
loading=පූරණය වෙමින්...
-step1=පියවර 1:
-step2=පියවර 2:
-
error=දෝෂයකි
error404=ඔබ ළඟා වීමට උත්සාහ කරන පිටුව නොපවතී හෝ ඔබට අවසර නැත එය බැලීමට.
@@ -255,7 +252,6 @@ org_no_results=ගැලපෙන සංවිධාන හමු නොවී
code_no_results=ඔබගේ සෙවුම් පදය ගැලපෙන ප්රභව කේතයක් නොමැත.
code_last_indexed_at=අවසන් සුචිගත %s
-
[auth]
create_new_account=ගිණුමක් ලියාපදිංචි කරන්න
register_helper_msg=දැනටමත් ගිණුමක් තිබේද? දැන්ම පුරනය වන්න!
@@ -784,7 +780,7 @@ transfer.accept_desc=`"%s" වෙත මාරු කරන්න`
desc.private=පෞද්ගලික
desc.public=ප්රසිද්ධ
-desc.public_template=සැකිලි
+desc.template=සැකිලි
desc.internal=අභ්යන්තර
desc.archived=සංරක්ෂිත
@@ -1342,9 +1338,6 @@ pulls.update_not_allowed=ශාඛාව යාවත්කාලීන කි
pulls.outdated_with_base_branch=මෙම ශාඛාව මූලික ශාඛාව සමඟ දිවයයි
pulls.closed_at=`මෙම අදින්න ඉල්ලීම වසා %[2]s`
pulls.reopened_at=`මෙම අදින්න ඉල්ලීම නැවත විවෘත කරන ලදි %[2]s`
-pulls.merge_instruction_hint=`ඔබට විධාන රේඛා උපදෙස්ද නැරඹිය හැකිය. `
-pulls.merge_instruction_step1_desc=ඔබගේ ව්යාපෘති ගබඩාවෙන්, නව ශාඛාවක් පරීක්ෂා කර වෙනස්කම් පරීක්ෂා කරන්න.
-pulls.merge_instruction_step2_desc=Gitea හි වෙනස්කම් සහ යාවත්කාලීන කිරීම ඒකාබද්ධ කරන්න.
@@ -2167,7 +2160,6 @@ emails.updated=වි-තැපෑල යාවත්කාල කෙරිණ
emails.not_updated=ඉල්ලූ විද්යුත් තැපැල් ලිපිනය යාවත්කාලීන කිරීමට අපොහොසත් විය: %v
emails.duplicate_active=මෙම විද්යුත් තැපැල් ලිපිනය වෙනත් පරිශීලකයෙකු සඳහා දැනටමත් ක්රියාකාරී වේ.
emails.change_email_header=විද්යුත් ගුණාංග යාවත්කාලීන කරන්න
-emails.change_email_text=මෙම ඊ-තැපැල් ලිපිනය යාවත්කාලීන කිරීමට ඔබට අවශ්යද?
orgs.org_manage_panel=සංවිධාන කළමනාකරණය
orgs.name=නම
@@ -2352,7 +2344,6 @@ config.enable_openid_signin=OpenID සංඥා සක්රීය කරන්
config.show_registration_button=ලියාපදිංචි බොත්තම පෙන්වන්න
config.require_sign_in_view=පිටු බැලීම සඳහා සිග්න්-දී අවශ්ය
config.mail_notify=වි-තැපැල් දැනුම්දීම් සබල කරන්න
-config.disable_key_size_check=අවම කී තරම පරීක්ෂා කරන්න අක්රීය
config.enable_captcha=කැප්චා සක්රීය කරන්න
config.active_code_lives=ක්රියාකාරී කේතය Lives
config.reset_password_code_lives=ගිණුම් කේත කල් ඉකුත් වීමේ වේලාව නැවත ලබා ගන්න
@@ -2559,5 +2550,6 @@ runs.commit=කැප
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=සංකේතාත්මක සබැඳිය
diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini
index d137a6d2be..aa02c701dd 100644
--- a/options/locale/locale_sk-SK.ini
+++ b/options/locale/locale_sk-SK.ini
@@ -100,9 +100,6 @@ write=Zapísať
preview=Náhľad
loading=Načítava sa…
-step1=Krok 1:
-step2=Krok 2:
-
error=Chyba
error404=Stránka, na ktorú sa pokúšate dostať, buď neexistuje, alebo nemáte oprávnenie na jej zobrazenie.
@@ -290,7 +287,6 @@ code_last_indexed_at=Naposledy indexované %s
relevant_repositories_tooltip=Repozitáre, ktoré sú forkami alebo ktoré nemajú tému, žiadnu ikonu ani popis, sú skryté.
relevant_repositories=Zobrazujú sa iba relevantné repozitáre, zobraziť nefiltrované výsledky.
-
[auth]
create_new_account=Zaregistrovať účet
register_helper_msg=Máte už účet? Prihláste sa teraz!
@@ -839,10 +835,8 @@ transfer.reject_desc=`Zrušiť prevod do "%s"`
desc.private=Súkromný
desc.public=Verejný
-desc.private_template=Súkromná šablóna
-desc.public_template=Šablóna
+desc.template=Šablóna
desc.internal=Interný
-desc.internal_template=Interná šablóna
desc.archived=Archivovaný
template.items=Položky šablóny
@@ -1297,5 +1291,6 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Symbolický odkaz
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index ce3f7d5d9b..411a83ed75 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -76,7 +76,6 @@ write=Skriv
preview=Förhandsgranska
loading=Laddar…
-
error404=Sidan du försöker nå finns inte eller så har du inte behörighet att se den.
@@ -240,7 +239,6 @@ org_no_results=Inga matchande organisationer hittades.
code_no_results=Ingen källkod hittades som matchar din sökterm.
code_last_indexed_at=Indexerades senast %s
-
[auth]
create_new_account=Registrera Konto
register_helper_msg=Har du redan ett konto? Logga in nu!
@@ -661,10 +659,8 @@ delete_preexisting_content=Ta bort filer i %s
desc.private=Privat
desc.public=Publik
-desc.private_template=Privat mall
-desc.public_template=Mall
+desc.template=Mall
desc.internal=Intern
-desc.internal_template=Intern mall
desc.archived=Arkiverade
template.items=Mallobjekt
@@ -1878,7 +1874,6 @@ config.enable_openid_signin=Aktivera OpenID-inloggning
config.show_registration_button=Visa registreringsknapp
config.require_sign_in_view=Kräv inloggning för att visa sidor
config.mail_notify=Aktivera Mejlnotifikationer
-config.disable_key_size_check=Avaktivera kontroll av minsta tillåtna nyckelstorlek
config.enable_captcha=Aktivera CAPTCHA
config.active_code_lives=Aktivera livstid för koder
config.default_keep_email_private=Dölj mejladresser som standard
@@ -2068,5 +2063,6 @@ runs.commit=Commit
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Symbolisk länk
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index 4c0fc95c0a..dd7d1b066e 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -107,9 +107,6 @@ write=Yaz
preview=Önizleme
loading=Yükleniyor…
-step1=1. Adım:
-step2=2. Adım:
-
error=Hata
error404=Ulaşmaya çalıştığınız sayfa mevcut değil veya görüntüleme yetkiniz yok.
@@ -351,7 +348,6 @@ code_last_indexed_at=Son dizinlenen %s
relevant_repositories_tooltip=Çatal olan veya konusu, simgesi veya açıklaması olmayan depolar gizlenmiştir.
relevant_repositories=Sadece ilişkili depolar gösteriliyor, süzülmemiş sonuçları göster.
-
[auth]
create_new_account=Hesap Oluştur
register_helper_msg=Bir hesabınız var mı? Şimdi giriş yapın!
@@ -919,7 +915,6 @@ visibility.private=Özel
visibility.private_tooltip=Sadece katıldığınız organizasyonların üyeleri tarafından görünür
[repo]
-new_repo_helper=Bir depo, sürüm geçmişi dahil tüm proje dosyalarını içerir. Zaten başka bir yerde mi barındırıyorsunuz? Depoyu taşıyın.
owner=Sahibi
owner_helper=Bazı organizasyonlar, en çok depo sayısı sınırı nedeniyle açılır menüde görünmeyebilir.
repo_name=Depo İsmi
@@ -1016,10 +1011,8 @@ transfer.no_permission_to_reject=Bu aktarımı reddetme izniniz yok.
desc.private=Özel
desc.public=Genel
-desc.private_template=Özel şablon
-desc.public_template=Şablon
+desc.template=Şablon
desc.internal=Dahili
-desc.internal_template=Dahili şablon
desc.archived=Arşivlenmiş
template.items=Şablon Öğeleri
@@ -1771,9 +1764,6 @@ pulls.outdated_with_base_branch=Bu dal, temel dal ile güncel değil
pulls.close=Değişiklik İsteğini Kapat
pulls.closed_at=`%[2]s değişiklik isteğini kapattı`
pulls.reopened_at=`%[2]s değişiklik isteğini yeniden açtı`
-pulls.merge_instruction_hint=`komut satırı talimatlarını da görüntüleyebilirsiniz.`
-pulls.merge_instruction_step1_desc=Proje deponuzdan yeni bir dala göz atın ve değişiklikleri test edin.
-pulls.merge_instruction_step2_desc=Gitea'daki değişiklikleri ve güncellemeleri birleştirin.
pulls.clear_merge_message=Birleştirme iletilerini temizle
pulls.clear_merge_message_hint=Birleştirme iletisini temizlemek sadece işleme ileti içeriğini kaldırır ama üretilmiş "Co-Authored-By …" gibi git fragmanlarını korur.
@@ -2342,7 +2332,7 @@ settings.lfs_findcommits=İşleme bul
settings.lfs_lfs_file_no_commits=Bu LFS dosyası için hiçbir işleme bulunamadı
settings.lfs_noattribute=Bu yol, varsayılan dalda kilitlenebilir özelliğe sahip değil
settings.lfs_delete=OID %s ile LFS dosyasını sil
-settings.lfs_delete_warning=Bir LFS dosyasını silmek, ödeme sırasında 'nesne yok' hatalarına neden olabilir. Emin misiniz?
+settings.lfs_delete_warning=Bir LFS dosyasını silmek, çekme sırasında 'nesne yok' hatalarına neden olabilir. Emin misiniz?
settings.lfs_findpointerfiles=İşaretçi dosyalarını bul
settings.lfs_locks=Kilitler
settings.lfs_invalid_locking_path=Geçersiz yol: %s
@@ -2815,7 +2805,6 @@ emails.updated=E-posta güncellendi
emails.not_updated=İstenen e-posta adresi güncellenemedi: %v
emails.duplicate_active=Bu e-posta adresi farklı bir kullanıcı için zaten aktif.
emails.change_email_header=E-posta Özelliklerini Güncelle
-emails.change_email_text=Bu e-posta adresini güncellemek istediğinizden emin misiniz?
orgs.org_manage_panel=Organizasyon Yönetimi
orgs.name=İsim
@@ -3030,7 +3019,6 @@ config.enable_openid_signin=OpenID Oturum Açmayı Etkinleştiriniz
config.show_registration_button=Kaydolma Düğmesini Göster
config.require_sign_in_view=Sayfaları Görüntülemek için Giriş Yapmaya Zorla
config.mail_notify=E-Posta Bildirimlerini Etkinleştir
-config.disable_key_size_check=Minimum Anahtar Uzunluğu Kontrolünü Devre Dışı Bırak
config.enable_captcha=CAPTCHA'yı Etkinleştir
config.active_code_lives=Kod Yaşamlarını Aktifleştir
config.reset_password_code_lives=Hesap Kodunun Sona Erme Zamanını Kurtar
@@ -3294,8 +3282,6 @@ alpine.repository.repositories=Depolar
alpine.repository.architectures=Mimariler
cargo.registry=Bu kütüğü Cargo yapılandırma dosyasına (örneğin ~/.cargo/config.toml) ayarlayın:
cargo.install=Paketi Cargo kullanarak kurmak için, şu komutu çalıştırın:
-cargo.details.repository_site=Depo Sitesi
-cargo.details.documentation_site=Belge Sitesi
chef.registry=Bu kütüğü ~/.chef/config.rb dosyasında ayarlayın:
chef.install=Paketi kurmak için, aşağıdaki komutu çalıştırın:
composer.registry=Bu kütüğü ~/.composer/config.json dosyasında ayarlayın:
@@ -3307,8 +3293,6 @@ conan.registry=Bu kütüğü komut satırını kullanarak kurun:
conan.install=Conan ile paket kurmak için aşağıdaki komutu çalıştırın:
conda.registry=Bu kütüğü .condarc dosyasında bir Conda deposu olarak ayarlayın:
conda.install=Conda ile paket kurmak için aşağıdaki komutu çalıştırın:
-conda.details.repository_site=Depo Sitesi
-conda.details.documentation_site=Belge Sitesi
container.details.type=Görüntü Türü
container.details.platform=Platform
container.pull=Görüntüyü komut satırını kullanarak çekin:
@@ -3476,7 +3460,6 @@ runs.all_workflows=Tüm İş Akışları
runs.commit=İşle
runs.pushed_by=iten
runs.invalid_workflow_helper=İş akışı yapılandırma dosyası geçersiz. Lütfen yapılandırma dosyanızı denetleyin: %s
-runs.no_matching_runner_helper=Eşleşen çalıştırıcı yok: %s
runs.actor=Aktör
runs.status=Durum
runs.actors_no_select=Tüm aktörler
@@ -3514,6 +3497,7 @@ type-3.display_name=Organizasyon Projesi
[git.filemode]
changed_filemode=%[1]s → %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=Dizin
normal_file=Normal dosya
executable_file=Çalıştırılabilir dosya
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index 85adc61d33..4cd6c44571 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -84,9 +84,6 @@ write=Писати
preview=Попередній перегляд
loading=Завантаження…
-step1=Крок 1:
-step2=Крок 2:
-
error=Помилка
error404=Сторінка, до якої ви намагаєтеся звернутися або до , не існує або Ви не маєте права на її перегляд.
@@ -270,7 +267,6 @@ org_no_results=Відповідних організацій не знайден
code_no_results=Відповідний пошуковому запитанню код не знайдено.
code_last_indexed_at=Останні індексовані %s
-
[auth]
create_new_account=Реєстрація облікового запису
register_helper_msg=Вже зареєстровані? Увійдіть зараз!
@@ -807,10 +803,8 @@ transfer.reject_desc=`Скасувати переміщення до "%s"`
desc.private=Приватний
desc.public=Публічний
-desc.private_template=Приватний шаблон
-desc.public_template=Шаблон
+desc.template=Шаблон
desc.internal=Внутрішній
-desc.internal_template=Внутрішній шаблон
desc.archived=Архівний
template.items=Елементи шаблону
@@ -1392,9 +1386,6 @@ pulls.update_not_allowed=Ви не можете оновити гілку
pulls.outdated_with_base_branch=Ця гілка застаріла відносно базової гілки
pulls.closed_at=`закрив цей запит на злиття %[2]s`
pulls.reopened_at=`повторно відкрив цей запит на злиття %[2]s`
-pulls.merge_instruction_hint=`Також можна переглянути інструкції для командного рядка.`
-pulls.merge_instruction_step1_desc=У репозиторії вашого проєкту перевірте нову гілку і протестуйте зміни.
-pulls.merge_instruction_step2_desc=Об'єднати зміни і оновити на Gitea.
@@ -2221,7 +2212,6 @@ emails.updated=Електронну пошту оновлено
emails.not_updated=Не вдалось оновити адресу електронної пошти: %v
emails.duplicate_active=Ця електронна адреса вже активна для іншого користувача.
emails.change_email_header=Редагувати властивості електронної пошти
-emails.change_email_text=Ви впевнені, що хочете оновити цю адресу електронної пошти?
orgs.org_manage_panel=Керування організаціями
orgs.name=Назва
@@ -2407,7 +2397,6 @@ config.enable_openid_signin=Увімкнути реєстрацію за доп
config.show_registration_button=`Показувати кнопку "Реєстрація"`
config.require_sign_in_view=Вимагати авторизації для перегляду сторінок
config.mail_notify=Увімкнути сповіщення електронною поштою
-config.disable_key_size_check=Вимкнути перевірку мінімального розміру ключа
config.enable_captcha=Увімкнути CAPTCHA
config.active_code_lives=Час актуальності кода підтвердження
config.reset_password_code_lives=Відновлення часу закінчення терміну дії коду облікового запису
@@ -2634,5 +2623,6 @@ runs.commit=Коміт
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=Символічне посилання
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index 8ebf6c509c..77414f1570 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -108,9 +108,6 @@ write=撰写
preview=预览
loading=正在加载...
-step1=第一步:
-step2=第二步:
-
error=错误
error404=您正尝试访问的页面 不存在 或 您尚未被授权 查看该页面。
go_back=返回
@@ -354,7 +351,6 @@ code_last_indexed_at=最后索引于 %s
relevant_repositories_tooltip=派生的仓库,以及缺少主题、图标和描述的仓库将被隐藏。
relevant_repositories=只显示相关的仓库, 显示未过滤结果。
-
[auth]
create_new_account=注册帐号
register_helper_msg=已经注册?立即登录!
@@ -924,7 +920,6 @@ visibility.private=私有
visibility.private_tooltip=仅对您已加入的组织的成员可见。
[repo]
-new_repo_helper=代码仓库包含了所有的项目文件,包括版本历史记录。已经在其他地方托管了一个?迁移仓库。
owner=拥有者
owner_helper=由于最大仓库数量限制,一些组织可能不会显示在下拉列表中。
repo_name=仓库名称
@@ -1029,10 +1024,8 @@ transfer.no_permission_to_reject=您没有权限拒绝此转让。
desc.private=私有库
desc.public=公开
-desc.private_template=私有模板
-desc.public_template=模板
+desc.template=模板
desc.internal=内部
-desc.internal_template=内部模板
desc.archived=已存档
template.items=模板选项
@@ -1797,9 +1790,6 @@ pulls.outdated_with_base_branch=此分支相比基础分支已过期
pulls.close=关闭合并请求
pulls.closed_at=`于 %[2]s 关闭此合并请求 `
pulls.reopened_at=`重新打开此合并请求 %[2]s`
-pulls.merge_instruction_hint=`你也可以查看 命令行指令`
-pulls.merge_instruction_step1_desc=从你的仓库中签出一个新的分支并测试变更。
-pulls.merge_instruction_step2_desc=合并变更并更新到 Gitea 上
pulls.clear_merge_message=清除合并信息
pulls.clear_merge_message_hint=清除合并消息只会删除提交消息内容,并保留生成的 git 附加内容,如“Co-Authored-By …”。
@@ -2311,7 +2301,6 @@ settings.dismiss_stale_approvals_desc=当新的提交更改合并请求内容被
settings.require_signed_commits=需要签名提交
settings.require_signed_commits_desc=拒绝推送未签名或无法验证的提交到分支
settings.protect_branch_name_pattern=受保护的分支名称模式
-settings.protect_branch_name_pattern_desc=分支保护的名称匹配规则。语法请参阅 文档 。如:main, release/**
settings.protect_patterns=规则
settings.protect_protected_file_patterns=受保护的文件模式(使用分号 ';' 分隔):
settings.protect_protected_file_patterns_desc=即使用户有权添加、编辑或删除此分支中的文件,也不允许直接更改受保护的文件。 可以使用分号 (';') 分隔多个模式。 见github.com/gobwas/glob文档了解模式语法。例如: .drone.yml, /docs/**/*.txt
@@ -2507,7 +2496,6 @@ release.releases_for=%s 的版本发布
release.tags_for=%s 的标签
branch.name=分支名称
-branch.search=搜索分支
branch.already_exists=名为 %s 的分支已存在。
branch.delete_head=刪除
branch.delete=删除分支 %s
@@ -2530,6 +2518,7 @@ branch.default_deletion_failed=不能删除默认分支"%s"。
branch.restore=`还原分支 "%s"`
branch.download=`下载分支 "%s"`
branch.rename=`重命名分支 "%s"`
+branch.search=搜索分支
branch.included_desc=此分支是默认分支的一部分
branch.included=已包含
branch.create_new_branch=从下列分支创建分支:
@@ -2857,7 +2846,6 @@ emails.updated=电子邮件已更新
emails.not_updated=无法更新请求的电子邮件地址: %v
emails.duplicate_active=此电子邮件地址已被另一个用户激活使用。
emails.change_email_header=更新电子邮件属性
-emails.change_email_text=您确认要更新这个电子邮件地址吗?
orgs.org_manage_panel=组织管理
orgs.name=名称
@@ -3075,7 +3063,6 @@ config.enable_openid_signin=启用 OpenID 登录
config.show_registration_button=显示注册按钮
config.require_sign_in_view=启用登录访问限制
config.mail_notify=启用邮件通知
-config.disable_key_size_check=禁用密钥最小长度检查
config.enable_captcha=启用登录验证码
config.active_code_lives=激活用户链接有效期
config.reset_password_code_lives=恢复账户验证码过期时间
@@ -3341,8 +3328,6 @@ alpine.repository.repositories=仓库管理
alpine.repository.architectures=架构
cargo.registry=在 Cargo 配置文件中设置此注册中心(例如:~/.cargo/config.toml):
cargo.install=要使用 Cargo 安装软件包,请运行以下命令:
-cargo.details.repository_site=仓库站点
-cargo.details.documentation_site=文档站点
chef.registry=在您的 ~/.chef/config.rb 文件中设置此注册中心:
chef.install=要安装包,请运行以下命令:
composer.registry=在您的 ~/.composer/config.json 文件中设置此注册中心:
@@ -3354,8 +3339,6 @@ conan.registry=从命令行设置此注册中心:
conan.install=要使用 Conan 安装软件包,请运行以下命令:
conda.registry=在您的 .condarc 文件中将此注册中心设置为 Conda 仓库:
conda.install=要使用 Conda 安装软件包,请运行以下命令:
-conda.details.repository_site=仓库站点
-conda.details.documentation_site=文档站点
container.details.type=镜像类型
container.details.platform=平台
container.pull=从命令行拉取镜像:
@@ -3525,7 +3508,6 @@ runs.commit=提交
runs.scheduled=已计划的
runs.pushed_by=推送者
runs.invalid_workflow_helper=工作流配置文件无效。请检查您的配置文件: %s
-runs.no_matching_runner_helper=没有匹配的runner:%s
runs.actor=操作者
runs.status=状态
runs.actors_no_select=所有操作者
@@ -3564,6 +3546,7 @@ type-3.display_name=组织项目
[git.filemode]
changed_filemode=%[1]s -> %[2]s
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
directory=目录
normal_file=普通文件
executable_file=可执行文件
diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini
index dfa048c5ef..d4074026fd 100644
--- a/options/locale/locale_zh-HK.ini
+++ b/options/locale/locale_zh-HK.ini
@@ -55,7 +55,6 @@ enabled=已啟用
-
concept_code_repository=儲存庫
@@ -119,7 +118,6 @@ users=使用者
organizations=組織
search=搜尋
-
[auth]
register_helper_msg=已經註冊?立即登錄!
forgot_password_title=忘記密碼
@@ -319,7 +317,7 @@ forks=複製儲存庫
desc.private=私有庫
-desc.public_template=樣板
+desc.template=樣板
template.avatar=頭像
@@ -841,7 +839,6 @@ config.db_path=資料庫路徑
config.service_config=服務設定
config.show_registration_button=顯示註冊按鈕
-config.disable_key_size_check=禁用金鑰最小長度檢查
config.active_code_lives=啟用用戶連結有效期
config.webhook_config=Webhook 設定
@@ -990,4 +987,5 @@ runners.task_list.repository=儲存庫
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index e058ca7191..ea79c45674 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -103,9 +103,6 @@ write=撰寫
preview=預覽
loading=載入中…
-step1=第一步:
-step2=第二步:
-
error=錯誤
error404=您正嘗試訪問的頁面 不存在 或 您尚未被授權 查看該頁面。
@@ -333,7 +330,6 @@ code_last_indexed_at=最後索引 %s
relevant_repositories_tooltip=已隱藏缺少主題、圖示、說明、Fork 的儲存庫。
relevant_repositories=只顯示相關的儲存庫,顯示未篩選的結果。
-
[auth]
create_new_account=註冊帳戶
register_helper_msg=已經有帳戶了?立即登入!
@@ -939,10 +935,8 @@ transfer.reject_desc=取消轉移到「%s」
desc.private=私有
desc.public=公開
-desc.private_template=私有範本
-desc.public_template=範本
+desc.template=模板
desc.internal=組織內部用
-desc.internal_template=組織內部範本
desc.archived=已封存
template.items=範本項目
@@ -1639,9 +1633,6 @@ pulls.outdated_with_base_branch=相對於基底分支,此分支已過時
pulls.close=關閉合併請求
pulls.closed_at=`關閉了這個合併請求 %[2]s`
pulls.reopened_at=`重新開放了這個合併請求 %[2]s`
-pulls.merge_instruction_hint=`您也可以查看命令列指南。`
-pulls.merge_instruction_step1_desc=在您的儲存庫中切換到新分支並測試變更。
-pulls.merge_instruction_step2_desc=合併變更並更新到 Gitea。
pulls.clear_merge_message=清除合併訊息
pulls.clear_merge_message_hint=清除合併訊息將僅移除提交訊息內容,留下產生的 git 結尾,如「Co-Authored-By …」。
@@ -2607,7 +2598,6 @@ emails.updated=信箱已更新
emails.not_updated=電子信箱更新失敗: %v
emails.duplicate_active=此信箱已被其他使用者使用
emails.change_email_header=更新電子信箱屬性
-emails.change_email_text=您確定要更新這個電子信箱?
orgs.org_manage_panel=組織管理
orgs.name=名稱
@@ -2818,7 +2808,6 @@ config.enable_openid_signin=啟用 OpenID 登入
config.show_registration_button=顯示註冊按鈕
config.require_sign_in_view=需要登入才能瀏覽頁面
config.mail_notify=啟用郵件通知
-config.disable_key_size_check=停用金鑰最小長度檢查
config.enable_captcha=啟用驗證碼
config.active_code_lives=啟用用戶連結有效期
config.reset_password_code_lives=帳戶救援碼有效時間
@@ -3072,8 +3061,6 @@ alpine.repository.repositories=儲存庫
alpine.repository.architectures=架構
cargo.registry=在 Cargo 組態檔設定此註冊中心 (例如: ~/.cargo/config.toml):
cargo.install=執行下列命令以使用 Cargo 安裝此套件:
-cargo.details.repository_site=儲存庫網站
-cargo.details.documentation_site=文件網站
chef.registry=在您的 ~/.chef/config.rb 檔設定此註冊中心:
chef.install=執行下列命令安裝此套件:
composer.registry=在您的 ~/.composer/config.json 檔設定此註冊中心:
@@ -3085,8 +3072,6 @@ conan.registry=透過下列命令設定此註冊中心:
conan.install=執行下列命令以使用 Conan 安裝此套件:
conda.registry=在您的 .condarc 檔設定此註冊中心為 Conda 存儲庫:
conda.install=執行下列命令以使用 Conda 安裝此套件:
-conda.details.repository_site=儲存庫網站
-conda.details.documentation_site=文件網站
container.details.type=映像檔類型
container.details.platform=平台
container.pull=透過下列命令拉取映像檔:
@@ -3239,7 +3224,6 @@ runners.reset_registration_token_success=成功重設了 Runner 註冊 Token
runs.all_workflows=所有工作流程
runs.commit=提交
runs.invalid_workflow_helper=工作流程設定檔無效。請檢查您的設定檔: %s
-runs.no_matching_runner_helper=找不到符合的 Runner: %s
runs.status=狀態
runs.no_runs=工作流程沒有執行過。
@@ -3254,5 +3238,6 @@ need_approval_desc=來自 Frok 儲存庫的合併請求需要核可才能執行
[projects]
[git.filemode]
+; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", …
symbolic_link=符號連結
diff --git a/package-lock.json b/package-lock.json
index 5a49efee23..5f4dc9bc2b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,7 +11,7 @@
"@citation-js/plugin-software-formats": "0.6.1",
"@claviska/jquery-minicolors": "2.3.6",
"@github/markdown-toolbar-element": "2.2.1",
- "@github/relative-time-element": "4.3.0",
+ "@github/relative-time-element": "4.3.1",
"@github/text-expander-element": "2.6.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.8.0",
@@ -33,19 +33,19 @@
"mermaid": "10.6.1",
"mini-css-extract-plugin": "2.7.6",
"minimatch": "9.0.3",
- "monaco-editor": "0.44.0",
+ "monaco-editor": "0.45.0",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.2.12",
"pretty-ms": "8.0.0",
- "sortablejs": "1.15.0",
- "swagger-ui-dist": "5.10.0",
+ "sortablejs": "1.15.1",
+ "swagger-ui-dist": "5.10.5",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
"toastify-js": "1.12.0",
"tributejs": "5.1.3",
"uint8-to-base64": "0.2.0",
- "vue": "3.3.8",
+ "vue": "3.3.13",
"vue-bar-graph": "2.0.0",
"vue-loader": "17.3.1",
"vue3-calendar-heatmap": "2.0.5",
@@ -55,35 +55,35 @@
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
- "@playwright/test": "1.40.0",
+ "@playwright/test": "1.40.1",
"@stoplight/spectral-cli": "6.11.0",
- "@stylistic/eslint-plugin-js": "1.4.0",
- "@vitejs/plugin-vue": "4.5.0",
- "eslint": "8.54.0",
+ "@stylistic/eslint-plugin-js": "1.5.1",
+ "@vitejs/plugin-vue": "4.5.2",
+ "eslint": "8.56.0",
"eslint-plugin-array-func": "4.0.0",
- "eslint-plugin-i": "2.29.0",
+ "eslint-plugin-i": "2.29.1",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
- "eslint-plugin-regexp": "2.1.1",
+ "eslint-plugin-regexp": "2.1.2",
"eslint-plugin-sonarjs": "0.23.0",
"eslint-plugin-unicorn": "49.0.0",
- "eslint-plugin-vitest": "0.3.9",
+ "eslint-plugin-vitest": "0.3.18",
"eslint-plugin-vitest-globals": "1.4.0",
- "eslint-plugin-vue": "9.18.1",
- "eslint-plugin-vue-scoped-css": "2.5.1",
+ "eslint-plugin-vue": "9.19.2",
+ "eslint-plugin-vue-scoped-css": "2.6.1",
"eslint-plugin-wc": "2.0.4",
- "jsdom": "22.1.0",
- "markdownlint-cli": "0.37.0",
+ "jsdom": "23.0.1",
+ "markdownlint-cli": "0.38.0",
"postcss-html": "1.5.0",
"stylelint": "15.11.0",
"stylelint-declaration-block-no-ignored-properties": "2.7.0",
"stylelint-declaration-strict-value": "1.9.2",
"stylelint-stylistic": "0.4.3",
- "svgo": "3.0.4",
+ "svgo": "3.1.0",
"updates": "15.0.4",
"vite-string-plugin": "1.1.2",
- "vitest": "0.34.6"
+ "vitest": "1.1.0"
},
"engines": {
"node": ">= 18.0.0"
@@ -286,9 +286,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
- "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
+ "version": "7.23.6",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz",
+ "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -920,9 +920,9 @@
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz",
- "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==",
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
@@ -987,18 +987,18 @@
}
},
"node_modules/@eslint/js": {
- "version": "8.54.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
- "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
+ "version": "8.56.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz",
+ "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@github/combobox-nav": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.3.0.tgz",
- "integrity": "sha512-5CX03DbsLZ41dX5hKHyQKtg133U6lruX4TD9G0Zs4W8BpWy7lN8DJ6TYaeZN/V7x8K34coaqNYk/Y5ic7stfkg=="
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.3.1.tgz",
+ "integrity": "sha512-gwxPzLw8XKecy1nP63i9lOBritS3bWmxl02UX6G0TwMQZbMem1BCS1tEZgYd3mkrkiDrUMWaX+DbFCuDFo3K+A=="
},
"node_modules/@github/markdown-toolbar-element": {
"version": "2.2.1",
@@ -1006,9 +1006,9 @@
"integrity": "sha512-ap+ulyqzG3aVqwKsKjbDdYwM75TQXZpPtmIuPwm+54OTgcC96267oX3cEqd1wSqGsH7O5PonZ//fE9jH7Q4JkA=="
},
"node_modules/@github/relative-time-element": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.3.0.tgz",
- "integrity": "sha512-+tFjX9//HRS1HnBa5cNgfEtE52arwiutYg1TOF+Trk40SPxst9Q8Rtc3BKD6aKsvfbtub68vfhipgchGjj9o7g=="
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@github/relative-time-element/-/relative-time-element-4.3.1.tgz",
+ "integrity": "sha512-zL79nlhZVCg7x2Pf/HT5MB0mowmErE71VXpF10/3Wy8dQwkninNO1M9aOizh2wKC5LkSpDXqNYjDZwbH0/bcSg=="
},
"node_modules/@github/text-expander-element": {
"version": "2.6.1",
@@ -1349,12 +1349,12 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.0.tgz",
- "integrity": "sha512-PdW+kn4eV99iP5gxWNSDQCbhMaDVej+RXL5xr6t04nbKLCBwYtA046t7ofoczHOm8u6c+45hpDKQVZqtqwkeQg==",
+ "version": "1.40.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz",
+ "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==",
"dev": true,
"dependencies": {
- "playwright": "1.40.0"
+ "playwright": "1.40.1"
},
"bin": {
"playwright": "cli.js"
@@ -1424,6 +1424,175 @@
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
"dev": true
},
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz",
+ "integrity": "sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.1.tgz",
+ "integrity": "sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz",
+ "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.1.tgz",
+ "integrity": "sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.1.tgz",
+ "integrity": "sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.1.tgz",
+ "integrity": "sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.1.tgz",
+ "integrity": "sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.1.tgz",
+ "integrity": "sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.1.tgz",
+ "integrity": "sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.1.tgz",
+ "integrity": "sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.1.tgz",
+ "integrity": "sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.1.tgz",
+ "integrity": "sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.1.tgz",
+ "integrity": "sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@sinclair/typebox": {
"version": "0.27.8",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
@@ -1882,16 +2051,21 @@
"dev": true
},
"node_modules/@stylistic/eslint-plugin-js": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.4.0.tgz",
- "integrity": "sha512-cANyn4ECWu8kxPmBM4K/Q4WocD3JbA0POmGbA2lJ4tynPE8jGyKpfP8SZj6BIidXV0pkyqvxEfaKppB4D16UsA==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.5.1.tgz",
+ "integrity": "sha512-iZF0rF+uOhAmOJYOJx1Yvmm3CZ1uz9n0SRd9dpBYHA3QAvfABUORh9LADWwZCigjHJkp2QbCZelGFJGwGz7Siw==",
"dev": true,
"dependencies": {
"acorn": "^8.11.2",
"escape-string-regexp": "^4.0.0",
"eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "graphemer": "^1.4.0"
+ "espree": "^9.6.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=8.40.0"
}
},
"node_modules/@swc/helpers": {
@@ -1899,15 +2073,6 @@
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.2.14.tgz",
"integrity": "sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA=="
},
- "node_modules/@tootallnate/once": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
- "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -1917,21 +2082,6 @@
"node": ">=10.13.0"
}
},
- "node_modules/@types/chai": {
- "version": "4.3.9",
- "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.9.tgz",
- "integrity": "sha512-69TtiDzu0bcmKQv3yg1Zx409/Kd7r0b5F1PfpYJfSHzLGtB53547V4u+9iqKYsTu/O2ai6KTb0TInNpvuQ3qmg==",
- "dev": true
- },
- "node_modules/@types/chai-subset": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.4.tgz",
- "integrity": "sha512-CCWNXrJYSUIojZ1149ksLl3AN9cmZ5djf+yUoVVV+NuYrtydItQVlL2ZDqyC6M6O9LWRnVf8yYDxbXHO2TfQZg==",
- "dev": true,
- "dependencies": {
- "@types/chai": "*"
- }
- },
"node_modules/@types/codemirror": {
"version": "5.60.12",
"resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.12.tgz",
@@ -2048,9 +2198,9 @@
"dev": true
},
"node_modules/@types/semver": {
- "version": "7.5.4",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz",
- "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
+ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
},
"node_modules/@types/tern": {
@@ -2073,13 +2223,13 @@
"dev": true
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz",
- "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.15.0.tgz",
+ "integrity": "sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/visitor-keys": "6.9.1"
+ "@typescript-eslint/types": "6.15.0",
+ "@typescript-eslint/visitor-keys": "6.15.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -2090,9 +2240,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz",
- "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.15.0.tgz",
+ "integrity": "sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -2103,13 +2253,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz",
- "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.15.0.tgz",
+ "integrity": "sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/visitor-keys": "6.9.1",
+ "@typescript-eslint/types": "6.15.0",
+ "@typescript-eslint/visitor-keys": "6.15.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@@ -2130,17 +2280,17 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz",
- "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.15.0.tgz",
+ "integrity": "sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.9.1",
- "@typescript-eslint/types": "6.9.1",
- "@typescript-eslint/typescript-estree": "6.9.1",
+ "@typescript-eslint/scope-manager": "6.15.0",
+ "@typescript-eslint/types": "6.15.0",
+ "@typescript-eslint/typescript-estree": "6.15.0",
"semver": "^7.5.4"
},
"engines": {
@@ -2155,12 +2305,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.9.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz",
- "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==",
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.15.0.tgz",
+ "integrity": "sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.9.1",
+ "@typescript-eslint/types": "6.15.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
@@ -2178,9 +2328,9 @@
"dev": true
},
"node_modules/@vitejs/plugin-vue": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.0.tgz",
- "integrity": "sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==",
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.2.tgz",
+ "integrity": "sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==",
"dev": true,
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -2191,13 +2341,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz",
- "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.1.0.tgz",
+ "integrity": "sha512-9IE2WWkcJo2BR9eqtY5MIo3TPmS50Pnwpm66A6neb2hvk/QSLfPXBz2qdiwUOQkwyFuuXEUj5380CbwfzW4+/w==",
"dev": true,
"dependencies": {
- "@vitest/spy": "0.34.6",
- "@vitest/utils": "0.34.6",
+ "@vitest/spy": "1.1.0",
+ "@vitest/utils": "1.1.0",
"chai": "^4.3.10"
},
"funding": {
@@ -2205,13 +2355,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz",
- "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.1.0.tgz",
+ "integrity": "sha512-zdNLJ00pm5z/uhbWF6aeIJCGMSyTyWImy3Fcp9piRGvueERFlQFbUwCpzVce79OLm2UHk9iwaMSOaU9jVHgNVw==",
"dev": true,
"dependencies": {
- "@vitest/utils": "0.34.6",
- "p-limit": "^4.0.0",
+ "@vitest/utils": "1.1.0",
+ "p-limit": "^5.0.0",
"pathe": "^1.1.1"
},
"funding": {
@@ -2219,15 +2369,15 @@
}
},
"node_modules/@vitest/runner/node_modules/p-limit": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
- "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz",
+ "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==",
"dev": true,
"dependencies": {
"yocto-queue": "^1.0.0"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
@@ -2246,14 +2396,14 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz",
- "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.1.0.tgz",
+ "integrity": "sha512-5O/wyZg09V5qmNmAlUgCBqflvn2ylgsWJRRuPrnHEfDNT6tQpQ8O1isNGgo+VxofISHqz961SG3iVvt3SPK/QQ==",
"dev": true,
"dependencies": {
- "magic-string": "^0.30.1",
+ "magic-string": "^0.30.5",
"pathe": "^1.1.1",
- "pretty-format": "^29.5.0"
+ "pretty-format": "^29.7.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
@@ -2272,65 +2422,65 @@
}
},
"node_modules/@vitest/spy": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz",
- "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.1.0.tgz",
+ "integrity": "sha512-sNOVSU/GE+7+P76qYo+VXdXhXffzWZcYIPQfmkiRxaNCSPiLANvQx5Mx6ZURJ/ndtEkUJEpvKLXqAYTKEY+lTg==",
"dev": true,
"dependencies": {
- "tinyspy": "^2.1.1"
+ "tinyspy": "^2.2.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/utils": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz",
- "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.1.0.tgz",
+ "integrity": "sha512-z+s510fKmYz4Y41XhNs3vcuFTFhcij2YF7F8VQfMEYAAUfqQh0Zfg7+w9xdgFGhPf3tX3TicAe+8BDITk6ampQ==",
"dev": true,
"dependencies": {
- "diff-sequences": "^29.4.3",
- "loupe": "^2.3.6",
- "pretty-format": "^29.5.0"
+ "diff-sequences": "^29.6.3",
+ "loupe": "^2.3.7",
+ "pretty-format": "^29.7.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vue/compiler-core": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.8.tgz",
- "integrity": "sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.13.tgz",
+ "integrity": "sha512-bwi9HShGu7uaZLOErZgsH2+ojsEdsjerbf2cMXPwmvcgZfVPZ2BVZzCVnwZBxTAYd6Mzbmf6izcUNDkWnBBQ6A==",
"dependencies": {
- "@babel/parser": "^7.23.0",
- "@vue/shared": "3.3.8",
+ "@babel/parser": "^7.23.5",
+ "@vue/shared": "3.3.13",
"estree-walker": "^2.0.2",
"source-map-js": "^1.0.2"
}
},
"node_modules/@vue/compiler-dom": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz",
- "integrity": "sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.13.tgz",
+ "integrity": "sha512-EYRDpbLadGtNL0Gph+HoKiYqXLqZ0xSSpR5Dvnu/Ep7ggaCbjRDIus1MMxTS2Qm0koXED4xSlvTZaTnI8cYAsw==",
"dependencies": {
- "@vue/compiler-core": "3.3.8",
- "@vue/shared": "3.3.8"
+ "@vue/compiler-core": "3.3.13",
+ "@vue/shared": "3.3.13"
}
},
"node_modules/@vue/compiler-sfc": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz",
- "integrity": "sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.13.tgz",
+ "integrity": "sha512-DQVmHEy/EKIgggvnGRLx21hSqnr1smUS9Aq8tfxiiot8UR0/pXKHN9k78/qQ7etyQTFj5em5nruODON7dBeumw==",
"dependencies": {
- "@babel/parser": "^7.23.0",
- "@vue/compiler-core": "3.3.8",
- "@vue/compiler-dom": "3.3.8",
- "@vue/compiler-ssr": "3.3.8",
- "@vue/reactivity-transform": "3.3.8",
- "@vue/shared": "3.3.8",
+ "@babel/parser": "^7.23.5",
+ "@vue/compiler-core": "3.3.13",
+ "@vue/compiler-dom": "3.3.13",
+ "@vue/compiler-ssr": "3.3.13",
+ "@vue/reactivity-transform": "3.3.13",
+ "@vue/shared": "3.3.13",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.5",
- "postcss": "^8.4.31",
+ "postcss": "^8.4.32",
"source-map-js": "^1.0.2"
}
},
@@ -2346,30 +2496,30 @@
}
},
"node_modules/@vue/compiler-ssr": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz",
- "integrity": "sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.13.tgz",
+ "integrity": "sha512-d/P3bCeUGmkJNS1QUZSAvoCIW4fkOKK3l2deE7zrp0ypJEy+En2AcypIkqvcFQOcw3F0zt2VfMvNsA9JmExTaw==",
"dependencies": {
- "@vue/compiler-dom": "3.3.8",
- "@vue/shared": "3.3.8"
+ "@vue/compiler-dom": "3.3.13",
+ "@vue/shared": "3.3.13"
}
},
"node_modules/@vue/reactivity": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.8.tgz",
- "integrity": "sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.13.tgz",
+ "integrity": "sha512-fjzCxceMahHhi4AxUBzQqqVhuA21RJ0COaWTbIBl1PruGW1CeY97louZzLi4smpYx+CHfFPPU/CS8NybbGvPKQ==",
"dependencies": {
- "@vue/shared": "3.3.8"
+ "@vue/shared": "3.3.13"
}
},
"node_modules/@vue/reactivity-transform": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz",
- "integrity": "sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.13.tgz",
+ "integrity": "sha512-oWnydGH0bBauhXvh5KXUy61xr9gKaMbtsMHk40IK9M4gMuKPJ342tKFarY0eQ6jef8906m35q37wwA8DMZOm5Q==",
"dependencies": {
- "@babel/parser": "^7.23.0",
- "@vue/compiler-core": "3.3.8",
- "@vue/shared": "3.3.8",
+ "@babel/parser": "^7.23.5",
+ "@vue/compiler-core": "3.3.13",
+ "@vue/shared": "3.3.13",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.5"
}
@@ -2386,40 +2536,40 @@
}
},
"node_modules/@vue/runtime-core": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.8.tgz",
- "integrity": "sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.13.tgz",
+ "integrity": "sha512-1TzA5TvGuh2zUwMJgdfvrBABWZ7y8kBwBhm7BXk8rvdx2SsgcGfz2ruv2GzuGZNvL1aKnK8CQMV/jFOrxNQUMA==",
"dependencies": {
- "@vue/reactivity": "3.3.8",
- "@vue/shared": "3.3.8"
+ "@vue/reactivity": "3.3.13",
+ "@vue/shared": "3.3.13"
}
},
"node_modules/@vue/runtime-dom": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz",
- "integrity": "sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.13.tgz",
+ "integrity": "sha512-JJkpE8R/hJKXqVTgUoODwS5wqKtOsmJPEqmp90PDVGygtJ4C0PtOkcEYXwhiVEmef6xeXcIlrT3Yo5aQ4qkHhQ==",
"dependencies": {
- "@vue/runtime-core": "3.3.8",
- "@vue/shared": "3.3.8",
- "csstype": "^3.1.2"
+ "@vue/runtime-core": "3.3.13",
+ "@vue/shared": "3.3.13",
+ "csstype": "^3.1.3"
}
},
"node_modules/@vue/server-renderer": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.8.tgz",
- "integrity": "sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.13.tgz",
+ "integrity": "sha512-vSnN+nuf6iSqTL3Qgx/9A+BT+0Zf/VJOgF5uMZrKjYPs38GMYyAU1coDyBNHauehXDaP+zl73VhwWv0vBRBHcg==",
"dependencies": {
- "@vue/compiler-ssr": "3.3.8",
- "@vue/shared": "3.3.8"
+ "@vue/compiler-ssr": "3.3.13",
+ "@vue/shared": "3.3.13"
},
"peerDependencies": {
- "vue": "3.3.8"
+ "vue": "3.3.13"
}
},
"node_modules/@vue/shared": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz",
- "integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw=="
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.13.tgz",
+ "integrity": "sha512-/zYUwiHD8j7gKx2argXEMCUXVST6q/21DFU0sTfNX0URJroCe3b1UF6vLJ3lQDfLNIiiRl2ONp7Nh5UVWS6QnA=="
},
"node_modules/@webassemblyjs/ast": {
"version": "1.11.6",
@@ -2608,12 +2758,6 @@
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
},
- "node_modules/abab": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
- "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
- "dev": true
- },
"node_modules/abort-controller": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
@@ -2678,15 +2822,15 @@
}
},
"node_modules/agent-base": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz",
+ "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==",
"dev": true,
"dependencies": {
- "debug": "4"
+ "debug": "^4.3.4"
},
"engines": {
- "node": ">= 6.0.0"
+ "node": ">= 14"
}
},
"node_modules/ajv": {
@@ -3625,9 +3769,9 @@
}
},
"node_modules/csstype": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
- "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/cytoscape": {
"version": "3.27.0",
@@ -4105,17 +4249,16 @@
"dev": true
},
"node_modules/data-urls": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
- "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+ "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
"dev": true,
"dependencies": {
- "abab": "^2.0.6",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.0"
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
}
},
"node_modules/dayjs": {
@@ -4394,18 +4537,6 @@
}
]
},
- "node_modules/domexception": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
- "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
- "dev": true,
- "dependencies": {
- "webidl-conversions": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
@@ -4739,15 +4870,15 @@
}
},
"node_modules/eslint": {
- "version": "8.54.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
- "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
+ "version": "8.56.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
+ "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.3",
- "@eslint/js": "8.54.0",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.56.0",
"@humanwhocodes/config-array": "^0.11.13",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@@ -4793,6 +4924,18 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/eslint-compat-utils": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz",
+ "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "eslint": ">=6.0.0"
+ }
+ },
"node_modules/eslint-import-resolver-node": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
@@ -4852,20 +4995,19 @@
}
},
"node_modules/eslint-plugin-i": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-i/-/eslint-plugin-i-2.29.0.tgz",
- "integrity": "sha512-slGeTS3GQzx9267wLJnNYNO8X9EHGsc75AKIAFvnvMYEcTJKotPKL1Ru5PIGVHIVet+2DsugePWp8Oxpx8G22w==",
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-i/-/eslint-plugin-i-2.29.1.tgz",
+ "integrity": "sha512-ORizX37MelIWLbMyqI7hi8VJMf7A0CskMmYkB+lkCX3aF4pkGV7kwx5bSEb4qx7Yce2rAf9s34HqDRPjGRZPNQ==",
"dev": true,
"dependencies": {
- "debug": "^3.2.7",
- "doctrine": "^2.1.0",
+ "debug": "^4.3.4",
+ "doctrine": "^3.0.0",
"eslint-import-resolver-node": "^0.3.9",
"eslint-module-utils": "^2.8.0",
- "get-tsconfig": "^4.6.2",
+ "get-tsconfig": "^4.7.2",
"is-glob": "^4.0.3",
"minimatch": "^3.1.2",
- "resolve": "^1.22.3",
- "semver": "^7.5.3"
+ "semver": "^7.5.4"
},
"engines": {
"node": ">=12"
@@ -4887,27 +5029,6 @@
"concat-map": "0.0.1"
}
},
- "node_modules/eslint-plugin-i/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-i/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/eslint-plugin-i/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -4954,9 +5075,9 @@
}
},
"node_modules/eslint-plugin-regexp": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.1.1.tgz",
- "integrity": "sha512-FGa/idrL5tzMCnGylyx8DCWTX3vDuEtE/CVqTx+yYwe5qY3JRppbNVkOVGIkQF0klVlrG+LxwAXRXTUr5yU5uA==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-2.1.2.tgz",
+ "integrity": "sha512-nnhNqHblaD8YTJiEHfyVRhiw8sm0eFQ9h+ee3rMqJhf2R9sJWbSXkjrLxIeCNZSNqitUOdaYFfrPVyvS9i72AA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
@@ -5018,15 +5139,15 @@
}
},
"node_modules/eslint-plugin-vitest": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.3.9.tgz",
- "integrity": "sha512-ZGrz8dWFlotM5dwrsMLP4VcY5MizwKNV4JTnY0VKdnuCZ+qeEUMHf1qd8kRGQA3tqLvXcV929wt2ANkduq2Pgw==",
+ "version": "0.3.18",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vitest/-/eslint-plugin-vitest-0.3.18.tgz",
+ "integrity": "sha512-IJzs6BpA//wkNxo5845uPIMOIp4j76MiKiagJ3hD6a2DemrktdpB7mmTjU0EeFuq14NXFoO1wN8Fwrx2VxWBRA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/utils": "^6.9.1"
+ "@typescript-eslint/utils": "^6.14.0"
},
"engines": {
- "node": "14.x || >= 16"
+ "node": "^18.0.0 || >= 20.0.0"
},
"peerDependencies": {
"eslint": ">=8.0.0",
@@ -5048,9 +5169,9 @@
"dev": true
},
"node_modules/eslint-plugin-vue": {
- "version": "9.18.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.18.1.tgz",
- "integrity": "sha512-7hZFlrEgg9NIzuVik2I9xSnJA5RsmOfueYgsUGUokEDLJ1LHtxO0Pl4duje1BriZ/jDWb+44tcIlC3yi0tdlZg==",
+ "version": "9.19.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.19.2.tgz",
+ "integrity": "sha512-CPDqTOG2K4Ni2o4J5wixkLVNwgctKXFu6oBpVJlpNq7f38lh9I80pRTouZSJ2MAebPJlINU/KTFSXyQfBUlymA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
@@ -5069,12 +5190,13 @@
}
},
"node_modules/eslint-plugin-vue-scoped-css": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-vue-scoped-css/-/eslint-plugin-vue-scoped-css-2.5.1.tgz",
- "integrity": "sha512-ynbeCHd0dzkUBoL1q10GNpGh/BZD0Frw8Z8txPFyuhiHN2m5ZT6gvfe2GtdEs0Rq3+NE+5yexfz0PDX/bgKuJw==",
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-vue-scoped-css/-/eslint-plugin-vue-scoped-css-2.6.1.tgz",
+ "integrity": "sha512-wz2jF+KgAGQFDncZ8k+0F47SY/FS/xVMD6iwuPsFlFER9490KOtNYfSOacwPq2peemUdBuLkzsQKjvTGG7Pq+Q==",
"dev": true,
"dependencies": {
- "eslint-utils": "^3.0.0",
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "eslint-compat-utils": "^0.1.2",
"lodash": "^4.17.21",
"postcss": "^8.4.31",
"postcss-safe-parser": "^6.0.0",
@@ -5122,33 +5244,6 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^2.0.0"
- },
- "engines": {
- "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/mysticatea"
- },
- "peerDependencies": {
- "eslint": ">=5"
- }
- },
- "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
- "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
- "dev": true,
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/eslint-visitor-keys": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
@@ -5284,6 +5379,29 @@
"node": ">=0.8.x"
}
},
+ "node_modules/execa": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+ "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^8.0.1",
+ "human-signals": "^5.0.0",
+ "is-stream": "^3.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^5.1.0",
+ "onetime": "^6.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.17"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5649,6 +5767,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/get-stream": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
+ "dev": true,
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-symbol-description": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
@@ -5777,9 +5907,9 @@
}
},
"node_modules/globals": {
- "version": "13.23.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
- "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -5974,15 +6104,15 @@
}
},
"node_modules/html-encoding-sniffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
- "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
"dev": true,
"dependencies": {
- "whatwg-encoding": "^2.0.0"
+ "whatwg-encoding": "^3.1.1"
},
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/html-tags": {
@@ -6029,30 +6159,38 @@
}
},
"node_modules/http-proxy-agent": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
- "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz",
+ "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==",
"dev": true,
"dependencies": {
- "@tootallnate/once": "2",
- "agent-base": "6",
- "debug": "4"
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
},
"engines": {
- "node": ">= 6"
+ "node": ">= 14"
}
},
"node_modules/https-proxy-agent": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
- "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==",
"dev": true,
"dependencies": {
- "agent-base": "6",
+ "agent-base": "^7.0.2",
"debug": "4"
},
"engines": {
- "node": ">= 6"
+ "node": ">= 14"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+ "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=16.17.0"
}
},
"node_modules/iconv-lite": {
@@ -6097,9 +6235,9 @@
]
},
"node_modules/ignore": {
- "version": "5.2.4",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
- "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
+ "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
"dev": true,
"engines": {
"node": ">= 4"
@@ -6501,6 +6639,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/is-string": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
@@ -6678,40 +6828,38 @@
}
},
"node_modules/jsdom": {
- "version": "22.1.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
- "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
+ "version": "23.0.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz",
+ "integrity": "sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==",
"dev": true,
"dependencies": {
- "abab": "^2.0.6",
"cssstyle": "^3.0.0",
- "data-urls": "^4.0.0",
+ "data-urls": "^5.0.0",
"decimal.js": "^10.4.3",
- "domexception": "^4.0.0",
"form-data": "^4.0.0",
- "html-encoding-sniffer": "^3.0.0",
- "http-proxy-agent": "^5.0.0",
- "https-proxy-agent": "^5.0.1",
+ "html-encoding-sniffer": "^4.0.0",
+ "http-proxy-agent": "^7.0.0",
+ "https-proxy-agent": "^7.0.2",
"is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.4",
+ "nwsapi": "^2.2.7",
"parse5": "^7.1.2",
"rrweb-cssom": "^0.6.0",
"saxes": "^6.0.0",
"symbol-tree": "^3.2.4",
- "tough-cookie": "^4.1.2",
- "w3c-xmlserializer": "^4.0.0",
+ "tough-cookie": "^4.1.3",
+ "w3c-xmlserializer": "^5.0.0",
"webidl-conversions": "^7.0.0",
- "whatwg-encoding": "^2.0.0",
- "whatwg-mimetype": "^3.0.0",
- "whatwg-url": "^12.0.1",
- "ws": "^8.13.0",
- "xml-name-validator": "^4.0.0"
+ "whatwg-encoding": "^3.1.1",
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0",
+ "ws": "^8.14.2",
+ "xml-name-validator": "^5.0.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
},
"peerDependencies": {
- "canvas": "^2.5.0"
+ "canvas": "^2.11.2"
},
"peerDependenciesMeta": {
"canvas": {
@@ -6719,6 +6867,15 @@
}
}
},
+ "node_modules/jsdom/node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/jsep": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz",
@@ -7207,10 +7364,14 @@
}
},
"node_modules/local-pkg": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
- "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz",
+ "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==",
"dev": true,
+ "dependencies": {
+ "mlly": "^1.4.2",
+ "pkg-types": "^1.0.3"
+ },
"engines": {
"node": ">=14"
},
@@ -7340,9 +7501,9 @@
}
},
"node_modules/markdown-it": {
- "version": "13.0.1",
- "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
- "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz",
+ "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==",
"dev": true,
"dependencies": {
"argparse": "^2.0.1",
@@ -7356,31 +7517,34 @@
}
},
"node_modules/markdownlint": {
- "version": "0.31.1",
- "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.31.1.tgz",
- "integrity": "sha512-CKMR2hgcIBrYlIUccDCOvi966PZ0kJExDrUi1R+oF9PvqQmCrTqjOsgIvf2403OmJ+CWomuzDoylr6KbuMyvHA==",
+ "version": "0.32.1",
+ "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.32.1.tgz",
+ "integrity": "sha512-3sx9xpi4xlHlokGyHO9k0g3gJbNY4DI6oNEeEYq5gQ4W7UkiJ90VDAnuDl2U+yyXOUa6BX+0gf69ZlTUGIBp6A==",
"dev": true,
"dependencies": {
- "markdown-it": "13.0.1",
+ "markdown-it": "13.0.2",
"markdownlint-micromark": "0.1.7"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/DavidAnson"
}
},
"node_modules/markdownlint-cli": {
- "version": "0.37.0",
- "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.37.0.tgz",
- "integrity": "sha512-hNKAc0bWBBuVhJbSWbUhRzavstiB4o1jh3JeSpwC4/dt6eJ54lRfYHRxVdzVp4qGWBKbeE6Pg490PFEfrKjqSg==",
+ "version": "0.38.0",
+ "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.38.0.tgz",
+ "integrity": "sha512-qkZRKJ4LVq6CJIkRIuJsEHvhWhm+FP0E7yhHvOMrrgdykgFWNYD4wuhZTjvigbJLTKPooP79yPiUDDZBCBI5JA==",
"dev": true,
"dependencies": {
- "commander": "~11.0.0",
+ "commander": "~11.1.0",
"get-stdin": "~9.0.0",
- "glob": "~10.3.4",
- "ignore": "~5.2.4",
+ "glob": "~10.3.10",
+ "ignore": "~5.3.0",
"js-yaml": "^4.1.0",
"jsonc-parser": "~3.2.0",
- "markdownlint": "~0.31.1",
+ "markdownlint": "~0.32.1",
"minimatch": "~9.0.3",
"run-con": "~1.3.2"
},
@@ -7388,13 +7552,13 @@
"markdownlint": "markdownlint.js"
},
"engines": {
- "node": ">=16"
+ "node": ">=18"
}
},
"node_modules/markdownlint-cli/node_modules/commander": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz",
- "integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==",
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
"dev": true,
"engines": {
"node": ">=16"
@@ -8097,6 +8261,18 @@
"node": ">= 0.6"
}
},
+ "node_modules/mimic-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -8183,9 +8359,9 @@
}
},
"node_modules/monaco-editor": {
- "version": "0.44.0",
- "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz",
- "integrity": "sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q=="
+ "version": "0.45.0",
+ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.45.0.tgz",
+ "integrity": "sha512-mjv1G1ZzfEE3k9HZN0dQ2olMdwIfaeAAjFiwNprLfYNRSz7ctv9XuCT7gPtBGrMUeV1/iZzYKj17Khu1hxoHOA=="
},
"node_modules/monaco-editor-webpack-plugin": {
"version": "7.1.0",
@@ -8218,9 +8394,9 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/nanoid": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
- "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+ "version": "3.3.7",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
+ "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"funding": [
{
"type": "github",
@@ -8365,6 +8541,33 @@
"node": ">=0.10.0"
}
},
+ "node_modules/npm-run-path": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
+ "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -8444,6 +8647,21 @@
"wrappy": "1"
}
},
+ "node_modules/onetime": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -8740,12 +8958,12 @@
"dev": true
},
"node_modules/playwright": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.0.tgz",
- "integrity": "sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==",
+ "version": "1.40.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz",
+ "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==",
"dev": true,
"dependencies": {
- "playwright-core": "1.40.0"
+ "playwright-core": "1.40.1"
},
"bin": {
"playwright": "cli.js"
@@ -8758,9 +8976,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.40.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.0.tgz",
- "integrity": "sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==",
+ "version": "1.40.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz",
+ "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -8788,9 +9006,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.31",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
- "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "version": "8.4.32",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
+ "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
"funding": [
{
"type": "opencollective",
@@ -8806,7 +9024,7 @@
}
],
"dependencies": {
- "nanoid": "^3.3.6",
+ "nanoid": "^3.3.7",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@@ -9819,9 +10037,9 @@
}
},
"node_modules/sortablejs": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
- "integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w=="
+ "version": "1.15.1",
+ "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.1.tgz",
+ "integrity": "sha512-P5Cjvb0UG1ZVNiDPj/n4V+DinttXG6K8n7vM/HQf0C25K3YKQTQY6fsr/sEGsJGpQ9exmPxluHxKBc0mLKU1lQ=="
},
"node_modules/source-list-map": {
"version": "2.0.1",
@@ -9950,9 +10168,9 @@
}
},
"node_modules/std-env": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz",
- "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==",
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.6.0.tgz",
+ "integrity": "sha512-aFZ19IgVmhdB2uX599ve2kE6BIE3YMnQ6Gp6BURhW/oIzpXGKr878TQfAQZn1+i0Flcc/UKUy1gOlcfaUBCryg==",
"dev": true
},
"node_modules/string-width": {
@@ -10052,6 +10270,18 @@
"node": ">=8"
}
},
+ "node_modules/strip-final-newline": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
@@ -10301,9 +10531,9 @@
"dev": true
},
"node_modules/svgo": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.4.tgz",
- "integrity": "sha512-T+Xul3JwuJ6VGXKo/p2ndqx1ibxNKnLTvRc1ZTWKCfyKS/GgNjRZcYsK84fxTsy/izr91g/Rwx6fGnVgaFSI5g==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.1.0.tgz",
+ "integrity": "sha512-R5SnNA89w1dYgNv570591F66v34b3eQShpIBcQtZtM5trJwm1VvxbIoMpRYY3ybTAutcKTLEmTsdnaknOHbiQA==",
"dev": true,
"dependencies": {
"@trysound/sax": "0.2.0",
@@ -10335,9 +10565,9 @@
}
},
"node_modules/swagger-ui-dist": {
- "version": "5.10.0",
- "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.10.0.tgz",
- "integrity": "sha512-PBTn5qDOQVtU29hrx74km86SnK3/mFtF3grI98y575y1aRpxiuStRTIvsfXFudPFkLofHU7H9a+fKrP+Oayc3g=="
+ "version": "5.10.5",
+ "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.10.5.tgz",
+ "integrity": "sha512-Uv8E7hV/nXALQKgW86X1i58gl1O6DFg+Uq54sDwhYqucBBxj/47dLNw872TNILNlOTuPA6dRvUMGQdmlpaX8qQ=="
},
"node_modules/symbol-tree": {
"version": "3.2.4",
@@ -10507,9 +10737,9 @@
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
},
"node_modules/tinypool": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz",
- "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==",
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.1.tgz",
+ "integrity": "sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg==",
"dev": true,
"engines": {
"node": ">=14.0.0"
@@ -10573,15 +10803,15 @@
}
},
"node_modules/tr46": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
- "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
"dev": true,
"dependencies": {
- "punycode": "^2.3.0"
+ "punycode": "^2.3.1"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
}
},
"node_modules/tributejs": {
@@ -10751,9 +10981,9 @@
"dev": true
},
"node_modules/ufo": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz",
- "integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==",
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz",
+ "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==",
"dev": true
},
"node_modules/uint8-to-base64": {
@@ -10930,29 +11160,29 @@
}
},
"node_modules/vite": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz",
- "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==",
+ "version": "5.0.10",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.10.tgz",
+ "integrity": "sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==",
"dev": true,
"dependencies": {
- "esbuild": "^0.18.10",
- "postcss": "^8.4.27",
- "rollup": "^3.27.1"
+ "esbuild": "^0.19.3",
+ "postcss": "^8.4.32",
+ "rollup": "^4.2.0"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
- "node": "^14.18.0 || >=16.0.0"
+ "node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://github.com/vitejs/vite?sponsor=1"
},
"optionalDependencies": {
- "fsevents": "~2.3.2"
+ "fsevents": "~2.3.3"
},
"peerDependencies": {
- "@types/node": ">= 14",
+ "@types/node": "^18.0.0 || >=20.0.0",
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
@@ -10985,23 +11215,22 @@
}
},
"node_modules/vite-node": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz",
- "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.1.0.tgz",
+ "integrity": "sha512-jV48DDUxGLEBdHCQvxL1mEh7+naVy+nhUUUaPAZLd3FJgXuxQiewHcfeZebbJ6onDqNGkP4r3MhQ342PRlG81Q==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.3.4",
- "mlly": "^1.4.0",
"pathe": "^1.1.1",
"picocolors": "^1.0.0",
- "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0"
+ "vite": "^5.0.0"
},
"bin": {
"vite-node": "vite-node.mjs"
},
"engines": {
- "node": ">=v14.18.0"
+ "node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
@@ -11016,465 +11245,101 @@
"node": ">=16"
}
},
- "node_modules/vite/node_modules/@esbuild/android-arm": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
- "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/android-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
- "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/android-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
- "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "android"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/darwin-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
- "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/darwin-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
- "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/freebsd-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
- "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/freebsd-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
- "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "freebsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-arm": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
- "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
- "cpu": [
- "arm"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
- "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-ia32": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
- "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-loong64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
- "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
- "cpu": [
- "loong64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-mips64el": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
- "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
- "cpu": [
- "mips64el"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-ppc64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
- "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
- "cpu": [
- "ppc64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-riscv64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
- "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
- "cpu": [
- "riscv64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-s390x": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
- "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
- "cpu": [
- "s390x"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/linux-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
- "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/netbsd-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
- "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "netbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/openbsd-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
- "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "openbsd"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/sunos-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
- "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "sunos"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/win32-arm64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
- "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
- "cpu": [
- "arm64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/win32-ia32": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
- "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
- "cpu": [
- "ia32"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/@esbuild/win32-x64": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
- "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
- "cpu": [
- "x64"
- ],
- "dev": true,
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/vite/node_modules/esbuild": {
- "version": "0.18.20",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
- "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+ "node_modules/vite/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
- "bin": {
- "esbuild": "bin/esbuild"
- },
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=12"
- },
- "optionalDependencies": {
- "@esbuild/android-arm": "0.18.20",
- "@esbuild/android-arm64": "0.18.20",
- "@esbuild/android-x64": "0.18.20",
- "@esbuild/darwin-arm64": "0.18.20",
- "@esbuild/darwin-x64": "0.18.20",
- "@esbuild/freebsd-arm64": "0.18.20",
- "@esbuild/freebsd-x64": "0.18.20",
- "@esbuild/linux-arm": "0.18.20",
- "@esbuild/linux-arm64": "0.18.20",
- "@esbuild/linux-ia32": "0.18.20",
- "@esbuild/linux-loong64": "0.18.20",
- "@esbuild/linux-mips64el": "0.18.20",
- "@esbuild/linux-ppc64": "0.18.20",
- "@esbuild/linux-riscv64": "0.18.20",
- "@esbuild/linux-s390x": "0.18.20",
- "@esbuild/linux-x64": "0.18.20",
- "@esbuild/netbsd-x64": "0.18.20",
- "@esbuild/openbsd-x64": "0.18.20",
- "@esbuild/sunos-x64": "0.18.20",
- "@esbuild/win32-arm64": "0.18.20",
- "@esbuild/win32-ia32": "0.18.20",
- "@esbuild/win32-x64": "0.18.20"
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/vite/node_modules/rollup": {
- "version": "3.29.4",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
- "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
+ "version": "4.9.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz",
+ "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
- "node": ">=14.18.0",
+ "node": ">=18.0.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.9.1",
+ "@rollup/rollup-android-arm64": "4.9.1",
+ "@rollup/rollup-darwin-arm64": "4.9.1",
+ "@rollup/rollup-darwin-x64": "4.9.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.9.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.9.1",
+ "@rollup/rollup-linux-arm64-musl": "4.9.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.9.1",
+ "@rollup/rollup-linux-x64-gnu": "4.9.1",
+ "@rollup/rollup-linux-x64-musl": "4.9.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.9.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.9.1",
+ "@rollup/rollup-win32-x64-msvc": "4.9.1",
"fsevents": "~2.3.2"
}
},
"node_modules/vitest": {
- "version": "0.34.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz",
- "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.1.0.tgz",
+ "integrity": "sha512-oDFiCrw7dd3Jf06HoMtSRARivvyjHJaTxikFxuqJjO76U436PqlVw1uLn7a8OSPrhSfMGVaRakKpA2lePdw79A==",
"dev": true,
"dependencies": {
- "@types/chai": "^4.3.5",
- "@types/chai-subset": "^1.3.3",
- "@types/node": "*",
- "@vitest/expect": "0.34.6",
- "@vitest/runner": "0.34.6",
- "@vitest/snapshot": "0.34.6",
- "@vitest/spy": "0.34.6",
- "@vitest/utils": "0.34.6",
- "acorn": "^8.9.0",
- "acorn-walk": "^8.2.0",
+ "@vitest/expect": "1.1.0",
+ "@vitest/runner": "1.1.0",
+ "@vitest/snapshot": "1.1.0",
+ "@vitest/spy": "1.1.0",
+ "@vitest/utils": "1.1.0",
+ "acorn-walk": "^8.3.0",
"cac": "^6.7.14",
"chai": "^4.3.10",
"debug": "^4.3.4",
- "local-pkg": "^0.4.3",
- "magic-string": "^0.30.1",
+ "execa": "^8.0.1",
+ "local-pkg": "^0.5.0",
+ "magic-string": "^0.30.5",
"pathe": "^1.1.1",
"picocolors": "^1.0.0",
- "std-env": "^3.3.3",
- "strip-literal": "^1.0.1",
- "tinybench": "^2.5.0",
- "tinypool": "^0.7.0",
- "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0",
- "vite-node": "0.34.6",
+ "std-env": "^3.5.0",
+ "strip-literal": "^1.3.0",
+ "tinybench": "^2.5.1",
+ "tinypool": "^0.8.1",
+ "vite": "^5.0.0",
+ "vite-node": "1.1.0",
"why-is-node-running": "^2.2.2"
},
"bin": {
"vitest": "vitest.mjs"
},
"engines": {
- "node": ">=v14.18.0"
+ "node": "^18.0.0 || >=20.0.0"
},
"funding": {
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
"@edge-runtime/vm": "*",
- "@vitest/browser": "*",
- "@vitest/ui": "*",
+ "@types/node": "^18.0.0 || >=20.0.0",
+ "@vitest/browser": "^1.0.0",
+ "@vitest/ui": "^1.0.0",
"happy-dom": "*",
- "jsdom": "*",
- "playwright": "*",
- "safaridriver": "*",
- "webdriverio": "*"
+ "jsdom": "*"
},
"peerDependenciesMeta": {
"@edge-runtime/vm": {
"optional": true
},
+ "@types/node": {
+ "optional": true
+ },
"@vitest/browser": {
"optional": true
},
@@ -11486,15 +11351,6 @@
},
"jsdom": {
"optional": true
- },
- "playwright": {
- "optional": true
- },
- "safaridriver": {
- "optional": true
- },
- "webdriverio": {
- "optional": true
}
}
},
@@ -11511,15 +11367,15 @@
}
},
"node_modules/vue": {
- "version": "3.3.8",
- "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.8.tgz",
- "integrity": "sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==",
+ "version": "3.3.13",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.13.tgz",
+ "integrity": "sha512-LDnUpQvDgsfc0u/YgtAgTMXJlJQqjkxW1PVcOnJA5cshPleULDjHi7U45pl2VJYazSSvLH8UKcid/kzH8I0a0Q==",
"dependencies": {
- "@vue/compiler-dom": "3.3.8",
- "@vue/compiler-sfc": "3.3.8",
- "@vue/runtime-dom": "3.3.8",
- "@vue/server-renderer": "3.3.8",
- "@vue/shared": "3.3.8"
+ "@vue/compiler-dom": "3.3.13",
+ "@vue/compiler-sfc": "3.3.13",
+ "@vue/runtime-dom": "3.3.13",
+ "@vue/server-renderer": "3.3.13",
+ "@vue/shared": "3.3.13"
},
"peerDependencies": {
"typescript": "*"
@@ -11597,15 +11453,24 @@
}
},
"node_modules/w3c-xmlserializer": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
- "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
"dev": true,
"dependencies": {
- "xml-name-validator": "^4.0.0"
+ "xml-name-validator": "^5.0.0"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
+ }
+ },
+ "node_modules/w3c-xmlserializer/node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
}
},
"node_modules/watchpack": {
@@ -11833,37 +11698,37 @@
}
},
"node_modules/whatwg-encoding": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
- "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
"dev": true,
"dependencies": {
"iconv-lite": "0.6.3"
},
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/whatwg-mimetype": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
- "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
"dev": true,
"engines": {
- "node": ">=12"
+ "node": ">=18"
}
},
"node_modules/whatwg-url": {
- "version": "12.0.1",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
- "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
"dev": true,
"dependencies": {
- "tr46": "^4.1.1",
+ "tr46": "^5.0.0",
"webidl-conversions": "^7.0.0"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
}
},
"node_modules/which": {
diff --git a/package.json b/package.json
index 4aee1bb049..801e85db83 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"@citation-js/plugin-software-formats": "0.6.1",
"@claviska/jquery-minicolors": "2.3.6",
"@github/markdown-toolbar-element": "2.2.1",
- "@github/relative-time-element": "4.3.0",
+ "@github/relative-time-element": "4.3.1",
"@github/text-expander-element": "2.6.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.8.0",
@@ -32,19 +32,19 @@
"mermaid": "10.6.1",
"mini-css-extract-plugin": "2.7.6",
"minimatch": "9.0.3",
- "monaco-editor": "0.44.0",
+ "monaco-editor": "0.45.0",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.2.12",
"pretty-ms": "8.0.0",
- "sortablejs": "1.15.0",
- "swagger-ui-dist": "5.10.0",
+ "sortablejs": "1.15.1",
+ "swagger-ui-dist": "5.10.5",
"throttle-debounce": "5.0.0",
"tinycolor2": "1.6.0",
"tippy.js": "6.3.7",
"toastify-js": "1.12.0",
"tributejs": "5.1.3",
"uint8-to-base64": "0.2.0",
- "vue": "3.3.8",
+ "vue": "3.3.13",
"vue-bar-graph": "2.0.0",
"vue-loader": "17.3.1",
"vue3-calendar-heatmap": "2.0.5",
@@ -54,35 +54,35 @@
},
"devDependencies": {
"@eslint-community/eslint-plugin-eslint-comments": "4.1.0",
- "@playwright/test": "1.40.0",
+ "@playwright/test": "1.40.1",
"@stoplight/spectral-cli": "6.11.0",
- "@stylistic/eslint-plugin-js": "1.4.0",
- "@vitejs/plugin-vue": "4.5.0",
- "eslint": "8.54.0",
+ "@stylistic/eslint-plugin-js": "1.5.1",
+ "@vitejs/plugin-vue": "4.5.2",
+ "eslint": "8.56.0",
"eslint-plugin-array-func": "4.0.0",
- "eslint-plugin-i": "2.29.0",
+ "eslint-plugin-i": "2.29.1",
"eslint-plugin-jquery": "1.5.1",
"eslint-plugin-no-jquery": "2.7.0",
"eslint-plugin-no-use-extend-native": "0.5.0",
- "eslint-plugin-regexp": "2.1.1",
+ "eslint-plugin-regexp": "2.1.2",
"eslint-plugin-sonarjs": "0.23.0",
"eslint-plugin-unicorn": "49.0.0",
- "eslint-plugin-vitest": "0.3.9",
+ "eslint-plugin-vitest": "0.3.18",
"eslint-plugin-vitest-globals": "1.4.0",
- "eslint-plugin-vue": "9.18.1",
- "eslint-plugin-vue-scoped-css": "2.5.1",
+ "eslint-plugin-vue": "9.19.2",
+ "eslint-plugin-vue-scoped-css": "2.6.1",
"eslint-plugin-wc": "2.0.4",
- "jsdom": "22.1.0",
- "markdownlint-cli": "0.37.0",
+ "jsdom": "23.0.1",
+ "markdownlint-cli": "0.38.0",
"postcss-html": "1.5.0",
"stylelint": "15.11.0",
"stylelint-declaration-block-no-ignored-properties": "2.7.0",
"stylelint-declaration-strict-value": "1.9.2",
"stylelint-stylistic": "0.4.3",
- "svgo": "3.0.4",
+ "svgo": "3.1.0",
"updates": "15.0.4",
"vite-string-plugin": "1.1.2",
- "vitest": "0.34.6"
+ "vitest": "1.1.0"
},
"browserslist": [
"defaults",
diff --git a/public/assets/img/svg/gitea-azuread.svg b/public/assets/img/svg/gitea-azuread.svg
index 1aee2aa40d..2bef0f7b4e 100644
--- a/public/assets/img/svg/gitea-azuread.svg
+++ b/public/assets/img/svg/gitea-azuread.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-azureadv2.svg b/public/assets/img/svg/gitea-azureadv2.svg
index 3d4af13e51..e8ffdf0765 100644
--- a/public/assets/img/svg/gitea-azureadv2.svg
+++ b/public/assets/img/svg/gitea-azureadv2.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-bitbucket.svg b/public/assets/img/svg/gitea-bitbucket.svg
index 1443f378d5..9f831012b7 100644
--- a/public/assets/img/svg/gitea-bitbucket.svg
+++ b/public/assets/img/svg/gitea-bitbucket.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-cargo.svg b/public/assets/img/svg/gitea-cargo.svg
index 1b720b1dac..c479710569 100644
--- a/public/assets/img/svg/gitea-cargo.svg
+++ b/public/assets/img/svg/gitea-cargo.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-chef.svg b/public/assets/img/svg/gitea-chef.svg
index 0ec6916eef..c5e8a721cc 100644
--- a/public/assets/img/svg/gitea-chef.svg
+++ b/public/assets/img/svg/gitea-chef.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-codebase.svg b/public/assets/img/svg/gitea-codebase.svg
index 5f3085f58c..b92a78e404 100644
--- a/public/assets/img/svg/gitea-codebase.svg
+++ b/public/assets/img/svg/gitea-codebase.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-composer.svg b/public/assets/img/svg/gitea-composer.svg
index aa311993c3..074e096206 100644
--- a/public/assets/img/svg/gitea-composer.svg
+++ b/public/assets/img/svg/gitea-composer.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-conan.svg b/public/assets/img/svg/gitea-conan.svg
index f1857c7f20..bc09314495 100644
--- a/public/assets/img/svg/gitea-conan.svg
+++ b/public/assets/img/svg/gitea-conan.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-cran.svg b/public/assets/img/svg/gitea-cran.svg
index b3b3e312bc..18502bf7c9 100644
--- a/public/assets/img/svg/gitea-cran.svg
+++ b/public/assets/img/svg/gitea-cran.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-debian.svg b/public/assets/img/svg/gitea-debian.svg
index 2471f35776..6894986613 100644
--- a/public/assets/img/svg/gitea-debian.svg
+++ b/public/assets/img/svg/gitea-debian.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-gitbucket.svg b/public/assets/img/svg/gitea-gitbucket.svg
index 4c0ef46d92..1a29b55d31 100644
--- a/public/assets/img/svg/gitea-gitbucket.svg
+++ b/public/assets/img/svg/gitea-gitbucket.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-gitea.svg b/public/assets/img/svg/gitea-gitea.svg
index 6574fbce5e..cb4d9615e6 100644
--- a/public/assets/img/svg/gitea-gitea.svg
+++ b/public/assets/img/svg/gitea-gitea.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-gitlab.svg b/public/assets/img/svg/gitea-gitlab.svg
index 742370ac9a..837ec4b016 100644
--- a/public/assets/img/svg/gitea-gitlab.svg
+++ b/public/assets/img/svg/gitea-gitlab.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-lock-cog.svg b/public/assets/img/svg/gitea-lock-cog.svg
index 7775b35f6d..f2985477d9 100644
--- a/public/assets/img/svg/gitea-lock-cog.svg
+++ b/public/assets/img/svg/gitea-lock-cog.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-mastodon.svg b/public/assets/img/svg/gitea-mastodon.svg
index 3511f097c9..c6119902d2 100644
--- a/public/assets/img/svg/gitea-mastodon.svg
+++ b/public/assets/img/svg/gitea-mastodon.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-matrix.svg b/public/assets/img/svg/gitea-matrix.svg
index 16023b0cae..877e510467 100644
--- a/public/assets/img/svg/gitea-matrix.svg
+++ b/public/assets/img/svg/gitea-matrix.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-maven.svg b/public/assets/img/svg/gitea-maven.svg
index 8f88991881..2a61adbff0 100644
--- a/public/assets/img/svg/gitea-maven.svg
+++ b/public/assets/img/svg/gitea-maven.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-onedev.svg b/public/assets/img/svg/gitea-onedev.svg
index 956aa2c9a9..94ad1bab31 100644
--- a/public/assets/img/svg/gitea-onedev.svg
+++ b/public/assets/img/svg/gitea-onedev.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-openid.svg b/public/assets/img/svg/gitea-openid.svg
index a7d2237605..9068f0b0e1 100644
--- a/public/assets/img/svg/gitea-openid.svg
+++ b/public/assets/img/svg/gitea-openid.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-rubygems.svg b/public/assets/img/svg/gitea-rubygems.svg
index 4741b37a7d..4e43bdf2f4 100644
--- a/public/assets/img/svg/gitea-rubygems.svg
+++ b/public/assets/img/svg/gitea-rubygems.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-split.svg b/public/assets/img/svg/gitea-split.svg
index 56b2ff193d..9ce3077a96 100644
--- a/public/assets/img/svg/gitea-split.svg
+++ b/public/assets/img/svg/gitea-split.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-swift.svg b/public/assets/img/svg/gitea-swift.svg
index 6e93083b53..c1429cd89e 100644
--- a/public/assets/img/svg/gitea-swift.svg
+++ b/public/assets/img/svg/gitea-swift.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-vscode.svg b/public/assets/img/svg/gitea-vscode.svg
index 1d36330524..453b9befcc 100644
--- a/public/assets/img/svg/gitea-vscode.svg
+++ b/public/assets/img/svg/gitea-vscode.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/gitea-whitespace.svg b/public/assets/img/svg/gitea-whitespace.svg
index d046d16e0b..9d3b342b3d 100644
--- a/public/assets/img/svg/gitea-whitespace.svg
+++ b/public/assets/img/svg/gitea-whitespace.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-accessibility.svg b/public/assets/img/svg/octicon-accessibility.svg
index e12784f340..8449e03af6 100644
--- a/public/assets/img/svg/octicon-accessibility.svg
+++ b/public/assets/img/svg/octicon-accessibility.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-arrow-down-left.svg b/public/assets/img/svg/octicon-arrow-down-left.svg
index 6001d57767..720f320826 100644
--- a/public/assets/img/svg/octicon-arrow-down-left.svg
+++ b/public/assets/img/svg/octicon-arrow-down-left.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-arrow-down.svg b/public/assets/img/svg/octicon-arrow-down.svg
index 6fb58b2677..d7c13f47cb 100644
--- a/public/assets/img/svg/octicon-arrow-down.svg
+++ b/public/assets/img/svg/octicon-arrow-down.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-arrow-left.svg b/public/assets/img/svg/octicon-arrow-left.svg
index e347e06005..88c6608823 100644
--- a/public/assets/img/svg/octicon-arrow-left.svg
+++ b/public/assets/img/svg/octicon-arrow-left.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-arrow-switch.svg b/public/assets/img/svg/octicon-arrow-switch.svg
index daf1fc001d..8d1bc1d7ac 100644
--- a/public/assets/img/svg/octicon-arrow-switch.svg
+++ b/public/assets/img/svg/octicon-arrow-switch.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-book.svg b/public/assets/img/svg/octicon-book.svg
index ee48f48a84..f979ad9ee8 100644
--- a/public/assets/img/svg/octicon-book.svg
+++ b/public/assets/img/svg/octicon-book.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-bookmark-slash.svg b/public/assets/img/svg/octicon-bookmark-slash.svg
index 79c07ef2a2..781ae92d22 100644
--- a/public/assets/img/svg/octicon-bookmark-slash.svg
+++ b/public/assets/img/svg/octicon-bookmark-slash.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-broadcast.svg b/public/assets/img/svg/octicon-broadcast.svg
index 6d999c43e8..6f076da79a 100644
--- a/public/assets/img/svg/octicon-broadcast.svg
+++ b/public/assets/img/svg/octicon-broadcast.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-bug.svg b/public/assets/img/svg/octicon-bug.svg
index 8245e6cd53..7966d757a7 100644
--- a/public/assets/img/svg/octicon-bug.svg
+++ b/public/assets/img/svg/octicon-bug.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-cache.svg b/public/assets/img/svg/octicon-cache.svg
index c7bb5cfe3f..784f6e290f 100644
--- a/public/assets/img/svg/octicon-cache.svg
+++ b/public/assets/img/svg/octicon-cache.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-checkbox.svg b/public/assets/img/svg/octicon-checkbox.svg
index eebffde2e0..40c782cdff 100644
--- a/public/assets/img/svg/octicon-checkbox.svg
+++ b/public/assets/img/svg/octicon-checkbox.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-checklist.svg b/public/assets/img/svg/octicon-checklist.svg
index 33ab2c3229..172f13a433 100644
--- a/public/assets/img/svg/octicon-checklist.svg
+++ b/public/assets/img/svg/octicon-checklist.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-chevron-down.svg b/public/assets/img/svg/octicon-chevron-down.svg
index 84e71ca4d8..b6d539cb6e 100644
--- a/public/assets/img/svg/octicon-chevron-down.svg
+++ b/public/assets/img/svg/octicon-chevron-down.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-chevron-left.svg b/public/assets/img/svg/octicon-chevron-left.svg
index a56612a7eb..7c259c9696 100644
--- a/public/assets/img/svg/octicon-chevron-left.svg
+++ b/public/assets/img/svg/octicon-chevron-left.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-cloud-offline.svg b/public/assets/img/svg/octicon-cloud-offline.svg
index 5193a54d28..f3621f76a0 100644
--- a/public/assets/img/svg/octicon-cloud-offline.svg
+++ b/public/assets/img/svg/octicon-cloud-offline.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-code-review.svg b/public/assets/img/svg/octicon-code-review.svg
index 595e48eb49..cadf52c350 100644
--- a/public/assets/img/svg/octicon-code-review.svg
+++ b/public/assets/img/svg/octicon-code-review.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-code-square.svg b/public/assets/img/svg/octicon-code-square.svg
index a95ca37e16..89fa9a84d6 100644
--- a/public/assets/img/svg/octicon-code-square.svg
+++ b/public/assets/img/svg/octicon-code-square.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-code.svg b/public/assets/img/svg/octicon-code.svg
index 33c920829d..dc3a376a70 100644
--- a/public/assets/img/svg/octicon-code.svg
+++ b/public/assets/img/svg/octicon-code.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-codescan-checkmark.svg b/public/assets/img/svg/octicon-codescan-checkmark.svg
index 773ad56dbe..dd4c0ca5be 100644
--- a/public/assets/img/svg/octicon-codescan-checkmark.svg
+++ b/public/assets/img/svg/octicon-codescan-checkmark.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-codescan.svg b/public/assets/img/svg/octicon-codescan.svg
index ac4b6b4a18..32e09706c3 100644
--- a/public/assets/img/svg/octicon-codescan.svg
+++ b/public/assets/img/svg/octicon-codescan.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-comment-discussion.svg b/public/assets/img/svg/octicon-comment-discussion.svg
index 7abc3f135f..83a4e568ff 100644
--- a/public/assets/img/svg/octicon-comment-discussion.svg
+++ b/public/assets/img/svg/octicon-comment-discussion.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-container.svg b/public/assets/img/svg/octicon-container.svg
index 2e6056bf41..330e6b3b09 100644
--- a/public/assets/img/svg/octicon-container.svg
+++ b/public/assets/img/svg/octicon-container.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-copilot-error.svg b/public/assets/img/svg/octicon-copilot-error.svg
index caaf0d5ec3..0eb840b48a 100644
--- a/public/assets/img/svg/octicon-copilot-error.svg
+++ b/public/assets/img/svg/octicon-copilot-error.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-copilot-warning.svg b/public/assets/img/svg/octicon-copilot-warning.svg
index e690dfb507..aa54972b4c 100644
--- a/public/assets/img/svg/octicon-copilot-warning.svg
+++ b/public/assets/img/svg/octicon-copilot-warning.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-copilot.svg b/public/assets/img/svg/octicon-copilot.svg
index 83872243cf..f3702590d9 100644
--- a/public/assets/img/svg/octicon-copilot.svg
+++ b/public/assets/img/svg/octicon-copilot.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-database.svg b/public/assets/img/svg/octicon-database.svg
index 03b5de464f..ec3b3eb557 100644
--- a/public/assets/img/svg/octicon-database.svg
+++ b/public/assets/img/svg/octicon-database.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-desktop-download.svg b/public/assets/img/svg/octicon-desktop-download.svg
index 4b1446a18e..917adba7ea 100644
--- a/public/assets/img/svg/octicon-desktop-download.svg
+++ b/public/assets/img/svg/octicon-desktop-download.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-diamond.svg b/public/assets/img/svg/octicon-diamond.svg
index cc30842ce9..82d0bcbcfe 100644
--- a/public/assets/img/svg/octicon-diamond.svg
+++ b/public/assets/img/svg/octicon-diamond.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-diff-ignored.svg b/public/assets/img/svg/octicon-diff-ignored.svg
index 47d59486e5..f11486856e 100644
--- a/public/assets/img/svg/octicon-diff-ignored.svg
+++ b/public/assets/img/svg/octicon-diff-ignored.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-discussion-closed.svg b/public/assets/img/svg/octicon-discussion-closed.svg
index 08c17812d7..af6cbbb39f 100644
--- a/public/assets/img/svg/octicon-discussion-closed.svg
+++ b/public/assets/img/svg/octicon-discussion-closed.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-discussion-duplicate.svg b/public/assets/img/svg/octicon-discussion-duplicate.svg
index ed93bf3b0f..4593169940 100644
--- a/public/assets/img/svg/octicon-discussion-duplicate.svg
+++ b/public/assets/img/svg/octicon-discussion-duplicate.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-discussion-outdated.svg b/public/assets/img/svg/octicon-discussion-outdated.svg
index 388dac3de1..5de43c5657 100644
--- a/public/assets/img/svg/octicon-discussion-outdated.svg
+++ b/public/assets/img/svg/octicon-discussion-outdated.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-download.svg b/public/assets/img/svg/octicon-download.svg
index f5ae4e389d..801817a995 100644
--- a/public/assets/img/svg/octicon-download.svg
+++ b/public/assets/img/svg/octicon-download.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-eye-closed.svg b/public/assets/img/svg/octicon-eye-closed.svg
index 364777d168..a892bca1d1 100644
--- a/public/assets/img/svg/octicon-eye-closed.svg
+++ b/public/assets/img/svg/octicon-eye-closed.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-eye.svg b/public/assets/img/svg/octicon-eye.svg
index 101194041e..0406c53a1a 100644
--- a/public/assets/img/svg/octicon-eye.svg
+++ b/public/assets/img/svg/octicon-eye.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-feed-issue-draft.svg b/public/assets/img/svg/octicon-feed-issue-draft.svg
index b1f8aca871..c3ca27fe13 100644
--- a/public/assets/img/svg/octicon-feed-issue-draft.svg
+++ b/public/assets/img/svg/octicon-feed-issue-draft.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-feed-issue-reopen.svg b/public/assets/img/svg/octicon-feed-issue-reopen.svg
index 1ee31ec368..c82d5b0fdc 100644
--- a/public/assets/img/svg/octicon-feed-issue-reopen.svg
+++ b/public/assets/img/svg/octicon-feed-issue-reopen.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-feed-rocket.svg b/public/assets/img/svg/octicon-feed-rocket.svg
index e74dfdddcc..b378e2ad18 100644
--- a/public/assets/img/svg/octicon-feed-rocket.svg
+++ b/public/assets/img/svg/octicon-feed-rocket.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-feed-star.svg b/public/assets/img/svg/octicon-feed-star.svg
index 70f6859fba..7085fbdc79 100644
--- a/public/assets/img/svg/octicon-feed-star.svg
+++ b/public/assets/img/svg/octicon-feed-star.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-feed-tag.svg b/public/assets/img/svg/octicon-feed-tag.svg
index 90a796f38b..6a1924707a 100644
--- a/public/assets/img/svg/octicon-feed-tag.svg
+++ b/public/assets/img/svg/octicon-feed-tag.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-file-added.svg b/public/assets/img/svg/octicon-file-added.svg
index 927784d2e6..a8cd80f3e8 100644
--- a/public/assets/img/svg/octicon-file-added.svg
+++ b/public/assets/img/svg/octicon-file-added.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-file-binary.svg b/public/assets/img/svg/octicon-file-binary.svg
index f6dd459eed..492e7d5433 100644
--- a/public/assets/img/svg/octicon-file-binary.svg
+++ b/public/assets/img/svg/octicon-file-binary.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-file-code.svg b/public/assets/img/svg/octicon-file-code.svg
index 38baefd9e9..1d6b6ace59 100644
--- a/public/assets/img/svg/octicon-file-code.svg
+++ b/public/assets/img/svg/octicon-file-code.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-file-symlink-file.svg b/public/assets/img/svg/octicon-file-symlink-file.svg
index 5b1d9aad23..93c69793c7 100644
--- a/public/assets/img/svg/octicon-file-symlink-file.svg
+++ b/public/assets/img/svg/octicon-file-symlink-file.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-file.svg b/public/assets/img/svg/octicon-file.svg
index 976d8d99d3..faf92c5431 100644
--- a/public/assets/img/svg/octicon-file.svg
+++ b/public/assets/img/svg/octicon-file.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-filter-remove.svg b/public/assets/img/svg/octicon-filter-remove.svg
index dd968226b1..1a83bf37e6 100644
--- a/public/assets/img/svg/octicon-filter-remove.svg
+++ b/public/assets/img/svg/octicon-filter-remove.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-flame.svg b/public/assets/img/svg/octicon-flame.svg
index 022f7edd23..2c2db145f5 100644
--- a/public/assets/img/svg/octicon-flame.svg
+++ b/public/assets/img/svg/octicon-flame.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-fold-up.svg b/public/assets/img/svg/octicon-fold-up.svg
index 6429cf4573..c139cf8362 100644
--- a/public/assets/img/svg/octicon-fold-up.svg
+++ b/public/assets/img/svg/octicon-fold-up.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-gear.svg b/public/assets/img/svg/octicon-gear.svg
index 2da0cff438..bfff730ca8 100644
--- a/public/assets/img/svg/octicon-gear.svg
+++ b/public/assets/img/svg/octicon-gear.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-gift.svg b/public/assets/img/svg/octicon-gift.svg
index dd2b6dda98..a8a8ff36b2 100644
--- a/public/assets/img/svg/octicon-gift.svg
+++ b/public/assets/img/svg/octicon-gift.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-globe.svg b/public/assets/img/svg/octicon-globe.svg
index b4f21b5b03..8849e6d2da 100644
--- a/public/assets/img/svg/octicon-globe.svg
+++ b/public/assets/img/svg/octicon-globe.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-goal.svg b/public/assets/img/svg/octicon-goal.svg
index 012a4f0c30..36a3dd8346 100644
--- a/public/assets/img/svg/octicon-goal.svg
+++ b/public/assets/img/svg/octicon-goal.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-graph.svg b/public/assets/img/svg/octicon-graph.svg
index 075c6afa7b..ea7fa822ae 100644
--- a/public/assets/img/svg/octicon-graph.svg
+++ b/public/assets/img/svg/octicon-graph.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-hash.svg b/public/assets/img/svg/octicon-hash.svg
index 3c74070d2b..9920504192 100644
--- a/public/assets/img/svg/octicon-hash.svg
+++ b/public/assets/img/svg/octicon-hash.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-heart-fill.svg b/public/assets/img/svg/octicon-heart-fill.svg
index 0665a16894..b076997bfb 100644
--- a/public/assets/img/svg/octicon-heart-fill.svg
+++ b/public/assets/img/svg/octicon-heart-fill.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-hourglass.svg b/public/assets/img/svg/octicon-hourglass.svg
index 815ddcd1c1..8ce847c7a7 100644
--- a/public/assets/img/svg/octicon-hourglass.svg
+++ b/public/assets/img/svg/octicon-hourglass.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-hubot.svg b/public/assets/img/svg/octicon-hubot.svg
index 46418adc08..0d74758cec 100644
--- a/public/assets/img/svg/octicon-hubot.svg
+++ b/public/assets/img/svg/octicon-hubot.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-infinity.svg b/public/assets/img/svg/octicon-infinity.svg
index aa94289fed..c51685a11a 100644
--- a/public/assets/img/svg/octicon-infinity.svg
+++ b/public/assets/img/svg/octicon-infinity.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-issue-closed.svg b/public/assets/img/svg/octicon-issue-closed.svg
index af0422c446..1d0aa0c2b4 100644
--- a/public/assets/img/svg/octicon-issue-closed.svg
+++ b/public/assets/img/svg/octicon-issue-closed.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-issue-draft.svg b/public/assets/img/svg/octicon-issue-draft.svg
index 5b3f598a95..1dac7ff3e2 100644
--- a/public/assets/img/svg/octicon-issue-draft.svg
+++ b/public/assets/img/svg/octicon-issue-draft.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-issue-reopened.svg b/public/assets/img/svg/octicon-issue-reopened.svg
index faac17d119..72c9c71c05 100644
--- a/public/assets/img/svg/octicon-issue-reopened.svg
+++ b/public/assets/img/svg/octicon-issue-reopened.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-link.svg b/public/assets/img/svg/octicon-link.svg
index e6b60a12f7..92805444e0 100644
--- a/public/assets/img/svg/octicon-link.svg
+++ b/public/assets/img/svg/octicon-link.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-location.svg b/public/assets/img/svg/octicon-location.svg
index d4fc960d2c..7f91acc2e7 100644
--- a/public/assets/img/svg/octicon-location.svg
+++ b/public/assets/img/svg/octicon-location.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-log.svg b/public/assets/img/svg/octicon-log.svg
index 3bc4b5e799..fe44666298 100644
--- a/public/assets/img/svg/octicon-log.svg
+++ b/public/assets/img/svg/octicon-log.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-logo-gist.svg b/public/assets/img/svg/octicon-logo-gist.svg
index 1409287526..3a4f903b6d 100644
--- a/public/assets/img/svg/octicon-logo-gist.svg
+++ b/public/assets/img/svg/octicon-logo-gist.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-logo-github.svg b/public/assets/img/svg/octicon-logo-github.svg
index e17a7ef3fc..f2bebfe73e 100644
--- a/public/assets/img/svg/octicon-logo-github.svg
+++ b/public/assets/img/svg/octicon-logo-github.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-mail.svg b/public/assets/img/svg/octicon-mail.svg
index 03bb8e5b40..750b742e6c 100644
--- a/public/assets/img/svg/octicon-mail.svg
+++ b/public/assets/img/svg/octicon-mail.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-megaphone.svg b/public/assets/img/svg/octicon-megaphone.svg
index 14c8c74a60..972bb098fc 100644
--- a/public/assets/img/svg/octicon-megaphone.svg
+++ b/public/assets/img/svg/octicon-megaphone.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-meter.svg b/public/assets/img/svg/octicon-meter.svg
index e192d5e8e0..94fbe535c5 100644
--- a/public/assets/img/svg/octicon-meter.svg
+++ b/public/assets/img/svg/octicon-meter.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-mirror.svg b/public/assets/img/svg/octicon-mirror.svg
index 05efbf2fc7..d9c67fcf84 100644
--- a/public/assets/img/svg/octicon-mirror.svg
+++ b/public/assets/img/svg/octicon-mirror.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-moon.svg b/public/assets/img/svg/octicon-moon.svg
index a51e223034..22c29d87da 100644
--- a/public/assets/img/svg/octicon-moon.svg
+++ b/public/assets/img/svg/octicon-moon.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-move-to-bottom.svg b/public/assets/img/svg/octicon-move-to-bottom.svg
index 10595b106c..ec32e84a84 100644
--- a/public/assets/img/svg/octicon-move-to-bottom.svg
+++ b/public/assets/img/svg/octicon-move-to-bottom.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-move-to-end.svg b/public/assets/img/svg/octicon-move-to-end.svg
index cd6e3e6ec9..0bb002dbaf 100644
--- a/public/assets/img/svg/octicon-move-to-end.svg
+++ b/public/assets/img/svg/octicon-move-to-end.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-move-to-top.svg b/public/assets/img/svg/octicon-move-to-top.svg
index 05316ded4a..5f1062b689 100644
--- a/public/assets/img/svg/octicon-move-to-top.svg
+++ b/public/assets/img/svg/octicon-move-to-top.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-number.svg b/public/assets/img/svg/octicon-number.svg
index 53c4d4e8f7..0a88de18aa 100644
--- a/public/assets/img/svg/octicon-number.svg
+++ b/public/assets/img/svg/octicon-number.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-package-dependencies.svg b/public/assets/img/svg/octicon-package-dependencies.svg
index ae408868b8..eb21a034c4 100644
--- a/public/assets/img/svg/octicon-package-dependencies.svg
+++ b/public/assets/img/svg/octicon-package-dependencies.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-package-dependents.svg b/public/assets/img/svg/octicon-package-dependents.svg
index bad01efc9b..d4845b13ae 100644
--- a/public/assets/img/svg/octicon-package-dependents.svg
+++ b/public/assets/img/svg/octicon-package-dependents.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-package.svg b/public/assets/img/svg/octicon-package.svg
index ce79726ae4..c6fe903d89 100644
--- a/public/assets/img/svg/octicon-package.svg
+++ b/public/assets/img/svg/octicon-package.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-paintbrush.svg b/public/assets/img/svg/octicon-paintbrush.svg
index 8cbfcf3ee4..ca9a739a7d 100644
--- a/public/assets/img/svg/octicon-paintbrush.svg
+++ b/public/assets/img/svg/octicon-paintbrush.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-passkey-fill.svg b/public/assets/img/svg/octicon-passkey-fill.svg
index 2394d3eaaf..6b27f566ae 100644
--- a/public/assets/img/svg/octicon-passkey-fill.svg
+++ b/public/assets/img/svg/octicon-passkey-fill.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-paste.svg b/public/assets/img/svg/octicon-paste.svg
index 13b4d7430d..ff36749e61 100644
--- a/public/assets/img/svg/octicon-paste.svg
+++ b/public/assets/img/svg/octicon-paste.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-person-add.svg b/public/assets/img/svg/octicon-person-add.svg
index 6dcdd20d83..ffcc63ccac 100644
--- a/public/assets/img/svg/octicon-person-add.svg
+++ b/public/assets/img/svg/octicon-person-add.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-pin-slash.svg b/public/assets/img/svg/octicon-pin-slash.svg
index 4cd88d58a1..35b9515588 100644
--- a/public/assets/img/svg/octicon-pin-slash.svg
+++ b/public/assets/img/svg/octicon-pin-slash.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-pin.svg b/public/assets/img/svg/octicon-pin.svg
index e24d9cc817..e49dbf6502 100644
--- a/public/assets/img/svg/octicon-pin.svg
+++ b/public/assets/img/svg/octicon-pin.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-pivot-column.svg b/public/assets/img/svg/octicon-pivot-column.svg
index 34370c2060..3df95c91ce 100644
--- a/public/assets/img/svg/octicon-pivot-column.svg
+++ b/public/assets/img/svg/octicon-pivot-column.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-project-template.svg b/public/assets/img/svg/octicon-project-template.svg
index 559465e7dc..31d4cc06b7 100644
--- a/public/assets/img/svg/octicon-project-template.svg
+++ b/public/assets/img/svg/octicon-project-template.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-read.svg b/public/assets/img/svg/octicon-read.svg
index dc27b12ae2..a67986aa2d 100644
--- a/public/assets/img/svg/octicon-read.svg
+++ b/public/assets/img/svg/octicon-read.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-redo.svg b/public/assets/img/svg/octicon-redo.svg
index a4fbeabeaa..fc0ee5fe1c 100644
--- a/public/assets/img/svg/octicon-redo.svg
+++ b/public/assets/img/svg/octicon-redo.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-rel-file-path.svg b/public/assets/img/svg/octicon-rel-file-path.svg
index d7617487e1..45837c2cd3 100644
--- a/public/assets/img/svg/octicon-rel-file-path.svg
+++ b/public/assets/img/svg/octicon-rel-file-path.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-reply.svg b/public/assets/img/svg/octicon-reply.svg
index 124511dae2..bffda4aaea 100644
--- a/public/assets/img/svg/octicon-reply.svg
+++ b/public/assets/img/svg/octicon-reply.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-repo-deleted.svg b/public/assets/img/svg/octicon-repo-deleted.svg
index c2f0fc8cf8..58587b31f0 100644
--- a/public/assets/img/svg/octicon-repo-deleted.svg
+++ b/public/assets/img/svg/octicon-repo-deleted.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-repo-pull.svg b/public/assets/img/svg/octicon-repo-pull.svg
index 8cee37524f..6ba95650c1 100644
--- a/public/assets/img/svg/octicon-repo-pull.svg
+++ b/public/assets/img/svg/octicon-repo-pull.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-repo-push.svg b/public/assets/img/svg/octicon-repo-push.svg
index f473dcb2b9..e227d55e7e 100644
--- a/public/assets/img/svg/octicon-repo-push.svg
+++ b/public/assets/img/svg/octicon-repo-push.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-repo-template.svg b/public/assets/img/svg/octicon-repo-template.svg
index 05b951e641..ec6033295f 100644
--- a/public/assets/img/svg/octicon-repo-template.svg
+++ b/public/assets/img/svg/octicon-repo-template.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-rocket.svg b/public/assets/img/svg/octicon-rocket.svg
index 967b2d63f4..afccfe66e0 100644
--- a/public/assets/img/svg/octicon-rocket.svg
+++ b/public/assets/img/svg/octicon-rocket.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-rss.svg b/public/assets/img/svg/octicon-rss.svg
index 757ec69e13..041c4c1d26 100644
--- a/public/assets/img/svg/octicon-rss.svg
+++ b/public/assets/img/svg/octicon-rss.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-shield-check.svg b/public/assets/img/svg/octicon-shield-check.svg
index 68c653adae..288b5b9fb4 100644
--- a/public/assets/img/svg/octicon-shield-check.svg
+++ b/public/assets/img/svg/octicon-shield-check.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-shield-lock.svg b/public/assets/img/svg/octicon-shield-lock.svg
index ef96e9a1e8..ea6f060807 100644
--- a/public/assets/img/svg/octicon-shield-lock.svg
+++ b/public/assets/img/svg/octicon-shield-lock.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-shield-x.svg b/public/assets/img/svg/octicon-shield-x.svg
index a87b9c189c..ef60791565 100644
--- a/public/assets/img/svg/octicon-shield-x.svg
+++ b/public/assets/img/svg/octicon-shield-x.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-shield.svg b/public/assets/img/svg/octicon-shield.svg
index 668979d7e5..5e7321ebf6 100644
--- a/public/assets/img/svg/octicon-shield.svg
+++ b/public/assets/img/svg/octicon-shield.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-sidebar-expand.svg b/public/assets/img/svg/octicon-sidebar-expand.svg
index 42816121a6..41e5c800f1 100644
--- a/public/assets/img/svg/octicon-sidebar-expand.svg
+++ b/public/assets/img/svg/octicon-sidebar-expand.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-skip.svg b/public/assets/img/svg/octicon-skip.svg
index 778827da66..c148c030e5 100644
--- a/public/assets/img/svg/octicon-skip.svg
+++ b/public/assets/img/svg/octicon-skip.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-sort-asc.svg b/public/assets/img/svg/octicon-sort-asc.svg
index 45d95c49e2..76fe377cb8 100644
--- a/public/assets/img/svg/octicon-sort-asc.svg
+++ b/public/assets/img/svg/octicon-sort-asc.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-sponsor-tiers.svg b/public/assets/img/svg/octicon-sponsor-tiers.svg
index a5afb85e23..f8981f00b2 100644
--- a/public/assets/img/svg/octicon-sponsor-tiers.svg
+++ b/public/assets/img/svg/octicon-sponsor-tiers.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-squirrel.svg b/public/assets/img/svg/octicon-squirrel.svg
index 4d04ca8061..d980fd42e7 100644
--- a/public/assets/img/svg/octicon-squirrel.svg
+++ b/public/assets/img/svg/octicon-squirrel.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-stack.svg b/public/assets/img/svg/octicon-stack.svg
index 683c6c4e2d..7a34bdda73 100644
--- a/public/assets/img/svg/octicon-stack.svg
+++ b/public/assets/img/svg/octicon-stack.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-star.svg b/public/assets/img/svg/octicon-star.svg
index 31e008b281..2001b8c0e8 100644
--- a/public/assets/img/svg/octicon-star.svg
+++ b/public/assets/img/svg/octicon-star.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-tasklist.svg b/public/assets/img/svg/octicon-tasklist.svg
index 227cd8a61b..f754249284 100644
--- a/public/assets/img/svg/octicon-tasklist.svg
+++ b/public/assets/img/svg/octicon-tasklist.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-telescope-fill.svg b/public/assets/img/svg/octicon-telescope-fill.svg
index c1961c3323..6d72e495aa 100644
--- a/public/assets/img/svg/octicon-telescope-fill.svg
+++ b/public/assets/img/svg/octicon-telescope-fill.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-telescope.svg b/public/assets/img/svg/octicon-telescope.svg
index 9ca9a6b372..e056c625d3 100644
--- a/public/assets/img/svg/octicon-telescope.svg
+++ b/public/assets/img/svg/octicon-telescope.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-thumbsdown.svg b/public/assets/img/svg/octicon-thumbsdown.svg
index 2d9f4d8afc..5b45c5f6ef 100644
--- a/public/assets/img/svg/octicon-thumbsdown.svg
+++ b/public/assets/img/svg/octicon-thumbsdown.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-thumbsup.svg b/public/assets/img/svg/octicon-thumbsup.svg
index 7871ab71dd..e1bf7ae54d 100644
--- a/public/assets/img/svg/octicon-thumbsup.svg
+++ b/public/assets/img/svg/octicon-thumbsup.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-tools.svg b/public/assets/img/svg/octicon-tools.svg
index 8b051eb3fd..5e111d44a2 100644
--- a/public/assets/img/svg/octicon-tools.svg
+++ b/public/assets/img/svg/octicon-tools.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-tracked-by-closed-completed.svg b/public/assets/img/svg/octicon-tracked-by-closed-completed.svg
index b12638d87d..74ec518279 100644
--- a/public/assets/img/svg/octicon-tracked-by-closed-completed.svg
+++ b/public/assets/img/svg/octicon-tracked-by-closed-completed.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-tracked-by-closed-not-planned.svg b/public/assets/img/svg/octicon-tracked-by-closed-not-planned.svg
index e96e93a40b..f738398428 100644
--- a/public/assets/img/svg/octicon-tracked-by-closed-not-planned.svg
+++ b/public/assets/img/svg/octicon-tracked-by-closed-not-planned.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-trash.svg b/public/assets/img/svg/octicon-trash.svg
index e0a1e56909..647e4480a3 100644
--- a/public/assets/img/svg/octicon-trash.svg
+++ b/public/assets/img/svg/octicon-trash.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-triangle-down.svg b/public/assets/img/svg/octicon-triangle-down.svg
index fd1dce1fe8..e8034484fc 100644
--- a/public/assets/img/svg/octicon-triangle-down.svg
+++ b/public/assets/img/svg/octicon-triangle-down.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-triangle-left.svg b/public/assets/img/svg/octicon-triangle-left.svg
index 66343551a9..fde4d16bad 100644
--- a/public/assets/img/svg/octicon-triangle-left.svg
+++ b/public/assets/img/svg/octicon-triangle-left.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-triangle-right.svg b/public/assets/img/svg/octicon-triangle-right.svg
index 7b39a67e6e..48a009760e 100644
--- a/public/assets/img/svg/octicon-triangle-right.svg
+++ b/public/assets/img/svg/octicon-triangle-right.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-triangle-up.svg b/public/assets/img/svg/octicon-triangle-up.svg
index f4b386b175..1982cc84c4 100644
--- a/public/assets/img/svg/octicon-triangle-up.svg
+++ b/public/assets/img/svg/octicon-triangle-up.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-trophy.svg b/public/assets/img/svg/octicon-trophy.svg
index ae33cff336..569dfefae0 100644
--- a/public/assets/img/svg/octicon-trophy.svg
+++ b/public/assets/img/svg/octicon-trophy.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-typography.svg b/public/assets/img/svg/octicon-typography.svg
index 0b2088ed2f..3ed9d8ff68 100644
--- a/public/assets/img/svg/octicon-typography.svg
+++ b/public/assets/img/svg/octicon-typography.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-undo.svg b/public/assets/img/svg/octicon-undo.svg
index 53ac646414..e69a1da263 100644
--- a/public/assets/img/svg/octicon-undo.svg
+++ b/public/assets/img/svg/octicon-undo.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-unlink.svg b/public/assets/img/svg/octicon-unlink.svg
index 778d5af83c..deb608706d 100644
--- a/public/assets/img/svg/octicon-unlink.svg
+++ b/public/assets/img/svg/octicon-unlink.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-unmute.svg b/public/assets/img/svg/octicon-unmute.svg
index 6ebdf38d14..b5d28c4517 100644
--- a/public/assets/img/svg/octicon-unmute.svg
+++ b/public/assets/img/svg/octicon-unmute.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-upload.svg b/public/assets/img/svg/octicon-upload.svg
index 16e3f04222..14ebf05957 100644
--- a/public/assets/img/svg/octicon-upload.svg
+++ b/public/assets/img/svg/octicon-upload.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-verified.svg b/public/assets/img/svg/octicon-verified.svg
index a6de1a30d6..c821390aaf 100644
--- a/public/assets/img/svg/octicon-verified.svg
+++ b/public/assets/img/svg/octicon-verified.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-versions.svg b/public/assets/img/svg/octicon-versions.svg
index b37de6aebe..e83a660694 100644
--- a/public/assets/img/svg/octicon-versions.svg
+++ b/public/assets/img/svg/octicon-versions.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-x-circle.svg b/public/assets/img/svg/octicon-x-circle.svg
index e4beb382fa..48b0eb8076 100644
--- a/public/assets/img/svg/octicon-x-circle.svg
+++ b/public/assets/img/svg/octicon-x-circle.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/public/assets/img/svg/octicon-zap.svg b/public/assets/img/svg/octicon-zap.svg
index f711e01eb1..a28c19ac13 100644
--- a/public/assets/img/svg/octicon-zap.svg
+++ b/public/assets/img/svg/octicon-zap.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go
index 5411237103..0d2062ad05 100644
--- a/routers/api/actions/artifacts.go
+++ b/routers/api/actions/artifacts.go
@@ -63,7 +63,6 @@ package actions
import (
"crypto/md5"
- "errors"
"fmt"
"net/http"
"strconv"
@@ -258,8 +257,11 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) {
return
}
- // update artifact size if zero
- if artifact.FileSize == 0 || artifact.FileCompressedSize == 0 {
+ // update artifact size if zero or not match, over write artifact size
+ if artifact.FileSize == 0 ||
+ artifact.FileCompressedSize == 0 ||
+ artifact.FileSize != fileRealTotalSize ||
+ artifact.FileCompressedSize != chunksTotalSize {
artifact.FileSize = fileRealTotalSize
artifact.FileCompressedSize = chunksTotalSize
artifact.ContentEncoding = ctx.Req.Header.Get("Content-Encoding")
@@ -268,6 +270,8 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) {
ctx.Error(http.StatusInternalServerError, "Error update artifact")
return
}
+ log.Debug("[artifact] update artifact size, artifact_id: %d, size: %d, compressed size: %d",
+ artifact.ID, artifact.FileSize, artifact.FileCompressedSize)
}
ctx.JSON(http.StatusOK, map[string]string{
@@ -423,15 +427,15 @@ func (ar artifactRoutes) downloadArtifact(ctx *ArtifactContext) {
}
artifactID := ctx.ParamsInt64("artifact_id")
- artifact, err := actions.GetArtifactByID(ctx, artifactID)
- if errors.Is(err, util.ErrNotExist) {
- log.Error("Error getting artifact: %v", err)
- ctx.Error(http.StatusNotFound, err.Error())
- return
- } else if err != nil {
+ artifact, exist, err := db.GetByID[actions.ActionArtifact](ctx, artifactID)
+ if err != nil {
log.Error("Error getting artifact: %v", err)
ctx.Error(http.StatusInternalServerError, err.Error())
return
+ } else if !exist {
+ log.Error("artifact with ID %d does not exist", artifactID)
+ ctx.Error(http.StatusNotFound, fmt.Sprintf("artifact with ID %d does not exist", artifactID))
+ return
}
if artifact.RunID != runID {
log.Error("Error dismatch runID and artifactID, task: %v, artifact: %v", runID, artifactID)
diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go
index c7ab70afa9..0713c8bba8 100644
--- a/routers/api/actions/artifacts_chunks.go
+++ b/routers/api/actions/artifacts_chunks.go
@@ -26,10 +26,11 @@ func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
contentRange := ctx.Req.Header.Get("Content-Range")
start, end, length := int64(0), int64(0), int64(0)
if _, err := fmt.Sscanf(contentRange, "bytes %d-%d/%d", &start, &end, &length); err != nil {
+ log.Warn("parse content range error: %v, content-range: %s", err, contentRange)
return -1, fmt.Errorf("parse content range error: %v", err)
}
// build chunk store path
- storagePath := fmt.Sprintf("tmp%d/%d-%d-%d.chunk", runID, artifact.ID, start, end)
+ storagePath := fmt.Sprintf("tmp%d/%d-%d-%d-%d.chunk", runID, runID, artifact.ID, start, end)
// use io.TeeReader to avoid reading all body to md5 sum.
// it writes data to hasher after reading end
// if hash is not matched, delete the read-end result
@@ -58,6 +59,7 @@ func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
}
type chunkFileItem struct {
+ RunID int64
ArtifactID int64
Start int64
End int64
@@ -67,9 +69,12 @@ type chunkFileItem struct {
func listChunksByRunID(st storage.ObjectStorage, runID int64) (map[int64][]*chunkFileItem, error) {
storageDir := fmt.Sprintf("tmp%d", runID)
var chunks []*chunkFileItem
- if err := st.IterateObjects(storageDir, func(path string, obj storage.Object) error {
- item := chunkFileItem{Path: path}
- if _, err := fmt.Sscanf(path, filepath.Join(storageDir, "%d-%d-%d.chunk"), &item.ArtifactID, &item.Start, &item.End); err != nil {
+ if err := st.IterateObjects(storageDir, func(fpath string, obj storage.Object) error {
+ baseName := filepath.Base(fpath)
+ // when read chunks from storage, it only contains storage dir and basename,
+ // no matter the subdirectory setting in storage config
+ item := chunkFileItem{Path: storageDir + "/" + baseName}
+ if _, err := fmt.Sscanf(baseName, "%d-%d-%d-%d.chunk", &item.RunID, &item.ArtifactID, &item.Start, &item.End); err != nil {
return fmt.Errorf("parse content range error: %v", err)
}
chunks = append(chunks, &item)
@@ -181,7 +186,14 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
}()
// save storage path to artifact
- log.Debug("[artifact] merge chunks to artifact: %d, %s", artifact.ID, storagePath)
+ log.Debug("[artifact] merge chunks to artifact: %d, %s, old:%s", artifact.ID, storagePath, artifact.StoragePath)
+ // if artifact is already uploaded, delete the old file
+ if artifact.StoragePath != "" {
+ if err := st.Delete(artifact.StoragePath); err != nil {
+ log.Warn("Error deleting old artifact: %s, %v", artifact.StoragePath, err)
+ }
+ }
+
artifact.StoragePath = storagePath
artifact.Status = int64(actions.ArtifactStatusUploadConfirmed)
if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
diff --git a/routers/api/actions/runner/utils.go b/routers/api/actions/runner/utils.go
index bf913f2c05..2555f86c80 100644
--- a/routers/api/actions/runner/utils.go
+++ b/routers/api/actions/runner/utils.go
@@ -94,6 +94,12 @@ func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[s
func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map[string]string {
variables := map[string]string{}
+ // Global
+ globalVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{})
+ if err != nil {
+ log.Error("find global variables: %v", err)
+ }
+
// Org / User level
ownerVariables, err := db.Find[actions_model.ActionVariable](ctx, actions_model.FindVariablesOpts{OwnerID: task.Job.Run.Repo.OwnerID})
if err != nil {
@@ -106,8 +112,8 @@ func getVariablesOfTask(ctx context.Context, task *actions_model.ActionTask) map
log.Error("find variables of repo: %d, error: %v", task.Job.Run.RepoID, err)
}
- // Level precedence: Repo > Org / User
- for _, v := range append(ownerVariables, repoVariables...) {
+ // Level precedence: Repo > Org / User > Global
+ for _, v := range append(globalVariables, append(ownerVariables, repoVariables...)...) {
variables[v.Name] = v.Data
}
diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go
index 2ba35e2138..9026387129 100644
--- a/routers/api/packages/api.go
+++ b/routers/api/packages/api.go
@@ -512,16 +512,7 @@ func CommonRoutes() *web.Route {
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
r.Get("/simple/{id}", pypi.PackageMetadata)
}, reqPackageAccess(perm.AccessModeRead))
- r.Group("/rpm", func() {
- r.Get(".repo", rpm.GetRepositoryConfig)
- r.Get("/repository.key", rpm.GetRepositoryKey)
- r.Put("/upload", reqPackageAccess(perm.AccessModeWrite), rpm.UploadPackageFile)
- r.Group("/package/{name}/{version}/{architecture}", func() {
- r.Get("", rpm.DownloadPackageFile)
- r.Delete("", reqPackageAccess(perm.AccessModeWrite), rpm.DeletePackageFile)
- })
- r.Get("/repodata/{filename}", rpm.GetRepositoryFile)
- }, reqPackageAccess(perm.AccessModeRead))
+ r.Group("/rpm", RpmRoutes(r), reqPackageAccess(perm.AccessModeRead))
r.Group("/rubygems", func() {
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
@@ -586,6 +577,82 @@ func CommonRoutes() *web.Route {
return r
}
+// Support for uploading rpm packages with arbitrary depth paths
+func RpmRoutes(r *web.Route) func() {
+ var (
+ groupRepoInfo = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)\.repo\z`)
+ groupUpload = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/upload\z`)
+ groupRpm = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/package/([^/]+)/([^/]+)/([^/]+)(?:/([^/]+\.rpm)|)\z`)
+ groupMetadata = regexp.MustCompile(`\A((?:/(?:[^/]+))*|)/repodata/([^/]+)\z`)
+ )
+
+ return func() {
+ r.Methods("HEAD,GET,POST,PUT,PATCH,DELETE", "*", func(ctx *context.Context) {
+ path := ctx.Params("*")
+ isHead := ctx.Req.Method == "HEAD"
+ isGetHead := ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
+ isPut := ctx.Req.Method == "PUT"
+ isDelete := ctx.Req.Method == "DELETE"
+
+ if path == "/repository.key" && isGetHead {
+ rpm.GetRepositoryKey(ctx)
+ return
+ }
+
+ // get repo
+ m := groupRepoInfo.FindStringSubmatch(path)
+ if len(m) == 2 && isGetHead {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ rpm.GetRepositoryConfig(ctx)
+ return
+ }
+ // get meta
+ m = groupMetadata.FindStringSubmatch(path)
+ if len(m) == 3 && isGetHead {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ ctx.SetParams("filename", m[2])
+ if isHead {
+ rpm.CheckRepositoryFileExistence(ctx)
+ } else {
+ rpm.GetRepositoryFile(ctx)
+ }
+ return
+ }
+ // upload
+ m = groupUpload.FindStringSubmatch(path)
+ if len(m) == 2 && isPut {
+ reqPackageAccess(perm.AccessModeWrite)(ctx)
+ if ctx.Written() {
+ return
+ }
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ rpm.UploadPackageFile(ctx)
+ return
+ }
+ // rpm down/delete
+ m = groupRpm.FindStringSubmatch(path)
+ if len(m) == 6 {
+ ctx.SetParams("group", strings.Trim(m[1], "/"))
+ ctx.SetParams("name", m[2])
+ ctx.SetParams("version", m[3])
+ ctx.SetParams("architecture", m[4])
+ if isGetHead {
+ rpm.DownloadPackageFile(ctx)
+ return
+ } else if isDelete {
+ reqPackageAccess(perm.AccessModeWrite)(ctx)
+ if ctx.Written() {
+ return
+ }
+ rpm.DeletePackageFile(ctx)
+ }
+ }
+ // default
+ ctx.Status(http.StatusNotFound)
+ })
+ }
+}
+
// ContainerRoutes provides endpoints that implement the OCI API to serve containers
// These have to be mounted on `/v2/...` to comply with the OCI spec:
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md
@@ -600,7 +667,10 @@ func ContainerRoutes() *web.Route {
})
r.Get("", container.ReqContainerAccess, container.DetermineSupport)
- r.Get("/token", container.Authenticate)
+ r.Group("/token", func() {
+ r.Get("", container.Authenticate)
+ r.Post("", container.AuthenticateNotImplemented)
+ })
r.Get("/_catalog", container.ReqContainerAccess, container.GetRepositoryList)
r.Group("/{username}", func() {
r.Group("/{image}", func() {
diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go
index 62eec3064c..dce3809264 100644
--- a/routers/api/packages/container/container.go
+++ b/routers/api/packages/container/container.go
@@ -156,6 +156,17 @@ func Authenticate(ctx *context.Context) {
})
}
+// https://distribution.github.io/distribution/spec/auth/oauth/
+func AuthenticateNotImplemented(ctx *context.Context) {
+ // This optional endpoint can be used to authenticate a client.
+ // It must implement the specification described in:
+ // https://datatracker.ietf.org/doc/html/rfc6749
+ // https://distribution.github.io/distribution/spec/auth/oauth/
+ // Purpose of this stub is to respond with 404 Not Found instead of 405 Method Not Allowed.
+
+ ctx.Status(http.StatusNotFound)
+}
+
// https://docs.docker.com/registry/spec/api/#listing-repositories
func GetRepositoryList(ctx *context.Context) {
n := ctx.FormInt("n")
diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go
index f5d8b67e16..75d19e2b43 100644
--- a/routers/api/packages/rpm/rpm.go
+++ b/routers/api/packages/rpm/rpm.go
@@ -33,11 +33,14 @@ func apiError(ctx *context.Context, status int, obj any) {
// https://dnf.readthedocs.io/en/latest/conf_ref.html
func GetRepositoryConfig(ctx *context.Context) {
+ group := ctx.Params("group")
+ if group != "" {
+ group = fmt.Sprintf("/%s", group)
+ }
url := fmt.Sprintf("%sapi/packages/%s/rpm", setting.AppURL, ctx.Package.Owner.Name)
-
- ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+`]
-name=`+ctx.Package.Owner.Name+` - `+setting.AppName+`
-baseurl=`+url+`
+ ctx.PlainText(http.StatusOK, `[gitea-`+ctx.Package.Owner.LowerName+strings.ReplaceAll(group, "/", "-")+`]
+name=`+ctx.Package.Owner.Name+` - `+setting.AppName+strings.ReplaceAll(group, "/", " - ")+`
+baseurl=`+url+group+`/
enabled=1
gpgcheck=1
gpgkey=`+url+`/repository.key`)
@@ -57,6 +60,30 @@ func GetRepositoryKey(ctx *context.Context) {
})
}
+func CheckRepositoryFileExistence(ctx *context.Context) {
+ pv, err := rpm_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID)
+ if err != nil {
+ apiError(ctx, http.StatusInternalServerError, err)
+ return
+ }
+
+ pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), ctx.Params("group"))
+ if err != nil {
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.Status(http.StatusNotFound)
+ } else {
+ apiError(ctx, http.StatusInternalServerError, err)
+ }
+ return
+ }
+
+ ctx.SetServeHeaders(&context.ServeHeaderOptions{
+ Filename: pf.Name,
+ LastModified: pf.CreatedUnix.AsLocalTime(),
+ })
+ ctx.Status(http.StatusOK)
+}
+
// Gets a pre-generated repository metadata file
func GetRepositoryFile(ctx *context.Context) {
pv, err := rpm_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID)
@@ -69,7 +96,8 @@ func GetRepositoryFile(ctx *context.Context) {
ctx,
pv,
&packages_service.PackageFileInfo{
- Filename: ctx.Params("filename"),
+ Filename: ctx.Params("filename"),
+ CompositeKey: ctx.Params("group"),
},
)
if err != nil {
@@ -121,7 +149,7 @@ func UploadPackageFile(ctx *context.Context) {
apiError(ctx, http.StatusInternalServerError, err)
return
}
-
+ group := ctx.Params("group")
_, _, err = packages_service.CreatePackageOrAddFileToExisting(
ctx,
&packages_service.PackageCreationInfo{
@@ -129,14 +157,15 @@ func UploadPackageFile(ctx *context.Context) {
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeRpm,
Name: pck.Name,
- Version: pck.Version,
+ Version: strings.Trim(fmt.Sprintf("%s/%s", group, pck.Version), "/"),
},
Creator: ctx.Doer,
Metadata: pck.VersionMetadata,
},
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture),
+ Filename: fmt.Sprintf("%s-%s.%s.rpm", pck.Name, pck.Version, pck.FileMetadata.Architecture),
+ CompositeKey: group,
},
Creator: ctx.Doer,
Data: buf,
@@ -158,7 +187,7 @@ func UploadPackageFile(ctx *context.Context) {
return
}
- if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID); err != nil {
+ if err := rpm_service.BuildRepositoryFiles(ctx, ctx.Package.Owner.ID, group); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
@@ -167,19 +196,20 @@ func UploadPackageFile(ctx *context.Context) {
}
func DownloadPackageFile(ctx *context.Context) {
+ group := ctx.Params("group")
name := ctx.Params("name")
version := ctx.Params("version")
-
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
ctx,
&packages_service.PackageInfo{
Owner: ctx.Package.Owner,
PackageType: packages_model.TypeRpm,
Name: name,
- Version: version,
+ Version: strings.Trim(fmt.Sprintf("%s/%s", group, version), "/"),
},
&packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")),
+ Filename: fmt.Sprintf("%s-%s.%s.rpm", name, version, ctx.Params("architecture")),
+ CompositeKey: group,
},
)
if err != nil {
@@ -195,14 +225,19 @@ func DownloadPackageFile(ctx *context.Context) {
}
func DeletePackageFile(webctx *context.Context) {
+ group := webctx.Params("group")
name := webctx.Params("name")
version := webctx.Params("version")
architecture := webctx.Params("architecture")
-
var pd *packages_model.PackageDescriptor
err := db.WithTx(webctx, func(ctx stdctx.Context) error {
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, webctx.Package.Owner.ID, packages_model.TypeRpm, name, version)
+ pv, err := packages_model.GetVersionByNameAndVersion(ctx,
+ webctx.Package.Owner.ID,
+ packages_model.TypeRpm,
+ name,
+ strings.Trim(fmt.Sprintf("%s/%s", group, version), "/"),
+ )
if err != nil {
return err
}
@@ -211,7 +246,7 @@ func DeletePackageFile(webctx *context.Context) {
ctx,
pv.ID,
fmt.Sprintf("%s-%s.%s.rpm", name, version, architecture),
- packages_model.EmptyFileKey,
+ group,
)
if err != nil {
return err
@@ -251,7 +286,7 @@ func DeletePackageFile(webctx *context.Context) {
notify_service.PackageDelete(webctx, webctx.Doer, pd)
}
- if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID); err != nil {
+ if err := rpm_service.BuildRepositoryFiles(webctx, webctx.Package.Owner.ID, group); err != nil {
apiError(webctx, http.StatusInternalServerError, err)
return
}
diff --git a/routers/api/v1/admin/runners.go b/routers/api/v1/admin/runners.go
new file mode 100644
index 0000000000..c0d9364435
--- /dev/null
+++ b/routers/api/v1/admin/runners.go
@@ -0,0 +1,26 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package admin
+
+import (
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/routers/api/v1/shared"
+)
+
+// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
+
+// GetRegistrationToken returns the token to register global runners
+func GetRegistrationToken(ctx *context.APIContext) {
+ // swagger:operation GET /admin/runners/registration-token admin adminGetRunnerRegistrationToken
+ // ---
+ // summary: Get an global actions runner registration token
+ // produces:
+ // - application/json
+ // parameters:
+ // responses:
+ // "200":
+ // "$ref": "#/responses/RegistrationToken"
+
+ shared.GetRegistrationToken(ctx, 0, 0)
+}
diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go
index 09d7c1a940..b4cc42ea5d 100644
--- a/routers/api/v1/admin/user.go
+++ b/routers/api/v1/admin/user.go
@@ -93,18 +93,28 @@ func CreateUser(ctx *context.APIContext) {
if ctx.Written() {
return
}
- if !password.IsComplexEnough(form.Password) {
- err := errors.New("PasswordComplexity")
- ctx.Error(http.StatusBadRequest, "PasswordComplexity", err)
- return
- }
- pwned, err := password.IsPwned(ctx, form.Password)
- if pwned {
- if err != nil {
- log.Error(err.Error())
+
+ if u.LoginType == auth.Plain {
+ if len(form.Password) < setting.MinPasswordLength {
+ err := errors.New("PasswordIsRequired")
+ ctx.Error(http.StatusBadRequest, "PasswordIsRequired", err)
+ return
+ }
+
+ if !password.IsComplexEnough(form.Password) {
+ err := errors.New("PasswordComplexity")
+ ctx.Error(http.StatusBadRequest, "PasswordComplexity", err)
+ return
+ }
+
+ pwned, err := password.IsPwned(ctx, form.Password)
+ if pwned {
+ if err != nil {
+ log.Error(err.Error())
+ }
+ ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
+ return
}
- ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
- return
}
overwriteDefault := &user_model.CreateUserOverwriteOptions{
@@ -173,6 +183,8 @@ func EditUser(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/User"
+ // "400":
+ // "$ref": "#/responses/error"
// "403":
// "$ref": "#/responses/forbidden"
// "422":
@@ -254,6 +266,10 @@ func EditUser(ctx *context.APIContext) {
ctx.ContextUser.Visibility = api.VisibilityModes[form.Visibility]
}
if form.Admin != nil {
+ if !*form.Admin && user_model.IsLastAdminUser(ctx, ctx.ContextUser) {
+ ctx.Error(http.StatusBadRequest, "LastAdmin", ctx.Tr("auth.last_admin"))
+ return
+ }
ctx.ContextUser.IsAdmin = *form.Admin
}
if form.AllowGitHook != nil {
@@ -331,7 +347,8 @@ func DeleteUser(ctx *context.APIContext) {
if err := user_service.DeleteUser(ctx, ctx.ContextUser, ctx.FormBool("purge")); err != nil {
if models.IsErrUserOwnRepos(err) ||
models.IsErrUserHasOrgs(err) ||
- models.IsErrUserOwnPackages(err) {
+ models.IsErrUserOwnPackages(err) ||
+ models.IsErrDeleteLastAdminUser(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "DeleteUser", err)
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 88162710f8..58e48a0ea5 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -35,10 +35,12 @@
// type: apiKey
// name: token
// in: query
+// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
// AccessToken:
// type: apiKey
// name: access_token
// in: query
+// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
// AuthorizationHeaderToken:
// type: apiKey
// name: Authorization
@@ -867,6 +869,31 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
}
}
+func individualPermsChecker(ctx *context.APIContext) {
+ // org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
+ if ctx.ContextUser.IsIndividual() {
+ switch {
+ case ctx.ContextUser.Visibility == api.VisibleTypePrivate:
+ if ctx.Doer == nil || (ctx.ContextUser.ID != ctx.Doer.ID && !ctx.Doer.IsAdmin) {
+ ctx.NotFound("Visit Project", nil)
+ return
+ }
+ case ctx.ContextUser.Visibility == api.VisibleTypeLimited:
+ if ctx.Doer == nil {
+ ctx.NotFound("Visit Project", nil)
+ return
+ }
+ }
+ }
+}
+
+// check for and warn against deprecated authentication options
+func checkDeprecatedAuthMethods(ctx *context.APIContext) {
+ if ctx.FormString("token") != "" || ctx.FormString("access_token") != "" {
+ ctx.Resp.Header().Set("Warning", "token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization.")
+ }
+}
+
// Routes registers all v1 APIs routes to web application.
func Routes() *web.Route {
m := web.NewRoute()
@@ -874,9 +901,7 @@ func Routes() *web.Route {
m.Use(securityHeaders())
if setting.CORSConfig.Enabled {
m.Use(cors.Handler(cors.Options{
- // Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option
- AllowedOrigins: setting.CORSConfig.AllowDomain,
- // setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
+ AllowedOrigins: setting.CORSConfig.AllowDomain,
AllowedMethods: setting.CORSConfig.Methods,
AllowCredentials: setting.CORSConfig.AllowCredentials,
AllowedHeaders: append(
@@ -887,6 +912,8 @@ func Routes() *web.Route {
}
m.Use(context.APIContexter())
+ m.Use(checkDeprecatedAuthMethods)
+
// Get user from session if logged in.
m.Use(apiAuth(buildAuthGroup()))
@@ -974,7 +1001,7 @@ func Routes() *web.Route {
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
m.Get("/activities/feeds", user.ListUserActivityFeeds)
- }, context_service.UserAssignmentAPI())
+ }, context_service.UserAssignmentAPI(), individualPermsChecker)
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
// Users (requires user scope)
@@ -1007,11 +1034,17 @@ func Routes() *web.Route {
Post(bind(api.CreateEmailOption{}), user.AddEmail).
Delete(bind(api.DeleteEmailOption{}), user.DeleteEmail)
- // create or update a user's actions secrets
- m.Group("/actions/secrets", func() {
- m.Combo("/{secretname}").
- Put(bind(api.CreateOrUpdateSecretOption{}), user.CreateOrUpdateSecret).
- Delete(user.DeleteSecret)
+ // manage user-level actions features
+ m.Group("/actions", func() {
+ m.Group("/secrets", func() {
+ m.Combo("/{secretname}").
+ Put(bind(api.CreateOrUpdateSecretOption{}), user.CreateOrUpdateSecret).
+ Delete(user.DeleteSecret)
+ })
+
+ m.Group("/runners", func() {
+ m.Get("/registration-token", reqToken(), user.GetRegistrationToken)
+ })
})
m.Get("/followers", user.ListMyFollowers)
@@ -1128,10 +1161,16 @@ func Routes() *web.Route {
m.Post("/accept", repo.AcceptTransfer)
m.Post("/reject", repo.RejectTransfer)
}, reqToken())
- m.Group("/actions/secrets", func() {
- m.Combo("/{secretname}").
- Put(reqToken(), reqOwner(), bind(api.CreateOrUpdateSecretOption{}), repo.CreateOrUpdateSecret).
- Delete(reqToken(), reqOwner(), repo.DeleteSecret)
+ m.Group("/actions", func() {
+ m.Group("/secrets", func() {
+ m.Combo("/{secretname}").
+ Put(reqToken(), reqOwner(), bind(api.CreateOrUpdateSecretOption{}), repo.CreateOrUpdateSecret).
+ Delete(reqToken(), reqOwner(), repo.DeleteSecret)
+ })
+
+ m.Group("/runners", func() {
+ m.Get("/registration-token", reqToken(), reqOwner(), repo.GetRegistrationToken)
+ })
})
m.Group("/hooks/git", func() {
m.Combo("").Get(repo.ListGitHooks)
@@ -1280,9 +1319,9 @@ func Routes() *web.Route {
m.Get("/subscribers", repo.ListSubscribers)
m.Group("/subscription", func() {
m.Get("", user.IsWatching)
- m.Put("", reqToken(), user.Watch)
- m.Delete("", reqToken(), user.Unwatch)
- })
+ m.Put("", user.Watch)
+ m.Delete("", user.Unwatch)
+ }, reqToken())
m.Group("/releases", func() {
m.Combo("").Get(repo.ListReleases).
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
@@ -1469,8 +1508,8 @@ func Routes() *web.Route {
m.Group("/{username}/{reponame}", func() {
m.Group("/issues", func() {
m.Combo("").Get(repo.ListIssues).
- Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue)
- m.Get("/pinned", repo.ListPinnedIssues)
+ Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), reqRepoReader(unit.TypeIssues), repo.CreateIssue)
+ m.Get("/pinned", reqRepoReader(unit.TypeIssues), repo.ListPinnedIssues)
m.Group("/comments", func() {
m.Get("", repo.ListRepoIssueComments)
m.Group("/{id}", func() {
@@ -1636,11 +1675,17 @@ func Routes() *web.Route {
m.Combo("/{username}").Get(reqToken(), org.IsMember).
Delete(reqToken(), reqOrgOwnership(), org.DeleteMember)
})
- m.Group("/actions/secrets", func() {
- m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
- m.Combo("/{secretname}").
- Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateSecret).
- Delete(reqToken(), reqOrgOwnership(), org.DeleteSecret)
+ m.Group("/actions", func() {
+ m.Group("/secrets", func() {
+ m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets)
+ m.Combo("/{secretname}").
+ Put(reqToken(), reqOrgOwnership(), bind(api.CreateOrUpdateSecretOption{}), org.CreateOrUpdateSecret).
+ Delete(reqToken(), reqOrgOwnership(), org.DeleteSecret)
+ })
+
+ m.Group("/runners", func() {
+ m.Get("/registration-token", reqToken(), reqOrgOwnership(), org.GetRegistrationToken)
+ })
})
m.Group("/public_members", func() {
m.Get("", org.ListPublicMembers)
@@ -1744,6 +1789,9 @@ func Routes() *web.Route {
Patch(bind(api.EditHookOption{}), admin.EditHook).
Delete(admin.DeleteHook)
})
+ m.Group("/runners", func() {
+ m.Get("/registration-token", admin.GetRegistrationToken)
+ })
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryAdmin), reqToken(), reqSiteAdmin())
m.Group("/projects", func() {
diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go
index f0d8d80dd4..cc754f64a2 100644
--- a/routers/api/v1/misc/nodeinfo.go
+++ b/routers/api/v1/misc/nodeinfo.go
@@ -29,10 +29,9 @@ func NodeInfo(ctx *context.APIContext) {
nodeInfoUsage := structs.NodeInfoUsage{}
if setting.Federation.ShareUserStatistics {
- cached := false
- if setting.CacheService.Enabled {
- nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage)
- }
+ var cached bool
+ nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage)
+
if !cached {
usersTotal := int(user_model.CountUsers(ctx, nil))
now := time.Now()
@@ -53,11 +52,10 @@ func NodeInfo(ctx *context.APIContext) {
LocalPosts: int(allIssues),
LocalComments: int(allComments),
}
- if setting.CacheService.Enabled {
- if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
- ctx.InternalServerError(err)
- return
- }
+
+ if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
+ ctx.InternalServerError(err)
+ return
}
}
}
diff --git a/routers/api/v1/org/runners.go b/routers/api/v1/org/runners.go
new file mode 100644
index 0000000000..05bce8daef
--- /dev/null
+++ b/routers/api/v1/org/runners.go
@@ -0,0 +1,31 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package org
+
+import (
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/routers/api/v1/shared"
+)
+
+// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
+
+// GetRegistrationToken returns the token to register org runners
+func GetRegistrationToken(ctx *context.APIContext) {
+ // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken
+ // ---
+ // summary: Get an organization's actions runner registration token
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: org
+ // in: path
+ // description: name of the organization
+ // type: string
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/RegistrationToken"
+
+ shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
+}
diff --git a/routers/api/v1/org/action.go b/routers/api/v1/org/secrets.go
similarity index 100%
rename from routers/api/v1/org/action.go
rename to routers/api/v1/org/secrets.go
diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go
index f2386a607e..edbfbcc568 100644
--- a/routers/api/v1/repo/branch.go
+++ b/routers/api/v1/repo/branch.go
@@ -10,6 +10,7 @@ import (
"net/http"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
@@ -137,7 +138,7 @@ func DeleteBranch(ctx *context.APIContext) {
}
// check whether branches of this repository has been synced
- totalNumOfBranches, err := git_model.CountBranches(ctx, git_model.FindBranchOptions{
+ totalNumOfBranches, err := db.Count[git_model.Branch](ctx, git_model.FindBranchOptions{
RepoID: ctx.Repo.Repository.ID,
IsDeletedBranch: util.OptionalBoolFalse,
})
@@ -251,12 +252,11 @@ func CreateBranch(ctx *context.APIContext) {
}
}
- err = repo_service.CreateNewBranchFromCommit(ctx, ctx.Doer, ctx.Repo.Repository, oldCommit.ID.String(), opt.BranchName)
+ err = repo_service.CreateNewBranchFromCommit(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, oldCommit.ID.String(), opt.BranchName)
if err != nil {
if git_model.IsErrBranchNotExist(err) {
ctx.Error(http.StatusNotFound, "", "The old branch does not exist")
- }
- if models.IsErrTagAlreadyExists(err) {
+ } else if models.IsErrTagAlreadyExists(err) {
ctx.Error(http.StatusConflict, "", "The branch with the same tag already exists.")
} else if git_model.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) {
ctx.Error(http.StatusConflict, "", "The branch already exists.")
@@ -342,7 +342,7 @@ func ListBranches(ctx *context.APIContext) {
IsDeletedBranch: util.OptionalBoolFalse,
}
var err error
- totalNumOfBranches, err = git_model.CountBranches(ctx, branchOpts)
+ totalNumOfBranches, err = db.Count[git_model.Branch](ctx, branchOpts)
if err != nil {
ctx.Error(http.StatusInternalServerError, "CountBranches", err)
return
@@ -361,7 +361,7 @@ func ListBranches(ctx *context.APIContext) {
return
}
- branches, err := git_model.FindBranches(ctx, branchOpts)
+ branches, err := db.Find[git_model.Branch](ctx, branchOpts)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetBranches", err)
return
@@ -615,6 +615,7 @@ func CreateBranchProtection(ctx *context.APIContext) {
BlockOnRejectedReviews: form.BlockOnRejectedReviews,
BlockOnOfficialReviewRequests: form.BlockOnOfficialReviewRequests,
DismissStaleApprovals: form.DismissStaleApprovals,
+ IgnoreStaleApprovals: form.IgnoreStaleApprovals,
RequireSignedCommits: form.RequireSignedCommits,
ProtectedFilePatterns: form.ProtectedFilePatterns,
UnprotectedFilePatterns: form.UnprotectedFilePatterns,
@@ -786,6 +787,10 @@ func EditBranchProtection(ctx *context.APIContext) {
protectBranch.DismissStaleApprovals = *form.DismissStaleApprovals
}
+ if form.IgnoreStaleApprovals != nil {
+ protectBranch.IgnoreStaleApprovals = *form.IgnoreStaleApprovals
+ }
+
if form.RequireSignedCommits != nil {
protectBranch.RequireSignedCommits = *form.RequireSignedCommits
}
diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go
index 2538bcdbc6..a222e50a5e 100644
--- a/routers/api/v1/repo/collaborators.go
+++ b/routers/api/v1/repo/collaborators.go
@@ -8,6 +8,7 @@ import (
"errors"
"net/http"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
@@ -53,7 +54,9 @@ func ListCollaborators(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- count, err := repo_model.CountCollaborators(ctx, ctx.Repo.Repository.ID)
+ count, err := db.Count[repo_model.Collaboration](ctx, repo_model.FindCollaborationOptions{
+ RepoID: ctx.Repo.Repository.ID,
+ })
if err != nil {
ctx.InternalServerError(err)
return
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 74e6361f6c..0f76a4b4ff 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -462,6 +462,24 @@ func ListIssues(ctx *context.APIContext) {
isPull = util.OptionalBoolNone
}
+ if isPull != util.OptionalBoolNone && !ctx.Repo.CanReadIssuesOrPulls(isPull.IsTrue()) {
+ ctx.NotFound()
+ return
+ }
+
+ if isPull == util.OptionalBoolNone {
+ canReadIssues := ctx.Repo.CanRead(unit.TypeIssues)
+ canReadPulls := ctx.Repo.CanRead(unit.TypePullRequests)
+ if !canReadIssues && !canReadPulls {
+ ctx.NotFound()
+ return
+ } else if !canReadIssues {
+ isPull = util.OptionalBoolTrue
+ } else if !canReadPulls {
+ isPull = util.OptionalBoolFalse
+ }
+ }
+
// FIXME: we should be more efficient here
createdByID := getUserIDForFilter(ctx, "created_by")
if ctx.Written() {
@@ -593,6 +611,10 @@ func GetIssue(ctx *context.APIContext) {
}
return
}
+ if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
+ ctx.NotFound()
+ return
+ }
ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue))
}
diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go
index c718424f7e..4db2c68a79 100644
--- a/routers/api/v1/repo/issue_comment.go
+++ b/routers/api/v1/repo/issue_comment.go
@@ -12,9 +12,11 @@ import (
issues_model "code.gitea.io/gitea/models/issues"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/convert"
@@ -71,6 +73,11 @@ func ListIssueComments(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "GetRawIssueByIndex", err)
return
}
+ if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
+ ctx.NotFound()
+ return
+ }
+
issue.Repo = ctx.Repo.Repository
opts := &issues_model.FindCommentsOptions{
@@ -271,12 +278,27 @@ func ListRepoIssueComments(ctx *context.APIContext) {
return
}
+ var isPull util.OptionalBool
+ canReadIssue := ctx.Repo.CanRead(unit.TypeIssues)
+ canReadPull := ctx.Repo.CanRead(unit.TypePullRequests)
+ if canReadIssue && canReadPull {
+ isPull = util.OptionalBoolNone
+ } else if canReadIssue {
+ isPull = util.OptionalBoolFalse
+ } else if canReadPull {
+ isPull = util.OptionalBoolTrue
+ } else {
+ ctx.NotFound()
+ return
+ }
+
opts := &issues_model.FindCommentsOptions{
ListOptions: utils.GetListOptions(ctx),
RepoID: ctx.Repo.Repository.ID,
Type: issues_model.CommentTypeComment,
Since: since,
Before: before,
+ IsPull: isPull,
}
comments, err := issues_model.FindComments(ctx, opts)
@@ -367,6 +389,11 @@ func CreateIssueComment(ctx *context.APIContext) {
return
}
+ if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
+ ctx.NotFound()
+ return
+ }
+
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.Doer.IsAdmin {
ctx.Error(http.StatusForbidden, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
return
@@ -436,6 +463,11 @@ func GetIssueComment(ctx *context.APIContext) {
return
}
+ if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
+ ctx.NotFound()
+ return
+ }
+
if comment.Type != issues_model.CommentTypeComment {
ctx.Status(http.StatusNoContent)
return
@@ -555,7 +587,17 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
return
}
- if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
+ if err := comment.LoadIssue(ctx); err != nil {
+ ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
+ return
+ }
+
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.Status(http.StatusNotFound)
+ return
+ }
+
+ if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
ctx.Status(http.StatusForbidden)
return
}
@@ -658,7 +700,17 @@ func deleteIssueComment(ctx *context.APIContext) {
return
}
- if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
+ if err := comment.LoadIssue(ctx); err != nil {
+ ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
+ return
+ }
+
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.Status(http.StatusNotFound)
+ return
+ }
+
+ if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
ctx.Status(http.StatusForbidden)
return
} else if comment.Type != issues_model.CommentTypeComment {
diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go
index c327c54d10..21e2f4dabd 100644
--- a/routers/api/v1/repo/issue_comment_attachment.go
+++ b/routers/api/v1/repo/issue_comment_attachment.go
@@ -329,6 +329,10 @@ func getIssueCommentSafe(ctx *context.APIContext) *issues_model.Comment {
return nil
}
+ if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
+ return nil
+ }
+
comment.Issue.Repo = ctx.Repo.Repository
return comment
diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go
index 0e3bcd93ef..62d1057cdf 100644
--- a/routers/api/v1/repo/issue_dependency.go
+++ b/routers/api/v1/repo/issue_dependency.go
@@ -102,23 +102,24 @@ func GetIssueDependencies(ctx *context.APIContext) {
return
}
- var lastRepoID int64
- var lastPerm access_model.Permission
+ repoPerms := make(map[int64]access_model.Permission)
+ repoPerms[ctx.Repo.Repository.ID] = ctx.Repo.Permission
for _, blocker := range blockersInfo {
// Get the permissions for this repository
- perm := lastPerm
- if lastRepoID != blocker.Repository.ID {
- if blocker.Repository.ID == ctx.Repo.Repository.ID {
- perm = ctx.Repo.Permission
- } else {
- var err error
- perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
- if err != nil {
- ctx.ServerError("GetUserRepoPermission", err)
- return
- }
+ // If the repo ID exists in the map, return the exist permissions
+ // else get the permission and add it to the map
+ var perm access_model.Permission
+ existPerm, ok := repoPerms[blocker.RepoID]
+ if ok {
+ perm = existPerm
+ } else {
+ var err error
+ perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return
}
- lastRepoID = blocker.Repository.ID
+ repoPerms[blocker.RepoID] = perm
}
// check permission
@@ -345,29 +346,31 @@ func GetIssueBlocks(ctx *context.APIContext) {
return
}
- var lastRepoID int64
- var lastPerm access_model.Permission
-
var issues []*issues_model.Issue
+
+ repoPerms := make(map[int64]access_model.Permission)
+ repoPerms[ctx.Repo.Repository.ID] = ctx.Repo.Permission
+
for i, depMeta := range deps {
if i < skip || i >= max {
continue
}
// Get the permissions for this repository
- perm := lastPerm
- if lastRepoID != depMeta.Repository.ID {
- if depMeta.Repository.ID == ctx.Repo.Repository.ID {
- perm = ctx.Repo.Permission
- } else {
- var err error
- perm, err = access_model.GetUserRepoPermission(ctx, &depMeta.Repository, ctx.Doer)
- if err != nil {
- ctx.ServerError("GetUserRepoPermission", err)
- return
- }
+ // If the repo ID exists in the map, return the exist permissions
+ // else get the permission and add it to the map
+ var perm access_model.Permission
+ existPerm, ok := repoPerms[depMeta.RepoID]
+ if ok {
+ perm = existPerm
+ } else {
+ var err error
+ perm, err = access_model.GetUserRepoPermission(ctx, &depMeta.Repository, ctx.Doer)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return
}
- lastRepoID = depMeta.Repository.ID
+ repoPerms[depMeta.RepoID] = perm
}
if !perm.CanReadIssuesOrPulls(depMeta.Issue.IsPull) {
diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go
index 29c99184e7..c886bd71b7 100644
--- a/routers/api/v1/repo/issue_reaction.go
+++ b/routers/api/v1/repo/issue_reaction.go
@@ -61,6 +61,12 @@ func GetIssueCommentReactions(ctx *context.APIContext) {
if err := comment.LoadIssue(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err)
+ return
+ }
+
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound()
+ return
}
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
@@ -190,9 +196,19 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp
return
}
- err = comment.LoadIssue(ctx)
- if err != nil {
+ if err = comment.LoadIssue(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue() failed", err)
+ return
+ }
+
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound()
+ return
+ }
+
+ if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
+ ctx.NotFound()
+ return
}
if comment.Issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) {
diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go
index 3dc5a60d1c..af48c40885 100644
--- a/routers/api/v1/repo/key.go
+++ b/routers/api/v1/repo/key.go
@@ -153,6 +153,12 @@ func GetDeployKey(ctx *context.APIContext) {
return
}
+ // this check make it more consistent
+ if key.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound()
+ return
+ }
+
if err = key.GetContent(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "GetContent", err)
return
diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go
index da470dfa74..9c2ed16d93 100644
--- a/routers/api/v1/repo/milestone.go
+++ b/routers/api/v1/repo/milestone.go
@@ -9,10 +9,12 @@ import (
"strconv"
"time"
+ "code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
"code.gitea.io/gitea/services/convert"
@@ -58,14 +60,21 @@ func ListMilestones(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- milestones, total, err := issues_model.GetMilestones(ctx, issues_model.GetMilestonesOption{
+ state := api.StateType(ctx.FormString("state"))
+ var isClosed util.OptionalBool
+ switch state {
+ case api.StateClosed, api.StateOpen:
+ isClosed = util.OptionalBoolOf(state == api.StateClosed)
+ }
+
+ milestones, total, err := db.FindAndCount[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
ListOptions: utils.GetListOptions(ctx),
RepoID: ctx.Repo.Repository.ID,
- State: api.StateType(ctx.FormString("state")),
+ IsClosed: isClosed,
Name: ctx.FormString("name"),
})
if err != nil {
- ctx.Error(http.StatusInternalServerError, "GetMilestones", err)
+ ctx.Error(http.StatusInternalServerError, "db.FindAndCount[issues_model.Milestone]", err)
return
}
diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go
index 72ddc758dc..26e0be301c 100644
--- a/routers/api/v1/repo/mirror.go
+++ b/routers/api/v1/repo/mirror.go
@@ -227,11 +227,18 @@ func GetPushMirrorByName(ctx *context.APIContext) {
mirrorName := ctx.Params(":name")
// Get push mirror of a specific repo by remoteName
- pushMirror, err := repo_model.GetPushMirror(ctx, repo_model.PushMirrorOptions{RepoID: ctx.Repo.Repository.ID, RemoteName: mirrorName})
+ pushMirror, exist, err := db.Get[repo_model.PushMirror](ctx, repo_model.PushMirrorOptions{
+ RepoID: ctx.Repo.Repository.ID,
+ RemoteName: mirrorName,
+ }.ToConds())
if err != nil {
- ctx.Error(http.StatusNotFound, "GetPushMirrors", err)
+ ctx.Error(http.StatusInternalServerError, "GetPushMirrors", err)
+ return
+ } else if !exist {
+ ctx.Error(http.StatusNotFound, "GetPushMirrors", nil)
return
}
+
m, err := convert.ToPushMirror(ctx, pushMirror)
if err != nil {
ctx.ServerError("GetPushMirrorByRemoteName", err)
@@ -368,7 +375,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro
RemoteAddress: remoteAddress,
}
- if err = repo_model.InsertPushMirror(ctx, pushMirror); err != nil {
+ if err = db.Insert(ctx, pushMirror); err != nil {
ctx.ServerError("InsertPushMirror", err)
return
}
diff --git a/routers/api/v1/repo/notes.go b/routers/api/v1/repo/notes.go
index 0b259703de..e7e00dae41 100644
--- a/routers/api/v1/repo/notes.go
+++ b/routers/api/v1/repo/notes.go
@@ -66,7 +66,7 @@ func getNote(ctx *context.APIContext, identifier string) {
return
}
- commitSHA, err := ctx.Repo.GitRepo.ConvertToSHA1(identifier)
+ commitID, err := ctx.Repo.GitRepo.ConvertToGitID(identifier)
if err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound(err)
@@ -77,7 +77,7 @@ func getNote(ctx *context.APIContext, identifier string) {
}
var note git.Note
- if err := git.GetNote(ctx, ctx.Repo.GitRepo, commitSHA.String(), ¬e); err != nil {
+ if err := git.GetNote(ctx, ctx.Repo.GitRepo, commitID.String(), ¬e); err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound(identifier)
return
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index d6b9dddd9d..b1cb7011f1 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -913,6 +913,10 @@ func MergePullRequest(ctx *context.APIContext) {
}
defer headRepo.Close()
}
+ if err := pull_service.RetargetChildrenOnMerge(ctx, ctx.Doer, pr); err != nil {
+ ctx.Error(http.StatusInternalServerError, "RetargetChildrenOnMerge", err)
+ return
+ }
if err := repo_service.DeleteBranch(ctx, ctx.Doer, pr.HeadRepo, headRepo, pr.HeadBranch); err != nil {
switch {
case git.IsErrBranchNotExist(err):
@@ -1329,17 +1333,16 @@ func GetPullRequestCommits(ctx *context.APIContext) {
userCache := make(map[string]*user_model.User)
- start, end := listOptions.GetStartEnd()
+ start, limit := listOptions.GetSkipTake()
- if end > totalNumberOfCommits {
- end = totalNumberOfCommits
- }
+ limit = min(limit, totalNumberOfCommits-start)
+ limit = max(limit, 0)
verification := ctx.FormString("verification") == "" || ctx.FormBool("verification")
files := ctx.FormString("files") == "" || ctx.FormBool("files")
- apiCommits := make([]*api.Commit, 0, end-start)
- for i := start; i < end; i++ {
+ apiCommits := make([]*api.Commit, 0, limit)
+ for i := start; i < start+limit; i++ {
apiCommit, err := convert.ToCommit(ctx, ctx.Repo.Repository, baseGitRepo, commits[i], userCache,
convert.ToCommitOptions{
Stat: true,
@@ -1477,19 +1480,14 @@ func GetPullRequestFiles(ctx *context.APIContext) {
totalNumberOfFiles := diff.NumFiles
totalNumberOfPages := int(math.Ceil(float64(totalNumberOfFiles) / float64(listOptions.PageSize)))
- start, end := listOptions.GetStartEnd()
+ start, limit := listOptions.GetSkipTake()
- if end > totalNumberOfFiles {
- end = totalNumberOfFiles
- }
+ limit = min(limit, totalNumberOfFiles-start)
- lenFiles := end - start
- if lenFiles < 0 {
- lenFiles = 0
- }
+ limit = max(limit, 0)
- apiFiles := make([]*api.ChangedFile, 0, lenFiles)
- for i := start; i < end; i++ {
+ apiFiles := make([]*api.ChangedFile, 0, limit)
+ for i := start; i < start+limit; i++ {
apiFiles = append(apiFiles, convert.ToChangedFile(diff.Files[i], pr.HeadRepo, endCommitID))
}
diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go
index 61e5bdd679..a41c5ba7d8 100644
--- a/routers/api/v1/repo/release.go
+++ b/routers/api/v1/repo/release.go
@@ -7,6 +7,7 @@ import (
"net/http"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
@@ -49,13 +50,12 @@ func GetRelease(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
id := ctx.ParamsInt64(":id")
- release, err := repo_model.GetReleaseByID(ctx, id)
+ release, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
- ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
+ ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err)
return
}
- if err != nil && repo_model.IsErrReleaseNotExist(err) ||
- release.IsTag || release.RepoID != ctx.Repo.Repository.ID {
+ if err != nil && repo_model.IsErrReleaseNotExist(err) || release.IsTag {
ctx.NotFound()
return
}
@@ -134,11 +134,6 @@ func ListReleases(ctx *context.APIContext) {
// in: query
// description: filter (exclude / include) pre-releases
// type: boolean
- // - name: per_page
- // in: query
- // description: page size of results, deprecated - use limit
- // type: integer
- // deprecated: true
// - name: page
// in: query
// description: page number of results to return (1-based)
@@ -153,9 +148,6 @@ func ListReleases(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
listOptions := utils.GetListOptions(ctx)
- if listOptions.PageSize == 0 && ctx.FormInt("per_page") != 0 {
- listOptions.PageSize = ctx.FormInt("per_page")
- }
opts := repo_model.FindReleasesOptions{
ListOptions: listOptions,
@@ -163,9 +155,10 @@ func ListReleases(ctx *context.APIContext) {
IncludeTags: false,
IsDraft: ctx.FormOptionalBool("draft"),
IsPreRelease: ctx.FormOptionalBool("pre-release"),
+ RepoID: ctx.Repo.Repository.ID,
}
- releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts)
+ releases, err := db.Find[repo_model.Release](ctx, opts)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetReleasesByRepoID", err)
return
@@ -179,7 +172,7 @@ func ListReleases(ctx *context.APIContext) {
rels[i] = convert.ToAPIRelease(ctx, ctx.Repo.Repository, release)
}
- filteredCount, err := repo_model.CountReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts)
+ filteredCount, err := db.Count[repo_model.Release](ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
@@ -315,13 +308,12 @@ func EditRelease(ctx *context.APIContext) {
form := web.GetForm(ctx).(*api.EditReleaseOption)
id := ctx.ParamsInt64(":id")
- rel, err := repo_model.GetReleaseByID(ctx, id)
+ rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
- ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
+ ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err)
return
}
- if err != nil && repo_model.IsErrReleaseNotExist(err) ||
- rel.IsTag || rel.RepoID != ctx.Repo.Repository.ID {
+ if err != nil && repo_model.IsErrReleaseNotExist(err) || rel.IsTag {
ctx.NotFound()
return
}
@@ -393,17 +385,16 @@ func DeleteRelease(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
id := ctx.ParamsInt64(":id")
- rel, err := repo_model.GetReleaseByID(ctx, id)
+ rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, id)
if err != nil && !repo_model.IsErrReleaseNotExist(err) {
- ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
+ ctx.Error(http.StatusInternalServerError, "GetReleaseForRepoByID", err)
return
}
- if err != nil && repo_model.IsErrReleaseNotExist(err) ||
- rel.IsTag || rel.RepoID != ctx.Repo.Repository.ID {
+ if err != nil && repo_model.IsErrReleaseNotExist(err) || rel.IsTag {
ctx.NotFound()
return
}
- if err := release_service.DeleteReleaseByID(ctx, id, ctx.Doer, false); err != nil {
+ if err := release_service.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, false); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
return
diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go
index 168ef550c5..c36bf12e6d 100644
--- a/routers/api/v1/repo/release_attachment.go
+++ b/routers/api/v1/repo/release_attachment.go
@@ -17,6 +17,23 @@ import (
"code.gitea.io/gitea/services/convert"
)
+func checkReleaseMatchRepo(ctx *context.APIContext, releaseID int64) bool {
+ release, err := repo_model.GetReleaseByID(ctx, releaseID)
+ if err != nil {
+ if repo_model.IsErrReleaseNotExist(err) {
+ ctx.NotFound()
+ return false
+ }
+ ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
+ return false
+ }
+ if release.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound()
+ return false
+ }
+ return true
+}
+
// GetReleaseAttachment gets a single attachment of the release
func GetReleaseAttachment(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/releases/{id}/assets/{attachment_id} repository repoGetReleaseAttachment
@@ -54,6 +71,10 @@ func GetReleaseAttachment(ctx *context.APIContext) {
// "$ref": "#/responses/notFound"
releaseID := ctx.ParamsInt64(":id")
+ if !checkReleaseMatchRepo(ctx, releaseID) {
+ return
+ }
+
attachID := ctx.ParamsInt64(":attachment_id")
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
if err != nil {
@@ -176,13 +197,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
// Check if release exists an load release
releaseID := ctx.ParamsInt64(":id")
- release, err := repo_model.GetReleaseByID(ctx, releaseID)
- if err != nil {
- if repo_model.IsErrReleaseNotExist(err) {
- ctx.NotFound()
- return
- }
- ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err)
+ if !checkReleaseMatchRepo(ctx, releaseID) {
return
}
@@ -203,7 +218,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
attach, err := attachment.UploadAttachment(ctx, file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{
Name: filename,
UploaderID: ctx.Doer.ID,
- RepoID: release.RepoID,
+ RepoID: ctx.Repo.Repository.ID,
ReleaseID: releaseID,
})
if err != nil {
@@ -264,6 +279,10 @@ func EditReleaseAttachment(ctx *context.APIContext) {
// Check if release exists an load release
releaseID := ctx.ParamsInt64(":id")
+ if !checkReleaseMatchRepo(ctx, releaseID) {
+ return
+ }
+
attachID := ctx.ParamsInt64(":attachment_id")
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
if err != nil {
@@ -328,6 +347,10 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
// Check if release exists an load release
releaseID := ctx.ParamsInt64(":id")
+ if !checkReleaseMatchRepo(ctx, releaseID) {
+ return
+ }
+
attachID := ctx.ParamsInt64(":attachment_id")
attach, err := repo_model.GetAttachmentByID(ctx, attachID)
if err != nil {
diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go
index 926a713c94..9f2098df06 100644
--- a/routers/api/v1/repo/release_tags.go
+++ b/routers/api/v1/repo/release_tags.go
@@ -112,7 +112,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) {
return
}
- if err = releaseservice.DeleteReleaseByID(ctx, release.ID, ctx.Doer, false); err != nil {
+ if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, release, ctx.Doer, false); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
return
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index 64c41d3a97..8ce03cf29c 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -242,17 +242,18 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
}
repo, err := repo_service.CreateRepository(ctx, ctx.Doer, owner, repo_service.CreateRepoOptions{
- Name: opt.Name,
- Description: opt.Description,
- IssueLabels: opt.IssueLabels,
- Gitignores: opt.Gitignores,
- License: opt.License,
- Readme: opt.Readme,
- IsPrivate: opt.Private,
- AutoInit: opt.AutoInit,
- DefaultBranch: opt.DefaultBranch,
- TrustModel: repo_model.ToTrustModel(opt.TrustModel),
- IsTemplate: opt.Template,
+ Name: opt.Name,
+ Description: opt.Description,
+ IssueLabels: opt.IssueLabels,
+ Gitignores: opt.Gitignores,
+ License: opt.License,
+ Readme: opt.Readme,
+ IsPrivate: opt.Private,
+ AutoInit: opt.AutoInit,
+ DefaultBranch: opt.DefaultBranch,
+ TrustModel: repo_model.ToTrustModel(opt.TrustModel),
+ IsTemplate: opt.Template,
+ ObjectFormatName: git.Sha1ObjectFormat.Name(),
})
if err != nil {
if repo_model.IsErrRepoAlreadyExist(err) {
@@ -982,7 +983,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
}
if len(units)+len(deleteUnitTypes) > 0 {
- if err := repo_model.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
+ if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err)
return err
}
diff --git a/routers/api/v1/repo/runners.go b/routers/api/v1/repo/runners.go
new file mode 100644
index 0000000000..0a2bbf8117
--- /dev/null
+++ b/routers/api/v1/repo/runners.go
@@ -0,0 +1,34 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repo
+
+import (
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/routers/api/v1/shared"
+)
+
+// GetRegistrationToken returns the token to register repo runners
+func GetRegistrationToken(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/runners/registration-token repository repoGetRunnerRegistrationToken
+ // ---
+ // summary: Get a repository's actions runner registration token
+ // produces:
+ // - application/json
+ // parameters:
+ // - name: owner
+ // in: path
+ // description: owner of the repo
+ // type: string
+ // required: true
+ // - name: repo
+ // in: path
+ // description: name of the repo
+ // type: string
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/RegistrationToken"
+
+ shared.GetRegistrationToken(ctx, ctx.Repo.Repository.OwnerID, ctx.Repo.Repository.ID)
+}
diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go
index 926d91ca81..b4edf0608c 100644
--- a/routers/api/v1/repo/status.go
+++ b/routers/api/v1/repo/status.go
@@ -7,6 +7,7 @@ import (
"fmt"
"net/http"
+ "code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
@@ -194,8 +195,10 @@ func getCommitStatuses(ctx *context.APIContext, sha string) {
listOptions := utils.GetListOptions(ctx)
- statuses, maxResults, err := git_model.GetCommitStatuses(ctx, repo, sha, &git_model.CommitStatusOptions{
+ statuses, maxResults, err := db.FindAndCount[git_model.CommitStatus](ctx, &git_model.CommitStatusOptions{
ListOptions: listOptions,
+ RepoID: repo.ID,
+ SHA: sha,
SortType: ctx.FormTrim("sort"),
State: ctx.FormTrim("state"),
})
diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go
index dbc8df0ef8..2f19f95e66 100644
--- a/routers/api/v1/repo/tag.go
+++ b/routers/api/v1/repo/tag.go
@@ -272,7 +272,7 @@ func DeleteTag(ctx *context.APIContext) {
return
}
- if err = releaseservice.DeleteReleaseByID(ctx, tag.ID, ctx.Doer, true); err != nil {
+ if err = releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, tag, ctx.Doer, true); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Error(http.StatusMethodNotAllowed, "delTag", "user not allowed to delete protected tag")
return
diff --git a/routers/api/v1/shared/runners.go b/routers/api/v1/shared/runners.go
new file mode 100644
index 0000000000..a342bd4b63
--- /dev/null
+++ b/routers/api/v1/shared/runners.go
@@ -0,0 +1,32 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package shared
+
+import (
+ "errors"
+ "net/http"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/util"
+)
+
+// RegistrationToken is response related to registeration token
+// swagger:response RegistrationToken
+type RegistrationToken struct {
+ Token string `json:"token"`
+}
+
+func GetRegistrationToken(ctx *context.APIContext, ownerID, repoID int64) {
+ token, err := actions_model.GetLatestRunnerToken(ctx, ownerID, repoID)
+ if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) {
+ token, err = actions_model.NewRunnerToken(ctx, ownerID, repoID)
+ }
+ if err != nil {
+ ctx.InternalServerError(err)
+ return
+ }
+
+ ctx.JSON(http.StatusOK, RegistrationToken{Token: token.Token})
+}
diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go
index edbc1d17b4..f045fb4d5d 100644
--- a/routers/api/v1/user/app.go
+++ b/routers/api/v1/user/app.go
@@ -342,6 +342,10 @@ func GetOauth2Application(ctx *context.APIContext) {
}
return
}
+ if app.UID != ctx.Doer.ID {
+ ctx.NotFound()
+ return
+ }
app.ClientSecret = ""
diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go
index 404b1d221e..234da5dfdc 100644
--- a/routers/api/v1/user/gpg_key.go
+++ b/routers/api/v1/user/gpg_key.go
@@ -18,23 +18,25 @@ import (
)
func listGPGKeys(ctx *context.APIContext, uid int64, listOptions db.ListOptions) {
- keys, err := asymkey_model.ListGPGKeys(ctx, uid, listOptions)
+ keys, total, err := db.FindAndCount[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ ListOptions: listOptions,
+ OwnerID: uid,
+ })
if err != nil {
ctx.Error(http.StatusInternalServerError, "ListGPGKeys", err)
return
}
+ if err := asymkey_model.GPGKeyList(keys).LoadSubKeys(ctx); err != nil {
+ ctx.Error(http.StatusInternalServerError, "ListGPGKeys", err)
+ return
+ }
+
apiKeys := make([]*api.GPGKey, len(keys))
for i := range keys {
apiKeys[i] = convert.ToGPGKey(keys[i])
}
- total, err := asymkey_model.CountUserGPGKeys(ctx, uid)
- if err != nil {
- ctx.InternalServerError(err)
- return
- }
-
ctx.SetTotalCountHeader(total)
ctx.JSON(http.StatusOK, &apiKeys)
}
@@ -112,7 +114,7 @@ func GetGPGKey(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- key, err := asymkey_model.GetGPGKeyByID(ctx, ctx.ParamsInt64(":id"))
+ key, err := asymkey_model.GetGPGKeyForUserByID(ctx, ctx.Doer.ID, ctx.ParamsInt64(":id"))
if err != nil {
if asymkey_model.IsErrGPGKeyNotExist(err) {
ctx.NotFound()
@@ -121,6 +123,10 @@ func GetGPGKey(ctx *context.APIContext) {
}
return
}
+ if err := key.LoadSubKeys(ctx); err != nil {
+ ctx.Error(http.StatusInternalServerError, "LoadSubKeys", err)
+ return
+ }
ctx.JSON(http.StatusOK, convert.ToGPGKey(key))
}
@@ -198,7 +204,10 @@ func VerifyUserGPGKey(ctx *context.APIContext) {
ctx.Error(http.StatusInternalServerError, "VerifyUserGPGKey", err)
}
- key, err := asymkey_model.GetGPGKeysByKeyID(ctx, form.KeyID)
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ KeyID: form.KeyID,
+ IncludeSubKeys: true,
+ })
if err != nil {
if asymkey_model.IsErrGPGKeyNotExist(err) {
ctx.NotFound()
@@ -207,7 +216,7 @@ func VerifyUserGPGKey(ctx *context.APIContext) {
}
return
}
- ctx.JSON(http.StatusOK, convert.ToGPGKey(key[0]))
+ ctx.JSON(http.StatusOK, convert.ToGPGKey(keys[0]))
}
// swagger:parameters userCurrentPostGPGKey
diff --git a/routers/api/v1/user/hook.go b/routers/api/v1/user/hook.go
index 50be519c81..e87385e4a2 100644
--- a/routers/api/v1/user/hook.go
+++ b/routers/api/v1/user/hook.go
@@ -62,6 +62,11 @@ func GetHook(ctx *context.APIContext) {
return
}
+ if !ctx.Doer.IsAdmin && hook.OwnerID != ctx.Doer.ID {
+ ctx.NotFound()
+ return
+ }
+
apiHook, err := webhook_service.ToHook(ctx.Doer.HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
diff --git a/routers/api/v1/user/runners.go b/routers/api/v1/user/runners.go
new file mode 100644
index 0000000000..51556ae0fb
--- /dev/null
+++ b/routers/api/v1/user/runners.go
@@ -0,0 +1,26 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package user
+
+import (
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/routers/api/v1/shared"
+)
+
+// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
+
+// GetRegistrationToken returns the token to register user runners
+func GetRegistrationToken(ctx *context.APIContext) {
+ // swagger:operation GET /user/actions/runners/registration-token user userGetRunnerRegistrationToken
+ // ---
+ // summary: Get an user's actions runner registration token
+ // produces:
+ // - application/json
+ // parameters:
+ // responses:
+ // "200":
+ // "$ref": "#/responses/RegistrationToken"
+
+ shared.GetRegistrationToken(ctx, ctx.Doer.ID, 0)
+}
diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go
index 32f5c85319..39714e343f 100644
--- a/routers/api/v1/utils/git.go
+++ b/routers/api/v1/utils/git.go
@@ -69,27 +69,28 @@ func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (str
return "", "", nil
}
-// ConvertToSHA1 returns a full-length SHA1 from a potential ID string
-func ConvertToSHA1(ctx gocontext.Context, repo *context.Repository, commitID string) (git.SHA1, error) {
- if len(commitID) == git.SHAFullLength && git.IsValidSHAPattern(commitID) {
- sha1, err := git.NewIDFromString(commitID)
+// ConvertToObjectID returns a full-length SHA1 from a potential ID string
+func ConvertToObjectID(ctx gocontext.Context, repo *context.Repository, commitID string) (git.ObjectID, error) {
+ objectFormat, _ := repo.GitRepo.GetObjectFormat()
+ if len(commitID) == objectFormat.FullLength() && objectFormat.IsValid(commitID) {
+ sha, err := git.NewIDFromString(commitID)
if err == nil {
- return sha1, nil
+ return sha, nil
}
}
gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repo.Repository.RepoPath())
if err != nil {
- return git.SHA1{}, fmt.Errorf("RepositoryFromContextOrOpen: %w", err)
+ return objectFormat.EmptyObjectID(), fmt.Errorf("RepositoryFromContextOrOpen: %w", err)
}
defer closer.Close()
- return gitRepo.ConvertToSHA1(commitID)
+ return gitRepo.ConvertToGitID(commitID)
}
// MustConvertToSHA1 returns a full-length SHA1 string from a potential ID string, or returns origin input if it can't convert to SHA1
func MustConvertToSHA1(ctx gocontext.Context, repo *context.Repository, commitID string) string {
- sha, err := ConvertToSHA1(ctx, repo, commitID)
+ sha, err := ConvertToObjectID(ctx, repo, commitID)
if err != nil {
return commitID
}
diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go
index 1207be25ac..28b21ab8db 100644
--- a/routers/api/v1/utils/hook.go
+++ b/routers/api/v1/utils/hook.go
@@ -6,6 +6,7 @@ package utils
import (
"fmt"
"net/http"
+ "strconv"
"strings"
"code.gitea.io/gitea/models/db"
@@ -157,6 +158,7 @@ func pullHook(events []string, event string) bool {
// addHook add the hook specified by `form`, `ownerID` and `repoID`. If there is
// an error, write to `ctx` accordingly. Return (webhook, ok)
func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoID int64) (*webhook.Webhook, bool) {
+ var isSystemWebhook bool
if !checkCreateHookOption(ctx, form) {
return nil, false
}
@@ -164,13 +166,22 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoI
if len(form.Events) == 0 {
form.Events = []string{"push"}
}
+ if form.Config["is_system_webhook"] != "" {
+ sw, err := strconv.ParseBool(form.Config["is_system_webhook"])
+ if err != nil {
+ ctx.Error(http.StatusUnprocessableEntity, "", "Invalid is_system_webhook value")
+ return nil, false
+ }
+ isSystemWebhook = sw
+ }
w := &webhook.Webhook{
- OwnerID: ownerID,
- RepoID: repoID,
- URL: form.Config["url"],
- ContentType: webhook.ToHookContentType(form.Config["content_type"]),
- Secret: form.Config["secret"],
- HTTPMethod: "POST",
+ OwnerID: ownerID,
+ RepoID: repoID,
+ URL: form.Config["url"],
+ ContentType: webhook.ToHookContentType(form.Config["content_type"]),
+ Secret: form.Config["secret"],
+ HTTPMethod: "POST",
+ IsSystemWebhook: isSystemWebhook,
HookEvent: &webhook_module.HookEvent{
ChooseEvents: true,
HookEvents: webhook_module.HookEvents{
diff --git a/routers/common/db.go b/routers/common/db.go
index 547f727ce2..a67c9582fa 100644
--- a/routers/common/db.go
+++ b/routers/common/db.go
@@ -37,7 +37,6 @@ func InitDBEngine(ctx context.Context) (err error) {
log.Info("Backing off for %d seconds", int64(setting.Database.DBConnectBackoff/time.Second))
time.Sleep(setting.Database.DBConnectBackoff)
}
- db.HasEngine = true
config.SetDynGetter(system_model.NewDatabaseDynKeyGetter())
return nil
}
diff --git a/routers/common/markup.go b/routers/common/markup.go
index aaedc13de9..a1c2c37ac0 100644
--- a/routers/common/markup.go
+++ b/routers/common/markup.go
@@ -32,8 +32,10 @@ func RenderMarkup(ctx *context.Base, repo *context.Repository, mode, text, urlPr
case "markdown":
// Raw markdown
if err := markdown.RenderRaw(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: urlPrefix,
+ },
}, strings.NewReader(text), ctx.Resp); err != nil {
ctx.Error(http.StatusInternalServerError, err.Error())
}
@@ -75,8 +77,10 @@ func RenderMarkup(ctx *context.Base, repo *context.Repository, mode, text, urlPr
}
if err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: urlPrefix,
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: urlPrefix,
+ },
Metas: meta,
IsWiki: wiki,
Type: markupType,
diff --git a/routers/init.go b/routers/init.go
index c1cfe26bc4..ee98aedb16 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -118,7 +118,7 @@ func InitWebInstalled(ctx context.Context) {
mustInit(storage.Init)
mailer.NewContext(ctx)
- mustInit(cache.NewContext)
+ mustInit(cache.Init)
mustInit(feed_service.Init)
mustInit(uinotification.Init)
mustInitCtx(ctx, archiver.Init)
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index d5a46e4e7f..1b274ae154 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -159,8 +159,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
// If we've pushed a branch (and not deleted it)
- if newCommitID != git.EmptySHA && refFullName.IsBranch() {
-
+ if git.IsEmptyCommitID(newCommitID) && refFullName.IsBranch() {
// First ensure we have the repository loaded, we're allowed pulls requests and we can get the base repo
if repo == nil {
repo = loadRepository(ctx, ownerName, repoName)
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index 4399e49851..90d8287f06 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -145,8 +145,9 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
repo := ctx.Repo.Repository
gitRepo := ctx.Repo.GitRepo
+ objectFormat, _ := gitRepo.GetObjectFormat()
- if branchName == repo.DefaultBranch && newCommitID == git.EmptySHA {
+ if branchName == repo.DefaultBranch && newCommitID == objectFormat.EmptyObjectID().String() {
log.Warn("Forbidden: Branch: %s is the default branch in %-v and cannot be deleted", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is the default branch and cannot be deleted", branchName),
@@ -174,7 +175,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
// First of all we need to enforce absolutely:
//
// 1. Detect and prevent deletion of the branch
- if newCommitID == git.EmptySHA {
+ if newCommitID == objectFormat.EmptyObjectID().String() {
log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo)
ctx.JSON(http.StatusForbidden, private.Response{
UserMsg: fmt.Sprintf("branch %s is protected from deletion", branchName),
@@ -183,7 +184,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
}
// 2. Disallow force pushes to protected branches
- if git.EmptySHA != oldCommitID {
+ if oldCommitID != objectFormat.EmptyObjectID().String() {
output, _, err := git.NewCommand(ctx, "rev-list", "--max-count=1").AddDynamicArguments(oldCommitID, "^"+newCommitID).RunStdString(&git.RunOpts{Dir: repo.RepoPath(), Env: ctx.env})
if err != nil {
log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err)
diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go
index 8604789529..42b8e5abed 100644
--- a/routers/private/hook_verification.go
+++ b/routers/private/hook_verification.go
@@ -29,7 +29,8 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
}()
var command *git.Command
- if oldCommitID == git.EmptySHA {
+ objectFormat, _ := repo.GetObjectFormat()
+ if oldCommitID == objectFormat.EmptyObjectID().String() {
// When creating a new branch, the oldCommitID is empty, by using "newCommitID --not --all":
// List commits that are reachable by following the newCommitID, exclude "all" existing heads/tags commits
// So, it only lists the new commits received, doesn't list the commits already present in the receiving repository
@@ -82,7 +83,8 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
_ = stdoutReader.Close()
_ = stdoutWriter.Close()
}()
- hash := git.MustIDFromString(sha)
+
+ commitID := git.MustIDFromString(sha)
return git.NewCommand(repo.Ctx, "cat-file", "commit").AddDynamicArguments(sha).
Run(&git.RunOpts{
@@ -91,7 +93,7 @@ func readAndVerifyCommit(sha string, repo *git.Repository, env []string) error {
Stdout: stdoutWriter,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
- commit, err := git.CommitFromReader(repo, hash, stdoutReader)
+ commit, err := git.CommitFromReader(repo, commitID, stdoutReader)
if err != nil {
return err
}
diff --git a/routers/private/hook_verification_test.go b/routers/private/hook_verification_test.go
index cd0c05ff50..04445b8eaf 100644
--- a/routers/private/hook_verification_test.go
+++ b/routers/private/hook_verification_test.go
@@ -22,14 +22,17 @@ func TestVerifyCommits(t *testing.T) {
defer gitRepo.Close()
assert.NoError(t, err)
+ objectFormat, err := gitRepo.GetObjectFormat()
+ assert.NoError(t, err)
+
testCases := []struct {
base, head string
verified bool
}{
{"72920278f2f999e3005801e5d5b8ab8139d3641c", "d766f2917716d45be24bfa968b8409544941be32", true},
- {git.EmptySHA, "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit
+ {objectFormat.EmptyObjectID().String(), "93eac826f6188f34646cea81bf426aa5ba7d3bfe", true}, // New branch with verified commit
{"9779d17a04f1e2640583d35703c62460b2d86e0a", "72920278f2f999e3005801e5d5b8ab8139d3641c", false},
- {git.EmptySHA, "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit
+ {objectFormat.EmptyObjectID().String(), "9ce3f779ae33f31fce17fac3c512047b75d7498b", false}, // New branch with unverified commit
}
for _, tc := range testCases {
diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go
index 1838fe190c..5559b6af88 100644
--- a/routers/web/admin/admin.go
+++ b/routers/web/admin/admin.go
@@ -12,6 +12,7 @@ import (
"time"
activities_model "code.gitea.io/gitea/models/activities"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/graceful"
@@ -27,6 +28,7 @@ import (
const (
tplDashboard base.TplName = "admin/dashboard"
+ tplSelfCheck base.TplName = "admin/self_check"
tplCron base.TplName = "admin/cron"
tplQueue base.TplName = "admin/queue"
tplStacktrace base.TplName = "admin/stacktrace"
@@ -172,6 +174,33 @@ func DashboardPost(ctx *context.Context) {
}
}
+func SelfCheck(ctx *context.Context) {
+ ctx.Data["PageIsAdminSelfCheck"] = true
+ r, err := db.CheckCollationsDefaultEngine()
+ if err != nil {
+ ctx.Flash.Error(fmt.Sprintf("CheckCollationsDefaultEngine: %v", err), true)
+ }
+
+ if r != nil {
+ ctx.Data["DatabaseType"] = setting.Database.Type
+ ctx.Data["DatabaseCheckResult"] = r
+ hasProblem := false
+ if !r.CollationEquals(r.DatabaseCollation, r.ExpectedCollation) {
+ ctx.Data["DatabaseCheckCollationMismatch"] = true
+ hasProblem = true
+ }
+ if !r.IsCollationCaseSensitive(r.DatabaseCollation) {
+ ctx.Data["DatabaseCheckCollationCaseInsensitive"] = true
+ hasProblem = true
+ }
+ ctx.Data["DatabaseCheckInconsistentCollationColumns"] = r.InconsistentCollationColumns
+ hasProblem = hasProblem || len(r.InconsistentCollationColumns) > 0
+
+ ctx.Data["DatabaseCheckHasProblems"] = hasProblem
+ }
+ ctx.HTML(http.StatusOK, tplSelfCheck)
+}
+
func CronTasks(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.monitor.cron")
ctx.Data["PageIsAdminMonitorCron"] = true
diff --git a/routers/web/admin/diagnosis.go b/routers/web/admin/diagnosis.go
index 5637894e6d..2d550125d5 100644
--- a/routers/web/admin/diagnosis.go
+++ b/routers/web/admin/diagnosis.go
@@ -58,4 +58,11 @@ func MonitorDiagnosis(ctx *context.Context) {
return
}
_ = pprof.Lookup("goroutine").WriteTo(f, 1)
+
+ f, err = zipWriter.CreateHeader(&zip.FileHeader{Name: "heap.dat", Method: zip.Deflate, Modified: time.Now()})
+ if err != nil {
+ ctx.ServerError("Failed to create zip file", err)
+ return
+ }
+ _ = pprof.Lookup("heap").WriteTo(f, 0)
}
diff --git a/routers/web/admin/notice.go b/routers/web/admin/notice.go
index 99039a2a9f..e1cb578d05 100644
--- a/routers/web/admin/notice.go
+++ b/routers/web/admin/notice.go
@@ -8,6 +8,7 @@ import (
"net/http"
"strconv"
+ "code.gitea.io/gitea/models/db"
system_model "code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
@@ -55,7 +56,7 @@ func DeleteNotices(ctx *context.Context) {
}
}
- if err := system_model.DeleteNoticesByIDs(ctx, ids); err != nil {
+ if err := db.DeleteByIDs[system_model.Notice](ctx, ids...); err != nil {
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
ctx.Status(http.StatusInternalServerError)
} else {
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index 44c4fa7512..8f6995b96f 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -436,6 +436,12 @@ func EditUserPost(ctx *context.Context) {
}
+ // Check whether user is the last admin
+ if !form.Admin && user_model.IsLastAdminUser(ctx, u) {
+ ctx.RenderWithErr(ctx.Tr("auth.last_admin"), tplUserEdit, &form)
+ return
+ }
+
u.LoginName = form.LoginName
u.FullName = form.FullName
emailChanged := !strings.EqualFold(u.Email, form.Email)
@@ -503,7 +509,10 @@ func DeleteUser(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
case models.IsErrUserOwnPackages(err):
ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages"))
- ctx.Redirect(setting.AppSubURL + "/admin/users/" + ctx.Params(":userid"))
+ ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
+ case models.IsErrDeleteLastAdminUser(err):
+ ctx.Flash.Error(ctx.Tr("auth.last_admin"))
+ ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.Params(":userid")))
default:
ctx.ServerError("DeleteUser", err)
}
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index 0ea91fc759..474bae98e4 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -45,10 +45,6 @@ const (
// autoSignIn reads cookie and try to auto-login.
func autoSignIn(ctx *context.Context) (bool, error) {
- if !db.HasEngine {
- return false, nil
- }
-
isSucceed := false
defer func() {
if !isSucceed {
@@ -145,7 +141,11 @@ func CheckAutoLogin(ctx *context.Context) bool {
if isSucceed {
middleware.DeleteRedirectToCookie(ctx.Resp)
- ctx.RedirectToFirst(redirectTo, setting.AppSubURL+string(setting.LandingPageURL))
+ nextRedirectTo := setting.AppSubURL + string(setting.LandingPageURL)
+ if setting.LandingPageURL == setting.LandingPageLogin {
+ nextRedirectTo = setting.AppSubURL + "/" // do not cycle-redirect to the login page
+ }
+ ctx.RedirectToFirst(redirectTo, nextRedirectTo)
return true
}
@@ -368,14 +368,14 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
return setting.AppSubURL + "/"
}
-func getUserName(gothUser *goth.User) string {
+func getUserName(gothUser *goth.User) (string, error) {
switch setting.OAuth2Client.Username {
case setting.OAuth2UsernameEmail:
- return strings.Split(gothUser.Email, "@")[0]
+ return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0])
case setting.OAuth2UsernameNickname:
- return gothUser.NickName
+ return user_model.NormalizeUserName(gothUser.NickName)
default: // OAuth2UsernameUserid
- return gothUser.UserID
+ return gothUser.UserID, nil
}
}
@@ -622,10 +622,8 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
ctx.HTML(http.StatusOK, TplActivate)
- if setting.CacheService.Enabled {
- if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
- log.Error("Set cache(MailResendLimit) fail: %v", err)
- }
+ if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
+ log.Error("Set cache(MailResendLimit) fail: %v", err)
}
return false
}
@@ -645,16 +643,14 @@ func Activate(ctx *context.Context) {
}
// Resend confirmation email.
if setting.Service.RegisterEmailConfirm {
- if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) {
+ if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) {
ctx.Data["ResendLimited"] = true
} else {
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
- if setting.CacheService.Enabled {
- if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
- log.Error("Set cache(MailResendLimit) fail: %v", err)
- }
+ if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
+ log.Error("Set cache(MailResendLimit) fail: %v", err)
}
}
} else {
@@ -789,7 +785,7 @@ func ActivateEmail(ctx *context.Context) {
if u, err := user_model.GetUserByID(ctx, email.UID); err != nil {
log.Warn("GetUserByID: %d", email.UID)
- } else if setting.CacheService.Enabled {
+ } else {
// Allow user to validate more emails
_ = ctx.Cache.Delete("MailResendLimit_" + u.LowerName)
}
diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go
index f41590dc13..1d94e52fe3 100644
--- a/routers/web/auth/linkaccount.go
+++ b/routers/web/auth/linkaccount.go
@@ -55,7 +55,11 @@ func LinkAccount(ctx *context.Context) {
}
gu, _ := gothUser.(goth.User)
- uname := getUserName(&gu)
+ uname, err := getUserName(&gu)
+ if err != nil {
+ ctx.ServerError("UserSignIn", err)
+ return
+ }
email := gu.Email
ctx.Data["user_name"] = uname
ctx.Data["email"] = email
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index 21d82cea45..00305a36ee 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -970,8 +970,13 @@ func SignInOAuthCallback(ctx *context.Context) {
ctx.ServerError("CreateUser", err)
return
}
+ uname, err := getUserName(&gothUser)
+ if err != nil {
+ ctx.ServerError("UserSignIn", err)
+ return
+ }
u = &user_model.User{
- Name: getUserName(&gothUser),
+ Name: uname,
FullName: gothUser.Name,
Email: gothUser.Email,
LoginType: auth.OAuth2,
diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go
index bdfa8c4025..def9c2bcaa 100644
--- a/routers/web/auth/password.go
+++ b/routers/web/auth/password.go
@@ -79,7 +79,7 @@ func ForgotPasswdPost(ctx *context.Context) {
return
}
- if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+u.LowerName) {
+ if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) {
ctx.Data["ResendLimited"] = true
ctx.HTML(http.StatusOK, tplForgotPassword)
return
@@ -87,10 +87,8 @@ func ForgotPasswdPost(ctx *context.Context) {
mailer.SendResetPasswordMail(u)
- if setting.CacheService.Enabled {
- if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
- log.Error("Set cache(MailResendLimit) fail: %v", err)
- }
+ if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
+ log.Error("Set cache(MailResendLimit) fail: %v", err)
}
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale)
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index 4d4918a8fd..95b1062253 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -51,9 +51,11 @@ func toReleaseLink(ctx *context.Context, act *activities_model.Action) string {
// If rendering fails, the original markdown text is returned
func renderMarkdown(ctx *context.Context, act *activities_model.Action, content string) string {
markdownCtx := &markup.RenderContext{
- Ctx: ctx,
- URLPrefix: act.GetRepoLink(ctx),
- Type: markdown.MarkupName,
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: act.GetRepoLink(ctx),
+ },
+ Type: markdown.MarkupName,
Metas: map[string]string{
"user": act.GetRepoUserName(ctx),
"repo": act.GetRepoName(ctx),
@@ -199,7 +201,6 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
switch act.OpType {
case activities_model.ActionCommitRepo, activities_model.ActionMirrorSyncPush:
push := templates.ActionContent2Commits(act)
- repoLink := act.GetRepoAbsoluteLink(ctx)
for _, commit := range push.Commits {
if len(desc) != 0 {
@@ -208,7 +209,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
desc += fmt.Sprintf("%s\n%s",
html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(ctx), commit.Sha1)),
commit.Sha1,
- templates.RenderCommitMessage(ctx, commit.Message, repoLink, nil),
+ templates.RenderCommitMessage(ctx, commit.Message, nil),
)
}
@@ -288,9 +289,11 @@ func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, i
link := &feeds.Link{Href: rel.HTMLURL()}
content, err = markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: rel.Repo.Link(),
- Metas: rel.Repo.ComposeMetas(ctx),
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: rel.Repo.Link(),
+ },
+ Metas: rel.Repo.ComposeMetas(ctx),
}, rel.Note)
if err != nil {
diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go
index ce86727e24..04f84c0c8d 100644
--- a/routers/web/feed/profile.go
+++ b/routers/web/feed/profile.go
@@ -42,8 +42,10 @@ func showUserFeed(ctx *context.Context, formatType string) {
}
ctxUserDescription, err := markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: ctx.ContextUser.HTMLURL(),
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.ContextUser.HTMLURL(),
+ },
Metas: map[string]string{
"user": ctx.ContextUser.GetDisplayName(),
},
diff --git a/routers/web/feed/release.go b/routers/web/feed/release.go
index fbfa11c63e..57b0c92766 100644
--- a/routers/web/feed/release.go
+++ b/routers/web/feed/release.go
@@ -6,6 +6,7 @@ package feed
import (
"time"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/context"
@@ -14,8 +15,9 @@ import (
// shows tags and/or releases on the repo as RSS / Atom feed
func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleasesOnly bool, formatType string) {
- releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{
+ releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
IncludeTags: !isReleasesOnly,
+ RepoID: ctx.Repo.Repository.ID,
})
if err != nil {
ctx.ServerError("GetReleasesByRepoID", err)
diff --git a/routers/web/githttp.go b/routers/web/githttp.go
index b2fb5b472f..8d0d1ce03a 100644
--- a/routers/web/githttp.go
+++ b/routers/web/githttp.go
@@ -28,16 +28,16 @@ func requireSignIn(ctx *context.Context) {
func gitHTTPRouters(m *web.Route) {
m.Group("", func() {
- m.PostOptions("/git-upload-pack", repo.ServiceUploadPack)
- m.PostOptions("/git-receive-pack", repo.ServiceReceivePack)
- m.GetOptions("/info/refs", repo.GetInfoRefs)
- m.GetOptions("/HEAD", repo.GetTextFile("HEAD"))
- m.GetOptions("/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
- m.GetOptions("/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
- m.GetOptions("/objects/info/packs", repo.GetInfoPacks)
- m.GetOptions("/objects/info/{file:[^/]*}", repo.GetTextFile(""))
- m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
- m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
- m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
+ m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
+ m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
+ m.Methods("GET,OPTIONS", "/info/refs", repo.GetInfoRefs)
+ m.Methods("GET,OPTIONS", "/HEAD", repo.GetTextFile("HEAD"))
+ m.Methods("GET,OPTIONS", "/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
+ m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
+ m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks)
+ m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile(""))
+ m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
+ m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
+ m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
}
diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go
index ecb73a928f..85f47613f0 100644
--- a/routers/web/healthcheck/check.go
+++ b/routers/web/healthcheck/check.go
@@ -121,10 +121,6 @@ func checkDatabase(ctx context.Context, checks checks) status {
// cache checks gitea cache status
func checkCache(checks checks) status {
- if !setting.CacheService.Enabled {
- return pass
- }
-
st := componentStatus{}
if err := cache.GetCache().Ping(); err != nil {
st.Status = fail
diff --git a/routers/web/misc/misc.go b/routers/web/misc/misc.go
index e351994010..54c93763f6 100644
--- a/routers/web/misc/misc.go
+++ b/routers/web/misc/misc.go
@@ -33,10 +33,6 @@ func DummyOK(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
}
-func DummyBadRequest(w http.ResponseWriter, req *http.Request) {
- w.WriteHeader(http.StatusBadRequest)
-}
-
func RobotsTxt(w http.ResponseWriter, req *http.Request) {
robotsTxt := util.FilePathJoinAbs(setting.CustomPath, "public/robots.txt")
if ok, _ := util.IsExist(robotsTxt); !ok {
diff --git a/routers/web/org/home.go b/routers/web/org/home.go
index a9adfdc03c..8bf02b2c42 100644
--- a/routers/web/org/home.go
+++ b/routers/web/org/home.go
@@ -5,6 +5,7 @@ package org
import (
"net/http"
+ "path"
"strings"
"code.gitea.io/gitea/models/db"
@@ -18,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
shared_user "code.gitea.io/gitea/routers/web/shared/user"
)
@@ -46,10 +48,8 @@ func Home(ctx *context.Context) {
ctx.Data["Title"] = org.DisplayName()
if len(org.Description) != 0 {
desc, err := markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: ctx.Repo.RepoLink,
- Metas: map[string]string{"mode": "document"},
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ Metas: map[string]string{"mode": "document"},
}, org.Description)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -157,14 +157,14 @@ func Home(ctx *context.Context) {
ctx.Data["ShowMemberAndTeamTab"] = ctx.Org.IsMember || len(members) > 0
- profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
+ profileDbRepo, profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
defer profileClose()
- prepareOrgProfileReadme(ctx, profileGitRepo, profileReadmeBlob)
+ prepareOrgProfileReadme(ctx, profileGitRepo, profileDbRepo, profileReadmeBlob)
ctx.HTML(http.StatusOK, tplOrgHome)
}
-func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repository, profileReadme *git.Blob) {
+func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repository, profileDbRepo *repo_model.Repository, profileReadme *git.Blob) {
if profileGitRepo == nil || profileReadme == nil {
return
}
@@ -175,7 +175,13 @@ func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repositor
if profileContent, err := markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
GitRepo: profileGitRepo,
- Metas: map[string]string{"mode": "document"},
+ Links: markup.Links{
+ // Pass repo link to markdown render for the full link of media elements.
+ // The profile of default branch would be shown.
+ Base: profileDbRepo.Link(),
+ BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
+ },
+ Metas: map[string]string{"mode": "document"},
}, bytes); err != nil {
log.Error("failed to RenderString: %v", err)
} else {
diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go
index 3b10f0b957..fe528a483b 100644
--- a/routers/web/repo/actions/actions.go
+++ b/routers/web/repo/actions/actions.go
@@ -18,6 +18,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/routers/web/repo"
"code.gitea.io/gitea/services/convert"
@@ -77,6 +78,7 @@ func List(ctx *context.Context) {
// Get all runner labels
runners, err := db.Find[actions_model.ActionRunner](ctx, actions_model.FindRunnerOptions{
RepoID: ctx.Repo.Repository.ID,
+ IsOnline: util.OptionalBoolTrue,
WithAvailable: true,
})
if err != nil {
@@ -113,7 +115,7 @@ func List(ctx *context.Context) {
continue
}
if !allRunnerLabels.Contains(ro) {
- workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_runner_helper", ro)
+ workflow.ErrMsg = ctx.Locale.Tr("actions.runs.no_matching_online_runner_helper", ro)
break
}
}
@@ -200,6 +202,7 @@ func List(ctx *context.Context) {
pager.AddParamString("actor", fmt.Sprint(actorID))
pager.AddParamString("status", fmt.Sprint(status))
ctx.Data["Page"] = pager
+ ctx.Data["HasWorkflowsOrRuns"] = len(workflows) > 0 || len(runs) > 0
ctx.HTML(http.StatusOK, tplListActions)
}
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index 1f1cca897e..d414779a14 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -114,24 +114,29 @@ func RefBlame(ctx *context.Context) {
return
}
- commitNames, previousCommits := processBlameParts(ctx, result.Parts)
+ commitNames := processBlameParts(ctx, result.Parts)
if ctx.Written() {
return
}
- renderBlame(ctx, result.Parts, commitNames, previousCommits)
+ renderBlame(ctx, result.Parts, commitNames)
ctx.HTML(http.StatusOK, tplRepoHome)
}
type blameResult struct {
- Parts []git.BlamePart
+ Parts []*git.BlamePart
UsesIgnoreRevs bool
FaultyIgnoreRevsFile bool
}
func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) {
- blameReader, err := git.CreateBlameReader(ctx, repoPath, commit, file, bypassBlameIgnore)
+ objectFormat, err := ctx.Repo.GitRepo.GetObjectFormat()
+ if err != nil {
+ ctx.NotFound("CreateBlameReader", err)
+ return nil, err
+ }
+ blameReader, err := git.CreateBlameReader(ctx, objectFormat, repoPath, commit, file, bypassBlameIgnore)
if err != nil {
return nil, err
}
@@ -147,7 +152,7 @@ func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, fil
if len(r.Parts) == 0 && r.UsesIgnoreRevs {
// try again without ignored revs
- blameReader, err = git.CreateBlameReader(ctx, repoPath, commit, file, true)
+ blameReader, err = git.CreateBlameReader(ctx, objectFormat, repoPath, commit, file, true)
if err != nil {
return nil, err
}
@@ -170,7 +175,9 @@ func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, fil
func fillBlameResult(br *git.BlameReader, r *blameResult) error {
r.UsesIgnoreRevs = br.UsesIgnoreRevs()
- r.Parts = make([]git.BlamePart, 0, 5)
+ previousHelper := make(map[string]*git.BlamePart)
+
+ r.Parts = make([]*git.BlamePart, 0, 5)
for {
blamePart, err := br.NextPart()
if err != nil {
@@ -179,18 +186,25 @@ func fillBlameResult(br *git.BlameReader, r *blameResult) error {
if blamePart == nil {
break
}
- r.Parts = append(r.Parts, *blamePart)
+
+ if prev, ok := previousHelper[blamePart.Sha]; ok {
+ if blamePart.PreviousSha == "" {
+ blamePart.PreviousSha = prev.PreviousSha
+ blamePart.PreviousPath = prev.PreviousPath
+ }
+ } else {
+ previousHelper[blamePart.Sha] = blamePart
+ }
+
+ r.Parts = append(r.Parts, blamePart)
}
return nil
}
-func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[string]*user_model.UserCommit, map[string]string) {
+func processBlameParts(ctx *context.Context, blameParts []*git.BlamePart) map[string]*user_model.UserCommit {
// store commit data by SHA to look up avatar info etc
commitNames := make(map[string]*user_model.UserCommit)
- // previousCommits contains links from SHA to parent SHA,
- // if parent also contains the current TreePath.
- previousCommits := make(map[string]string)
// and as blameParts can reference the same commits multiple
// times, we cache the lookup work locally
commits := make([]*git.Commit, 0, len(blameParts))
@@ -214,29 +228,11 @@ func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[st
} else {
ctx.ServerError("Repo.GitRepo.GetCommit", err)
}
- return nil, nil
+ return nil
}
commitCache[sha] = commit
}
- // find parent commit
- if commit.ParentCount() > 0 {
- psha := commit.Parents[0]
- previousCommit, ok := commitCache[psha.String()]
- if !ok {
- previousCommit, _ = commit.Parent(0)
- if previousCommit != nil {
- commitCache[psha.String()] = previousCommit
- }
- }
- // only store parent commit ONCE, if it has the file
- if previousCommit != nil {
- if haz1, _ := previousCommit.HasFile(ctx.Repo.TreePath); haz1 {
- previousCommits[commit.ID.String()] = previousCommit.ID.String()
- }
- }
- }
-
commits = append(commits, commit)
}
@@ -245,10 +241,10 @@ func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[st
commitNames[c.ID.String()] = c
}
- return commitNames, previousCommits
+ return commitNames
}
-func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames map[string]*user_model.UserCommit, previousCommits map[string]string) {
+func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames map[string]*user_model.UserCommit) {
repoLink := ctx.Repo.RepoLink
language := ""
@@ -295,7 +291,6 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
}
commit := commitNames[part.Sha]
- previousSha := previousCommits[part.Sha]
if index == 0 {
// Count commit number
commitCnt++
@@ -313,8 +308,8 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
br.Avatar = gotemplate.HTML(avatar)
br.RepoLink = repoLink
br.PartSha = part.Sha
- br.PreviousSha = previousSha
- br.PreviousShaURL = fmt.Sprintf("%s/blame/commit/%s/%s", repoLink, url.PathEscape(previousSha), util.PathEscapeSegments(ctx.Repo.TreePath))
+ br.PreviousSha = part.PreviousSha
+ br.PreviousShaURL = fmt.Sprintf("%s/blame/commit/%s/%s", repoLink, url.PathEscape(part.PreviousSha), util.PathEscapeSegments(part.PreviousPath))
br.CommitURL = fmt.Sprintf("%s/commit/%s", repoLink, url.PathEscape(part.Sha))
br.CommitMessage = commit.CommitMessage
br.CommitSince = commitSince
@@ -332,8 +327,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
lexerName = lexerNameForLine
}
- br.EscapeStatus, line = charset.EscapeControlHTML(line, ctx.Locale)
- br.Code = gotemplate.HTML(line)
+ br.EscapeStatus, br.Code = charset.EscapeControlHTML(line, ctx.Locale)
rows = append(rows, br)
escapeStatus = escapeStatus.Or(br.EscapeStatus)
}
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index bc72d5f2ec..c543160f42 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -147,11 +147,18 @@ func RestoreBranchPost(ctx *context.Context) {
return
}
+ objectFormat, err := git.GetObjectFormatOfRepo(ctx, ctx.Repo.Repository.RepoPath())
+ if err != nil {
+ log.Error("RestoreBranch: CreateBranch: %w", err)
+ ctx.Flash.Error(ctx.Tr("repo.branch.restore_failed", deletedBranch.Name))
+ return
+ }
+
// Don't return error below this
if err := repo_service.PushUpdate(
&repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromBranch(deletedBranch.Name),
- OldCommitID: git.EmptySHA,
+ OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: deletedBranch.CommitID,
PusherID: ctx.Doer.ID,
PusherName: ctx.Doer.Name,
@@ -191,9 +198,9 @@ func CreateBranch(ctx *context.Context) {
}
err = release_service.CreateNewTag(ctx, ctx.Doer, ctx.Repo.Repository, target, form.NewBranchName, "")
} else if ctx.Repo.IsViewBranch {
- err = repo_service.CreateNewBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.BranchName, form.NewBranchName)
+ err = repo_service.CreateNewBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.BranchName, form.NewBranchName)
} else {
- err = repo_service.CreateNewBranchFromCommit(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.CommitID, form.NewBranchName)
+ err = repo_service.CreateNewBranchFromCommit(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, ctx.Repo.CommitID, form.NewBranchName)
}
if err != nil {
if models.IsErrProtectedTagName(err) {
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index 3587d287fc..abb39caa57 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -7,7 +7,9 @@ package repo
import (
"errors"
"fmt"
+ "html/template"
"net/http"
+ "path"
"strings"
asymkey_model "code.gitea.io/gitea/models/asymkey"
@@ -21,7 +23,9 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitgraph"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
git_service "code.gitea.io/gitea/services/repository"
)
@@ -294,7 +298,7 @@ func Diff(ctx *context.Context) {
}
return
}
- if len(commitID) != git.SHAFullLength {
+ if len(commitID) != commit.ID.Type().FullLength() {
commitID = commit.ID.String()
}
@@ -370,9 +374,21 @@ func Diff(ctx *context.Context) {
note := &git.Note{}
err = git.GetNote(ctx, ctx.Repo.GitRepo, commitID, note)
if err == nil {
- ctx.Data["Note"] = string(charset.ToUTF8WithFallback(note.Message))
ctx.Data["NoteCommit"] = note.Commit
ctx.Data["NoteAuthor"] = user_model.ValidateCommitWithEmail(ctx, note.Commit)
+ ctx.Data["NoteRendered"], err = markup.RenderCommitMessage(&markup.RenderContext{
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ BranchPath: path.Join("commit", util.PathEscapeSegments(commitID)),
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ }, template.HTMLEscapeString(string(charset.ToUTF8WithFallback(note.Message))))
+ if err != nil {
+ ctx.ServerError("RenderCommitMessage", err)
+ return
+ }
}
ctx.Data["BranchName"], err = commit.GetBranchName()
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index b69af3c61c..042b8ed692 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -310,13 +310,14 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
baseIsCommit := ctx.Repo.GitRepo.IsCommitExist(ci.BaseBranch)
baseIsBranch := ctx.Repo.GitRepo.IsBranchExist(ci.BaseBranch)
baseIsTag := ctx.Repo.GitRepo.IsTagExist(ci.BaseBranch)
+ objectFormat, _ := ctx.Repo.GitRepo.GetObjectFormat()
if !baseIsCommit && !baseIsBranch && !baseIsTag {
// Check if baseBranch is short sha commit hash
if baseCommit, _ := ctx.Repo.GitRepo.GetCommit(ci.BaseBranch); baseCommit != nil {
ci.BaseBranch = baseCommit.ID.String()
ctx.Data["BaseBranch"] = ci.BaseBranch
baseIsCommit = true
- } else if ci.BaseBranch == git.EmptySHA {
+ } else if ci.BaseBranch == objectFormat.EmptyObjectID().String() {
if isSameRepo {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
} else {
@@ -844,6 +845,7 @@ func CompareDiff(ctx *context.Context) {
}
}
+ ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanWrite(unit.TypeProjects)
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "comment")
diff --git a/routers/web/repo/githttp.go b/routers/web/repo/githttp.go
index 6ff385f989..6d3dd5a3fe 100644
--- a/routers/web/repo/githttp.go
+++ b/routers/web/repo/githttp.go
@@ -329,7 +329,7 @@ func dummyInfoRefs(ctx *context.Context) {
}
}()
- if err := git.InitRepository(ctx, tmpDir, true); err != nil {
+ if err := git.InitRepository(ctx, tmpDir, true, git.Sha1ObjectFormat.Name()); err != nil {
log.Error("Failed to init bare repo for git-receive-pack cache: %v", err)
return
}
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index fad4a10de8..c8c9924a9e 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -237,10 +237,18 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
}
}
- isShowClosed := ctx.FormString("state") == "closed"
- // if open issues are zero and close don't, use closed as default
+ var isShowClosed util.OptionalBool
+ switch ctx.FormString("state") {
+ case "closed":
+ isShowClosed = util.OptionalBoolTrue
+ case "all":
+ isShowClosed = util.OptionalBoolNone
+ default:
+ isShowClosed = util.OptionalBoolFalse
+ }
+ // if there are closed issues and no open issues, default to showing all issues
if len(ctx.FormString("state")) == 0 && issueStats.OpenCount == 0 && issueStats.ClosedCount != 0 {
- isShowClosed = true
+ isShowClosed = util.OptionalBoolNone
}
if repo.IsTimetrackerEnabled(ctx) {
@@ -260,10 +268,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
}
var total int
- if !isShowClosed {
- total = int(issueStats.OpenCount)
- } else {
+ switch isShowClosed {
+ case util.OptionalBoolTrue:
total = int(issueStats.ClosedCount)
+ case util.OptionalBoolNone:
+ total = int(issueStats.OpenCount + issueStats.ClosedCount)
+ default:
+ total = int(issueStats.OpenCount)
}
pager := context.NewPagination(total, setting.UI.IssuePagingNum, page, 5)
@@ -282,7 +293,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
ReviewedID: reviewedID,
MilestoneIDs: mileIDs,
ProjectID: projectID,
- IsClosed: util.OptionalBoolOf(isShowClosed),
+ IsClosed: isShowClosed,
IsPull: isPullOption,
LabelIDs: labelIDs,
SortType: sortType,
@@ -428,6 +439,9 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
ctx.Data["OpenCount"] = issueStats.OpenCount
ctx.Data["ClosedCount"] = issueStats.ClosedCount
linkStr := "%s?q=%s&type=%s&sort=%s&state=%s&labels=%s&milestone=%d&project=%d&assignee=%d&poster=%d&archived=%t"
+ ctx.Data["AllStatesLink"] = fmt.Sprintf(linkStr, ctx.Link,
+ url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "all", url.QueryEscape(selectLabels),
+ mentionedID, projectID, assigneeID, posterID, archived)
ctx.Data["OpenLink"] = fmt.Sprintf(linkStr, ctx.Link,
url.QueryEscape(keyword), url.QueryEscape(viewType), url.QueryEscape(sortType), "open", url.QueryEscape(selectLabels),
mentionedID, projectID, assigneeID, posterID, archived)
@@ -442,11 +456,13 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
ctx.Data["ProjectID"] = projectID
ctx.Data["AssigneeID"] = assigneeID
ctx.Data["PosterID"] = posterID
- ctx.Data["IsShowClosed"] = isShowClosed
ctx.Data["Keyword"] = keyword
- if isShowClosed {
+ switch isShowClosed {
+ case util.OptionalBoolTrue:
ctx.Data["State"] = "closed"
- } else {
+ case util.OptionalBoolNone:
+ ctx.Data["State"] = "all"
+ default:
ctx.Data["State"] = "open"
}
ctx.Data["ShowArchivedLabels"] = archived
@@ -510,9 +526,8 @@ func Issues(ctx *context.Context) {
func renderMilestones(ctx *context.Context) {
// Get milestones
- milestones, _, err := issues_model.GetMilestones(ctx, issues_model.GetMilestonesOption{
+ milestones, err := db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
RepoID: ctx.Repo.Repository.ID,
- State: api.StateAll,
})
if err != nil {
ctx.ServerError("GetAllRepoMilestones", err)
@@ -534,17 +549,17 @@ func renderMilestones(ctx *context.Context) {
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.Repository) {
var err error
- ctx.Data["OpenMilestones"], _, err = issues_model.GetMilestones(ctx, issues_model.GetMilestonesOption{
- RepoID: repo.ID,
- State: api.StateOpen,
+ ctx.Data["OpenMilestones"], err = db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
+ RepoID: repo.ID,
+ IsClosed: util.OptionalBoolFalse,
})
if err != nil {
ctx.ServerError("GetMilestones", err)
return
}
- ctx.Data["ClosedMilestones"], _, err = issues_model.GetMilestones(ctx, issues_model.GetMilestonesOption{
- RepoID: repo.ID,
- State: api.StateClosed,
+ ctx.Data["ClosedMilestones"], err = db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
+ RepoID: repo.ID,
+ IsClosed: util.OptionalBoolTrue,
})
if err != nil {
ctx.ServerError("GetMilestones", err)
@@ -1319,7 +1334,7 @@ func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *use
return roleDescriptor, err
} else if hasMergedPR {
roleDescriptor.RoleInRepo = issues_model.RoleRepoContributor
- } else {
+ } else if issue.IsPull {
// only display first time contributor in the first opening pull request
roleDescriptor.RoleInRepo = issues_model.RoleRepoFirstTimeContributor
}
@@ -1437,12 +1452,13 @@ func ViewIssue(ctx *context.Context) {
}
}
ctx.Data["IssueWatch"] = iw
-
issue.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, issue.Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -1602,10 +1618,12 @@ func ViewIssue(ctx *context.Context) {
}
comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, comment.Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -1679,10 +1697,12 @@ func ViewIssue(ctx *context.Context) {
}
} else if comment.Type.HasContentSupport() {
comment.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, comment.Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -1963,7 +1983,7 @@ func ViewIssue(ctx *context.Context) {
return
}
- ctx.Data["BlockingDependencies"], ctx.Data["BlockingByDependenciesNotPermitted"] = checkBlockedByIssues(ctx, blocking)
+ ctx.Data["BlockingDependencies"], ctx.Data["BlockingDependenciesNotPermitted"] = checkBlockedByIssues(ctx, blocking)
if ctx.Written() {
return
}
@@ -2024,38 +2044,34 @@ func ViewIssue(ctx *context.Context) {
// checkBlockedByIssues return canRead and notPermitted
func checkBlockedByIssues(ctx *context.Context, blockers []*issues_model.DependencyInfo) (canRead, notPermitted []*issues_model.DependencyInfo) {
- var (
- lastRepoID int64
- lastPerm access_model.Permission
- )
- for i, blocker := range blockers {
+ repoPerms := make(map[int64]access_model.Permission)
+ repoPerms[ctx.Repo.Repository.ID] = ctx.Repo.Permission
+ for _, blocker := range blockers {
// Get the permissions for this repository
- perm := lastPerm
- if lastRepoID != blocker.Repository.ID {
- if blocker.Repository.ID == ctx.Repo.Repository.ID {
- perm = ctx.Repo.Permission
- } else {
- var err error
- perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
- if err != nil {
- ctx.ServerError("GetUserRepoPermission", err)
- return nil, nil
- }
+ // If the repo ID exists in the map, return the exist permissions
+ // else get the permission and add it to the map
+ var perm access_model.Permission
+ existPerm, ok := repoPerms[blocker.RepoID]
+ if ok {
+ perm = existPerm
+ } else {
+ var err error
+ perm, err = access_model.GetUserRepoPermission(ctx, &blocker.Repository, ctx.Doer)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil, nil
}
- lastRepoID = blocker.Repository.ID
+ repoPerms[blocker.RepoID] = perm
}
-
- // check permission
- if !perm.CanReadIssuesOrPulls(blocker.Issue.IsPull) {
- blockers[len(notPermitted)], blockers[i] = blocker, blockers[len(notPermitted)]
- notPermitted = blockers[:len(notPermitted)+1]
+ if perm.CanReadIssuesOrPulls(blocker.Issue.IsPull) {
+ canRead = append(canRead, blocker)
+ } else {
+ notPermitted = append(notPermitted, blocker)
}
}
- blockers = blockers[len(notPermitted):]
- sortDependencyInfo(blockers)
+ sortDependencyInfo(canRead)
sortDependencyInfo(notPermitted)
-
- return blockers, notPermitted
+ return canRead, notPermitted
}
func sortDependencyInfo(blockers []*issues_model.DependencyInfo) {
@@ -2239,10 +2255,12 @@ func UpdateIssueContent(ctx *context.Context) {
}
content, err := markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, issue.Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -3106,6 +3124,11 @@ func UpdateCommentContent(ctx *context.Context) {
return
}
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
+ return
+ }
+
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
ctx.Error(http.StatusForbidden)
return
@@ -3143,10 +3166,12 @@ func UpdateCommentContent(ctx *context.Context) {
}
content, err := markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.FormString("context"), // FIXME: <- IS THIS SAFE ?
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, comment.Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -3172,6 +3197,11 @@ func DeleteComment(ctx *context.Context) {
return
}
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
+ return
+ }
+
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
ctx.Error(http.StatusForbidden)
return
@@ -3298,6 +3328,11 @@ func ChangeCommentReaction(ctx *context.Context) {
return
}
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
+ return
+ }
+
if !ctx.IsSigned || (ctx.Doer.ID != comment.PosterID && !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull)) {
if log.IsTrace() {
if ctx.IsSigned {
@@ -3441,6 +3476,21 @@ func GetCommentAttachments(ctx *context.Context) {
return
}
+ if err := comment.LoadIssue(ctx); err != nil {
+ ctx.NotFoundOrServerError("LoadIssue", issues_model.IsErrIssueNotExist, err)
+ return
+ }
+
+ if comment.Issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
+ return
+ }
+
+ if !ctx.Repo.Permission.CanReadIssuesOrPulls(comment.Issue.IsPull) {
+ ctx.NotFound("CanReadIssuesOrPulls", issues_model.ErrCommentNotExist{})
+ return
+ }
+
if !comment.Type.HasAttachmentSupport() {
ctx.ServerError("GetCommentAttachments", fmt.Errorf("comment type %v does not support attachments", comment.Type))
return
diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go
index 5c378fe9d7..0f376db145 100644
--- a/routers/web/repo/issue_content_history.go
+++ b/routers/web/repo/issue_content_history.go
@@ -122,7 +122,7 @@ func GetContentHistoryDetail(ctx *context.Context) {
}
historyID := ctx.FormInt64("history_id")
- history, prevHistory, err := issues_model.GetIssueContentHistoryAndPrev(ctx, historyID)
+ history, prevHistory, err := issues_model.GetIssueContentHistoryAndPrev(ctx, issue.ID, historyID)
if err != nil {
ctx.JSON(http.StatusNotFound, map[string]any{
"message": "Can not find the content history",
@@ -193,15 +193,29 @@ func SoftDeleteContentHistory(ctx *context.Context) {
var comment *issues_model.Comment
var history *issues_model.ContentHistory
var err error
+
+ if history, err = issues_model.GetIssueContentHistoryByID(ctx, historyID); err != nil {
+ log.Error("can not get issue content history %v. err=%v", historyID, err)
+ return
+ }
+ if history.IssueID != issue.ID {
+ ctx.NotFound("CompareRepoID", issues_model.ErrCommentNotExist{})
+ return
+ }
if commentID != 0 {
+ if history.CommentID != commentID {
+ ctx.NotFound("CompareCommentID", issues_model.ErrCommentNotExist{})
+ return
+ }
+
if comment, err = issues_model.GetCommentByID(ctx, commentID); err != nil {
log.Error("can not get comment for issue content history %v. err=%v", historyID, err)
return
}
- }
- if history, err = issues_model.GetIssueContentHistoryByID(ctx, historyID); err != nil {
- log.Error("can not get issue content history %v. err=%v", historyID, err)
- return
+ if comment.IssueID != issue.ID {
+ ctx.NotFound("CompareIssueID", issues_model.ErrCommentNotExist{})
+ return
+ }
}
canSoftDelete := canSoftDeleteContentHistory(ctx, issue, comment, history)
diff --git a/routers/web/repo/issue_pin.go b/routers/web/repo/issue_pin.go
index f853f72335..9f334129f9 100644
--- a/routers/web/repo/issue_pin.go
+++ b/routers/web/repo/issue_pin.go
@@ -90,6 +90,12 @@ func IssuePinMove(ctx *context.Context) {
return
}
+ if issue.RepoID != ctx.Repo.Repository.ID {
+ ctx.Status(http.StatusNotFound)
+ log.Error("Issue does not belong to this repository")
+ return
+ }
+
err = issue.MovePin(ctx, form.Position)
if err != nil {
ctx.Status(http.StatusInternalServerError)
diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go
index 0e6f630747..19db2abd68 100644
--- a/routers/web/repo/milestone.go
+++ b/routers/web/repo/milestone.go
@@ -16,7 +16,6 @@ import (
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web"
@@ -46,18 +45,13 @@ func Milestones(ctx *context.Context) {
page = 1
}
- state := structs.StateOpen
- if isShowClosed {
- state = structs.StateClosed
- }
-
- miles, total, err := issues_model.GetMilestones(ctx, issues_model.GetMilestonesOption{
+ miles, total, err := db.FindAndCount[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
ListOptions: db.ListOptions{
Page: page,
PageSize: setting.UI.IssuePagingNum,
},
RepoID: ctx.Repo.Repository.ID,
- State: state,
+ IsClosed: util.OptionalBoolOf(isShowClosed),
SortType: sortType,
Name: keyword,
})
@@ -80,17 +74,19 @@ func Milestones(ctx *context.Context) {
url.QueryEscape(keyword), url.QueryEscape(sortType))
if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) {
- if err := miles.LoadTotalTrackedTimes(ctx); err != nil {
+ if err := issues_model.MilestoneList(miles).LoadTotalTrackedTimes(ctx); err != nil {
ctx.ServerError("LoadTotalTrackedTimes", err)
return
}
}
for _, m := range miles {
m.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, m.Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -281,10 +277,12 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
}
milestone.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, milestone.Content)
if err != nil {
ctx.ServerError("RenderString", err)
diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go
index 199a065245..4908bb796d 100644
--- a/routers/web/repo/projects.go
+++ b/routers/web/repo/projects.go
@@ -90,10 +90,12 @@ func Projects(ctx *context.Context) {
for i := range projects {
projects[i].RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, projects[i].Description)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -357,10 +359,12 @@ func ViewProject(ctx *context.Context) {
ctx.Data["LinkedPRs"] = linkedPrsMap
project.RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, project.Description)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -468,7 +472,7 @@ func AddBoardToProjectPost(ctx *context.Context) {
return
}
- project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id"))
+ project, err := project_model.GetProjectForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
if err != nil {
if project_model.IsErrProjectNotExist(err) {
ctx.NotFound("", nil)
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index ec109ed665..e36d7092af 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -653,7 +653,15 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
if pb != nil && pb.EnableStatusCheck {
ctx.Data["is_context_required"] = func(context string) bool {
for _, c := range pb.StatusCheckContexts {
- if gp, err := glob.Compile(c); err == nil && gp.Match(context) {
+ if c == context {
+ return true
+ }
+ if gp, err := glob.Compile(c); err != nil {
+ // All newly created status_check_contexts are checked to ensure they are valid glob expressions before being stored in the database.
+ // But some old status_check_context created before glob was introduced may be invalid glob expressions.
+ // So log the error here for debugging.
+ log.Error("compile glob %q: %v", c, err)
+ } else if gp.Match(context) {
return true
}
}
@@ -1141,30 +1149,28 @@ func MergePullRequest(ctx *context.Context) {
switch {
case errors.Is(err, pull_service.ErrIsClosed):
if issue.IsPull {
- ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
+ ctx.JSONError(ctx.Tr("repo.pulls.is_closed"))
} else {
- ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
+ ctx.JSONError(ctx.Tr("repo.issues.closed_title"))
}
case errors.Is(err, pull_service.ErrUserNotAllowedToMerge):
- ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
+ ctx.JSONError(ctx.Tr("repo.pulls.update_not_allowed"))
case errors.Is(err, pull_service.ErrHasMerged):
- ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
+ ctx.JSONError(ctx.Tr("repo.pulls.has_merged"))
case errors.Is(err, pull_service.ErrIsWorkInProgress):
- ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
+ ctx.JSONError(ctx.Tr("repo.pulls.no_merge_wip"))
case errors.Is(err, pull_service.ErrNotMergableState):
- ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
+ ctx.JSONError(ctx.Tr("repo.pulls.no_merge_not_ready"))
case models.IsErrDisallowedToMerge(err):
- ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
+ ctx.JSONError(ctx.Tr("repo.pulls.no_merge_not_ready"))
case asymkey_service.IsErrWontSign(err):
- ctx.Flash.Error(err.Error()) // has no translation ...
+ ctx.JSONError(err.Error()) // has no translation ...
case errors.Is(err, pull_service.ErrDependenciesLeft):
- ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
+ ctx.JSONError(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
default:
ctx.ServerError("WebCheck", err)
- return
}
- ctx.Redirect(issue.Link())
return
}
@@ -1172,18 +1178,18 @@ func MergePullRequest(ctx *context.Context) {
if manuallyMerged {
if err := pull_service.MergedManually(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
switch {
-
case models.IsErrInvalidMergeStyle(err):
- ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
+ ctx.JSONError(ctx.Tr("repo.pulls.invalid_merge_option"))
case strings.Contains(err.Error(), "Wrong commit ID"):
- ctx.Flash.Error(ctx.Tr("repo.pulls.wrong_commit_id"))
+ ctx.JSONError(ctx.Tr("repo.pulls.wrong_commit_id"))
default:
ctx.ServerError("MergedManually", err)
- return
}
+
+ return
}
- ctx.Redirect(issue.Link())
+ ctx.JSONRedirect(issue.Link())
return
}
@@ -1213,15 +1219,14 @@ func MergePullRequest(ctx *context.Context) {
} else if scheduled {
// nothing more to do ...
ctx.Flash.Success(ctx.Tr("repo.pulls.auto_merge_newly_scheduled"))
- ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, pr.Index))
+ ctx.JSONRedirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, pr.Index))
return
}
}
if err := pull_service.Merge(ctx, pr, ctx.Doer, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message, false); err != nil {
if models.IsErrInvalidMergeStyle(err) {
- ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
- ctx.Redirect(issue.Link())
+ ctx.JSONError(ctx.Tr("repo.pulls.invalid_merge_option"))
} else if models.IsErrMergeConflicts(err) {
conflictError := err.(models.ErrMergeConflicts)
flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
@@ -1234,7 +1239,7 @@ func MergePullRequest(ctx *context.Context) {
return
}
ctx.Flash.Error(flashError)
- ctx.Redirect(issue.Link())
+ ctx.JSONRedirect(issue.Link())
} else if models.IsErrRebaseConflicts(err) {
conflictError := err.(models.ErrRebaseConflicts)
flashError, err := ctx.RenderToString(tplAlertDetails, map[string]any{
@@ -1278,7 +1283,7 @@ func MergePullRequest(ctx *context.Context) {
}
ctx.Flash.Error(flashError)
}
- ctx.Redirect(issue.Link())
+ ctx.JSONRedirect(issue.Link())
} else {
ctx.ServerError("Merge", err)
}
@@ -1287,7 +1292,7 @@ func MergePullRequest(ctx *context.Context) {
log.Trace("Pull request merged: %d", pr.ID)
if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil {
- ctx.ServerError("CreateOrStopIssueStopwatch", err)
+ ctx.ServerError("stopTimerIfAvailable", err)
return
}
@@ -1301,7 +1306,7 @@ func MergePullRequest(ctx *context.Context) {
return
}
if exist {
- ctx.Redirect(issue.Link())
+ ctx.JSONRedirect(issue.Link())
return
}
@@ -1319,7 +1324,7 @@ func MergePullRequest(ctx *context.Context) {
deleteBranch(ctx, pr, headRepo)
}
- ctx.Redirect(issue.Link())
+ ctx.JSONRedirect(issue.Link())
}
// CancelAutoMergePullRequest cancels a scheduled pr
@@ -1379,7 +1384,7 @@ func CompareAndPullRequestPost(ctx *context.Context) {
return
}
- labelIDs, assigneeIDs, milestoneID, _ := ValidateRepoMetas(ctx, *form, true)
+ labelIDs, assigneeIDs, milestoneID, projectID := ValidateRepoMetas(ctx, *form, true)
if ctx.Written() {
return
}
@@ -1457,6 +1462,17 @@ func CompareAndPullRequestPost(ctx *context.Context) {
return
}
+ if projectID > 0 {
+ if !ctx.Repo.CanWrite(unit.TypeProjects) {
+ ctx.Error(http.StatusBadRequest, "user hasn't the permission to write to projects")
+ return
+ }
+ if err := issues_model.ChangeProjectAssign(ctx, pullIssue, ctx.Doer, projectID); err != nil {
+ ctx.ServerError("ChangeProjectAssign", err)
+ return
+ }
+ }
+
log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID)
ctx.JSONRedirect(pullIssue.Link())
}
@@ -1571,6 +1587,12 @@ func CleanUpPullRequest(ctx *context.Context) {
func deleteBranch(ctx *context.Context, pr *issues_model.PullRequest, gitRepo *git.Repository) {
fullBranchName := pr.HeadRepo.FullName() + ":" + pr.HeadBranch
+
+ if err := pull_service.RetargetChildrenOnMerge(ctx, ctx.Doer, pr); err != nil {
+ ctx.Flash.Error(ctx.Tr("repo.branch.deletion_failed", fullBranchName))
+ return
+ }
+
if err := repo_service.DeleteBranch(ctx, ctx.Doer, pr.HeadRepo, gitRepo, pr.HeadBranch); err != nil {
switch {
case git.IsErrBranchNotExist(err):
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 5cbd6b3d51..fdb247d413 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -95,9 +95,10 @@ func Releases(ctx *context.Context) {
ListOptions: listOptions,
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
IncludeDrafts: writeAccess,
+ RepoID: ctx.Repo.Repository.ID,
}
- releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts)
+ releases, err := db.Find[repo_model.Release](ctx, opts)
if err != nil {
ctx.ServerError("GetReleasesByRepoID", err)
return
@@ -135,10 +136,12 @@ func Releases(ctx *context.Context) {
}
r.Note, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, r.Note)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -174,6 +177,7 @@ func TagsList(ctx *context.Context) {
// Disable the showCreateNewBranch form in the dropdown on this page.
ctx.Data["CanCreateBranch"] = false
ctx.Data["HideBranchesInDropdown"] = true
+ ctx.Data["CanCreateRelease"] = ctx.Repo.CanWrite(unit.TypeReleases) && !ctx.Repo.Repository.IsArchived
listOptions := db.ListOptions{
Page: ctx.FormInt("page"),
@@ -193,9 +197,10 @@ func TagsList(ctx *context.Context) {
IncludeDrafts: true,
IncludeTags: true,
HasSha1: util.OptionalBoolTrue,
+ RepoID: ctx.Repo.Repository.ID,
}
- releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts)
+ releases, err := db.Find[repo_model.Release](ctx, opts)
if err != nil {
ctx.ServerError("GetReleasesByRepoID", err)
return
@@ -284,10 +289,12 @@ func SingleRelease(ctx *context.Context) {
}
}
release.Note, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
}, release.Note)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -616,7 +623,27 @@ func DeleteTag(ctx *context.Context) {
}
func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) {
- if err := releaseservice.DeleteReleaseByID(ctx, ctx.FormInt64("id"), ctx.Doer, isDelTag); err != nil {
+ redirect := func() {
+ if isDelTag {
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/tags")
+ return
+ }
+
+ ctx.JSONRedirect(ctx.Repo.RepoLink + "/releases")
+ }
+
+ rel, err := repo_model.GetReleaseForRepoByID(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id"))
+ if err != nil {
+ if repo_model.IsErrReleaseNotExist(err) {
+ ctx.NotFound("GetReleaseForRepoByID", err)
+ } else {
+ ctx.Flash.Error("DeleteReleaseByID: " + err.Error())
+ redirect()
+ }
+ return
+ }
+
+ if err := releaseservice.DeleteReleaseByID(ctx, ctx.Repo.Repository, rel, ctx.Doer, isDelTag); err != nil {
if models.IsErrProtectedTagName(err) {
ctx.Flash.Error(ctx.Tr("repo.release.tag_name_protected"))
} else {
@@ -630,10 +657,5 @@ func deleteReleaseOrTag(ctx *context.Context, isDelTag bool) {
}
}
- if isDelTag {
- ctx.JSONRedirect(ctx.Repo.RepoLink + "/tags")
- return
- }
-
- ctx.JSONRedirect(ctx.Repo.RepoLink + "/releases")
+ redirect()
}
diff --git a/routers/web/repo/release_test.go b/routers/web/repo/release_test.go
index a5a923d464..c4a2c1904e 100644
--- a/routers/web/repo/release_test.go
+++ b/routers/web/repo/release_test.go
@@ -6,6 +6,7 @@ package repo
import (
"testing"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/models/unittest"
@@ -74,8 +75,9 @@ func TestCalReleaseNumCommitsBehind(t *testing.T) {
contexttest.LoadGitRepo(t, ctx)
t.Cleanup(func() { ctx.Repo.GitRepo.Close() })
- releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{
+ releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
IncludeDrafts: ctx.Repo.CanWrite(unit.TypeReleases),
+ RepoID: ctx.Repo.Repository.ID,
})
assert.NoError(t, err)
diff --git a/routers/web/repo/render.go b/routers/web/repo/render.go
index 33476c1d2c..f2c6ab3f8f 100644
--- a/routers/web/repo/render.go
+++ b/routers/web/repo/render.go
@@ -57,16 +57,15 @@ func RenderFile(ctx *context.Context) {
return
}
- treeLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
- if ctx.Repo.TreePath != "" {
- treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
- }
-
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
err = markup.Render(&markup.RenderContext{
- Ctx: ctx,
- RelativePath: ctx.Repo.TreePath,
- URLPrefix: path.Dir(treeLink),
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ BranchPath: ctx.Repo.BranchNameSubURL(),
+ TreePath: path.Dir(ctx.Repo.TreePath),
+ },
Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
GitRepo: ctx.Repo.GitRepo,
InStandalonePage: true,
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index b3b6b48871..b5c550ae45 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -159,6 +159,7 @@ func Create(ctx *context.Context) {
ctx.Data["private"] = getRepoPrivate(ctx)
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate
ctx.Data["default_branch"] = setting.Repository.DefaultBranch
+ ctx.Data["hash_type"] = "sha1"
ctxUser := checkContextUser(ctx, ctx.FormInt64("org"))
if ctx.Written() {
@@ -277,17 +278,18 @@ func CreatePost(ctx *context.Context) {
}
} else {
repo, err = repo_service.CreateRepository(ctx, ctx.Doer, ctxUser, repo_service.CreateRepoOptions{
- Name: form.RepoName,
- Description: form.Description,
- Gitignores: form.Gitignores,
- IssueLabels: form.IssueLabels,
- License: form.License,
- Readme: form.Readme,
- IsPrivate: form.Private || setting.Repository.ForcePrivate,
- DefaultBranch: form.DefaultBranch,
- AutoInit: form.AutoInit,
- IsTemplate: form.Template,
- TrustModel: repo_model.ToTrustModel(form.TrustModel),
+ Name: form.RepoName,
+ Description: form.Description,
+ Gitignores: form.Gitignores,
+ IssueLabels: form.IssueLabels,
+ License: form.License,
+ Readme: form.Readme,
+ IsPrivate: form.Private || setting.Repository.ForcePrivate,
+ DefaultBranch: form.DefaultBranch,
+ AutoInit: form.AutoInit,
+ IsTemplate: form.Template,
+ TrustModel: repo_model.DefaultTrustModel,
+ ObjectFormatName: form.ObjectFormatName,
})
if err == nil {
log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
@@ -377,7 +379,10 @@ func RedirectDownload(ctx *context.Context) {
)
tagNames := []string{vTag}
curRepo := ctx.Repo.Repository
- releases, err := repo_model.GetReleasesByRepoIDAndNames(ctx, curRepo.ID, tagNames)
+ releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
+ RepoID: curRepo.ID,
+ TagNames: tagNames,
+ })
if err != nil {
ctx.ServerError("RedirectDownload", err)
return
@@ -606,7 +611,7 @@ func SearchRepo(ctx *context.Context) {
}
// call the database O(1) times to get the commit statuses for all repos
- repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptions{})
+ repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptionsAll)
if err != nil {
log.Error("GetLatestCommitStatusForPairs: %v", err)
return
diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go
index 9bf54e706a..c8a576e576 100644
--- a/routers/web/repo/setting/default_branch.go
+++ b/routers/web/repo/setting/default_branch.go
@@ -6,13 +6,12 @@ package setting
import (
"net/http"
- repo_model "code.gitea.io/gitea/models/repo"
+ git_model "code.gitea.io/gitea/models/git"
"code.gitea.io/gitea/modules/context"
- "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/web/repo"
- notify_service "code.gitea.io/gitea/services/notify"
+ repo_service "code.gitea.io/gitea/services/repository"
)
// SetDefaultBranchPost set default branch
@@ -35,23 +34,14 @@ func SetDefaultBranchPost(ctx *context.Context) {
}
branch := ctx.FormString("branch")
- if !ctx.Repo.GitRepo.IsBranchExist(branch) {
- ctx.Status(http.StatusNotFound)
- return
- } else if repo.DefaultBranch != branch {
- repo.DefaultBranch = branch
- if err := ctx.Repo.GitRepo.SetDefaultBranch(branch); err != nil {
- if !git.IsErrUnsupportedVersion(err) {
- ctx.ServerError("SetDefaultBranch", err)
- return
- }
- }
- if err := repo_model.UpdateDefaultBranch(ctx, repo); err != nil {
+ if err := repo_service.SetRepoDefaultBranch(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, branch); err != nil {
+ switch {
+ case git_model.IsErrBranchNotExist(err):
+ ctx.Status(http.StatusNotFound)
+ default:
ctx.ServerError("SetDefaultBranch", err)
- return
}
-
- notify_service.ChangeDefaultBranch(ctx, repo)
+ return
}
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go
index d478acdde0..edf1298c20 100644
--- a/routers/web/repo/setting/lfs.go
+++ b/routers/web/repo/setting/lfs.go
@@ -388,20 +388,21 @@ func LFSFileFind(ctx *context.Context) {
sha := ctx.FormString("sha")
ctx.Data["Title"] = oid
ctx.Data["PageIsSettingsLFS"] = true
- var hash git.SHA1
+ objectFormat, _ := ctx.Repo.GitRepo.GetObjectFormat()
+ var objectID git.ObjectID
if len(sha) == 0 {
pointer := lfs.Pointer{Oid: oid, Size: size}
- hash = git.ComputeBlobHash([]byte(pointer.StringContent()))
- sha = hash.String()
+ objectID = git.ComputeBlobHash(objectFormat, []byte(pointer.StringContent()))
+ sha = objectID.String()
} else {
- hash = git.MustIDFromString(sha)
+ objectID = git.MustIDFromString(sha)
}
ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
ctx.Data["Oid"] = oid
ctx.Data["Size"] = size
ctx.Data["SHA"] = sha
- results, err := pipeline.FindLFSFile(ctx.Repo.GitRepo, hash)
+ results, err := pipeline.FindLFSFile(ctx.Repo.GitRepo, objectID)
if err != nil && err != io.EOF {
log.Error("Failure in FindLFSFile: %v", err)
ctx.ServerError("LFSFind: FindLFSFile.", err)
diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go
index 73adfec95a..98d6977b81 100644
--- a/routers/web/repo/setting/protected_branch.go
+++ b/routers/web/repo/setting/protected_branch.go
@@ -228,6 +228,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) {
protectBranch.BlockOnRejectedReviews = f.BlockOnRejectedReviews
protectBranch.BlockOnOfficialReviewRequests = f.BlockOnOfficialReviewRequests
protectBranch.DismissStaleApprovals = f.DismissStaleApprovals
+ protectBranch.IgnoreStaleApprovals = f.IgnoreStaleApprovals
protectBranch.RequireSignedCommits = f.RequireSignedCommits
protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns
protectBranch.UnprotectedFilePatterns = f.UnprotectedFilePatterns
diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go
index 0864b1c911..e721b7c739 100644
--- a/routers/web/repo/setting/setting.go
+++ b/routers/web/repo/setting/setting.go
@@ -418,7 +418,7 @@ func SettingsPost(ctx *context.Context) {
Interval: interval,
RemoteAddress: remoteAddress,
}
- if err := repo_model.InsertPushMirror(ctx, m); err != nil {
+ if err := db.Insert(ctx, m); err != nil {
ctx.ServerError("InsertPushMirror", err)
return
}
@@ -594,7 +594,7 @@ func SettingsPost(ctx *context.Context) {
return
}
- if err := repo_model.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
+ if err := repo_service.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil {
ctx.ServerError("UpdateRepositoryUnits", err)
return
}
diff --git a/routers/web/repo/setting/variables.go b/routers/web/repo/setting/variables.go
index a697a5d8d8..428aa0bd5c 100644
--- a/routers/web/repo/setting/variables.go
+++ b/routers/web/repo/setting/variables.go
@@ -15,9 +15,10 @@ import (
)
const (
- tplRepoVariables base.TplName = "repo/settings/actions"
- tplOrgVariables base.TplName = "org/settings/actions"
- tplUserVariables base.TplName = "user/settings/actions"
+ tplRepoVariables base.TplName = "repo/settings/actions"
+ tplOrgVariables base.TplName = "org/settings/actions"
+ tplUserVariables base.TplName = "user/settings/actions"
+ tplAdminVariables base.TplName = "admin/actions"
)
type variablesCtx struct {
@@ -26,6 +27,7 @@ type variablesCtx struct {
IsRepo bool
IsOrg bool
IsUser bool
+ IsGlobal bool
VariablesTemplate base.TplName
RedirectLink string
}
@@ -33,6 +35,7 @@ type variablesCtx struct {
func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
if ctx.Data["PageIsRepoSettings"] == true {
return &variablesCtx{
+ OwnerID: 0,
RepoID: ctx.Repo.Repository.ID,
IsRepo: true,
VariablesTemplate: tplRepoVariables,
@@ -48,6 +51,7 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
}
return &variablesCtx{
OwnerID: ctx.ContextUser.ID,
+ RepoID: 0,
IsOrg: true,
VariablesTemplate: tplOrgVariables,
RedirectLink: ctx.Org.OrgLink + "/settings/actions/variables",
@@ -57,12 +61,23 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
if ctx.Data["PageIsUserSettings"] == true {
return &variablesCtx{
OwnerID: ctx.Doer.ID,
+ RepoID: 0,
IsUser: true,
VariablesTemplate: tplUserVariables,
RedirectLink: setting.AppSubURL + "/user/settings/actions/variables",
}, nil
}
+ if ctx.Data["PageIsAdmin"] == true {
+ return &variablesCtx{
+ OwnerID: 0,
+ RepoID: 0,
+ IsGlobal: true,
+ VariablesTemplate: tplAdminVariables,
+ RedirectLink: setting.AppSubURL + "/admin/actions/variables",
+ }, nil
+ }
+
return nil, errors.New("unable to set Variables context")
}
diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go
index 5100bf782f..ab3c70006f 100644
--- a/routers/web/repo/setting/webhook.go
+++ b/routers/web/repo/setting/webhook.go
@@ -655,8 +655,14 @@ func TestWebhook(ctx *context.Context) {
commit := ctx.Repo.Commit
if commit == nil {
ghost := user_model.NewGhostUser()
+ objectFormat, err := git.GetObjectFormatOfRepo(ctx, ctx.Repo.Repository.RepoPath())
+ if err != nil {
+ ctx.Flash.Error("GetObjectFormatOfRepo: " + err.Error())
+ ctx.Status(http.StatusInternalServerError)
+ return
+ }
commit = &git.Commit{
- ID: git.MustIDFromString(git.EmptySHA),
+ ID: objectFormat.EmptyObjectID(),
Author: ghost.NewGitSig(),
Committer: ghost.NewGitSig(),
CommitMessage: "This is a fake commit",
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index ba2ac3af11..aa07d5939d 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -9,6 +9,7 @@ import (
gocontext "context"
"encoding/base64"
"fmt"
+ "html/template"
"image"
"io"
"net/http"
@@ -157,7 +158,7 @@ func findReadmeFileInEntries(ctx *context.Context, entries []*git.TreeEntry, try
return "", readmeFile, nil
}
-func renderDirectory(ctx *context.Context, treeLink string) {
+func renderDirectory(ctx *context.Context) {
entries := renderDirectoryFiles(ctx, 1*time.Second)
if ctx.Written() {
return
@@ -174,7 +175,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
return
}
- renderReadmeFile(ctx, subfolder, readmeFile, treeLink)
+ renderReadmeFile(ctx, subfolder, readmeFile)
}
// localizedExtensions prepends the provided language code with and without a
@@ -258,7 +259,7 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte,
return buf, dataRc, &fileInfo{st.IsText(), true, meta.Size, &meta.Pointer, st}, nil
}
-func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.TreeEntry, readmeTreelink string) {
+func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.TreeEntry) {
target := readmeFile
if readmeFile != nil && readmeFile.IsLink() {
target, _ = readmeFile.FollowLinks()
@@ -311,25 +312,28 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr
ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
Ctx: ctx,
RelativePath: path.Join(ctx.Repo.TreePath, readmeFile.Name()), // ctx.Repo.TreePath is the directory not the Readme so we must append the Readme filename (and path).
- URLPrefix: path.Join(readmeTreelink, subfolder),
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ BranchPath: ctx.Repo.BranchNameSubURL(),
+ TreePath: path.Join(ctx.Repo.TreePath, subfolder),
+ },
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
}, rd)
if err != nil {
log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.Name(), ctx.Repo.Repository, err)
- buf := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
- ctx.Data["FileContent"] = buf.String()
- }
- } else {
- ctx.Data["IsPlainText"] = true
- buf := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
- if err != nil {
- log.Error("Read failed: %v", err)
+ delete(ctx.Data, "IsMarkup")
}
+ }
- ctx.Data["FileContent"] = buf.String()
+ if ctx.Data["IsMarkup"] != true {
+ ctx.Data["IsPlainText"] = true
+ content, err := io.ReadAll(rd)
+ if err != nil {
+ log.Error("Read readme content failed: %v", err)
+ }
+ contentEscaped := template.HTMLEscapeString(util.UnsafeBytesToString(content))
+ ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlHTML(template.HTML(contentEscaped), ctx.Locale)
}
if !fInfo.isLFSFile && ctx.Repo.CanEnableEditor(ctx, ctx.Doer) {
@@ -337,7 +341,36 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr
}
}
-func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink string) {
+func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
+ // Show latest commit info of repository in table header,
+ // or of directory if not in root directory.
+ ctx.Data["LatestCommit"] = latestCommit
+ if latestCommit != nil {
+
+ verification := asymkey_model.ParseCommitWithSignature(ctx, latestCommit)
+
+ if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
+ return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID)
+ }, nil); err != nil {
+ ctx.ServerError("CalculateTrustStatus", err)
+ return false
+ }
+ ctx.Data["LatestCommitVerification"] = verification
+ ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(ctx, latestCommit)
+
+ statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{ListAll: true})
+ if err != nil {
+ log.Error("GetLatestCommitStatus: %v", err)
+ }
+
+ ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
+ ctx.Data["LatestCommitStatuses"] = statuses
+ }
+
+ return true
+}
+
+func renderFile(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["IsViewFile"] = true
ctx.Data["HideRepoInfo"] = true
blob := entry.Blob()
@@ -351,7 +384,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName)
ctx.Data["FileIsSymlink"] = entry.IsLink()
ctx.Data["FileName"] = blob.Name()
- ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
+ ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
+
+ commit, err := ctx.Repo.Commit.GetCommitByPath(ctx.Repo.TreePath)
+ if err != nil {
+ ctx.ServerError("GetCommitByPath", err)
+ return
+ }
+
+ if !loadLatestCommitData(ctx, commit) {
+ return
+ }
if ctx.Repo.TreePath == ".editorconfig" {
_, editorconfigWarning, editorconfigErr := ctx.Repo.GetEditorconfig(ctx.Repo.Commit)
@@ -479,9 +522,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
Ctx: ctx,
Type: markupType,
RelativePath: ctx.Repo.TreePath,
- URLPrefix: path.Dir(treeLink),
- Metas: metas,
- GitRepo: ctx.Repo.GitRepo,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ BranchPath: ctx.Repo.BranchNameSubURL(),
+ TreePath: path.Dir(ctx.Repo.TreePath),
+ },
+ Metas: metas,
+ GitRepo: ctx.Repo.GitRepo,
}, rd)
if err != nil {
ctx.ServerError("Render", err)
@@ -493,7 +540,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
buf, _ := io.ReadAll(rd)
// The Open Group Base Specification: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html
- // empty: 0 lines; "a": 1 line, 1 incomplete-line; "a\n": 1 line; "a\nb": 1 line, 1 incomplete-line;
+ // empty: 0 lines; "a": 1 incomplete-line; "a\n": 1 line; "a\nb": 1 line, 1 incomplete-line;
// Gitea uses the definition (like most modern editors):
// empty: 0 lines; "a": 1 line; "a\n": 2 lines; "a\nb": 2 lines;
// When rendering, the last empty line is not rendered in UI, while the line-number is still counted, to tell users that the file contains a trailing EOL.
@@ -585,9 +632,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
Ctx: ctx,
RelativePath: ctx.Repo.TreePath,
- URLPrefix: path.Dir(treeLink),
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
- GitRepo: ctx.Repo.GitRepo,
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ BranchPath: ctx.Repo.BranchNameSubURL(),
+ TreePath: path.Dir(ctx.Repo.TreePath),
+ },
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
}, rd)
if err != nil {
ctx.ServerError("Render", err)
@@ -620,7 +671,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
}
-func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input io.Reader) (escaped *charset.EscapeStatus, output string, err error) {
+func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input io.Reader) (escaped *charset.EscapeStatus, output template.HTML, err error) {
markupRd, markupWr := io.Pipe()
defer markupWr.Close()
done := make(chan struct{})
@@ -628,7 +679,7 @@ func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input i
sb := &strings.Builder{}
// We allow NBSP here this is rendered
escaped, _ = charset.EscapeControlReader(markupRd, sb, ctx.Locale, charset.RuneNBSP)
- output = sb.String()
+ output = template.HTML(sb.String())
close(done)
}()
err = markup.Render(renderCtx, input, markupWr)
@@ -711,21 +762,14 @@ func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
}
for _, entry := range allEntries {
if entry.Name() == "CITATION.cff" || entry.Name() == "CITATION.bib" {
- ctx.Data["CitiationExist"] = true
// Read Citation file contents
- blob := entry.Blob()
- dataRc, err := blob.DataAsync()
- if err != nil {
- ctx.ServerError("DataAsync", err)
- return
+ if content, err := entry.Blob().GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil {
+ log.Error("checkCitationFile: GetBlobContent: %v", err)
+ } else {
+ ctx.Data["CitiationExist"] = true
+ ctx.PageData["citationFileContent"] = content
+ break
}
- defer dataRc.Close()
- ctx.PageData["citationFileContent"], err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
- if err != nil {
- ctx.ServerError("GetBlobContent", err)
- return
- }
- break
}
}
}
@@ -841,29 +885,8 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri
return nil
}
- // Show latest commit info of repository in table header,
- // or of directory if not in root directory.
- ctx.Data["LatestCommit"] = latestCommit
- if latestCommit != nil {
-
- verification := asymkey_model.ParseCommitWithSignature(ctx, latestCommit)
-
- if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) {
- return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID)
- }, nil); err != nil {
- ctx.ServerError("CalculateTrustStatus", err)
- return nil
- }
- ctx.Data["LatestCommitVerification"] = verification
- ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(ctx, latestCommit)
-
- statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, latestCommit.ID.String(), db.ListOptions{ListAll: true})
- if err != nil {
- log.Error("GetLatestCommitStatus: %v", err)
- }
-
- ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
- ctx.Data["LatestCommitStatuses"] = statuses
+ if !loadLatestCommitData(ctx, latestCommit) {
+ return nil
}
branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
@@ -952,14 +975,6 @@ func renderCode(ctx *context.Context) {
}
ctx.Data["Title"] = title
- branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
- treeLink := branchLink
- rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL()
-
- if len(ctx.Repo.TreePath) > 0 {
- treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
- }
-
// Get Topics of this repo
renderRepoTopics(ctx)
if ctx.Written() {
@@ -984,9 +999,9 @@ func renderCode(ctx *context.Context) {
}
if entry.IsDir() {
- renderDirectory(ctx, treeLink)
+ renderDirectory(ctx)
} else {
- renderFile(ctx, entry, treeLink, rawLink)
+ renderFile(ctx, entry)
}
if ctx.Written() {
return
@@ -1027,6 +1042,12 @@ func renderCode(ctx *context.Context) {
}
ctx.Data["Paths"] = paths
+
+ branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
+ treeLink := branchLink
+ if len(ctx.Repo.TreePath) > 0 {
+ treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
+ }
ctx.Data["TreeLink"] = treeLink
ctx.Data["TreeNames"] = treeNames
ctx.Data["BranchLink"] = branchLink
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 8ea18a186c..4e09f046cf 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -238,10 +238,12 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
}
rctx := &markup.RenderContext{
- Ctx: ctx,
- URLPrefix: ctx.Repo.RepoLink,
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
- IsWiki: true,
+ Ctx: ctx,
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(ctx),
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ },
+ IsWiki: true,
}
buf := &strings.Builder{}
diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go
index 411d499eb4..0f8d64e7b2 100644
--- a/routers/web/shared/user/header.go
+++ b/routers/web/shared/user/header.go
@@ -47,10 +47,8 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
if len(ctx.ContextUser.Description) != 0 {
content, err := markdown.RenderString(&markup.RenderContext{
- URLPrefix: ctx.Repo.RepoLink,
- Metas: map[string]string{"mode": "document"},
- GitRepo: ctx.Repo.GitRepo,
- Ctx: ctx,
+ Metas: map[string]string{"mode": "document"},
+ Ctx: ctx,
}, ctx.ContextUser.Description)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -87,7 +85,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
}
}
-func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profileGitRepo *git.Repository, profileReadmeBlob *git.Blob, profileClose func()) {
+func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadmeBlob *git.Blob, profileClose func()) {
profileDbRepo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ".profile")
if err == nil {
perm, err := access_model.GetUserRepoPermission(ctx, profileDbRepo, doer)
@@ -105,7 +103,7 @@ func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profile
} else if !repo_model.IsErrRepoNotExist(err) {
log.Error("FindUserProfileReadme failed to GetRepositoryByName: %v", err)
}
- return profileGitRepo, profileReadmeBlob, func() {
+ return profileDbRepo, profileGitRepo, profileReadmeBlob, func() {
if profileGitRepo != nil {
_ = profileGitRepo.Close()
}
@@ -115,7 +113,7 @@ func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profile
func RenderUserHeader(ctx *context.Context) {
prepareContextForCommonProfile(ctx)
- _, profileReadmeBlob, profileClose := FindUserProfileReadme(ctx, ctx.Doer)
+ _, _, profileReadmeBlob, profileClose := FindUserProfileReadme(ctx, ctx.Doer)
defer profileClose()
ctx.Data["HasProfileReadme"] = profileReadmeBlob != nil
}
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index b4fb25dfe0..44920817c9 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -26,7 +26,6 @@ import (
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/context"
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
- "code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
@@ -213,13 +212,26 @@ func Milestones(ctx *context.Context) {
}
}
- counts, err := issues_model.CountMilestonesByRepoCondAndKw(ctx, userRepoCond, keyword, isShowClosed)
+ counts, err := issues_model.CountMilestonesMap(ctx, issues_model.FindMilestoneOptions{
+ RepoCond: userRepoCond,
+ Name: keyword,
+ IsClosed: util.OptionalBoolOf(isShowClosed),
+ })
if err != nil {
ctx.ServerError("CountMilestonesByRepoIDs", err)
return
}
- milestones, err := issues_model.SearchMilestones(ctx, repoCond, page, isShowClosed, sortType, keyword)
+ milestones, err := db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
+ ListOptions: db.ListOptions{
+ Page: page,
+ PageSize: setting.UI.IssuePagingNum,
+ },
+ RepoCond: repoCond,
+ IsClosed: util.OptionalBoolOf(isShowClosed),
+ SortType: sortType,
+ Name: keyword,
+ })
if err != nil {
ctx.ServerError("SearchMilestones", err)
return
@@ -246,9 +258,11 @@ func Milestones(ctx *context.Context) {
}
milestones[i].RenderedContent, err = markdown.RenderString(&markup.RenderContext{
- URLPrefix: milestones[i].Repo.Link(),
- Metas: milestones[i].Repo.ComposeMetas(ctx),
- Ctx: ctx,
+ Links: markup.Links{
+ Base: milestones[i].Repo.Link(),
+ },
+ Metas: milestones[i].Repo.ComposeMetas(ctx),
+ Ctx: ctx,
}, milestones[i].Content)
if err != nil {
ctx.ServerError("RenderString", err)
@@ -335,7 +349,6 @@ func Pulls(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("pull_requests")
ctx.Data["PageIsPulls"] = true
- ctx.Data["SingleRepoAction"] = "pull"
buildIssueOverview(ctx, unit.TypePullRequests)
}
@@ -349,7 +362,6 @@ func Issues(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("issues")
ctx.Data["PageIsIssues"] = true
- ctx.Data["SingleRepoAction"] = "issue"
buildIssueOverview(ctx, unit.TypeIssues)
}
@@ -475,6 +487,13 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
opts.RepoIDs = []int64{0}
}
}
+ if ctx.Doer.ID == ctxUser.ID && filterMode != issues_model.FilterModeYourRepositories {
+ // If the doer is the same as the context user, which means the doer is viewing his own dashboard,
+ // it's not enough to show the repos that the doer owns or has been explicitly granted access to,
+ // because the doer may create issues or be mentioned in any public repo.
+ // So we need search issues in all public repos.
+ opts.AllPublic = true
+ }
switch filterMode {
case issues_model.FilterModeAll:
@@ -499,14 +518,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
isShowClosed := ctx.FormString("state") == "closed"
opts.IsClosed = util.OptionalBoolOf(isShowClosed)
- // Filter repos and count issues in them. Count will be used later.
- // USING NON-FINAL STATE OF opts FOR A QUERY.
- issueCountByRepo, err := issue_indexer.CountIssuesByRepo(ctx, issue_indexer.ToSearchOptions(keyword, opts))
- if err != nil {
- ctx.ServerError("CountIssuesByRepo", err)
- return
- }
-
// Make sure page number is at least 1. Will be posted to ctx.Data.
page := ctx.FormInt("page")
if page <= 1 {
@@ -531,17 +542,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
}
opts.LabelIDs = labelIDs
- // Parse ctx.FormString("repos") and remember matched repo IDs for later.
- // Gets set when clicking filters on the issues overview page.
- selectedRepoIDs := getRepoIDs(ctx.FormString("repos"))
- // Remove repo IDs that are not accessible to the user.
- selectedRepoIDs = slices.DeleteFunc(selectedRepoIDs, func(v int64) bool {
- return !accessibleRepos.Contains(v)
- })
- if len(selectedRepoIDs) > 0 {
- opts.RepoIDs = selectedRepoIDs
- }
-
// ------------------------------
// Get issues as defined by opts.
// ------------------------------
@@ -562,41 +562,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
}
}
- // ----------------------------------
- // Add repository pointers to Issues.
- // ----------------------------------
-
- // Remove repositories that should not be shown,
- // which are repositories that have no issues and are not selected by the user.
- selectedRepos := container.SetOf(selectedRepoIDs...)
- for k, v := range issueCountByRepo {
- if v == 0 && !selectedRepos.Contains(k) {
- delete(issueCountByRepo, k)
- }
- }
-
- // showReposMap maps repository IDs to their Repository pointers.
- showReposMap, err := loadRepoByIDs(ctx, ctxUser, issueCountByRepo, unitType)
- if err != nil {
- if repo_model.IsErrRepoNotExist(err) {
- ctx.NotFound("GetRepositoryByID", err)
- return
- }
- ctx.ServerError("loadRepoByIDs", err)
- return
- }
-
- // a RepositoryList
- showRepos := repo_model.RepositoryListOfMap(showReposMap)
- sort.Sort(showRepos)
-
- // maps pull request IDs to their CommitStatus. Will be posted to ctx.Data.
- for _, issue := range issues {
- if issue.Repo == nil {
- issue.Repo = showReposMap[issue.RepoID]
- }
- }
-
commitStatuses, lastStatus, err := pull_service.GetIssuesAllCommitStatus(ctx, issues)
if err != nil {
ctx.ServerError("GetIssuesLastCommitStatus", err)
@@ -606,7 +571,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
// -------------------------------
// Fill stats to post to ctx.Data.
// -------------------------------
- issueStats, err := getUserIssueStats(ctx, filterMode, issue_indexer.ToSearchOptions(keyword, opts), ctx.Doer.ID)
+ issueStats, err := getUserIssueStats(ctx, ctxUser, filterMode, issue_indexer.ToSearchOptions(keyword, opts))
if err != nil {
ctx.ServerError("getUserIssueStats", err)
return
@@ -619,25 +584,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
} else {
shownIssues = int(issueStats.ClosedCount)
}
- if len(opts.RepoIDs) != 0 {
- shownIssues = 0
- for _, repoID := range opts.RepoIDs {
- shownIssues += int(issueCountByRepo[repoID])
- }
- }
-
- var allIssueCount int64
- for _, issueCount := range issueCountByRepo {
- allIssueCount += issueCount
- }
- ctx.Data["TotalIssueCount"] = allIssueCount
-
- if len(opts.RepoIDs) == 1 {
- repo := showReposMap[opts.RepoIDs[0]]
- if repo != nil {
- ctx.Data["SingleRepoLink"] = repo.Link()
- }
- }
ctx.Data["IsShowClosed"] = isShowClosed
@@ -674,12 +620,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
}
ctx.Data["CommitLastStatus"] = lastStatus
ctx.Data["CommitStatuses"] = commitStatuses
- ctx.Data["Repos"] = showRepos
- ctx.Data["Counts"] = issueCountByRepo
ctx.Data["IssueStats"] = issueStats
ctx.Data["ViewType"] = viewType
ctx.Data["SortType"] = sortType
- ctx.Data["RepoIDs"] = selectedRepoIDs
ctx.Data["IsShowClosed"] = isShowClosed
ctx.Data["SelectLabels"] = selectedLabels
@@ -689,15 +632,9 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
ctx.Data["State"] = "open"
}
- // Convert []int64 to string
- reposParam, _ := json.Marshal(opts.RepoIDs)
-
- ctx.Data["ReposParam"] = string(reposParam)
-
pager := context.NewPagination(shownIssues, setting.UI.IssuePagingNum, page, 5)
pager.AddParam(ctx, "q", "Keyword")
pager.AddParam(ctx, "type", "ViewType")
- pager.AddParam(ctx, "repos", "ReposParam")
pager.AddParam(ctx, "sort", "SortType")
pager.AddParam(ctx, "state", "State")
pager.AddParam(ctx, "labels", "SelectLabels")
@@ -708,55 +645,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
ctx.HTML(http.StatusOK, tplIssues)
}
-func getRepoIDs(reposQuery string) []int64 {
- if len(reposQuery) == 0 || reposQuery == "[]" {
- return []int64{}
- }
- if !issueReposQueryPattern.MatchString(reposQuery) {
- log.Warn("issueReposQueryPattern does not match query: %q", reposQuery)
- return []int64{}
- }
-
- var repoIDs []int64
- // remove "[" and "]" from string
- reposQuery = reposQuery[1 : len(reposQuery)-1]
- // for each ID (delimiter ",") add to int to repoIDs
- for _, rID := range strings.Split(reposQuery, ",") {
- // Ensure nonempty string entries
- if rID != "" && rID != "0" {
- rIDint64, err := strconv.ParseInt(rID, 10, 64)
- if err == nil {
- repoIDs = append(repoIDs, rIDint64)
- }
- }
- }
-
- return repoIDs
-}
-
-func loadRepoByIDs(ctx *context.Context, ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) {
- totalRes := make(map[int64]*repo_model.Repository, len(issueCountByRepo))
- repoIDs := make([]int64, 0, 500)
- for id := range issueCountByRepo {
- if id <= 0 {
- continue
- }
- repoIDs = append(repoIDs, id)
- if len(repoIDs) == 500 {
- if err := repo_model.FindReposMapByIDs(ctx, repoIDs, totalRes); err != nil {
- return nil, err
- }
- repoIDs = repoIDs[:0]
- }
- }
- if len(repoIDs) > 0 {
- if err := repo_model.FindReposMapByIDs(ctx, repoIDs, totalRes); err != nil {
- return nil, err
- }
- }
- return totalRes, nil
-}
-
// ShowSSHKeys output all the ssh keys of user by uid
func ShowSSHKeys(ctx *context.Context) {
keys, err := db.Find[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
@@ -777,7 +665,10 @@ func ShowSSHKeys(ctx *context.Context) {
// ShowGPGKeys output all the public GPG keys of user by uid
func ShowGPGKeys(ctx *context.Context) {
- keys, err := asymkey_model.ListGPGKeys(ctx, ctx.ContextUser.ID, db.ListOptions{})
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ ListOptions: db.ListOptionsAll,
+ OwnerID: ctx.ContextUser.ID,
+ })
if err != nil {
ctx.ServerError("ListGPGKeys", err)
return
@@ -870,8 +761,15 @@ func UsernameSubRoute(ctx *context.Context) {
}
}
-func getUserIssueStats(ctx *context.Context, filterMode int, opts *issue_indexer.SearchOptions, doerID int64) (*issues_model.IssueStats, error) {
+func getUserIssueStats(ctx *context.Context, ctxUser *user_model.User, filterMode int, opts *issue_indexer.SearchOptions) (*issues_model.IssueStats, error) {
+ doerID := ctx.Doer.ID
+
opts = opts.Copy(func(o *issue_indexer.SearchOptions) {
+ // If the doer is the same as the context user, which means the doer is viewing his own dashboard,
+ // it's not enough to show the repos that the doer owns or has been explicitly granted access to,
+ // because the doer may create issues or be mentioned in any public repo.
+ // So we need search issues in all public repos.
+ o.AllPublic = doerID == ctxUser.ID
o.AssigneeID = nil
o.PosterID = nil
o.MentionID = nil
@@ -887,7 +785,10 @@ func getUserIssueStats(ctx *context.Context, filterMode int, opts *issue_indexer
{
openClosedOpts := opts.Copy()
switch filterMode {
- case issues_model.FilterModeAll, issues_model.FilterModeYourRepositories:
+ case issues_model.FilterModeAll:
+ // no-op
+ case issues_model.FilterModeYourRepositories:
+ openClosedOpts.AllPublic = false
case issues_model.FilterModeAssign:
openClosedOpts.AssigneeID = &doerID
case issues_model.FilterModeCreate:
@@ -911,7 +812,7 @@ func getUserIssueStats(ctx *context.Context, filterMode int, opts *issue_indexer
}
}
- ret.YourRepositoriesCount, err = issue_indexer.CountIssues(ctx, opts)
+ ret.YourRepositoriesCount, err = issue_indexer.CountIssues(ctx, opts.Copy(func(o *issue_indexer.SearchOptions) { o.AllPublic = false }))
if err != nil {
return nil, err
}
diff --git a/routers/web/user/home_test.go b/routers/web/user/home_test.go
index 1eb1fad057..a32b015cd1 100644
--- a/routers/web/user/home_test.go
+++ b/routers/web/user/home_test.go
@@ -45,9 +45,7 @@ func TestArchivedIssues(t *testing.T) {
// Assert: One Issue (ID 30) from one Repo (ID 50) is retrieved, while nothing from archived Repo 51 is retrieved
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
- assert.EqualValues(t, map[int64]int64{50: 1}, ctx.Data["Counts"])
assert.Len(t, ctx.Data["Issues"], 1)
- assert.Len(t, ctx.Data["Repos"], 1)
}
func TestIssues(t *testing.T) {
@@ -60,10 +58,8 @@ func TestIssues(t *testing.T) {
Issues(ctx)
assert.EqualValues(t, http.StatusOK, ctx.Resp.Status())
- assert.EqualValues(t, map[int64]int64{1: 1, 2: 1}, ctx.Data["Counts"])
assert.EqualValues(t, true, ctx.Data["IsShowClosed"])
assert.Len(t, ctx.Data["Issues"], 1)
- assert.Len(t, ctx.Data["Repos"], 2)
}
func TestPulls(t *testing.T) {
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index ac278e300d..c5305ebcd9 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -7,6 +7,7 @@ package user
import (
"fmt"
"net/http"
+ "path"
"strings"
activities_model "code.gitea.io/gitea/models/activities"
@@ -64,17 +65,17 @@ func userProfile(ctx *context.Context) {
ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
}
- profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
+ profileDbRepo, profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
defer profileClose()
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
- prepareUserProfileTabData(ctx, showPrivate, profileGitRepo, profileReadmeBlob)
+ prepareUserProfileTabData(ctx, showPrivate, profileDbRepo, profileGitRepo, profileReadmeBlob)
// call PrepareContextForProfileBigAvatar later to avoid re-querying the NumFollowers & NumFollowing
shared_user.PrepareContextForProfileBigAvatar(ctx)
ctx.HTML(http.StatusOK, tplProfile)
}
-func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGitRepo *git.Repository, profileReadme *git.Blob) {
+func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadme *git.Blob) {
// if there is a profile readme, default to "overview" page, otherwise, default to "repositories" page
// if there is not a profile readme, the overview tab should be treated as the repositories tab
tab := ctx.FormString("tab")
@@ -236,7 +237,16 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGi
if profileContent, err := markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
GitRepo: profileGitRepo,
- Metas: map[string]string{"mode": "document"},
+ Links: markup.Links{
+ // Give the repo link to the markdown render for the full link of media element.
+ // the media link usually be like /[user]/[repoName]/media/branch/[branchName],
+ // Eg. /Tom/.profile/media/branch/main
+ // The branch shown on the profile page is the default branch, this need to be in sync with doc, see:
+ // https://docs.gitea.com/usage/profile-readme
+ Base: profileDbRepo.Link(),
+ BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
+ },
+ Metas: map[string]string{"mode": "document"},
}, bytes); err != nil {
log.Error("failed to RenderString: %v", err)
} else {
diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go
index 5c14f3ad4b..7a306636e0 100644
--- a/routers/web/user/setting/account.go
+++ b/routers/web/user/setting/account.go
@@ -105,7 +105,7 @@ func EmailPost(ctx *context.Context) {
// Send activation Email
if ctx.FormString("_method") == "SENDACTIVATION" {
var address string
- if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) {
+ if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) {
log.Error("Send activation: activation still pending")
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
@@ -141,11 +141,10 @@ func EmailPost(ctx *context.Context) {
}
address = email.Email
- if setting.CacheService.Enabled {
- if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
- log.Error("Set cache(MailResendLimit) fail: %v", err)
- }
+ if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
+ log.Error("Set cache(MailResendLimit) fail: %v", err)
}
+
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
@@ -204,11 +203,10 @@ func EmailPost(ctx *context.Context) {
// Send confirmation email
if setting.Service.RegisterEmailConfirm {
mailer.SendActivateEmailMail(ctx.Doer, email)
- if setting.CacheService.Enabled {
- if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
- log.Error("Set cache(MailResendLimit) fail: %v", err)
- }
+ if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil {
+ log.Error("Set cache(MailResendLimit) fail: %v", err)
}
+
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
} else {
ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
@@ -246,6 +244,13 @@ func DeleteAccount(ctx *context.Context) {
return
}
+ // admin should not delete themself
+ if ctx.Doer.IsAdmin {
+ ctx.Flash.Error(ctx.Tr("form.admin_cannot_delete_self"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/account")
+ return
+ }
+
if err := user.DeleteUser(ctx, ctx.Doer, false); err != nil {
switch {
case models.IsErrUserOwnRepos(err):
@@ -257,6 +262,9 @@ func DeleteAccount(ctx *context.Context) {
case models.IsErrUserOwnPackages(err):
ctx.Flash.Error(ctx.Tr("form.still_own_packages"))
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
+ case models.IsErrDeleteLastAdminUser(err):
+ ctx.Flash.Error(ctx.Tr("auth.last_admin"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/account")
default:
ctx.ServerError("DeleteUser", err)
}
@@ -276,7 +284,7 @@ func loadAccountData(ctx *context.Context) {
user_model.EmailAddress
CanBePrimary bool
}
- pendingActivation := setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName)
+ pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName)
emails := make([]*UserEmail, len(emlist))
for i, em := range emlist {
var email UserEmail
diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go
index 0dfb506fa9..16410d06ff 100644
--- a/routers/web/user/setting/keys.go
+++ b/routers/web/user/setting/keys.go
@@ -277,18 +277,29 @@ func loadKeysData(ctx *context.Context) {
}
ctx.Data["ExternalKeys"] = externalKeys
- gpgkeys, err := asymkey_model.ListGPGKeys(ctx, ctx.Doer.ID, db.ListOptions{})
+ gpgkeys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ ListOptions: db.ListOptionsAll,
+ OwnerID: ctx.Doer.ID,
+ })
if err != nil {
ctx.ServerError("ListGPGKeys", err)
return
}
+ if err := asymkey_model.GPGKeyList(gpgkeys).LoadSubKeys(ctx); err != nil {
+ ctx.ServerError("LoadSubKeys", err)
+ return
+ }
ctx.Data["GPGKeys"] = gpgkeys
tokenToSign := asymkey_model.VerificationToken(ctx.Doer, 1)
// generate a new aes cipher using the csrfToken
ctx.Data["TokenToSign"] = tokenToSign
- principals, err := asymkey_model.ListPrincipalKeys(ctx, ctx.Doer.ID, db.ListOptions{})
+ principals, err := db.Find[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
+ ListOptions: db.ListOptionsAll,
+ OwnerID: ctx.Doer.ID,
+ KeyTypes: []asymkey_model.KeyType{asymkey_model.KeyTypePrincipal},
+ })
if err != nil {
ctx.ServerError("ListPrincipalKeys", err)
return
diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go
index d8331fef43..00614565d2 100644
--- a/routers/web/user/setting/profile.go
+++ b/routers/web/user/setting/profile.go
@@ -14,6 +14,7 @@ import (
"path/filepath"
"strings"
+ "code.gitea.io/gitea/models/avatars"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
@@ -130,7 +131,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
ctxUser.UseCustomAvatar = form.Source == forms.AvatarLocal
if len(form.Gravatar) > 0 {
if form.Avatar != nil {
- ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
+ ctxUser.Avatar = avatars.HashEmail(form.Gravatar)
} else {
ctxUser.Avatar = ""
}
diff --git a/routers/web/web.go b/routers/web/web.go
index da7360f1b8..22f98d95de 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -60,13 +60,12 @@ const (
GzipMinSize = 1400
)
-// CorsHandler return a http handler who set CORS options if enabled by config
-func CorsHandler() func(next http.Handler) http.Handler {
+// optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests.
+func optionsCorsHandler() func(next http.Handler) http.Handler {
+ var corsHandler func(next http.Handler) http.Handler
if setting.CORSConfig.Enabled {
- return cors.Handler(cors.Options{
- // Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option
- AllowedOrigins: setting.CORSConfig.AllowDomain,
- // setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
+ corsHandler = cors.Handler(cors.Options{
+ AllowedOrigins: setting.CORSConfig.AllowDomain,
AllowedMethods: setting.CORSConfig.Methods,
AllowCredentials: setting.CORSConfig.AllowCredentials,
AllowedHeaders: setting.CORSConfig.Headers,
@@ -75,7 +74,23 @@ func CorsHandler() func(next http.Handler) http.Handler {
}
return func(next http.Handler) http.Handler {
- return next
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodOptions {
+ if corsHandler != nil && r.Header.Get("Access-Control-Request-Method") != "" {
+ corsHandler(next).ServeHTTP(w, r)
+ } else {
+ // it should explicitly deny OPTIONS requests if CORS handler is not executed, to avoid the next GET/POST handler being incorrectly called by the OPTIONS request
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ }
+ return
+ }
+ // for non-OPTIONS requests, call the CORS handler to add some related headers like "Vary"
+ if corsHandler != nil {
+ corsHandler(next).ServeHTTP(w, r)
+ } else {
+ next.ServeHTTP(w, r)
+ }
+ })
}
}
@@ -218,7 +233,7 @@ func Routes() *web.Route {
routes := web.NewRoute()
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
- routes.Methods("GET, HEAD", "/assets/*", CorsHandler(), public.FileHandlerFunc())
+ routes.Methods("GET, HEAD, OPTIONS", "/assets/*", optionsCorsHandler(), public.FileHandlerFunc())
routes.Methods("GET, HEAD", "/avatars/*", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
routes.Methods("GET, HEAD", "/repo-avatars/*", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
@@ -417,7 +432,7 @@ func registerRoutes(m *web.Route) {
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo_setting.PackagistHooksEditPost)
}
- addSettingVariablesRoutes := func() {
+ addSettingsVariablesRoutes := func() {
m.Group("/variables", func() {
m.Get("", repo_setting.Variables)
m.Post("/new", web.Bind(forms.EditVariableForm{}), repo_setting.VariableCreate)
@@ -458,8 +473,8 @@ func registerRoutes(m *web.Route) {
m.Get("/change-password", func(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
})
- m.Any("/*", CorsHandler(), public.FileHandlerFunc())
- }, CorsHandler())
+ m.Methods("GET, HEAD", "/*", public.FileHandlerFunc())
+ }, optionsCorsHandler())
m.Group("/explore", func() {
m.Get("", func(ctx *context.Context) {
@@ -532,12 +547,11 @@ func registerRoutes(m *web.Route) {
// TODO manage redirection
m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
}, ignSignInAndCsrf, reqSignIn)
- m.Get("/login/oauth/userinfo", ignSignInAndCsrf, auth.InfoOAuth)
- m.Options("/login/oauth/access_token", CorsHandler(), misc.DummyBadRequest)
- m.Post("/login/oauth/access_token", CorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
- m.Get("/login/oauth/keys", ignSignInAndCsrf, auth.OIDCKeys)
- m.Options("/login/oauth/introspect", CorsHandler(), misc.DummyBadRequest)
- m.Post("/login/oauth/introspect", CorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
+
+ m.Methods("GET, OPTIONS", "/login/oauth/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
+ m.Methods("POST, OPTIONS", "/login/oauth/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
+ m.Methods("GET, OPTIONS", "/login/oauth/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys)
+ m.Methods("POST, OPTIONS", "/login/oauth/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
m.Group("/user/settings", func() {
m.Get("", user_setting.Profile)
@@ -616,7 +630,7 @@ func registerRoutes(m *web.Route) {
m.Get("", user_setting.RedirectToDefaultSetting)
addSettingsRunnersRoutes()
addSettingsSecretsRoutes()
- addSettingVariablesRoutes()
+ addSettingsVariablesRoutes()
}, actions.MustEnableActions)
m.Get("/organization", user_setting.Organization)
@@ -664,6 +678,8 @@ func registerRoutes(m *web.Route) {
m.Get("", admin.Dashboard)
m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
+ m.Get("/self_check", admin.SelfCheck)
+
m.Group("/config", func() {
m.Get("", admin.Config)
m.Post("", admin.ChangeConfig)
@@ -761,13 +777,14 @@ func registerRoutes(m *web.Route) {
m.Group("/actions", func() {
m.Get("", admin.RedirectToDefaultSetting)
addSettingsRunnersRoutes()
+ addSettingsVariablesRoutes()
})
}, adminReq, ctxDataSet("EnableOAuth2", setting.OAuth2.Enable, "EnablePackages", setting.Packages.Enabled))
// ***** END: Admin *****
m.Group("", func() {
m.Get("/{username}", user.UsernameSubRoute)
- m.Get("/attachments/{uuid}", repo.GetAttachment)
+ m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment)
}, ignSignIn)
m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action)
@@ -796,6 +813,24 @@ func registerRoutes(m *web.Route) {
}
}
+ individualPermsChecker := func(ctx *context.Context) {
+ // org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
+ if ctx.ContextUser.IsIndividual() {
+ switch {
+ case ctx.ContextUser.Visibility == structs.VisibleTypePrivate:
+ if ctx.Doer == nil || (ctx.ContextUser.ID != ctx.Doer.ID && !ctx.Doer.IsAdmin) {
+ ctx.NotFound("Visit Project", nil)
+ return
+ }
+ case ctx.ContextUser.Visibility == structs.VisibleTypeLimited:
+ if ctx.Doer == nil {
+ ctx.NotFound("Visit Project", nil)
+ return
+ }
+ }
+ }
+ }
+
// ***** START: Organization *****
m.Group("/org", func() {
m.Group("/{org}", func() {
@@ -885,7 +920,7 @@ func registerRoutes(m *web.Route) {
m.Get("", org_setting.RedirectToDefaultSetting)
addSettingsRunnersRoutes()
addSettingsSecretsRoutes()
- addSettingVariablesRoutes()
+ addSettingsVariablesRoutes()
}, actions.MustEnableActions)
m.Methods("GET,POST", "/delete", org.SettingsDelete)
@@ -976,11 +1011,11 @@ func registerRoutes(m *web.Route) {
return
}
})
- })
+ }, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true), individualPermsChecker)
m.Group("", func() {
m.Get("/code", user.CodeSearch)
- }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false))
+ }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker)
}, ignSignIn, context_service.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code)
m.Group("/{username}/{reponame}", func() {
@@ -1064,7 +1099,7 @@ func registerRoutes(m *web.Route) {
m.Get("", repo_setting.RedirectToDefaultSetting)
addSettingsRunnersRoutes()
addSettingsSecretsRoutes()
- addSettingVariablesRoutes()
+ addSettingsVariablesRoutes()
}, actions.MustEnableActions)
// the follow handler must be under "settings", otherwise this incomplete repo can't be accessed
m.Group("/migrate", func() {
diff --git a/services/actions/commit_status.go b/services/actions/commit_status.go
index 08a7dde67c..72a3ab7ac6 100644
--- a/services/actions/commit_status.go
+++ b/services/actions/commit_status.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
user_model "code.gitea.io/gitea/models/user"
+ git "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
api "code.gitea.io/gitea/modules/structs"
webhook_module "code.gitea.io/gitea/modules/webhook"
@@ -114,9 +115,13 @@ func createCommitStatus(ctx context.Context, job *actions_model.ActionRunJob) er
}
creator := user_model.NewActionsUser()
+ commitID, err := git.NewIDFromString(sha)
+ if err != nil {
+ return fmt.Errorf("HashTypeInterfaceFromHashString: %w", err)
+ }
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
Repo: repo,
- SHA: sha,
+ SHA: commitID,
Creator: creator,
CommitStatus: &git_model.CommitStatus{
SHA: sha,
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 175b8a4118..0618f15602 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -117,6 +117,9 @@ func notify(ctx context.Context, input *notifyInput) error {
return nil
}
if unit_model.TypeActions.UnitGlobalDisabled() {
+ if err := actions_model.CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
+ log.Error("CleanRepoScheduleTasks: %v", err)
+ }
return nil
}
if err := input.Repo.LoadUnits(ctx); err != nil {
@@ -153,7 +156,11 @@ func notify(ctx context.Context, input *notifyInput) error {
var detectedWorkflows []*actions_module.DetectedWorkflow
actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig()
- workflows, schedules, err := actions_module.DetectWorkflows(gitRepo, commit, input.Event, input.Payload)
+ workflows, schedules, err := actions_module.DetectWorkflows(gitRepo, commit,
+ input.Event,
+ input.Payload,
+ input.Event == webhook_module.HookEventPush && input.Ref == input.Repo.DefaultBranch,
+ )
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
@@ -167,7 +174,7 @@ func notify(ctx context.Context, input *notifyInput) error {
continue
}
- if wf.TriggerEvent != actions_module.GithubEventPullRequestTarget {
+ if wf.TriggerEvent.Name != actions_module.GithubEventPullRequestTarget {
detectedWorkflows = append(detectedWorkflows, wf)
}
}
@@ -180,7 +187,7 @@ func notify(ctx context.Context, input *notifyInput) error {
if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %w", err)
}
- baseWorkflows, _, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload)
+ baseWorkflows, _, err := actions_module.DetectWorkflows(gitRepo, baseCommit, input.Event, input.Payload, false)
if err != nil {
return fmt.Errorf("DetectWorkflows: %w", err)
}
@@ -188,14 +195,14 @@ func notify(ctx context.Context, input *notifyInput) error {
log.Trace("repo %s with commit %s couldn't find pull_request_target workflows", input.Repo.RepoPath(), baseCommit.ID)
} else {
for _, wf := range baseWorkflows {
- if wf.TriggerEvent == actions_module.GithubEventPullRequestTarget {
+ if wf.TriggerEvent.Name == actions_module.GithubEventPullRequestTarget {
detectedWorkflows = append(detectedWorkflows, wf)
}
}
}
}
- if err := handleSchedules(ctx, schedules, commit, input); err != nil {
+ if err := handleSchedules(ctx, schedules, commit, input, ref); err != nil {
return err
}
@@ -265,7 +272,7 @@ func handleWorkflows(
IsForkPullRequest: isForkPullRequest,
Event: input.Event,
EventPayload: string(p),
- TriggerEvent: dwf.TriggerEvent,
+ TriggerEvent: dwf.TriggerEvent.Name,
Status: actions_model.StatusWaiting,
}
if need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer); err != nil {
@@ -289,6 +296,7 @@ func handleWorkflows(
run.RepoID,
run.Ref,
run.WorkflowID,
+ run.Event,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
@@ -399,6 +407,7 @@ func handleSchedules(
detectedWorkflows []*actions_module.DetectedWorkflow,
commit *git.Commit,
input *notifyInput,
+ ref string,
) error {
branch, err := commit.GetBranchName()
if err != nil {
@@ -413,8 +422,8 @@ func handleSchedules(
log.Error("CountSchedules: %v", err)
return err
} else if count > 0 {
- if err := actions_model.DeleteScheduleTaskByRepo(ctx, input.Repo.ID); err != nil {
- log.Error("DeleteCronTaskByRepo: %v", err)
+ if err := actions_model.CleanRepoScheduleTasks(ctx, input.Repo); err != nil {
+ log.Error("CleanRepoScheduleTasks: %v", err)
}
}
@@ -448,26 +457,13 @@ func handleSchedules(
OwnerID: input.Repo.OwnerID,
WorkflowID: dwf.EntryName,
TriggerUserID: input.Doer.ID,
- Ref: input.Ref,
+ Ref: ref,
CommitSHA: commit.ID.String(),
Event: input.Event,
EventPayload: string(p),
Specs: schedules,
Content: dwf.Content,
}
-
- // cancel running jobs if the event is push
- if run.Event == webhook_module.HookEventPush {
- // cancel running jobs of the same workflow
- if err := actions_model.CancelRunningJobs(
- ctx,
- run.RepoID,
- run.Ref,
- run.WorkflowID,
- ); err != nil {
- log.Error("CancelRunningJobs: %v", err)
- }
- }
crons = append(crons, run)
}
diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go
index 8eef2b67bd..e7aa4a39ac 100644
--- a/services/actions/schedule_tasks.go
+++ b/services/actions/schedule_tasks.go
@@ -59,6 +59,7 @@ func startTasks(ctx context.Context) error {
row.RepoID,
row.Schedule.Ref,
row.Schedule.WorkflowID,
+ webhook_module.HookEventSchedule,
); err != nil {
log.Error("CancelRunningJobs: %v", err)
}
@@ -113,6 +114,7 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule)
CommitSHA: cron.CommitSHA,
Event: cron.Event,
EventPayload: cron.EventPayload,
+ TriggerEvent: string(webhook_module.HookEventSchedule),
ScheduleID: cron.ID,
Status: actions_model.StatusWaiting,
}
diff --git a/services/agit/agit.go b/services/agit/agit.go
index acfedf09d4..bc68372570 100644
--- a/services/agit/agit.go
+++ b/services/agit/agit.go
@@ -36,9 +36,10 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
topicBranch = opts.GitPushOptions["topic"]
_, forcePush = opts.GitPushOptions["force-push"]
+ objectFormat, _ := gitRepo.GetObjectFormat()
for i := range opts.OldCommitIDs {
- if opts.NewCommitIDs[i] == git.EmptySHA {
+ if opts.NewCommitIDs[i] == objectFormat.EmptyObjectID().String() {
results = append(results, private.HookProcReceiveRefResult{
OriginalRef: opts.RefFullNames[i],
OldOID: opts.OldCommitIDs[i],
@@ -148,10 +149,11 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
log.Trace("Pull request created: %d/%d", repo.ID, prIssue.ID)
+ objectFormat, _ := gitRepo.GetObjectFormat()
results = append(results, private.HookProcReceiveRefResult{
Ref: pr.GetGitRefName(),
OriginalRef: opts.RefFullNames[i],
- OldOID: git.EmptySHA,
+ OldOID: objectFormat.EmptyObjectID().String(),
NewOID: opts.NewCommitIDs[i],
})
continue
diff --git a/services/asymkey/sign.go b/services/asymkey/sign.go
index 1598f32165..0c4aac8156 100644
--- a/services/asymkey/sign.go
+++ b/services/asymkey/sign.go
@@ -143,7 +143,10 @@ Loop:
case always:
break Loop
case pubkey:
- keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ OwnerID: u.ID,
+ IncludeSubKeys: true,
+ })
if err != nil {
return false, "", nil, err
}
@@ -179,7 +182,10 @@ Loop:
case always:
break Loop
case pubkey:
- keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ OwnerID: u.ID,
+ IncludeSubKeys: true,
+ })
if err != nil {
return false, "", nil, err
}
@@ -232,7 +238,10 @@ Loop:
case always:
break Loop
case pubkey:
- keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ OwnerID: u.ID,
+ IncludeSubKeys: true,
+ })
if err != nil {
return false, "", nil, err
}
@@ -294,7 +303,10 @@ Loop:
case always:
break Loop
case pubkey:
- keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ OwnerID: u.ID,
+ IncludeSubKeys: true,
+ })
if err != nil {
return false, "", nil, err
}
diff --git a/services/asymkey/ssh_key.go b/services/asymkey/ssh_key.go
index 1c3bf09b08..83d7edafa3 100644
--- a/services/asymkey/ssh_key.go
+++ b/services/asymkey/ssh_key.go
@@ -33,7 +33,7 @@ func DeletePublicKey(ctx context.Context, doer *user_model.User, id int64) (err
}
defer committer.Close()
- if err = asymkey_model.DeletePublicKeys(dbCtx, id); err != nil {
+ if _, err = db.DeleteByID[asymkey_model.PublicKey](dbCtx, id); err != nil {
return err
}
diff --git a/services/auth/auth_token_test.go b/services/auth/auth_token_test.go
index 654275df17..23c8d17e59 100644
--- a/services/auth/auth_token_test.go
+++ b/services/auth/auth_token_test.go
@@ -37,14 +37,14 @@ func TestCheckAuthToken(t *testing.T) {
})
t.Run("Expired", func(t *testing.T) {
- timeutil.Set(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
+ timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
assert.NoError(t, err)
assert.NotNil(t, at)
assert.NotEmpty(t, token)
- timeutil.Unset()
+ timeutil.MockUnset()
at2, err := CheckAuthToken(db.DefaultContext, at.ID+":"+token)
assert.ErrorIs(t, err, ErrAuthTokenExpired)
@@ -83,15 +83,15 @@ func TestCheckAuthToken(t *testing.T) {
func TestRegenerateAuthToken(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- timeutil.Set(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
- defer timeutil.Unset()
+ timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
+ defer timeutil.MockUnset()
at, token, err := CreateAuthTokenForUserID(db.DefaultContext, 2)
assert.NoError(t, err)
assert.NotNil(t, at)
assert.NotEmpty(t, token)
- timeutil.Set(time.Date(2023, 1, 1, 0, 0, 1, 0, time.UTC))
+ timeutil.MockSet(time.Date(2023, 1, 1, 0, 0, 1, 0, time.UTC))
at2, token2, err := RegenerateAuthToken(db.DefaultContext, at)
assert.NoError(t, err)
diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go
index 08a2a05539..f2f7858a85 100644
--- a/services/auth/oauth2.go
+++ b/services/auth/oauth2.go
@@ -14,6 +14,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/auth/source/oauth2"
@@ -62,14 +63,19 @@ func (o *OAuth2) Name() string {
// representing whether the token exists or not
func parseToken(req *http.Request) (string, bool) {
_ = req.ParseForm()
- // Check token.
- if token := req.Form.Get("token"); token != "" {
- return token, true
- }
- // Check access token.
- if token := req.Form.Get("access_token"); token != "" {
- return token, true
+ if !setting.DisableQueryAuthToken {
+ // Check token.
+ if token := req.Form.Get("token"); token != "" {
+ return token, true
+ }
+ // Check access token.
+ if token := req.Form.Get("access_token"); token != "" {
+ return token, true
+ }
+ } else if req.Form.Get("token") != "" || req.Form.Get("access_token") != "" {
+ log.Warn("API token sent in query string but DISABLE_QUERY_AUTH_TOKEN=true")
}
+
// check header token
if auHead := req.Header.Get("Authorization"); auHead != "" {
auths := strings.Fields(auHead)
diff --git a/services/convert/convert.go b/services/convert/convert.go
index 366782390a..ca3ec32a40 100644
--- a/services/convert/convert.go
+++ b/services/convert/convert.go
@@ -158,6 +158,7 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api
BlockOnOfficialReviewRequests: bp.BlockOnOfficialReviewRequests,
BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch,
DismissStaleApprovals: bp.DismissStaleApprovals,
+ IgnoreStaleApprovals: bp.IgnoreStaleApprovals,
RequireSignedCommits: bp.RequireSignedCommits,
ProtectedFilePatterns: bp.ProtectedFilePatterns,
UnprotectedFilePatterns: bp.UnprotectedFilePatterns,
@@ -308,40 +309,38 @@ func ToTeam(ctx context.Context, team *organization.Team, loadOrg ...bool) (*api
// ToTeams convert models.Team list to api.Team list
func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([]*api.Team, error) {
- if len(teams) == 0 || teams[0] == nil {
- return nil, nil
- }
-
cache := make(map[int64]*api.Organization)
- apiTeams := make([]*api.Team, len(teams))
- for i := range teams {
- if err := teams[i].LoadUnits(ctx); err != nil {
+ apiTeams := make([]*api.Team, 0, len(teams))
+ for _, t := range teams {
+ if err := t.LoadUnits(ctx); err != nil {
return nil, err
}
- apiTeams[i] = &api.Team{
- ID: teams[i].ID,
- Name: teams[i].Name,
- Description: teams[i].Description,
- IncludesAllRepositories: teams[i].IncludesAllRepositories,
- CanCreateOrgRepo: teams[i].CanCreateOrgRepo,
- Permission: teams[i].AccessMode.String(),
- Units: teams[i].GetUnitNames(),
- UnitsMap: teams[i].GetUnitsMap(),
+ apiTeam := &api.Team{
+ ID: t.ID,
+ Name: t.Name,
+ Description: t.Description,
+ IncludesAllRepositories: t.IncludesAllRepositories,
+ CanCreateOrgRepo: t.CanCreateOrgRepo,
+ Permission: t.AccessMode.String(),
+ Units: t.GetUnitNames(),
+ UnitsMap: t.GetUnitsMap(),
}
if loadOrgs {
- apiOrg, ok := cache[teams[i].OrgID]
+ apiOrg, ok := cache[t.OrgID]
if !ok {
- org, err := organization.GetOrgByID(ctx, teams[i].OrgID)
+ org, err := organization.GetOrgByID(ctx, t.OrgID)
if err != nil {
return nil, err
}
apiOrg = ToOrganization(ctx, org)
- cache[teams[i].OrgID] = apiOrg
+ cache[t.OrgID] = apiOrg
}
- apiTeams[i].Organization = apiOrg
+ apiTeam.Organization = apiOrg
}
+
+ apiTeams = append(apiTeams, apiTeam)
}
return apiTeams, nil
}
diff --git a/services/convert/git_commit_test.go b/services/convert/git_commit_test.go
index 8c4ef88ebe..73cb5e8c71 100644
--- a/services/convert/git_commit_test.go
+++ b/services/convert/git_commit_test.go
@@ -19,12 +19,12 @@ import (
func TestToCommitMeta(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- sha1, _ := git.NewIDFromString("0000000000000000000000000000000000000000")
+ sha1 := git.Sha1ObjectFormat
signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)}
tag := &git.Tag{
Name: "Test Tag",
- ID: sha1,
- Object: sha1,
+ ID: sha1.EmptyObjectID(),
+ Object: sha1.EmptyObjectID(),
Type: "Test Type",
Tagger: signature,
Message: "Test Message",
@@ -34,8 +34,8 @@ func TestToCommitMeta(t *testing.T) {
assert.NotNil(t, commitMeta)
assert.EqualValues(t, &api.CommitMeta{
- SHA: "0000000000000000000000000000000000000000",
- URL: util.URLJoin(headRepo.APIURL(), "git/commits", "0000000000000000000000000000000000000000"),
+ SHA: sha1.EmptyObjectID().String(),
+ URL: util.URLJoin(headRepo.APIURL(), "git/commits", sha1.EmptyObjectID().String()),
Created: time.Unix(0, 0),
}, commitMeta)
}
diff --git a/services/convert/pull_review.go b/services/convert/pull_review.go
index 0332606285..aa7ad68a47 100644
--- a/services/convert/pull_review.go
+++ b/services/convert/pull_review.go
@@ -21,15 +21,9 @@ func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model.
r.Reviewer = user_model.NewGhostUser()
}
- apiTeam, err := ToTeam(ctx, r.ReviewerTeam)
- if err != nil {
- return nil, err
- }
-
result := &api.PullReview{
ID: r.ID,
Reviewer: ToUser(ctx, r.Reviewer, doer),
- ReviewerTeam: apiTeam,
State: api.ReviewStateUnknown,
Body: r.Content,
CommitID: r.CommitID,
@@ -43,6 +37,14 @@ func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model.
HTMLPullURL: r.Issue.HTMLURL(),
}
+ if r.ReviewerTeam != nil {
+ var err error
+ result.ReviewerTeam, err = ToTeam(ctx, r.ReviewerTeam)
+ if err != nil {
+ return nil, err
+ }
+ }
+
switch r.Type {
case issues_model.ReviewTypeApprove:
result.State = api.ReviewStateApproved
diff --git a/services/convert/repository.go b/services/convert/repository.go
index 71038cd062..c16180c0af 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -8,6 +8,7 @@ import (
"time"
"code.gitea.io/gitea/models"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
@@ -133,7 +134,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR
return nil
}
- numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false})
+ numReleases, _ := db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{
+ IncludeDrafts: false,
+ IncludeTags: false,
+ RepoID: repo.ID,
+ })
mirrorInterval := ""
var mirrorUpdated time.Time
diff --git a/services/cron/tasks.go b/services/cron/tasks.go
index d2c3d1d812..f0956a97d8 100644
--- a/services/cron/tasks.go
+++ b/services/cron/tasks.go
@@ -84,13 +84,15 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
t.lock.Unlock()
defer func() {
taskStatusTable.Stop(t.Name)
- if err := recover(); err != nil {
- // Recover a panic within the
- combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
- log.Error("PANIC whilst running task: %s Value: %v", t.Name, combinedErr)
- }
}()
graceful.GetManager().RunWithShutdownContext(func(baseCtx context.Context) {
+ defer func() {
+ if err := recover(); err != nil {
+ // Recover a panic within the execution of the task.
+ combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
+ log.Error("PANIC whilst running task: %s Value: %v", t.Name, combinedErr)
+ }
+ }()
// Store the time of this run, before the function is executed, so it
// matches the behavior of what the cron library does.
t.lock.Lock()
diff --git a/services/cron/tasks_test.go b/services/cron/tasks_test.go
index 69052d739c..979371a022 100644
--- a/services/cron/tasks_test.go
+++ b/services/cron/tasks_test.go
@@ -4,6 +4,7 @@
package cron
import (
+ "sort"
"strconv"
"testing"
@@ -22,9 +23,10 @@ func TestAddTaskToScheduler(t *testing.T) {
},
})
assert.NoError(t, err)
- assert.Len(t, scheduler.Jobs(), 1)
- assert.Equal(t, "task 1", scheduler.Jobs()[0].Tags()[0])
- assert.Equal(t, "5 4 * * *", scheduler.Jobs()[0].Tags()[1])
+ jobs := scheduler.Jobs()
+ assert.Len(t, jobs, 1)
+ assert.Equal(t, "task 1", jobs[0].Tags()[0])
+ assert.Equal(t, "5 4 * * *", jobs[0].Tags()[1])
// with seconds
err = addTaskToScheduler(&Task{
@@ -34,9 +36,13 @@ func TestAddTaskToScheduler(t *testing.T) {
},
})
assert.NoError(t, err)
- assert.Len(t, scheduler.Jobs(), 2)
- assert.Equal(t, "task 2", scheduler.Jobs()[1].Tags()[0])
- assert.Equal(t, "30 5 4 * * *", scheduler.Jobs()[1].Tags()[1])
+ jobs = scheduler.Jobs() // the item order is not guaranteed, so we need to sort it before "assert"
+ sort.Slice(jobs, func(i, j int) bool {
+ return jobs[i].Tags()[0] < jobs[j].Tags()[0]
+ })
+ assert.Len(t, jobs, 2)
+ assert.Equal(t, "task 2", jobs[1].Tags()[0])
+ assert.Equal(t, "30 5 4 * * *", jobs[1].Tags()[1])
}
func TestScheduleHasSeconds(t *testing.T) {
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index 5df7ec8fd6..845eccf817 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -21,13 +21,6 @@ import (
"gitea.com/go-chi/binding"
)
-// _______________________________________ _________.______________________ _______________.___.
-// \______ \_ _____/\______ \_____ \ / _____/| \__ ___/\_____ \\______ \__ | |
-// | _/| __)_ | ___// | \ \_____ \ | | | | / | \| _// | |
-// | | \| \ | | / | \/ \| | | | / | \ | \\____ |
-// |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
-// \/ \/ \/ \/ \/ \/ \/
-
// CreateRepoForm form for creating repository
type CreateRepoForm struct {
UID int64 `binding:"Required"`
@@ -50,9 +43,9 @@ type CreateRepoForm struct {
Avatar bool
Labels bool
ProtectedBranch bool
- TrustModel string
ForkSingleBranch string
+ ObjectFormatName string
}
// Validate validates the fields
@@ -211,6 +204,7 @@ type ProtectBranchForm struct {
BlockOnOfficialReviewRequests bool
BlockOnOutdatedBranch bool
DismissStaleApprovals bool
+ IgnoreStaleApprovals bool
RequireSignedCommits bool
ProtectedFilePatterns string
UnprotectedFilePatterns string
diff --git a/services/forms/user_form.go b/services/forms/user_form.go
index c0eb03f554..cbab274238 100644
--- a/services/forms/user_form.go
+++ b/services/forms/user_form.go
@@ -365,7 +365,7 @@ func (f *EditVariableForm) Validate(req *http.Request, errs binding.Errors) bind
// NewAccessTokenForm form for creating access token
type NewAccessTokenForm struct {
- Name string `binding:"Required;MaxSize(255)"`
+ Name string `binding:"Required;MaxSize(255)" locale:"settings.token_name"`
Scope []string
}
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 8bf6cba844..0f6e2b6c17 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -285,15 +285,15 @@ type DiffInline struct {
// DiffInlineWithUnicodeEscape makes a DiffInline with hidden unicode characters escaped
func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) DiffInline {
- status, content := charset.EscapeControlHTML(string(s), locale)
- return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
+ status, content := charset.EscapeControlHTML(s, locale)
+ return DiffInline{EscapeStatus: status, Content: content}
}
// DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped
func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline {
highlighted, _ := highlight.Code(fileName, language, code)
status, content := charset.EscapeControlHTML(highlighted, locale)
- return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
+ return DiffInline{EscapeStatus: status, Content: content}
}
// GetComputedInlineDiffFor computes inline diff for the given line.
@@ -1115,10 +1115,15 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
}
cmdDiff := git.NewCommand(gitRepo.Ctx)
- if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
+ objectFormat, err := gitRepo.GetObjectFormat()
+ if err != nil {
+ return nil, err
+ }
+
+ if (len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String()) && commit.ParentCount() == 0 {
cmdDiff.AddArguments("diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M").
AddArguments(opts.WhitespaceBehavior...).
- AddArguments("4b825dc642cb6eb9a060e54bf8d69288fbee4904"). // append empty tree ref
+ AddDynamicArguments(objectFormat.EmptyTree().String()).
AddDynamicArguments(opts.AfterCommitID)
} else {
actualBeforeCommitID := opts.BeforeCommitID
@@ -1224,8 +1229,8 @@ func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, fi
}
diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
- if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA {
- diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID}
+ if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() {
+ diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
}
diff.NumFiles, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
if err != nil && strings.Contains(err.Error(), "no merge base") {
@@ -1256,12 +1261,15 @@ func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStat
separator = ".."
}
- diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
- if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == git.EmptySHA {
- diffPaths = []string{git.EmptyTreeSHA, opts.AfterCommitID}
+ objectFormat, err := gitRepo.GetObjectFormat()
+ if err != nil {
+ return nil, err
}
- var err error
+ diffPaths := []string{opts.BeforeCommitID + separator + opts.AfterCommitID}
+ if len(opts.BeforeCommitID) == 0 || opts.BeforeCommitID == objectFormat.EmptyObjectID().String() {
+ diffPaths = []string{objectFormat.EmptyTree().String(), opts.AfterCommitID}
+ }
_, diff.TotalAddition, diff.TotalDeletion, err = git.GetDiffShortStat(gitRepo.Ctx, repoPath, nil, diffPaths...)
if err != nil && strings.Contains(err.Error(), "no merge base") {
diff --git a/services/gitdiff/highlightdiff.go b/services/gitdiff/highlightdiff.go
index f1e2b1d3cb..35d4844550 100644
--- a/services/gitdiff/highlightdiff.go
+++ b/services/gitdiff/highlightdiff.go
@@ -93,10 +93,10 @@ func (hcd *highlightCodeDiff) diffWithHighlight(filename, language, codeA, codeB
highlightCodeA, _ := highlight.Code(filename, language, codeA)
highlightCodeB, _ := highlight.Code(filename, language, codeB)
- highlightCodeA = hcd.convertToPlaceholders(highlightCodeA)
- highlightCodeB = hcd.convertToPlaceholders(highlightCodeB)
+ convertedCodeA := hcd.convertToPlaceholders(string(highlightCodeA))
+ convertedCodeB := hcd.convertToPlaceholders(string(highlightCodeB))
- diffs := diffMatchPatch.DiffMain(highlightCodeA, highlightCodeB, true)
+ diffs := diffMatchPatch.DiffMain(convertedCodeA, convertedCodeB, true)
diffs = diffMatchPatch.DiffCleanupEfficiency(diffs)
for i := range diffs {
diff --git a/services/indexer/notify.go b/services/indexer/notify.go
index e0b87faedb..f1e21a2d40 100644
--- a/services/indexer/notify.go
+++ b/services/indexer/notify.go
@@ -130,3 +130,25 @@ func (r *indexerNotifier) IssueChangeTitle(ctx context.Context, doer *user_model
func (r *indexerNotifier) IssueChangeRef(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldRef string) {
issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
}
+
+func (r *indexerNotifier) IssueChangeStatus(ctx context.Context, doer *user_model.User, commitID string, issue *issues_model.Issue, actionComment *issues_model.Comment, closeOrReopen bool) {
+ issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
+}
+
+func (r *indexerNotifier) IssueChangeAssignee(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, assignee *user_model.User, removed bool, comment *issues_model.Comment) {
+ issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
+}
+
+func (r *indexerNotifier) IssueChangeMilestone(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) {
+ issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
+}
+
+func (r *indexerNotifier) IssueChangeLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue,
+ addedLabels, removedLabels []*issues_model.Label,
+) {
+ issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
+}
+
+func (r *indexerNotifier) IssueClearLabels(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) {
+ issue_indexer.UpdateIssueIndexer(ctx, issue.ID)
+}
diff --git a/services/issue/assignee_test.go b/services/issue/assignee_test.go
index e16b012a17..da25da60ee 100644
--- a/services/issue/assignee_test.go
+++ b/services/issue/assignee_test.go
@@ -18,8 +18,12 @@ func TestDeleteNotPassedAssignee(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
// Fake issue with assignees
- issue, err := issues_model.GetIssueWithAttrsByID(db.DefaultContext, 1)
+ issue, err := issues_model.GetIssueByID(db.DefaultContext, 1)
assert.NoError(t, err)
+
+ err = issue.LoadAttributes(db.DefaultContext)
+ assert.NoError(t, err)
+
assert.Len(t, issue.Assignees, 1)
user1, err := user_model.GetUserByID(db.DefaultContext, 1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him
diff --git a/services/lfs/server.go b/services/lfs/server.go
index 58b4663345..62134b7d60 100644
--- a/services/lfs/server.go
+++ b/services/lfs/server.go
@@ -232,7 +232,7 @@ func BatchHandler(ctx *context.Context) {
return
}
if accessible {
- _, err := git_model.NewLFSMetaObject(ctx, &git_model.LFSMetaObject{Pointer: p, RepositoryID: repository.ID})
+ _, err := git_model.NewLFSMetaObject(ctx, repository.ID, p)
if err != nil {
log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err)
writeStatus(ctx, http.StatusInternalServerError)
@@ -325,7 +325,7 @@ func UploadHandler(ctx *context.Context) {
log.Error("Error putting LFS MetaObject [%s] into content store. Error: %v", p.Oid, err)
return err
}
- _, err := git_model.NewLFSMetaObject(ctx, &git_model.LFSMetaObject{Pointer: p, RepositoryID: repository.ID})
+ _, err := git_model.NewLFSMetaObject(ctx, repository.ID, p)
return err
}
diff --git a/services/mailer/mail.go b/services/mailer/mail.go
index b597dd0487..cf80333608 100644
--- a/services/mailer/mail.go
+++ b/services/mailer/mail.go
@@ -220,9 +220,11 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
// This is the body of the new issue or comment, not the mail body
body, err := markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: ctx.Issue.Repo.HTMLURL(),
- Metas: ctx.Issue.Repo.ComposeMetas(ctx),
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: ctx.Issue.Repo.HTMLURL(),
+ },
+ Metas: ctx.Issue.Repo.ComposeMetas(ctx),
}, ctx.Content)
if err != nil {
return nil, err
diff --git a/services/mailer/mail_release.go b/services/mailer/mail_release.go
index 88973a6be2..801c2476c2 100644
--- a/services/mailer/mail_release.go
+++ b/services/mailer/mail_release.go
@@ -57,9 +57,11 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *repo_mo
var err error
rel.RenderedNote, err = markdown.RenderString(&markup.RenderContext{
- Ctx: ctx,
- URLPrefix: rel.Repo.Link(),
- Metas: rel.Repo.ComposeMetas(ctx),
+ Ctx: ctx,
+ Links: markup.Links{
+ Base: rel.Repo.HTMLURL(),
+ },
+ Metas: rel.Repo.ComposeMetas(ctx),
}, rel.Note)
if err != nil {
log.Error("markdown.RenderString(%d): %v", rel.RepoID, err)
diff --git a/services/migrations/common.go b/services/migrations/common.go
index 4f9837472d..d88518899d 100644
--- a/services/migrations/common.go
+++ b/services/migrations/common.go
@@ -48,16 +48,18 @@ func CheckAndEnsureSafePR(pr *base.PullRequest, commonCloneBaseURL string, g bas
}
// SECURITY: SHAs Must be a SHA
- if pr.MergeCommitSHA != "" && !git.IsValidSHAPattern(pr.MergeCommitSHA) {
+ // FIXME: hash only a SHA1
+ CommitType := git.Sha1ObjectFormat
+ if pr.MergeCommitSHA != "" && !CommitType.IsValid(pr.MergeCommitSHA) {
WarnAndNotice("PR #%d in %s has invalid MergeCommitSHA: %s", pr.Number, g, pr.MergeCommitSHA)
pr.MergeCommitSHA = ""
}
- if pr.Head.SHA != "" && !git.IsValidSHAPattern(pr.Head.SHA) {
+ if pr.Head.SHA != "" && !CommitType.IsValid(pr.Head.SHA) {
WarnAndNotice("PR #%d in %s has invalid HeadSHA: %s", pr.Number, g, pr.Head.SHA)
pr.Head.SHA = ""
valid = false
}
- if pr.Base.SHA != "" && !git.IsValidSHAPattern(pr.Base.SHA) {
+ if pr.Base.SHA != "" && !CommitType.IsValid(pr.Base.SHA) {
WarnAndNotice("PR #%d in %s has invalid BaseSHA: %s", pr.Number, g, pr.Base.SHA)
pr.Base.SHA = ""
valid = false
diff --git a/services/migrations/error.go b/services/migrations/error.go
index c8e6c8fe13..5e0e0742c9 100644
--- a/services/migrations/error.go
+++ b/services/migrations/error.go
@@ -7,7 +7,7 @@ package migrations
import (
"errors"
- "github.com/google/go-github/v53/github"
+ "github.com/google/go-github/v57/github"
)
// ErrRepoNotCreated returns the error that repository not created
diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go
index ddc2cbd4ec..23d855d615 100644
--- a/services/migrations/gitea_uploader.go
+++ b/services/migrations/gitea_uploader.go
@@ -862,7 +862,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
line := comment.Line
if line != 0 {
comment.Position = 1
- } else {
+ } else if comment.DiffHunk != "" {
_, _, line, _ = git.ParseDiffHunkString(comment.DiffHunk)
}
@@ -892,7 +892,8 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
comment.UpdatedAt = comment.CreatedAt
}
- if !git.IsValidSHAPattern(comment.CommitID) {
+ objectFormat, _ := g.gitRepo.GetObjectFormat()
+ if !objectFormat.IsValid(comment.CommitID) {
log.Warn("Invalid comment CommitID[%s] on comment[%d] in PR #%d of %s/%s replaced with %s", comment.CommitID, pr.Index, g.repoOwner, g.repoName, headCommitID)
comment.CommitID = headCommitID
}
diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go
index 84db83bc67..4ec0361dfb 100644
--- a/services/migrations/gitea_uploader_test.go
+++ b/services/migrations/gitea_uploader_test.go
@@ -65,16 +65,16 @@ func TestGiteaUploadRepo(t *testing.T) {
assert.True(t, repo.HasWiki())
assert.EqualValues(t, repo_model.RepositoryReady, repo.Status)
- milestones, _, err := issues_model.GetMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
- RepoID: repo.ID,
- State: structs.StateOpen,
+ milestones, err := db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
+ RepoID: repo.ID,
+ IsClosed: util.OptionalBoolFalse,
})
assert.NoError(t, err)
assert.Len(t, milestones, 1)
- milestones, _, err = issues_model.GetMilestones(db.DefaultContext, issues_model.GetMilestonesOption{
- RepoID: repo.ID,
- State: structs.StateClosed,
+ milestones, err = db.Find[issues_model.Milestone](db.DefaultContext, issues_model.FindMilestoneOptions{
+ RepoID: repo.ID,
+ IsClosed: util.OptionalBoolTrue,
})
assert.NoError(t, err)
assert.Empty(t, milestones)
@@ -83,22 +83,24 @@ func TestGiteaUploadRepo(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, labels, 12)
- releases, err := repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{
+ releases, err := db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{
ListOptions: db.ListOptions{
PageSize: 10,
Page: 0,
},
IncludeTags: true,
+ RepoID: repo.ID,
})
assert.NoError(t, err)
assert.Len(t, releases, 8)
- releases, err = repo_model.GetReleasesByRepoID(db.DefaultContext, repo.ID, repo_model.FindReleasesOptions{
+ releases, err = db.Find[repo_model.Release](db.DefaultContext, repo_model.FindReleasesOptions{
ListOptions: db.ListOptions{
PageSize: 10,
Page: 0,
},
IncludeTags: false,
+ RepoID: repo.ID,
})
assert.NoError(t, err)
assert.Len(t, releases, 1)
@@ -232,7 +234,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) {
//
fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
baseRef := "master"
- assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false))
+ assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false, fromRepo.ObjectFormatName))
err := git.NewCommand(git.DefaultContext, "symbolic-ref").AddDynamicArguments("HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()})
assert.NoError(t, err)
assert.NoError(t, os.WriteFile(filepath.Join(fromRepo.RepoPath(), "README.md"), []byte(fmt.Sprintf("# Testing Repository\n\nOriginally created in: %s", fromRepo.RepoPath())), 0o644))
diff --git a/services/migrations/github.go b/services/migrations/github.go
index f27c1a34da..be573b33b3 100644
--- a/services/migrations/github.go
+++ b/services/migrations/github.go
@@ -20,7 +20,7 @@ import (
"code.gitea.io/gitea/modules/proxy"
"code.gitea.io/gitea/modules/structs"
- "github.com/google/go-github/v53/github"
+ "github.com/google/go-github/v57/github"
"golang.org/x/oauth2"
)
@@ -135,7 +135,7 @@ func (g *GithubDownloaderV3) LogString() string {
func (g *GithubDownloaderV3) addClient(client *http.Client, baseURL string) {
githubClient := github.NewClient(client)
if baseURL != "https://github.com" {
- githubClient, _ = github.NewEnterpriseClient(baseURL, baseURL, client)
+ githubClient, _ = github.NewClient(client).WithEnterpriseURLs(baseURL, baseURL)
}
g.clients = append(g.clients, githubClient)
g.rates = append(g.rates, nil)
@@ -168,14 +168,14 @@ func (g *GithubDownloaderV3) waitAndPickClient() {
err := g.RefreshRate()
if err != nil {
- log.Error("g.getClient().RateLimits: %s", err)
+ log.Error("g.getClient().RateLimit.Get: %s", err)
}
}
}
// RefreshRate update the current rate (doesn't count in rate limit)
func (g *GithubDownloaderV3) RefreshRate() error {
- rates, _, err := g.getClient().RateLimits(g.ctx)
+ rates, _, err := g.getClient().RateLimit.Get(g.ctx)
if err != nil {
// if rate limit is not enabled, ignore it
if strings.Contains(err.Error(), "404") {
diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go
index 22bc4cf8f3..3db10465fc 100644
--- a/services/migrations/gitlab.go
+++ b/services/migrations/gitlab.go
@@ -55,19 +55,36 @@ func (f *GitlabDownloaderFactory) GitServiceType() structs.GitServiceType {
return structs.GitlabService
}
+type gitlabIIDResolver struct {
+ maxIssueIID int64
+ frozen bool
+}
+
+func (r *gitlabIIDResolver) recordIssueIID(issueIID int) {
+ if r.frozen {
+ panic("cannot record issue IID after pull request IID generation has started")
+ }
+ r.maxIssueIID = max(r.maxIssueIID, int64(issueIID))
+}
+
+func (r *gitlabIIDResolver) generatePullRequestNumber(mrIID int) int64 {
+ r.frozen = true
+ return r.maxIssueIID + int64(mrIID)
+}
+
// GitlabDownloader implements a Downloader interface to get repository information
// from gitlab via go-gitlab
// - issueCount is incremented in GetIssues() to ensure PR and Issue numbers do not overlap,
// because Gitlab has individual Issue and Pull Request numbers.
type GitlabDownloader struct {
base.NullDownloader
- ctx context.Context
- client *gitlab.Client
- baseURL string
- repoID int
- repoName string
- issueCount int64
- maxPerPage int
+ ctx context.Context
+ client *gitlab.Client
+ baseURL string
+ repoID int
+ repoName string
+ iidResolver gitlabIIDResolver
+ maxPerPage int
}
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
@@ -450,8 +467,8 @@ func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, er
Context: gitlabIssueContext{IsMergeRequest: false},
})
- // increment issueCount, to be used in GetPullRequests()
- g.issueCount++
+ // record the issue IID, to be used in GetPullRequests()
+ g.iidResolver.recordIssueIID(issue.IID)
}
return allIssues, len(issues) < perPage, nil
@@ -607,8 +624,8 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque
awardPage++
}
- // Add the PR ID to the Issue Count because PR and Issues share ID space in Gitea
- newPRNumber := g.issueCount + int64(pr.IID)
+ // Generate new PR Numbers by the known Issue Numbers, because they share the same number space in Gitea, but they are independent in Gitlab
+ newPRNumber := g.iidResolver.generatePullRequestNumber(pr.IID)
allPRs = append(allPRs, &base.PullRequest{
Title: pr.Title,
diff --git a/services/migrations/gitlab_test.go b/services/migrations/gitlab_test.go
index 731486eff2..1e0aa2b025 100644
--- a/services/migrations/gitlab_test.go
+++ b/services/migrations/gitlab_test.go
@@ -516,3 +516,20 @@ func TestAwardsToReactions(t *testing.T) {
},
}, reactions)
}
+
+func TestGitlabIIDResolver(t *testing.T) {
+ r := gitlabIIDResolver{}
+ r.recordIssueIID(1)
+ r.recordIssueIID(2)
+ r.recordIssueIID(3)
+ r.recordIssueIID(2)
+ assert.EqualValues(t, 4, r.generatePullRequestNumber(1))
+ assert.EqualValues(t, 13, r.generatePullRequestNumber(10))
+
+ assert.Panics(t, func() {
+ r := gitlabIIDResolver{}
+ r.recordIssueIID(1)
+ assert.EqualValues(t, 2, r.generatePullRequestNumber(1))
+ r.recordIssueIID(3) // the generation procedure has been started, it shouldn't accept any new issue IID, so it panics
+ })
+}
diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go
index be426d4312..6f03e14ab0 100644
--- a/services/mirror/mirror_pull.go
+++ b/services/mirror/mirror_pull.go
@@ -478,9 +478,13 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err)
continue
}
+ objectFormat, err := git.GetObjectFormatOfRepo(ctx, m.Repo.RepoPath())
+ if err != nil {
+ log.Error("SyncMirrors [repo: %-v]: unable to GetHashTypeOfRepo: %v", m.Repo, err)
+ }
notify_service.SyncPushCommits(ctx, m.Repo.MustOwner(ctx), m.Repo, &repo_module.PushUpdateOptions{
RefFullName: result.refName,
- OldCommitID: git.EmptySHA,
+ OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: commitID,
}, repo_module.NewPushCommits())
notify_service.SyncCreateRef(ctx, m.Repo.MustOwner(ctx), m.Repo, result.refName, commitID)
diff --git a/services/mirror/mirror_push.go b/services/mirror/mirror_push.go
index 6eaca71495..b117e79fac 100644
--- a/services/mirror/mirror_push.go
+++ b/services/mirror/mirror_push.go
@@ -12,6 +12,7 @@ import (
"strings"
"time"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/lfs"
@@ -93,8 +94,9 @@ func SyncPushMirror(ctx context.Context, mirrorID int64) bool {
log.Error("PANIC whilst syncPushMirror[%d] Panic: %v\nStacktrace: %s", mirrorID, err, log.Stack(2))
}()
- m, err := repo_model.GetPushMirror(ctx, repo_model.PushMirrorOptions{ID: mirrorID})
- if err != nil {
+ // TODO: Handle "!exist" better
+ m, exist, err := db.GetByID[repo_model.PushMirror](ctx, mirrorID)
+ if err != nil || !exist {
log.Error("GetPushMirrorByID [%d]: %v", mirrorID, err)
return false
}
diff --git a/services/packages/alpine/repository.go b/services/packages/alpine/repository.go
index 46093d5bdd..30b7a06eb3 100644
--- a/services/packages/alpine/repository.go
+++ b/services/packages/alpine/repository.go
@@ -82,10 +82,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error {
}
for _, pf := range pfs {
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -157,12 +154,11 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, IndexFilename, fmt.Sprintf("%s|%s|%s", branch, repository, architecture))
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
+ } else if pf == nil {
+ return nil
}
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- return packages_model.DeleteFileByID(ctx, pf.ID)
+ return packages_service.DeletePackageFile(ctx, pf)
}
// Cache data needed for all repository files
diff --git a/services/packages/cargo/index.go b/services/packages/cargo/index.go
index 8164ffb01c..e8a8313625 100644
--- a/services/packages/cargo/index.go
+++ b/services/packages/cargo/index.go
@@ -267,11 +267,11 @@ func alterRepositoryContent(ctx context.Context, doer *user_model.User, repo *re
defer t.Close()
var lastCommitID string
- if err := t.Clone(repo.DefaultBranch); err != nil {
+ if err := t.Clone(repo.DefaultBranch, true); err != nil {
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return err
}
- if err := t.Init(); err != nil {
+ if err := t.Init(repo.ObjectFormatName); err != nil {
return err
}
} else {
diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go
index 9bdd9d6aad..04ee6c4419 100644
--- a/services/packages/cleanup/cleanup.go
+++ b/services/packages/cleanup/cleanup.go
@@ -15,6 +15,7 @@ import (
packages_module "code.gitea.io/gitea/modules/packages"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
+ alpine_service "code.gitea.io/gitea/services/packages/alpine"
cargo_service "code.gitea.io/gitea/services/packages/cargo"
container_service "code.gitea.io/gitea/services/packages/container"
debian_service "code.gitea.io/gitea/services/packages/debian"
@@ -122,6 +123,10 @@ func ExecuteCleanupRules(outerCtx context.Context) error {
if err := debian_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
return fmt.Errorf("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
}
+ } else if pcr.Type == packages_model.TypeAlpine {
+ if err := alpine_service.BuildAllRepositoryFiles(ctx, pcr.OwnerID); err != nil {
+ return fmt.Errorf("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w", pcr.ID, err)
+ }
}
}
return nil
diff --git a/services/packages/container/cleanup.go b/services/packages/container/cleanup.go
index 1a9ef26391..dd3f158dbf 100644
--- a/services/packages/container/cleanup.go
+++ b/services/packages/container/cleanup.go
@@ -11,6 +11,7 @@ import (
container_model "code.gitea.io/gitea/models/packages/container"
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/util"
+ packages_service "code.gitea.io/gitea/services/packages"
digest "github.com/opencontainers/go-digest"
)
@@ -47,10 +48,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e
}
for _, pf := range pfs {
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
diff --git a/services/packages/debian/repository.go b/services/packages/debian/repository.go
index cbde53f961..86c54e40c8 100644
--- a/services/packages/debian/repository.go
+++ b/services/packages/debian/repository.go
@@ -67,7 +67,7 @@ func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, err
}
func generateKeypair() (string, string, error) {
- e, err := openpgp.NewEntity(setting.AppName, "Debian Registry", "", nil)
+ e, err := openpgp.NewEntity("", "Debian Registry", "", nil)
if err != nil {
return "", "", err
}
@@ -110,10 +110,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error {
}
for _, pf := range pfs {
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -181,12 +178,11 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, key)
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
+ } else if pf == nil {
+ continue
}
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -286,12 +282,11 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages
pf, err := packages_model.GetFileForVersionByName(ctx, repoVersion.ID, filename, distribution)
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
+ } else if pf == nil {
+ continue
}
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
diff --git a/services/packages/rpm/repository.go b/services/packages/rpm/repository.go
index 1d0dc83cae..7a49efde4f 100644
--- a/services/packages/rpm/repository.go
+++ b/services/packages/rpm/repository.go
@@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/json"
packages_module "code.gitea.io/gitea/modules/packages"
rpm_module "code.gitea.io/gitea/modules/packages/rpm"
- "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
@@ -68,7 +67,7 @@ func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, err
}
func generateKeypair() (string, string, error) {
- e, err := openpgp.NewEntity(setting.AppName, "RPM Registry", "", nil)
+ e, err := openpgp.NewEntity("", "RPM Registry", "", nil)
if err != nil {
return "", "", err
}
@@ -127,16 +126,17 @@ type packageData struct {
type packageCache = map[*packages_model.PackageFile]*packageData
// BuildSpecificRepositoryFiles builds metadata files for the repository
-func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
+func BuildRepositoryFiles(ctx context.Context, ownerID int64, compositeKey string) error {
pv, err := GetOrCreateRepositoryVersion(ctx, ownerID)
if err != nil {
return err
}
pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
- OwnerID: ownerID,
- PackageType: packages_model.TypeRpm,
- Query: "%.rpm",
+ OwnerID: ownerID,
+ PackageType: packages_model.TypeRpm,
+ Query: "%.rpm",
+ CompositeKey: compositeKey,
})
if err != nil {
return err
@@ -149,10 +149,7 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
return err
}
for _, pf := range pfs {
- if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
- return err
- }
- if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
+ if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
return err
}
}
@@ -198,15 +195,15 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
cache[pf] = pd
}
- primary, err := buildPrimary(ctx, pv, pfs, cache)
+ primary, err := buildPrimary(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
- filelists, err := buildFilelists(ctx, pv, pfs, cache)
+ filelists, err := buildFilelists(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
- other, err := buildOther(ctx, pv, pfs, cache)
+ other, err := buildOther(ctx, pv, pfs, cache, compositeKey)
if err != nil {
return err
}
@@ -220,11 +217,12 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error {
filelists,
other,
},
+ compositeKey,
)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#repomd-xml
-func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData) error {
+func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData, compositeKey string) error {
type Repomd struct {
XMLName xml.Name `xml:"repomd"`
Xmlns string `xml:"xmlns,attr"`
@@ -279,7 +277,8 @@ func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: file.Name,
+ Filename: file.Name,
+ CompositeKey: compositeKey,
},
Creator: user_model.NewGhostUser(),
Data: file.Data,
@@ -296,7 +295,7 @@ func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#primary-xml
-func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) {
+func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) {
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -376,7 +375,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
files = append(files, f)
}
}
-
+ packageVersion := fmt.Sprintf("%s-%s", pd.FileMetadata.Version, pd.FileMetadata.Release)
packages = append(packages, &Package{
Type: "rpm",
Name: pd.Package.Name,
@@ -405,7 +404,7 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
Archive: pd.FileMetadata.ArchiveSize,
},
Location: Location{
- Href: fmt.Sprintf("package/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(pd.Version.Version), url.PathEscape(pd.FileMetadata.Architecture)),
+ Href: fmt.Sprintf("package/%s/%s/%s/%s", url.PathEscape(pd.Package.Name), url.PathEscape(packageVersion), url.PathEscape(pd.FileMetadata.Architecture), url.PathEscape(fmt.Sprintf("%s-%s.%s.rpm", pd.Package.Name, packageVersion, pd.FileMetadata.Architecture))),
},
Format: Format{
License: pd.VersionMetadata.License,
@@ -435,11 +434,11 @@ func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []
XmlnsRpm: "http://linux.duke.edu/metadata/rpm",
PackageCount: len(pfs),
Packages: packages,
- })
+ }, compositeKey)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#filelists-xml
-func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl
+func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -482,11 +481,12 @@ func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pfs),
Packages: packages,
- })
+ },
+ compositeKey)
}
// https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#other-xml
-func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl
+func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache, compositeKey string) (*repoData, error) { //nolint:dupl
type Version struct {
Epoch string `xml:"epoch,attr"`
Version string `xml:"ver,attr"`
@@ -529,7 +529,7 @@ func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*p
Xmlns: "http://linux.duke.edu/metadata/other",
PackageCount: len(pfs),
Packages: packages,
- })
+ }, compositeKey)
}
// writtenCounter counts all written bytes
@@ -549,10 +549,8 @@ func (wc *writtenCounter) Written() int64 {
return wc.written
}
-func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) {
+func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any, compositeKey string) (*repoData, error) {
content, _ := packages_module.NewHashedBuffer()
- defer content.Close()
-
gzw := gzip.NewWriter(content)
wc := &writtenCounter{}
h := sha256.New()
@@ -575,7 +573,8 @@ func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion,
pv,
&packages_service.PackageFileCreationInfo{
PackageFileInfo: packages_service.PackageFileInfo{
- Filename: filename,
+ Filename: filename,
+ CompositeKey: compositeKey,
},
Creator: user_model.NewGhostUser(),
Data: content,
diff --git a/services/pull/check.go b/services/pull/check.go
index b51b58f480..ebe4c6d61b 100644
--- a/services/pull/check.go
+++ b/services/pull/check.go
@@ -215,24 +215,29 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com
return nil, fmt.Errorf("GetFullCommitID(%s) in %s: %w", prHeadRef, pr.BaseRepo.FullName(), err)
}
+ gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
+ if err != nil {
+ return nil, fmt.Errorf("%-v OpenRepository: %w", pr.BaseRepo, err)
+ }
+ defer gitRepo.Close()
+
+ objectFormat, err := gitRepo.GetObjectFormat()
+ if err != nil {
+ return nil, fmt.Errorf("%-v GetObjectFormat: %w", pr.BaseRepo, err)
+ }
+
// Get the commit from BaseBranch where the pull request got merged
mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse").
AddDynamicArguments(prHeadCommitID + ".." + pr.BaseBranch).
RunStdString(&git.RunOpts{Dir: pr.BaseRepo.RepoPath()})
if err != nil {
return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %w", err)
- } else if len(mergeCommit) < git.SHAFullLength {
+ } else if len(mergeCommit) < objectFormat.FullLength() {
// PR was maybe fast-forwarded, so just use last commit of PR
mergeCommit = prHeadCommitID
}
mergeCommit = strings.TrimSpace(mergeCommit)
- gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath())
- if err != nil {
- return nil, fmt.Errorf("%-v OpenRepository: %w", pr.BaseRepo, err)
- }
- defer gitRepo.Close()
-
commit, err := gitRepo.GetCommit(mergeCommit)
if err != nil {
return nil, fmt.Errorf("GetMergeCommit[%s]: %w", mergeCommit, err)
diff --git a/services/pull/lfs.go b/services/pull/lfs.go
index 2ca82b5633..ed03583d4f 100644
--- a/services/pull/lfs.go
+++ b/services/pull/lfs.go
@@ -127,9 +127,7 @@ func createLFSMetaObjectsFromCatFileBatch(ctx context.Context, catFileBatchReade
// OK we have a pointer that is associated with the head repo
// and is actually a file in the LFS
// Therefore it should be associated with the base repo
- meta := &git_model.LFSMetaObject{Pointer: pointer}
- meta.RepositoryID = pr.BaseRepoID
- if _, err := git_model.NewLFSMetaObject(ctx, meta); err != nil {
+ if _, err := git_model.NewLFSMetaObject(ctx, pr.BaseRepoID, pointer); err != nil {
_ = catFileBatchReader.CloseWithError(err)
break
}
diff --git a/services/pull/merge.go b/services/pull/merge.go
index 33c7455c08..63f0268beb 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -486,7 +486,8 @@ func MergedManually(ctx context.Context, pr *issues_model.PullRequest, doer *use
return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged}
}
- if len(commitID) < git.SHAFullLength {
+ objectFormat, _ := baseGitRepo.GetObjectFormat()
+ if len(commitID) != objectFormat.FullLength() {
return fmt.Errorf("Wrong commit ID")
}
diff --git a/services/pull/patch.go b/services/pull/patch.go
index 688cbcc027..acaff04bda 100644
--- a/services/pull/patch.go
+++ b/services/pull/patch.go
@@ -129,6 +129,7 @@ func (e *errMergeConflict) Error() string {
func attemptMerge(ctx context.Context, file *unmergedFile, tmpBasePath string, gitRepo *git.Repository) error {
log.Trace("Attempt to merge:\n%v", file)
+
switch {
case file.stage1 != nil && (file.stage2 == nil || file.stage3 == nil):
// 1. Deleted in one or both:
diff --git a/services/pull/pull.go b/services/pull/pull.go
index 2f5143903a..930954bdfd 100644
--- a/services/pull/pull.go
+++ b/services/pull/pull.go
@@ -4,6 +4,7 @@
package pull
import (
+ "bytes"
"context"
"fmt"
"io"
@@ -327,7 +328,8 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
}
if err == nil {
for _, pr := range prs {
- if newCommitID != "" && newCommitID != git.EmptySHA {
+ objectFormat, _ := git.GetObjectFormatOfRepo(ctx, pr.BaseRepo.RepoPath())
+ if newCommitID != "" && newCommitID != objectFormat.EmptyObjectID().String() {
changed, err := checkIfPRContentChanged(ctx, pr, oldCommitID, newCommitID)
if err != nil {
log.Error("checkIfPRContentChanged: %v", err)
@@ -421,9 +423,11 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest,
return false, fmt.Errorf("unable to open pipe for to run diff: %w", err)
}
+ stderr := new(bytes.Buffer)
if err := cmd.Run(&git.RunOpts{
Dir: prCtx.tmpBasePath,
Stdout: stdoutWriter,
+ Stderr: stderr,
PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
defer func() {
@@ -435,6 +439,7 @@ func checkIfPRContentChanged(ctx context.Context, pr *issues_model.PullRequest,
if err == util.ErrNotEmpty {
return true, nil
}
+ err = git.ConcatenateError(err, stderr.String())
log.Error("Unable to run diff on %s %s %s in tempRepo for PR[%d]%s/%s...%s/%s: Error: %v",
newCommitID, oldCommitID, base,
@@ -541,6 +546,43 @@ func (errs errlist) Error() string {
return ""
}
+// RetargetChildrenOnMerge retarget children pull requests on merge if possible
+func RetargetChildrenOnMerge(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) error {
+ if setting.Repository.PullRequest.RetargetChildrenOnMerge && pr.BaseRepoID == pr.HeadRepoID {
+ return RetargetBranchPulls(ctx, doer, pr.HeadRepoID, pr.HeadBranch, pr.BaseBranch)
+ }
+ return nil
+}
+
+// RetargetBranchPulls change target branch for all pull requests whose base branch is the branch
+// Both branch and targetBranch must be in the same repo (for security reasons)
+func RetargetBranchPulls(ctx context.Context, doer *user_model.User, repoID int64, branch, targetBranch string) error {
+ prs, err := issues_model.GetUnmergedPullRequestsByBaseInfo(ctx, repoID, branch)
+ if err != nil {
+ return err
+ }
+
+ if err := issues_model.PullRequestList(prs).LoadAttributes(ctx); err != nil {
+ return err
+ }
+
+ var errs errlist
+ for _, pr := range prs {
+ if err = pr.Issue.LoadRepo(ctx); err != nil {
+ errs = append(errs, err)
+ } else if err = ChangeTargetBranch(ctx, pr, doer, targetBranch); err != nil &&
+ !issues_model.IsErrIssueIsClosed(err) && !models.IsErrPullRequestHasMerged(err) &&
+ !issues_model.IsErrPullRequestAlreadyExists(err) {
+ errs = append(errs, err)
+ }
+ }
+
+ if len(errs) > 0 {
+ return errs
+ }
+ return nil
+}
+
// CloseBranchPulls close all the pull requests who's head branch is the branch
func CloseBranchPulls(ctx context.Context, doer *user_model.User, repoID int64, branch string) error {
prs, err := issues_model.GetUnmergedPullRequestsByHeadInfo(ctx, repoID, branch)
diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go
index db32940e38..36bdbde55c 100644
--- a/services/pull/temp_repo.go
+++ b/services/pull/temp_repo.go
@@ -94,7 +94,7 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
baseRepoPath := pr.BaseRepo.RepoPath()
headRepoPath := pr.HeadRepo.RepoPath()
- if err := git.InitRepository(ctx, tmpBasePath, false); err != nil {
+ if err := git.InitRepository(ctx, tmpBasePath, false, pr.BaseRepo.ObjectFormatName); err != nil {
log.Error("Unable to init tmpBasePath for %-v: %v", pr, err)
cancel()
return nil, nil, err
@@ -168,11 +168,12 @@ func createTemporaryRepoForPR(ctx context.Context, pr *issues_model.PullRequest)
}
trackingBranch := "tracking"
+ objectFormat := git.ObjectFormatFromName(pr.BaseRepo.ObjectFormatName)
// Fetch head branch
var headBranch string
if pr.Flow == issues_model.PullRequestFlowGithub {
headBranch = git.BranchPrefix + pr.HeadBranch
- } else if len(pr.HeadCommitID) == git.SHAFullLength { // for not created pull request
+ } else if len(pr.HeadCommitID) == objectFormat.FullLength() { // for not created pull request
headBranch = pr.HeadCommitID
} else {
headBranch = pr.GetGitRefName()
diff --git a/services/release/release.go b/services/release/release.go
index e0035d42fc..ddfb11fa47 100644
--- a/services/release/release.go
+++ b/services/release/release.go
@@ -86,16 +86,17 @@ func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Rel
created = true
rel.LowerTagName = strings.ToLower(rel.TagName)
+ objectFormat, _ := gitRepo.GetObjectFormat()
commits := repository.NewPushCommits()
commits.HeadCommit = repository.CommitToPushCommit(commit)
- commits.CompareURL = rel.Repo.ComposeCompareURL(git.EmptySHA, commit.ID.String())
+ commits.CompareURL = rel.Repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), commit.ID.String())
refFullName := git.RefNameFromTag(rel.TagName)
notify_service.PushCommits(
ctx, rel.Publisher, rel.Repo,
&repository.PushUpdateOptions{
RefFullName: refFullName,
- OldCommitID: git.EmptySHA,
+ OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: commit.ID.String(),
}, commits)
notify_service.CreateRef(ctx, rel.Publisher, rel.Repo, refFullName, commit.ID.String())
@@ -301,17 +302,7 @@ func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repo
}
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
-func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, delTag bool) error {
- rel, err := repo_model.GetReleaseByID(ctx, id)
- if err != nil {
- return fmt.Errorf("GetReleaseByID: %w", err)
- }
-
- repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID)
- if err != nil {
- return fmt.Errorf("GetRepositoryByID: %w", err)
- }
-
+func DeleteReleaseByID(ctx context.Context, repo *repo_model.Repository, rel *repo_model.Release, doer *user_model.User, delTag bool) error {
if delTag {
protectedTags, err := git_model.GetProtectedTags(ctx, rel.RepoID)
if err != nil {
@@ -335,28 +326,32 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del
}
refName := git.RefNameFromTag(rel.TagName)
+ objectFormat, err := git.GetObjectFormatOfRepo(ctx, repo.RepoPath())
+ if err != nil {
+ return err
+ }
notify_service.PushCommits(
ctx, doer, repo,
&repository.PushUpdateOptions{
RefFullName: refName,
OldCommitID: rel.Sha1,
- NewCommitID: git.EmptySHA,
+ NewCommitID: objectFormat.EmptyObjectID().String(),
}, repository.NewPushCommits())
notify_service.DeleteRef(ctx, doer, repo, refName)
- if err := repo_model.DeleteReleaseByID(ctx, id); err != nil {
+ if _, err := db.DeleteByID[repo_model.Release](ctx, rel.ID); err != nil {
return fmt.Errorf("DeleteReleaseByID: %w", err)
}
} else {
rel.IsTag = true
- if err = repo_model.UpdateRelease(ctx, rel); err != nil {
+ if err := repo_model.UpdateRelease(ctx, rel); err != nil {
return fmt.Errorf("Update: %w", err)
}
}
rel.Repo = repo
- if err = rel.LoadAttributes(ctx); err != nil {
+ if err := rel.LoadAttributes(ctx); err != nil {
return fmt.Errorf("LoadAttributes: %w", err)
}
diff --git a/services/repository/archiver/archiver.go b/services/repository/archiver/archiver.go
index 9f1ea48dca..c2ad4d484a 100644
--- a/services/repository/archiver/archiver.go
+++ b/services/repository/archiver/archiver.go
@@ -9,7 +9,6 @@ import (
"fmt"
"io"
"os"
- "regexp"
"strings"
"time"
@@ -36,10 +35,6 @@ type ArchiveRequest struct {
CommitID string
}
-// SHA1 hashes will only go up to 40 characters, but SHA256 hashes will go all
-// the way to 64.
-var shaRegex = regexp.MustCompile(`^[0-9a-f]{4,64}$`)
-
// ErrUnknownArchiveFormat request archive format is not supported
type ErrUnknownArchiveFormat struct {
RequestFormat string
@@ -96,30 +91,13 @@ func NewRequest(repoID int64, repo *git.Repository, uri string) (*ArchiveRequest
r.refName = strings.TrimSuffix(uri, ext)
- var err error
// Get corresponding commit.
- if repo.IsBranchExist(r.refName) {
- r.CommitID, err = repo.GetBranchCommitID(r.refName)
- if err != nil {
- return nil, err
- }
- } else if repo.IsTagExist(r.refName) {
- r.CommitID, err = repo.GetTagCommitID(r.refName)
- if err != nil {
- return nil, err
- }
- } else if shaRegex.MatchString(r.refName) {
- if repo.IsCommitExist(r.refName) {
- r.CommitID = r.refName
- } else {
- return nil, git.ErrNotExist{
- ID: r.refName,
- }
- }
- } else {
+ commitID, err := repo.ConvertToGitID(r.refName)
+ if err != nil {
return nil, RepoRefNotFoundError{RefName: r.refName}
}
+ r.CommitID = commitID.String()
return r, nil
}
@@ -199,7 +177,7 @@ func doArchive(ctx context.Context, r *ArchiveRequest) (*repo_model.RepoArchiver
CommitID: r.CommitID,
Status: repo_model.ArchiverGenerating,
}
- if err := repo_model.AddRepoArchiver(ctx, archiver); err != nil {
+ if err := db.Insert(ctx, archiver); err != nil {
return nil, err
}
}
@@ -331,7 +309,7 @@ func StartArchive(request *ArchiveRequest) error {
}
func deleteOldRepoArchiver(ctx context.Context, archiver *repo_model.RepoArchiver) error {
- if err := repo_model.DeleteRepoArchiver(ctx, archiver); err != nil {
+ if _, err := db.DeleteByID[repo_model.RepoArchiver](ctx, archiver.ID); err != nil {
return err
}
p := archiver.RelativePath()
@@ -346,7 +324,7 @@ func DeleteOldRepositoryArchives(ctx context.Context, olderThan time.Duration) e
log.Trace("Doing: ArchiveCleanup")
for {
- archivers, err := repo_model.FindRepoArchives(ctx, repo_model.FindRepoArchiversOption{
+ archivers, err := db.Find[repo_model.RepoArchiver](ctx, repo_model.FindRepoArchiversOption{
ListOptions: db.ListOptions{
PageSize: 100,
Page: 1,
diff --git a/services/repository/branch.go b/services/repository/branch.go
index 735fa1a756..6ddc6badfa 100644
--- a/services/repository/branch.go
+++ b/services/repository/branch.go
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models"
+ actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
@@ -20,7 +21,9 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/queue"
repo_module "code.gitea.io/gitea/modules/repository"
+ "code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
+ webhook_module "code.gitea.io/gitea/modules/webhook"
notify_service "code.gitea.io/gitea/services/notify"
files_service "code.gitea.io/gitea/services/repository/files"
@@ -28,35 +31,13 @@ import (
)
// CreateNewBranch creates a new repository branch
-func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldBranchName, branchName string) (err error) {
- err = repo.MustNotBeArchived()
+func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, oldBranchName, branchName string) (err error) {
+ branch, err := git_model.GetBranch(ctx, repo.ID, oldBranchName)
if err != nil {
return err
}
- // Check if branch name can be used
- if err := checkBranchName(ctx, repo, branchName); err != nil {
- return err
- }
-
- if !git.IsBranchExist(ctx, repo.RepoPath(), oldBranchName) {
- return git_model.ErrBranchNotExist{
- BranchName: oldBranchName,
- }
- }
-
- if err := git.Push(ctx, repo.RepoPath(), git.PushOptions{
- Remote: repo.RepoPath(),
- Branch: fmt.Sprintf("%s%s:%s%s", git.BranchPrefix, oldBranchName, git.BranchPrefix, branchName),
- Env: repo_module.PushingEnvironment(doer, repo),
- }); err != nil {
- if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
- return err
- }
- return fmt.Errorf("push: %w", err)
- }
-
- return nil
+ return CreateNewBranchFromCommit(ctx, doer, repo, gitRepo, branch.CommitID, branchName)
}
// Branch contains the branch information
@@ -87,22 +68,17 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git
Keyword: keyword,
}
- totalNumOfBranches, err := git_model.CountBranches(ctx, branchOpts)
+ dbBranches, totalNumOfBranches, err := db.FindAndCount[git_model.Branch](ctx, branchOpts)
if err != nil {
return nil, nil, 0, err
}
branchOpts.ExcludeBranchNames = []string{repo.DefaultBranch}
- dbBranches, err := git_model.FindBranches(ctx, branchOpts)
- if err != nil {
+ if err := git_model.BranchList(dbBranches).LoadDeletedBy(ctx); err != nil {
return nil, nil, 0, err
}
-
- if err := dbBranches.LoadDeletedBy(ctx); err != nil {
- return nil, nil, 0, err
- }
- if err := dbBranches.LoadPusher(ctx); err != nil {
+ if err := git_model.BranchList(dbBranches).LoadPusher(ctx); err != nil {
return nil, nil, 0, err
}
@@ -249,8 +225,49 @@ func checkBranchName(ctx context.Context, repo *repo_model.Repository, name stri
return err
}
+// syncBranchToDB sync the branch information in the database. It will try to update the branch first,
+// if updated success with affect records > 0, then all are done. Because that means the branch has been in the database.
+// If no record is affected, that means the branch does not exist in database. So there are two possibilities.
+// One is this is a new branch, then we just need to insert the record. Another is the branches haven't been synced,
+// then we need to sync all the branches into database.
+func syncBranchToDB(ctx context.Context, repoID, pusherID int64, branchName string, commit *git.Commit) error {
+ cnt, err := git_model.UpdateBranch(ctx, repoID, pusherID, branchName, commit)
+ if err != nil {
+ return fmt.Errorf("git_model.UpdateBranch %d:%s failed: %v", repoID, branchName, err)
+ }
+ if cnt > 0 { // This means branch does exist, so it's a normal update. It also means the branch has been synced.
+ return nil
+ }
+
+ // if user haven't visit UI but directly push to a branch after upgrading from 1.20 -> 1.21,
+ // we cannot simply insert the branch but need to check we have branches or not
+ hasBranch, err := db.Exist[git_model.Branch](ctx, git_model.FindBranchOptions{
+ RepoID: repoID,
+ IsDeletedBranch: util.OptionalBoolFalse,
+ }.ToConds())
+ if err != nil {
+ return err
+ }
+ if !hasBranch {
+ if _, err = repo_module.SyncRepoBranches(ctx, repoID, pusherID); err != nil {
+ return fmt.Errorf("repo_module.SyncRepoBranches %d:%s failed: %v", repoID, branchName, err)
+ }
+ return nil
+ }
+
+ // if database have branches but not this branch, it means this is a new branch
+ return db.Insert(ctx, &git_model.Branch{
+ RepoID: repoID,
+ Name: branchName,
+ CommitID: commit.ID.String(),
+ CommitMessage: commit.Summary(),
+ PusherID: pusherID,
+ CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()),
+ })
+}
+
// CreateNewBranchFromCommit creates a new repository branch
-func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, branchName string) (err error) {
+func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, commitID, branchName string) (err error) {
err = repo.MustNotBeArchived()
if err != nil {
return err
@@ -263,7 +280,7 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
if err := git.Push(ctx, repo.RepoPath(), git.PushOptions{
Remote: repo.RepoPath(),
- Branch: fmt.Sprintf("%s:%s%s", commit, git.BranchPrefix, branchName),
+ Branch: fmt.Sprintf("%s:%s%s", commitID, git.BranchPrefix, branchName),
Env: repo_module.PushingEnvironment(doer, repo),
}); err != nil {
if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) {
@@ -271,7 +288,6 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo
}
return fmt.Errorf("push: %w", err)
}
-
return nil
}
@@ -294,13 +310,28 @@ func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_m
return "from_not_exist", nil
}
- if err := git_model.RenameBranch(ctx, repo, from, to, func(isDefault bool) error {
+ if err := git_model.RenameBranch(ctx, repo, from, to, func(ctx context.Context, isDefault bool) error {
err2 := gitRepo.RenameBranch(from, to)
if err2 != nil {
return err2
}
if isDefault {
+ // if default branch changed, we need to delete all schedules and cron jobs
+ if err := actions_model.DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
+ log.Error("DeleteCronTaskByRepo: %v", err)
+ }
+ // cancel running cron jobs of this repository and delete old schedules
+ if err := actions_model.CancelRunningJobs(
+ ctx,
+ repo.ID,
+ from,
+ "",
+ webhook_module.HookEventSchedule,
+ ); err != nil {
+ log.Error("CancelRunningJobs: %v", err)
+ }
+
err2 = gitRepo.SetDefaultBranch(to)
if err2 != nil {
return err2
@@ -352,6 +383,11 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
return fmt.Errorf("GetBranch: %vc", err)
}
+ objectFormat, err := gitRepo.GetObjectFormat()
+ if err != nil {
+ return err
+ }
+
if rawBranch.IsDeleted {
return nil
}
@@ -378,7 +414,7 @@ func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.R
&repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromBranch(branchName),
OldCommitID: commit.ID.String(),
- NewCommitID: git.EmptySHA,
+ NewCommitID: objectFormat.EmptyObjectID().String(),
PusherID: doer.ID,
PusherName: doer.Name,
RepoUserName: repo.OwnerName,
@@ -431,3 +467,50 @@ func AddAllRepoBranchesToSyncQueue(ctx context.Context, doerID int64) error {
}
return nil
}
+
+func SetRepoDefaultBranch(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, newBranchName string) error {
+ if repo.DefaultBranch == newBranchName {
+ return nil
+ }
+
+ if !gitRepo.IsBranchExist(newBranchName) {
+ return git_model.ErrBranchNotExist{
+ BranchName: newBranchName,
+ }
+ }
+
+ oldDefaultBranchName := repo.DefaultBranch
+ repo.DefaultBranch = newBranchName
+ if err := db.WithTx(ctx, func(ctx context.Context) error {
+ if err := repo_model.UpdateDefaultBranch(ctx, repo); err != nil {
+ return err
+ }
+
+ if err := actions_model.DeleteScheduleTaskByRepo(ctx, repo.ID); err != nil {
+ log.Error("DeleteCronTaskByRepo: %v", err)
+ }
+ // cancel running cron jobs of this repository and delete old schedules
+ if err := actions_model.CancelRunningJobs(
+ ctx,
+ repo.ID,
+ oldDefaultBranchName,
+ "",
+ webhook_module.HookEventSchedule,
+ ); err != nil {
+ log.Error("CancelRunningJobs: %v", err)
+ }
+
+ if err := gitRepo.SetDefaultBranch(newBranchName); err != nil {
+ if !git.IsErrUnsupportedVersion(err) {
+ return err
+ }
+ }
+ return nil
+ }); err != nil {
+ return err
+ }
+
+ notify_service.ChangeDefaultBranch(ctx, repo)
+
+ return nil
+}
diff --git a/services/repository/cache.go b/services/repository/cache.go
index 91351cbf49..b0811a99fc 100644
--- a/services/repository/cache.go
+++ b/services/repository/cache.go
@@ -9,15 +9,10 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/setting"
)
// CacheRef cachhe last commit information of the branch or the tag
func CacheRef(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, fullRefName git.RefName) error {
- if !setting.CacheService.LastCommit.Enabled {
- return nil
- }
-
commit, err := gitRepo.GetCommit(fullRefName.String())
if err != nil {
return err
diff --git a/services/repository/check.go b/services/repository/check.go
index 2f26d030c3..b874ede51f 100644
--- a/services/repository/check.go
+++ b/services/repository/check.go
@@ -192,7 +192,7 @@ func ReinitMissingRepositories(ctx context.Context) error {
default:
}
log.Trace("Initializing %d/%d...", repo.OwnerID, repo.ID)
- if err := git.InitRepository(ctx, repo.RepoPath(), true); err != nil {
+ if err := git.InitRepository(ctx, repo.RepoPath(), true, repo.ObjectFormatName); err != nil {
log.Error("Unable (re)initialize repository %d at %s. Error: %v", repo.ID, repo.RepoPath(), err)
if err2 := system_model.CreateRepositoryNotice("InitRepository [%d]: %v", repo.ID, err); err2 != nil {
log.Error("CreateRepositoryNotice: %v", err2)
diff --git a/services/repository/create.go b/services/repository/create.go
index b6b6454c44..bcf2c85c21 100644
--- a/services/repository/create.go
+++ b/services/repository/create.go
@@ -27,22 +27,23 @@ import (
// CreateRepoOptions contains the create repository options
type CreateRepoOptions struct {
- Name string
- Description string
- OriginalURL string
- GitServiceType api.GitServiceType
- Gitignores string
- IssueLabels string
- License string
- Readme string
- DefaultBranch string
- IsPrivate bool
- IsMirror bool
- IsTemplate bool
- AutoInit bool
- Status repo_model.RepositoryStatus
- TrustModel repo_model.TrustModelType
- MirrorInterval string
+ Name string
+ Description string
+ OriginalURL string
+ GitServiceType api.GitServiceType
+ Gitignores string
+ IssueLabels string
+ License string
+ Readme string
+ DefaultBranch string
+ IsPrivate bool
+ IsMirror bool
+ IsTemplate bool
+ AutoInit bool
+ Status repo_model.RepositoryStatus
+ TrustModel repo_model.TrustModelType
+ MirrorInterval string
+ ObjectFormatName string
}
func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
@@ -134,7 +135,7 @@ func prepareRepoCommit(ctx context.Context, repo *repo_model.Repository, tmpDir,
// InitRepository initializes README and .gitignore if needed.
func initRepository(ctx context.Context, repoPath string, u *user_model.User, repo *repo_model.Repository, opts CreateRepoOptions) (err error) {
- if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name); err != nil {
+ if err = repo_module.CheckInitRepository(ctx, repo.OwnerName, repo.Name, opts.ObjectFormatName); err != nil {
return err
}
@@ -234,6 +235,7 @@ func CreateRepositoryDirectly(ctx context.Context, doer, u *user_model.User, opt
TrustModel: opts.TrustModel,
IsMirror: opts.IsMirror,
DefaultBranch: opts.DefaultBranch,
+ ObjectFormatName: opts.ObjectFormatName,
}
var rollbackRepo *repo_model.Repository
diff --git a/services/repository/files/cherry_pick.go b/services/repository/files/cherry_pick.go
index c1c5bfb617..613b46d8f6 100644
--- a/services/repository/files/cherry_pick.go
+++ b/services/repository/files/cherry_pick.go
@@ -31,12 +31,15 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
log.Error("%v", err)
}
defer t.Close()
- if err := t.Clone(opts.OldBranch); err != nil {
+ if err := t.Clone(opts.OldBranch, false); err != nil {
return nil, err
}
if err := t.SetDefaultIndex(); err != nil {
return nil, err
}
+ if err := t.RefreshIndex(); err != nil {
+ return nil, err
+ }
// Get the commit of the original branch
commit, err := t.GetBranchCommit(opts.OldBranch)
@@ -48,7 +51,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
- lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
+ lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("CherryPick: Invalid last commit ID: %w", err)
}
@@ -67,7 +70,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod
}
parent, err := commit.ParentID(0)
if err != nil {
- parent = git.MustIDFromString(git.EmptyTreeSHA)
+ parent = git.ObjectFormatFromName(repo.ObjectFormatName).EmptyTree()
}
base, right := parent.String(), commit.ID.String()
diff --git a/services/repository/files/commit.go b/services/repository/files/commit.go
index 3e4627487b..048e41e6fd 100644
--- a/services/repository/files/commit.go
+++ b/services/repository/files/commit.go
@@ -29,10 +29,15 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
}
defer closer.Close()
- if commit, err := gitRepo.GetCommit(sha); err != nil {
+ objectFormat, err := gitRepo.GetObjectFormat()
+ if err != nil {
+ return fmt.Errorf("GetObjectFormat[%s]: %w", repoPath, err)
+ }
+ commit, err := gitRepo.GetCommit(sha)
+ if err != nil {
gitRepo.Close()
return fmt.Errorf("GetCommit[%s]: %w", sha, err)
- } else if len(sha) != git.SHAFullLength {
+ } else if len(sha) != objectFormat.FullLength() {
// use complete commit sha
sha = commit.ID.String()
}
@@ -41,7 +46,7 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato
if err := git_model.NewCommitStatus(ctx, git_model.NewCommitStatusOptions{
Repo: repo,
Creator: creator,
- SHA: sha,
+ SHA: commit.ID,
CommitStatus: status,
}); err != nil {
return fmt.Errorf("NewCommitStatus[repo_id: %d, user_id: %d, sha: %s]: %w", repo.ID, creator.ID, sha, err)
diff --git a/services/repository/files/diff.go b/services/repository/files/diff.go
index 373249b114..bf8b938e21 100644
--- a/services/repository/files/diff.go
+++ b/services/repository/files/diff.go
@@ -21,7 +21,7 @@ func GetDiffPreview(ctx context.Context, repo *repo_model.Repository, branch, tr
return nil, err
}
defer t.Close()
- if err := t.Clone(branch); err != nil {
+ if err := t.Clone(branch, true); err != nil {
return nil, err
}
if err := t.SetDefaultIndex(); err != nil {
diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go
index 5ef0619636..14f8caaa8c 100644
--- a/services/repository/files/patch.go
+++ b/services/repository/files/patch.go
@@ -113,7 +113,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
log.Error("%v", err)
}
defer t.Close()
- if err := t.Clone(opts.OldBranch); err != nil {
+ if err := t.Clone(opts.OldBranch, true); err != nil {
return nil, err
}
if err := t.SetDefaultIndex(); err != nil {
@@ -130,7 +130,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
- lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
+ lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("ApplyPatch: Invalid last commit ID: %w", err)
}
diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go
index be13b2016a..9fcd335c55 100644
--- a/services/repository/files/temp_repo.go
+++ b/services/repository/files/temp_repo.go
@@ -51,8 +51,13 @@ func (t *TemporaryUploadRepository) Close() {
}
// Clone the base repository to our path and set branch as the HEAD
-func (t *TemporaryUploadRepository) Clone(branch string) error {
- if _, _, err := git.NewCommand(t.ctx, "clone", "-s", "--bare", "-b").AddDynamicArguments(branch, t.repo.RepoPath(), t.basePath).RunStdString(nil); err != nil {
+func (t *TemporaryUploadRepository) Clone(branch string, bare bool) error {
+ cmd := git.NewCommand(t.ctx, "clone", "-s", "-b").AddDynamicArguments(branch, t.repo.RepoPath(), t.basePath)
+ if bare {
+ cmd.AddArguments("--bare")
+ }
+
+ if _, _, err := cmd.RunStdString(nil); err != nil {
stderr := err.Error()
if matched, _ := regexp.MatchString(".*Remote branch .* not found in upstream origin.*", stderr); matched {
return git.ErrBranchNotExist{
@@ -77,8 +82,8 @@ func (t *TemporaryUploadRepository) Clone(branch string) error {
}
// Init the repository
-func (t *TemporaryUploadRepository) Init() error {
- if err := git.InitRepository(t.ctx, t.basePath, false); err != nil {
+func (t *TemporaryUploadRepository) Init(objectFormatName string) error {
+ if err := git.InitRepository(t.ctx, t.basePath, false, objectFormatName); err != nil {
return err
}
gitRepo, err := git.OpenRepository(t.ctx, t.basePath)
@@ -97,6 +102,14 @@ func (t *TemporaryUploadRepository) SetDefaultIndex() error {
return nil
}
+// RefreshIndex looks at the current index and checks to see if merges or updates are needed by checking stat() information.
+func (t *TemporaryUploadRepository) RefreshIndex() error {
+ if _, _, err := git.NewCommand(t.ctx, "update-index", "--refresh").RunStdString(&git.RunOpts{Dir: t.basePath}); err != nil {
+ return fmt.Errorf("RefreshIndex: %w", err)
+ }
+ return nil
+}
+
// LsFiles checks if the given filename arguments are in the index
func (t *TemporaryUploadRepository) LsFiles(filenames ...string) ([]string, error) {
stdOut := new(bytes.Buffer)
diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go
index 0b1d304845..9d3185c3fc 100644
--- a/services/repository/files/tree.go
+++ b/services/repository/files/tree.go
@@ -37,19 +37,21 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
}
apiURL := repo.APIURL()
apiURLLen := len(apiURL)
+ objectFormat, _ := gitRepo.GetObjectFormat()
+ hashLen := objectFormat.FullLength()
- // 51 is len(sha1) + len("/git/blobs/"). 40 + 11.
- blobURL := make([]byte, apiURLLen+51)
+ const gitBlobsPath = "/git/blobs/"
+ blobURL := make([]byte, apiURLLen+hashLen+len(gitBlobsPath))
copy(blobURL, apiURL)
- copy(blobURL[apiURLLen:], "/git/blobs/")
+ copy(blobURL[apiURLLen:], []byte(gitBlobsPath))
- // 51 is len(sha1) + len("/git/trees/"). 40 + 11.
- treeURL := make([]byte, apiURLLen+51)
+ const gitTreePath = "/git/trees/"
+ treeURL := make([]byte, apiURLLen+hashLen+len(gitTreePath))
copy(treeURL, apiURL)
- copy(treeURL[apiURLLen:], "/git/trees/")
+ copy(treeURL[apiURLLen:], []byte(gitTreePath))
- // 40 is the size of the sha1 hash in hexadecimal format.
- copyPos := len(treeURL) - git.SHAFullLength
+ // copyPos is at the start of the hash
+ copyPos := len(treeURL) - hashLen
if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage {
perPage = setting.API.DefaultGitTreesPerPage
diff --git a/services/repository/files/update.go b/services/repository/files/update.go
index 2a08bcbace..1892043304 100644
--- a/services/repository/files/update.go
+++ b/services/repository/files/update.go
@@ -146,7 +146,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
}
defer t.Close()
hasOldBranch := true
- if err := t.Clone(opts.OldBranch); err != nil {
+ if err := t.Clone(opts.OldBranch, true); err != nil {
for _, file := range opts.Files {
if file.Operation == "delete" {
return nil, err
@@ -155,7 +155,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return nil, err
}
- if err := t.Init(); err != nil {
+ if err := t.Init(repo.ObjectFormatName); err != nil {
return nil, err
}
hasOldBranch = false
@@ -202,7 +202,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
- lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
+ lastCommitID, err := t.gitRepo.ConvertToGitID(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("ConvertToSHA1: Invalid last commit ID: %w", err)
}
@@ -438,7 +438,7 @@ func CreateOrUpdateFile(ctx context.Context, t *TemporaryUploadRepository, file
if lfsMetaObject != nil {
// We have an LFS object - create it
- lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, lfsMetaObject)
+ lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, lfsMetaObject.RepositoryID, lfsMetaObject.Pointer)
if err != nil {
return err
}
diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go
index f4e1da7bb1..cbfaf49d13 100644
--- a/services/repository/files/upload.go
+++ b/services/repository/files/upload.go
@@ -87,11 +87,11 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
defer t.Close()
hasOldBranch := true
- if err = t.Clone(opts.OldBranch); err != nil {
+ if err = t.Clone(opts.OldBranch, true); err != nil {
if !git.IsErrBranchNotExist(err) || !repo.IsEmpty {
return err
}
- if err = t.Init(); err != nil {
+ if err = t.Init(repo.ObjectFormatName); err != nil {
return err
}
hasOldBranch = false
@@ -143,7 +143,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use
if infos[i].lfsMetaObject == nil {
continue
}
- infos[i].lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, infos[i].lfsMetaObject)
+ infos[i].lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, infos[i].lfsMetaObject.RepositoryID, infos[i].lfsMetaObject.Pointer)
if err != nil {
// OK Now we need to cleanup
return cleanUpAfterFailure(ctx, &infos, t, err)
diff --git a/services/repository/lfs.go b/services/repository/lfs.go
index 8e654b6f13..b437fda15d 100644
--- a/services/repository/lfs.go
+++ b/services/repository/lfs.go
@@ -78,13 +78,14 @@ func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.R
store := lfs.NewContentStore()
errStop := errors.New("STOPERR")
+ objectFormat, _ := gitRepo.GetObjectFormat()
err = git_model.IterateLFSMetaObjectsForRepo(ctx, repo.ID, func(ctx context.Context, metaObject *git_model.LFSMetaObject, count int64) error {
if opts.NumberToCheckPerRepo > 0 && total > opts.NumberToCheckPerRepo {
return errStop
}
total++
- pointerSha := git.ComputeBlobHash([]byte(metaObject.Pointer.StringContent()))
+ pointerSha := git.ComputeBlobHash(objectFormat, []byte(metaObject.Pointer.StringContent()))
if gitRepo.IsObjectExist(pointerSha.String()) {
return git_model.MarkLFSMetaObject(ctx, metaObject.ID)
diff --git a/services/repository/lfs_test.go b/services/repository/lfs_test.go
index 61348143d0..ee0b8f6b89 100644
--- a/services/repository/lfs_test.go
+++ b/services/repository/lfs_test.go
@@ -52,7 +52,7 @@ func storeObjectInRepo(t *testing.T, repositoryID int64, content *[]byte) string
pointer, err := lfs.GeneratePointer(bytes.NewReader(*content))
assert.NoError(t, err)
- _, err = git_model.NewLFSMetaObject(db.DefaultContext, &git_model.LFSMetaObject{Pointer: pointer, RepositoryID: repositoryID})
+ _, err = git_model.NewLFSMetaObject(db.DefaultContext, repositoryID, pointer)
assert.NoError(t, err)
contentStore := lfs.NewContentStore()
exist, err := contentStore.Exists(pointer)
diff --git a/services/repository/push.go b/services/repository/push.go
index 97da45f52b..e86eebde81 100644
--- a/services/repository/push.go
+++ b/services/repository/push.go
@@ -35,7 +35,9 @@ var pushQueue *queue.WorkerPoolQueue[[]*repo_module.PushUpdateOptions]
func handler(items ...[]*repo_module.PushUpdateOptions) [][]*repo_module.PushUpdateOptions {
for _, opts := range items {
if err := pushUpdates(opts); err != nil {
- log.Error("pushUpdate failed: %v", err)
+ // Username and repository stays the same between items in opts.
+ pushUpdate := opts[0]
+ log.Error("pushUpdate[%s/%s] failed: %v", pushUpdate.RepoUserName, pushUpdate.RepoName, err)
}
}
return nil
@@ -63,7 +65,7 @@ func PushUpdates(opts []*repo_module.PushUpdateOptions) error {
for _, opt := range opts {
if opt.IsNewRef() && opt.IsDelRef() {
- return fmt.Errorf("Old and new revisions are both %s", git.EmptySHA)
+ return fmt.Errorf("Old and new revisions are both NULL")
}
}
@@ -92,6 +94,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
defer gitRepo.Close()
+ objectFormat, err := gitRepo.GetObjectFormat()
+ if err != nil {
+ return fmt.Errorf("unknown repository ObjectFormat [%s]: %w", repoPath, err)
+ }
+
if err = repo_module.UpdateRepoSize(ctx, repo); err != nil {
return fmt.Errorf("Failed to update size for repository: %v", err)
}
@@ -104,7 +111,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
log.Trace("pushUpdates: %-v %s %s %s", repo, opts.OldCommitID, opts.NewCommitID, opts.RefFullName)
if opts.IsNewRef() && opts.IsDelRef() {
- return fmt.Errorf("old and new revisions are both %s", git.EmptySHA)
+ return fmt.Errorf("old and new revisions are both %s", objectFormat.EmptyObjectID())
}
if opts.RefFullName.IsTag() {
if pusher == nil || pusher.ID != opts.PusherID {
@@ -124,7 +131,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
&repo_module.PushUpdateOptions{
RefFullName: git.RefNameFromTag(tagName),
OldCommitID: opts.OldCommitID,
- NewCommitID: git.EmptySHA,
+ NewCommitID: objectFormat.EmptyObjectID().String(),
}, repo_module.NewPushCommits())
delTags = append(delTags, tagName)
@@ -137,13 +144,13 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
commits := repo_module.NewPushCommits()
commits.HeadCommit = repo_module.CommitToPushCommit(newCommit)
- commits.CompareURL = repo.ComposeCompareURL(git.EmptySHA, opts.NewCommitID)
+ commits.CompareURL = repo.ComposeCompareURL(objectFormat.EmptyObjectID().String(), opts.NewCommitID)
notify_service.PushCommits(
ctx, pusher, repo,
&repo_module.PushUpdateOptions{
RefFullName: opts.RefFullName,
- OldCommitID: git.EmptySHA,
+ OldCommitID: objectFormat.EmptyObjectID().String(),
NewCommitID: opts.NewCommitID,
}, commits)
@@ -227,7 +234,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
oldCommitID := opts.OldCommitID
- if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 {
+ if oldCommitID == objectFormat.EmptyObjectID().String() && len(commits.Commits) > 0 {
oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1)
if err != nil && !git.IsErrNotExist(err) {
log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err)
@@ -243,11 +250,11 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}
}
- if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch {
+ if oldCommitID == objectFormat.EmptyObjectID().String() && repo.DefaultBranch != branch {
oldCommitID = repo.DefaultBranch
}
- if oldCommitID != git.EmptySHA {
+ if oldCommitID != objectFormat.EmptyObjectID().String() {
commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID)
} else {
commits.CompareURL = ""
@@ -257,7 +264,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
}
- if err = git_model.UpdateBranch(ctx, repo.ID, opts.PusherID, branch, newCommit); err != nil {
+ if err = syncBranchToDB(ctx, repo.ID, opts.PusherID, branch, newCommit); err != nil {
return fmt.Errorf("git_model.UpdateBranch %s:%s failed: %v", repo.FullName(), branch, err)
}
@@ -320,9 +327,12 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
lowerTags = append(lowerTags, strings.ToLower(tag))
}
- releases, err := repo_model.GetReleasesByRepoIDAndNames(ctx, repo.ID, lowerTags)
+ releases, err := db.Find[repo_model.Release](ctx, repo_model.FindReleasesOptions{
+ RepoID: repo.ID,
+ TagNames: lowerTags,
+ })
if err != nil {
- return fmt.Errorf("GetReleasesByRepoIDAndNames: %w", err)
+ return fmt.Errorf("db.Find[repo_model.Release]: %w", err)
}
relMap := make(map[string]*repo_model.Release)
for _, rel := range releases {
diff --git a/services/repository/setting.go b/services/repository/setting.go
new file mode 100644
index 0000000000..6496ac4014
--- /dev/null
+++ b/services/repository/setting.go
@@ -0,0 +1,47 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package repository
+
+import (
+ "context"
+ "slices"
+
+ actions_model "code.gitea.io/gitea/models/actions"
+ "code.gitea.io/gitea/models/db"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/log"
+)
+
+// UpdateRepositoryUnits updates a repository's units
+func UpdateRepositoryUnits(ctx context.Context, repo *repo_model.Repository, units []repo_model.RepoUnit, deleteUnitTypes []unit.Type) (err error) {
+ ctx, committer, err := db.TxContext(ctx)
+ if err != nil {
+ return err
+ }
+ defer committer.Close()
+
+ // Delete existing settings of units before adding again
+ for _, u := range units {
+ deleteUnitTypes = append(deleteUnitTypes, u.Type)
+ }
+
+ if slices.Contains(deleteUnitTypes, unit.TypeActions) {
+ if err := actions_model.CleanRepoScheduleTasks(ctx, repo); err != nil {
+ log.Error("CleanRepoScheduleTasks: %v", err)
+ }
+ }
+
+ if _, err = db.GetEngine(ctx).Where("repo_id = ?", repo.ID).In("type", deleteUnitTypes).Delete(new(repo_model.RepoUnit)); err != nil {
+ return err
+ }
+
+ if len(units) > 0 {
+ if err = db.Insert(ctx, units); err != nil {
+ return err
+ }
+ }
+
+ return committer.Commit()
+}
diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go
index 97e15ba6c7..031c474dd7 100644
--- a/services/secrets/secrets.go
+++ b/services/secrets/secrets.go
@@ -76,7 +76,7 @@ func DeleteSecretByName(ctx context.Context, ownerID, repoID int64, name string)
}
func deleteSecret(ctx context.Context, s *secret_model.Secret) error {
- if _, err := db.DeleteByID(ctx, s.ID, s); err != nil {
+ if _, err := db.DeleteByID[secret_model.Secret](ctx, s.ID); err != nil {
return err
}
return nil
diff --git a/services/user/delete.go b/services/user/delete.go
index c4617e064e..0e9c866171 100644
--- a/services/user/delete.go
+++ b/services/user/delete.go
@@ -159,7 +159,9 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
// ***** END: PublicKey *****
// ***** START: GPGPublicKey *****
- keys, err := asymkey_model.ListGPGKeys(ctx, u.ID, db.ListOptions{})
+ keys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
+ OwnerID: u.ID,
+ })
if err != nil {
return fmt.Errorf("ListGPGKeys: %w", err)
}
@@ -185,7 +187,7 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
}
// ***** END: ExternalLoginUser *****
- if _, err = db.DeleteByID(ctx, u.ID, new(user_model.User)); err != nil {
+ if _, err = db.DeleteByID[user_model.User](ctx, u.ID); err != nil {
return fmt.Errorf("delete: %w", err)
}
diff --git a/services/user/user.go b/services/user/user.go
index 932e359c9f..8bf083192f 100644
--- a/services/user/user.go
+++ b/services/user/user.go
@@ -129,6 +129,10 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
return fmt.Errorf("%s is an organization not a user", u.Name)
}
+ if user_model.IsLastAdminUser(ctx, u) {
+ return models.ErrDeleteLastAdminUser{UID: u.ID}
+ }
+
if purge {
// Disable the user first
// NOTE: This is deliberately not within a transaction as it must disable the user immediately to prevent any further action by the user to be purged.
@@ -295,7 +299,8 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error {
}
if err := DeleteUser(ctx, u, false); err != nil {
// Ignore users that were set inactive by admin.
- if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || models.IsErrUserOwnPackages(err) {
+ if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) ||
+ models.IsErrUserOwnPackages(err) || models.IsErrDeleteLastAdminUser(err) {
continue
}
return err
diff --git a/services/webhook/slack.go b/services/webhook/slack.go
index ac27b5bc71..945b0662d8 100644
--- a/services/webhook/slack.go
+++ b/services/webhook/slack.go
@@ -92,6 +92,7 @@ func SlackLinkFormatter(url, text string) string {
// SlackLinkToRef slack-formatter link to a repo ref
func SlackLinkToRef(repoURL, ref string) string {
+ // FIXME: SHA1 hardcoded here
url := git.RefURL(repoURL, ref)
refName := git.RefName(ref).ShortName()
return SlackLinkFormatter(url, refName)
diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index 18371efd09..ce54a00da7 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -19,6 +19,7 @@ import (
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/sync"
asymkey_service "code.gitea.io/gitea/services/asymkey"
+ repo_service "code.gitea.io/gitea/services/repository"
)
// TODO: use clustered lock (unique queue? or *abuse* cache)
@@ -36,7 +37,7 @@ func InitWiki(ctx context.Context, repo *repo_model.Repository) error {
return nil
}
- if err := git.InitRepository(ctx, repo.WikiPath(), true); err != nil {
+ if err := git.InitRepository(ctx, repo.WikiPath(), true, repo.ObjectFormatName); err != nil {
return fmt.Errorf("InitRepository: %w", err)
} else if err = repo_module.CreateDelegateHooks(repo.WikiPath()); err != nil {
return fmt.Errorf("createDelegateHooks: %w", err)
@@ -350,7 +351,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model
// DeleteWiki removes the actual and local copy of repository wiki.
func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error {
- if err := repo_model.UpdateRepositoryUnits(ctx, repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
+ if err := repo_service.UpdateRepositoryUnits(ctx, repo, nil, []unit.Type{unit.TypeWiki}); err != nil {
return err
}
diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go
index e8da176a08..277fa086ac 100644
--- a/services/wiki/wiki_test.go
+++ b/services/wiki/wiki_test.go
@@ -302,7 +302,7 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) {
// Now create a temporaryDirectory
tmpDir := t.TempDir()
- err := git.InitRepository(git.DefaultContext, tmpDir, true)
+ err := git.InitRepository(git.DefaultContext, tmpDir, true, git.Sha1ObjectFormat.Name())
assert.NoError(t, err)
gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir)
diff --git a/templates/admin/actions.tmpl b/templates/admin/actions.tmpl
index 9640e0fd1f..597863d73b 100644
--- a/templates/admin/actions.tmpl
+++ b/templates/admin/actions.tmpl
@@ -3,5 +3,8 @@
{{if eq .PageType "runners"}}
{{template "shared/actions/runner_list" .}}
{{end}}
+ {{if eq .PageType "variables"}}
+ {{template "shared/variables/variable_list" .}}
+ {{end}}
{{template "admin/layout_footer" .}}
diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl
index 7eb9d086e6..1cc4b7bb09 100644
--- a/templates/admin/config.tmpl
+++ b/templates/admin/config.tmpl
@@ -151,8 +151,6 @@