diff --git a/.github/workflows/pull-docker-dryrun.yml b/.github/workflows/pull-docker-dryrun.yml
index 405521c354c..bcc19e3eba8 100644
--- a/.github/workflows/pull-docker-dryrun.yml
+++ b/.github/workflows/pull-docker-dryrun.yml
@@ -29,6 +29,7 @@ jobs:
context: .
platforms: linux/amd64,linux/arm64,linux/riscv64
push: false
+ cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
- name: Build rootless container image
uses: docker/build-push-action@v6
with:
@@ -36,3 +37,4 @@ jobs:
push: false
platforms: linux/amd64,linux/arm64,linux/riscv64
file: Dockerfile.rootless
+ cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml
index f073df05d39..a7b2fda0426 100644
--- a/.github/workflows/release-nightly.yml
+++ b/.github/workflows/release-nightly.yml
@@ -120,6 +120,8 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
+ cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful
+ cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootful,mode=max
- name: build rootless docker image
uses: docker/build-push-action@v6
with:
@@ -129,3 +131,5 @@ jobs:
file: Dockerfile.rootless
tags: ${{ steps.meta_rootless.outputs.tags }}
annotations: ${{ steps.meta_rootless.outputs.annotations }}
+ cache-from: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless
+ cache-to: type=registry,ref=ghcr.io/go-gitea/gitea:buildcache-rootless,mode=max
diff --git a/.golangci.yml b/.golangci.yml
index 2b85c89fdce..afd91d65e59 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -51,8 +51,6 @@ linters:
desc: do not use the go-chi cache package, use gitea's cache system
- pkg: github.com/pkg/errors
desc: use builtin errors package instead
- - pkg: github.com/go-ap/errors
- desc: use builtin errors package instead
nolintlint:
allow-unused: false
require-explanation: true
@@ -141,9 +139,6 @@ linters:
- linters:
- unused
text: (?i)swagger
- - linters:
- - staticcheck
- text: (?i)argument x is overwritten before first use
- linters:
- gocritic
text: '(?i)commentFormatting: put a space between `//` and comment text'
diff --git a/Makefile b/Makefile
index cb7742c5c74..280aa853b8e 100644
--- a/Makefile
+++ b/Makefile
@@ -15,13 +15,13 @@ XGO_VERSION := go-1.25.x
AIR_PACKAGE ?= github.com/air-verse/air@v1
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/v3/cmd/editorconfig-checker@v3
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.9.2
-GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.9.0
+GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1
GXZ_PACKAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.15
-MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.7.0
+MISSPELL_PACKAGE ?= github.com/golangci/misspell/cmd/misspell@v0.8.0
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.33.1
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@v1
-ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.10
+ACTIONLINT_PACKAGE ?= github.com/rhysd/actionlint/cmd/actionlint@v1.7.11
DOCKER_IMAGE ?= gitea/gitea
DOCKER_TAG ?= latest
@@ -322,11 +322,11 @@ lint-md-fix: node_modules ## lint markdown files and fix issues
.PHONY: lint-spell
lint-spell: ## lint spelling
- @go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -error $(SPELLCHECK_FILES)
+ @git ls-files $(SPELLCHECK_FILES) | xargs go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -error
.PHONY: lint-spell-fix
lint-spell-fix: ## lint spelling and fix issues
- @go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -w $(SPELLCHECK_FILES)
+ @git ls-files $(SPELLCHECK_FILES) | xargs go run $(MISSPELL_PACKAGE) -dict assets/misspellings.csv -w
.PHONY: lint-go
lint-go: ## lint go files
diff --git a/assets/go-licenses.json b/assets/go-licenses.json
index 03fdbcc0b20..30f56e5f872 100644
--- a/assets/go-licenses.json
+++ b/assets/go-licenses.json
@@ -39,11 +39,6 @@
"path": "filippo.io/edwards25519/LICENSE",
"licenseText": "Copyright (c) 2009 The Go Authors. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
- {
- "name": "git.sr.ht/~mariusor/go-xsd-duration",
- "path": "git.sr.ht/~mariusor/go-xsd-duration/LICENSE",
- "licenseText": "MIT License\n\nCopyright (c) 2019 Go xsd:duration\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
- },
{
"name": "gitea.com/go-chi/binding",
"path": "gitea.com/go-chi/binding/LICENSE",
@@ -489,21 +484,6 @@
"path": "github.com/gliderlabs/ssh/LICENSE",
"licenseText": "Copyright (c) 2016 Glider Labs. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n * Neither the name of Glider Labs nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
},
- {
- "name": "github.com/go-ap/activitypub",
- "path": "github.com/go-ap/activitypub/LICENSE",
- "licenseText": "MIT License\n\nCopyright (c) 2017 Golang ActitvityPub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
- },
- {
- "name": "github.com/go-ap/errors",
- "path": "github.com/go-ap/errors/LICENSE",
- "licenseText": "MIT License\n\nCopyright (c) 2019 Golang ActitvityPub\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
- },
- {
- "name": "github.com/go-ap/jsonld",
- "path": "github.com/go-ap/jsonld/LICENSE",
- "licenseText": "MIT License\n\nCopyright (c) 2017 Marius Orcsik\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
- },
{
"name": "github.com/go-asn1-ber/asn1-ber",
"path": "github.com/go-asn1-ber/asn1-ber/LICENSE",
@@ -1154,11 +1134,6 @@
"path": "github.com/urfave/cli/v3/LICENSE",
"licenseText": "MIT License\n\nCopyright (c) 2023 urfave/cli maintainers\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
},
- {
- "name": "github.com/valyala/fastjson",
- "path": "github.com/valyala/fastjson/LICENSE",
- "licenseText": "The MIT License (MIT)\n\nCopyright (c) 2018 Aliaksandr Valialkin\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
- },
{
"name": "github.com/wneessen/go-mail",
"path": "github.com/wneessen/go-mail/LICENSE",
diff --git a/cmd/hook.go b/cmd/hook.go
index 6004f679acf..4f6492b0f05 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -205,6 +205,7 @@ Gitea or set your environment appropriately.`, "")
PullRequestID: prID,
DeployKeyID: deployKeyID,
ActionPerm: actionPerm,
+ IsWiki: isWiki,
}
scanner := bufio.NewScanner(os.Stdin)
@@ -366,6 +367,7 @@ Gitea or set your environment appropriately.`, "")
GitPushOptions: pushOptions(),
PullRequestID: prID,
PushTrigger: repo_module.PushTrigger(os.Getenv(repo_module.EnvPushTrigger)),
+ IsWiki: isWiki,
}
oldCommitIDs := make([]string, hookBatchSize)
newCommitIDs := make([]string, hookBatchSize)
@@ -513,6 +515,7 @@ Gitea or set your environment appropriately.`, "")
reader := bufio.NewReader(os.Stdin)
repoUser := os.Getenv(repo_module.EnvRepoUsername)
+ isWiki, _ := strconv.ParseBool(os.Getenv(repo_module.EnvRepoIsWiki))
repoName := os.Getenv(repo_module.EnvRepoName)
pusherID, _ := strconv.ParseInt(os.Getenv(repo_module.EnvPusherID), 10, 64)
pusherName := os.Getenv(repo_module.EnvPusherName)
@@ -590,6 +593,7 @@ Gitea or set your environment appropriately.`, "")
UserName: pusherName,
UserID: pusherID,
GitPushOptions: make(map[string]string),
+ IsWiki: isWiki,
}
hookOptions.OldCommitIDs = make([]string, 0, hookBatchSize)
hookOptions.NewCommitIDs = make([]string, 0, hookBatchSize)
diff --git a/cmd/mailer.go b/cmd/mailer.go
index 72bd8e56012..a7dbd68e20a 100644
--- a/cmd/mailer.go
+++ b/cmd/mailer.go
@@ -17,10 +17,10 @@ func runSendMail(ctx context.Context, c *cli.Command) error {
setting.MustInstalled()
subject := c.String("title")
- confirmSkiped := c.Bool("force")
+ confirmSkipped := c.Bool("force")
body := c.String("content")
- if !confirmSkiped {
+ if !confirmSkipped {
if len(body) == 0 {
fmt.Print("warning: Content is empty")
}
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index f5e8f03ae23..9297f3d0627 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -74,6 +74,7 @@ RUN_USER = ; git
;; especially when the Gitea instance needs to be accessed in a container network.
;; * legacy: detect the public URL from "Host" header if "X-Forwarded-Proto" header exists, otherwise use "ROOT_URL".
;; * auto: always use "Host" header, and also use "X-Forwarded-Proto" header if it exists. If no "Host" header, use "ROOT_URL".
+;; * never: always use "ROOT_URL", never detect from request headers.
;PUBLIC_URL_DETECTION = legacy
;;
;; For development purpose only. It makes Gitea handle sub-path ("/sub-path/owner/repo/...") directly when debugging without a reverse proxy.
@@ -238,9 +239,6 @@ RUN_USER = ; git
;; Indicate whether to check minimum key size with corresponding type
;MINIMUM_KEY_SIZE_CHECK = false
;;
-;; Disable CDN even in "prod" mode
-;OFFLINE_MODE = true
-;;
;; TLS Settings: Either ACME or manual
;; (Other common TLS configuration are found before)
;ENABLE_ACME = false
@@ -1983,12 +1981,12 @@ LEVEL = Info
;; or a custom avatar source, like: http://cn.gravatar.com/avatar/
;GRAVATAR_SOURCE = gravatar
;;
-;; This value will always be true in offline mode.
+;; Deprecated, see Web UI Admin Panel -> Config -> Settings
;DISABLE_GRAVATAR = false
;;
;; Federated avatar lookup uses DNS to discover avatar associated
;; with emails, see https://www.libravatar.org
-;; This value will always be false in offline mode or when Gravatar is disabled.
+;; Deprecated, see Web UI Admin Panel -> Config -> Settings
;ENABLE_FEDERATED_AVATAR = false
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/flake.lock b/flake.lock
index a608aa3b892..d00e8c85018 100644
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
- "lastModified": 1771369470,
- "narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=",
+ "lastModified": 1772198003,
+ "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=",
"owner": "nixos",
"repo": "nixpkgs",
- "rev": "0182a361324364ae3f436a63005877674cf45efb",
+ "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61",
"type": "github"
},
"original": {
diff --git a/go.mod b/go.mod
index c5486fceb89..c85c4c0b399 100644
--- a/go.mod
+++ b/go.mod
@@ -46,8 +46,6 @@ require (
github.com/felixge/fgprof v0.9.5
github.com/fsnotify/fsnotify v1.9.0
github.com/gliderlabs/ssh v0.3.8
- github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742
- github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
github.com/go-chi/chi/v5 v5.2.5
github.com/go-chi/cors v1.2.2
github.com/go-co-op/gocron v1.37.0
@@ -135,7 +133,6 @@ require (
code.gitea.io/gitea-vet v0.2.3 // indirect
dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
- git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/DataDog/zstd v1.5.7 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
@@ -177,7 +174,7 @@ require (
github.com/caddyserver/zerossl v0.1.4 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/cloudflare/circl v1.6.1 // indirect
+ github.com/cloudflare/circl v1.6.3 // indirect
github.com/couchbase/go-couchbase v0.1.1 // indirect
github.com/couchbase/gomemcached v0.3.3 // indirect
github.com/couchbase/goutils v0.1.2 // indirect
@@ -191,7 +188,6 @@ require (
github.com/fatih/color v1.18.0 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/git-lfs/pktline v0.0.0-20230103162542-ca444d533ef1 // indirect
- github.com/go-ap/errors v0.0.0-20250527110557-c8db454e53fd // indirect
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
github.com/go-enry/go-oniguruma v1.2.1 // indirect
github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e // indirect
@@ -263,7 +259,6 @@ require (
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/tinylib/msgp v1.6.1 // indirect
github.com/unknwon/com v1.0.1 // indirect
- github.com/valyala/fastjson v1.6.4 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -297,8 +292,6 @@ replace github.com/jaytaylor/html2text => github.com/Necoro/html2text v0.0.0-202
replace github.com/nektos/act => gitea.com/gitea/act v0.261.8
-replace git.sr.ht/~mariusor/go-xsd-duration => gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078
-
exclude github.com/gofrs/uuid v3.2.0+incompatible
exclude github.com/gofrs/uuid v4.0.0+incompatible
diff --git a/go.sum b/go.sum
index 883547adad9..02e65325429 100644
--- a/go.sum
+++ b/go.sum
@@ -33,8 +33,6 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gitea.com/gitea/act v0.261.8 h1:rUWB5GOZOubfe2VteKb7XP3HRIbcW3UUmfh7bVAgQcA=
gitea.com/gitea/act v0.261.8/go.mod h1:lTp4136rwbZiZS3ZVQeHCvd4qRAZ7LYeiRBqOSdMY/4=
-gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:BAFmdZpRW7zMQZQDClaCWobRj9uL1MR3MzpCVJvc5s4=
-gitea.com/gitea/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso=
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed/go.mod h1:E3i3cgB04dDx0v3CytCgRTTn9Z/9x891aet3r456RVw=
gitea.com/go-chi/cache v0.2.1 h1:bfAPkvXlbcZxPCpcmDVCWoHgiBSBmZN/QosnZvEC0+g=
@@ -229,8 +227,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
+github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8=
+github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -305,12 +303,6 @@ github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
-github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742 h1:X+SsQlZSgJO0A4d1+nI7+g4axZ8u3iUKPirYb5nB5ic=
-github.com/go-ap/activitypub v0.0.0-20250810115208-cb73b20a1742/go.mod h1:0rgUaERG5qjYenwz4oN5OnUjvkdRuHRjb+2c8FRjz+w=
-github.com/go-ap/errors v0.0.0-20250527110557-c8db454e53fd h1:fM5mNIWTPoxoOYoTLd6ifkKXSlXa830l5MYXsrt1UmE=
-github.com/go-ap/errors v0.0.0-20250527110557-c8db454e53fd/go.mod h1:Vkh+Z3f24K8nMsJKXo1FHn5ebPsXvB/WDH5JRtYqdNo=
-github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73 h1:GMKIYXyXPGIp+hYiWOhfqK4A023HdgisDT4YGgf99mw=
-github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo=
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
@@ -766,8 +758,6 @@ github.com/urfave/cli-docs/v3 v3.0.0-alpha6 h1:w/l/N0xw1rO/aHRIGXJ0lDwwYFOzilup1
github.com/urfave/cli-docs/v3 v3.0.0-alpha6/go.mod h1:p7Z4lg8FSTrPB9GTaNyTrK3ygffHZcK3w0cU2VE+mzU=
github.com/urfave/cli/v3 v3.4.1 h1:1M9UOCy5bLmGnuu1yn3t3CB4rG79Rtoxuv1sPhnm6qM=
github.com/urfave/cli/v3 v3.4.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
-github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
-github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8=
github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k=
diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index 2f5aff09335..e2bb72b722a 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -14,6 +14,7 @@ import (
"net/url"
"slices"
"strings"
+ "time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/container"
@@ -27,6 +28,11 @@ import (
"xorm.io/xorm"
)
+// Authorization codes should expire within 10 minutes per https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2
+const oauth2AuthorizationCodeValidity = 10 * time.Minute
+
+var ErrOAuth2AuthorizationCodeInvalidated = errors.New("oauth2 authorization code already invalidated")
+
// OAuth2Application represents an OAuth2 client (RFC 6749)
type OAuth2Application struct {
ID int64 `xorm:"pk autoincr"`
@@ -386,6 +392,14 @@ func (code *OAuth2AuthorizationCode) TableName() string {
return "oauth2_authorization_code"
}
+// IsExpired reports whether the authorization code is expired.
+func (code *OAuth2AuthorizationCode) IsExpired() bool {
+ if code.ValidUntil.IsZero() {
+ return true
+ }
+ return code.ValidUntil <= timeutil.TimeStampNow()
+}
+
// GenerateRedirectURI generates a redirect URI for a successful authorization request. State will be used if not empty.
func (code *OAuth2AuthorizationCode) GenerateRedirectURI(state string) (*url.URL, error) {
redirect, err := url.Parse(code.RedirectURI)
@@ -403,8 +417,14 @@ func (code *OAuth2AuthorizationCode) GenerateRedirectURI(state string) (*url.URL
// Invalidate deletes the auth code from the database to invalidate this code
func (code *OAuth2AuthorizationCode) Invalidate(ctx context.Context) error {
- _, err := db.GetEngine(ctx).ID(code.ID).NoAutoCondition().Delete(code)
- return err
+ affected, err := db.GetEngine(ctx).ID(code.ID).NoAutoCondition().Delete(code)
+ if err != nil {
+ return err
+ }
+ if affected == 0 {
+ return ErrOAuth2AuthorizationCodeInvalidated
+ }
+ return nil
}
// ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation.
@@ -472,6 +492,7 @@ func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redi
// for code scanners to grab sensitive tokens.
codeSecret := "gta_" + base32Lower.EncodeToString(rBytes)
+ validUntil := time.Now().Add(oauth2AuthorizationCodeValidity)
code = &OAuth2AuthorizationCode{
Grant: grant,
GrantID: grant.ID,
@@ -479,6 +500,7 @@ func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redi
Code: codeSecret,
CodeChallenge: codeChallenge,
CodeChallengeMethod: codeChallengeMethod,
+ ValidUntil: timeutil.TimeStamp(validUntil.Unix()),
}
if err := db.Insert(ctx, code); err != nil {
return nil, err
diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go
index 97f750755a2..88ae065652c 100644
--- a/models/auth/oauth2_test.go
+++ b/models/auth/oauth2_test.go
@@ -5,13 +5,45 @@ package auth_test
import (
"testing"
+ "time"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/unittest"
+ "code.gitea.io/gitea/modules/timeutil"
"github.com/stretchr/testify/assert"
)
+func TestOAuth2AuthorizationCodeValidity(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ t.Run("GenerateSetsValidUntil", func(t *testing.T) {
+ grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
+ expectedValidUntil := timeutil.TimeStamp(time.Now().Unix() + 600)
+ code, err := grant.GenerateNewAuthorizationCode(t.Context(), "http://127.0.0.1/", "", "")
+ assert.NoError(t, err)
+ assert.Equal(t, expectedValidUntil, code.ValidUntil)
+ assert.False(t, code.IsExpired())
+ assert.NoError(t, code.Invalidate(t.Context()))
+ })
+
+ t.Run("Expired", func(t *testing.T) {
+ defer timeutil.MockSet(time.Unix(2, 0).UTC())()
+
+ code := &auth_model.OAuth2AuthorizationCode{ValidUntil: timeutil.TimeStamp(1)}
+ assert.True(t, code.IsExpired())
+ })
+
+ t.Run("InvalidateTwice", func(t *testing.T) {
+ code, err := auth_model.GetOAuth2AuthorizationByCode(t.Context(), "authcode")
+ assert.NoError(t, err)
+ if assert.NotNil(t, code) {
+ assert.NoError(t, code.Invalidate(t.Context()))
+ assert.ErrorIs(t, code.Invalidate(t.Context()), auth_model.ErrOAuth2AuthorizationCodeInvalidated)
+ }
+ })
+}
+
func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
diff --git a/models/auth/source.go b/models/auth/source.go
index 08cfc9615b0..c0b262f870a 100644
--- a/models/auth/source.go
+++ b/models/auth/source.go
@@ -117,7 +117,7 @@ func RegisterTypeConfig(typ Type, exemplar Config) {
type Source struct {
ID int64 `xorm:"pk autoincr"`
Type Type
- Name string `xorm:"UNIQUE"`
+ Name string `xorm:"UNIQUE"` // it can be the OIDC's provider name, see services/auth/source/oauth2/source_register.go: RegisterSource
IsActive bool `xorm:"INDEX NOT NULL DEFAULT false"`
IsSyncEnabled bool `xorm:"INDEX NOT NULL DEFAULT false"`
TwoFactorPolicy string `xorm:"two_factor_policy NOT NULL DEFAULT ''"`
diff --git a/models/git/branch.go b/models/git/branch.go
index bc6e2a17486..698c43f1472 100644
--- a/models/git/branch.go
+++ b/models/git/branch.go
@@ -247,7 +247,7 @@ func DeleteBranches(ctx context.Context, repoID, doerID int64, branchIDs []int64
return err
}
for _, branch := range branches {
- if err := AddDeletedBranch(ctx, repoID, branch.Name, doerID); err != nil {
+ if err := MarkBranchAsDeleted(ctx, repoID, branch.Name, doerID); err != nil {
return err
}
}
@@ -268,8 +268,8 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string
})
}
-// AddDeletedBranch adds a deleted branch to the database
-func AddDeletedBranch(ctx context.Context, repoID int64, branchName string, deletedByID int64) error {
+// MarkBranchAsDeleted marks branch as deleted
+func MarkBranchAsDeleted(ctx context.Context, repoID int64, branchName string, deletedByID int64) error {
branch, err := GetBranch(ctx, repoID, branchName)
if err != nil {
return err
@@ -583,3 +583,12 @@ func FindRecentlyPushedNewBranches(ctx context.Context, doer *user_model.User, o
return newBranches, nil
}
+
+// CountBranches returns the number of branches in the repository
+func CountBranches(ctx context.Context, repoID int64, includeDeleted bool) (int64, error) {
+ sess := db.GetEngine(ctx).Where("repo_id=?", repoID)
+ if !includeDeleted {
+ sess.And("is_deleted=?", false)
+ }
+ return sess.Count(new(Branch))
+}
diff --git a/models/git/branch_test.go b/models/git/branch_test.go
index 9e6148946d7..3832df93509 100644
--- a/models/git/branch_test.go
+++ b/models/git/branch_test.go
@@ -28,8 +28,8 @@ func TestAddDeletedBranch(t *testing.T) {
firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{ID: 1})
assert.True(t, firstBranch.IsDeleted)
- assert.NoError(t, git_model.AddDeletedBranch(t.Context(), repo.ID, firstBranch.Name, firstBranch.DeletedByID))
- assert.NoError(t, git_model.AddDeletedBranch(t.Context(), repo.ID, "branch2", int64(1)))
+ assert.NoError(t, git_model.MarkBranchAsDeleted(t.Context(), repo.ID, firstBranch.Name, firstBranch.DeletedByID))
+ assert.NoError(t, git_model.MarkBranchAsDeleted(t.Context(), repo.ID, "branch2", int64(1)))
secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.Branch{RepoID: repo.ID, Name: "branch2"})
assert.True(t, secondBranch.IsDeleted)
@@ -263,3 +263,25 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, deletedBranch)
}
+
+func TestCountBranches(t *testing.T) {
+ // 1. Setup - Exactly like TestAddDeletedBranch
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+
+ // 2. Execution - Using t.Context() to match the rest of the file
+ initialCount, err := git_model.CountBranches(t.Context(), repo.ID, false)
+ assert.NoError(t, err)
+
+ // 3. Database Action - Using t.Context()
+ err = db.Insert(t.Context(), &git_model.Branch{
+ RepoID: repo.ID,
+ Name: "test-branch-for-counting",
+ })
+ assert.NoError(t, err)
+
+ // 4. Verification
+ newCount, err := git_model.CountBranches(t.Context(), repo.ID, false)
+ assert.NoError(t, err)
+ assert.Equal(t, initialCount+1, newCount)
+}
diff --git a/models/issues/review_list.go b/models/issues/review_list.go
index 86b1a2e76e6..d0430cd06d3 100644
--- a/models/issues/review_list.go
+++ b/models/issues/review_list.go
@@ -173,9 +173,9 @@ func GetReviewsByIssueID(ctx context.Context, issueID int64) (latestReviews, mig
reviewersMap := make(map[int64][]*Review) // key is reviewer id
originalReviewersMap := make(map[int64][]*Review) // key is original author id
reviewTeamsMap := make(map[int64][]*Review) // key is reviewer team id
- countedReivewTypes := []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, ReviewTypeComment}
+ countedReviewTypes := []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest, ReviewTypeComment}
for _, review := range reviews {
- if review.ReviewerTeamID == 0 && slices.Contains(countedReivewTypes, review.Type) && !review.Dismissed {
+ if review.ReviewerTeamID == 0 && slices.Contains(countedReviewTypes, review.Type) && !review.Dismissed {
if review.OriginalAuthorID != 0 {
originalReviewersMap[review.OriginalAuthorID] = append(originalReviewersMap[review.OriginalAuthorID], review)
} else {
diff --git a/models/organization/org.go b/models/organization/org.go
index b4d28f54054..10a2c330e56 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -178,7 +178,7 @@ func (org *Organization) HomeLink() string {
return org.AsUser().HomeLink()
}
-// FindOrgMembersOpts represensts find org members conditions
+// FindOrgMembersOpts represents find org members conditions
type FindOrgMembersOpts struct {
db.ListOptions
Doer *user_model.User
diff --git a/models/repo/avatar.go b/models/repo/avatar.go
index eff64bd2398..bfb08d9982d 100644
--- a/models/repo/avatar.go
+++ b/models/repo/avatar.go
@@ -41,20 +41,14 @@ func generateRandomAvatar(ctx context.Context, repo *Repository) error {
idToString := strconv.FormatInt(repo.ID, 10)
seed := idToString
- img, err := avatar.RandomImage([]byte(seed))
- if err != nil {
- return fmt.Errorf("RandomImage: %w", err)
- }
+ img := avatar.RandomImageDefaultSize([]byte(seed))
repo.Avatar = idToString
if err := storage.SaveFrom(storage.RepoAvatars, repo.CustomAvatarRelativePath(), func(w io.Writer) error {
- if err := png.Encode(w, img); err != nil {
- log.Error("Encode: %v", err)
- }
- return err
+ return png.Encode(w, img)
}); err != nil {
- return fmt.Errorf("Failed to create dir %s: %w", repo.CustomAvatarRelativePath(), err)
+ return fmt.Errorf("failed to create dir %s: %w", repo.CustomAvatarRelativePath(), err)
}
log.Info("New random avatar created for repository: %d", repo.ID)
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 07b9bf30ccd..25207cc28b0 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -281,7 +281,7 @@ func (repo *Repository) SizeDetailsString() string {
var str strings.Builder
sizeDetails := repo.SizeDetails()
for _, detail := range sizeDetails {
- str.WriteString(fmt.Sprintf("%s: %s, ", detail.Name, base.FileSize(detail.Size)))
+ fmt.Fprintf(&str, "%s: %s, ", detail.Name, base.FileSize(detail.Size))
}
return strings.TrimSuffix(str.String(), ", ")
}
@@ -422,52 +422,37 @@ func (repo *Repository) UnitEnabled(ctx context.Context, tp unit.Type) bool {
return false
}
-// MustGetUnit always returns a RepoUnit object
+// MustGetUnit always returns a RepoUnit object even if the unit doesn't exist (not enabled)
func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit {
ru, err := repo.GetUnit(ctx, tp)
if err == nil {
return ru
}
-
+ if !errors.Is(err, util.ErrNotExist) {
+ setting.PanicInDevOrTesting("Failed to get unit %v for repository %d: %v", tp, repo.ID, err)
+ }
+ ru = &RepoUnit{RepoID: repo.ID, Type: tp}
switch tp {
case unit.TypeExternalWiki:
- return &RepoUnit{
- Type: tp,
- Config: new(ExternalWikiConfig),
- }
+ ru.Config = new(ExternalWikiConfig)
case unit.TypeExternalTracker:
- return &RepoUnit{
- Type: tp,
- Config: new(ExternalTrackerConfig),
- }
+ ru.Config = new(ExternalTrackerConfig)
case unit.TypePullRequests:
- return &RepoUnit{
- Type: tp,
- Config: new(PullRequestsConfig),
- }
+ ru.Config = new(PullRequestsConfig)
case unit.TypeIssues:
- return &RepoUnit{
- Type: tp,
- Config: new(IssuesConfig),
- }
+ ru.Config = new(IssuesConfig)
case unit.TypeActions:
- return &RepoUnit{
- Type: tp,
- Config: new(ActionsConfig),
- }
+ ru.Config = new(ActionsConfig)
case unit.TypeProjects:
- cfg := new(ProjectsConfig)
- cfg.ProjectsMode = ProjectsModeNone
- return &RepoUnit{
- Type: tp,
- Config: cfg,
+ ru.Config = new(ProjectsConfig)
+ default: // other units don't have config
+ }
+ if ru.Config != nil {
+ if err = ru.Config.FromDB(nil); err != nil {
+ setting.PanicInDevOrTesting("Failed to load default config for unit %v of repository %d: %v", tp, repo.ID, err)
}
}
-
- return &RepoUnit{
- Type: tp,
- Config: new(UnitConfig),
- }
+ return ru
}
// GetUnit returns a RepoUnit object
diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go
index d03d5e1e6a4..491e96770c4 100644
--- a/models/repo/repo_unit.go
+++ b/models/repo/repo_unit.go
@@ -134,10 +134,25 @@ type PullRequestsConfig struct {
DefaultTargetBranch string
}
+func DefaultPullRequestsConfig() *PullRequestsConfig {
+ cfg := &PullRequestsConfig{
+ AllowMerge: true,
+ AllowRebase: true,
+ AllowRebaseMerge: true,
+ AllowSquash: true,
+ AllowFastForwardOnly: true,
+ AllowRebaseUpdate: true,
+ DefaultAllowMaintainerEdit: true,
+ }
+ cfg.DefaultMergeStyle = MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle)
+ cfg.DefaultMergeStyle = util.IfZero(cfg.DefaultMergeStyle, MergeStyleMerge)
+ return cfg
+}
+
// FromDB fills up a PullRequestsConfig from serialized format.
func (cfg *PullRequestsConfig) FromDB(bs []byte) error {
- // AllowRebaseUpdate = true as default for existing PullRequestConfig in DB
- cfg.AllowRebaseUpdate = true
+ // set default values for existing PullRequestConfig in DB
+ *cfg = *DefaultPullRequestsConfig()
return json.UnmarshalHandleDoubleEncode(bs, &cfg)
}
@@ -156,17 +171,8 @@ func (cfg *PullRequestsConfig) IsMergeStyleAllowed(mergeStyle MergeStyle) bool {
mergeStyle == MergeStyleManuallyMerged && cfg.AllowManualMerge
}
-// GetDefaultMergeStyle returns the default merge style for this pull request
-func (cfg *PullRequestsConfig) GetDefaultMergeStyle() MergeStyle {
- if len(cfg.DefaultMergeStyle) != 0 {
- return cfg.DefaultMergeStyle
- }
-
- if setting.Repository.PullRequest.DefaultMergeStyle != "" {
- return MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle)
- }
-
- return MergeStyleMerge
+func DefaultPullRequestsUnit(repoID int64) RepoUnit {
+ return RepoUnit{RepoID: repoID, Type: unit.TypePullRequests, Config: DefaultPullRequestsConfig()}
}
type ActionsConfig struct {
@@ -241,6 +247,8 @@ type ProjectsConfig struct {
// FromDB fills up a ProjectsConfig from serialized format.
func (cfg *ProjectsConfig) FromDB(bs []byte) error {
+ // TODO: remove GetProjectsMode, only use ProjectsMode
+ cfg.ProjectsMode = ProjectsModeAll
return json.UnmarshalHandleDoubleEncode(bs, &cfg)
}
diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go
index 08cf964bc8b..e15a64b01e8 100644
--- a/models/repo/user_repo.go
+++ b/models/repo/user_repo.go
@@ -147,19 +147,21 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
}
// GetIssuePostersWithSearch returns users with limit of 30 whose username started with prefix that have authored an issue/pull request for the given repository
-// If isShowFullName is set to true, also include full name prefix search
-func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string, isShowFullName bool) ([]*user_model.User, error) {
+// It searches with the "user.name" and "user.full_name" fields case-insensitively.
+func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string) ([]*user_model.User, error) {
users := make([]*user_model.User, 0, 30)
- var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"}
- if search != "" && isShowFullName {
- prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%"))
- }
cond := builder.In("`user`.id",
builder.Select("poster_id").From("issue").Where(
builder.Eq{"repo_id": repo.ID}.
And(builder.Eq{"is_pull": isPull}),
- ).GroupBy("poster_id")).And(prefixCond)
+ ).GroupBy("poster_id"))
+
+ if search != "" {
+ var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"}
+ prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%"))
+ cond = cond.And(prefixCond)
+ }
return users, db.GetEngine(ctx).
Where(cond).
diff --git a/models/repo/user_repo_test.go b/models/repo/user_repo_test.go
index a53cf39dc4c..cd8a0f1a1f7 100644
--- a/models/repo/user_repo_test.go
+++ b/models/repo/user_repo_test.go
@@ -44,12 +44,12 @@ func TestGetIssuePostersWithSearch(t *testing.T) {
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
- users, err := repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "USER", false /* full name */)
+ users, err := repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "USER")
require.NoError(t, err)
require.Len(t, users, 1)
assert.Equal(t, "user2", users[0].Name)
- users, err = repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "TW%O", true /* full name */)
+ users, err = repo_model.GetIssuePostersWithSearch(t.Context(), repo2, false, "TW%O")
require.NoError(t, err)
require.Len(t, users, 1)
assert.Equal(t, "user2", users[0].Name)
diff --git a/models/user/avatar.go b/models/user/avatar.go
index 542bd93b982..5811d859117 100644
--- a/models/user/avatar.go
+++ b/models/user/avatar.go
@@ -30,22 +30,16 @@ func GenerateRandomAvatar(ctx context.Context, u *User) error {
seed = u.Name
}
- img, err := avatar.RandomImage([]byte(seed))
- if err != nil {
- return fmt.Errorf("RandomImage: %w", err)
- }
+ img := avatar.RandomImageDefaultSize([]byte(seed))
u.Avatar = avatars.HashEmail(seed)
- _, err = storage.Avatars.Stat(u.CustomAvatarRelativePath())
+ _, err := storage.Avatars.Stat(u.CustomAvatarRelativePath())
if err != nil {
// If unable to Stat the avatar file (usually it means non-existing), then try to save a new one
// Don't share the images so that we can delete them easily
if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
- if err := png.Encode(w, img); err != nil {
- log.Error("Encode: %v", err)
- }
- return nil
+ return png.Encode(w, img)
}); err != nil {
return fmt.Errorf("failed to save avatar %s: %w", u.CustomAvatarRelativePath(), err)
}
@@ -74,7 +68,7 @@ func (u *User) AvatarLinkWithSize(ctx context.Context, size int) string {
switch {
case u.UseCustomAvatar:
useLocalAvatar = true
- case disableGravatar, setting.OfflineMode:
+ case disableGravatar:
useLocalAvatar = true
autoGenerateAvatar = true
}
diff --git a/models/user/list.go b/models/user/list.go
index 4337c34963e..aaaa7965c89 100644
--- a/models/user/list.go
+++ b/models/user/list.go
@@ -24,7 +24,7 @@ func (users UserList) GetUserIDs() []int64 {
return userIDs
}
-// GetTwoFaStatus return state of 2FA enrollement
+// GetTwoFaStatus return state of 2FA enrollment
func (users UserList) GetTwoFaStatus(ctx context.Context) map[int64]bool {
results := make(map[int64]bool, len(users))
for _, user := range users {
diff --git a/models/user/setting_options.go b/models/user/setting_options.go
index 6d37ef63d55..587a46e8dec 100644
--- a/models/user/setting_options.go
+++ b/models/user/setting_options.go
@@ -11,10 +11,6 @@ const (
// SettingsKeyShowOutdatedComments is the setting key whether or not to show outdated comments in PRs
SettingsKeyShowOutdatedComments = "comment_code.show_outdated"
- // UserActivityPubPrivPem is user's private key
- UserActivityPubPrivPem = "activitypub.priv_pem"
- // UserActivityPubPubPem is user's public key
- UserActivityPubPubPem = "activitypub.pub_pem"
// SignupIP is the IP address that the user signed up with
SignupIP = "signup.ip"
// SignupUserAgent is the user agent that the user signed up with
diff --git a/models/user/user.go b/models/user/user.go
index f8e8b5c64a2..a74662bb12a 100644
--- a/models/user/user.go
+++ b/models/user/user.go
@@ -8,6 +8,7 @@ import (
"context"
"encoding/hex"
"fmt"
+ "html/template"
"mime"
"net/mail"
"net/url"
@@ -28,6 +29,7 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/htmlutil"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
@@ -185,7 +187,7 @@ func (u *User) BeforeUpdate() {
}
// FIXME: this email doesn't need to be in lowercase, because the emails are mainly managed by the email table with lower_email field
- // This trick could be removed in new releases to display the user inputed email as-is.
+ // This trick could be removed in new releases to display the user inputted email as-is.
u.Email = strings.ToLower(u.Email)
if !u.IsOrganization() {
if len(u.AvatarEmail) == 0 {
@@ -417,16 +419,6 @@ func (u *User) IsTokenAccessAllowed() bool {
return u.Type == UserTypeIndividual || u.Type == UserTypeBot
}
-// DisplayName returns full name if it's not empty,
-// returns username otherwise.
-func (u *User) DisplayName() string {
- trimmed := strings.TrimSpace(u.FullName)
- if len(trimmed) > 0 {
- return trimmed
- }
- return u.Name
-}
-
// EmailTo returns a string suitable to be put into a e-mail `To:` header.
func (u *User) EmailTo() string {
sanitizedDisplayName := globalVars().emailToReplacer.Replace(u.DisplayName())
@@ -445,27 +437,45 @@ func (u *User) EmailTo() string {
return fmt.Sprintf("%s <%s>", mime.QEncoding.Encode("utf-8", add.Name), add.Address)
}
-// GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set,
-// returns username otherwise.
+// TODO: DefaultShowFullName causes messy logic, there are already too many methods to display a user's "display name", need to refactor them
+// * user.Name / user.FullName: directly used in templates
+// * user.DisplayName(): always show FullName if it's not empty, otherwise show Name
+// * user.GetDisplayName(): show FullName if it's not empty and DefaultShowFullName is set, otherwise show Name
+// * user.ShortName(): used a lot in templates, but it should be removed and let frontend use "ellipsis" styles
+// * activity action.ShortActUserName/GetActDisplayName/GetActDisplayNameTitle, etc: duplicate and messy
+
+// DisplayName returns full name if it's not empty, returns username otherwise.
+func (u *User) DisplayName() string {
+ fullName := strings.TrimSpace(u.FullName)
+ if fullName != "" {
+ return fullName
+ }
+ return u.Name
+}
+
+// GetDisplayName returns full name if it's not empty and DEFAULT_SHOW_FULL_NAME is set, otherwise, username.
func (u *User) GetDisplayName() string {
if setting.UI.DefaultShowFullName {
- trimmed := strings.TrimSpace(u.FullName)
- if len(trimmed) > 0 {
- return trimmed
+ fullName := strings.TrimSpace(u.FullName)
+ if fullName != "" {
+ return fullName
}
}
return u.Name
}
-// GetCompleteName returns the full name and username in the form of
-// "Full Name (username)" if full name is not empty, otherwise it returns
-// "username".
-func (u *User) GetCompleteName() string {
- trimmedFullName := strings.TrimSpace(u.FullName)
- if len(trimmedFullName) > 0 {
- return fmt.Sprintf("%s (%s)", trimmedFullName, u.Name)
+// ShortName ellipses username to length (still used by many templates), it calls GetDisplayName and respects DEFAULT_SHOW_FULL_NAME
+func (u *User) ShortName(length int) string {
+ return util.EllipsisDisplayString(u.GetDisplayName(), length)
+}
+
+func (u *User) GetShortDisplayNameLinkHTML() template.HTML {
+ fullName := strings.TrimSpace(u.FullName)
+ displayName, displayTooltip := u.Name, fullName
+ if setting.UI.DefaultShowFullName && fullName != "" {
+ displayName, displayTooltip = fullName, u.Name
}
- return u.Name
+ return htmlutil.HTMLFormat(`%s`, u.HomeLink(), displayTooltip, displayName)
}
func gitSafeName(name string) string {
@@ -488,14 +498,6 @@ func (u *User) GitName() string {
return fmt.Sprintf("user-%d", u.ID)
}
-// ShortName ellipses username to length
-func (u *User) ShortName(length int) string {
- if setting.UI.DefaultShowFullName && len(u.FullName) > 0 {
- return util.EllipsisDisplayString(u.FullName, length)
- }
- return util.EllipsisDisplayString(u.Name, length)
-}
-
// IsMailable checks if a user is eligible to receive emails.
// System users like Ghost and Gitea Actions are excluded.
func (u *User) IsMailable() bool {
diff --git a/modules/actions/workflows_test.go b/modules/actions/workflows_test.go
index 77a65aae496..ea027366f7e 100644
--- a/modules/actions/workflows_test.go
+++ b/modules/actions/workflows_test.go
@@ -190,7 +190,7 @@ func TestDetectMatched(t *testing.T) {
expected: true,
},
{
- desc: "HookEventSchedue(schedule) matches GithubEventSchedule(schedule)",
+ desc: "HookEventSchedule(schedule) matches GithubEventSchedule(schedule)",
triggedEvent: webhook_module.HookEventSchedule,
payload: nil,
yamlOn: "on: schedule",
diff --git a/modules/activitypub/client.go b/modules/activitypub/client.go
deleted file mode 100644
index a9941f9b759..00000000000
--- a/modules/activitypub/client.go
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package activitypub
-
-import (
- "bytes"
- "context"
- "crypto/rsa"
- "crypto/x509"
- "encoding/pem"
- "fmt"
- "net/http"
- "strings"
- "time"
-
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/proxy"
- "code.gitea.io/gitea/modules/setting"
-
- "github.com/42wim/httpsig"
-)
-
-const (
- // ActivityStreamsContentType const
- ActivityStreamsContentType = `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`
- httpsigExpirationTime = 60
-)
-
-// Gets the current time as an RFC 2616 formatted string
-// RFC 2616 requires RFC 1123 dates but with GMT instead of UTC
-func CurrentTime() string {
- return strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT")
-}
-
-func containsRequiredHTTPHeaders(method string, headers []string) error {
- var hasRequestTarget, hasDate, hasDigest bool
- for _, header := range headers {
- hasRequestTarget = hasRequestTarget || header == httpsig.RequestTarget
- hasDate = hasDate || header == "Date"
- hasDigest = hasDigest || header == "Digest"
- }
- if !hasRequestTarget {
- return fmt.Errorf("missing http header for %s: %s", method, httpsig.RequestTarget)
- } else if !hasDate {
- return fmt.Errorf("missing http header for %s: Date", method)
- } else if !hasDigest && method != http.MethodGet {
- return fmt.Errorf("missing http header for %s: Digest", method)
- }
- return nil
-}
-
-// Client struct
-type Client struct {
- client *http.Client
- algs []httpsig.Algorithm
- digestAlg httpsig.DigestAlgorithm
- getHeaders []string
- postHeaders []string
- priv *rsa.PrivateKey
- pubID string
-}
-
-// NewClient function
-func NewClient(ctx context.Context, user *user_model.User, pubID string) (c *Client, err error) {
- if err = containsRequiredHTTPHeaders(http.MethodGet, setting.Federation.GetHeaders); err != nil {
- return nil, err
- } else if err = containsRequiredHTTPHeaders(http.MethodPost, setting.Federation.PostHeaders); err != nil {
- return nil, err
- }
-
- priv, err := GetPrivateKey(ctx, user)
- if err != nil {
- return nil, err
- }
- privPem, _ := pem.Decode([]byte(priv))
- privParsed, err := x509.ParsePKCS1PrivateKey(privPem.Bytes)
- if err != nil {
- return nil, err
- }
-
- c = &Client{
- client: &http.Client{
- Transport: &http.Transport{
- Proxy: proxy.Proxy(),
- },
- },
- algs: setting.HttpsigAlgs,
- digestAlg: httpsig.DigestAlgorithm(setting.Federation.DigestAlgorithm),
- getHeaders: setting.Federation.GetHeaders,
- postHeaders: setting.Federation.PostHeaders,
- priv: privParsed,
- pubID: pubID,
- }
- return c, err
-}
-
-// NewRequest function
-func (c *Client) NewRequest(b []byte, to string) (req *http.Request, err error) {
- buf := bytes.NewBuffer(b)
- req, err = http.NewRequest(http.MethodPost, to, buf)
- if err != nil {
- return nil, err
- }
- req.Header.Add("Content-Type", ActivityStreamsContentType)
- req.Header.Add("Date", CurrentTime())
- req.Header.Add("User-Agent", "Gitea/"+setting.AppVer)
- signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime)
- if err != nil {
- return nil, err
- }
- err = signer.SignRequest(c.priv, c.pubID, req, b)
- return req, err
-}
-
-// Post function
-func (c *Client) Post(b []byte, to string) (resp *http.Response, err error) {
- var req *http.Request
- if req, err = c.NewRequest(b, to); err != nil {
- return nil, err
- }
- resp, err = c.client.Do(req)
- return resp, err
-}
diff --git a/modules/activitypub/client_test.go b/modules/activitypub/client_test.go
deleted file mode 100644
index 361270a8005..00000000000
--- a/modules/activitypub/client_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package activitypub
-
-import (
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/setting"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestActivityPubSignedPost(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- pubID := "https://example.com/pubID"
- c, err := NewClient(t.Context(), user, pubID)
- assert.NoError(t, err)
-
- expected := "BODY"
- srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- assert.Regexp(t, "^"+setting.Federation.DigestAlgorithm, r.Header.Get("Digest"))
- assert.Contains(t, r.Header.Get("Signature"), pubID)
- assert.Equal(t, ActivityStreamsContentType, r.Header.Get("Content-Type"))
- body, err := io.ReadAll(r.Body)
- assert.NoError(t, err)
- assert.Equal(t, expected, string(body))
- fmt.Fprint(w, expected)
- }))
- defer srv.Close()
-
- r, err := c.Post([]byte(expected), srv.URL)
- assert.NoError(t, err)
- defer r.Body.Close()
- body, err := io.ReadAll(r.Body)
- assert.NoError(t, err)
- assert.Equal(t, expected, string(body))
-}
diff --git a/modules/activitypub/main_test.go b/modules/activitypub/main_test.go
deleted file mode 100644
index 4591f1fa555..00000000000
--- a/modules/activitypub/main_test.go
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package activitypub
-
-import (
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
-
- _ "code.gitea.io/gitea/models"
- _ "code.gitea.io/gitea/models/actions"
- _ "code.gitea.io/gitea/models/activities"
-)
-
-func TestMain(m *testing.M) {
- unittest.MainTest(m)
-}
diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go
deleted file mode 100644
index 7f939af352a..00000000000
--- a/modules/activitypub/user_settings.go
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package activitypub
-
-import (
- "context"
-
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/util"
-)
-
-const rsaBits = 3072
-
-// GetKeyPair function returns a user's private and public keys
-func GetKeyPair(ctx context.Context, user *user_model.User) (pub, priv string, err error) {
- var settings map[string]*user_model.Setting
- settings, err = user_model.GetSettings(ctx, user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem})
- if err != nil {
- return pub, priv, err
- } else if len(settings) == 0 {
- if priv, pub, err = util.GenerateKeyPair(rsaBits); err != nil {
- return pub, priv, err
- }
- if err = user_model.SetUserSetting(ctx, user.ID, user_model.UserActivityPubPrivPem, priv); err != nil {
- return pub, priv, err
- }
- if err = user_model.SetUserSetting(ctx, user.ID, user_model.UserActivityPubPubPem, pub); err != nil {
- return pub, priv, err
- }
- return pub, priv, err
- }
- priv = settings[user_model.UserActivityPubPrivPem].SettingValue
- pub = settings[user_model.UserActivityPubPubPem].SettingValue
- return pub, priv, err
-}
-
-// GetPublicKey function returns a user's public key
-func GetPublicKey(ctx context.Context, user *user_model.User) (pub string, err error) {
- pub, _, err = GetKeyPair(ctx, user)
- return pub, err
-}
-
-// GetPrivateKey function returns a user's private key
-func GetPrivateKey(ctx context.Context, user *user_model.User) (priv string, err error) {
- _, priv, err = GetKeyPair(ctx, user)
- return priv, err
-}
diff --git a/modules/activitypub/user_settings_test.go b/modules/activitypub/user_settings_test.go
deleted file mode 100644
index 105d4aedea1..00000000000
--- a/modules/activitypub/user_settings_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package activitypub
-
-import (
- "testing"
-
- "code.gitea.io/gitea/models/unittest"
- user_model "code.gitea.io/gitea/models/user"
-
- _ "code.gitea.io/gitea/models" // https://forum.gitea.com/t/testfixtures-could-not-clean-table-access-no-such-table-access/4137/4
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestUserSettings(t *testing.T) {
- assert.NoError(t, unittest.PrepareTestDatabase())
- user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- pub, priv, err := GetKeyPair(t.Context(), user1)
- assert.NoError(t, err)
- pub1, err := GetPublicKey(t.Context(), user1)
- assert.NoError(t, err)
- assert.Equal(t, pub, pub1)
- priv1, err := GetPrivateKey(t.Context(), user1)
- assert.NoError(t, err)
- assert.Equal(t, priv, priv1)
-}
diff --git a/modules/assetfs/embed.go b/modules/assetfs/embed.go
index 0b544635db0..7c90e3aca21 100644
--- a/modules/assetfs/embed.go
+++ b/modules/assetfs/embed.go
@@ -260,7 +260,7 @@ func (fi *embeddedFileInfo) Mode() fs.FileMode {
}
func (fi *embeddedFileInfo) ModTime() time.Time {
- return getExecutableModTime()
+ return GetExecutableModTime()
}
func (fi *embeddedFileInfo) IsDir() bool {
@@ -279,9 +279,9 @@ func (fi *embeddedFileInfo) Info() (fs.FileInfo, error) {
return fi, nil
}
-// getExecutableModTime returns the modification time of the executable file.
+// GetExecutableModTime returns the modification time of the executable file.
// In bindata, we can't use the ModTime of the files because we need to make the build reproducible
-var getExecutableModTime = sync.OnceValue(func() (modTime time.Time) {
+var GetExecutableModTime = sync.OnceValue(func() (modTime time.Time) {
exePath, err := os.Executable()
if err != nil {
return modTime
diff --git a/modules/auth/password/hash/setting.go b/modules/auth/password/hash/setting.go
index f0715f31e1a..e0caed5ba88 100644
--- a/modules/auth/password/hash/setting.go
+++ b/modules/auth/password/hash/setting.go
@@ -14,7 +14,7 @@ const DefaultHashAlgorithmName = "pbkdf2"
var DefaultHashAlgorithm *PasswordHashAlgorithm
-// aliasAlgorithNames provides a mapping between the value of PASSWORD_HASH_ALGO
+// aliasAlgorithmNames provides a mapping between the value of PASSWORD_HASH_ALGO
// configured in the app.ini and the parameters used within the hashers internally.
//
// If it is necessary to change the default parameters for any hasher in future you
diff --git a/modules/avatar/avatar.go b/modules/avatar/avatar.go
index 106215ec0b2..3b622b99af0 100644
--- a/modules/avatar/avatar.go
+++ b/modules/avatar/avatar.go
@@ -28,21 +28,18 @@ import (
// than the size after resizing.
const DefaultAvatarSize = 256
-// RandomImageSize generates and returns a random avatar image unique to input data
+// RandomImageWithSize generates and returns a random avatar image unique to input data
// in custom size (height and width).
-func RandomImageSize(size int, data []byte) (image.Image, error) {
+func RandomImageWithSize(size int, data []byte) image.Image {
// we use white as background, and use dark colors to draw blocks
- imgMaker, err := identicon.New(size, color.White, identicon.DarkColors...)
- if err != nil {
- return nil, fmt.Errorf("identicon.New: %w", err)
- }
- return imgMaker.Make(data), nil
+ imgMaker := identicon.New(size, color.White, identicon.DarkColors)
+ return imgMaker.Make(data)
}
-// RandomImage generates and returns a random avatar image unique to input data
+// RandomImageDefaultSize generates and returns a random avatar image unique to input data
// in default size (height and width).
-func RandomImage(data []byte) (image.Image, error) {
- return RandomImageSize(DefaultAvatarSize*setting.Avatar.RenderedSizeFactor, data)
+func RandomImageDefaultSize(data []byte) image.Image {
+ return RandomImageWithSize(DefaultAvatarSize*setting.Avatar.RenderedSizeFactor, data)
}
// processAvatarImage process the avatar image data, crop and resize it if necessary.
diff --git a/modules/avatar/avatar_test.go b/modules/avatar/avatar_test.go
index a5a1a7c1b06..5414184b6b2 100644
--- a/modules/avatar/avatar_test.go
+++ b/modules/avatar/avatar_test.go
@@ -15,19 +15,6 @@ import (
"github.com/stretchr/testify/assert"
)
-func Test_RandomImageSize(t *testing.T) {
- _, err := RandomImageSize(0, []byte("gitea@local"))
- assert.Error(t, err)
-
- _, err = RandomImageSize(64, []byte("gitea@local"))
- assert.NoError(t, err)
-}
-
-func Test_RandomImage(t *testing.T) {
- _, err := RandomImage([]byte("gitea@local"))
- assert.NoError(t, err)
-}
-
func Test_ProcessAvatarPNG(t *testing.T) {
setting.Avatar.MaxWidth = 4096
setting.Avatar.MaxHeight = 4096
@@ -134,3 +121,18 @@ func Test_ProcessAvatarImage(t *testing.T) {
_, err = processAvatarImage(origin, 262144)
assert.ErrorContains(t, err, "image width is too large: 10 > 5")
}
+
+func BenchmarkRandomImage(b *testing.B) {
+ b.Run("size-48", func(b *testing.B) {
+ for b.Loop() {
+ // BenchmarkRandomImage/size-48-12 49549 22899 ns/op
+ RandomImageWithSize(48, []byte("test-content"))
+ }
+ })
+ b.Run("size-96", func(b *testing.B) {
+ for b.Loop() {
+ // BenchmarkRandomImage/size-96-12 13816 88187 ns/op
+ RandomImageWithSize(96, []byte("test-content"))
+ }
+ })
+}
diff --git a/modules/avatar/identicon/identicon.go b/modules/avatar/identicon/identicon.go
index 19f87da85af..a1a0f0d7bfe 100644
--- a/modules/avatar/identicon/identicon.go
+++ b/modules/avatar/identicon/identicon.go
@@ -8,13 +8,14 @@ package identicon
import (
"crypto/sha256"
- "errors"
- "fmt"
"image"
"image/color"
)
-const minImageSize = 16
+const (
+ minImageSize = 16
+ maxImageSize = 2048
+)
// Identicon is used to generate pseudo-random avatars
type Identicon struct {
@@ -24,25 +25,17 @@ type Identicon struct {
rect image.Rectangle
}
-// New returns an Identicon struct with the correct settings
-// size image size
-// back background color
-// fore all possible foreground colors. only one foreground color will be picked randomly for one image
-func New(size int, back color.Color, fore ...color.Color) (*Identicon, error) {
- if len(fore) == 0 {
- return nil, errors.New("foreground is not set")
- }
-
- if size < minImageSize {
- return nil, fmt.Errorf("size %d is smaller than min size %d", size, minImageSize)
- }
-
+// New returns an Identicon struct.
+// Only one foreground color will be picked randomly for one image.
+func New(size int, backColor color.Color, foreColors []color.Color) *Identicon {
+ size = max(size, minImageSize)
+ size = min(size, maxImageSize)
return &Identicon{
- foreColors: fore,
- backColor: back,
+ foreColors: foreColors,
+ backColor: backColor,
size: size,
rect: image.Rect(0, 0, size, size),
- }, nil
+ }
}
// Make generates an avatar by data
diff --git a/modules/avatar/identicon/identicon_test.go b/modules/avatar/identicon/identicon_test.go
index 23bcc73e2e6..6af4b41cce7 100644
--- a/modules/avatar/identicon/identicon_test.go
+++ b/modules/avatar/identicon/identicon_test.go
@@ -23,7 +23,7 @@ func TestGenerate(t *testing.T) {
}
backColor := color.White
- imgMaker, err := New(64, backColor, DarkColors...)
+ imgMaker, err := New(64, backColor, DarkColors)
assert.NoError(t, err)
for i := 0; i < 100; i++ {
s := strconv.Itoa(i)
diff --git a/modules/git/commit.go b/modules/git/commit.go
index b98d36d946f..dfecfe60575 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -86,50 +86,6 @@ func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
return c.repo.getCommitByPathWithID(c.ID, relpath)
}
-// AddChanges marks local changes to be ready for commit.
-func AddChanges(ctx context.Context, repoPath string, all bool, files ...string) error {
- cmd := gitcmd.NewCommand().AddArguments("add")
- if all {
- cmd.AddArguments("--all")
- }
- cmd.AddDashesAndList(files...)
- _, _, err := cmd.WithDir(repoPath).RunStdString(ctx)
- return err
-}
-
-// CommitChangesOptions the options when a commit created
-type CommitChangesOptions struct {
- Committer *Signature
- Author *Signature
- Message string
-}
-
-// CommitChanges commits local changes with given committer, author and message.
-// If author is nil, it will be the same as committer.
-func CommitChanges(ctx context.Context, repoPath string, opts CommitChangesOptions) error {
- cmd := gitcmd.NewCommand()
- if opts.Committer != nil {
- cmd.AddOptionValues("-c", "user.name="+opts.Committer.Name)
- cmd.AddOptionValues("-c", "user.email="+opts.Committer.Email)
- }
- cmd.AddArguments("commit")
-
- if opts.Author == nil {
- opts.Author = opts.Committer
- }
- if opts.Author != nil {
- cmd.AddOptionFormat("--author='%s <%s>'", opts.Author.Name, opts.Author.Email)
- }
- cmd.AddOptionFormat("--message=%s", opts.Message)
-
- _, _, err := cmd.WithDir(repoPath).RunStdString(ctx)
- // No stderr but exit status 1 means nothing to commit.
- if gitcmd.IsErrorExitCode(err, 1) {
- return nil
- }
- return err
-}
-
// CommitsByRange returns the specific page commits before current revision, every page's number default by CommitsRangeSize
func (c *Commit) CommitsByRange(page, pageSize int, not, since, until string) ([]*Commit, error) {
return c.repo.commitsByRangeWithTime(c.ID, page, pageSize, not, since, until)
diff --git a/modules/git/foreachref/format.go b/modules/git/foreachref/format.go
index d2f9998fe81..87c1c9a4ff9 100644
--- a/modules/git/foreachref/format.go
+++ b/modules/git/foreachref/format.go
@@ -53,7 +53,7 @@ func (f Format) Flag() string {
var formatFlag strings.Builder
for i, field := range f.fieldNames {
// field key and field value
- formatFlag.WriteString(fmt.Sprintf("%s %%(%s)", field, field))
+ fmt.Fprintf(&formatFlag, "%s %%(%s)", field, field)
if i < len(f.fieldNames)-1 {
// note: escape delimiters to allow control characters as
@@ -72,7 +72,7 @@ func (f Format) Parser(r io.Reader) *Parser {
return NewParser(r, f)
}
-// hexEscaped produces hex-escpaed characters from a string. For example, "\n\0"
+// hexEscaped produces hex-escaped characters from a string. For example, "\n\0"
// would turn into "%0a%00".
func (f Format) hexEscaped(delim []byte) string {
var escaped strings.Builder
diff --git a/modules/git/grep.go b/modules/git/grep.go
index 051a7a1d405..47f66b88b24 100644
--- a/modules/git/grep.go
+++ b/modules/git/grep.go
@@ -11,6 +11,7 @@ import (
"slices"
"strconv"
"strings"
+ "time"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/util"
@@ -39,6 +40,10 @@ type GrepOptions struct {
PathspecList []string
}
+// grepSearchTimeout is the timeout for git grep search, it should be long enough to get results
+// but not too long to cause performance issues
+const grepSearchTimeout = 30 * time.Second
+
func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepOptions) ([]*GrepResult, error) {
/*
The output is like this ( "^@" means \x00):
@@ -76,6 +81,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
stdoutReader, stdoutReaderClose := cmd.MakeStdoutPipe()
defer stdoutReaderClose()
err := cmd.WithDir(repo.Path).
+ WithTimeout(grepSearchTimeout).
WithPipelineFunc(func(ctx gitcmd.Context) error {
isInBlock := false
rd := bufio.NewReaderSize(stdoutReader, util.IfZero(opts.MaxLineLength, 16*1024))
diff --git a/modules/httpcache/httpcache.go b/modules/httpcache/httpcache.go
index dd3efab7a57..e23cf0a92a2 100644
--- a/modules/httpcache/httpcache.go
+++ b/modules/httpcache/httpcache.go
@@ -60,21 +60,6 @@ func CacheControlForPrivateStatic() *CacheControlOptions {
}
}
-// HandleGenericETagCache handles ETag-based caching for a HTTP request.
-// It returns true if the request was handled.
-func HandleGenericETagCache(req *http.Request, w http.ResponseWriter, etag string) (handled bool) {
- if len(etag) > 0 {
- w.Header().Set("Etag", etag)
- if checkIfNoneMatchIsValid(req, etag) {
- w.WriteHeader(http.StatusNotModified)
- return true
- }
- }
- // not sure whether it is a public content, so just use "private" (old behavior)
- SetCacheControlInHeader(w.Header(), CacheControlForPrivateStatic())
- return false
-}
-
// checkIfNoneMatchIsValid tests if the header If-None-Match matches the ETag
func checkIfNoneMatchIsValid(req *http.Request, etag string) bool {
ifNoneMatch := req.Header.Get("If-None-Match")
@@ -89,10 +74,18 @@ func checkIfNoneMatchIsValid(req *http.Request, etag string) bool {
return false
}
-// HandleGenericETagTimeCache handles ETag-based caching with Last-Modified caching for a HTTP request.
+func HandleGenericETagPublicCache(req *http.Request, w http.ResponseWriter, etag string, lastModified *time.Time) bool {
+ return handleGenericETagTimeCache(req, w, etag, lastModified, CacheControlForPublicStatic())
+}
+
+func HandleGenericETagPrivateCache(req *http.Request, w http.ResponseWriter, etag string, lastModified *time.Time) bool {
+ return handleGenericETagTimeCache(req, w, etag, lastModified, CacheControlForPrivateStatic())
+}
+
+// handleGenericETagTimeCache handles ETag-based caching with Last-Modified caching for the HTTP request.
// It returns true if the request was handled.
-func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag string, lastModified *time.Time) (handled bool) {
- if len(etag) > 0 {
+func handleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag string, lastModified *time.Time, cacheControlOpts *CacheControlOptions) (handled bool) {
+ if etag != "" {
w.Header().Set("Etag", etag)
}
if lastModified != nil && !lastModified.IsZero() {
@@ -100,7 +93,7 @@ func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag s
w.Header().Set("Last-Modified", lastModified.UTC().Format(http.TimeFormat))
}
- if len(etag) > 0 {
+ if etag != "" {
if checkIfNoneMatchIsValid(req, etag) {
w.WriteHeader(http.StatusNotModified)
return true
@@ -117,7 +110,6 @@ func HandleGenericETagTimeCache(req *http.Request, w http.ResponseWriter, etag s
}
}
- // not sure whether it is a public content, so just use "private" (old behavior)
- SetCacheControlInHeader(w.Header(), CacheControlForPrivateStatic())
+ SetCacheControlInHeader(w.Header(), cacheControlOpts)
return false
}
diff --git a/modules/httpcache/httpcache_test.go b/modules/httpcache/httpcache_test.go
index d81f06097c1..d510cbe4d7f 100644
--- a/modules/httpcache/httpcache_test.go
+++ b/modules/httpcache/httpcache_test.go
@@ -6,92 +6,73 @@ package httpcache
import (
"net/http"
"net/http/httptest"
- "strings"
"testing"
+ "time"
+
+ "code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
-func countFormalHeaders(h http.Header) (c int) {
- for k := range h {
- // ignore our headers for internal usage
- if strings.HasPrefix(k, "X-Gitea-") {
- continue
- }
- c++
- }
- return c
-}
-
func TestHandleGenericETagCache(t *testing.T) {
- etag := `"test"`
+ matchedEtag := `"matched-etag"`
+ lastModifiedTime := new(time.Date(2021, time.January, 2, 15, 4, 5, 0, time.FixedZone("test-zone", 8*3600)))
+ lastModified := lastModifiedTime.UTC().Format(http.TimeFormat)
+ cacheControl := "max-age=0, private, must-revalidate, no-transform"
+ type testCase struct {
+ name string
+ reqHeaders map[string]string
+ wantHandled bool
+ wantHeaders map[string]string
+ wantStatus int
+ }
+ cases := []testCase{
+ {
+ name: "No If-None-Match",
+ wantHandled: false,
+ wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
+ },
+ {
+ name: "Mismatched If-None-Match",
+ reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag"`},
+ wantHandled: false,
+ wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
+ },
+ {
+ name: "Matched If-None-Match",
+ reqHeaders: map[string]string{"If-None-Match": matchedEtag},
+ wantHandled: true,
+ wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": matchedEtag},
+ wantStatus: http.StatusNotModified,
+ },
+ {
+ name: "Multiple Mismatched If-None-Match",
+ reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag1", "mismatched-etag2"`},
+ wantHandled: false,
+ wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": cacheControl, "Etag": matchedEtag},
+ },
+ {
+ name: "Multiple Matched If-None-Match",
+ reqHeaders: map[string]string{"If-None-Match": `"mismatched-etag", ` + matchedEtag},
+ wantHandled: true,
+ wantHeaders: map[string]string{"Last-Modified": lastModified, "Cache-Control": "", "Etag": matchedEtag},
+ wantStatus: http.StatusNotModified,
+ },
+ }
- t.Run("No_If-None-Match", func(t *testing.T) {
- req := &http.Request{Header: make(http.Header)}
- w := httptest.NewRecorder()
-
- handled := HandleGenericETagCache(req, w, etag)
-
- assert.False(t, handled)
- assert.Equal(t, 2, countFormalHeaders(w.Header()))
- assert.Contains(t, w.Header(), "Cache-Control")
- assert.Contains(t, w.Header(), "Etag")
- assert.Equal(t, etag, w.Header().Get("Etag"))
- })
- t.Run("Wrong_If-None-Match", func(t *testing.T) {
- req := &http.Request{Header: make(http.Header)}
- w := httptest.NewRecorder()
-
- req.Header.Set("If-None-Match", `"wrong etag"`)
-
- handled := HandleGenericETagCache(req, w, etag)
-
- assert.False(t, handled)
- assert.Equal(t, 2, countFormalHeaders(w.Header()))
- assert.Contains(t, w.Header(), "Cache-Control")
- assert.Contains(t, w.Header(), "Etag")
- assert.Equal(t, etag, w.Header().Get("Etag"))
- })
- t.Run("Correct_If-None-Match", func(t *testing.T) {
- req := &http.Request{Header: make(http.Header)}
- w := httptest.NewRecorder()
-
- req.Header.Set("If-None-Match", etag)
-
- handled := HandleGenericETagCache(req, w, etag)
-
- assert.True(t, handled)
- assert.Equal(t, 1, countFormalHeaders(w.Header()))
- assert.Contains(t, w.Header(), "Etag")
- assert.Equal(t, etag, w.Header().Get("Etag"))
- assert.Equal(t, http.StatusNotModified, w.Code)
- })
- t.Run("Multiple_Wrong_If-None-Match", func(t *testing.T) {
- req := &http.Request{Header: make(http.Header)}
- w := httptest.NewRecorder()
-
- req.Header.Set("If-None-Match", `"wrong etag", "wrong etag "`)
-
- handled := HandleGenericETagCache(req, w, etag)
-
- assert.False(t, handled)
- assert.Equal(t, 2, countFormalHeaders(w.Header()))
- assert.Contains(t, w.Header(), "Cache-Control")
- assert.Contains(t, w.Header(), "Etag")
- assert.Equal(t, etag, w.Header().Get("Etag"))
- })
- t.Run("Multiple_Correct_If-None-Match", func(t *testing.T) {
- req := &http.Request{Header: make(http.Header)}
- w := httptest.NewRecorder()
-
- req.Header.Set("If-None-Match", `"wrong etag", `+etag)
-
- handled := HandleGenericETagCache(req, w, etag)
-
- assert.True(t, handled)
- assert.Equal(t, 1, countFormalHeaders(w.Header()))
- assert.Contains(t, w.Header(), "Etag")
- assert.Equal(t, etag, w.Header().Get("Etag"))
- assert.Equal(t, http.StatusNotModified, w.Code)
- })
+ for _, tc := range cases {
+ t.Run(tc.name, func(t *testing.T) {
+ req := httptest.NewRequest(http.MethodGet, "http://example.com/test", nil)
+ for k, v := range tc.reqHeaders {
+ req.Header.Set(k, v)
+ }
+ w := httptest.NewRecorder()
+ assert.Equal(t, tc.wantHandled, HandleGenericETagPrivateCache(req, w, matchedEtag, lastModifiedTime))
+ resp := w.Result()
+ for k, v := range tc.wantHeaders {
+ assert.Equal(t, v, resp.Header.Get(k))
+ }
+ assert.Equal(t, tc.wantStatus, util.Iif(resp.StatusCode == http.StatusOK, 0, resp.StatusCode))
+ })
+ }
}
diff --git a/modules/httplib/url.go b/modules/httplib/url.go
index 5f35e669643..a689c9e98ee 100644
--- a/modules/httplib/url.go
+++ b/modules/httplib/url.go
@@ -46,14 +46,14 @@ func IsRelativeURL(s string) bool {
func getRequestScheme(req *http.Request) string {
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
- if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
- return s
+ if proto, ok := parseForwardedProtoValue(req.Header.Get("X-Forwarded-Proto")); ok {
+ return proto
}
- if s := req.Header.Get("X-Forwarded-Protocol"); s != "" {
- return s
+ if proto, ok := parseForwardedProtoValue(req.Header.Get("X-Forwarded-Protocol")); ok {
+ return proto
}
- if s := req.Header.Get("X-Url-Scheme"); s != "" {
- return s
+ if proto, ok := parseForwardedProtoValue(req.Header.Get("X-Url-Scheme")); ok {
+ return proto
}
if s := req.Header.Get("Front-End-Https"); s != "" {
return util.Iif(s == "on", "https", "http")
@@ -64,6 +64,13 @@ func getRequestScheme(req *http.Request) string {
return ""
}
+func parseForwardedProtoValue(val string) (string, bool) {
+ if val == "http" || val == "https" {
+ return val, true
+ }
+ return "", false
+}
+
// GuessCurrentAppURL tries to guess the current full public URL (with sub-path) by http headers. It always has a '/' suffix, exactly the same as setting.AppURL
// TODO: should rename it to GuessCurrentPublicURL in the future
func GuessCurrentAppURL(ctx context.Context) string {
@@ -72,6 +79,10 @@ func GuessCurrentAppURL(ctx context.Context) string {
// GuessCurrentHostURL tries to guess the current full host URL (no sub-path) by http headers, there is no trailing slash.
func GuessCurrentHostURL(ctx context.Context) string {
+ // "never" means always trust ROOT_URL and skip any request header detection.
+ if setting.PublicURLDetection == setting.PublicURLNever {
+ return strings.TrimSuffix(setting.AppURL, setting.AppSubURL+"/")
+ }
// Try the best guess to get the current host URL (will be used for public URL) by http headers.
// At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong.
// There are some cases:
diff --git a/modules/httplib/url_test.go b/modules/httplib/url_test.go
index 4270d9fa895..373693693b5 100644
--- a/modules/httplib/url_test.go
+++ b/modules/httplib/url_test.go
@@ -47,6 +47,7 @@ func TestGuessCurrentHostURL(t *testing.T) {
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
headersWithProto := http.Header{"X-Forwarded-Proto": {"https"}}
+ maliciousProtoHeaders := http.Header{"X-Forwarded-Proto": {"http://attacker.host/?trash="}}
t.Run("Legacy", func(t *testing.T) {
defer test.MockVariableValue(&setting.PublicURLDetection, setting.PublicURLLegacy)()
@@ -60,6 +61,9 @@ func TestGuessCurrentHostURL(t *testing.T) {
// if "X-Forwarded-Proto" exists, then use it and "Host" header
ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto})
assert.Equal(t, "https://req-host:3000", GuessCurrentHostURL(ctx))
+
+ ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: maliciousProtoHeaders})
+ assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
})
t.Run("Auto", func(t *testing.T) {
@@ -76,6 +80,24 @@ func TestGuessCurrentHostURL(t *testing.T) {
ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto})
assert.Equal(t, "https://req-host:3000", GuessCurrentHostURL(ctx))
+
+ ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: maliciousProtoHeaders})
+ assert.Equal(t, "http://req-host:3000", GuessCurrentHostURL(ctx))
+ })
+
+ t.Run("Never", func(t *testing.T) {
+ defer test.MockVariableValue(&setting.PublicURLDetection, setting.PublicURLNever)()
+
+ assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(t.Context()))
+
+ ctx := context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000"})
+ assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
+
+ ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", TLS: &tls.ConnectionState{}})
+ assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
+
+ ctx = context.WithValue(t.Context(), RequestContextKey, &http.Request{Host: "req-host:3000", Header: headersWithProto})
+ assert.Equal(t, "http://cfg-host", GuessCurrentHostURL(ctx))
})
}
diff --git a/modules/indexer/code/elasticsearch/elasticsearch.go b/modules/indexer/code/elasticsearch/elasticsearch.go
index 99f974b646d..9d170528ad3 100644
--- a/modules/indexer/code/elasticsearch/elasticsearch.go
+++ b/modules/indexer/code/elasticsearch/elasticsearch.go
@@ -393,7 +393,7 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
elastic.NewHighlight().
Field("content").
Field("filename").
- NumOfFragments(0). // return all highting content on fragments
+ NumOfFragments(0). // return all highlighting content on fragments
HighlighterType("fvh"),
).
Sort("_score", false).
@@ -426,7 +426,7 @@ func (b *Indexer) Search(ctx context.Context, opts *internal.SearchOptions) (int
elastic.NewHighlight().
Field("content").
Field("filename").
- NumOfFragments(0). // return all highting content on fragments
+ NumOfFragments(0). // return all highlighting content on fragments
HighlighterType("fvh"),
).
Sort("_score", false).
diff --git a/modules/lfstransfer/backend/backend.go b/modules/lfstransfer/backend/backend.go
index f4e6157091a..92f08eac136 100644
--- a/modules/lfstransfer/backend/backend.go
+++ b/modules/lfstransfer/backend/backend.go
@@ -95,7 +95,7 @@ func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, args trans
var respBody lfs.BatchResponse
err = json.Unmarshal(respBytes, &respBody)
if err != nil {
- g.logger.Log("json umarshal error", err)
+ g.logger.Log("json unmarshal error", err)
return nil, err
}
diff --git a/modules/lfstransfer/backend/lock.go b/modules/lfstransfer/backend/lock.go
index 2c3c16a9bb0..5bfa3a89c30 100644
--- a/modules/lfstransfer/backend/lock.go
+++ b/modules/lfstransfer/backend/lock.go
@@ -69,7 +69,7 @@ func (g *giteaLockBackend) Create(path, refname string) (transfer.Lock, error) {
var respBody lfslock.LFSLockResponse
err = json.Unmarshal(respBytes, &respBody)
if err != nil {
- g.logger.Log("json umarshal error", err)
+ g.logger.Log("json unmarshal error", err)
return nil, err
}
@@ -202,7 +202,7 @@ func (g *giteaLockBackend) queryLocks(v url.Values) ([]transfer.Lock, string, er
var respBody lfslock.LFSLockList
err = json.Unmarshal(respBytes, &respBody)
if err != nil {
- g.logger.Log("json umarshal error", err)
+ g.logger.Log("json unmarshal error", err)
return nil, "", err
}
diff --git a/modules/lfstransfer/logger.go b/modules/lfstransfer/logger.go
index 517c2d9ba13..dfb9c0bb660 100644
--- a/modules/lfstransfer/logger.go
+++ b/modules/lfstransfer/logger.go
@@ -17,5 +17,5 @@ func newLogger() transfer.Logger {
}
// Log implements transfer.Logger
-func (g *GiteaLogger) Log(msg string, itms ...any) {
+func (g *GiteaLogger) Log(msg string, items ...any) {
}
diff --git a/modules/markup/common/linkify.go b/modules/markup/common/linkify.go
index 3eecb97eac1..aff1813803e 100644
--- a/modules/markup/common/linkify.go
+++ b/modules/markup/common/linkify.go
@@ -20,13 +20,13 @@ import (
)
type GlobalVarsType struct {
- wwwURLRegxp *regexp.Regexp
- LinkRegex *regexp.Regexp // fast matching a URL link, no any extra validation.
+ wwwURLRegexp *regexp.Regexp
+ LinkRegex *regexp.Regexp // fast matching a URL link, no any extra validation.
}
var GlobalVars = sync.OnceValue(func() *GlobalVarsType {
v := &GlobalVarsType{}
- v.wwwURLRegxp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}((?:/|[#?])[-a-zA-Z0-9@:%_\+.~#!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
+ v.wwwURLRegexp = regexp.MustCompile(`^www\.[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}((?:/|[#?])[-a-zA-Z0-9@:%_\+.~#!?&//=\(\);,'">\^{}\[\]` + "`" + `]*)?`)
v.LinkRegex, _ = xurls.StrictMatchingScheme("https?://")
return v
})
@@ -75,7 +75,7 @@ func (s *linkifyParser) Parse(parent ast.Node, block text.Reader, pc parser.Cont
m = GlobalVars().LinkRegex.FindSubmatchIndex(line)
}
if m == nil && bytes.HasPrefix(line, domainWWW) {
- m = GlobalVars().wwwURLRegxp.FindSubmatchIndex(line)
+ m = GlobalVars().wwwURLRegexp.FindSubmatchIndex(line)
protocol = []byte("http")
}
if m != nil {
diff --git a/modules/markup/sanitizer_default.go b/modules/markup/sanitizer_default.go
index 7fdf66c4bce..77ba8bf4f4c 100644
--- a/modules/markup/sanitizer_default.go
+++ b/modules/markup/sanitizer_default.go
@@ -81,7 +81,7 @@ func (st *Sanitizer) createDefaultPolicy() *bluemonday.Policy {
"data-markdown-generated-content", "data-attr-class",
}
generalSafeElements := []string{
- "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "i", "strong", "em", "a", "pre", "code", "img", "tt",
+ "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b", "center", "i", "strong", "em", "a", "pre", "code", "img", "tt",
"div", "ins", "del", "sup", "sub", "p", "ol", "ul", "table", "thead", "tbody", "tfoot", "blockquote", "label",
"dl", "dt", "dd", "kbd", "q", "samp", "var", "hr", "ruby", "rt", "rp", "li", "tr", "td", "th", "s", "strike", "summary",
"details", "caption", "figure", "figcaption",
diff --git a/modules/optional/option.go b/modules/optional/option.go
index cbecf869873..a278723bef2 100644
--- a/modules/optional/option.go
+++ b/modules/optional/option.go
@@ -67,3 +67,17 @@ func ParseBool(s string) Option[bool] {
}
return Some(v)
}
+
+func AssignPtrValue[T comparable](changed *bool, target, src *T) {
+ if src != nil && *src != *target {
+ *target = *src
+ *changed = true
+ }
+}
+
+func AssignPtrString[TO, FROM ~string](changed *bool, target *TO, src *FROM) {
+ if src != nil && string(*src) != string(*target) {
+ *target = TO(*src)
+ *changed = true
+ }
+}
diff --git a/modules/packages/cran/metadata.go b/modules/packages/cran/metadata.go
index 0b0bfb07c66..0856565e101 100644
--- a/modules/packages/cran/metadata.go
+++ b/modules/packages/cran/metadata.go
@@ -34,7 +34,7 @@ var (
var (
fieldPattern = regexp.MustCompile(`\A\S+:`)
namePattern = regexp.MustCompile(`\A[a-zA-Z][a-zA-Z0-9\.]*[a-zA-Z0-9]\z`)
- versionPattern = regexp.MustCompile(`\A[0-9]+(?:[.\-][0-9]+){1,3}\z`)
+ versionPattern = regexp.MustCompile(`\A[0-9]+(?:[.\-][0-9]+)+\z`)
authorReplacePattern = regexp.MustCompile(`[\[\(].+?[\]\)]`)
)
diff --git a/modules/packages/cran/metadata_test.go b/modules/packages/cran/metadata_test.go
index ff68c34c51a..1d652a4a058 100644
--- a/modules/packages/cran/metadata_test.go
+++ b/modules/packages/cran/metadata_test.go
@@ -128,13 +128,22 @@ func TestParseDescription(t *testing.T) {
})
t.Run("InvalidVersion", func(t *testing.T) {
- for _, version := range []string{"1", "1 0", "1.2.3.4.5", "1-2-3-4-5", "1.", "1.0.", "1-", "1-0-"} {
+ for _, version := range []string{"1", "1 0", "1.", "1.0.", "1-", "1-0-"} {
p, err := ParseDescription(createDescription(packageName, version))
assert.Nil(t, p)
assert.ErrorIs(t, err, ErrInvalidVersion)
}
})
+ t.Run("ValidVersionManyComponents", func(t *testing.T) {
+ for _, version := range []string{"0.3.4.0.2", "1.2.3.4.5", "1-2-3-4-5"} {
+ p, err := ParseDescription(createDescription(packageName, version))
+ assert.NoError(t, err)
+ assert.NotNil(t, p)
+ assert.Equal(t, version, p.Version)
+ }
+ })
+
t.Run("Valid", func(t *testing.T) {
p, err := ParseDescription(createDescription(packageName, packageVersion))
assert.NoError(t, err)
diff --git a/modules/setting/config.go b/modules/setting/config.go
index fb99325a956..a41734a843c 100644
--- a/modules/setting/config.go
+++ b/modules/setting/config.go
@@ -12,8 +12,8 @@ import (
)
type PictureStruct struct {
- DisableGravatar *config.Value[bool]
- EnableFederatedAvatar *config.Value[bool]
+ DisableGravatar *config.Option[bool]
+ EnableFederatedAvatar *config.Option[bool]
}
type OpenWithEditorApp struct {
@@ -23,6 +23,9 @@ type OpenWithEditorApp struct {
type OpenWithEditorAppsType []OpenWithEditorApp
+// ToTextareaString is only used in templates, for help prompt only
+// TODO: OPEN-WITH-EDITOR-APP-JSON: Because there is no "rich UI", a plain text editor is used to manage the list of apps
+// Maybe we can use some better formats like Yaml in the future, then a simple textarea can manage the config clearly
func (t OpenWithEditorAppsType) ToTextareaString() string {
var ret strings.Builder
for _, app := range t {
@@ -31,7 +34,7 @@ func (t OpenWithEditorAppsType) ToTextareaString() string {
return ret.String()
}
-func DefaultOpenWithEditorApps() OpenWithEditorAppsType {
+func openWithEditorAppsDefaultValue() OpenWithEditorAppsType {
return OpenWithEditorAppsType{
{
DisplayName: "VS Code",
@@ -49,13 +52,14 @@ func DefaultOpenWithEditorApps() OpenWithEditorAppsType {
}
type RepositoryStruct struct {
- OpenWithEditorApps *config.Value[OpenWithEditorAppsType]
- GitGuideRemoteName *config.Value[string]
+ OpenWithEditorApps *config.Option[OpenWithEditorAppsType]
+ GitGuideRemoteName *config.Option[string]
}
type ConfigStruct struct {
Picture *PictureStruct
Repository *RepositoryStruct
+ Instance *InstanceStruct
}
var (
@@ -67,12 +71,16 @@ func initDefaultConfig() {
config.SetCfgSecKeyGetter(&cfgSecKeyGetter{})
defaultConfig = &ConfigStruct{
Picture: &PictureStruct{
- DisableGravatar: config.ValueJSON[bool]("picture.disable_gravatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "DISABLE_GRAVATAR"}),
- EnableFederatedAvatar: config.ValueJSON[bool]("picture.enable_federated_avatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "ENABLE_FEDERATED_AVATAR"}),
+ DisableGravatar: config.NewOption[bool]("picture.disable_gravatar").WithDefaultSimple(true).WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "DISABLE_GRAVATAR"}),
+ EnableFederatedAvatar: config.NewOption[bool]("picture.enable_federated_avatar").WithFileConfig(config.CfgSecKey{Sec: "picture", Key: "ENABLE_FEDERATED_AVATAR"}),
},
Repository: &RepositoryStruct{
- OpenWithEditorApps: config.ValueJSON[OpenWithEditorAppsType]("repository.open-with.editor-apps"),
- GitGuideRemoteName: config.ValueJSON[string]("repository.git-guide-remote-name").WithDefault("origin"),
+ OpenWithEditorApps: config.NewOption[OpenWithEditorAppsType]("repository.open-with.editor-apps").WithEmptyAsDefault().WithDefaultFunc(openWithEditorAppsDefaultValue),
+ GitGuideRemoteName: config.NewOption[string]("repository.git-guide-remote-name").WithEmptyAsDefault().WithDefaultSimple("origin"),
+ },
+ Instance: &InstanceStruct{
+ WebBanner: config.NewOption[WebBannerType]("instance.web_banner"),
+ MaintenanceMode: config.NewOption[MaintenanceModeType]("instance.maintenance_mode"),
},
}
}
diff --git a/modules/setting/config/value.go b/modules/setting/config/value.go
index 301c60f5e82..c01f41303c6 100644
--- a/modules/setting/config/value.go
+++ b/modules/setting/config/value.go
@@ -5,6 +5,7 @@ package config
import (
"context"
+ "reflect"
"sync"
"code.gitea.io/gitea/modules/json"
@@ -16,18 +17,31 @@ type CfgSecKey struct {
Sec, Key string
}
-type Value[T any] struct {
+// OptionInterface is used to overcome Golang's generic interface limitation
+type OptionInterface interface {
+ GetDefaultValue() any
+}
+
+type Option[T any] struct {
mu sync.RWMutex
cfgSecKey CfgSecKey
dynKey string
- def, value T
+ value T
+ defSimple T
+ defFunc func() T
+ emptyAsDef bool
+ has bool
revision int
}
-func (value *Value[T]) parse(key, valStr string) (v T) {
- v = value.def
+func (opt *Option[T]) GetDefaultValue() any {
+ return opt.DefaultValue()
+}
+
+func (opt *Option[T]) parse(key, valStr string) (v T) {
+ v = opt.DefaultValue()
if valStr != "" {
if err := json.Unmarshal(util.UnsafeStringToBytes(valStr), &v); err != nil {
log.Error("Unable to unmarshal json config for key %q, err: %v", key, err)
@@ -36,7 +50,35 @@ func (value *Value[T]) parse(key, valStr string) (v T) {
return v
}
-func (value *Value[T]) Value(ctx context.Context) (v T) {
+func (opt *Option[T]) HasValue(ctx context.Context) bool {
+ _, _, has := opt.ValueRevision(ctx)
+ return has
+}
+
+func (opt *Option[T]) Value(ctx context.Context) (v T) {
+ v, _, _ = opt.ValueRevision(ctx)
+ return v
+}
+
+func isZeroOrEmpty(v any) bool {
+ if v == nil {
+ return true // interface itself is nil
+ }
+ r := reflect.ValueOf(v)
+ if r.IsZero() {
+ return true
+ }
+
+ if r.Kind() == reflect.Slice || r.Kind() == reflect.Map {
+ if r.IsNil() {
+ return true
+ }
+ return r.Len() == 0
+ }
+ return false
+}
+
+func (opt *Option[T]) ValueRevision(ctx context.Context) (v T, rev int, has bool) {
dg := GetDynGetter()
if dg == nil {
// this is an edge case: the database is not initialized but the system setting is going to be used
@@ -44,55 +86,96 @@ func (value *Value[T]) Value(ctx context.Context) (v T) {
panic("no config dyn value getter")
}
- rev := dg.GetRevision(ctx)
+ rev = dg.GetRevision(ctx)
// if the revision in the database doesn't change, use the last value
- value.mu.RLock()
- if rev == value.revision {
- v = value.value
- value.mu.RUnlock()
- return v
+ opt.mu.RLock()
+ if rev == opt.revision {
+ v = opt.value
+ has = opt.has
+ opt.mu.RUnlock()
+ return v, rev, has
}
- value.mu.RUnlock()
+ opt.mu.RUnlock()
// try to parse the config and cache it
var valStr *string
- if dynVal, has := dg.GetValue(ctx, value.dynKey); has {
+ if dynVal, hasDbValue := dg.GetValue(ctx, opt.dynKey); hasDbValue {
valStr = &dynVal
- } else if cfgVal, has := GetCfgSecKeyGetter().GetValue(value.cfgSecKey.Sec, value.cfgSecKey.Key); has {
+ } else if cfgVal, hasCfgValue := GetCfgSecKeyGetter().GetValue(opt.cfgSecKey.Sec, opt.cfgSecKey.Key); hasCfgValue {
valStr = &cfgVal
}
if valStr == nil {
- v = value.def
+ v = opt.DefaultValue()
+ has = false
} else {
- v = value.parse(value.dynKey, *valStr)
+ v = opt.parse(opt.dynKey, *valStr)
+ if opt.emptyAsDef && isZeroOrEmpty(v) {
+ v = opt.DefaultValue()
+ } else {
+ has = true
+ }
}
- value.mu.Lock()
- value.value = v
- value.revision = rev
- value.mu.Unlock()
+ opt.mu.Lock()
+ opt.value = v
+ opt.revision = rev
+ opt.has = has
+ opt.mu.Unlock()
+ return v, rev, has
+}
+
+func (opt *Option[T]) DynKey() string {
+ return opt.dynKey
+}
+
+// WithDefaultFunc sets the default value with a function
+// The "def" value might be changed during runtime (e.g.: Unmarshal with default), so it shouldn't use the same pointer or slice
+func (opt *Option[T]) WithDefaultFunc(f func() T) *Option[T] {
+ opt.defFunc = f
+ return opt
+}
+
+func (opt *Option[T]) WithDefaultSimple(def T) *Option[T] {
+ v := any(def)
+ switch v.(type) {
+ case string, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+ default:
+ // TODO: use reflect to support convertible basic types like `type State string`
+ r := reflect.ValueOf(v)
+ if r.Kind() != reflect.Struct {
+ panic("invalid type for default value, use WithDefaultFunc instead")
+ }
+ }
+ opt.defSimple = def
+ return opt
+}
+
+func (opt *Option[T]) WithEmptyAsDefault() *Option[T] {
+ opt.emptyAsDef = true
+ return opt
+}
+
+func (opt *Option[T]) DefaultValue() T {
+ if opt.defFunc != nil {
+ return opt.defFunc()
+ }
+ return opt.defSimple
+}
+
+func (opt *Option[T]) WithFileConfig(cfgSecKey CfgSecKey) *Option[T] {
+ opt.cfgSecKey = cfgSecKey
+ return opt
+}
+
+var allConfigOptions = map[string]OptionInterface{}
+
+func NewOption[T any](dynKey string) *Option[T] {
+ v := &Option[T]{dynKey: dynKey}
+ allConfigOptions[dynKey] = v
return v
}
-func (value *Value[T]) DynKey() string {
- return value.dynKey
-}
-
-func (value *Value[T]) WithDefault(def T) *Value[T] {
- value.def = def
- return value
-}
-
-func (value *Value[T]) DefaultValue() T {
- return value.def
-}
-
-func (value *Value[T]) WithFileConfig(cfgSecKey CfgSecKey) *Value[T] {
- value.cfgSecKey = cfgSecKey
- return value
-}
-
-func ValueJSON[T any](dynKey string) *Value[T] {
- return &Value[T]{dynKey: dynKey}
+func GetConfigOption(dynKey string) OptionInterface {
+ return allConfigOptions[dynKey]
}
diff --git a/modules/setting/config_option_instance.go b/modules/setting/config_option_instance.go
new file mode 100644
index 00000000000..6d97055a75e
--- /dev/null
+++ b/modules/setting/config_option_instance.go
@@ -0,0 +1,58 @@
+// Copyright 2026 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "time"
+
+ "code.gitea.io/gitea/modules/setting/config"
+)
+
+// WebBannerType fields are directly used in templates,
+// do remember to update the template if you change the fields
+type WebBannerType struct {
+ DisplayEnabled bool
+ ContentMessage string
+ StartTimeUnix int64
+ EndTimeUnix int64
+}
+
+func (b WebBannerType) ShouldDisplay() bool {
+ if !b.DisplayEnabled || b.ContentMessage == "" {
+ return false
+ }
+ now := time.Now().Unix()
+ if b.StartTimeUnix > 0 && now < b.StartTimeUnix {
+ return false
+ }
+ if b.EndTimeUnix > 0 && now > b.EndTimeUnix {
+ return false
+ }
+ return true
+}
+
+type MaintenanceModeType struct {
+ AdminWebAccessOnly bool
+ StartTimeUnix int64
+ EndTimeUnix int64
+}
+
+func (m MaintenanceModeType) IsActive() bool {
+ if !m.AdminWebAccessOnly {
+ return false
+ }
+ now := time.Now().Unix()
+ if m.StartTimeUnix > 0 && now < m.StartTimeUnix {
+ return false
+ }
+ if m.EndTimeUnix > 0 && now > m.EndTimeUnix {
+ return false
+ }
+ return true
+}
+
+type InstanceStruct struct {
+ WebBanner *config.Option[WebBannerType]
+ MaintenanceMode *config.Option[MaintenanceModeType]
+}
diff --git a/modules/setting/picture.go b/modules/setting/picture.go
index fafae45baba..d20a110b6c4 100644
--- a/modules/setting/picture.go
+++ b/modules/setting/picture.go
@@ -22,9 +22,7 @@ var (
RenderedSizeFactor: 2,
}
- GravatarSource string
- DisableGravatar bool // Depreciated: migrated to database
- EnableFederatedAvatar bool // Depreciated: migrated to database
+ GravatarSource string
RepoAvatar = struct {
Storage *Storage
@@ -65,29 +63,12 @@ func loadAvatarsFrom(rootCfg ConfigProvider) error {
GravatarSource = source
}
- DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool(GetDefaultDisableGravatar())
- deprecatedSettingDB(rootCfg, "", "DISABLE_GRAVATAR")
- EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool(GetDefaultEnableFederatedAvatar(DisableGravatar))
- deprecatedSettingDB(rootCfg, "", "ENABLE_FEDERATED_AVATAR")
+ deprecatedSettingDB(rootCfg, "picture", "DISABLE_GRAVATAR")
+ deprecatedSettingDB(rootCfg, "picture", "ENABLE_FEDERATED_AVATAR")
return nil
}
-func GetDefaultDisableGravatar() bool {
- return OfflineMode
-}
-
-func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool {
- v := !InstallLock
- if OfflineMode {
- v = false
- }
- if disableGravatar {
- v = false
- }
- return v
-}
-
func loadRepoAvatarFrom(rootCfg ConfigProvider) error {
sec := rootCfg.Section("picture")
diff --git a/modules/setting/server.go b/modules/setting/server.go
index a865e942a62..50a38f544ba 100644
--- a/modules/setting/server.go
+++ b/modules/setting/server.go
@@ -44,6 +44,7 @@ const (
const (
PublicURLAuto = "auto"
PublicURLLegacy = "legacy"
+ PublicURLNever = "never"
)
// Server settings
@@ -91,7 +92,6 @@ var (
RedirectOtherPort bool
RedirectorUseProxyProtocol bool
PortToRedirect string
- OfflineMode bool
CertFile string
KeyFile string
StaticRootPath string
@@ -287,7 +287,7 @@ func loadServerFrom(rootCfg ConfigProvider) {
defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort
AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL)
PublicURLDetection = sec.Key("PUBLIC_URL_DETECTION").MustString(PublicURLLegacy)
- if PublicURLDetection != PublicURLAuto && PublicURLDetection != PublicURLLegacy {
+ if PublicURLDetection != PublicURLAuto && PublicURLDetection != PublicURLLegacy && PublicURLDetection != PublicURLNever {
log.Fatal("Invalid PUBLIC_URL_DETECTION value: %s", PublicURLDetection)
}
@@ -346,7 +346,6 @@ func loadServerFrom(rootCfg ConfigProvider) {
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
RedirectorUseProxyProtocol = sec.Key("REDIRECTOR_USE_PROXY_PROTOCOL").MustBool(UseProxyProtocol)
- OfflineMode = sec.Key("OFFLINE_MODE").MustBool(true)
if len(StaticRootPath) == 0 {
StaticRootPath = AppWorkPath
}
diff --git a/modules/setting/ui.go b/modules/setting/ui.go
index 77a5b45d0a0..722341a71ea 100644
--- a/modules/setting/ui.go
+++ b/modules/setting/ui.go
@@ -25,7 +25,6 @@ var UI = struct {
ReactionMaxUserNum int
MaxDisplayFileSize int64
ShowUserEmail bool
- DefaultShowFullName bool
DefaultTheme string
Themes []string
FileIconTheme string
@@ -43,6 +42,15 @@ var UI = struct {
AmbiguousUnicodeDetection bool
+ // TODO: DefaultShowFullName is introduced by https://github.com/go-gitea/gitea/pull/6710
+ // But there are still many edge cases:
+ // * Many places still use "username", not respecting this setting
+ // * Many places use "Full Name" if it is not empty, cause inconsistent UI for users who have set their full name but some others don't
+ // * Even if DefaultShowFullName=false, many places still need to show the full name
+ // For most cases, either "username" or "username (Full Name)" should be used and are good enough.
+ // Only in very few cases (e.g.: unimportant lists, narrow layout), "username" or "Full Name" can be used.
+ DefaultShowFullName bool
+
Notification struct {
MinTimeout time.Duration
TimeoutStep time.Duration
diff --git a/modules/storage/local.go b/modules/storage/local.go
index 8a1776f606d..5ea6f055ce7 100644
--- a/modules/storage/local.go
+++ b/modules/storage/local.go
@@ -5,6 +5,7 @@ package storage
import (
"context"
+ "errors"
"fmt"
"io"
"net/url"
@@ -27,25 +28,32 @@ type LocalStorage struct {
// NewLocalStorage returns a local files
func NewLocalStorage(ctx context.Context, config *setting.Storage) (ObjectStorage, error) {
+ // prepare storage root path
if !filepath.IsAbs(config.Path) {
- return nil, fmt.Errorf("LocalStorageConfig.Path should have been prepared by setting/storage.go and should be an absolute path, but not: %q", config.Path)
- }
- log.Info("Creating new Local Storage at %s", config.Path)
- if err := os.MkdirAll(config.Path, os.ModePerm); err != nil {
- return nil, err
+ return nil, fmt.Errorf("LocalStorage config.Path should have been prepared by setting/storage.go and should be an absolute path, but not: %q", config.Path)
}
+ storageRoot := util.FilePathJoinAbs(config.Path)
- if config.TemporaryPath == "" {
- config.TemporaryPath = filepath.Join(config.Path, "tmp")
+ // prepare storage temporary path
+ storageTmp := config.TemporaryPath
+ if storageTmp == "" {
+ storageTmp = filepath.Join(storageRoot, "tmp")
}
- if !filepath.IsAbs(config.TemporaryPath) {
- return nil, fmt.Errorf("LocalStorageConfig.TemporaryPath should be an absolute path, but not: %q", config.TemporaryPath)
+ if !filepath.IsAbs(storageTmp) {
+ return nil, fmt.Errorf("LocalStorage config.TemporaryPath should be an absolute path, but not: %q", config.TemporaryPath)
+ }
+ storageTmp = util.FilePathJoinAbs(storageTmp)
+
+ // create the storage root if not exist
+ log.Info("Creating new Local Storage at %s", storageRoot)
+ if err := os.MkdirAll(storageRoot, os.ModePerm); err != nil {
+ return nil, err
}
return &LocalStorage{
ctx: ctx,
- dir: config.Path,
- tmpdir: config.TemporaryPath,
+ dir: storageRoot,
+ tmpdir: storageTmp,
}, nil
}
@@ -108,9 +116,21 @@ func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
return os.Stat(l.buildLocalPath(path))
}
-// Delete delete a file
+func (l *LocalStorage) deleteEmptyParentDirs(localFullPath string) {
+ for parent := filepath.Dir(localFullPath); len(parent) > len(l.dir); parent = filepath.Dir(parent) {
+ if err := os.Remove(parent); err != nil {
+ // since the target file has been deleted, parent dir error is not related to the file deletion itself.
+ break
+ }
+ }
+}
+
+// Delete deletes the file in storage and removes the empty parent directories (if possible)
func (l *LocalStorage) Delete(path string) error {
- return util.Remove(l.buildLocalPath(path))
+ localFullPath := l.buildLocalPath(path)
+ err := util.Remove(localFullPath)
+ l.deleteEmptyParentDirs(localFullPath)
+ return err
}
// URL gets the redirect URL to a file
@@ -118,34 +138,38 @@ func (l *LocalStorage) URL(path, name, _ string, reqParams url.Values) (*url.URL
return nil, ErrURLNotSupported
}
+func (l *LocalStorage) normalizeWalkError(err error) error {
+ if errors.Is(err, os.ErrNotExist) {
+ // ignore it because the file may be deleted during the walk, and we don't care about it
+ return nil
+ }
+ return err
+}
+
// IterateObjects iterates across the objects in the local storage
func (l *LocalStorage) IterateObjects(dirName string, fn func(path string, obj Object) error) error {
dir := l.buildLocalPath(dirName)
- return filepath.WalkDir(dir, func(path string, d os.DirEntry, err error) error {
- if err != nil {
+ return filepath.WalkDir(dir, func(path string, d os.DirEntry, errWalk error) error {
+ if err := l.ctx.Err(); err != nil {
return err
}
- select {
- case <-l.ctx.Done():
- return l.ctx.Err()
- default:
+ if errWalk != nil {
+ return l.normalizeWalkError(errWalk)
}
- if path == l.dir {
- return nil
- }
- if d.IsDir() {
+ if path == l.dir || d.IsDir() {
return nil
}
+
relPath, err := filepath.Rel(l.dir, path)
if err != nil {
- return err
+ return l.normalizeWalkError(err)
}
obj, err := os.Open(path)
if err != nil {
- return err
+ return l.normalizeWalkError(err)
}
defer obj.Close()
- return fn(relPath, obj)
+ return fn(filepath.ToSlash(relPath), obj)
})
}
diff --git a/modules/storage/local_test.go b/modules/storage/local_test.go
index 0592fd716ba..29c13539d0e 100644
--- a/modules/storage/local_test.go
+++ b/modules/storage/local_test.go
@@ -4,11 +4,14 @@
package storage
import (
+ "os"
+ "strings"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func TestBuildLocalPath(t *testing.T) {
@@ -53,6 +56,49 @@ func TestBuildLocalPath(t *testing.T) {
}
}
+func TestLocalStorageDelete(t *testing.T) {
+ rootDir := t.TempDir()
+ st, err := NewLocalStorage(t.Context(), &setting.Storage{Path: rootDir})
+ require.NoError(t, err)
+
+ assertExists := func(t *testing.T, path string, exists bool) {
+ _, err = os.Stat(rootDir + "/" + path)
+ if exists {
+ require.NoError(t, err)
+ } else {
+ require.ErrorIs(t, err, os.ErrNotExist)
+ }
+ }
+
+ _, err = st.Save("dir/sub1/1-a.txt", strings.NewReader(""), -1)
+ require.NoError(t, err)
+ _, err = st.Save("dir/sub1/1-b.txt", strings.NewReader(""), -1)
+ require.NoError(t, err)
+ _, err = st.Save("dir/sub2/2-a.txt", strings.NewReader(""), -1)
+ require.NoError(t, err)
+
+ assertExists(t, "dir/sub1/1-a.txt", true)
+ assertExists(t, "dir/sub1/1-b.txt", true)
+ assertExists(t, "dir/sub2/2-a.txt", true)
+
+ require.NoError(t, st.Delete("dir/sub1/1-a.txt"))
+ assertExists(t, "dir/sub1", true)
+ assertExists(t, "dir/sub1/1-a.txt", false)
+ assertExists(t, "dir/sub1/1-b.txt", true)
+ assertExists(t, "dir/sub2/2-a.txt", true)
+
+ require.NoError(t, st.Delete("dir/sub1/1-b.txt"))
+ assertExists(t, ".", true)
+ assertExists(t, "dir/sub1", false)
+ assertExists(t, "dir/sub1/1-a.txt", false)
+ assertExists(t, "dir/sub1/1-b.txt", false)
+ assertExists(t, "dir/sub2/2-a.txt", true)
+
+ require.NoError(t, st.Delete("dir/sub2/2-a.txt"))
+ assertExists(t, ".", true)
+ assertExists(t, "dir", false)
+}
+
func TestLocalStorageIterator(t *testing.T) {
testStorageIterator(t, setting.LocalStorageType, &setting.Storage{Path: t.TempDir()})
}
diff --git a/modules/storage/storage.go b/modules/storage/storage.go
index 1868817c057..74d0cd47c87 100644
--- a/modules/storage/storage.go
+++ b/modules/storage/storage.go
@@ -68,7 +68,12 @@ type ObjectStorage interface {
Stat(path string) (os.FileInfo, error)
Delete(path string) error
URL(path, name, method string, reqParams url.Values) (*url.URL, error)
- IterateObjects(path string, iterator func(path string, obj Object) error) error
+
+ // IterateObjects calls the iterator function for each object in the storage with the given path as prefix
+ // The "fullPath" argument in callback is the full path in this storage.
+ // * IterateObjects("", ...): iterate all objects in this storage
+ // * IterateObjects("sub-path", ...): iterate all objects with "sub-path" as prefix in this storage, the "fullPath" will be like "sub-path/xxx"
+ IterateObjects(basePath string, iterator func(fullPath string, obj Object) error) error
}
// Copy copies a file from source ObjectStorage to dest ObjectStorage
diff --git a/modules/structs/activitypub.go b/modules/structs/activitypub.go
deleted file mode 100644
index 39a6c1ac2ac..00000000000
--- a/modules/structs/activitypub.go
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package structs
-
-// ActivityPub type
-type ActivityPub struct {
- // Context defines the JSON-LD context for ActivityPub
- Context string `json:"@context"`
-}
diff --git a/modules/structs/repo.go b/modules/structs/repo.go
index a08cf360371..3507cc410a1 100644
--- a/modules/structs/repo.go
+++ b/modules/structs/repo.go
@@ -73,6 +73,7 @@ type Repository struct {
Stars int `json:"stars_count"`
Forks int `json:"forks_count"`
Watchers int `json:"watchers_count"`
+ BranchCount int `json:"branch_count"`
OpenIssues int `json:"open_issues_count"`
OpenPulls int `json:"open_pr_counter"`
Releases int `json:"release_counter"`
diff --git a/modules/structs/repo_actions.go b/modules/structs/repo_actions.go
index b491d6ccce0..86bf4959d18 100644
--- a/modules/structs/repo_actions.go
+++ b/modules/structs/repo_actions.go
@@ -205,3 +205,10 @@ type ActionRunnersResponse struct {
Entries []*ActionRunner `json:"runners"`
TotalCount int64 `json:"total_count"`
}
+
+// RunDetails returns workflow_dispatch runid and url
+type RunDetails struct {
+ WorkflowRunID int64 `json:"workflow_run_id"`
+ RunURL string `json:"run_url"`
+ HTMLURL string `json:"html_url"`
+}
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index 11c52bd5a7f..82087568dfd 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -96,9 +96,6 @@ func NewFuncMap() template.FuncMap {
"AssetVersion": func() string {
return setting.AssetVersion
},
- "DefaultShowFullName": func() bool {
- return setting.UI.DefaultShowFullName
- },
"ShowFooterTemplateLoadTime": func() bool {
return setting.Other.ShowFooterTemplateLoadTime
},
diff --git a/modules/templates/util_avatar.go b/modules/templates/util_avatar.go
index ee9994ab0b8..524c64d0b6e 100644
--- a/modules/templates/util_avatar.go
+++ b/modules/templates/util_avatar.go
@@ -16,6 +16,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
gitea_html "code.gitea.io/gitea/modules/htmlutil"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/util"
)
type AvatarUtils struct {
@@ -29,13 +30,9 @@ func NewAvatarUtils(ctx context.Context) *AvatarUtils {
// AvatarHTML creates the HTML for an avatar
func AvatarHTML(src string, size int, class, name string) template.HTML {
sizeStr := strconv.Itoa(size)
-
- if name == "" {
- name = "avatar"
- }
-
+ name = util.IfZero(name, "avatar")
// use empty alt, otherwise if the image fails to load, the width will follow the "alt" text's width
- return template.HTML(``)
+ return template.HTML(`
`)
}
// Avatar renders user avatars. args: user, size (int), class (string)
diff --git a/modules/util/path.go b/modules/util/path.go
index 48447d7b905..baed03b443c 100644
--- a/modules/util/path.go
+++ b/modules/util/path.go
@@ -75,19 +75,21 @@ const filepathSeparator = string(os.PathSeparator)
// {`/foo`, ``, `bar`} => `/foo/bar`
// {`/foo`, `..`, `bar`} => `/foo/bar`
func FilePathJoinAbs(base string, sub ...string) string {
- elems := make([]string, 1, len(sub)+1)
-
// POSIX filesystem can have `\` in file names. Windows: `\` and `/` are both used for path separators
// to keep the behavior consistent, we do not allow `\` in file names, replace all `\` with `/`
- if isOSWindows() {
- elems[0] = filepath.Clean(base)
- } else {
- elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", filepathSeparator))
+ if !isOSWindows() {
+ base = strings.ReplaceAll(base, "\\", filepathSeparator)
}
- if !filepath.IsAbs(elems[0]) {
- // This shouldn't happen. If there is really necessary to pass in relative path, return the full path with filepath.Abs() instead
- panic(fmt.Sprintf("FilePathJoinAbs: %q (for path %v) is not absolute, do not guess a relative path based on current working directory", elems[0], elems))
+ if !filepath.IsAbs(base) {
+ // This shouldn't happen. If it is really necessary to handle relative paths, use filepath.Abs() to get absolute paths first
+ panic(fmt.Sprintf("FilePathJoinAbs: %q (for path %v) is not absolute, do not guess a relative path based on current working directory", base, sub))
}
+ if len(sub) == 0 {
+ return filepath.Clean(base)
+ }
+
+ elems := make([]string, 1, len(sub)+1)
+ elems[0] = base
for _, s := range sub {
if s == "" {
continue
@@ -98,7 +100,7 @@ func FilePathJoinAbs(base string, sub ...string) string {
elems = append(elems, filepath.Clean(filepathSeparator+strings.ReplaceAll(s, "\\", filepathSeparator)))
}
}
- // the elems[0] must be an absolute path, just join them together
+ // the elems[0] must be an absolute path, just join them together, and Join will also do Clean
return filepath.Join(elems...)
}
diff --git a/modules/web/middleware/cookie.go b/modules/web/middleware/cookie.go
index f98aceba101..336c276fe8f 100644
--- a/modules/web/middleware/cookie.go
+++ b/modules/web/middleware/cookie.go
@@ -14,7 +14,11 @@ import (
"code.gitea.io/gitea/modules/util"
)
-const cookieRedirectTo = "redirect_to"
+const (
+ CookieWebBannerDismissed = "gitea_disbnr"
+ CookieTheme = "gitea_theme"
+ cookieRedirectTo = "redirect_to"
+)
func GetRedirectToCookie(req *http.Request) string {
return GetSiteCookie(req, cookieRedirectTo)
diff --git a/options/fileicon/material-icon-rules.json b/options/fileicon/material-icon-rules.json
index 8ee5dde0b2e..9163732315d 100644
--- a/options/fileicon/material-icon-rules.json
+++ b/options/fileicon/material-icon-rules.json
@@ -3,7155 +3,9041 @@
"rust": "folder-rust",
".rust": "folder-rust",
"_rust": "folder-rust",
+ "-rust": "folder-rust",
"__rust__": "folder-rust",
"bot": "folder-robot",
".bot": "folder-robot",
"_bot": "folder-robot",
+ "-bot": "folder-robot",
"__bot__": "folder-robot",
"bots": "folder-robot",
".bots": "folder-robot",
"_bots": "folder-robot",
+ "-bots": "folder-robot",
"__bots__": "folder-robot",
"robot": "folder-robot",
".robot": "folder-robot",
"_robot": "folder-robot",
+ "-robot": "folder-robot",
"__robot__": "folder-robot",
"robots": "folder-robot",
".robots": "folder-robot",
"_robots": "folder-robot",
+ "-robots": "folder-robot",
"__robots__": "folder-robot",
+ "agent": "folder-robot",
+ ".agent": "folder-robot",
+ "_agent": "folder-robot",
+ "-agent": "folder-robot",
+ "__agent__": "folder-robot",
+ "agents": "folder-robot",
+ ".agents": "folder-robot",
+ "_agents": "folder-robot",
+ "-agents": "folder-robot",
+ "__agents__": "folder-robot",
"src": "folder-src",
".src": "folder-src",
"_src": "folder-src",
+ "-src": "folder-src",
"__src__": "folder-src",
"srcs": "folder-src",
".srcs": "folder-src",
"_srcs": "folder-src",
+ "-srcs": "folder-src",
"__srcs__": "folder-src",
"source": "folder-src",
".source": "folder-src",
"_source": "folder-src",
+ "-source": "folder-src",
"__source__": "folder-src",
"sources": "folder-src",
".sources": "folder-src",
"_sources": "folder-src",
+ "-sources": "folder-src",
"__sources__": "folder-src",
"code": "folder-src",
".code": "folder-src",
"_code": "folder-src",
+ "-code": "folder-src",
"__code__": "folder-src",
"dist": "folder-dist",
".dist": "folder-dist",
"_dist": "folder-dist",
+ "-dist": "folder-dist",
"__dist__": "folder-dist",
"out": "folder-dist",
".out": "folder-dist",
"_out": "folder-dist",
+ "-out": "folder-dist",
"__out__": "folder-dist",
"output": "folder-dist",
".output": "folder-dist",
"_output": "folder-dist",
+ "-output": "folder-dist",
"__output__": "folder-dist",
+ "outputs": "folder-dist",
+ ".outputs": "folder-dist",
+ "_outputs": "folder-dist",
+ "-outputs": "folder-dist",
+ "__outputs__": "folder-dist",
"build": "folder-dist",
".build": "folder-dist",
"_build": "folder-dist",
+ "-build": "folder-dist",
"__build__": "folder-dist",
"builds": "folder-dist",
".builds": "folder-dist",
"_builds": "folder-dist",
+ "-builds": "folder-dist",
"__builds__": "folder-dist",
"release": "folder-dist",
".release": "folder-dist",
"_release": "folder-dist",
+ "-release": "folder-dist",
"__release__": "folder-dist",
"bin": "folder-dist",
".bin": "folder-dist",
"_bin": "folder-dist",
+ "-bin": "folder-dist",
"__bin__": "folder-dist",
"distribution": "folder-dist",
".distribution": "folder-dist",
"_distribution": "folder-dist",
+ "-distribution": "folder-dist",
"__distribution__": "folder-dist",
"built": "folder-dist",
".built": "folder-dist",
"_built": "folder-dist",
+ "-built": "folder-dist",
"__built__": "folder-dist",
"compiled": "folder-dist",
".compiled": "folder-dist",
"_compiled": "folder-dist",
+ "-compiled": "folder-dist",
"__compiled__": "folder-dist",
"css": "folder-css",
".css": "folder-css",
"_css": "folder-css",
+ "-css": "folder-css",
"__css__": "folder-css",
"stylesheet": "folder-css",
".stylesheet": "folder-css",
"_stylesheet": "folder-css",
+ "-stylesheet": "folder-css",
"__stylesheet__": "folder-css",
"stylesheets": "folder-css",
".stylesheets": "folder-css",
"_stylesheets": "folder-css",
+ "-stylesheets": "folder-css",
"__stylesheets__": "folder-css",
"style": "folder-css",
".style": "folder-css",
"_style": "folder-css",
+ "-style": "folder-css",
"__style__": "folder-css",
"styles": "folder-css",
".styles": "folder-css",
"_styles": "folder-css",
+ "-styles": "folder-css",
"__styles__": "folder-css",
"sass": "folder-sass",
".sass": "folder-sass",
"_sass": "folder-sass",
+ "-sass": "folder-sass",
"__sass__": "folder-sass",
"scss": "folder-sass",
".scss": "folder-sass",
"_scss": "folder-sass",
+ "-scss": "folder-sass",
"__scss__": "folder-sass",
"tv": "folder-television",
".tv": "folder-television",
"_tv": "folder-television",
+ "-tv": "folder-television",
"__tv__": "folder-television",
"television": "folder-television",
".television": "folder-television",
"_television": "folder-television",
+ "-television": "folder-television",
"__television__": "folder-television",
"desktop": "folder-desktop",
".desktop": "folder-desktop",
"_desktop": "folder-desktop",
+ "-desktop": "folder-desktop",
"__desktop__": "folder-desktop",
"display": "folder-desktop",
".display": "folder-desktop",
"_display": "folder-desktop",
+ "-display": "folder-desktop",
"__display__": "folder-desktop",
"console": "folder-console",
".console": "folder-console",
"_console": "folder-console",
+ "-console": "folder-console",
"__console__": "folder-console",
"xbox": "folder-console",
".xbox": "folder-console",
"_xbox": "folder-console",
+ "-xbox": "folder-console",
"__xbox__": "folder-console",
"ps4": "folder-console",
".ps4": "folder-console",
"_ps4": "folder-console",
+ "-ps4": "folder-console",
"__ps4__": "folder-console",
"ps5": "folder-console",
".ps5": "folder-console",
"_ps5": "folder-console",
+ "-ps5": "folder-console",
"__ps5__": "folder-console",
"switch": "folder-console",
".switch": "folder-console",
"_switch": "folder-console",
+ "-switch": "folder-console",
"__switch__": "folder-console",
"game": "folder-console",
".game": "folder-console",
"_game": "folder-console",
+ "-game": "folder-console",
"__game__": "folder-console",
"games": "folder-console",
".games": "folder-console",
"_games": "folder-console",
+ "-games": "folder-console",
"__games__": "folder-console",
"images": "folder-images",
".images": "folder-images",
"_images": "folder-images",
+ "-images": "folder-images",
"__images__": "folder-images",
"image": "folder-images",
".image": "folder-images",
"_image": "folder-images",
+ "-image": "folder-images",
"__image__": "folder-images",
"imgs": "folder-images",
".imgs": "folder-images",
"_imgs": "folder-images",
+ "-imgs": "folder-images",
"__imgs__": "folder-images",
"img": "folder-images",
".img": "folder-images",
"_img": "folder-images",
+ "-img": "folder-images",
"__img__": "folder-images",
"icons": "folder-images",
".icons": "folder-images",
"_icons": "folder-images",
+ "-icons": "folder-images",
"__icons__": "folder-images",
"icon": "folder-images",
".icon": "folder-images",
"_icon": "folder-images",
+ "-icon": "folder-images",
"__icon__": "folder-images",
"icos": "folder-images",
".icos": "folder-images",
"_icos": "folder-images",
+ "-icos": "folder-images",
"__icos__": "folder-images",
"ico": "folder-images",
".ico": "folder-images",
"_ico": "folder-images",
+ "-ico": "folder-images",
"__ico__": "folder-images",
"figures": "folder-images",
".figures": "folder-images",
"_figures": "folder-images",
+ "-figures": "folder-images",
"__figures__": "folder-images",
"figure": "folder-images",
".figure": "folder-images",
"_figure": "folder-images",
+ "-figure": "folder-images",
"__figure__": "folder-images",
"figs": "folder-images",
".figs": "folder-images",
"_figs": "folder-images",
+ "-figs": "folder-images",
"__figs__": "folder-images",
"fig": "folder-images",
".fig": "folder-images",
"_fig": "folder-images",
+ "-fig": "folder-images",
"__fig__": "folder-images",
"screenshot": "folder-images",
".screenshot": "folder-images",
"_screenshot": "folder-images",
+ "-screenshot": "folder-images",
"__screenshot__": "folder-images",
"screenshots": "folder-images",
".screenshots": "folder-images",
"_screenshots": "folder-images",
+ "-screenshots": "folder-images",
"__screenshots__": "folder-images",
"screengrab": "folder-images",
".screengrab": "folder-images",
"_screengrab": "folder-images",
+ "-screengrab": "folder-images",
"__screengrab__": "folder-images",
"screengrabs": "folder-images",
".screengrabs": "folder-images",
"_screengrabs": "folder-images",
+ "-screengrabs": "folder-images",
"__screengrabs__": "folder-images",
"pic": "folder-images",
".pic": "folder-images",
"_pic": "folder-images",
+ "-pic": "folder-images",
"__pic__": "folder-images",
"pics": "folder-images",
".pics": "folder-images",
"_pics": "folder-images",
+ "-pics": "folder-images",
"__pics__": "folder-images",
"picture": "folder-images",
".picture": "folder-images",
"_picture": "folder-images",
+ "-picture": "folder-images",
"__picture__": "folder-images",
"pictures": "folder-images",
".pictures": "folder-images",
"_pictures": "folder-images",
+ "-pictures": "folder-images",
"__pictures__": "folder-images",
"photo": "folder-images",
".photo": "folder-images",
"_photo": "folder-images",
+ "-photo": "folder-images",
"__photo__": "folder-images",
"photos": "folder-images",
".photos": "folder-images",
"_photos": "folder-images",
+ "-photos": "folder-images",
"__photos__": "folder-images",
"photograph": "folder-images",
".photograph": "folder-images",
"_photograph": "folder-images",
+ "-photograph": "folder-images",
"__photograph__": "folder-images",
"photographs": "folder-images",
".photographs": "folder-images",
"_photographs": "folder-images",
+ "-photographs": "folder-images",
"__photographs__": "folder-images",
"texture": "folder-images",
".texture": "folder-images",
"_texture": "folder-images",
+ "-texture": "folder-images",
"__texture__": "folder-images",
"textures": "folder-images",
".textures": "folder-images",
"_textures": "folder-images",
+ "-textures": "folder-images",
"__textures__": "folder-images",
"script": "folder-scripts",
".script": "folder-scripts",
"_script": "folder-scripts",
+ "-script": "folder-scripts",
"__script__": "folder-scripts",
"scripts": "folder-scripts",
".scripts": "folder-scripts",
"_scripts": "folder-scripts",
+ "-scripts": "folder-scripts",
"__scripts__": "folder-scripts",
"scripting": "folder-scripts",
".scripting": "folder-scripts",
"_scripting": "folder-scripts",
+ "-scripting": "folder-scripts",
"__scripting__": "folder-scripts",
"node": "folder-node",
".node": "folder-node",
"_node": "folder-node",
+ "-node": "folder-node",
"__node__": "folder-node",
"nodejs": "folder-node",
".nodejs": "folder-node",
"_nodejs": "folder-node",
+ "-nodejs": "folder-node",
"__nodejs__": "folder-node",
"node_modules": "folder-node",
".node_modules": "folder-node",
"_node_modules": "folder-node",
+ "-node_modules": "folder-node",
"__node_modules__": "folder-node",
"js": "folder-javascript",
".js": "folder-javascript",
"_js": "folder-javascript",
+ "-js": "folder-javascript",
"__js__": "folder-javascript",
"javascript": "folder-javascript",
".javascript": "folder-javascript",
"_javascript": "folder-javascript",
+ "-javascript": "folder-javascript",
"__javascript__": "folder-javascript",
"javascripts": "folder-javascript",
".javascripts": "folder-javascript",
"_javascripts": "folder-javascript",
+ "-javascripts": "folder-javascript",
"__javascripts__": "folder-javascript",
"cjs": "folder-javascript",
".cjs": "folder-javascript",
"_cjs": "folder-javascript",
+ "-cjs": "folder-javascript",
"__cjs__": "folder-javascript",
"mjs": "folder-javascript",
".mjs": "folder-javascript",
"_mjs": "folder-javascript",
+ "-mjs": "folder-javascript",
"__mjs__": "folder-javascript",
"json": "folder-json",
".json": "folder-json",
"_json": "folder-json",
+ "-json": "folder-json",
"__json__": "folder-json",
"jsons": "folder-json",
".jsons": "folder-json",
"_jsons": "folder-json",
+ "-jsons": "folder-json",
"__jsons__": "folder-json",
"jsonc": "folder-json",
".jsonc": "folder-json",
"_jsonc": "folder-json",
+ "-jsonc": "folder-json",
"__jsonc__": "folder-json",
"jsonl": "folder-json",
".jsonl": "folder-json",
"_jsonl": "folder-json",
+ "-jsonl": "folder-json",
"__jsonl__": "folder-json",
"font": "folder-font",
".font": "folder-font",
"_font": "folder-font",
+ "-font": "folder-font",
"__font__": "folder-font",
"fonts": "folder-font",
".fonts": "folder-font",
"_fonts": "folder-font",
+ "-fonts": "folder-font",
"__fonts__": "folder-font",
"typeface": "folder-font",
".typeface": "folder-font",
"_typeface": "folder-font",
+ "-typeface": "folder-font",
"__typeface__": "folder-font",
"typefaces": "folder-font",
".typefaces": "folder-font",
"_typefaces": "folder-font",
+ "-typefaces": "folder-font",
"__typefaces__": "folder-font",
"bower_components": "folder-bower",
".bower_components": "folder-bower",
"_bower_components": "folder-bower",
+ "-bower_components": "folder-bower",
"__bower_components__": "folder-bower",
"test": "folder-test",
".test": "folder-test",
"_test": "folder-test",
+ "-test": "folder-test",
"__test__": "folder-test",
"tests": "folder-test",
".tests": "folder-test",
"_tests": "folder-test",
+ "-tests": "folder-test",
"__tests__": "folder-test",
"testing": "folder-test",
".testing": "folder-test",
"_testing": "folder-test",
+ "-testing": "folder-test",
"__testing__": "folder-test",
"snapshots": "folder-test",
".snapshots": "folder-test",
"_snapshots": "folder-test",
+ "-snapshots": "folder-test",
"__snapshots__": "folder-test",
"spec": "folder-test",
".spec": "folder-test",
"_spec": "folder-test",
+ "-spec": "folder-test",
"__spec__": "folder-test",
"specs": "folder-test",
".specs": "folder-test",
"_specs": "folder-test",
+ "-specs": "folder-test",
"__specs__": "folder-test",
"testfiles": "folder-test",
".testfiles": "folder-test",
"_testfiles": "folder-test",
+ "-testfiles": "folder-test",
"__testfiles__": "folder-test",
"directive": "folder-directive",
".directive": "folder-directive",
"_directive": "folder-directive",
+ "-directive": "folder-directive",
"__directive__": "folder-directive",
"directives": "folder-directive",
".directives": "folder-directive",
"_directives": "folder-directive",
+ "-directives": "folder-directive",
"__directives__": "folder-directive",
"jinja": "folder-jinja",
".jinja": "folder-jinja",
"_jinja": "folder-jinja",
+ "-jinja": "folder-jinja",
"__jinja__": "folder-jinja",
"jinja2": "folder-jinja",
".jinja2": "folder-jinja",
"_jinja2": "folder-jinja",
+ "-jinja2": "folder-jinja",
"__jinja2__": "folder-jinja",
"j2": "folder-jinja",
".j2": "folder-jinja",
"_j2": "folder-jinja",
+ "-j2": "folder-jinja",
"__j2__": "folder-jinja",
"markdown": "folder-markdown",
".markdown": "folder-markdown",
"_markdown": "folder-markdown",
+ "-markdown": "folder-markdown",
"__markdown__": "folder-markdown",
"md": "folder-markdown",
".md": "folder-markdown",
"_md": "folder-markdown",
+ "-md": "folder-markdown",
"__md__": "folder-markdown",
"pdm-plugins": "folder-pdm",
".pdm-plugins": "folder-pdm",
"_pdm-plugins": "folder-pdm",
+ "-pdm-plugins": "folder-pdm",
"__pdm-plugins__": "folder-pdm",
"pdm-build": "folder-pdm",
".pdm-build": "folder-pdm",
"_pdm-build": "folder-pdm",
+ "-pdm-build": "folder-pdm",
"__pdm-build__": "folder-pdm",
"php": "folder-php",
".php": "folder-php",
"_php": "folder-php",
+ "-php": "folder-php",
"__php__": "folder-php",
"phpmailer": "folder-phpmailer",
".phpmailer": "folder-phpmailer",
"_phpmailer": "folder-phpmailer",
+ "-phpmailer": "folder-phpmailer",
"__phpmailer__": "folder-phpmailer",
"sublime": "folder-sublime",
".sublime": "folder-sublime",
"_sublime": "folder-sublime",
+ "-sublime": "folder-sublime",
"__sublime__": "folder-sublime",
"doc": "folder-docs",
".doc": "folder-docs",
"_doc": "folder-docs",
+ "-doc": "folder-docs",
"__doc__": "folder-docs",
"docs": "folder-docs",
".docs": "folder-docs",
"_docs": "folder-docs",
+ "-docs": "folder-docs",
"__docs__": "folder-docs",
"document": "folder-docs",
".document": "folder-docs",
"_document": "folder-docs",
+ "-document": "folder-docs",
"__document__": "folder-docs",
"documents": "folder-docs",
".documents": "folder-docs",
"_documents": "folder-docs",
+ "-documents": "folder-docs",
"__documents__": "folder-docs",
"documentation": "folder-docs",
".documentation": "folder-docs",
"_documentation": "folder-docs",
+ "-documentation": "folder-docs",
"__documentation__": "folder-docs",
"post": "folder-docs",
".post": "folder-docs",
"_post": "folder-docs",
+ "-post": "folder-docs",
"__post__": "folder-docs",
"posts": "folder-docs",
".posts": "folder-docs",
"_posts": "folder-docs",
+ "-posts": "folder-docs",
"__posts__": "folder-docs",
"article": "folder-docs",
".article": "folder-docs",
"_article": "folder-docs",
+ "-article": "folder-docs",
"__article__": "folder-docs",
"articles": "folder-docs",
".articles": "folder-docs",
"_articles": "folder-docs",
+ "-articles": "folder-docs",
"__articles__": "folder-docs",
"wiki": "folder-docs",
".wiki": "folder-docs",
"_wiki": "folder-docs",
+ "-wiki": "folder-docs",
"__wiki__": "folder-docs",
"news": "folder-docs",
".news": "folder-docs",
"_news": "folder-docs",
+ "-news": "folder-docs",
"__news__": "folder-docs",
"blog": "folder-docs",
".blog": "folder-docs",
"_blog": "folder-docs",
+ "-blog": "folder-docs",
"__blog__": "folder-docs",
"knowledge": "folder-docs",
".knowledge": "folder-docs",
"_knowledge": "folder-docs",
+ "-knowledge": "folder-docs",
"__knowledge__": "folder-docs",
"diary": "folder-docs",
".diary": "folder-docs",
"_diary": "folder-docs",
+ "-diary": "folder-docs",
"__diary__": "folder-docs",
"note": "folder-docs",
".note": "folder-docs",
"_note": "folder-docs",
+ "-note": "folder-docs",
"__note__": "folder-docs",
"notes": "folder-docs",
".notes": "folder-docs",
"_notes": "folder-docs",
+ "-notes": "folder-docs",
"__notes__": "folder-docs",
"github/workflows": "folder-gh-workflows",
".github/workflows": "folder-gh-workflows",
"_github/workflows": "folder-gh-workflows",
+ "-github/workflows": "folder-gh-workflows",
"__github/workflows__": "folder-gh-workflows",
"git": "folder-git",
".git": "folder-git",
"_git": "folder-git",
+ "-git": "folder-git",
"__git__": "folder-git",
"patches": "folder-git",
".patches": "folder-git",
"_patches": "folder-git",
+ "-patches": "folder-git",
"__patches__": "folder-git",
"githooks": "folder-git",
".githooks": "folder-git",
"_githooks": "folder-git",
+ "-githooks": "folder-git",
"__githooks__": "folder-git",
"submodules": "folder-git",
".submodules": "folder-git",
"_submodules": "folder-git",
+ "-submodules": "folder-git",
"__submodules__": "folder-git",
"github": "folder-github",
".github": "folder-github",
"_github": "folder-github",
+ "-github": "folder-github",
"__github__": "folder-github",
"gitea": "folder-gitea",
".gitea": "folder-gitea",
"_gitea": "folder-gitea",
+ "-gitea": "folder-gitea",
"__gitea__": "folder-gitea",
"gitlab": "folder-gitlab",
".gitlab": "folder-gitlab",
"_gitlab": "folder-gitlab",
+ "-gitlab": "folder-gitlab",
"__gitlab__": "folder-gitlab",
"forgejo": "folder-forgejo",
".forgejo": "folder-forgejo",
"_forgejo": "folder-forgejo",
+ "-forgejo": "folder-forgejo",
"__forgejo__": "folder-forgejo",
"vscode": "folder-vscode",
".vscode": "folder-vscode",
"_vscode": "folder-vscode",
+ "-vscode": "folder-vscode",
"__vscode__": "folder-vscode",
"vscode-test": "folder-vscode",
".vscode-test": "folder-vscode",
"_vscode-test": "folder-vscode",
+ "-vscode-test": "folder-vscode",
"__vscode-test__": "folder-vscode",
"view": "folder-views",
".view": "folder-views",
"_view": "folder-views",
+ "-view": "folder-views",
"__view__": "folder-views",
"views": "folder-views",
".views": "folder-views",
"_views": "folder-views",
+ "-views": "folder-views",
"__views__": "folder-views",
"screen": "folder-views",
".screen": "folder-views",
"_screen": "folder-views",
+ "-screen": "folder-views",
"__screen__": "folder-views",
"screens": "folder-views",
".screens": "folder-views",
"_screens": "folder-views",
+ "-screens": "folder-views",
"__screens__": "folder-views",
"page": "folder-views",
".page": "folder-views",
"_page": "folder-views",
+ "-page": "folder-views",
"__page__": "folder-views",
"pages": "folder-views",
".pages": "folder-views",
"_pages": "folder-views",
+ "-pages": "folder-views",
"__pages__": "folder-views",
"public_html": "folder-views",
".public_html": "folder-views",
"_public_html": "folder-views",
+ "-public_html": "folder-views",
"__public_html__": "folder-views",
"html": "folder-views",
".html": "folder-views",
"_html": "folder-views",
+ "-html": "folder-views",
"__html__": "folder-views",
"vue": "folder-vue",
".vue": "folder-vue",
"_vue": "folder-vue",
+ "-vue": "folder-vue",
"__vue__": "folder-vue",
"vuepress": "folder-vuepress",
".vuepress": "folder-vuepress",
"_vuepress": "folder-vuepress",
+ "-vuepress": "folder-vuepress",
"__vuepress__": "folder-vuepress",
"expo": "folder-expo",
".expo": "folder-expo",
"_expo": "folder-expo",
+ "-expo": "folder-expo",
"__expo__": "folder-expo",
"expo-shared": "folder-expo",
".expo-shared": "folder-expo",
"_expo-shared": "folder-expo",
+ "-expo-shared": "folder-expo",
"__expo-shared__": "folder-expo",
"cfg": "folder-config",
".cfg": "folder-config",
"_cfg": "folder-config",
+ "-cfg": "folder-config",
"__cfg__": "folder-config",
"cfgs": "folder-config",
".cfgs": "folder-config",
"_cfgs": "folder-config",
+ "-cfgs": "folder-config",
"__cfgs__": "folder-config",
"conf": "folder-config",
".conf": "folder-config",
"_conf": "folder-config",
+ "-conf": "folder-config",
"__conf__": "folder-config",
"confs": "folder-config",
".confs": "folder-config",
"_confs": "folder-config",
+ "-confs": "folder-config",
"__confs__": "folder-config",
"config": "folder-config",
".config": "folder-config",
"_config": "folder-config",
+ "-config": "folder-config",
"__config__": "folder-config",
"configs": "folder-config",
".configs": "folder-config",
"_configs": "folder-config",
+ "-configs": "folder-config",
"__configs__": "folder-config",
"configuration": "folder-config",
".configuration": "folder-config",
"_configuration": "folder-config",
+ "-configuration": "folder-config",
"__configuration__": "folder-config",
"configurations": "folder-config",
".configurations": "folder-config",
"_configurations": "folder-config",
+ "-configurations": "folder-config",
"__configurations__": "folder-config",
"setting": "folder-config",
".setting": "folder-config",
"_setting": "folder-config",
+ "-setting": "folder-config",
"__setting__": "folder-config",
"settings": "folder-config",
".settings": "folder-config",
"_settings": "folder-config",
+ "-settings": "folder-config",
"__settings__": "folder-config",
"meta-inf": "folder-config",
".meta-inf": "folder-config",
"_meta-inf": "folder-config",
+ "-meta-inf": "folder-config",
"__meta-inf__": "folder-config",
"option": "folder-config",
".option": "folder-config",
"_option": "folder-config",
+ "-option": "folder-config",
"__option__": "folder-config",
"options": "folder-config",
".options": "folder-config",
"_options": "folder-config",
+ "-options": "folder-config",
"__options__": "folder-config",
"pref": "folder-config",
".pref": "folder-config",
"_pref": "folder-config",
+ "-pref": "folder-config",
"__pref__": "folder-config",
"prefs": "folder-config",
".prefs": "folder-config",
"_prefs": "folder-config",
+ "-prefs": "folder-config",
"__prefs__": "folder-config",
"preference": "folder-config",
".preference": "folder-config",
"_preference": "folder-config",
+ "-preference": "folder-config",
"__preference__": "folder-config",
"preferences": "folder-config",
".preferences": "folder-config",
"_preferences": "folder-config",
+ "-preferences": "folder-config",
"__preferences__": "folder-config",
"props": "folder-config",
".props": "folder-config",
"_props": "folder-config",
+ "-props": "folder-config",
"__props__": "folder-config",
"properties": "folder-config",
".properties": "folder-config",
"_properties": "folder-config",
+ "-properties": "folder-config",
"__properties__": "folder-config",
"i18n": "folder-i18n",
".i18n": "folder-i18n",
"_i18n": "folder-i18n",
+ "-i18n": "folder-i18n",
"__i18n__": "folder-i18n",
"internationalization": "folder-i18n",
".internationalization": "folder-i18n",
"_internationalization": "folder-i18n",
+ "-internationalization": "folder-i18n",
"__internationalization__": "folder-i18n",
"lang": "folder-i18n",
".lang": "folder-i18n",
"_lang": "folder-i18n",
+ "-lang": "folder-i18n",
"__lang__": "folder-i18n",
"langs": "folder-i18n",
".langs": "folder-i18n",
"_langs": "folder-i18n",
+ "-langs": "folder-i18n",
"__langs__": "folder-i18n",
"language": "folder-i18n",
".language": "folder-i18n",
"_language": "folder-i18n",
+ "-language": "folder-i18n",
"__language__": "folder-i18n",
"languages": "folder-i18n",
".languages": "folder-i18n",
"_languages": "folder-i18n",
+ "-languages": "folder-i18n",
"__languages__": "folder-i18n",
"locale": "folder-i18n",
".locale": "folder-i18n",
"_locale": "folder-i18n",
+ "-locale": "folder-i18n",
"__locale__": "folder-i18n",
"locales": "folder-i18n",
".locales": "folder-i18n",
"_locales": "folder-i18n",
+ "-locales": "folder-i18n",
"__locales__": "folder-i18n",
"l10n": "folder-i18n",
".l10n": "folder-i18n",
"_l10n": "folder-i18n",
+ "-l10n": "folder-i18n",
"__l10n__": "folder-i18n",
"localization": "folder-i18n",
".localization": "folder-i18n",
"_localization": "folder-i18n",
+ "-localization": "folder-i18n",
"__localization__": "folder-i18n",
"translation": "folder-i18n",
".translation": "folder-i18n",
"_translation": "folder-i18n",
+ "-translation": "folder-i18n",
"__translation__": "folder-i18n",
"translate": "folder-i18n",
".translate": "folder-i18n",
"_translate": "folder-i18n",
+ "-translate": "folder-i18n",
"__translate__": "folder-i18n",
"translations": "folder-i18n",
".translations": "folder-i18n",
"_translations": "folder-i18n",
+ "-translations": "folder-i18n",
"__translations__": "folder-i18n",
"tx": "folder-i18n",
".tx": "folder-i18n",
"_tx": "folder-i18n",
+ "-tx": "folder-i18n",
"__tx__": "folder-i18n",
"components": "folder-components",
".components": "folder-components",
"_components": "folder-components",
+ "-components": "folder-components",
"__components__": "folder-components",
"widget": "folder-components",
".widget": "folder-components",
"_widget": "folder-components",
+ "-widget": "folder-components",
"__widget__": "folder-components",
"widgets": "folder-components",
".widgets": "folder-components",
"_widgets": "folder-components",
+ "-widgets": "folder-components",
"__widgets__": "folder-components",
"fragments": "folder-components",
".fragments": "folder-components",
"_fragments": "folder-components",
+ "-fragments": "folder-components",
"__fragments__": "folder-components",
"verdaccio": "folder-verdaccio",
".verdaccio": "folder-verdaccio",
"_verdaccio": "folder-verdaccio",
+ "-verdaccio": "folder-verdaccio",
"__verdaccio__": "folder-verdaccio",
"aurelia_project": "folder-aurelia",
".aurelia_project": "folder-aurelia",
"_aurelia_project": "folder-aurelia",
+ "-aurelia_project": "folder-aurelia",
"__aurelia_project__": "folder-aurelia",
"resource": "folder-resource",
".resource": "folder-resource",
"_resource": "folder-resource",
+ "-resource": "folder-resource",
"__resource__": "folder-resource",
"resources": "folder-resource",
".resources": "folder-resource",
"_resources": "folder-resource",
+ "-resources": "folder-resource",
"__resources__": "folder-resource",
"res": "folder-resource",
".res": "folder-resource",
"_res": "folder-resource",
+ "-res": "folder-resource",
"__res__": "folder-resource",
"asset": "folder-resource",
".asset": "folder-resource",
"_asset": "folder-resource",
+ "-asset": "folder-resource",
"__asset__": "folder-resource",
"assets": "folder-resource",
".assets": "folder-resource",
"_assets": "folder-resource",
+ "-assets": "folder-resource",
"__assets__": "folder-resource",
"static": "folder-resource",
".static": "folder-resource",
"_static": "folder-resource",
+ "-static": "folder-resource",
"__static__": "folder-resource",
"report": "folder-resource",
".report": "folder-resource",
"_report": "folder-resource",
+ "-report": "folder-resource",
"__report__": "folder-resource",
"reports": "folder-resource",
".reports": "folder-resource",
"_reports": "folder-resource",
+ "-reports": "folder-resource",
"__reports__": "folder-resource",
"lib": "folder-lib",
".lib": "folder-lib",
"_lib": "folder-lib",
+ "-lib": "folder-lib",
"__lib__": "folder-lib",
"libs": "folder-lib",
".libs": "folder-lib",
"_libs": "folder-lib",
+ "-libs": "folder-lib",
"__libs__": "folder-lib",
"library": "folder-lib",
".library": "folder-lib",
"_library": "folder-lib",
+ "-library": "folder-lib",
"__library__": "folder-lib",
"libraries": "folder-lib",
".libraries": "folder-lib",
"_libraries": "folder-lib",
+ "-libraries": "folder-lib",
"__libraries__": "folder-lib",
"vendor": "folder-lib",
".vendor": "folder-lib",
"_vendor": "folder-lib",
+ "-vendor": "folder-lib",
"__vendor__": "folder-lib",
"vendors": "folder-lib",
".vendors": "folder-lib",
"_vendors": "folder-lib",
+ "-vendors": "folder-lib",
"__vendors__": "folder-lib",
"third-party": "folder-lib",
".third-party": "folder-lib",
"_third-party": "folder-lib",
+ "-third-party": "folder-lib",
"__third-party__": "folder-lib",
"lib64": "folder-lib",
".lib64": "folder-lib",
"_lib64": "folder-lib",
+ "-lib64": "folder-lib",
"__lib64__": "folder-lib",
"themes": "folder-theme",
".themes": "folder-theme",
"_themes": "folder-theme",
+ "-themes": "folder-theme",
"__themes__": "folder-theme",
"theme": "folder-theme",
".theme": "folder-theme",
"_theme": "folder-theme",
+ "-theme": "folder-theme",
"__theme__": "folder-theme",
"color": "folder-theme",
".color": "folder-theme",
"_color": "folder-theme",
+ "-color": "folder-theme",
"__color__": "folder-theme",
"colors": "folder-theme",
".colors": "folder-theme",
"_colors": "folder-theme",
+ "-colors": "folder-theme",
"__colors__": "folder-theme",
"colour": "folder-theme",
".colour": "folder-theme",
"_colour": "folder-theme",
+ "-colour": "folder-theme",
"__colour__": "folder-theme",
"colours": "folder-theme",
".colours": "folder-theme",
"_colours": "folder-theme",
+ "-colours": "folder-theme",
"__colours__": "folder-theme",
"design": "folder-theme",
".design": "folder-theme",
"_design": "folder-theme",
+ "-design": "folder-theme",
"__design__": "folder-theme",
"designs": "folder-theme",
".designs": "folder-theme",
"_designs": "folder-theme",
+ "-designs": "folder-theme",
"__designs__": "folder-theme",
"palette": "folder-theme",
".palette": "folder-theme",
"_palette": "folder-theme",
+ "-palette": "folder-theme",
"__palette__": "folder-theme",
"palettes": "folder-theme",
".palettes": "folder-theme",
"_palettes": "folder-theme",
+ "-palettes": "folder-theme",
"__palettes__": "folder-theme",
"webpack": "folder-webpack",
".webpack": "folder-webpack",
"_webpack": "folder-webpack",
+ "-webpack": "folder-webpack",
"__webpack__": "folder-webpack",
"global": "folder-global",
".global": "folder-global",
"_global": "folder-global",
+ "-global": "folder-global",
"__global__": "folder-global",
"public": "folder-public",
".public": "folder-public",
"_public": "folder-public",
+ "-public": "folder-public",
"__public__": "folder-public",
"www": "folder-public",
".www": "folder-public",
"_www": "folder-public",
+ "-www": "folder-public",
"__www__": "folder-public",
"wwwroot": "folder-public",
".wwwroot": "folder-public",
"_wwwroot": "folder-public",
+ "-wwwroot": "folder-public",
"__wwwroot__": "folder-public",
"web": "folder-public",
".web": "folder-public",
"_web": "folder-public",
+ "-web": "folder-public",
"__web__": "folder-public",
"website": "folder-public",
".website": "folder-public",
"_website": "folder-public",
+ "-website": "folder-public",
"__website__": "folder-public",
"websites": "folder-public",
".websites": "folder-public",
"_websites": "folder-public",
+ "-websites": "folder-public",
"__websites__": "folder-public",
"site": "folder-public",
".site": "folder-public",
"_site": "folder-public",
+ "-site": "folder-public",
"__site__": "folder-public",
"browser": "folder-public",
".browser": "folder-public",
"_browser": "folder-public",
+ "-browser": "folder-public",
"__browser__": "folder-public",
"browsers": "folder-public",
".browsers": "folder-public",
"_browsers": "folder-public",
+ "-browsers": "folder-public",
"__browsers__": "folder-public",
+ "proxy": "folder-public",
+ ".proxy": "folder-public",
+ "_proxy": "folder-public",
+ "-proxy": "folder-public",
+ "__proxy__": "folder-public",
"inc": "folder-include",
".inc": "folder-include",
"_inc": "folder-include",
+ "-inc": "folder-include",
"__inc__": "folder-include",
"include": "folder-include",
".include": "folder-include",
"_include": "folder-include",
+ "-include": "folder-include",
"__include__": "folder-include",
"includes": "folder-include",
".includes": "folder-include",
"_includes": "folder-include",
+ "-includes": "folder-include",
"__includes__": "folder-include",
"partial": "folder-include",
".partial": "folder-include",
"_partial": "folder-include",
+ "-partial": "folder-include",
"__partial__": "folder-include",
"partials": "folder-include",
".partials": "folder-include",
"_partials": "folder-include",
+ "-partials": "folder-include",
"__partials__": "folder-include",
"inc64": "folder-include",
".inc64": "folder-include",
"_inc64": "folder-include",
+ "-inc64": "folder-include",
"__inc64__": "folder-include",
"docker": "folder-docker",
".docker": "folder-docker",
"_docker": "folder-docker",
+ "-docker": "folder-docker",
"__docker__": "folder-docker",
"dockerfiles": "folder-docker",
".dockerfiles": "folder-docker",
"_dockerfiles": "folder-docker",
+ "-dockerfiles": "folder-docker",
"__dockerfiles__": "folder-docker",
"dockerhub": "folder-docker",
".dockerhub": "folder-docker",
"_dockerhub": "folder-docker",
+ "-dockerhub": "folder-docker",
"__dockerhub__": "folder-docker",
"astro": "folder-astro",
".astro": "folder-astro",
"_astro": "folder-astro",
+ "-astro": "folder-astro",
"__astro__": "folder-astro",
"db": "folder-database",
".db": "folder-database",
"_db": "folder-database",
+ "-db": "folder-database",
"__db__": "folder-database",
"data": "folder-database",
".data": "folder-database",
"_data": "folder-database",
+ "-data": "folder-database",
"__data__": "folder-database",
"database": "folder-database",
".database": "folder-database",
"_database": "folder-database",
+ "-database": "folder-database",
"__database__": "folder-database",
"databases": "folder-database",
".databases": "folder-database",
"_databases": "folder-database",
+ "-databases": "folder-database",
"__databases__": "folder-database",
"sql": "folder-database",
".sql": "folder-database",
"_sql": "folder-database",
+ "-sql": "folder-database",
"__sql__": "folder-database",
"migrations": "folder-migrations",
".migrations": "folder-migrations",
"_migrations": "folder-migrations",
+ "-migrations": "folder-migrations",
"__migrations__": "folder-migrations",
"migration": "folder-migrations",
".migration": "folder-migrations",
"_migration": "folder-migrations",
+ "-migration": "folder-migrations",
"__migration__": "folder-migrations",
"log": "folder-log",
".log": "folder-log",
"_log": "folder-log",
+ "-log": "folder-log",
"__log__": "folder-log",
"logs": "folder-log",
".logs": "folder-log",
"_logs": "folder-log",
+ "-logs": "folder-log",
"__logs__": "folder-log",
"logging": "folder-log",
".logging": "folder-log",
"_logging": "folder-log",
+ "-logging": "folder-log",
"__logging__": "folder-log",
"target": "folder-target",
".target": "folder-target",
"_target": "folder-target",
+ "-target": "folder-target",
"__target__": "folder-target",
"temp": "folder-temp",
".temp": "folder-temp",
"_temp": "folder-temp",
+ "-temp": "folder-temp",
"__temp__": "folder-temp",
"tmp": "folder-temp",
".tmp": "folder-temp",
"_tmp": "folder-temp",
+ "-tmp": "folder-temp",
"__tmp__": "folder-temp",
"cached": "folder-temp",
".cached": "folder-temp",
"_cached": "folder-temp",
+ "-cached": "folder-temp",
"__cached__": "folder-temp",
"cache": "folder-temp",
".cache": "folder-temp",
"_cache": "folder-temp",
+ "-cache": "folder-temp",
"__cache__": "folder-temp",
"aws": "folder-aws",
".aws": "folder-aws",
"_aws": "folder-aws",
+ "-aws": "folder-aws",
"__aws__": "folder-aws",
"azure": "folder-aws",
".azure": "folder-aws",
"_azure": "folder-aws",
+ "-azure": "folder-aws",
"__azure__": "folder-aws",
"gcp": "folder-aws",
".gcp": "folder-aws",
"_gcp": "folder-aws",
+ "-gcp": "folder-aws",
"__gcp__": "folder-aws",
"aud": "folder-audio",
".aud": "folder-audio",
"_aud": "folder-audio",
+ "-aud": "folder-audio",
"__aud__": "folder-audio",
"auds": "folder-audio",
".auds": "folder-audio",
"_auds": "folder-audio",
+ "-auds": "folder-audio",
"__auds__": "folder-audio",
"audio": "folder-audio",
".audio": "folder-audio",
"_audio": "folder-audio",
+ "-audio": "folder-audio",
"__audio__": "folder-audio",
"audios": "folder-audio",
".audios": "folder-audio",
"_audios": "folder-audio",
+ "-audios": "folder-audio",
"__audios__": "folder-audio",
"music": "folder-audio",
".music": "folder-audio",
"_music": "folder-audio",
+ "-music": "folder-audio",
"__music__": "folder-audio",
"song": "folder-audio",
".song": "folder-audio",
"_song": "folder-audio",
+ "-song": "folder-audio",
"__song__": "folder-audio",
"songs": "folder-audio",
".songs": "folder-audio",
"_songs": "folder-audio",
+ "-songs": "folder-audio",
"__songs__": "folder-audio",
"sound": "folder-audio",
".sound": "folder-audio",
"_sound": "folder-audio",
+ "-sound": "folder-audio",
"__sound__": "folder-audio",
"sounds": "folder-audio",
".sounds": "folder-audio",
"_sounds": "folder-audio",
+ "-sounds": "folder-audio",
"__sounds__": "folder-audio",
"voice": "folder-audio",
".voice": "folder-audio",
"_voice": "folder-audio",
+ "-voice": "folder-audio",
"__voice__": "folder-audio",
"voices": "folder-audio",
".voices": "folder-audio",
"_voices": "folder-audio",
+ "-voices": "folder-audio",
"__voices__": "folder-audio",
"recordings": "folder-audio",
".recordings": "folder-audio",
"_recordings": "folder-audio",
+ "-recordings": "folder-audio",
"__recordings__": "folder-audio",
"playlist": "folder-audio",
".playlist": "folder-audio",
"_playlist": "folder-audio",
+ "-playlist": "folder-audio",
"__playlist__": "folder-audio",
"playlists": "folder-audio",
".playlists": "folder-audio",
"_playlists": "folder-audio",
+ "-playlists": "folder-audio",
"__playlists__": "folder-audio",
"vid": "folder-video",
".vid": "folder-video",
"_vid": "folder-video",
+ "-vid": "folder-video",
"__vid__": "folder-video",
"vids": "folder-video",
".vids": "folder-video",
"_vids": "folder-video",
+ "-vids": "folder-video",
"__vids__": "folder-video",
"video": "folder-video",
".video": "folder-video",
"_video": "folder-video",
+ "-video": "folder-video",
"__video__": "folder-video",
"videos": "folder-video",
".videos": "folder-video",
"_videos": "folder-video",
+ "-videos": "folder-video",
"__videos__": "folder-video",
"movie": "folder-video",
".movie": "folder-video",
"_movie": "folder-video",
+ "-movie": "folder-video",
"__movie__": "folder-video",
"movies": "folder-video",
".movies": "folder-video",
"_movies": "folder-video",
+ "-movies": "folder-video",
"__movies__": "folder-video",
"media": "folder-video",
".media": "folder-video",
"_media": "folder-video",
+ "-media": "folder-video",
"__media__": "folder-video",
"kubernetes": "folder-kubernetes",
".kubernetes": "folder-kubernetes",
"_kubernetes": "folder-kubernetes",
+ "-kubernetes": "folder-kubernetes",
"__kubernetes__": "folder-kubernetes",
"k8s": "folder-kubernetes",
".k8s": "folder-kubernetes",
"_k8s": "folder-kubernetes",
+ "-k8s": "folder-kubernetes",
"__k8s__": "folder-kubernetes",
"import": "folder-import",
".import": "folder-import",
"_import": "folder-import",
+ "-import": "folder-import",
"__import__": "folder-import",
"imports": "folder-import",
".imports": "folder-import",
"_imports": "folder-import",
+ "-imports": "folder-import",
"__imports__": "folder-import",
"imported": "folder-import",
".imported": "folder-import",
"_imported": "folder-import",
+ "-imported": "folder-import",
"__imported__": "folder-import",
"export": "folder-export",
".export": "folder-export",
"_export": "folder-export",
+ "-export": "folder-export",
"__export__": "folder-export",
"exports": "folder-export",
".exports": "folder-export",
"_exports": "folder-export",
+ "-exports": "folder-export",
"__exports__": "folder-export",
"exported": "folder-export",
".exported": "folder-export",
"_exported": "folder-export",
+ "-exported": "folder-export",
"__exported__": "folder-export",
"wakatime": "folder-wakatime",
".wakatime": "folder-wakatime",
"_wakatime": "folder-wakatime",
+ "-wakatime": "folder-wakatime",
"__wakatime__": "folder-wakatime",
"circleci": "folder-circleci",
".circleci": "folder-circleci",
"_circleci": "folder-circleci",
+ "-circleci": "folder-circleci",
"__circleci__": "folder-circleci",
"wordpress-org": "folder-wordpress",
".wordpress-org": "folder-wordpress",
"_wordpress-org": "folder-wordpress",
+ "-wordpress-org": "folder-wordpress",
"__wordpress-org__": "folder-wordpress",
"wp-content": "folder-wordpress",
".wp-content": "folder-wordpress",
"_wp-content": "folder-wordpress",
+ "-wp-content": "folder-wordpress",
"__wp-content__": "folder-wordpress",
"gradle": "folder-gradle",
".gradle": "folder-gradle",
"_gradle": "folder-gradle",
+ "-gradle": "folder-gradle",
"__gradle__": "folder-gradle",
"coverage": "folder-coverage",
".coverage": "folder-coverage",
"_coverage": "folder-coverage",
+ "-coverage": "folder-coverage",
"__coverage__": "folder-coverage",
"nyc-output": "folder-coverage",
".nyc-output": "folder-coverage",
"_nyc-output": "folder-coverage",
+ "-nyc-output": "folder-coverage",
"__nyc-output__": "folder-coverage",
"nyc_output": "folder-coverage",
".nyc_output": "folder-coverage",
"_nyc_output": "folder-coverage",
+ "-nyc_output": "folder-coverage",
"__nyc_output__": "folder-coverage",
"e2e": "folder-coverage",
".e2e": "folder-coverage",
"_e2e": "folder-coverage",
+ "-e2e": "folder-coverage",
"__e2e__": "folder-coverage",
"it": "folder-coverage",
".it": "folder-coverage",
"_it": "folder-coverage",
+ "-it": "folder-coverage",
"__it__": "folder-coverage",
"integration-test": "folder-coverage",
".integration-test": "folder-coverage",
"_integration-test": "folder-coverage",
+ "-integration-test": "folder-coverage",
"__integration-test__": "folder-coverage",
"integration-tests": "folder-coverage",
".integration-tests": "folder-coverage",
"_integration-tests": "folder-coverage",
+ "-integration-tests": "folder-coverage",
"__integration-tests__": "folder-coverage",
"class": "folder-class",
".class": "folder-class",
"_class": "folder-class",
+ "-class": "folder-class",
"__class__": "folder-class",
"classes": "folder-class",
".classes": "folder-class",
"_classes": "folder-class",
+ "-classes": "folder-class",
"__classes__": "folder-class",
"model": "folder-class",
".model": "folder-class",
"_model": "folder-class",
+ "-model": "folder-class",
"__model__": "folder-class",
"models": "folder-class",
".models": "folder-class",
"_models": "folder-class",
+ "-models": "folder-class",
"__models__": "folder-class",
"schemas": "folder-class",
".schemas": "folder-class",
"_schemas": "folder-class",
+ "-schemas": "folder-class",
"__schemas__": "folder-class",
"schema": "folder-class",
".schema": "folder-class",
"_schema": "folder-class",
+ "-schema": "folder-class",
"__schema__": "folder-class",
"other": "folder-other",
".other": "folder-other",
"_other": "folder-other",
+ "-other": "folder-other",
"__other__": "folder-other",
"others": "folder-other",
".others": "folder-other",
"_others": "folder-other",
+ "-others": "folder-other",
"__others__": "folder-other",
"misc": "folder-other",
".misc": "folder-other",
"_misc": "folder-other",
+ "-misc": "folder-other",
"__misc__": "folder-other",
"miscellaneous": "folder-other",
".miscellaneous": "folder-other",
"_miscellaneous": "folder-other",
+ "-miscellaneous": "folder-other",
"__miscellaneous__": "folder-other",
"extra": "folder-other",
".extra": "folder-other",
"_extra": "folder-other",
+ "-extra": "folder-other",
"__extra__": "folder-other",
"extras": "folder-other",
".extras": "folder-other",
"_extras": "folder-other",
+ "-extras": "folder-other",
"__extras__": "folder-other",
"etc": "folder-other",
".etc": "folder-other",
"_etc": "folder-other",
+ "-etc": "folder-other",
"__etc__": "folder-other",
"lua": "folder-lua",
".lua": "folder-lua",
"_lua": "folder-lua",
+ "-lua": "folder-lua",
"__lua__": "folder-lua",
"turbo": "folder-turborepo",
".turbo": "folder-turborepo",
"_turbo": "folder-turborepo",
+ "-turbo": "folder-turborepo",
"__turbo__": "folder-turborepo",
"typescript": "folder-typescript",
".typescript": "folder-typescript",
"_typescript": "folder-typescript",
+ "-typescript": "folder-typescript",
"__typescript__": "folder-typescript",
"ts": "folder-typescript",
".ts": "folder-typescript",
"_ts": "folder-typescript",
+ "-ts": "folder-typescript",
"__ts__": "folder-typescript",
"typings": "folder-typescript",
".typings": "folder-typescript",
"_typings": "folder-typescript",
+ "-typings": "folder-typescript",
"__typings__": "folder-typescript",
"@types": "folder-typescript",
".@types": "folder-typescript",
"_@types": "folder-typescript",
+ "-@types": "folder-typescript",
"__@types__": "folder-typescript",
"types": "folder-typescript",
".types": "folder-typescript",
"_types": "folder-typescript",
+ "-types": "folder-typescript",
"__types__": "folder-typescript",
"cts": "folder-typescript",
".cts": "folder-typescript",
"_cts": "folder-typescript",
+ "-cts": "folder-typescript",
"__cts__": "folder-typescript",
"mts": "folder-typescript",
".mts": "folder-typescript",
"_mts": "folder-typescript",
+ "-mts": "folder-typescript",
"__mts__": "folder-typescript",
"graphql": "folder-graphql",
".graphql": "folder-graphql",
"_graphql": "folder-graphql",
+ "-graphql": "folder-graphql",
"__graphql__": "folder-graphql",
"gql": "folder-graphql",
".gql": "folder-graphql",
"_gql": "folder-graphql",
+ "-gql": "folder-graphql",
"__gql__": "folder-graphql",
"routes": "folder-routes",
".routes": "folder-routes",
"_routes": "folder-routes",
+ "-routes": "folder-routes",
"__routes__": "folder-routes",
"router": "folder-routes",
".router": "folder-routes",
"_router": "folder-routes",
+ "-router": "folder-routes",
"__router__": "folder-routes",
"routers": "folder-routes",
".routers": "folder-routes",
"_routers": "folder-routes",
+ "-routers": "folder-routes",
"__routers__": "folder-routes",
"navigation": "folder-routes",
".navigation": "folder-routes",
"_navigation": "folder-routes",
+ "-navigation": "folder-routes",
"__navigation__": "folder-routes",
"navigations": "folder-routes",
".navigations": "folder-routes",
"_navigations": "folder-routes",
+ "-navigations": "folder-routes",
"__navigations__": "folder-routes",
"routing": "folder-routes",
".routing": "folder-routes",
"_routing": "folder-routes",
+ "-routing": "folder-routes",
"__routing__": "folder-routes",
"ci": "folder-ci",
".ci": "folder-ci",
"_ci": "folder-ci",
+ "-ci": "folder-ci",
"__ci__": "folder-ci",
"eslint": "folder-eslint",
".eslint": "folder-eslint",
"_eslint": "folder-eslint",
+ "-eslint": "folder-eslint",
"__eslint__": "folder-eslint",
"eslint-plugin": "folder-eslint",
".eslint-plugin": "folder-eslint",
"_eslint-plugin": "folder-eslint",
+ "-eslint-plugin": "folder-eslint",
"__eslint-plugin__": "folder-eslint",
"eslint-plugins": "folder-eslint",
".eslint-plugins": "folder-eslint",
"_eslint-plugins": "folder-eslint",
+ "-eslint-plugins": "folder-eslint",
"__eslint-plugins__": "folder-eslint",
"eslint-config": "folder-eslint",
".eslint-config": "folder-eslint",
"_eslint-config": "folder-eslint",
+ "-eslint-config": "folder-eslint",
"__eslint-config__": "folder-eslint",
"eslint-configs": "folder-eslint",
".eslint-configs": "folder-eslint",
"_eslint-configs": "folder-eslint",
+ "-eslint-configs": "folder-eslint",
"__eslint-configs__": "folder-eslint",
"benchmark": "folder-benchmark",
".benchmark": "folder-benchmark",
"_benchmark": "folder-benchmark",
+ "-benchmark": "folder-benchmark",
"__benchmark__": "folder-benchmark",
"benchmarks": "folder-benchmark",
".benchmarks": "folder-benchmark",
"_benchmarks": "folder-benchmark",
+ "-benchmarks": "folder-benchmark",
"__benchmarks__": "folder-benchmark",
"bench": "folder-benchmark",
".bench": "folder-benchmark",
"_bench": "folder-benchmark",
+ "-bench": "folder-benchmark",
"__bench__": "folder-benchmark",
+ "benches": "folder-benchmark",
+ ".benches": "folder-benchmark",
+ "_benches": "folder-benchmark",
+ "-benches": "folder-benchmark",
+ "__benches__": "folder-benchmark",
"performance": "folder-benchmark",
".performance": "folder-benchmark",
"_performance": "folder-benchmark",
+ "-performance": "folder-benchmark",
"__performance__": "folder-benchmark",
"perf": "folder-benchmark",
".perf": "folder-benchmark",
"_perf": "folder-benchmark",
+ "-perf": "folder-benchmark",
"__perf__": "folder-benchmark",
"profiling": "folder-benchmark",
".profiling": "folder-benchmark",
"_profiling": "folder-benchmark",
+ "-profiling": "folder-benchmark",
"__profiling__": "folder-benchmark",
"measure": "folder-benchmark",
".measure": "folder-benchmark",
"_measure": "folder-benchmark",
+ "-measure": "folder-benchmark",
"__measure__": "folder-benchmark",
"measures": "folder-benchmark",
".measures": "folder-benchmark",
"_measures": "folder-benchmark",
+ "-measures": "folder-benchmark",
"__measures__": "folder-benchmark",
"measurement": "folder-benchmark",
".measurement": "folder-benchmark",
"_measurement": "folder-benchmark",
+ "-measurement": "folder-benchmark",
"__measurement__": "folder-benchmark",
"messages": "folder-messages",
".messages": "folder-messages",
"_messages": "folder-messages",
+ "-messages": "folder-messages",
"__messages__": "folder-messages",
"messaging": "folder-messages",
".messaging": "folder-messages",
"_messaging": "folder-messages",
+ "-messaging": "folder-messages",
"__messaging__": "folder-messages",
"forum": "folder-messages",
".forum": "folder-messages",
"_forum": "folder-messages",
+ "-forum": "folder-messages",
"__forum__": "folder-messages",
"chat": "folder-messages",
".chat": "folder-messages",
"_chat": "folder-messages",
+ "-chat": "folder-messages",
"__chat__": "folder-messages",
"chats": "folder-messages",
".chats": "folder-messages",
"_chats": "folder-messages",
+ "-chats": "folder-messages",
"__chats__": "folder-messages",
"conversation": "folder-messages",
".conversation": "folder-messages",
"_conversation": "folder-messages",
+ "-conversation": "folder-messages",
"__conversation__": "folder-messages",
"conversations": "folder-messages",
".conversations": "folder-messages",
"_conversations": "folder-messages",
+ "-conversations": "folder-messages",
"__conversations__": "folder-messages",
"dialog": "folder-messages",
".dialog": "folder-messages",
"_dialog": "folder-messages",
+ "-dialog": "folder-messages",
"__dialog__": "folder-messages",
"dialogs": "folder-messages",
".dialogs": "folder-messages",
"_dialogs": "folder-messages",
+ "-dialogs": "folder-messages",
"__dialogs__": "folder-messages",
"less": "folder-less",
".less": "folder-less",
"_less": "folder-less",
+ "-less": "folder-less",
"__less__": "folder-less",
"gulp": "folder-gulp",
".gulp": "folder-gulp",
"_gulp": "folder-gulp",
+ "-gulp": "folder-gulp",
"__gulp__": "folder-gulp",
"gulp-tasks": "folder-gulp",
".gulp-tasks": "folder-gulp",
"_gulp-tasks": "folder-gulp",
+ "-gulp-tasks": "folder-gulp",
"__gulp-tasks__": "folder-gulp",
"gulpfile.js": "folder-gulp",
".gulpfile.js": "folder-gulp",
"_gulpfile.js": "folder-gulp",
+ "-gulpfile.js": "folder-gulp",
"__gulpfile.js__": "folder-gulp",
"gulpfile.mjs": "folder-gulp",
".gulpfile.mjs": "folder-gulp",
"_gulpfile.mjs": "folder-gulp",
+ "-gulpfile.mjs": "folder-gulp",
"__gulpfile.mjs__": "folder-gulp",
"gulpfile.ts": "folder-gulp",
".gulpfile.ts": "folder-gulp",
"_gulpfile.ts": "folder-gulp",
+ "-gulpfile.ts": "folder-gulp",
"__gulpfile.ts__": "folder-gulp",
"gulpfile.babel.js": "folder-gulp",
".gulpfile.babel.js": "folder-gulp",
"_gulpfile.babel.js": "folder-gulp",
+ "-gulpfile.babel.js": "folder-gulp",
"__gulpfile.babel.js__": "folder-gulp",
"gulpfiles": "folder-gulp",
".gulpfiles": "folder-gulp",
"_gulpfiles": "folder-gulp",
+ "-gulpfiles": "folder-gulp",
"__gulpfiles__": "folder-gulp",
"python": "folder-python",
".python": "folder-python",
"_python": "folder-python",
+ "-python": "folder-python",
"__python__": "folder-python",
"pycache": "folder-python",
".pycache": "folder-python",
"_pycache": "folder-python",
+ "-pycache": "folder-python",
"__pycache__": "folder-python",
"pytest_cache": "folder-python",
".pytest_cache": "folder-python",
"_pytest_cache": "folder-python",
+ "-pytest_cache": "folder-python",
"__pytest_cache__": "folder-python",
"sandbox": "folder-sandbox",
".sandbox": "folder-sandbox",
"_sandbox": "folder-sandbox",
+ "-sandbox": "folder-sandbox",
"__sandbox__": "folder-sandbox",
"sandboxes": "folder-sandbox",
".sandboxes": "folder-sandbox",
"_sandboxes": "folder-sandbox",
+ "-sandboxes": "folder-sandbox",
"__sandboxes__": "folder-sandbox",
"playground": "folder-sandbox",
".playground": "folder-sandbox",
"_playground": "folder-sandbox",
+ "-playground": "folder-sandbox",
"__playground__": "folder-sandbox",
"playgrounds": "folder-sandbox",
".playgrounds": "folder-sandbox",
"_playgrounds": "folder-sandbox",
+ "-playgrounds": "folder-sandbox",
"__playgrounds__": "folder-sandbox",
"scons": "folder-scons",
".scons": "folder-scons",
"_scons": "folder-scons",
+ "-scons": "folder-scons",
"__scons__": "folder-scons",
"sconf_temp": "folder-scons",
".sconf_temp": "folder-scons",
"_sconf_temp": "folder-scons",
+ "-sconf_temp": "folder-scons",
"__sconf_temp__": "folder-scons",
"scons_cache": "folder-scons",
".scons_cache": "folder-scons",
"_scons_cache": "folder-scons",
+ "-scons_cache": "folder-scons",
"__scons_cache__": "folder-scons",
"mojo": "folder-mojo",
".mojo": "folder-mojo",
"_mojo": "folder-mojo",
+ "-mojo": "folder-mojo",
"__mojo__": "folder-mojo",
"moon": "folder-moon",
".moon": "folder-moon",
"_moon": "folder-moon",
+ "-moon": "folder-moon",
"__moon__": "folder-moon",
"debug": "folder-debug",
".debug": "folder-debug",
"_debug": "folder-debug",
+ "-debug": "folder-debug",
"__debug__": "folder-debug",
"debugger": "folder-debug",
".debugger": "folder-debug",
"_debugger": "folder-debug",
+ "-debugger": "folder-debug",
"__debugger__": "folder-debug",
"debugging": "folder-debug",
".debugging": "folder-debug",
"_debugging": "folder-debug",
+ "-debugging": "folder-debug",
"__debugging__": "folder-debug",
"fastlane": "folder-fastlane",
".fastlane": "folder-fastlane",
"_fastlane": "folder-fastlane",
+ "-fastlane": "folder-fastlane",
"__fastlane__": "folder-fastlane",
"plugin": "folder-plugin",
".plugin": "folder-plugin",
"_plugin": "folder-plugin",
+ "-plugin": "folder-plugin",
"__plugin__": "folder-plugin",
"plugins": "folder-plugin",
".plugins": "folder-plugin",
"_plugins": "folder-plugin",
+ "-plugins": "folder-plugin",
"__plugins__": "folder-plugin",
"mod": "folder-plugin",
".mod": "folder-plugin",
"_mod": "folder-plugin",
+ "-mod": "folder-plugin",
"__mod__": "folder-plugin",
"mods": "folder-plugin",
".mods": "folder-plugin",
"_mods": "folder-plugin",
+ "-mods": "folder-plugin",
"__mods__": "folder-plugin",
"modding": "folder-plugin",
".modding": "folder-plugin",
"_modding": "folder-plugin",
+ "-modding": "folder-plugin",
"__modding__": "folder-plugin",
"extension": "folder-plugin",
".extension": "folder-plugin",
"_extension": "folder-plugin",
+ "-extension": "folder-plugin",
"__extension__": "folder-plugin",
"extensions": "folder-plugin",
".extensions": "folder-plugin",
"_extensions": "folder-plugin",
+ "-extensions": "folder-plugin",
"__extensions__": "folder-plugin",
"addon": "folder-plugin",
".addon": "folder-plugin",
"_addon": "folder-plugin",
+ "-addon": "folder-plugin",
"__addon__": "folder-plugin",
"addons": "folder-plugin",
".addons": "folder-plugin",
"_addons": "folder-plugin",
+ "-addons": "folder-plugin",
"__addons__": "folder-plugin",
"addin": "folder-plugin",
".addin": "folder-plugin",
"_addin": "folder-plugin",
+ "-addin": "folder-plugin",
"__addin__": "folder-plugin",
"addins": "folder-plugin",
".addins": "folder-plugin",
"_addins": "folder-plugin",
+ "-addins": "folder-plugin",
"__addins__": "folder-plugin",
"module": "folder-plugin",
".module": "folder-plugin",
"_module": "folder-plugin",
+ "-module": "folder-plugin",
"__module__": "folder-plugin",
"modules": "folder-plugin",
".modules": "folder-plugin",
"_modules": "folder-plugin",
+ "-modules": "folder-plugin",
"__modules__": "folder-plugin",
"middleware": "folder-middleware",
".middleware": "folder-middleware",
"_middleware": "folder-middleware",
+ "-middleware": "folder-middleware",
"__middleware__": "folder-middleware",
"middlewares": "folder-middleware",
".middlewares": "folder-middleware",
"_middlewares": "folder-middleware",
+ "-middlewares": "folder-middleware",
"__middlewares__": "folder-middleware",
"controller": "folder-controller",
".controller": "folder-controller",
"_controller": "folder-controller",
+ "-controller": "folder-controller",
"__controller__": "folder-controller",
"controllers": "folder-controller",
".controllers": "folder-controller",
"_controllers": "folder-controller",
+ "-controllers": "folder-controller",
"__controllers__": "folder-controller",
"controls": "folder-controller",
".controls": "folder-controller",
"_controls": "folder-controller",
+ "-controls": "folder-controller",
"__controls__": "folder-controller",
"service": "folder-controller",
".service": "folder-controller",
"_service": "folder-controller",
+ "-service": "folder-controller",
"__service__": "folder-controller",
"services": "folder-controller",
".services": "folder-controller",
"_services": "folder-controller",
+ "-services": "folder-controller",
"__services__": "folder-controller",
"provider": "folder-controller",
".provider": "folder-controller",
"_provider": "folder-controller",
+ "-provider": "folder-controller",
"__provider__": "folder-controller",
"providers": "folder-controller",
".providers": "folder-controller",
"_providers": "folder-controller",
+ "-providers": "folder-controller",
"__providers__": "folder-controller",
"handler": "folder-controller",
".handler": "folder-controller",
"_handler": "folder-controller",
+ "-handler": "folder-controller",
"__handler__": "folder-controller",
"handlers": "folder-controller",
".handlers": "folder-controller",
"_handlers": "folder-controller",
+ "-handlers": "folder-controller",
"__handlers__": "folder-controller",
"ansible": "folder-ansible",
".ansible": "folder-ansible",
"_ansible": "folder-ansible",
+ "-ansible": "folder-ansible",
"__ansible__": "folder-ansible",
"server": "folder-server",
".server": "folder-server",
"_server": "folder-server",
+ "-server": "folder-server",
"__server__": "folder-server",
"servers": "folder-server",
".servers": "folder-server",
"_servers": "folder-server",
+ "-servers": "folder-server",
"__servers__": "folder-server",
"backend": "folder-server",
".backend": "folder-server",
"_backend": "folder-server",
+ "-backend": "folder-server",
"__backend__": "folder-server",
"backends": "folder-server",
".backends": "folder-server",
"_backends": "folder-server",
+ "-backends": "folder-server",
"__backends__": "folder-server",
"inventory": "folder-server",
".inventory": "folder-server",
"_inventory": "folder-server",
+ "-inventory": "folder-server",
"__inventory__": "folder-server",
"inventories": "folder-server",
".inventories": "folder-server",
"_inventories": "folder-server",
+ "-inventories": "folder-server",
"__inventories__": "folder-server",
"infrastructure": "folder-server",
".infrastructure": "folder-server",
"_infrastructure": "folder-server",
+ "-infrastructure": "folder-server",
"__infrastructure__": "folder-server",
"infra": "folder-server",
".infra": "folder-server",
"_infra": "folder-server",
+ "-infra": "folder-server",
"__infra__": "folder-server",
"client": "folder-client",
".client": "folder-client",
"_client": "folder-client",
+ "-client": "folder-client",
"__client__": "folder-client",
"clients": "folder-client",
".clients": "folder-client",
"_clients": "folder-client",
+ "-clients": "folder-client",
"__clients__": "folder-client",
"frontend": "folder-client",
".frontend": "folder-client",
"_frontend": "folder-client",
+ "-frontend": "folder-client",
"__frontend__": "folder-client",
"frontends": "folder-client",
".frontends": "folder-client",
"_frontends": "folder-client",
+ "-frontends": "folder-client",
"__frontends__": "folder-client",
"pwa": "folder-client",
".pwa": "folder-client",
"_pwa": "folder-client",
+ "-pwa": "folder-client",
"__pwa__": "folder-client",
"spa": "folder-client",
".spa": "folder-client",
"_spa": "folder-client",
+ "-spa": "folder-client",
"__spa__": "folder-client",
"tasks": "folder-tasks",
".tasks": "folder-tasks",
"_tasks": "folder-tasks",
+ "-tasks": "folder-tasks",
"__tasks__": "folder-tasks",
"tickets": "folder-tasks",
".tickets": "folder-tasks",
"_tickets": "folder-tasks",
+ "-tickets": "folder-tasks",
"__tickets__": "folder-tasks",
"android": "folder-android",
".android": "folder-android",
"_android": "folder-android",
+ "-android": "folder-android",
"__android__": "folder-android",
"ios": "folder-ios",
".ios": "folder-ios",
"_ios": "folder-ios",
+ "-ios": "folder-ios",
"__ios__": "folder-ios",
"presentation": "folder-ui",
".presentation": "folder-ui",
"_presentation": "folder-ui",
+ "-presentation": "folder-ui",
"__presentation__": "folder-ui",
"gui": "folder-ui",
".gui": "folder-ui",
"_gui": "folder-ui",
+ "-gui": "folder-ui",
"__gui__": "folder-ui",
"ui": "folder-ui",
".ui": "folder-ui",
"_ui": "folder-ui",
+ "-ui": "folder-ui",
"__ui__": "folder-ui",
"ux": "folder-ui",
".ux": "folder-ui",
"_ux": "folder-ui",
+ "-ux": "folder-ui",
"__ux__": "folder-ui",
"uploads": "folder-upload",
".uploads": "folder-upload",
"_uploads": "folder-upload",
+ "-uploads": "folder-upload",
"__uploads__": "folder-upload",
"upload": "folder-upload",
".upload": "folder-upload",
"_upload": "folder-upload",
+ "-upload": "folder-upload",
"__upload__": "folder-upload",
"downloads": "folder-download",
".downloads": "folder-download",
"_downloads": "folder-download",
+ "-downloads": "folder-download",
"__downloads__": "folder-download",
"download": "folder-download",
".download": "folder-download",
"_download": "folder-download",
+ "-download": "folder-download",
"__download__": "folder-download",
"downloader": "folder-download",
".downloader": "folder-download",
"_downloader": "folder-download",
+ "-downloader": "folder-download",
"__downloader__": "folder-download",
"downloaders": "folder-download",
".downloaders": "folder-download",
"_downloaders": "folder-download",
+ "-downloaders": "folder-download",
"__downloaders__": "folder-download",
"tools": "folder-tools",
".tools": "folder-tools",
"_tools": "folder-tools",
+ "-tools": "folder-tools",
"__tools__": "folder-tools",
"toolkit": "folder-tools",
".toolkit": "folder-tools",
"_toolkit": "folder-tools",
+ "-toolkit": "folder-tools",
"__toolkit__": "folder-tools",
"toolkits": "folder-tools",
".toolkits": "folder-tools",
"_toolkits": "folder-tools",
+ "-toolkits": "folder-tools",
"__toolkits__": "folder-tools",
"toolbox": "folder-tools",
".toolbox": "folder-tools",
"_toolbox": "folder-tools",
+ "-toolbox": "folder-tools",
"__toolbox__": "folder-tools",
"toolboxes": "folder-tools",
".toolboxes": "folder-tools",
"_toolboxes": "folder-tools",
+ "-toolboxes": "folder-tools",
"__toolboxes__": "folder-tools",
"tooling": "folder-tools",
".tooling": "folder-tools",
"_tooling": "folder-tools",
+ "-tooling": "folder-tools",
"__tooling__": "folder-tools",
"devtools": "folder-tools",
".devtools": "folder-tools",
"_devtools": "folder-tools",
+ "-devtools": "folder-tools",
"__devtools__": "folder-tools",
"kit": "folder-tools",
".kit": "folder-tools",
"_kit": "folder-tools",
+ "-kit": "folder-tools",
"__kit__": "folder-tools",
"kits": "folder-tools",
".kits": "folder-tools",
"_kits": "folder-tools",
+ "-kits": "folder-tools",
"__kits__": "folder-tools",
"helpers": "folder-helper",
".helpers": "folder-helper",
"_helpers": "folder-helper",
+ "-helpers": "folder-helper",
"__helpers__": "folder-helper",
"helper": "folder-helper",
".helper": "folder-helper",
"_helper": "folder-helper",
+ "-helper": "folder-helper",
"__helper__": "folder-helper",
"serverless": "folder-serverless",
".serverless": "folder-serverless",
"_serverless": "folder-serverless",
+ "-serverless": "folder-serverless",
"__serverless__": "folder-serverless",
"api": "folder-api",
".api": "folder-api",
"_api": "folder-api",
+ "-api": "folder-api",
"__api__": "folder-api",
"apis": "folder-api",
".apis": "folder-api",
"_apis": "folder-api",
+ "-apis": "folder-api",
"__apis__": "folder-api",
"restapi": "folder-api",
".restapi": "folder-api",
"_restapi": "folder-api",
+ "-restapi": "folder-api",
"__restapi__": "folder-api",
"app": "folder-app",
".app": "folder-app",
"_app": "folder-app",
+ "-app": "folder-app",
"__app__": "folder-app",
"apps": "folder-app",
".apps": "folder-app",
"_apps": "folder-app",
+ "-apps": "folder-app",
"__apps__": "folder-app",
"application": "folder-app",
".application": "folder-app",
"_application": "folder-app",
+ "-application": "folder-app",
"__application__": "folder-app",
"applications": "folder-app",
".applications": "folder-app",
"_applications": "folder-app",
+ "-applications": "folder-app",
"__applications__": "folder-app",
"apollo": "folder-apollo",
".apollo": "folder-apollo",
"_apollo": "folder-apollo",
+ "-apollo": "folder-apollo",
"__apollo__": "folder-apollo",
"apollo-client": "folder-apollo",
".apollo-client": "folder-apollo",
"_apollo-client": "folder-apollo",
+ "-apollo-client": "folder-apollo",
"__apollo-client__": "folder-apollo",
"apollo-cache": "folder-apollo",
".apollo-cache": "folder-apollo",
"_apollo-cache": "folder-apollo",
+ "-apollo-cache": "folder-apollo",
"__apollo-cache__": "folder-apollo",
"apollo-config": "folder-apollo",
".apollo-config": "folder-apollo",
"_apollo-config": "folder-apollo",
+ "-apollo-config": "folder-apollo",
"__apollo-config__": "folder-apollo",
"arc": "folder-archive",
".arc": "folder-archive",
"_arc": "folder-archive",
+ "-arc": "folder-archive",
"__arc__": "folder-archive",
"arcs": "folder-archive",
".arcs": "folder-archive",
"_arcs": "folder-archive",
+ "-arcs": "folder-archive",
"__arcs__": "folder-archive",
"archive": "folder-archive",
".archive": "folder-archive",
"_archive": "folder-archive",
+ "-archive": "folder-archive",
"__archive__": "folder-archive",
"archives": "folder-archive",
".archives": "folder-archive",
"_archives": "folder-archive",
+ "-archives": "folder-archive",
"__archives__": "folder-archive",
"archival": "folder-archive",
".archival": "folder-archive",
"_archival": "folder-archive",
+ "-archival": "folder-archive",
"__archival__": "folder-archive",
"bkp": "folder-backup",
".bkp": "folder-backup",
"_bkp": "folder-backup",
+ "-bkp": "folder-backup",
"__bkp__": "folder-backup",
"bkps": "folder-backup",
".bkps": "folder-backup",
"_bkps": "folder-backup",
+ "-bkps": "folder-backup",
"__bkps__": "folder-backup",
"bak": "folder-backup",
".bak": "folder-backup",
"_bak": "folder-backup",
+ "-bak": "folder-backup",
"__bak__": "folder-backup",
"baks": "folder-backup",
".baks": "folder-backup",
"_baks": "folder-backup",
+ "-baks": "folder-backup",
"__baks__": "folder-backup",
"backup": "folder-backup",
".backup": "folder-backup",
"_backup": "folder-backup",
+ "-backup": "folder-backup",
"__backup__": "folder-backup",
"backups": "folder-backup",
".backups": "folder-backup",
"_backups": "folder-backup",
+ "-backups": "folder-backup",
"__backups__": "folder-backup",
"back-up": "folder-backup",
".back-up": "folder-backup",
"_back-up": "folder-backup",
+ "-back-up": "folder-backup",
"__back-up__": "folder-backup",
"back-ups": "folder-backup",
".back-ups": "folder-backup",
"_back-ups": "folder-backup",
+ "-back-ups": "folder-backup",
"__back-ups__": "folder-backup",
"history": "folder-backup",
".history": "folder-backup",
"_history": "folder-backup",
+ "-history": "folder-backup",
"__history__": "folder-backup",
"histories": "folder-backup",
".histories": "folder-backup",
"_histories": "folder-backup",
+ "-histories": "folder-backup",
"__histories__": "folder-backup",
"batch": "folder-batch",
".batch": "folder-batch",
"_batch": "folder-batch",
+ "-batch": "folder-batch",
"__batch__": "folder-batch",
"batchs": "folder-batch",
".batchs": "folder-batch",
"_batchs": "folder-batch",
+ "-batchs": "folder-batch",
"__batchs__": "folder-batch",
"batches": "folder-batch",
".batches": "folder-batch",
"_batches": "folder-batch",
+ "-batches": "folder-batch",
"__batches__": "folder-batch",
"buildkite": "folder-buildkite",
".buildkite": "folder-buildkite",
"_buildkite": "folder-buildkite",
+ "-buildkite": "folder-buildkite",
"__buildkite__": "folder-buildkite",
"cluster": "folder-cluster",
".cluster": "folder-cluster",
"_cluster": "folder-cluster",
+ "-cluster": "folder-cluster",
"__cluster__": "folder-cluster",
"clusters": "folder-cluster",
".clusters": "folder-cluster",
"_clusters": "folder-cluster",
+ "-clusters": "folder-cluster",
"__clusters__": "folder-cluster",
"command": "folder-command",
".command": "folder-command",
"_command": "folder-command",
+ "-command": "folder-command",
"__command__": "folder-command",
"commands": "folder-command",
".commands": "folder-command",
"_commands": "folder-command",
+ "-commands": "folder-command",
"__commands__": "folder-command",
"commandline": "folder-command",
".commandline": "folder-command",
"_commandline": "folder-command",
+ "-commandline": "folder-command",
"__commandline__": "folder-command",
"cmd": "folder-command",
".cmd": "folder-command",
"_cmd": "folder-command",
+ "-cmd": "folder-command",
"__cmd__": "folder-command",
"cli": "folder-command",
".cli": "folder-command",
"_cli": "folder-command",
+ "-cli": "folder-command",
"__cli__": "folder-command",
"clis": "folder-command",
".clis": "folder-command",
"_clis": "folder-command",
+ "-clis": "folder-command",
"__clis__": "folder-command",
"constant": "folder-constant",
".constant": "folder-constant",
"_constant": "folder-constant",
+ "-constant": "folder-constant",
"__constant__": "folder-constant",
"constants": "folder-constant",
".constants": "folder-constant",
"_constants": "folder-constant",
+ "-constants": "folder-constant",
"__constants__": "folder-constant",
"const": "folder-constant",
".const": "folder-constant",
"_const": "folder-constant",
+ "-const": "folder-constant",
"__const__": "folder-constant",
"consts": "folder-constant",
".consts": "folder-constant",
"_consts": "folder-constant",
+ "-consts": "folder-constant",
"__consts__": "folder-constant",
"container": "folder-container",
".container": "folder-container",
"_container": "folder-container",
+ "-container": "folder-container",
"__container__": "folder-container",
"containers": "folder-container",
".containers": "folder-container",
"_containers": "folder-container",
+ "-containers": "folder-container",
"__containers__": "folder-container",
"devcontainer": "folder-container",
".devcontainer": "folder-container",
"_devcontainer": "folder-container",
+ "-devcontainer": "folder-container",
"__devcontainer__": "folder-container",
"content": "folder-content",
".content": "folder-content",
"_content": "folder-content",
+ "-content": "folder-content",
"__content__": "folder-content",
"contents": "folder-content",
".contents": "folder-content",
"_contents": "folder-content",
+ "-contents": "folder-content",
"__contents__": "folder-content",
"context": "folder-context",
".context": "folder-context",
"_context": "folder-context",
+ "-context": "folder-context",
"__context__": "folder-context",
"contexts": "folder-context",
".contexts": "folder-context",
"_contexts": "folder-context",
+ "-contexts": "folder-context",
"__contexts__": "folder-context",
"core": "folder-core",
".core": "folder-core",
"_core": "folder-core",
+ "-core": "folder-core",
"__core__": "folder-core",
"delta": "folder-delta",
".delta": "folder-delta",
"_delta": "folder-delta",
+ "-delta": "folder-delta",
"__delta__": "folder-delta",
"deltas": "folder-delta",
".deltas": "folder-delta",
"_deltas": "folder-delta",
+ "-deltas": "folder-delta",
"__deltas__": "folder-delta",
"changes": "folder-delta",
".changes": "folder-delta",
"_changes": "folder-delta",
+ "-changes": "folder-delta",
"__changes__": "folder-delta",
"dump": "folder-dump",
".dump": "folder-dump",
"_dump": "folder-dump",
+ "-dump": "folder-dump",
"__dump__": "folder-dump",
"dumps": "folder-dump",
".dumps": "folder-dump",
"_dumps": "folder-dump",
+ "-dumps": "folder-dump",
"__dumps__": "folder-dump",
"demo": "folder-examples",
".demo": "folder-examples",
"_demo": "folder-examples",
+ "-demo": "folder-examples",
"__demo__": "folder-examples",
"demos": "folder-examples",
".demos": "folder-examples",
"_demos": "folder-examples",
+ "-demos": "folder-examples",
"__demos__": "folder-examples",
"example": "folder-examples",
".example": "folder-examples",
"_example": "folder-examples",
+ "-example": "folder-examples",
"__example__": "folder-examples",
"examples": "folder-examples",
".examples": "folder-examples",
"_examples": "folder-examples",
+ "-examples": "folder-examples",
"__examples__": "folder-examples",
"sample": "folder-examples",
".sample": "folder-examples",
"_sample": "folder-examples",
+ "-sample": "folder-examples",
"__sample__": "folder-examples",
"samples": "folder-examples",
".samples": "folder-examples",
"_samples": "folder-examples",
+ "-samples": "folder-examples",
"__samples__": "folder-examples",
"sample-data": "folder-examples",
".sample-data": "folder-examples",
"_sample-data": "folder-examples",
+ "-sample-data": "folder-examples",
"__sample-data__": "folder-examples",
"env": "folder-environment",
".env": "folder-environment",
"_env": "folder-environment",
+ "-env": "folder-environment",
"__env__": "folder-environment",
"envs": "folder-environment",
".envs": "folder-environment",
"_envs": "folder-environment",
+ "-envs": "folder-environment",
"__envs__": "folder-environment",
"environment": "folder-environment",
".environment": "folder-environment",
"_environment": "folder-environment",
+ "-environment": "folder-environment",
"__environment__": "folder-environment",
"environments": "folder-environment",
".environments": "folder-environment",
"_environments": "folder-environment",
+ "-environments": "folder-environment",
"__environments__": "folder-environment",
"venv": "folder-environment",
".venv": "folder-environment",
"_venv": "folder-environment",
+ "-venv": "folder-environment",
"__venv__": "folder-environment",
"func": "folder-functions",
".func": "folder-functions",
"_func": "folder-functions",
+ "-func": "folder-functions",
"__func__": "folder-functions",
"funcs": "folder-functions",
".funcs": "folder-functions",
"_funcs": "folder-functions",
+ "-funcs": "folder-functions",
"__funcs__": "folder-functions",
"function": "folder-functions",
".function": "folder-functions",
"_function": "folder-functions",
+ "-function": "folder-functions",
"__function__": "folder-functions",
"functions": "folder-functions",
".functions": "folder-functions",
"_functions": "folder-functions",
+ "-functions": "folder-functions",
"__functions__": "folder-functions",
"lambda": "folder-functions",
".lambda": "folder-functions",
"_lambda": "folder-functions",
+ "-lambda": "folder-functions",
"__lambda__": "folder-functions",
"lambdas": "folder-functions",
".lambdas": "folder-functions",
"_lambdas": "folder-functions",
+ "-lambdas": "folder-functions",
"__lambdas__": "folder-functions",
"logic": "folder-functions",
".logic": "folder-functions",
"_logic": "folder-functions",
+ "-logic": "folder-functions",
"__logic__": "folder-functions",
"math": "folder-functions",
".math": "folder-functions",
"_math": "folder-functions",
+ "-math": "folder-functions",
"__math__": "folder-functions",
"maths": "folder-functions",
".maths": "folder-functions",
"_maths": "folder-functions",
+ "-maths": "folder-functions",
"__maths__": "folder-functions",
"calc": "folder-functions",
".calc": "folder-functions",
"_calc": "folder-functions",
+ "-calc": "folder-functions",
"__calc__": "folder-functions",
"calcs": "folder-functions",
".calcs": "folder-functions",
"_calcs": "folder-functions",
+ "-calcs": "folder-functions",
"__calcs__": "folder-functions",
"calculation": "folder-functions",
".calculation": "folder-functions",
"_calculation": "folder-functions",
+ "-calculation": "folder-functions",
"__calculation__": "folder-functions",
"calculations": "folder-functions",
".calculations": "folder-functions",
"_calculations": "folder-functions",
+ "-calculations": "folder-functions",
"__calculations__": "folder-functions",
"composable": "folder-functions",
".composable": "folder-functions",
"_composable": "folder-functions",
+ "-composable": "folder-functions",
"__composable__": "folder-functions",
"composables": "folder-functions",
".composables": "folder-functions",
"_composables": "folder-functions",
+ "-composables": "folder-functions",
"__composables__": "folder-functions",
"generator": "folder-generator",
".generator": "folder-generator",
"_generator": "folder-generator",
+ "-generator": "folder-generator",
"__generator__": "folder-generator",
"generators": "folder-generator",
".generators": "folder-generator",
"_generators": "folder-generator",
+ "-generators": "folder-generator",
"__generators__": "folder-generator",
"generated": "folder-generator",
".generated": "folder-generator",
"_generated": "folder-generator",
+ "-generated": "folder-generator",
"__generated__": "folder-generator",
"cfn-gen": "folder-generator",
".cfn-gen": "folder-generator",
"_cfn-gen": "folder-generator",
+ "-cfn-gen": "folder-generator",
"__cfn-gen__": "folder-generator",
"gen": "folder-generator",
".gen": "folder-generator",
"_gen": "folder-generator",
+ "-gen": "folder-generator",
"__gen__": "folder-generator",
"gens": "folder-generator",
".gens": "folder-generator",
"_gens": "folder-generator",
+ "-gens": "folder-generator",
"__gens__": "folder-generator",
"auto": "folder-generator",
".auto": "folder-generator",
"_auto": "folder-generator",
+ "-auto": "folder-generator",
"__auto__": "folder-generator",
"hook": "folder-hook",
".hook": "folder-hook",
"_hook": "folder-hook",
+ "-hook": "folder-hook",
"__hook__": "folder-hook",
"hooks": "folder-hook",
".hooks": "folder-hook",
"_hooks": "folder-hook",
+ "-hooks": "folder-hook",
"__hooks__": "folder-hook",
"trigger": "folder-trigger",
".trigger": "folder-trigger",
"_trigger": "folder-trigger",
+ "-trigger": "folder-trigger",
"__trigger__": "folder-trigger",
"triggers": "folder-trigger",
".triggers": "folder-trigger",
"_triggers": "folder-trigger",
+ "-triggers": "folder-trigger",
"__triggers__": "folder-trigger",
"job": "folder-job",
".job": "folder-job",
"_job": "folder-job",
+ "-job": "folder-job",
"__job__": "folder-job",
"jobs": "folder-job",
".jobs": "folder-job",
"_jobs": "folder-job",
+ "-jobs": "folder-job",
"__jobs__": "folder-job",
"key": "folder-keys",
".key": "folder-keys",
"_key": "folder-keys",
+ "-key": "folder-keys",
"__key__": "folder-keys",
"keys": "folder-keys",
".keys": "folder-keys",
"_keys": "folder-keys",
+ "-keys": "folder-keys",
"__keys__": "folder-keys",
"token": "folder-keys",
".token": "folder-keys",
"_token": "folder-keys",
+ "-token": "folder-keys",
"__token__": "folder-keys",
"tokens": "folder-keys",
".tokens": "folder-keys",
"_tokens": "folder-keys",
+ "-tokens": "folder-keys",
"__tokens__": "folder-keys",
"jwt": "folder-keys",
".jwt": "folder-keys",
"_jwt": "folder-keys",
+ "-jwt": "folder-keys",
"__jwt__": "folder-keys",
"secret": "folder-keys",
".secret": "folder-keys",
"_secret": "folder-keys",
+ "-secret": "folder-keys",
"__secret__": "folder-keys",
"secrets": "folder-keys",
".secrets": "folder-keys",
"_secrets": "folder-keys",
+ "-secrets": "folder-keys",
"__secrets__": "folder-keys",
"layout": "folder-layout",
".layout": "folder-layout",
"_layout": "folder-layout",
+ "-layout": "folder-layout",
"__layout__": "folder-layout",
"layouts": "folder-layout",
".layouts": "folder-layout",
"_layouts": "folder-layout",
+ "-layouts": "folder-layout",
"__layouts__": "folder-layout",
"mail": "folder-mail",
".mail": "folder-mail",
"_mail": "folder-mail",
+ "-mail": "folder-mail",
"__mail__": "folder-mail",
"mails": "folder-mail",
".mails": "folder-mail",
"_mails": "folder-mail",
+ "-mails": "folder-mail",
"__mails__": "folder-mail",
"email": "folder-mail",
".email": "folder-mail",
"_email": "folder-mail",
+ "-email": "folder-mail",
"__email__": "folder-mail",
"emails": "folder-mail",
".emails": "folder-mail",
"_emails": "folder-mail",
+ "-emails": "folder-mail",
"__emails__": "folder-mail",
"smtp": "folder-mail",
".smtp": "folder-mail",
"_smtp": "folder-mail",
+ "-smtp": "folder-mail",
"__smtp__": "folder-mail",
"mailers": "folder-mail",
".mailers": "folder-mail",
"_mailers": "folder-mail",
+ "-mailers": "folder-mail",
"__mailers__": "folder-mail",
"mappings": "folder-mappings",
".mappings": "folder-mappings",
"_mappings": "folder-mappings",
+ "-mappings": "folder-mappings",
"__mappings__": "folder-mappings",
"mapping": "folder-mappings",
".mapping": "folder-mappings",
"_mapping": "folder-mappings",
+ "-mapping": "folder-mappings",
"__mapping__": "folder-mappings",
"meta": "folder-meta",
".meta": "folder-meta",
"_meta": "folder-meta",
+ "-meta": "folder-meta",
"__meta__": "folder-meta",
"metadata": "folder-meta",
".metadata": "folder-meta",
"_metadata": "folder-meta",
+ "-metadata": "folder-meta",
"__metadata__": "folder-meta",
"changesets": "folder-changesets",
".changesets": "folder-changesets",
"_changesets": "folder-changesets",
+ "-changesets": "folder-changesets",
"__changesets__": "folder-changesets",
"changeset": "folder-changesets",
".changeset": "folder-changesets",
"_changeset": "folder-changesets",
+ "-changeset": "folder-changesets",
"__changeset__": "folder-changesets",
"package": "folder-packages",
".package": "folder-packages",
"_package": "folder-packages",
+ "-package": "folder-packages",
"__package__": "folder-packages",
"packages": "folder-packages",
".packages": "folder-packages",
"_packages": "folder-packages",
+ "-packages": "folder-packages",
"__packages__": "folder-packages",
"pkg": "folder-packages",
".pkg": "folder-packages",
"_pkg": "folder-packages",
+ "-pkg": "folder-packages",
"__pkg__": "folder-packages",
"pkgs": "folder-packages",
".pkgs": "folder-packages",
"_pkgs": "folder-packages",
+ "-pkgs": "folder-packages",
"__pkgs__": "folder-packages",
"serverpackages": "folder-packages",
".serverpackages": "folder-packages",
"_serverpackages": "folder-packages",
+ "-serverpackages": "folder-packages",
"__serverpackages__": "folder-packages",
"devpackages": "folder-packages",
".devpackages": "folder-packages",
"_devpackages": "folder-packages",
+ "-devpackages": "folder-packages",
"__devpackages__": "folder-packages",
"dependencies": "folder-packages",
".dependencies": "folder-packages",
"_dependencies": "folder-packages",
+ "-dependencies": "folder-packages",
"__dependencies__": "folder-packages",
"shared": "folder-shared",
".shared": "folder-shared",
"_shared": "folder-shared",
+ "-shared": "folder-shared",
"__shared__": "folder-shared",
"common": "folder-shared",
".common": "folder-shared",
"_common": "folder-shared",
+ "-common": "folder-shared",
"__common__": "folder-shared",
"glsl": "folder-shader",
".glsl": "folder-shader",
"_glsl": "folder-shader",
+ "-glsl": "folder-shader",
"__glsl__": "folder-shader",
"hlsl": "folder-shader",
".hlsl": "folder-shader",
"_hlsl": "folder-shader",
+ "-hlsl": "folder-shader",
"__hlsl__": "folder-shader",
"shader": "folder-shader",
".shader": "folder-shader",
"_shader": "folder-shader",
+ "-shader": "folder-shader",
"__shader__": "folder-shader",
"shaders": "folder-shader",
".shaders": "folder-shader",
"_shaders": "folder-shader",
+ "-shaders": "folder-shader",
"__shaders__": "folder-shader",
"stack": "folder-stack",
".stack": "folder-stack",
"_stack": "folder-stack",
+ "-stack": "folder-stack",
"__stack__": "folder-stack",
"stacks": "folder-stack",
".stacks": "folder-stack",
"_stacks": "folder-stack",
+ "-stacks": "folder-stack",
"__stacks__": "folder-stack",
"template": "folder-template",
".template": "folder-template",
"_template": "folder-template",
+ "-template": "folder-template",
"__template__": "folder-template",
"templates": "folder-template",
".templates": "folder-template",
"_templates": "folder-template",
+ "-templates": "folder-template",
"__templates__": "folder-template",
"github/issue_template": "folder-template",
".github/issue_template": "folder-template",
"_github/issue_template": "folder-template",
+ "-github/issue_template": "folder-template",
"__github/issue_template__": "folder-template",
"github/pull_request_template": "folder-template",
".github/pull_request_template": "folder-template",
"_github/pull_request_template": "folder-template",
+ "-github/pull_request_template": "folder-template",
"__github/pull_request_template__": "folder-template",
"util": "folder-utils",
".util": "folder-utils",
"_util": "folder-utils",
+ "-util": "folder-utils",
"__util__": "folder-utils",
"utils": "folder-utils",
".utils": "folder-utils",
"_utils": "folder-utils",
+ "-utils": "folder-utils",
"__utils__": "folder-utils",
"utility": "folder-utils",
".utility": "folder-utils",
"_utility": "folder-utils",
+ "-utility": "folder-utils",
"__utility__": "folder-utils",
"utilities": "folder-utils",
".utilities": "folder-utils",
"_utilities": "folder-utils",
+ "-utilities": "folder-utils",
"__utilities__": "folder-utils",
"supabase": "folder-supabase",
".supabase": "folder-supabase",
"_supabase": "folder-supabase",
+ "-supabase": "folder-supabase",
"__supabase__": "folder-supabase",
"private": "folder-private",
".private": "folder-private",
"_private": "folder-private",
+ "-private": "folder-private",
"__private__": "folder-private",
"linux": "folder-linux",
".linux": "folder-linux",
"_linux": "folder-linux",
+ "-linux": "folder-linux",
"__linux__": "folder-linux",
"linuxbsd": "folder-linux",
".linuxbsd": "folder-linux",
"_linuxbsd": "folder-linux",
+ "-linuxbsd": "folder-linux",
"__linuxbsd__": "folder-linux",
"unix": "folder-linux",
".unix": "folder-linux",
"_unix": "folder-linux",
+ "-unix": "folder-linux",
"__unix__": "folder-linux",
"wsl": "folder-linux",
".wsl": "folder-linux",
"_wsl": "folder-linux",
+ "-wsl": "folder-linux",
"__wsl__": "folder-linux",
"ubuntu": "folder-linux",
".ubuntu": "folder-linux",
"_ubuntu": "folder-linux",
+ "-ubuntu": "folder-linux",
"__ubuntu__": "folder-linux",
"deb": "folder-linux",
".deb": "folder-linux",
"_deb": "folder-linux",
+ "-deb": "folder-linux",
"__deb__": "folder-linux",
"debian": "folder-linux",
".debian": "folder-linux",
"_debian": "folder-linux",
+ "-debian": "folder-linux",
"__debian__": "folder-linux",
"deepin": "folder-linux",
".deepin": "folder-linux",
"_deepin": "folder-linux",
+ "-deepin": "folder-linux",
"__deepin__": "folder-linux",
"centos": "folder-linux",
".centos": "folder-linux",
"_centos": "folder-linux",
+ "-centos": "folder-linux",
"__centos__": "folder-linux",
"popos": "folder-linux",
".popos": "folder-linux",
"_popos": "folder-linux",
+ "-popos": "folder-linux",
"__popos__": "folder-linux",
"mint": "folder-linux",
".mint": "folder-linux",
"_mint": "folder-linux",
+ "-mint": "folder-linux",
"__mint__": "folder-linux",
"windows": "folder-windows",
".windows": "folder-windows",
"_windows": "folder-windows",
+ "-windows": "folder-windows",
"__windows__": "folder-windows",
"win": "folder-windows",
".win": "folder-windows",
"_win": "folder-windows",
+ "-win": "folder-windows",
"__win__": "folder-windows",
"win32": "folder-windows",
".win32": "folder-windows",
"_win32": "folder-windows",
+ "-win32": "folder-windows",
"__win32__": "folder-windows",
"windows11": "folder-windows",
".windows11": "folder-windows",
"_windows11": "folder-windows",
+ "-windows11": "folder-windows",
"__windows11__": "folder-windows",
"windows10": "folder-windows",
".windows10": "folder-windows",
"_windows10": "folder-windows",
+ "-windows10": "folder-windows",
"__windows10__": "folder-windows",
"windowsxp": "folder-windows",
".windowsxp": "folder-windows",
"_windowsxp": "folder-windows",
+ "-windowsxp": "folder-windows",
"__windowsxp__": "folder-windows",
"windowsnt": "folder-windows",
".windowsnt": "folder-windows",
"_windowsnt": "folder-windows",
+ "-windowsnt": "folder-windows",
"__windowsnt__": "folder-windows",
"win11": "folder-windows",
".win11": "folder-windows",
"_win11": "folder-windows",
+ "-win11": "folder-windows",
"__win11__": "folder-windows",
"win10": "folder-windows",
".win10": "folder-windows",
"_win10": "folder-windows",
+ "-win10": "folder-windows",
"__win10__": "folder-windows",
"winxp": "folder-windows",
".winxp": "folder-windows",
"_winxp": "folder-windows",
+ "-winxp": "folder-windows",
"__winxp__": "folder-windows",
"winnt": "folder-windows",
".winnt": "folder-windows",
"_winnt": "folder-windows",
+ "-winnt": "folder-windows",
"__winnt__": "folder-windows",
"macos": "folder-macos",
".macos": "folder-macos",
"_macos": "folder-macos",
+ "-macos": "folder-macos",
"__macos__": "folder-macos",
"mac": "folder-macos",
".mac": "folder-macos",
"_mac": "folder-macos",
+ "-mac": "folder-macos",
"__mac__": "folder-macos",
"osx": "folder-macos",
".osx": "folder-macos",
"_osx": "folder-macos",
+ "-osx": "folder-macos",
"__osx__": "folder-macos",
"ds_store": "folder-macos",
".ds_store": "folder-macos",
"_ds_store": "folder-macos",
+ "-ds_store": "folder-macos",
"__ds_store__": "folder-macos",
"iphone": "folder-macos",
".iphone": "folder-macos",
"_iphone": "folder-macos",
+ "-iphone": "folder-macos",
"__iphone__": "folder-macos",
"ipad": "folder-macos",
".ipad": "folder-macos",
"_ipad": "folder-macos",
+ "-ipad": "folder-macos",
"__ipad__": "folder-macos",
"ipod": "folder-macos",
".ipod": "folder-macos",
"_ipod": "folder-macos",
+ "-ipod": "folder-macos",
"__ipod__": "folder-macos",
"macbook": "folder-macos",
".macbook": "folder-macos",
"_macbook": "folder-macos",
+ "-macbook": "folder-macos",
"__macbook__": "folder-macos",
"macbook-air": "folder-macos",
".macbook-air": "folder-macos",
"_macbook-air": "folder-macos",
+ "-macbook-air": "folder-macos",
"__macbook-air__": "folder-macos",
"macosx": "folder-macos",
".macosx": "folder-macos",
"_macosx": "folder-macos",
+ "-macosx": "folder-macos",
"__macosx__": "folder-macos",
"apple": "folder-macos",
".apple": "folder-macos",
"_apple": "folder-macos",
+ "-apple": "folder-macos",
"__apple__": "folder-macos",
"error": "folder-error",
".error": "folder-error",
"_error": "folder-error",
+ "-error": "folder-error",
"__error__": "folder-error",
"errors": "folder-error",
".errors": "folder-error",
"_errors": "folder-error",
+ "-errors": "folder-error",
"__errors__": "folder-error",
"err": "folder-error",
".err": "folder-error",
"_err": "folder-error",
+ "-err": "folder-error",
"__err__": "folder-error",
"errs": "folder-error",
".errs": "folder-error",
"_errs": "folder-error",
+ "-errs": "folder-error",
"__errs__": "folder-error",
"crash": "folder-error",
".crash": "folder-error",
"_crash": "folder-error",
+ "-crash": "folder-error",
"__crash__": "folder-error",
"crashes": "folder-error",
".crashes": "folder-error",
"_crashes": "folder-error",
+ "-crashes": "folder-error",
"__crashes__": "folder-error",
"event": "folder-event",
".event": "folder-event",
"_event": "folder-event",
+ "-event": "folder-event",
"__event__": "folder-event",
"events": "folder-event",
".events": "folder-event",
"_events": "folder-event",
+ "-events": "folder-event",
"__events__": "folder-event",
"auth": "folder-secure",
".auth": "folder-secure",
"_auth": "folder-secure",
+ "-auth": "folder-secure",
"__auth__": "folder-secure",
"authentication": "folder-secure",
".authentication": "folder-secure",
"_authentication": "folder-secure",
+ "-authentication": "folder-secure",
"__authentication__": "folder-secure",
"secure": "folder-secure",
".secure": "folder-secure",
"_secure": "folder-secure",
+ "-secure": "folder-secure",
"__secure__": "folder-secure",
"security": "folder-secure",
".security": "folder-secure",
"_security": "folder-secure",
+ "-security": "folder-secure",
"__security__": "folder-secure",
"cert": "folder-secure",
".cert": "folder-secure",
"_cert": "folder-secure",
+ "-cert": "folder-secure",
"__cert__": "folder-secure",
"certs": "folder-secure",
".certs": "folder-secure",
"_certs": "folder-secure",
+ "-certs": "folder-secure",
"__certs__": "folder-secure",
"certificate": "folder-secure",
".certificate": "folder-secure",
"_certificate": "folder-secure",
+ "-certificate": "folder-secure",
"__certificate__": "folder-secure",
"certificates": "folder-secure",
".certificates": "folder-secure",
"_certificates": "folder-secure",
+ "-certificates": "folder-secure",
"__certificates__": "folder-secure",
"ssl": "folder-secure",
".ssl": "folder-secure",
"_ssl": "folder-secure",
+ "-ssl": "folder-secure",
"__ssl__": "folder-secure",
"cipher": "folder-secure",
".cipher": "folder-secure",
"_cipher": "folder-secure",
+ "-cipher": "folder-secure",
"__cipher__": "folder-secure",
"cypher": "folder-secure",
".cypher": "folder-secure",
"_cypher": "folder-secure",
+ "-cypher": "folder-secure",
"__cypher__": "folder-secure",
"tls": "folder-secure",
".tls": "folder-secure",
"_tls": "folder-secure",
+ "-tls": "folder-secure",
"__tls__": "folder-secure",
"custom": "folder-custom",
".custom": "folder-custom",
"_custom": "folder-custom",
+ "-custom": "folder-custom",
"__custom__": "folder-custom",
"customs": "folder-custom",
".customs": "folder-custom",
"_customs": "folder-custom",
+ "-customs": "folder-custom",
"__customs__": "folder-custom",
"draft": "folder-mock",
".draft": "folder-mock",
"_draft": "folder-mock",
+ "-draft": "folder-mock",
"__draft__": "folder-mock",
"drafts": "folder-mock",
".drafts": "folder-mock",
"_drafts": "folder-mock",
+ "-drafts": "folder-mock",
"__drafts__": "folder-mock",
"mock": "folder-mock",
".mock": "folder-mock",
"_mock": "folder-mock",
+ "-mock": "folder-mock",
"__mock__": "folder-mock",
"mocks": "folder-mock",
".mocks": "folder-mock",
"_mocks": "folder-mock",
+ "-mocks": "folder-mock",
"__mocks__": "folder-mock",
"fixture": "folder-mock",
".fixture": "folder-mock",
"_fixture": "folder-mock",
+ "-fixture": "folder-mock",
"__fixture__": "folder-mock",
"fixtures": "folder-mock",
".fixtures": "folder-mock",
"_fixtures": "folder-mock",
+ "-fixtures": "folder-mock",
"__fixtures__": "folder-mock",
"concept": "folder-mock",
".concept": "folder-mock",
"_concept": "folder-mock",
+ "-concept": "folder-mock",
"__concept__": "folder-mock",
"concepts": "folder-mock",
".concepts": "folder-mock",
"_concepts": "folder-mock",
+ "-concepts": "folder-mock",
"__concepts__": "folder-mock",
"sketch": "folder-mock",
".sketch": "folder-mock",
"_sketch": "folder-mock",
+ "-sketch": "folder-mock",
"__sketch__": "folder-mock",
"sketches": "folder-mock",
".sketches": "folder-mock",
"_sketches": "folder-mock",
+ "-sketches": "folder-mock",
"__sketches__": "folder-mock",
"syntax": "folder-syntax",
".syntax": "folder-syntax",
"_syntax": "folder-syntax",
+ "-syntax": "folder-syntax",
"__syntax__": "folder-syntax",
"syntaxes": "folder-syntax",
".syntaxes": "folder-syntax",
"_syntaxes": "folder-syntax",
+ "-syntaxes": "folder-syntax",
"__syntaxes__": "folder-syntax",
"spellcheck": "folder-syntax",
".spellcheck": "folder-syntax",
"_spellcheck": "folder-syntax",
+ "-spellcheck": "folder-syntax",
"__spellcheck__": "folder-syntax",
"spellcheckers": "folder-syntax",
".spellcheckers": "folder-syntax",
"_spellcheckers": "folder-syntax",
+ "-spellcheckers": "folder-syntax",
"__spellcheckers__": "folder-syntax",
"vm": "folder-vm",
".vm": "folder-vm",
"_vm": "folder-vm",
+ "-vm": "folder-vm",
"__vm__": "folder-vm",
"vms": "folder-vm",
".vms": "folder-vm",
"_vms": "folder-vm",
+ "-vms": "folder-vm",
"__vms__": "folder-vm",
"stylus": "folder-stylus",
".stylus": "folder-stylus",
"_stylus": "folder-stylus",
+ "-stylus": "folder-stylus",
"__stylus__": "folder-stylus",
"flow-typed": "folder-flow",
".flow-typed": "folder-flow",
"_flow-typed": "folder-flow",
+ "-flow-typed": "folder-flow",
"__flow-typed__": "folder-flow",
"rule": "folder-rules",
".rule": "folder-rules",
"_rule": "folder-rules",
+ "-rule": "folder-rules",
"__rule__": "folder-rules",
"rules": "folder-rules",
".rules": "folder-rules",
"_rules": "folder-rules",
+ "-rules": "folder-rules",
"__rules__": "folder-rules",
"validation": "folder-rules",
".validation": "folder-rules",
"_validation": "folder-rules",
+ "-validation": "folder-rules",
"__validation__": "folder-rules",
"validations": "folder-rules",
".validations": "folder-rules",
"_validations": "folder-rules",
+ "-validations": "folder-rules",
"__validations__": "folder-rules",
"validator": "folder-rules",
".validator": "folder-rules",
"_validator": "folder-rules",
+ "-validator": "folder-rules",
"__validator__": "folder-rules",
"validators": "folder-rules",
".validators": "folder-rules",
"_validators": "folder-rules",
+ "-validators": "folder-rules",
"__validators__": "folder-rules",
"review": "folder-review",
".review": "folder-review",
"_review": "folder-review",
+ "-review": "folder-review",
"__review__": "folder-review",
"reviews": "folder-review",
".reviews": "folder-review",
"_reviews": "folder-review",
+ "-reviews": "folder-review",
"__reviews__": "folder-review",
"revisal": "folder-review",
".revisal": "folder-review",
"_revisal": "folder-review",
+ "-revisal": "folder-review",
"__revisal__": "folder-review",
"revisals": "folder-review",
".revisals": "folder-review",
"_revisals": "folder-review",
+ "-revisals": "folder-review",
"__revisals__": "folder-review",
"reviewed": "folder-review",
".reviewed": "folder-review",
"_reviewed": "folder-review",
+ "-reviewed": "folder-review",
"__reviewed__": "folder-review",
"preview": "folder-review",
".preview": "folder-review",
"_preview": "folder-review",
+ "-preview": "folder-review",
"__preview__": "folder-review",
"previews": "folder-review",
".previews": "folder-review",
"_previews": "folder-review",
+ "-previews": "folder-review",
"__previews__": "folder-review",
"anim": "folder-animation",
".anim": "folder-animation",
"_anim": "folder-animation",
+ "-anim": "folder-animation",
"__anim__": "folder-animation",
"anims": "folder-animation",
".anims": "folder-animation",
"_anims": "folder-animation",
+ "-anims": "folder-animation",
"__anims__": "folder-animation",
"animation": "folder-animation",
".animation": "folder-animation",
"_animation": "folder-animation",
+ "-animation": "folder-animation",
"__animation__": "folder-animation",
"animations": "folder-animation",
".animations": "folder-animation",
"_animations": "folder-animation",
+ "-animations": "folder-animation",
"__animations__": "folder-animation",
"animated": "folder-animation",
".animated": "folder-animation",
"_animated": "folder-animation",
+ "-animated": "folder-animation",
"__animated__": "folder-animation",
"motion": "folder-animation",
".motion": "folder-animation",
"_motion": "folder-animation",
+ "-motion": "folder-animation",
"__motion__": "folder-animation",
"motions": "folder-animation",
".motions": "folder-animation",
"_motions": "folder-animation",
+ "-motions": "folder-animation",
"__motions__": "folder-animation",
"transition": "folder-animation",
".transition": "folder-animation",
"_transition": "folder-animation",
+ "-transition": "folder-animation",
"__transition__": "folder-animation",
"transitions": "folder-animation",
".transitions": "folder-animation",
"_transitions": "folder-animation",
+ "-transitions": "folder-animation",
"__transitions__": "folder-animation",
"easing": "folder-animation",
".easing": "folder-animation",
"_easing": "folder-animation",
+ "-easing": "folder-animation",
"__easing__": "folder-animation",
"easings": "folder-animation",
".easings": "folder-animation",
"_easings": "folder-animation",
+ "-easings": "folder-animation",
"__easings__": "folder-animation",
"guard": "folder-guard",
".guard": "folder-guard",
"_guard": "folder-guard",
+ "-guard": "folder-guard",
"__guard__": "folder-guard",
"guards": "folder-guard",
".guards": "folder-guard",
"_guards": "folder-guard",
+ "-guards": "folder-guard",
"__guards__": "folder-guard",
"prisma": "folder-prisma",
".prisma": "folder-prisma",
"_prisma": "folder-prisma",
+ "-prisma": "folder-prisma",
"__prisma__": "folder-prisma",
"prisma/schema": "folder-prisma",
".prisma/schema": "folder-prisma",
"_prisma/schema": "folder-prisma",
+ "-prisma/schema": "folder-prisma",
"__prisma/schema__": "folder-prisma",
"pipe": "folder-pipe",
".pipe": "folder-pipe",
"_pipe": "folder-pipe",
+ "-pipe": "folder-pipe",
"__pipe__": "folder-pipe",
"pipes": "folder-pipe",
".pipes": "folder-pipe",
"_pipes": "folder-pipe",
+ "-pipes": "folder-pipe",
"__pipes__": "folder-pipe",
"pipeline": "folder-pipe",
".pipeline": "folder-pipe",
"_pipeline": "folder-pipe",
+ "-pipeline": "folder-pipe",
"__pipeline__": "folder-pipe",
"pipelines": "folder-pipe",
".pipelines": "folder-pipe",
"_pipelines": "folder-pipe",
+ "-pipelines": "folder-pipe",
"__pipelines__": "folder-pipe",
"interceptor": "folder-interceptor",
".interceptor": "folder-interceptor",
"_interceptor": "folder-interceptor",
+ "-interceptor": "folder-interceptor",
"__interceptor__": "folder-interceptor",
"interceptors": "folder-interceptor",
".interceptors": "folder-interceptor",
"_interceptors": "folder-interceptor",
+ "-interceptors": "folder-interceptor",
"__interceptors__": "folder-interceptor",
"svg": "folder-svg",
".svg": "folder-svg",
"_svg": "folder-svg",
+ "-svg": "folder-svg",
"__svg__": "folder-svg",
"svgs": "folder-svg",
".svgs": "folder-svg",
"_svgs": "folder-svg",
+ "-svgs": "folder-svg",
"__svgs__": "folder-svg",
"vector": "folder-svg",
".vector": "folder-svg",
"_vector": "folder-svg",
+ "-vector": "folder-svg",
"__vector__": "folder-svg",
"vectors": "folder-svg",
".vectors": "folder-svg",
"_vectors": "folder-svg",
+ "-vectors": "folder-svg",
"__vectors__": "folder-svg",
"nuxt": "folder-nuxt",
".nuxt": "folder-nuxt",
"_nuxt": "folder-nuxt",
+ "-nuxt": "folder-nuxt",
"__nuxt__": "folder-nuxt",
"terraform": "folder-terraform",
".terraform": "folder-terraform",
"_terraform": "folder-terraform",
+ "-terraform": "folder-terraform",
"__terraform__": "folder-terraform",
"mobile": "folder-mobile",
".mobile": "folder-mobile",
"_mobile": "folder-mobile",
+ "-mobile": "folder-mobile",
"__mobile__": "folder-mobile",
"mobiles": "folder-mobile",
".mobiles": "folder-mobile",
"_mobiles": "folder-mobile",
+ "-mobiles": "folder-mobile",
"__mobiles__": "folder-mobile",
"portable": "folder-mobile",
".portable": "folder-mobile",
"_portable": "folder-mobile",
+ "-portable": "folder-mobile",
"__portable__": "folder-mobile",
"portability": "folder-mobile",
".portability": "folder-mobile",
"_portability": "folder-mobile",
+ "-portability": "folder-mobile",
"__portability__": "folder-mobile",
"phone": "folder-mobile",
".phone": "folder-mobile",
"_phone": "folder-mobile",
+ "-phone": "folder-mobile",
"__phone__": "folder-mobile",
"phones": "folder-mobile",
".phones": "folder-mobile",
"_phones": "folder-mobile",
+ "-phones": "folder-mobile",
"__phones__": "folder-mobile",
"stencil": "folder-stencil",
".stencil": "folder-stencil",
"_stencil": "folder-stencil",
+ "-stencil": "folder-stencil",
"__stencil__": "folder-stencil",
"firebase": "folder-firebase",
".firebase": "folder-firebase",
"_firebase": "folder-firebase",
+ "-firebase": "folder-firebase",
"__firebase__": "folder-firebase",
"firestore": "folder-firestore",
".firestore": "folder-firestore",
"_firestore": "folder-firestore",
+ "-firestore": "folder-firestore",
"__firestore__": "folder-firestore",
"cloud-firestore": "folder-firestore",
".cloud-firestore": "folder-firestore",
"_cloud-firestore": "folder-firestore",
+ "-cloud-firestore": "folder-firestore",
"__cloud-firestore__": "folder-firestore",
"firebase-firestore": "folder-firestore",
".firebase-firestore": "folder-firestore",
"_firebase-firestore": "folder-firestore",
+ "-firebase-firestore": "folder-firestore",
"__firebase-firestore__": "folder-firestore",
"cloud-functions": "folder-cloud-functions",
".cloud-functions": "folder-cloud-functions",
"_cloud-functions": "folder-cloud-functions",
+ "-cloud-functions": "folder-cloud-functions",
"__cloud-functions__": "folder-cloud-functions",
"cloudfunctions": "folder-cloud-functions",
".cloudfunctions": "folder-cloud-functions",
"_cloudfunctions": "folder-cloud-functions",
+ "-cloudfunctions": "folder-cloud-functions",
"__cloudfunctions__": "folder-cloud-functions",
"firebase-cloud-functions": "folder-cloud-functions",
".firebase-cloud-functions": "folder-cloud-functions",
"_firebase-cloud-functions": "folder-cloud-functions",
+ "-firebase-cloud-functions": "folder-cloud-functions",
"__firebase-cloud-functions__": "folder-cloud-functions",
"firebase-cloudfunctions": "folder-cloud-functions",
".firebase-cloudfunctions": "folder-cloud-functions",
"_firebase-cloudfunctions": "folder-cloud-functions",
+ "-firebase-cloudfunctions": "folder-cloud-functions",
"__firebase-cloudfunctions__": "folder-cloud-functions",
"svelte": "folder-svelte",
".svelte": "folder-svelte",
"_svelte": "folder-svelte",
+ "-svelte": "folder-svelte",
"__svelte__": "folder-svelte",
"svelte-kit": "folder-svelte",
".svelte-kit": "folder-svelte",
"_svelte-kit": "folder-svelte",
+ "-svelte-kit": "folder-svelte",
"__svelte-kit__": "folder-svelte",
"update": "folder-update",
".update": "folder-update",
"_update": "folder-update",
+ "-update": "folder-update",
"__update__": "folder-update",
"updates": "folder-update",
".updates": "folder-update",
"_updates": "folder-update",
+ "-updates": "folder-update",
"__updates__": "folder-update",
"upgrade": "folder-update",
".upgrade": "folder-update",
"_upgrade": "folder-update",
+ "-upgrade": "folder-update",
"__upgrade__": "folder-update",
"upgrades": "folder-update",
".upgrades": "folder-update",
"_upgrades": "folder-update",
+ "-upgrades": "folder-update",
"__upgrades__": "folder-update",
"idea": "folder-intellij",
".idea": "folder-intellij",
"_idea": "folder-intellij",
+ "-idea": "folder-intellij",
"__idea__": "folder-intellij",
"azure-pipelines": "folder-azure-pipelines",
".azure-pipelines": "folder-azure-pipelines",
"_azure-pipelines": "folder-azure-pipelines",
+ "-azure-pipelines": "folder-azure-pipelines",
"__azure-pipelines__": "folder-azure-pipelines",
"azure-pipelines-ci": "folder-azure-pipelines",
".azure-pipelines-ci": "folder-azure-pipelines",
"_azure-pipelines-ci": "folder-azure-pipelines",
+ "-azure-pipelines-ci": "folder-azure-pipelines",
"__azure-pipelines-ci__": "folder-azure-pipelines",
"mjml": "folder-mjml",
".mjml": "folder-mjml",
"_mjml": "folder-mjml",
+ "-mjml": "folder-mjml",
"__mjml__": "folder-mjml",
"admin": "folder-admin",
".admin": "folder-admin",
"_admin": "folder-admin",
+ "-admin": "folder-admin",
"__admin__": "folder-admin",
"admins": "folder-admin",
".admins": "folder-admin",
"_admins": "folder-admin",
+ "-admins": "folder-admin",
"__admins__": "folder-admin",
"manager": "folder-admin",
".manager": "folder-admin",
"_manager": "folder-admin",
+ "-manager": "folder-admin",
"__manager__": "folder-admin",
"managers": "folder-admin",
".managers": "folder-admin",
"_managers": "folder-admin",
+ "-managers": "folder-admin",
"__managers__": "folder-admin",
"moderator": "folder-admin",
".moderator": "folder-admin",
"_moderator": "folder-admin",
+ "-moderator": "folder-admin",
"__moderator__": "folder-admin",
"moderators": "folder-admin",
".moderators": "folder-admin",
"_moderators": "folder-admin",
+ "-moderators": "folder-admin",
"__moderators__": "folder-admin",
"jupyter": "folder-jupyter",
".jupyter": "folder-jupyter",
"_jupyter": "folder-jupyter",
+ "-jupyter": "folder-jupyter",
"__jupyter__": "folder-jupyter",
"notebook": "folder-jupyter",
".notebook": "folder-jupyter",
"_notebook": "folder-jupyter",
+ "-notebook": "folder-jupyter",
"__notebook__": "folder-jupyter",
"notebooks": "folder-jupyter",
".notebooks": "folder-jupyter",
"_notebooks": "folder-jupyter",
+ "-notebooks": "folder-jupyter",
"__notebooks__": "folder-jupyter",
"ipynb": "folder-jupyter",
".ipynb": "folder-jupyter",
"_ipynb": "folder-jupyter",
+ "-ipynb": "folder-jupyter",
"__ipynb__": "folder-jupyter",
"scala": "folder-scala",
".scala": "folder-scala",
"_scala": "folder-scala",
+ "-scala": "folder-scala",
"__scala__": "folder-scala",
"connection": "folder-connection",
".connection": "folder-connection",
"_connection": "folder-connection",
+ "-connection": "folder-connection",
"__connection__": "folder-connection",
"connections": "folder-connection",
".connections": "folder-connection",
"_connections": "folder-connection",
+ "-connections": "folder-connection",
"__connections__": "folder-connection",
"integration": "folder-connection",
".integration": "folder-connection",
"_integration": "folder-connection",
+ "-integration": "folder-connection",
"__integration__": "folder-connection",
"integrations": "folder-connection",
".integrations": "folder-connection",
"_integrations": "folder-connection",
+ "-integrations": "folder-connection",
"__integrations__": "folder-connection",
"remote": "folder-connection",
".remote": "folder-connection",
"_remote": "folder-connection",
+ "-remote": "folder-connection",
"__remote__": "folder-connection",
"remotes": "folder-connection",
".remotes": "folder-connection",
"_remotes": "folder-connection",
+ "-remotes": "folder-connection",
"__remotes__": "folder-connection",
"quasar": "folder-quasar",
".quasar": "folder-quasar",
"_quasar": "folder-quasar",
+ "-quasar": "folder-quasar",
"__quasar__": "folder-quasar",
"next": "folder-next",
".next": "folder-next",
"_next": "folder-next",
+ "-next": "folder-next",
"__next__": "folder-next",
"dal": "folder-dal",
".dal": "folder-dal",
"_dal": "folder-dal",
+ "-dal": "folder-dal",
"__dal__": "folder-dal",
"data-access": "folder-dal",
".data-access": "folder-dal",
"_data-access": "folder-dal",
+ "-data-access": "folder-dal",
"__data-access__": "folder-dal",
"data-access-layer": "folder-dal",
".data-access-layer": "folder-dal",
"_data-access-layer": "folder-dal",
+ "-data-access-layer": "folder-dal",
"__data-access-layer__": "folder-dal",
"cobol": "folder-cobol",
".cobol": "folder-cobol",
"_cobol": "folder-cobol",
+ "-cobol": "folder-cobol",
"__cobol__": "folder-cobol",
"yarn": "folder-yarn",
".yarn": "folder-yarn",
"_yarn": "folder-yarn",
+ "-yarn": "folder-yarn",
"__yarn__": "folder-yarn",
"husky": "folder-husky",
".husky": "folder-husky",
"_husky": "folder-husky",
+ "-husky": "folder-husky",
"__husky__": "folder-husky",
"storybook": "folder-storybook",
".storybook": "folder-storybook",
"_storybook": "folder-storybook",
+ "-storybook": "folder-storybook",
"__storybook__": "folder-storybook",
"stories": "folder-storybook",
".stories": "folder-storybook",
"_stories": "folder-storybook",
+ "-stories": "folder-storybook",
"__stories__": "folder-storybook",
"base": "folder-base",
".base": "folder-base",
"_base": "folder-base",
+ "-base": "folder-base",
"__base__": "folder-base",
"bases": "folder-base",
".bases": "folder-base",
"_bases": "folder-base",
+ "-bases": "folder-base",
"__bases__": "folder-base",
"cart": "folder-cart",
".cart": "folder-cart",
"_cart": "folder-cart",
+ "-cart": "folder-cart",
"__cart__": "folder-cart",
"shopping-cart": "folder-cart",
".shopping-cart": "folder-cart",
"_shopping-cart": "folder-cart",
+ "-shopping-cart": "folder-cart",
"__shopping-cart__": "folder-cart",
"shopping": "folder-cart",
".shopping": "folder-cart",
"_shopping": "folder-cart",
+ "-shopping": "folder-cart",
"__shopping__": "folder-cart",
"shop": "folder-cart",
".shop": "folder-cart",
"_shop": "folder-cart",
+ "-shop": "folder-cart",
"__shop__": "folder-cart",
"home": "folder-home",
".home": "folder-home",
"_home": "folder-home",
+ "-home": "folder-home",
"__home__": "folder-home",
"start": "folder-home",
".start": "folder-home",
"_start": "folder-home",
+ "-start": "folder-home",
"__start__": "folder-home",
"main": "folder-home",
".main": "folder-home",
"_main": "folder-home",
+ "-main": "folder-home",
"__main__": "folder-home",
"landing": "folder-home",
".landing": "folder-home",
"_landing": "folder-home",
+ "-landing": "folder-home",
"__landing__": "folder-home",
"project": "folder-project",
".project": "folder-project",
"_project": "folder-project",
+ "-project": "folder-project",
"__project__": "folder-project",
"projects": "folder-project",
".projects": "folder-project",
"_projects": "folder-project",
+ "-projects": "folder-project",
"__projects__": "folder-project",
"proj": "folder-project",
".proj": "folder-project",
"_proj": "folder-project",
+ "-proj": "folder-project",
"__proj__": "folder-project",
"projs": "folder-project",
".projs": "folder-project",
"_projs": "folder-project",
+ "-projs": "folder-project",
"__projs__": "folder-project",
"prompt": "folder-prompts",
".prompt": "folder-prompts",
"_prompt": "folder-prompts",
+ "-prompt": "folder-prompts",
"__prompt__": "folder-prompts",
"prompts": "folder-prompts",
".prompts": "folder-prompts",
"_prompts": "folder-prompts",
+ "-prompts": "folder-prompts",
"__prompts__": "folder-prompts",
"interface": "folder-interface",
".interface": "folder-interface",
"_interface": "folder-interface",
+ "-interface": "folder-interface",
"__interface__": "folder-interface",
"interfaces": "folder-interface",
".interfaces": "folder-interface",
"_interfaces": "folder-interface",
+ "-interfaces": "folder-interface",
"__interfaces__": "folder-interface",
"netlify": "folder-netlify",
".netlify": "folder-netlify",
"_netlify": "folder-netlify",
+ "-netlify": "folder-netlify",
"__netlify__": "folder-netlify",
"enum": "folder-enum",
".enum": "folder-enum",
"_enum": "folder-enum",
+ "-enum": "folder-enum",
"__enum__": "folder-enum",
"enums": "folder-enum",
".enums": "folder-enum",
"_enums": "folder-enum",
+ "-enums": "folder-enum",
"__enums__": "folder-enum",
"pact": "folder-contract",
".pact": "folder-contract",
"_pact": "folder-contract",
+ "-pact": "folder-contract",
"__pact__": "folder-contract",
"pacts": "folder-contract",
".pacts": "folder-contract",
"_pacts": "folder-contract",
+ "-pacts": "folder-contract",
"__pacts__": "folder-contract",
"contract": "folder-contract",
".contract": "folder-contract",
"_contract": "folder-contract",
+ "-contract": "folder-contract",
"__contract__": "folder-contract",
"contracts": "folder-contract",
".contracts": "folder-contract",
"_contracts": "folder-contract",
+ "-contracts": "folder-contract",
"__contracts__": "folder-contract",
"contract-testing": "folder-contract",
".contract-testing": "folder-contract",
"_contract-testing": "folder-contract",
+ "-contract-testing": "folder-contract",
"__contract-testing__": "folder-contract",
"contract-test": "folder-contract",
".contract-test": "folder-contract",
"_contract-test": "folder-contract",
+ "-contract-test": "folder-contract",
"__contract-test__": "folder-contract",
"contract-tests": "folder-contract",
".contract-tests": "folder-contract",
"_contract-tests": "folder-contract",
+ "-contract-tests": "folder-contract",
"__contract-tests__": "folder-contract",
"helm": "folder-helm",
".helm": "folder-helm",
"_helm": "folder-helm",
+ "-helm": "folder-helm",
"__helm__": "folder-helm",
"helmchart": "folder-helm",
".helmchart": "folder-helm",
"_helmchart": "folder-helm",
+ "-helmchart": "folder-helm",
"__helmchart__": "folder-helm",
"helmcharts": "folder-helm",
".helmcharts": "folder-helm",
"_helmcharts": "folder-helm",
+ "-helmcharts": "folder-helm",
"__helmcharts__": "folder-helm",
"queue": "folder-queue",
".queue": "folder-queue",
"_queue": "folder-queue",
+ "-queue": "folder-queue",
"__queue__": "folder-queue",
"queues": "folder-queue",
".queues": "folder-queue",
"_queues": "folder-queue",
+ "-queues": "folder-queue",
"__queues__": "folder-queue",
"bull": "folder-queue",
".bull": "folder-queue",
"_bull": "folder-queue",
+ "-bull": "folder-queue",
"__bull__": "folder-queue",
"mq": "folder-queue",
".mq": "folder-queue",
"_mq": "folder-queue",
+ "-mq": "folder-queue",
"__mq__": "folder-queue",
"vercel": "folder-vercel",
".vercel": "folder-vercel",
"_vercel": "folder-vercel",
+ "-vercel": "folder-vercel",
"__vercel__": "folder-vercel",
"now": "folder-vercel",
".now": "folder-vercel",
"_now": "folder-vercel",
+ "-now": "folder-vercel",
"__now__": "folder-vercel",
"cypress": "folder-cypress",
".cypress": "folder-cypress",
"_cypress": "folder-cypress",
+ "-cypress": "folder-cypress",
"__cypress__": "folder-cypress",
"decorator": "folder-decorators",
".decorator": "folder-decorators",
"_decorator": "folder-decorators",
+ "-decorator": "folder-decorators",
"__decorator__": "folder-decorators",
"decorators": "folder-decorators",
".decorators": "folder-decorators",
"_decorators": "folder-decorators",
+ "-decorators": "folder-decorators",
"__decorators__": "folder-decorators",
"java": "folder-java",
".java": "folder-java",
"_java": "folder-java",
+ "-java": "folder-java",
"__java__": "folder-java",
"resolver": "folder-resolver",
".resolver": "folder-resolver",
"_resolver": "folder-resolver",
+ "-resolver": "folder-resolver",
"__resolver__": "folder-resolver",
"resolvers": "folder-resolver",
".resolvers": "folder-resolver",
"_resolvers": "folder-resolver",
+ "-resolvers": "folder-resolver",
"__resolvers__": "folder-resolver",
"angular": "folder-angular",
".angular": "folder-angular",
"_angular": "folder-angular",
+ "-angular": "folder-angular",
"__angular__": "folder-angular",
"unity": "folder-unity",
".unity": "folder-unity",
"_unity": "folder-unity",
+ "-unity": "folder-unity",
"__unity__": "folder-unity",
"pdf": "folder-pdf",
".pdf": "folder-pdf",
"_pdf": "folder-pdf",
+ "-pdf": "folder-pdf",
"__pdf__": "folder-pdf",
"pdfs": "folder-pdf",
".pdfs": "folder-pdf",
"_pdfs": "folder-pdf",
+ "-pdfs": "folder-pdf",
"__pdfs__": "folder-pdf",
"protobuf": "folder-proto",
".protobuf": "folder-proto",
"_protobuf": "folder-proto",
+ "-protobuf": "folder-proto",
"__protobuf__": "folder-proto",
"protobufs": "folder-proto",
".protobufs": "folder-proto",
"_protobufs": "folder-proto",
+ "-protobufs": "folder-proto",
"__protobufs__": "folder-proto",
"proto": "folder-proto",
".proto": "folder-proto",
"_proto": "folder-proto",
+ "-proto": "folder-proto",
"protos": "folder-proto",
".protos": "folder-proto",
"_protos": "folder-proto",
+ "-protos": "folder-proto",
"__protos__": "folder-proto",
"plastic": "folder-plastic",
".plastic": "folder-plastic",
"_plastic": "folder-plastic",
+ "-plastic": "folder-plastic",
"__plastic__": "folder-plastic",
"gamemaker": "folder-gamemaker",
".gamemaker": "folder-gamemaker",
"_gamemaker": "folder-gamemaker",
+ "-gamemaker": "folder-gamemaker",
"__gamemaker__": "folder-gamemaker",
"gamemaker2": "folder-gamemaker",
".gamemaker2": "folder-gamemaker",
"_gamemaker2": "folder-gamemaker",
+ "-gamemaker2": "folder-gamemaker",
"__gamemaker2__": "folder-gamemaker",
"hg": "folder-mercurial",
".hg": "folder-mercurial",
"_hg": "folder-mercurial",
+ "-hg": "folder-mercurial",
"__hg__": "folder-mercurial",
"hghooks": "folder-mercurial",
".hghooks": "folder-mercurial",
"_hghooks": "folder-mercurial",
+ "-hghooks": "folder-mercurial",
"__hghooks__": "folder-mercurial",
"hgext": "folder-mercurial",
".hgext": "folder-mercurial",
"_hgext": "folder-mercurial",
+ "-hgext": "folder-mercurial",
"__hgext__": "folder-mercurial",
"godot": "folder-godot",
".godot": "folder-godot",
"_godot": "folder-godot",
+ "-godot": "folder-godot",
"__godot__": "folder-godot",
"godot-cpp": "folder-godot",
".godot-cpp": "folder-godot",
"_godot-cpp": "folder-godot",
+ "-godot-cpp": "folder-godot",
"__godot-cpp__": "folder-godot",
"lottie": "folder-lottie",
".lottie": "folder-lottie",
"_lottie": "folder-lottie",
+ "-lottie": "folder-lottie",
"__lottie__": "folder-lottie",
"lotties": "folder-lottie",
".lotties": "folder-lottie",
"_lotties": "folder-lottie",
+ "-lotties": "folder-lottie",
"__lotties__": "folder-lottie",
"lottiefiles": "folder-lottie",
".lottiefiles": "folder-lottie",
"_lottiefiles": "folder-lottie",
+ "-lottiefiles": "folder-lottie",
"__lottiefiles__": "folder-lottie",
"taskfile": "folder-taskfile",
".taskfile": "folder-taskfile",
"_taskfile": "folder-taskfile",
+ "-taskfile": "folder-taskfile",
"__taskfile__": "folder-taskfile",
"taskfiles": "folder-taskfile",
".taskfiles": "folder-taskfile",
"_taskfiles": "folder-taskfile",
+ "-taskfiles": "folder-taskfile",
"__taskfiles__": "folder-taskfile",
"drizzle": "folder-drizzle",
".drizzle": "folder-drizzle",
"_drizzle": "folder-drizzle",
+ "-drizzle": "folder-drizzle",
"__drizzle__": "folder-drizzle",
"cloudflare": "folder-cloudflare",
".cloudflare": "folder-cloudflare",
"_cloudflare": "folder-cloudflare",
+ "-cloudflare": "folder-cloudflare",
"__cloudflare__": "folder-cloudflare",
"seeds": "folder-seeders",
".seeds": "folder-seeders",
"_seeds": "folder-seeders",
+ "-seeds": "folder-seeders",
"__seeds__": "folder-seeders",
"seeders": "folder-seeders",
".seeders": "folder-seeders",
"_seeders": "folder-seeders",
+ "-seeders": "folder-seeders",
"__seeders__": "folder-seeders",
"seed": "folder-seeders",
".seed": "folder-seeders",
"_seed": "folder-seeders",
+ "-seed": "folder-seeders",
"__seed__": "folder-seeders",
"seeding": "folder-seeders",
".seeding": "folder-seeders",
"_seeding": "folder-seeders",
+ "-seeding": "folder-seeders",
"__seeding__": "folder-seeders",
"store": "folder-store",
".store": "folder-store",
"_store": "folder-store",
+ "-store": "folder-store",
"__store__": "folder-store",
"stores": "folder-store",
".stores": "folder-store",
"_stores": "folder-store",
+ "-stores": "folder-store",
"__stores__": "folder-store",
"bicep": "folder-bicep",
".bicep": "folder-bicep",
"_bicep": "folder-bicep",
+ "-bicep": "folder-bicep",
"__bicep__": "folder-bicep",
"snap": "folder-snapcraft",
".snap": "folder-snapcraft",
"_snap": "folder-snapcraft",
+ "-snap": "folder-snapcraft",
"__snap__": "folder-snapcraft",
"snapcraft": "folder-snapcraft",
".snapcraft": "folder-snapcraft",
"_snapcraft": "folder-snapcraft",
+ "-snapcraft": "folder-snapcraft",
"__snapcraft__": "folder-snapcraft",
"dev": "folder-development",
".dev": "folder-development",
"_dev": "folder-development",
+ "-dev": "folder-development",
"__dev__": "folder-development",
"development": "folder-development",
".development": "folder-development",
"_development": "folder-development",
+ "-development": "folder-development",
"__development__": "folder-development",
"flutter": "folder-flutter",
".flutter": "folder-flutter",
"_flutter": "folder-flutter",
+ "-flutter": "folder-flutter",
"__flutter__": "folder-flutter",
"snippet": "folder-snippet",
".snippet": "folder-snippet",
"_snippet": "folder-snippet",
+ "-snippet": "folder-snippet",
"__snippet__": "folder-snippet",
"snippets": "folder-snippet",
".snippets": "folder-snippet",
"_snippets": "folder-snippet",
+ "-snippets": "folder-snippet",
"__snippets__": "folder-snippet",
"element": "folder-element",
".element": "folder-element",
"_element": "folder-element",
+ "-element": "folder-element",
"__element__": "folder-element",
"elements": "folder-element",
".elements": "folder-element",
"_elements": "folder-element",
+ "-elements": "folder-element",
"__elements__": "folder-element",
"src-tauri": "folder-src-tauri",
".src-tauri": "folder-src-tauri",
"_src-tauri": "folder-src-tauri",
+ "-src-tauri": "folder-src-tauri",
"__src-tauri__": "folder-src-tauri",
"favicon": "folder-favicon",
".favicon": "folder-favicon",
"_favicon": "folder-favicon",
+ "-favicon": "folder-favicon",
"__favicon__": "folder-favicon",
"favicons": "folder-favicon",
".favicons": "folder-favicon",
"_favicons": "folder-favicon",
+ "-favicons": "folder-favicon",
"__favicons__": "folder-favicon",
"feature": "folder-features",
".feature": "folder-features",
"_feature": "folder-features",
+ "-feature": "folder-features",
"__feature__": "folder-features",
"features": "folder-features",
".features": "folder-features",
"_features": "folder-features",
+ "-features": "folder-features",
"__features__": "folder-features",
"feat": "folder-features",
".feat": "folder-features",
"_feat": "folder-features",
+ "-feat": "folder-features",
"__feat__": "folder-features",
"feats": "folder-features",
".feats": "folder-features",
"_feats": "folder-features",
+ "-feats": "folder-features",
"__feats__": "folder-features",
"lefthook": "folder-lefthook",
".lefthook": "folder-lefthook",
"_lefthook": "folder-lefthook",
+ "-lefthook": "folder-lefthook",
"__lefthook__": "folder-lefthook",
"lefthook-local": "folder-lefthook",
".lefthook-local": "folder-lefthook",
"_lefthook-local": "folder-lefthook",
+ "-lefthook-local": "folder-lefthook",
"__lefthook-local__": "folder-lefthook",
"bloc": "folder-bloc",
".bloc": "folder-bloc",
"_bloc": "folder-bloc",
+ "-bloc": "folder-bloc",
"__bloc__": "folder-bloc",
"cubit": "folder-bloc",
".cubit": "folder-bloc",
"_cubit": "folder-bloc",
+ "-cubit": "folder-bloc",
"__cubit__": "folder-bloc",
"blocs": "folder-bloc",
".blocs": "folder-bloc",
"_blocs": "folder-bloc",
+ "-blocs": "folder-bloc",
"__blocs__": "folder-bloc",
"cubits": "folder-bloc",
".cubits": "folder-bloc",
"_cubits": "folder-bloc",
+ "-cubits": "folder-bloc",
"__cubits__": "folder-bloc",
"powershell": "folder-powershell",
".powershell": "folder-powershell",
"_powershell": "folder-powershell",
+ "-powershell": "folder-powershell",
"__powershell__": "folder-powershell",
"ps": "folder-powershell",
".ps": "folder-powershell",
"_ps": "folder-powershell",
+ "-ps": "folder-powershell",
"__ps__": "folder-powershell",
"ps1": "folder-powershell",
".ps1": "folder-powershell",
"_ps1": "folder-powershell",
+ "-ps1": "folder-powershell",
"__ps1__": "folder-powershell",
"repository": "folder-repository",
".repository": "folder-repository",
"_repository": "folder-repository",
+ "-repository": "folder-repository",
"__repository__": "folder-repository",
"repositories": "folder-repository",
".repositories": "folder-repository",
"_repositories": "folder-repository",
+ "-repositories": "folder-repository",
"__repositories__": "folder-repository",
"repo": "folder-repository",
".repo": "folder-repository",
"_repo": "folder-repository",
+ "-repo": "folder-repository",
"__repo__": "folder-repository",
"repos": "folder-repository",
".repos": "folder-repository",
"_repos": "folder-repository",
+ "-repos": "folder-repository",
"__repos__": "folder-repository",
"luau": "folder-luau",
".luau": "folder-luau",
"_luau": "folder-luau",
+ "-luau": "folder-luau",
"__luau__": "folder-luau",
"obsidian": "folder-obsidian",
".obsidian": "folder-obsidian",
"_obsidian": "folder-obsidian",
+ "-obsidian": "folder-obsidian",
"__obsidian__": "folder-obsidian",
"trash": "folder-trash",
".trash": "folder-trash",
"_trash": "folder-trash",
+ "-trash": "folder-trash",
"__trash__": "folder-trash",
"cline_docs": "folder-cline",
".cline_docs": "folder-cline",
"_cline_docs": "folder-cline",
+ "-cline_docs": "folder-cline",
"__cline_docs__": "folder-cline",
"liquibase": "folder-liquibase",
".liquibase": "folder-liquibase",
"_liquibase": "folder-liquibase",
+ "-liquibase": "folder-liquibase",
"__liquibase__": "folder-liquibase",
"dart": "folder-dart",
".dart": "folder-dart",
"_dart": "folder-dart",
+ "-dart": "folder-dart",
"__dart__": "folder-dart",
"dart_tool": "folder-dart",
".dart_tool": "folder-dart",
"_dart_tool": "folder-dart",
+ "-dart_tool": "folder-dart",
"__dart_tool__": "folder-dart",
"dart_tools": "folder-dart",
".dart_tools": "folder-dart",
"_dart_tools": "folder-dart",
+ "-dart_tools": "folder-dart",
"__dart_tools__": "folder-dart",
"zeabur": "folder-zeabur",
".zeabur": "folder-zeabur",
"_zeabur": "folder-zeabur",
+ "-zeabur": "folder-zeabur",
"__zeabur__": "folder-zeabur",
"kusto": "folder-kusto",
".kusto": "folder-kusto",
"_kusto": "folder-kusto",
+ "-kusto": "folder-kusto",
"__kusto__": "folder-kusto",
"kql": "folder-kusto",
".kql": "folder-kusto",
"_kql": "folder-kusto",
+ "-kql": "folder-kusto",
"__kql__": "folder-kusto",
"policy": "folder-policy",
".policy": "folder-policy",
"_policy": "folder-policy",
+ "-policy": "folder-policy",
"__policy__": "folder-policy",
"policies": "folder-policy",
".policies": "folder-policy",
"_policies": "folder-policy",
+ "-policies": "folder-policy",
"__policies__": "folder-policy",
"attachment": "folder-attachment",
".attachment": "folder-attachment",
"_attachment": "folder-attachment",
+ "-attachment": "folder-attachment",
"__attachment__": "folder-attachment",
"attachments": "folder-attachment",
".attachments": "folder-attachment",
"_attachments": "folder-attachment",
+ "-attachments": "folder-attachment",
"__attachments__": "folder-attachment",
"bibliography": "folder-bibliography",
".bibliography": "folder-bibliography",
"_bibliography": "folder-bibliography",
+ "-bibliography": "folder-bibliography",
"__bibliography__": "folder-bibliography",
"bibliographies": "folder-bibliography",
".bibliographies": "folder-bibliography",
"_bibliographies": "folder-bibliography",
+ "-bibliographies": "folder-bibliography",
"__bibliographies__": "folder-bibliography",
"book": "folder-bibliography",
".book": "folder-bibliography",
"_book": "folder-bibliography",
+ "-book": "folder-bibliography",
"__book__": "folder-bibliography",
"books": "folder-bibliography",
".books": "folder-bibliography",
"_books": "folder-bibliography",
+ "-books": "folder-bibliography",
"__books__": "folder-bibliography",
"link": "folder-link",
".link": "folder-link",
"_link": "folder-link",
+ "-link": "folder-link",
"__link__": "folder-link",
"links": "folder-link",
".links": "folder-link",
"_links": "folder-link",
+ "-links": "folder-link",
"__links__": "folder-link",
"pytorch": "folder-pytorch",
".pytorch": "folder-pytorch",
"_pytorch": "folder-pytorch",
+ "-pytorch": "folder-pytorch",
"__pytorch__": "folder-pytorch",
"torch": "folder-pytorch",
".torch": "folder-pytorch",
"_torch": "folder-pytorch",
+ "-torch": "folder-pytorch",
"__torch__": "folder-pytorch",
"blender": "folder-blender",
".blender": "folder-blender",
"_blender": "folder-blender",
+ "-blender": "folder-blender",
"__blender__": "folder-blender",
"blender-assets": "folder-blender",
".blender-assets": "folder-blender",
"_blender-assets": "folder-blender",
+ "-blender-assets": "folder-blender",
"__blender-assets__": "folder-blender",
"blender-files": "folder-blender",
".blender-files": "folder-blender",
"_blender-files": "folder-blender",
+ "-blender-files": "folder-blender",
"__blender-files__": "folder-blender",
"blender-project": "folder-blender",
".blender-project": "folder-blender",
"_blender-project": "folder-blender",
+ "-blender-project": "folder-blender",
"__blender-project__": "folder-blender",
"blender-models": "folder-blender",
".blender-models": "folder-blender",
"_blender-models": "folder-blender",
+ "-blender-models": "folder-blender",
"__blender-models__": "folder-blender",
"atoms": "folder-atom",
".atoms": "folder-atom",
"_atoms": "folder-atom",
+ "-atoms": "folder-atom",
"__atoms__": "folder-atom",
"atom": "folder-atom",
".atom": "folder-atom",
"_atom": "folder-atom",
+ "-atom": "folder-atom",
"__atom__": "folder-atom",
"molecules": "folder-molecule",
".molecules": "folder-molecule",
"_molecules": "folder-molecule",
+ "-molecules": "folder-molecule",
"__molecules__": "folder-molecule",
"molecule": "folder-molecule",
".molecule": "folder-molecule",
"_molecule": "folder-molecule",
+ "-molecule": "folder-molecule",
"__molecule__": "folder-molecule",
"organisms": "folder-organism",
".organisms": "folder-organism",
"_organisms": "folder-organism",
+ "-organisms": "folder-organism",
"__organisms__": "folder-organism",
"organism": "folder-organism",
".organism": "folder-organism",
"_organism": "folder-organism",
+ "-organism": "folder-organism",
"__organism__": "folder-organism",
".claude": "folder-claude",
"..claude": "folder-claude",
"_.claude": "folder-claude",
+ "-.claude": "folder-claude",
"__.claude__": "folder-claude",
".cursor": "folder-cursor",
"..cursor": "folder-cursor",
"_.cursor": "folder-cursor",
+ "-.cursor": "folder-cursor",
"__.cursor__": "folder-cursor",
".gemini": "folder-gemini-ai",
"..gemini": "folder-gemini-ai",
"_.gemini": "folder-gemini-ai",
+ "-.gemini": "folder-gemini-ai",
"__.gemini__": "folder-gemini-ai",
+ "gemini": "folder-gemini-ai",
+ "_gemini": "folder-gemini-ai",
+ "-gemini": "folder-gemini-ai",
+ "__gemini__": "folder-gemini-ai",
+ "gemini-ai": "folder-gemini-ai",
+ ".gemini-ai": "folder-gemini-ai",
+ "_gemini-ai": "folder-gemini-ai",
+ "-gemini-ai": "folder-gemini-ai",
+ "__gemini-ai__": "folder-gemini-ai",
+ "geminiai": "folder-gemini-ai",
+ ".geminiai": "folder-gemini-ai",
+ "_geminiai": "folder-gemini-ai",
+ "-geminiai": "folder-gemini-ai",
+ "__geminiai__": "folder-gemini-ai",
"input": "folder-input",
".input": "folder-input",
"_input": "folder-input",
+ "-input": "folder-input",
"__input__": "folder-input",
"inputs": "folder-input",
".inputs": "folder-input",
"_inputs": "folder-input",
+ "-inputs": "folder-input",
"__inputs__": "folder-input",
"io": "folder-input",
".io": "folder-input",
"_io": "folder-input",
+ "-io": "folder-input",
"__io__": "folder-input",
"in": "folder-input",
".in": "folder-input",
"_in": "folder-input",
+ "-in": "folder-input",
"__in__": "folder-input",
"salt": "folder-salt",
".salt": "folder-salt",
"_salt": "folder-salt",
+ "-salt": "folder-salt",
"__salt__": "folder-salt",
"saltstack": "folder-salt",
".saltstack": "folder-salt",
"_saltstack": "folder-salt",
+ "-saltstack": "folder-salt",
"__saltstack__": "folder-salt",
"simulations": "folder-simulations",
".simulations": "folder-simulations",
"_simulations": "folder-simulations",
+ "-simulations": "folder-simulations",
"__simulations__": "folder-simulations",
"simulation": "folder-simulations",
".simulation": "folder-simulations",
"_simulation": "folder-simulations",
+ "-simulation": "folder-simulations",
"__simulation__": "folder-simulations",
"sim": "folder-simulations",
".sim": "folder-simulations",
"_sim": "folder-simulations",
+ "-sim": "folder-simulations",
"__sim__": "folder-simulations",
"sims": "folder-simulations",
".sims": "folder-simulations",
"_sims": "folder-simulations",
+ "-sims": "folder-simulations",
"__sims__": "folder-simulations",
"metro": "folder-metro",
".metro": "folder-metro",
"_metro": "folder-metro",
+ "-metro": "folder-metro",
"__metro__": "folder-metro",
"filter": "folder-filter",
".filter": "folder-filter",
"_filter": "folder-filter",
+ "-filter": "folder-filter",
"__filter__": "folder-filter",
"filters": "folder-filter",
".filters": "folder-filter",
"_filters": "folder-filter",
+ "-filters": "folder-filter",
"__filters__": "folder-filter",
"toc": "folder-toc",
".toc": "folder-toc",
"_toc": "folder-toc",
+ "-toc": "folder-toc",
"__toc__": "folder-toc",
"table-of-contents": "folder-toc",
".table-of-contents": "folder-toc",
"_table-of-contents": "folder-toc",
+ "-table-of-contents": "folder-toc",
"__table-of-contents__": "folder-toc",
"cue": "folder-cue",
".cue": "folder-cue",
"_cue": "folder-cue",
+ "-cue": "folder-cue",
"__cue__": "folder-cue",
"cues": "folder-cue",
".cues": "folder-cue",
"_cues": "folder-cue",
+ "-cues": "folder-cue",
"__cues__": "folder-cue",
"license": "folder-license",
".license": "folder-license",
"_license": "folder-license",
+ "-license": "folder-license",
"__license__": "folder-license",
"licenses": "folder-license",
".licenses": "folder-license",
"_licenses": "folder-license",
- "__licenses__": "folder-license"
+ "-licenses": "folder-license",
+ "__licenses__": "folder-license",
+ "form": "folder-form",
+ ".form": "folder-form",
+ "_form": "folder-form",
+ "-form": "folder-form",
+ "__form__": "folder-form",
+ "forms": "folder-form",
+ ".forms": "folder-form",
+ "_forms": "folder-form",
+ "-forms": "folder-form",
+ "__forms__": "folder-form"
},
"folderNamesExpanded": {
"rust": "folder-rust-open",
".rust": "folder-rust-open",
"_rust": "folder-rust-open",
+ "-rust": "folder-rust-open",
"__rust__": "folder-rust-open",
"bot": "folder-robot-open",
".bot": "folder-robot-open",
"_bot": "folder-robot-open",
+ "-bot": "folder-robot-open",
"__bot__": "folder-robot-open",
"bots": "folder-robot-open",
".bots": "folder-robot-open",
"_bots": "folder-robot-open",
+ "-bots": "folder-robot-open",
"__bots__": "folder-robot-open",
"robot": "folder-robot-open",
".robot": "folder-robot-open",
"_robot": "folder-robot-open",
+ "-robot": "folder-robot-open",
"__robot__": "folder-robot-open",
"robots": "folder-robot-open",
".robots": "folder-robot-open",
"_robots": "folder-robot-open",
+ "-robots": "folder-robot-open",
"__robots__": "folder-robot-open",
+ "agent": "folder-robot-open",
+ ".agent": "folder-robot-open",
+ "_agent": "folder-robot-open",
+ "-agent": "folder-robot-open",
+ "__agent__": "folder-robot-open",
+ "agents": "folder-robot-open",
+ ".agents": "folder-robot-open",
+ "_agents": "folder-robot-open",
+ "-agents": "folder-robot-open",
+ "__agents__": "folder-robot-open",
"src": "folder-src-open",
".src": "folder-src-open",
"_src": "folder-src-open",
+ "-src": "folder-src-open",
"__src__": "folder-src-open",
"srcs": "folder-src-open",
".srcs": "folder-src-open",
"_srcs": "folder-src-open",
+ "-srcs": "folder-src-open",
"__srcs__": "folder-src-open",
"source": "folder-src-open",
".source": "folder-src-open",
"_source": "folder-src-open",
+ "-source": "folder-src-open",
"__source__": "folder-src-open",
"sources": "folder-src-open",
".sources": "folder-src-open",
"_sources": "folder-src-open",
+ "-sources": "folder-src-open",
"__sources__": "folder-src-open",
"code": "folder-src-open",
".code": "folder-src-open",
"_code": "folder-src-open",
+ "-code": "folder-src-open",
"__code__": "folder-src-open",
"dist": "folder-dist-open",
".dist": "folder-dist-open",
"_dist": "folder-dist-open",
+ "-dist": "folder-dist-open",
"__dist__": "folder-dist-open",
"out": "folder-dist-open",
".out": "folder-dist-open",
"_out": "folder-dist-open",
+ "-out": "folder-dist-open",
"__out__": "folder-dist-open",
"output": "folder-dist-open",
".output": "folder-dist-open",
"_output": "folder-dist-open",
+ "-output": "folder-dist-open",
"__output__": "folder-dist-open",
+ "outputs": "folder-dist-open",
+ ".outputs": "folder-dist-open",
+ "_outputs": "folder-dist-open",
+ "-outputs": "folder-dist-open",
+ "__outputs__": "folder-dist-open",
"build": "folder-dist-open",
".build": "folder-dist-open",
"_build": "folder-dist-open",
+ "-build": "folder-dist-open",
"__build__": "folder-dist-open",
"builds": "folder-dist-open",
".builds": "folder-dist-open",
"_builds": "folder-dist-open",
+ "-builds": "folder-dist-open",
"__builds__": "folder-dist-open",
"release": "folder-dist-open",
".release": "folder-dist-open",
"_release": "folder-dist-open",
+ "-release": "folder-dist-open",
"__release__": "folder-dist-open",
"bin": "folder-dist-open",
".bin": "folder-dist-open",
"_bin": "folder-dist-open",
+ "-bin": "folder-dist-open",
"__bin__": "folder-dist-open",
"distribution": "folder-dist-open",
".distribution": "folder-dist-open",
"_distribution": "folder-dist-open",
+ "-distribution": "folder-dist-open",
"__distribution__": "folder-dist-open",
"built": "folder-dist-open",
".built": "folder-dist-open",
"_built": "folder-dist-open",
+ "-built": "folder-dist-open",
"__built__": "folder-dist-open",
"compiled": "folder-dist-open",
".compiled": "folder-dist-open",
"_compiled": "folder-dist-open",
+ "-compiled": "folder-dist-open",
"__compiled__": "folder-dist-open",
"css": "folder-css-open",
".css": "folder-css-open",
"_css": "folder-css-open",
+ "-css": "folder-css-open",
"__css__": "folder-css-open",
"stylesheet": "folder-css-open",
".stylesheet": "folder-css-open",
"_stylesheet": "folder-css-open",
+ "-stylesheet": "folder-css-open",
"__stylesheet__": "folder-css-open",
"stylesheets": "folder-css-open",
".stylesheets": "folder-css-open",
"_stylesheets": "folder-css-open",
+ "-stylesheets": "folder-css-open",
"__stylesheets__": "folder-css-open",
"style": "folder-css-open",
".style": "folder-css-open",
"_style": "folder-css-open",
+ "-style": "folder-css-open",
"__style__": "folder-css-open",
"styles": "folder-css-open",
".styles": "folder-css-open",
"_styles": "folder-css-open",
+ "-styles": "folder-css-open",
"__styles__": "folder-css-open",
"sass": "folder-sass-open",
".sass": "folder-sass-open",
"_sass": "folder-sass-open",
+ "-sass": "folder-sass-open",
"__sass__": "folder-sass-open",
"scss": "folder-sass-open",
".scss": "folder-sass-open",
"_scss": "folder-sass-open",
+ "-scss": "folder-sass-open",
"__scss__": "folder-sass-open",
"tv": "folder-television-open",
".tv": "folder-television-open",
"_tv": "folder-television-open",
+ "-tv": "folder-television-open",
"__tv__": "folder-television-open",
"television": "folder-television-open",
".television": "folder-television-open",
"_television": "folder-television-open",
+ "-television": "folder-television-open",
"__television__": "folder-television-open",
"desktop": "folder-desktop-open",
".desktop": "folder-desktop-open",
"_desktop": "folder-desktop-open",
+ "-desktop": "folder-desktop-open",
"__desktop__": "folder-desktop-open",
"display": "folder-desktop-open",
".display": "folder-desktop-open",
"_display": "folder-desktop-open",
+ "-display": "folder-desktop-open",
"__display__": "folder-desktop-open",
"console": "folder-console-open",
".console": "folder-console-open",
"_console": "folder-console-open",
+ "-console": "folder-console-open",
"__console__": "folder-console-open",
"xbox": "folder-console-open",
".xbox": "folder-console-open",
"_xbox": "folder-console-open",
+ "-xbox": "folder-console-open",
"__xbox__": "folder-console-open",
"ps4": "folder-console-open",
".ps4": "folder-console-open",
"_ps4": "folder-console-open",
+ "-ps4": "folder-console-open",
"__ps4__": "folder-console-open",
"ps5": "folder-console-open",
".ps5": "folder-console-open",
"_ps5": "folder-console-open",
+ "-ps5": "folder-console-open",
"__ps5__": "folder-console-open",
"switch": "folder-console-open",
".switch": "folder-console-open",
"_switch": "folder-console-open",
+ "-switch": "folder-console-open",
"__switch__": "folder-console-open",
"game": "folder-console-open",
".game": "folder-console-open",
"_game": "folder-console-open",
+ "-game": "folder-console-open",
"__game__": "folder-console-open",
"games": "folder-console-open",
".games": "folder-console-open",
"_games": "folder-console-open",
+ "-games": "folder-console-open",
"__games__": "folder-console-open",
"images": "folder-images-open",
".images": "folder-images-open",
"_images": "folder-images-open",
+ "-images": "folder-images-open",
"__images__": "folder-images-open",
"image": "folder-images-open",
".image": "folder-images-open",
"_image": "folder-images-open",
+ "-image": "folder-images-open",
"__image__": "folder-images-open",
"imgs": "folder-images-open",
".imgs": "folder-images-open",
"_imgs": "folder-images-open",
+ "-imgs": "folder-images-open",
"__imgs__": "folder-images-open",
"img": "folder-images-open",
".img": "folder-images-open",
"_img": "folder-images-open",
+ "-img": "folder-images-open",
"__img__": "folder-images-open",
"icons": "folder-images-open",
".icons": "folder-images-open",
"_icons": "folder-images-open",
+ "-icons": "folder-images-open",
"__icons__": "folder-images-open",
"icon": "folder-images-open",
".icon": "folder-images-open",
"_icon": "folder-images-open",
+ "-icon": "folder-images-open",
"__icon__": "folder-images-open",
"icos": "folder-images-open",
".icos": "folder-images-open",
"_icos": "folder-images-open",
+ "-icos": "folder-images-open",
"__icos__": "folder-images-open",
"ico": "folder-images-open",
".ico": "folder-images-open",
"_ico": "folder-images-open",
+ "-ico": "folder-images-open",
"__ico__": "folder-images-open",
"figures": "folder-images-open",
".figures": "folder-images-open",
"_figures": "folder-images-open",
+ "-figures": "folder-images-open",
"__figures__": "folder-images-open",
"figure": "folder-images-open",
".figure": "folder-images-open",
"_figure": "folder-images-open",
+ "-figure": "folder-images-open",
"__figure__": "folder-images-open",
"figs": "folder-images-open",
".figs": "folder-images-open",
"_figs": "folder-images-open",
+ "-figs": "folder-images-open",
"__figs__": "folder-images-open",
"fig": "folder-images-open",
".fig": "folder-images-open",
"_fig": "folder-images-open",
+ "-fig": "folder-images-open",
"__fig__": "folder-images-open",
"screenshot": "folder-images-open",
".screenshot": "folder-images-open",
"_screenshot": "folder-images-open",
+ "-screenshot": "folder-images-open",
"__screenshot__": "folder-images-open",
"screenshots": "folder-images-open",
".screenshots": "folder-images-open",
"_screenshots": "folder-images-open",
+ "-screenshots": "folder-images-open",
"__screenshots__": "folder-images-open",
"screengrab": "folder-images-open",
".screengrab": "folder-images-open",
"_screengrab": "folder-images-open",
+ "-screengrab": "folder-images-open",
"__screengrab__": "folder-images-open",
"screengrabs": "folder-images-open",
".screengrabs": "folder-images-open",
"_screengrabs": "folder-images-open",
+ "-screengrabs": "folder-images-open",
"__screengrabs__": "folder-images-open",
"pic": "folder-images-open",
".pic": "folder-images-open",
"_pic": "folder-images-open",
+ "-pic": "folder-images-open",
"__pic__": "folder-images-open",
"pics": "folder-images-open",
".pics": "folder-images-open",
"_pics": "folder-images-open",
+ "-pics": "folder-images-open",
"__pics__": "folder-images-open",
"picture": "folder-images-open",
".picture": "folder-images-open",
"_picture": "folder-images-open",
+ "-picture": "folder-images-open",
"__picture__": "folder-images-open",
"pictures": "folder-images-open",
".pictures": "folder-images-open",
"_pictures": "folder-images-open",
+ "-pictures": "folder-images-open",
"__pictures__": "folder-images-open",
"photo": "folder-images-open",
".photo": "folder-images-open",
"_photo": "folder-images-open",
+ "-photo": "folder-images-open",
"__photo__": "folder-images-open",
"photos": "folder-images-open",
".photos": "folder-images-open",
"_photos": "folder-images-open",
+ "-photos": "folder-images-open",
"__photos__": "folder-images-open",
"photograph": "folder-images-open",
".photograph": "folder-images-open",
"_photograph": "folder-images-open",
+ "-photograph": "folder-images-open",
"__photograph__": "folder-images-open",
"photographs": "folder-images-open",
".photographs": "folder-images-open",
"_photographs": "folder-images-open",
+ "-photographs": "folder-images-open",
"__photographs__": "folder-images-open",
"texture": "folder-images-open",
".texture": "folder-images-open",
"_texture": "folder-images-open",
+ "-texture": "folder-images-open",
"__texture__": "folder-images-open",
"textures": "folder-images-open",
".textures": "folder-images-open",
"_textures": "folder-images-open",
+ "-textures": "folder-images-open",
"__textures__": "folder-images-open",
"script": "folder-scripts-open",
".script": "folder-scripts-open",
"_script": "folder-scripts-open",
+ "-script": "folder-scripts-open",
"__script__": "folder-scripts-open",
"scripts": "folder-scripts-open",
".scripts": "folder-scripts-open",
"_scripts": "folder-scripts-open",
+ "-scripts": "folder-scripts-open",
"__scripts__": "folder-scripts-open",
"scripting": "folder-scripts-open",
".scripting": "folder-scripts-open",
"_scripting": "folder-scripts-open",
+ "-scripting": "folder-scripts-open",
"__scripting__": "folder-scripts-open",
"node": "folder-node-open",
".node": "folder-node-open",
"_node": "folder-node-open",
+ "-node": "folder-node-open",
"__node__": "folder-node-open",
"nodejs": "folder-node-open",
".nodejs": "folder-node-open",
"_nodejs": "folder-node-open",
+ "-nodejs": "folder-node-open",
"__nodejs__": "folder-node-open",
"node_modules": "folder-node-open",
".node_modules": "folder-node-open",
"_node_modules": "folder-node-open",
+ "-node_modules": "folder-node-open",
"__node_modules__": "folder-node-open",
"js": "folder-javascript-open",
".js": "folder-javascript-open",
"_js": "folder-javascript-open",
+ "-js": "folder-javascript-open",
"__js__": "folder-javascript-open",
"javascript": "folder-javascript-open",
".javascript": "folder-javascript-open",
"_javascript": "folder-javascript-open",
+ "-javascript": "folder-javascript-open",
"__javascript__": "folder-javascript-open",
"javascripts": "folder-javascript-open",
".javascripts": "folder-javascript-open",
"_javascripts": "folder-javascript-open",
+ "-javascripts": "folder-javascript-open",
"__javascripts__": "folder-javascript-open",
"cjs": "folder-javascript-open",
".cjs": "folder-javascript-open",
"_cjs": "folder-javascript-open",
+ "-cjs": "folder-javascript-open",
"__cjs__": "folder-javascript-open",
"mjs": "folder-javascript-open",
".mjs": "folder-javascript-open",
"_mjs": "folder-javascript-open",
+ "-mjs": "folder-javascript-open",
"__mjs__": "folder-javascript-open",
"json": "folder-json-open",
".json": "folder-json-open",
"_json": "folder-json-open",
+ "-json": "folder-json-open",
"__json__": "folder-json-open",
"jsons": "folder-json-open",
".jsons": "folder-json-open",
"_jsons": "folder-json-open",
+ "-jsons": "folder-json-open",
"__jsons__": "folder-json-open",
"jsonc": "folder-json-open",
".jsonc": "folder-json-open",
"_jsonc": "folder-json-open",
+ "-jsonc": "folder-json-open",
"__jsonc__": "folder-json-open",
"jsonl": "folder-json-open",
".jsonl": "folder-json-open",
"_jsonl": "folder-json-open",
+ "-jsonl": "folder-json-open",
"__jsonl__": "folder-json-open",
"font": "folder-font-open",
".font": "folder-font-open",
"_font": "folder-font-open",
+ "-font": "folder-font-open",
"__font__": "folder-font-open",
"fonts": "folder-font-open",
".fonts": "folder-font-open",
"_fonts": "folder-font-open",
+ "-fonts": "folder-font-open",
"__fonts__": "folder-font-open",
"typeface": "folder-font-open",
".typeface": "folder-font-open",
"_typeface": "folder-font-open",
+ "-typeface": "folder-font-open",
"__typeface__": "folder-font-open",
"typefaces": "folder-font-open",
".typefaces": "folder-font-open",
"_typefaces": "folder-font-open",
+ "-typefaces": "folder-font-open",
"__typefaces__": "folder-font-open",
"bower_components": "folder-bower-open",
".bower_components": "folder-bower-open",
"_bower_components": "folder-bower-open",
+ "-bower_components": "folder-bower-open",
"__bower_components__": "folder-bower-open",
"test": "folder-test-open",
".test": "folder-test-open",
"_test": "folder-test-open",
+ "-test": "folder-test-open",
"__test__": "folder-test-open",
"tests": "folder-test-open",
".tests": "folder-test-open",
"_tests": "folder-test-open",
+ "-tests": "folder-test-open",
"__tests__": "folder-test-open",
"testing": "folder-test-open",
".testing": "folder-test-open",
"_testing": "folder-test-open",
+ "-testing": "folder-test-open",
"__testing__": "folder-test-open",
"snapshots": "folder-test-open",
".snapshots": "folder-test-open",
"_snapshots": "folder-test-open",
+ "-snapshots": "folder-test-open",
"__snapshots__": "folder-test-open",
"spec": "folder-test-open",
".spec": "folder-test-open",
"_spec": "folder-test-open",
+ "-spec": "folder-test-open",
"__spec__": "folder-test-open",
"specs": "folder-test-open",
".specs": "folder-test-open",
"_specs": "folder-test-open",
+ "-specs": "folder-test-open",
"__specs__": "folder-test-open",
"testfiles": "folder-test-open",
".testfiles": "folder-test-open",
"_testfiles": "folder-test-open",
+ "-testfiles": "folder-test-open",
"__testfiles__": "folder-test-open",
"directive": "folder-directive-open",
".directive": "folder-directive-open",
"_directive": "folder-directive-open",
+ "-directive": "folder-directive-open",
"__directive__": "folder-directive-open",
"directives": "folder-directive-open",
".directives": "folder-directive-open",
"_directives": "folder-directive-open",
+ "-directives": "folder-directive-open",
"__directives__": "folder-directive-open",
"jinja": "folder-jinja-open",
".jinja": "folder-jinja-open",
"_jinja": "folder-jinja-open",
+ "-jinja": "folder-jinja-open",
"__jinja__": "folder-jinja-open",
"jinja2": "folder-jinja-open",
".jinja2": "folder-jinja-open",
"_jinja2": "folder-jinja-open",
+ "-jinja2": "folder-jinja-open",
"__jinja2__": "folder-jinja-open",
"j2": "folder-jinja-open",
".j2": "folder-jinja-open",
"_j2": "folder-jinja-open",
+ "-j2": "folder-jinja-open",
"__j2__": "folder-jinja-open",
"markdown": "folder-markdown-open",
".markdown": "folder-markdown-open",
"_markdown": "folder-markdown-open",
+ "-markdown": "folder-markdown-open",
"__markdown__": "folder-markdown-open",
"md": "folder-markdown-open",
".md": "folder-markdown-open",
"_md": "folder-markdown-open",
+ "-md": "folder-markdown-open",
"__md__": "folder-markdown-open",
"pdm-plugins": "folder-pdm-open",
".pdm-plugins": "folder-pdm-open",
"_pdm-plugins": "folder-pdm-open",
+ "-pdm-plugins": "folder-pdm-open",
"__pdm-plugins__": "folder-pdm-open",
"pdm-build": "folder-pdm-open",
".pdm-build": "folder-pdm-open",
"_pdm-build": "folder-pdm-open",
+ "-pdm-build": "folder-pdm-open",
"__pdm-build__": "folder-pdm-open",
"php": "folder-php-open",
".php": "folder-php-open",
"_php": "folder-php-open",
+ "-php": "folder-php-open",
"__php__": "folder-php-open",
"phpmailer": "folder-phpmailer-open",
".phpmailer": "folder-phpmailer-open",
"_phpmailer": "folder-phpmailer-open",
+ "-phpmailer": "folder-phpmailer-open",
"__phpmailer__": "folder-phpmailer-open",
"sublime": "folder-sublime-open",
".sublime": "folder-sublime-open",
"_sublime": "folder-sublime-open",
+ "-sublime": "folder-sublime-open",
"__sublime__": "folder-sublime-open",
"doc": "folder-docs-open",
".doc": "folder-docs-open",
"_doc": "folder-docs-open",
+ "-doc": "folder-docs-open",
"__doc__": "folder-docs-open",
"docs": "folder-docs-open",
".docs": "folder-docs-open",
"_docs": "folder-docs-open",
+ "-docs": "folder-docs-open",
"__docs__": "folder-docs-open",
"document": "folder-docs-open",
".document": "folder-docs-open",
"_document": "folder-docs-open",
+ "-document": "folder-docs-open",
"__document__": "folder-docs-open",
"documents": "folder-docs-open",
".documents": "folder-docs-open",
"_documents": "folder-docs-open",
+ "-documents": "folder-docs-open",
"__documents__": "folder-docs-open",
"documentation": "folder-docs-open",
".documentation": "folder-docs-open",
"_documentation": "folder-docs-open",
+ "-documentation": "folder-docs-open",
"__documentation__": "folder-docs-open",
"post": "folder-docs-open",
".post": "folder-docs-open",
"_post": "folder-docs-open",
+ "-post": "folder-docs-open",
"__post__": "folder-docs-open",
"posts": "folder-docs-open",
".posts": "folder-docs-open",
"_posts": "folder-docs-open",
+ "-posts": "folder-docs-open",
"__posts__": "folder-docs-open",
"article": "folder-docs-open",
".article": "folder-docs-open",
"_article": "folder-docs-open",
+ "-article": "folder-docs-open",
"__article__": "folder-docs-open",
"articles": "folder-docs-open",
".articles": "folder-docs-open",
"_articles": "folder-docs-open",
+ "-articles": "folder-docs-open",
"__articles__": "folder-docs-open",
"wiki": "folder-docs-open",
".wiki": "folder-docs-open",
"_wiki": "folder-docs-open",
+ "-wiki": "folder-docs-open",
"__wiki__": "folder-docs-open",
"news": "folder-docs-open",
".news": "folder-docs-open",
"_news": "folder-docs-open",
+ "-news": "folder-docs-open",
"__news__": "folder-docs-open",
"blog": "folder-docs-open",
".blog": "folder-docs-open",
"_blog": "folder-docs-open",
+ "-blog": "folder-docs-open",
"__blog__": "folder-docs-open",
"knowledge": "folder-docs-open",
".knowledge": "folder-docs-open",
"_knowledge": "folder-docs-open",
+ "-knowledge": "folder-docs-open",
"__knowledge__": "folder-docs-open",
"diary": "folder-docs-open",
".diary": "folder-docs-open",
"_diary": "folder-docs-open",
+ "-diary": "folder-docs-open",
"__diary__": "folder-docs-open",
"note": "folder-docs-open",
".note": "folder-docs-open",
"_note": "folder-docs-open",
+ "-note": "folder-docs-open",
"__note__": "folder-docs-open",
"notes": "folder-docs-open",
".notes": "folder-docs-open",
"_notes": "folder-docs-open",
+ "-notes": "folder-docs-open",
"__notes__": "folder-docs-open",
"github/workflows": "folder-gh-workflows-open",
".github/workflows": "folder-gh-workflows-open",
"_github/workflows": "folder-gh-workflows-open",
+ "-github/workflows": "folder-gh-workflows-open",
"__github/workflows__": "folder-gh-workflows-open",
"git": "folder-git-open",
".git": "folder-git-open",
"_git": "folder-git-open",
+ "-git": "folder-git-open",
"__git__": "folder-git-open",
"patches": "folder-git-open",
".patches": "folder-git-open",
"_patches": "folder-git-open",
+ "-patches": "folder-git-open",
"__patches__": "folder-git-open",
"githooks": "folder-git-open",
".githooks": "folder-git-open",
"_githooks": "folder-git-open",
+ "-githooks": "folder-git-open",
"__githooks__": "folder-git-open",
"submodules": "folder-git-open",
".submodules": "folder-git-open",
"_submodules": "folder-git-open",
+ "-submodules": "folder-git-open",
"__submodules__": "folder-git-open",
"github": "folder-github-open",
".github": "folder-github-open",
"_github": "folder-github-open",
+ "-github": "folder-github-open",
"__github__": "folder-github-open",
"gitea": "folder-gitea-open",
".gitea": "folder-gitea-open",
"_gitea": "folder-gitea-open",
+ "-gitea": "folder-gitea-open",
"__gitea__": "folder-gitea-open",
"gitlab": "folder-gitlab-open",
".gitlab": "folder-gitlab-open",
"_gitlab": "folder-gitlab-open",
+ "-gitlab": "folder-gitlab-open",
"__gitlab__": "folder-gitlab-open",
"forgejo": "folder-forgejo-open",
".forgejo": "folder-forgejo-open",
"_forgejo": "folder-forgejo-open",
+ "-forgejo": "folder-forgejo-open",
"__forgejo__": "folder-forgejo-open",
"vscode": "folder-vscode-open",
".vscode": "folder-vscode-open",
"_vscode": "folder-vscode-open",
+ "-vscode": "folder-vscode-open",
"__vscode__": "folder-vscode-open",
"vscode-test": "folder-vscode-open",
".vscode-test": "folder-vscode-open",
"_vscode-test": "folder-vscode-open",
+ "-vscode-test": "folder-vscode-open",
"__vscode-test__": "folder-vscode-open",
"view": "folder-views-open",
".view": "folder-views-open",
"_view": "folder-views-open",
+ "-view": "folder-views-open",
"__view__": "folder-views-open",
"views": "folder-views-open",
".views": "folder-views-open",
"_views": "folder-views-open",
+ "-views": "folder-views-open",
"__views__": "folder-views-open",
"screen": "folder-views-open",
".screen": "folder-views-open",
"_screen": "folder-views-open",
+ "-screen": "folder-views-open",
"__screen__": "folder-views-open",
"screens": "folder-views-open",
".screens": "folder-views-open",
"_screens": "folder-views-open",
+ "-screens": "folder-views-open",
"__screens__": "folder-views-open",
"page": "folder-views-open",
".page": "folder-views-open",
"_page": "folder-views-open",
+ "-page": "folder-views-open",
"__page__": "folder-views-open",
"pages": "folder-views-open",
".pages": "folder-views-open",
"_pages": "folder-views-open",
+ "-pages": "folder-views-open",
"__pages__": "folder-views-open",
"public_html": "folder-views-open",
".public_html": "folder-views-open",
"_public_html": "folder-views-open",
+ "-public_html": "folder-views-open",
"__public_html__": "folder-views-open",
"html": "folder-views-open",
".html": "folder-views-open",
"_html": "folder-views-open",
+ "-html": "folder-views-open",
"__html__": "folder-views-open",
"vue": "folder-vue-open",
".vue": "folder-vue-open",
"_vue": "folder-vue-open",
+ "-vue": "folder-vue-open",
"__vue__": "folder-vue-open",
"vuepress": "folder-vuepress-open",
".vuepress": "folder-vuepress-open",
"_vuepress": "folder-vuepress-open",
+ "-vuepress": "folder-vuepress-open",
"__vuepress__": "folder-vuepress-open",
"expo": "folder-expo-open",
".expo": "folder-expo-open",
"_expo": "folder-expo-open",
+ "-expo": "folder-expo-open",
"__expo__": "folder-expo-open",
"expo-shared": "folder-expo-open",
".expo-shared": "folder-expo-open",
"_expo-shared": "folder-expo-open",
+ "-expo-shared": "folder-expo-open",
"__expo-shared__": "folder-expo-open",
"cfg": "folder-config-open",
".cfg": "folder-config-open",
"_cfg": "folder-config-open",
+ "-cfg": "folder-config-open",
"__cfg__": "folder-config-open",
"cfgs": "folder-config-open",
".cfgs": "folder-config-open",
"_cfgs": "folder-config-open",
+ "-cfgs": "folder-config-open",
"__cfgs__": "folder-config-open",
"conf": "folder-config-open",
".conf": "folder-config-open",
"_conf": "folder-config-open",
+ "-conf": "folder-config-open",
"__conf__": "folder-config-open",
"confs": "folder-config-open",
".confs": "folder-config-open",
"_confs": "folder-config-open",
+ "-confs": "folder-config-open",
"__confs__": "folder-config-open",
"config": "folder-config-open",
".config": "folder-config-open",
"_config": "folder-config-open",
+ "-config": "folder-config-open",
"__config__": "folder-config-open",
"configs": "folder-config-open",
".configs": "folder-config-open",
"_configs": "folder-config-open",
+ "-configs": "folder-config-open",
"__configs__": "folder-config-open",
"configuration": "folder-config-open",
".configuration": "folder-config-open",
"_configuration": "folder-config-open",
+ "-configuration": "folder-config-open",
"__configuration__": "folder-config-open",
"configurations": "folder-config-open",
".configurations": "folder-config-open",
"_configurations": "folder-config-open",
+ "-configurations": "folder-config-open",
"__configurations__": "folder-config-open",
"setting": "folder-config-open",
".setting": "folder-config-open",
"_setting": "folder-config-open",
+ "-setting": "folder-config-open",
"__setting__": "folder-config-open",
"settings": "folder-config-open",
".settings": "folder-config-open",
"_settings": "folder-config-open",
+ "-settings": "folder-config-open",
"__settings__": "folder-config-open",
"META-INF": "folder-config-open",
".META-INF": "folder-config-open",
"_META-INF": "folder-config-open",
+ "-META-INF": "folder-config-open",
"__META-INF__": "folder-config-open",
"option": "folder-config-open",
".option": "folder-config-open",
"_option": "folder-config-open",
+ "-option": "folder-config-open",
"__option__": "folder-config-open",
"options": "folder-config-open",
".options": "folder-config-open",
"_options": "folder-config-open",
+ "-options": "folder-config-open",
"__options__": "folder-config-open",
"pref": "folder-config-open",
".pref": "folder-config-open",
"_pref": "folder-config-open",
+ "-pref": "folder-config-open",
"__pref__": "folder-config-open",
"prefs": "folder-config-open",
".prefs": "folder-config-open",
"_prefs": "folder-config-open",
+ "-prefs": "folder-config-open",
"__prefs__": "folder-config-open",
"preference": "folder-config-open",
".preference": "folder-config-open",
"_preference": "folder-config-open",
+ "-preference": "folder-config-open",
"__preference__": "folder-config-open",
"preferences": "folder-config-open",
".preferences": "folder-config-open",
"_preferences": "folder-config-open",
+ "-preferences": "folder-config-open",
"__preferences__": "folder-config-open",
"props": "folder-config-open",
".props": "folder-config-open",
"_props": "folder-config-open",
+ "-props": "folder-config-open",
"__props__": "folder-config-open",
"properties": "folder-config-open",
".properties": "folder-config-open",
"_properties": "folder-config-open",
+ "-properties": "folder-config-open",
"__properties__": "folder-config-open",
"i18n": "folder-i18n-open",
".i18n": "folder-i18n-open",
"_i18n": "folder-i18n-open",
+ "-i18n": "folder-i18n-open",
"__i18n__": "folder-i18n-open",
"internationalization": "folder-i18n-open",
".internationalization": "folder-i18n-open",
"_internationalization": "folder-i18n-open",
+ "-internationalization": "folder-i18n-open",
"__internationalization__": "folder-i18n-open",
"lang": "folder-i18n-open",
".lang": "folder-i18n-open",
"_lang": "folder-i18n-open",
+ "-lang": "folder-i18n-open",
"__lang__": "folder-i18n-open",
"langs": "folder-i18n-open",
".langs": "folder-i18n-open",
"_langs": "folder-i18n-open",
+ "-langs": "folder-i18n-open",
"__langs__": "folder-i18n-open",
"language": "folder-i18n-open",
".language": "folder-i18n-open",
"_language": "folder-i18n-open",
+ "-language": "folder-i18n-open",
"__language__": "folder-i18n-open",
"languages": "folder-i18n-open",
".languages": "folder-i18n-open",
"_languages": "folder-i18n-open",
+ "-languages": "folder-i18n-open",
"__languages__": "folder-i18n-open",
"locale": "folder-i18n-open",
".locale": "folder-i18n-open",
"_locale": "folder-i18n-open",
+ "-locale": "folder-i18n-open",
"__locale__": "folder-i18n-open",
"locales": "folder-i18n-open",
".locales": "folder-i18n-open",
"_locales": "folder-i18n-open",
+ "-locales": "folder-i18n-open",
"__locales__": "folder-i18n-open",
"l10n": "folder-i18n-open",
".l10n": "folder-i18n-open",
"_l10n": "folder-i18n-open",
+ "-l10n": "folder-i18n-open",
"__l10n__": "folder-i18n-open",
"localization": "folder-i18n-open",
".localization": "folder-i18n-open",
"_localization": "folder-i18n-open",
+ "-localization": "folder-i18n-open",
"__localization__": "folder-i18n-open",
"translation": "folder-i18n-open",
".translation": "folder-i18n-open",
"_translation": "folder-i18n-open",
+ "-translation": "folder-i18n-open",
"__translation__": "folder-i18n-open",
"translate": "folder-i18n-open",
".translate": "folder-i18n-open",
"_translate": "folder-i18n-open",
+ "-translate": "folder-i18n-open",
"__translate__": "folder-i18n-open",
"translations": "folder-i18n-open",
".translations": "folder-i18n-open",
"_translations": "folder-i18n-open",
+ "-translations": "folder-i18n-open",
"__translations__": "folder-i18n-open",
"tx": "folder-i18n-open",
".tx": "folder-i18n-open",
"_tx": "folder-i18n-open",
+ "-tx": "folder-i18n-open",
"__tx__": "folder-i18n-open",
"components": "folder-components-open",
".components": "folder-components-open",
"_components": "folder-components-open",
+ "-components": "folder-components-open",
"__components__": "folder-components-open",
"widget": "folder-components-open",
".widget": "folder-components-open",
"_widget": "folder-components-open",
+ "-widget": "folder-components-open",
"__widget__": "folder-components-open",
"widgets": "folder-components-open",
".widgets": "folder-components-open",
"_widgets": "folder-components-open",
+ "-widgets": "folder-components-open",
"__widgets__": "folder-components-open",
"fragments": "folder-components-open",
".fragments": "folder-components-open",
"_fragments": "folder-components-open",
+ "-fragments": "folder-components-open",
"__fragments__": "folder-components-open",
"verdaccio": "folder-verdaccio-open",
".verdaccio": "folder-verdaccio-open",
"_verdaccio": "folder-verdaccio-open",
+ "-verdaccio": "folder-verdaccio-open",
"__verdaccio__": "folder-verdaccio-open",
"aurelia_project": "folder-aurelia-open",
".aurelia_project": "folder-aurelia-open",
"_aurelia_project": "folder-aurelia-open",
+ "-aurelia_project": "folder-aurelia-open",
"__aurelia_project__": "folder-aurelia-open",
"resource": "folder-resource-open",
".resource": "folder-resource-open",
"_resource": "folder-resource-open",
+ "-resource": "folder-resource-open",
"__resource__": "folder-resource-open",
"resources": "folder-resource-open",
".resources": "folder-resource-open",
"_resources": "folder-resource-open",
+ "-resources": "folder-resource-open",
"__resources__": "folder-resource-open",
"res": "folder-resource-open",
".res": "folder-resource-open",
"_res": "folder-resource-open",
+ "-res": "folder-resource-open",
"__res__": "folder-resource-open",
"asset": "folder-resource-open",
".asset": "folder-resource-open",
"_asset": "folder-resource-open",
+ "-asset": "folder-resource-open",
"__asset__": "folder-resource-open",
"assets": "folder-resource-open",
".assets": "folder-resource-open",
"_assets": "folder-resource-open",
+ "-assets": "folder-resource-open",
"__assets__": "folder-resource-open",
"static": "folder-resource-open",
".static": "folder-resource-open",
"_static": "folder-resource-open",
+ "-static": "folder-resource-open",
"__static__": "folder-resource-open",
"report": "folder-resource-open",
".report": "folder-resource-open",
"_report": "folder-resource-open",
+ "-report": "folder-resource-open",
"__report__": "folder-resource-open",
"reports": "folder-resource-open",
".reports": "folder-resource-open",
"_reports": "folder-resource-open",
+ "-reports": "folder-resource-open",
"__reports__": "folder-resource-open",
"lib": "folder-lib-open",
".lib": "folder-lib-open",
"_lib": "folder-lib-open",
+ "-lib": "folder-lib-open",
"__lib__": "folder-lib-open",
"libs": "folder-lib-open",
".libs": "folder-lib-open",
"_libs": "folder-lib-open",
+ "-libs": "folder-lib-open",
"__libs__": "folder-lib-open",
"library": "folder-lib-open",
".library": "folder-lib-open",
"_library": "folder-lib-open",
+ "-library": "folder-lib-open",
"__library__": "folder-lib-open",
"libraries": "folder-lib-open",
".libraries": "folder-lib-open",
"_libraries": "folder-lib-open",
+ "-libraries": "folder-lib-open",
"__libraries__": "folder-lib-open",
"vendor": "folder-lib-open",
".vendor": "folder-lib-open",
"_vendor": "folder-lib-open",
+ "-vendor": "folder-lib-open",
"__vendor__": "folder-lib-open",
"vendors": "folder-lib-open",
".vendors": "folder-lib-open",
"_vendors": "folder-lib-open",
+ "-vendors": "folder-lib-open",
"__vendors__": "folder-lib-open",
"third-party": "folder-lib-open",
".third-party": "folder-lib-open",
"_third-party": "folder-lib-open",
+ "-third-party": "folder-lib-open",
"__third-party__": "folder-lib-open",
"lib64": "folder-lib-open",
".lib64": "folder-lib-open",
"_lib64": "folder-lib-open",
+ "-lib64": "folder-lib-open",
"__lib64__": "folder-lib-open",
"themes": "folder-theme-open",
".themes": "folder-theme-open",
"_themes": "folder-theme-open",
+ "-themes": "folder-theme-open",
"__themes__": "folder-theme-open",
"theme": "folder-theme-open",
".theme": "folder-theme-open",
"_theme": "folder-theme-open",
+ "-theme": "folder-theme-open",
"__theme__": "folder-theme-open",
"color": "folder-theme-open",
".color": "folder-theme-open",
"_color": "folder-theme-open",
+ "-color": "folder-theme-open",
"__color__": "folder-theme-open",
"colors": "folder-theme-open",
".colors": "folder-theme-open",
"_colors": "folder-theme-open",
+ "-colors": "folder-theme-open",
"__colors__": "folder-theme-open",
"colour": "folder-theme-open",
".colour": "folder-theme-open",
"_colour": "folder-theme-open",
+ "-colour": "folder-theme-open",
"__colour__": "folder-theme-open",
"colours": "folder-theme-open",
".colours": "folder-theme-open",
"_colours": "folder-theme-open",
+ "-colours": "folder-theme-open",
"__colours__": "folder-theme-open",
"design": "folder-theme-open",
".design": "folder-theme-open",
"_design": "folder-theme-open",
+ "-design": "folder-theme-open",
"__design__": "folder-theme-open",
"designs": "folder-theme-open",
".designs": "folder-theme-open",
"_designs": "folder-theme-open",
+ "-designs": "folder-theme-open",
"__designs__": "folder-theme-open",
"palette": "folder-theme-open",
".palette": "folder-theme-open",
"_palette": "folder-theme-open",
+ "-palette": "folder-theme-open",
"__palette__": "folder-theme-open",
"palettes": "folder-theme-open",
".palettes": "folder-theme-open",
"_palettes": "folder-theme-open",
+ "-palettes": "folder-theme-open",
"__palettes__": "folder-theme-open",
"webpack": "folder-webpack-open",
".webpack": "folder-webpack-open",
"_webpack": "folder-webpack-open",
+ "-webpack": "folder-webpack-open",
"__webpack__": "folder-webpack-open",
"global": "folder-global-open",
".global": "folder-global-open",
"_global": "folder-global-open",
+ "-global": "folder-global-open",
"__global__": "folder-global-open",
"public": "folder-public-open",
".public": "folder-public-open",
"_public": "folder-public-open",
+ "-public": "folder-public-open",
"__public__": "folder-public-open",
"www": "folder-public-open",
".www": "folder-public-open",
"_www": "folder-public-open",
+ "-www": "folder-public-open",
"__www__": "folder-public-open",
"wwwroot": "folder-public-open",
".wwwroot": "folder-public-open",
"_wwwroot": "folder-public-open",
+ "-wwwroot": "folder-public-open",
"__wwwroot__": "folder-public-open",
"web": "folder-public-open",
".web": "folder-public-open",
"_web": "folder-public-open",
+ "-web": "folder-public-open",
"__web__": "folder-public-open",
"website": "folder-public-open",
".website": "folder-public-open",
"_website": "folder-public-open",
+ "-website": "folder-public-open",
"__website__": "folder-public-open",
"websites": "folder-public-open",
".websites": "folder-public-open",
"_websites": "folder-public-open",
+ "-websites": "folder-public-open",
"__websites__": "folder-public-open",
"site": "folder-public-open",
".site": "folder-public-open",
"_site": "folder-public-open",
+ "-site": "folder-public-open",
"__site__": "folder-public-open",
"browser": "folder-public-open",
".browser": "folder-public-open",
"_browser": "folder-public-open",
+ "-browser": "folder-public-open",
"__browser__": "folder-public-open",
"browsers": "folder-public-open",
".browsers": "folder-public-open",
"_browsers": "folder-public-open",
+ "-browsers": "folder-public-open",
"__browsers__": "folder-public-open",
+ "proxy": "folder-public-open",
+ ".proxy": "folder-public-open",
+ "_proxy": "folder-public-open",
+ "-proxy": "folder-public-open",
+ "__proxy__": "folder-public-open",
"inc": "folder-include-open",
".inc": "folder-include-open",
"_inc": "folder-include-open",
+ "-inc": "folder-include-open",
"__inc__": "folder-include-open",
"include": "folder-include-open",
".include": "folder-include-open",
"_include": "folder-include-open",
+ "-include": "folder-include-open",
"__include__": "folder-include-open",
"includes": "folder-include-open",
".includes": "folder-include-open",
"_includes": "folder-include-open",
+ "-includes": "folder-include-open",
"__includes__": "folder-include-open",
"partial": "folder-include-open",
".partial": "folder-include-open",
"_partial": "folder-include-open",
+ "-partial": "folder-include-open",
"__partial__": "folder-include-open",
"partials": "folder-include-open",
".partials": "folder-include-open",
"_partials": "folder-include-open",
+ "-partials": "folder-include-open",
"__partials__": "folder-include-open",
"inc64": "folder-include-open",
".inc64": "folder-include-open",
"_inc64": "folder-include-open",
+ "-inc64": "folder-include-open",
"__inc64__": "folder-include-open",
"docker": "folder-docker-open",
".docker": "folder-docker-open",
"_docker": "folder-docker-open",
+ "-docker": "folder-docker-open",
"__docker__": "folder-docker-open",
"dockerfiles": "folder-docker-open",
".dockerfiles": "folder-docker-open",
"_dockerfiles": "folder-docker-open",
+ "-dockerfiles": "folder-docker-open",
"__dockerfiles__": "folder-docker-open",
"dockerhub": "folder-docker-open",
".dockerhub": "folder-docker-open",
"_dockerhub": "folder-docker-open",
+ "-dockerhub": "folder-docker-open",
"__dockerhub__": "folder-docker-open",
"astro": "folder-astro-open",
".astro": "folder-astro-open",
"_astro": "folder-astro-open",
+ "-astro": "folder-astro-open",
"__astro__": "folder-astro-open",
"db": "folder-database-open",
".db": "folder-database-open",
"_db": "folder-database-open",
+ "-db": "folder-database-open",
"__db__": "folder-database-open",
"data": "folder-database-open",
".data": "folder-database-open",
"_data": "folder-database-open",
+ "-data": "folder-database-open",
"__data__": "folder-database-open",
"database": "folder-database-open",
".database": "folder-database-open",
"_database": "folder-database-open",
+ "-database": "folder-database-open",
"__database__": "folder-database-open",
"databases": "folder-database-open",
".databases": "folder-database-open",
"_databases": "folder-database-open",
+ "-databases": "folder-database-open",
"__databases__": "folder-database-open",
"sql": "folder-database-open",
".sql": "folder-database-open",
"_sql": "folder-database-open",
+ "-sql": "folder-database-open",
"__sql__": "folder-database-open",
"migrations": "folder-migrations-open",
".migrations": "folder-migrations-open",
"_migrations": "folder-migrations-open",
+ "-migrations": "folder-migrations-open",
"__migrations__": "folder-migrations-open",
"migration": "folder-migrations-open",
".migration": "folder-migrations-open",
"_migration": "folder-migrations-open",
+ "-migration": "folder-migrations-open",
"__migration__": "folder-migrations-open",
"log": "folder-log-open",
".log": "folder-log-open",
"_log": "folder-log-open",
+ "-log": "folder-log-open",
"__log__": "folder-log-open",
"logs": "folder-log-open",
".logs": "folder-log-open",
"_logs": "folder-log-open",
+ "-logs": "folder-log-open",
"__logs__": "folder-log-open",
"logging": "folder-log-open",
".logging": "folder-log-open",
"_logging": "folder-log-open",
+ "-logging": "folder-log-open",
"__logging__": "folder-log-open",
"target": "folder-target-open",
".target": "folder-target-open",
"_target": "folder-target-open",
+ "-target": "folder-target-open",
"__target__": "folder-target-open",
"temp": "folder-temp-open",
".temp": "folder-temp-open",
"_temp": "folder-temp-open",
+ "-temp": "folder-temp-open",
"__temp__": "folder-temp-open",
"tmp": "folder-temp-open",
".tmp": "folder-temp-open",
"_tmp": "folder-temp-open",
+ "-tmp": "folder-temp-open",
"__tmp__": "folder-temp-open",
"cached": "folder-temp-open",
".cached": "folder-temp-open",
"_cached": "folder-temp-open",
+ "-cached": "folder-temp-open",
"__cached__": "folder-temp-open",
"cache": "folder-temp-open",
".cache": "folder-temp-open",
"_cache": "folder-temp-open",
+ "-cache": "folder-temp-open",
"__cache__": "folder-temp-open",
"aws": "folder-aws-open",
".aws": "folder-aws-open",
"_aws": "folder-aws-open",
+ "-aws": "folder-aws-open",
"__aws__": "folder-aws-open",
"azure": "folder-aws-open",
".azure": "folder-aws-open",
"_azure": "folder-aws-open",
+ "-azure": "folder-aws-open",
"__azure__": "folder-aws-open",
"gcp": "folder-aws-open",
".gcp": "folder-aws-open",
"_gcp": "folder-aws-open",
+ "-gcp": "folder-aws-open",
"__gcp__": "folder-aws-open",
"aud": "folder-audio-open",
".aud": "folder-audio-open",
"_aud": "folder-audio-open",
+ "-aud": "folder-audio-open",
"__aud__": "folder-audio-open",
"auds": "folder-audio-open",
".auds": "folder-audio-open",
"_auds": "folder-audio-open",
+ "-auds": "folder-audio-open",
"__auds__": "folder-audio-open",
"audio": "folder-audio-open",
".audio": "folder-audio-open",
"_audio": "folder-audio-open",
+ "-audio": "folder-audio-open",
"__audio__": "folder-audio-open",
"audios": "folder-audio-open",
".audios": "folder-audio-open",
"_audios": "folder-audio-open",
+ "-audios": "folder-audio-open",
"__audios__": "folder-audio-open",
"music": "folder-audio-open",
".music": "folder-audio-open",
"_music": "folder-audio-open",
+ "-music": "folder-audio-open",
"__music__": "folder-audio-open",
"song": "folder-audio-open",
".song": "folder-audio-open",
"_song": "folder-audio-open",
+ "-song": "folder-audio-open",
"__song__": "folder-audio-open",
"songs": "folder-audio-open",
".songs": "folder-audio-open",
"_songs": "folder-audio-open",
+ "-songs": "folder-audio-open",
"__songs__": "folder-audio-open",
"sound": "folder-audio-open",
".sound": "folder-audio-open",
"_sound": "folder-audio-open",
+ "-sound": "folder-audio-open",
"__sound__": "folder-audio-open",
"sounds": "folder-audio-open",
".sounds": "folder-audio-open",
"_sounds": "folder-audio-open",
+ "-sounds": "folder-audio-open",
"__sounds__": "folder-audio-open",
"voice": "folder-audio-open",
".voice": "folder-audio-open",
"_voice": "folder-audio-open",
+ "-voice": "folder-audio-open",
"__voice__": "folder-audio-open",
"voices": "folder-audio-open",
".voices": "folder-audio-open",
"_voices": "folder-audio-open",
+ "-voices": "folder-audio-open",
"__voices__": "folder-audio-open",
"recordings": "folder-audio-open",
".recordings": "folder-audio-open",
"_recordings": "folder-audio-open",
+ "-recordings": "folder-audio-open",
"__recordings__": "folder-audio-open",
"playlist": "folder-audio-open",
".playlist": "folder-audio-open",
"_playlist": "folder-audio-open",
+ "-playlist": "folder-audio-open",
"__playlist__": "folder-audio-open",
"playlists": "folder-audio-open",
".playlists": "folder-audio-open",
"_playlists": "folder-audio-open",
+ "-playlists": "folder-audio-open",
"__playlists__": "folder-audio-open",
"vid": "folder-video-open",
".vid": "folder-video-open",
"_vid": "folder-video-open",
+ "-vid": "folder-video-open",
"__vid__": "folder-video-open",
"vids": "folder-video-open",
".vids": "folder-video-open",
"_vids": "folder-video-open",
+ "-vids": "folder-video-open",
"__vids__": "folder-video-open",
"video": "folder-video-open",
".video": "folder-video-open",
"_video": "folder-video-open",
+ "-video": "folder-video-open",
"__video__": "folder-video-open",
"videos": "folder-video-open",
".videos": "folder-video-open",
"_videos": "folder-video-open",
+ "-videos": "folder-video-open",
"__videos__": "folder-video-open",
"movie": "folder-video-open",
".movie": "folder-video-open",
"_movie": "folder-video-open",
+ "-movie": "folder-video-open",
"__movie__": "folder-video-open",
"movies": "folder-video-open",
".movies": "folder-video-open",
"_movies": "folder-video-open",
+ "-movies": "folder-video-open",
"__movies__": "folder-video-open",
"media": "folder-video-open",
".media": "folder-video-open",
"_media": "folder-video-open",
+ "-media": "folder-video-open",
"__media__": "folder-video-open",
"kubernetes": "folder-kubernetes-open",
".kubernetes": "folder-kubernetes-open",
"_kubernetes": "folder-kubernetes-open",
+ "-kubernetes": "folder-kubernetes-open",
"__kubernetes__": "folder-kubernetes-open",
"k8s": "folder-kubernetes-open",
".k8s": "folder-kubernetes-open",
"_k8s": "folder-kubernetes-open",
+ "-k8s": "folder-kubernetes-open",
"__k8s__": "folder-kubernetes-open",
"import": "folder-import-open",
".import": "folder-import-open",
"_import": "folder-import-open",
+ "-import": "folder-import-open",
"__import__": "folder-import-open",
"imports": "folder-import-open",
".imports": "folder-import-open",
"_imports": "folder-import-open",
+ "-imports": "folder-import-open",
"__imports__": "folder-import-open",
"imported": "folder-import-open",
".imported": "folder-import-open",
"_imported": "folder-import-open",
+ "-imported": "folder-import-open",
"__imported__": "folder-import-open",
"export": "folder-export-open",
".export": "folder-export-open",
"_export": "folder-export-open",
+ "-export": "folder-export-open",
"__export__": "folder-export-open",
"exports": "folder-export-open",
".exports": "folder-export-open",
"_exports": "folder-export-open",
+ "-exports": "folder-export-open",
"__exports__": "folder-export-open",
"exported": "folder-export-open",
".exported": "folder-export-open",
"_exported": "folder-export-open",
+ "-exported": "folder-export-open",
"__exported__": "folder-export-open",
"wakatime": "folder-wakatime-open",
".wakatime": "folder-wakatime-open",
"_wakatime": "folder-wakatime-open",
+ "-wakatime": "folder-wakatime-open",
"__wakatime__": "folder-wakatime-open",
"circleci": "folder-circleci-open",
".circleci": "folder-circleci-open",
"_circleci": "folder-circleci-open",
+ "-circleci": "folder-circleci-open",
"__circleci__": "folder-circleci-open",
"wordpress-org": "folder-wordpress-open",
".wordpress-org": "folder-wordpress-open",
"_wordpress-org": "folder-wordpress-open",
+ "-wordpress-org": "folder-wordpress-open",
"__wordpress-org__": "folder-wordpress-open",
"wp-content": "folder-wordpress-open",
".wp-content": "folder-wordpress-open",
"_wp-content": "folder-wordpress-open",
+ "-wp-content": "folder-wordpress-open",
"__wp-content__": "folder-wordpress-open",
"gradle": "folder-gradle-open",
".gradle": "folder-gradle-open",
"_gradle": "folder-gradle-open",
+ "-gradle": "folder-gradle-open",
"__gradle__": "folder-gradle-open",
"coverage": "folder-coverage-open",
".coverage": "folder-coverage-open",
"_coverage": "folder-coverage-open",
+ "-coverage": "folder-coverage-open",
"__coverage__": "folder-coverage-open",
"nyc-output": "folder-coverage-open",
".nyc-output": "folder-coverage-open",
"_nyc-output": "folder-coverage-open",
+ "-nyc-output": "folder-coverage-open",
"__nyc-output__": "folder-coverage-open",
"nyc_output": "folder-coverage-open",
".nyc_output": "folder-coverage-open",
"_nyc_output": "folder-coverage-open",
+ "-nyc_output": "folder-coverage-open",
"__nyc_output__": "folder-coverage-open",
"e2e": "folder-coverage-open",
".e2e": "folder-coverage-open",
"_e2e": "folder-coverage-open",
+ "-e2e": "folder-coverage-open",
"__e2e__": "folder-coverage-open",
"it": "folder-coverage-open",
".it": "folder-coverage-open",
"_it": "folder-coverage-open",
+ "-it": "folder-coverage-open",
"__it__": "folder-coverage-open",
"integration-test": "folder-coverage-open",
".integration-test": "folder-coverage-open",
"_integration-test": "folder-coverage-open",
+ "-integration-test": "folder-coverage-open",
"__integration-test__": "folder-coverage-open",
"integration-tests": "folder-coverage-open",
".integration-tests": "folder-coverage-open",
"_integration-tests": "folder-coverage-open",
+ "-integration-tests": "folder-coverage-open",
"__integration-tests__": "folder-coverage-open",
"class": "folder-class-open",
".class": "folder-class-open",
"_class": "folder-class-open",
+ "-class": "folder-class-open",
"__class__": "folder-class-open",
"classes": "folder-class-open",
".classes": "folder-class-open",
"_classes": "folder-class-open",
+ "-classes": "folder-class-open",
"__classes__": "folder-class-open",
"model": "folder-class-open",
".model": "folder-class-open",
"_model": "folder-class-open",
+ "-model": "folder-class-open",
"__model__": "folder-class-open",
"models": "folder-class-open",
".models": "folder-class-open",
"_models": "folder-class-open",
+ "-models": "folder-class-open",
"__models__": "folder-class-open",
"schemas": "folder-class-open",
".schemas": "folder-class-open",
"_schemas": "folder-class-open",
+ "-schemas": "folder-class-open",
"__schemas__": "folder-class-open",
"schema": "folder-class-open",
".schema": "folder-class-open",
"_schema": "folder-class-open",
+ "-schema": "folder-class-open",
"__schema__": "folder-class-open",
"other": "folder-other-open",
".other": "folder-other-open",
"_other": "folder-other-open",
+ "-other": "folder-other-open",
"__other__": "folder-other-open",
"others": "folder-other-open",
".others": "folder-other-open",
"_others": "folder-other-open",
+ "-others": "folder-other-open",
"__others__": "folder-other-open",
"misc": "folder-other-open",
".misc": "folder-other-open",
"_misc": "folder-other-open",
+ "-misc": "folder-other-open",
"__misc__": "folder-other-open",
"miscellaneous": "folder-other-open",
".miscellaneous": "folder-other-open",
"_miscellaneous": "folder-other-open",
+ "-miscellaneous": "folder-other-open",
"__miscellaneous__": "folder-other-open",
"extra": "folder-other-open",
".extra": "folder-other-open",
"_extra": "folder-other-open",
+ "-extra": "folder-other-open",
"__extra__": "folder-other-open",
"extras": "folder-other-open",
".extras": "folder-other-open",
"_extras": "folder-other-open",
+ "-extras": "folder-other-open",
"__extras__": "folder-other-open",
"etc": "folder-other-open",
".etc": "folder-other-open",
"_etc": "folder-other-open",
+ "-etc": "folder-other-open",
"__etc__": "folder-other-open",
"lua": "folder-lua-open",
".lua": "folder-lua-open",
"_lua": "folder-lua-open",
+ "-lua": "folder-lua-open",
"__lua__": "folder-lua-open",
"turbo": "folder-turborepo-open",
".turbo": "folder-turborepo-open",
"_turbo": "folder-turborepo-open",
+ "-turbo": "folder-turborepo-open",
"__turbo__": "folder-turborepo-open",
"typescript": "folder-typescript-open",
".typescript": "folder-typescript-open",
"_typescript": "folder-typescript-open",
+ "-typescript": "folder-typescript-open",
"__typescript__": "folder-typescript-open",
"ts": "folder-typescript-open",
".ts": "folder-typescript-open",
"_ts": "folder-typescript-open",
+ "-ts": "folder-typescript-open",
"__ts__": "folder-typescript-open",
"typings": "folder-typescript-open",
".typings": "folder-typescript-open",
"_typings": "folder-typescript-open",
+ "-typings": "folder-typescript-open",
"__typings__": "folder-typescript-open",
"@types": "folder-typescript-open",
".@types": "folder-typescript-open",
"_@types": "folder-typescript-open",
+ "-@types": "folder-typescript-open",
"__@types__": "folder-typescript-open",
"types": "folder-typescript-open",
".types": "folder-typescript-open",
"_types": "folder-typescript-open",
+ "-types": "folder-typescript-open",
"__types__": "folder-typescript-open",
"cts": "folder-typescript-open",
".cts": "folder-typescript-open",
"_cts": "folder-typescript-open",
+ "-cts": "folder-typescript-open",
"__cts__": "folder-typescript-open",
"mts": "folder-typescript-open",
".mts": "folder-typescript-open",
"_mts": "folder-typescript-open",
+ "-mts": "folder-typescript-open",
"__mts__": "folder-typescript-open",
"graphql": "folder-graphql-open",
".graphql": "folder-graphql-open",
"_graphql": "folder-graphql-open",
+ "-graphql": "folder-graphql-open",
"__graphql__": "folder-graphql-open",
"gql": "folder-graphql-open",
".gql": "folder-graphql-open",
"_gql": "folder-graphql-open",
+ "-gql": "folder-graphql-open",
"__gql__": "folder-graphql-open",
"routes": "folder-routes-open",
".routes": "folder-routes-open",
"_routes": "folder-routes-open",
+ "-routes": "folder-routes-open",
"__routes__": "folder-routes-open",
"router": "folder-routes-open",
".router": "folder-routes-open",
"_router": "folder-routes-open",
+ "-router": "folder-routes-open",
"__router__": "folder-routes-open",
"routers": "folder-routes-open",
".routers": "folder-routes-open",
"_routers": "folder-routes-open",
+ "-routers": "folder-routes-open",
"__routers__": "folder-routes-open",
"navigation": "folder-routes-open",
".navigation": "folder-routes-open",
"_navigation": "folder-routes-open",
+ "-navigation": "folder-routes-open",
"__navigation__": "folder-routes-open",
"navigations": "folder-routes-open",
".navigations": "folder-routes-open",
"_navigations": "folder-routes-open",
+ "-navigations": "folder-routes-open",
"__navigations__": "folder-routes-open",
"routing": "folder-routes-open",
".routing": "folder-routes-open",
"_routing": "folder-routes-open",
+ "-routing": "folder-routes-open",
"__routing__": "folder-routes-open",
"ci": "folder-ci-open",
".ci": "folder-ci-open",
"_ci": "folder-ci-open",
+ "-ci": "folder-ci-open",
"__ci__": "folder-ci-open",
"eslint": "folder-eslint-open",
".eslint": "folder-eslint-open",
"_eslint": "folder-eslint-open",
+ "-eslint": "folder-eslint-open",
"__eslint__": "folder-eslint-open",
"eslint-plugin": "folder-eslint-open",
".eslint-plugin": "folder-eslint-open",
"_eslint-plugin": "folder-eslint-open",
+ "-eslint-plugin": "folder-eslint-open",
"__eslint-plugin__": "folder-eslint-open",
"eslint-plugins": "folder-eslint-open",
".eslint-plugins": "folder-eslint-open",
"_eslint-plugins": "folder-eslint-open",
+ "-eslint-plugins": "folder-eslint-open",
"__eslint-plugins__": "folder-eslint-open",
"eslint-config": "folder-eslint-open",
".eslint-config": "folder-eslint-open",
"_eslint-config": "folder-eslint-open",
+ "-eslint-config": "folder-eslint-open",
"__eslint-config__": "folder-eslint-open",
"eslint-configs": "folder-eslint-open",
".eslint-configs": "folder-eslint-open",
"_eslint-configs": "folder-eslint-open",
+ "-eslint-configs": "folder-eslint-open",
"__eslint-configs__": "folder-eslint-open",
"benchmark": "folder-benchmark-open",
".benchmark": "folder-benchmark-open",
"_benchmark": "folder-benchmark-open",
+ "-benchmark": "folder-benchmark-open",
"__benchmark__": "folder-benchmark-open",
"benchmarks": "folder-benchmark-open",
".benchmarks": "folder-benchmark-open",
"_benchmarks": "folder-benchmark-open",
+ "-benchmarks": "folder-benchmark-open",
"__benchmarks__": "folder-benchmark-open",
"bench": "folder-benchmark-open",
".bench": "folder-benchmark-open",
"_bench": "folder-benchmark-open",
+ "-bench": "folder-benchmark-open",
"__bench__": "folder-benchmark-open",
+ "benches": "folder-benchmark-open",
+ ".benches": "folder-benchmark-open",
+ "_benches": "folder-benchmark-open",
+ "-benches": "folder-benchmark-open",
+ "__benches__": "folder-benchmark-open",
"performance": "folder-benchmark-open",
".performance": "folder-benchmark-open",
"_performance": "folder-benchmark-open",
+ "-performance": "folder-benchmark-open",
"__performance__": "folder-benchmark-open",
"perf": "folder-benchmark-open",
".perf": "folder-benchmark-open",
"_perf": "folder-benchmark-open",
+ "-perf": "folder-benchmark-open",
"__perf__": "folder-benchmark-open",
"profiling": "folder-benchmark-open",
".profiling": "folder-benchmark-open",
"_profiling": "folder-benchmark-open",
+ "-profiling": "folder-benchmark-open",
"__profiling__": "folder-benchmark-open",
"measure": "folder-benchmark-open",
".measure": "folder-benchmark-open",
"_measure": "folder-benchmark-open",
+ "-measure": "folder-benchmark-open",
"__measure__": "folder-benchmark-open",
"measures": "folder-benchmark-open",
".measures": "folder-benchmark-open",
"_measures": "folder-benchmark-open",
+ "-measures": "folder-benchmark-open",
"__measures__": "folder-benchmark-open",
"measurement": "folder-benchmark-open",
".measurement": "folder-benchmark-open",
"_measurement": "folder-benchmark-open",
+ "-measurement": "folder-benchmark-open",
"__measurement__": "folder-benchmark-open",
"messages": "folder-messages-open",
".messages": "folder-messages-open",
"_messages": "folder-messages-open",
+ "-messages": "folder-messages-open",
"__messages__": "folder-messages-open",
"messaging": "folder-messages-open",
".messaging": "folder-messages-open",
"_messaging": "folder-messages-open",
+ "-messaging": "folder-messages-open",
"__messaging__": "folder-messages-open",
"forum": "folder-messages-open",
".forum": "folder-messages-open",
"_forum": "folder-messages-open",
+ "-forum": "folder-messages-open",
"__forum__": "folder-messages-open",
"chat": "folder-messages-open",
".chat": "folder-messages-open",
"_chat": "folder-messages-open",
+ "-chat": "folder-messages-open",
"__chat__": "folder-messages-open",
"chats": "folder-messages-open",
".chats": "folder-messages-open",
"_chats": "folder-messages-open",
+ "-chats": "folder-messages-open",
"__chats__": "folder-messages-open",
"conversation": "folder-messages-open",
".conversation": "folder-messages-open",
"_conversation": "folder-messages-open",
+ "-conversation": "folder-messages-open",
"__conversation__": "folder-messages-open",
"conversations": "folder-messages-open",
".conversations": "folder-messages-open",
"_conversations": "folder-messages-open",
+ "-conversations": "folder-messages-open",
"__conversations__": "folder-messages-open",
"dialog": "folder-messages-open",
".dialog": "folder-messages-open",
"_dialog": "folder-messages-open",
+ "-dialog": "folder-messages-open",
"__dialog__": "folder-messages-open",
"dialogs": "folder-messages-open",
".dialogs": "folder-messages-open",
"_dialogs": "folder-messages-open",
+ "-dialogs": "folder-messages-open",
"__dialogs__": "folder-messages-open",
"less": "folder-less-open",
".less": "folder-less-open",
"_less": "folder-less-open",
+ "-less": "folder-less-open",
"__less__": "folder-less-open",
"gulp": "folder-gulp-open",
".gulp": "folder-gulp-open",
"_gulp": "folder-gulp-open",
+ "-gulp": "folder-gulp-open",
"__gulp__": "folder-gulp-open",
"gulp-tasks": "folder-gulp-open",
".gulp-tasks": "folder-gulp-open",
"_gulp-tasks": "folder-gulp-open",
+ "-gulp-tasks": "folder-gulp-open",
"__gulp-tasks__": "folder-gulp-open",
"gulpfile.js": "folder-gulp-open",
".gulpfile.js": "folder-gulp-open",
"_gulpfile.js": "folder-gulp-open",
+ "-gulpfile.js": "folder-gulp-open",
"__gulpfile.js__": "folder-gulp-open",
"gulpfile.mjs": "folder-gulp-open",
".gulpfile.mjs": "folder-gulp-open",
"_gulpfile.mjs": "folder-gulp-open",
+ "-gulpfile.mjs": "folder-gulp-open",
"__gulpfile.mjs__": "folder-gulp-open",
"gulpfile.ts": "folder-gulp-open",
".gulpfile.ts": "folder-gulp-open",
"_gulpfile.ts": "folder-gulp-open",
+ "-gulpfile.ts": "folder-gulp-open",
"__gulpfile.ts__": "folder-gulp-open",
"gulpfile.babel.js": "folder-gulp-open",
".gulpfile.babel.js": "folder-gulp-open",
"_gulpfile.babel.js": "folder-gulp-open",
+ "-gulpfile.babel.js": "folder-gulp-open",
"__gulpfile.babel.js__": "folder-gulp-open",
"gulpfiles": "folder-gulp-open",
".gulpfiles": "folder-gulp-open",
"_gulpfiles": "folder-gulp-open",
+ "-gulpfiles": "folder-gulp-open",
"__gulpfiles__": "folder-gulp-open",
"python": "folder-python-open",
".python": "folder-python-open",
"_python": "folder-python-open",
+ "-python": "folder-python-open",
"__python__": "folder-python-open",
"pycache": "folder-python-open",
".pycache": "folder-python-open",
"_pycache": "folder-python-open",
+ "-pycache": "folder-python-open",
"__pycache__": "folder-python-open",
"pytest_cache": "folder-python-open",
".pytest_cache": "folder-python-open",
"_pytest_cache": "folder-python-open",
+ "-pytest_cache": "folder-python-open",
"__pytest_cache__": "folder-python-open",
"sandbox": "folder-sandbox-open",
".sandbox": "folder-sandbox-open",
"_sandbox": "folder-sandbox-open",
+ "-sandbox": "folder-sandbox-open",
"__sandbox__": "folder-sandbox-open",
"sandboxes": "folder-sandbox-open",
".sandboxes": "folder-sandbox-open",
"_sandboxes": "folder-sandbox-open",
+ "-sandboxes": "folder-sandbox-open",
"__sandboxes__": "folder-sandbox-open",
"playground": "folder-sandbox-open",
".playground": "folder-sandbox-open",
"_playground": "folder-sandbox-open",
+ "-playground": "folder-sandbox-open",
"__playground__": "folder-sandbox-open",
"playgrounds": "folder-sandbox-open",
".playgrounds": "folder-sandbox-open",
"_playgrounds": "folder-sandbox-open",
+ "-playgrounds": "folder-sandbox-open",
"__playgrounds__": "folder-sandbox-open",
"scons": "folder-scons-open",
".scons": "folder-scons-open",
"_scons": "folder-scons-open",
+ "-scons": "folder-scons-open",
"__scons__": "folder-scons-open",
"sconf_temp": "folder-scons-open",
".sconf_temp": "folder-scons-open",
"_sconf_temp": "folder-scons-open",
+ "-sconf_temp": "folder-scons-open",
"__sconf_temp__": "folder-scons-open",
"scons_cache": "folder-scons-open",
".scons_cache": "folder-scons-open",
"_scons_cache": "folder-scons-open",
+ "-scons_cache": "folder-scons-open",
"__scons_cache__": "folder-scons-open",
"mojo": "folder-mojo-open",
".mojo": "folder-mojo-open",
"_mojo": "folder-mojo-open",
+ "-mojo": "folder-mojo-open",
"__mojo__": "folder-mojo-open",
"moon": "folder-moon-open",
".moon": "folder-moon-open",
"_moon": "folder-moon-open",
+ "-moon": "folder-moon-open",
"__moon__": "folder-moon-open",
"debug": "folder-debug-open",
".debug": "folder-debug-open",
"_debug": "folder-debug-open",
+ "-debug": "folder-debug-open",
"__debug__": "folder-debug-open",
"debugger": "folder-debug-open",
".debugger": "folder-debug-open",
"_debugger": "folder-debug-open",
+ "-debugger": "folder-debug-open",
"__debugger__": "folder-debug-open",
"debugging": "folder-debug-open",
".debugging": "folder-debug-open",
"_debugging": "folder-debug-open",
+ "-debugging": "folder-debug-open",
"__debugging__": "folder-debug-open",
"fastlane": "folder-fastlane-open",
".fastlane": "folder-fastlane-open",
"_fastlane": "folder-fastlane-open",
+ "-fastlane": "folder-fastlane-open",
"__fastlane__": "folder-fastlane-open",
"plugin": "folder-plugin-open",
".plugin": "folder-plugin-open",
"_plugin": "folder-plugin-open",
+ "-plugin": "folder-plugin-open",
"__plugin__": "folder-plugin-open",
"plugins": "folder-plugin-open",
".plugins": "folder-plugin-open",
"_plugins": "folder-plugin-open",
+ "-plugins": "folder-plugin-open",
"__plugins__": "folder-plugin-open",
"mod": "folder-plugin-open",
".mod": "folder-plugin-open",
"_mod": "folder-plugin-open",
+ "-mod": "folder-plugin-open",
"__mod__": "folder-plugin-open",
"mods": "folder-plugin-open",
".mods": "folder-plugin-open",
"_mods": "folder-plugin-open",
+ "-mods": "folder-plugin-open",
"__mods__": "folder-plugin-open",
"modding": "folder-plugin-open",
".modding": "folder-plugin-open",
"_modding": "folder-plugin-open",
+ "-modding": "folder-plugin-open",
"__modding__": "folder-plugin-open",
"extension": "folder-plugin-open",
".extension": "folder-plugin-open",
"_extension": "folder-plugin-open",
+ "-extension": "folder-plugin-open",
"__extension__": "folder-plugin-open",
"extensions": "folder-plugin-open",
".extensions": "folder-plugin-open",
"_extensions": "folder-plugin-open",
+ "-extensions": "folder-plugin-open",
"__extensions__": "folder-plugin-open",
"addon": "folder-plugin-open",
".addon": "folder-plugin-open",
"_addon": "folder-plugin-open",
+ "-addon": "folder-plugin-open",
"__addon__": "folder-plugin-open",
"addons": "folder-plugin-open",
".addons": "folder-plugin-open",
"_addons": "folder-plugin-open",
+ "-addons": "folder-plugin-open",
"__addons__": "folder-plugin-open",
"addin": "folder-plugin-open",
".addin": "folder-plugin-open",
"_addin": "folder-plugin-open",
+ "-addin": "folder-plugin-open",
"__addin__": "folder-plugin-open",
"addins": "folder-plugin-open",
".addins": "folder-plugin-open",
"_addins": "folder-plugin-open",
+ "-addins": "folder-plugin-open",
"__addins__": "folder-plugin-open",
"module": "folder-plugin-open",
".module": "folder-plugin-open",
"_module": "folder-plugin-open",
+ "-module": "folder-plugin-open",
"__module__": "folder-plugin-open",
"modules": "folder-plugin-open",
".modules": "folder-plugin-open",
"_modules": "folder-plugin-open",
+ "-modules": "folder-plugin-open",
"__modules__": "folder-plugin-open",
"middleware": "folder-middleware-open",
".middleware": "folder-middleware-open",
"_middleware": "folder-middleware-open",
+ "-middleware": "folder-middleware-open",
"__middleware__": "folder-middleware-open",
"middlewares": "folder-middleware-open",
".middlewares": "folder-middleware-open",
"_middlewares": "folder-middleware-open",
+ "-middlewares": "folder-middleware-open",
"__middlewares__": "folder-middleware-open",
"controller": "folder-controller-open",
".controller": "folder-controller-open",
"_controller": "folder-controller-open",
+ "-controller": "folder-controller-open",
"__controller__": "folder-controller-open",
"controllers": "folder-controller-open",
".controllers": "folder-controller-open",
"_controllers": "folder-controller-open",
+ "-controllers": "folder-controller-open",
"__controllers__": "folder-controller-open",
"controls": "folder-controller-open",
".controls": "folder-controller-open",
"_controls": "folder-controller-open",
+ "-controls": "folder-controller-open",
"__controls__": "folder-controller-open",
"service": "folder-controller-open",
".service": "folder-controller-open",
"_service": "folder-controller-open",
+ "-service": "folder-controller-open",
"__service__": "folder-controller-open",
"services": "folder-controller-open",
".services": "folder-controller-open",
"_services": "folder-controller-open",
+ "-services": "folder-controller-open",
"__services__": "folder-controller-open",
"provider": "folder-controller-open",
".provider": "folder-controller-open",
"_provider": "folder-controller-open",
+ "-provider": "folder-controller-open",
"__provider__": "folder-controller-open",
"providers": "folder-controller-open",
".providers": "folder-controller-open",
"_providers": "folder-controller-open",
+ "-providers": "folder-controller-open",
"__providers__": "folder-controller-open",
"handler": "folder-controller-open",
".handler": "folder-controller-open",
"_handler": "folder-controller-open",
+ "-handler": "folder-controller-open",
"__handler__": "folder-controller-open",
"handlers": "folder-controller-open",
".handlers": "folder-controller-open",
"_handlers": "folder-controller-open",
+ "-handlers": "folder-controller-open",
"__handlers__": "folder-controller-open",
"ansible": "folder-ansible-open",
".ansible": "folder-ansible-open",
"_ansible": "folder-ansible-open",
+ "-ansible": "folder-ansible-open",
"__ansible__": "folder-ansible-open",
"server": "folder-server-open",
".server": "folder-server-open",
"_server": "folder-server-open",
+ "-server": "folder-server-open",
"__server__": "folder-server-open",
"servers": "folder-server-open",
".servers": "folder-server-open",
"_servers": "folder-server-open",
+ "-servers": "folder-server-open",
"__servers__": "folder-server-open",
"backend": "folder-server-open",
".backend": "folder-server-open",
"_backend": "folder-server-open",
+ "-backend": "folder-server-open",
"__backend__": "folder-server-open",
"backends": "folder-server-open",
".backends": "folder-server-open",
"_backends": "folder-server-open",
+ "-backends": "folder-server-open",
"__backends__": "folder-server-open",
"inventory": "folder-server-open",
".inventory": "folder-server-open",
"_inventory": "folder-server-open",
+ "-inventory": "folder-server-open",
"__inventory__": "folder-server-open",
"inventories": "folder-server-open",
".inventories": "folder-server-open",
"_inventories": "folder-server-open",
+ "-inventories": "folder-server-open",
"__inventories__": "folder-server-open",
"infrastructure": "folder-server-open",
".infrastructure": "folder-server-open",
"_infrastructure": "folder-server-open",
+ "-infrastructure": "folder-server-open",
"__infrastructure__": "folder-server-open",
"infra": "folder-server-open",
".infra": "folder-server-open",
"_infra": "folder-server-open",
+ "-infra": "folder-server-open",
"__infra__": "folder-server-open",
"client": "folder-client-open",
".client": "folder-client-open",
"_client": "folder-client-open",
+ "-client": "folder-client-open",
"__client__": "folder-client-open",
"clients": "folder-client-open",
".clients": "folder-client-open",
"_clients": "folder-client-open",
+ "-clients": "folder-client-open",
"__clients__": "folder-client-open",
"frontend": "folder-client-open",
".frontend": "folder-client-open",
"_frontend": "folder-client-open",
+ "-frontend": "folder-client-open",
"__frontend__": "folder-client-open",
"frontends": "folder-client-open",
".frontends": "folder-client-open",
"_frontends": "folder-client-open",
+ "-frontends": "folder-client-open",
"__frontends__": "folder-client-open",
"pwa": "folder-client-open",
".pwa": "folder-client-open",
"_pwa": "folder-client-open",
+ "-pwa": "folder-client-open",
"__pwa__": "folder-client-open",
"spa": "folder-client-open",
".spa": "folder-client-open",
"_spa": "folder-client-open",
+ "-spa": "folder-client-open",
"__spa__": "folder-client-open",
"tasks": "folder-tasks-open",
".tasks": "folder-tasks-open",
"_tasks": "folder-tasks-open",
+ "-tasks": "folder-tasks-open",
"__tasks__": "folder-tasks-open",
"tickets": "folder-tasks-open",
".tickets": "folder-tasks-open",
"_tickets": "folder-tasks-open",
+ "-tickets": "folder-tasks-open",
"__tickets__": "folder-tasks-open",
"android": "folder-android-open",
".android": "folder-android-open",
"_android": "folder-android-open",
+ "-android": "folder-android-open",
"__android__": "folder-android-open",
"ios": "folder-ios-open",
".ios": "folder-ios-open",
"_ios": "folder-ios-open",
+ "-ios": "folder-ios-open",
"__ios__": "folder-ios-open",
"presentation": "folder-ui-open",
".presentation": "folder-ui-open",
"_presentation": "folder-ui-open",
+ "-presentation": "folder-ui-open",
"__presentation__": "folder-ui-open",
"gui": "folder-ui-open",
".gui": "folder-ui-open",
"_gui": "folder-ui-open",
+ "-gui": "folder-ui-open",
"__gui__": "folder-ui-open",
"ui": "folder-ui-open",
".ui": "folder-ui-open",
"_ui": "folder-ui-open",
+ "-ui": "folder-ui-open",
"__ui__": "folder-ui-open",
"ux": "folder-ui-open",
".ux": "folder-ui-open",
"_ux": "folder-ui-open",
+ "-ux": "folder-ui-open",
"__ux__": "folder-ui-open",
"uploads": "folder-upload-open",
".uploads": "folder-upload-open",
"_uploads": "folder-upload-open",
+ "-uploads": "folder-upload-open",
"__uploads__": "folder-upload-open",
"upload": "folder-upload-open",
".upload": "folder-upload-open",
"_upload": "folder-upload-open",
+ "-upload": "folder-upload-open",
"__upload__": "folder-upload-open",
"downloads": "folder-download-open",
".downloads": "folder-download-open",
"_downloads": "folder-download-open",
+ "-downloads": "folder-download-open",
"__downloads__": "folder-download-open",
"download": "folder-download-open",
".download": "folder-download-open",
"_download": "folder-download-open",
+ "-download": "folder-download-open",
"__download__": "folder-download-open",
"downloader": "folder-download-open",
".downloader": "folder-download-open",
"_downloader": "folder-download-open",
+ "-downloader": "folder-download-open",
"__downloader__": "folder-download-open",
"downloaders": "folder-download-open",
".downloaders": "folder-download-open",
"_downloaders": "folder-download-open",
+ "-downloaders": "folder-download-open",
"__downloaders__": "folder-download-open",
"tools": "folder-tools-open",
".tools": "folder-tools-open",
"_tools": "folder-tools-open",
+ "-tools": "folder-tools-open",
"__tools__": "folder-tools-open",
"toolkit": "folder-tools-open",
".toolkit": "folder-tools-open",
"_toolkit": "folder-tools-open",
+ "-toolkit": "folder-tools-open",
"__toolkit__": "folder-tools-open",
"toolkits": "folder-tools-open",
".toolkits": "folder-tools-open",
"_toolkits": "folder-tools-open",
+ "-toolkits": "folder-tools-open",
"__toolkits__": "folder-tools-open",
"toolbox": "folder-tools-open",
".toolbox": "folder-tools-open",
"_toolbox": "folder-tools-open",
+ "-toolbox": "folder-tools-open",
"__toolbox__": "folder-tools-open",
"toolboxes": "folder-tools-open",
".toolboxes": "folder-tools-open",
"_toolboxes": "folder-tools-open",
+ "-toolboxes": "folder-tools-open",
"__toolboxes__": "folder-tools-open",
"tooling": "folder-tools-open",
".tooling": "folder-tools-open",
"_tooling": "folder-tools-open",
+ "-tooling": "folder-tools-open",
"__tooling__": "folder-tools-open",
"devtools": "folder-tools-open",
".devtools": "folder-tools-open",
"_devtools": "folder-tools-open",
+ "-devtools": "folder-tools-open",
"__devtools__": "folder-tools-open",
"kit": "folder-tools-open",
".kit": "folder-tools-open",
"_kit": "folder-tools-open",
+ "-kit": "folder-tools-open",
"__kit__": "folder-tools-open",
"kits": "folder-tools-open",
".kits": "folder-tools-open",
"_kits": "folder-tools-open",
+ "-kits": "folder-tools-open",
"__kits__": "folder-tools-open",
"helpers": "folder-helper-open",
".helpers": "folder-helper-open",
"_helpers": "folder-helper-open",
+ "-helpers": "folder-helper-open",
"__helpers__": "folder-helper-open",
"helper": "folder-helper-open",
".helper": "folder-helper-open",
"_helper": "folder-helper-open",
+ "-helper": "folder-helper-open",
"__helper__": "folder-helper-open",
"serverless": "folder-serverless-open",
".serverless": "folder-serverless-open",
"_serverless": "folder-serverless-open",
+ "-serverless": "folder-serverless-open",
"__serverless__": "folder-serverless-open",
"api": "folder-api-open",
".api": "folder-api-open",
"_api": "folder-api-open",
+ "-api": "folder-api-open",
"__api__": "folder-api-open",
"apis": "folder-api-open",
".apis": "folder-api-open",
"_apis": "folder-api-open",
+ "-apis": "folder-api-open",
"__apis__": "folder-api-open",
"restapi": "folder-api-open",
".restapi": "folder-api-open",
"_restapi": "folder-api-open",
+ "-restapi": "folder-api-open",
"__restapi__": "folder-api-open",
"app": "folder-app-open",
".app": "folder-app-open",
"_app": "folder-app-open",
+ "-app": "folder-app-open",
"__app__": "folder-app-open",
"apps": "folder-app-open",
".apps": "folder-app-open",
"_apps": "folder-app-open",
+ "-apps": "folder-app-open",
"__apps__": "folder-app-open",
"application": "folder-app-open",
".application": "folder-app-open",
"_application": "folder-app-open",
+ "-application": "folder-app-open",
"__application__": "folder-app-open",
"applications": "folder-app-open",
".applications": "folder-app-open",
"_applications": "folder-app-open",
+ "-applications": "folder-app-open",
"__applications__": "folder-app-open",
"apollo": "folder-apollo-open",
".apollo": "folder-apollo-open",
"_apollo": "folder-apollo-open",
+ "-apollo": "folder-apollo-open",
"__apollo__": "folder-apollo-open",
"apollo-client": "folder-apollo-open",
".apollo-client": "folder-apollo-open",
"_apollo-client": "folder-apollo-open",
+ "-apollo-client": "folder-apollo-open",
"__apollo-client__": "folder-apollo-open",
"apollo-cache": "folder-apollo-open",
".apollo-cache": "folder-apollo-open",
"_apollo-cache": "folder-apollo-open",
+ "-apollo-cache": "folder-apollo-open",
"__apollo-cache__": "folder-apollo-open",
"apollo-config": "folder-apollo-open",
".apollo-config": "folder-apollo-open",
"_apollo-config": "folder-apollo-open",
+ "-apollo-config": "folder-apollo-open",
"__apollo-config__": "folder-apollo-open",
"arc": "folder-archive-open",
".arc": "folder-archive-open",
"_arc": "folder-archive-open",
+ "-arc": "folder-archive-open",
"__arc__": "folder-archive-open",
"arcs": "folder-archive-open",
".arcs": "folder-archive-open",
"_arcs": "folder-archive-open",
+ "-arcs": "folder-archive-open",
"__arcs__": "folder-archive-open",
"archive": "folder-archive-open",
".archive": "folder-archive-open",
"_archive": "folder-archive-open",
+ "-archive": "folder-archive-open",
"__archive__": "folder-archive-open",
"archives": "folder-archive-open",
".archives": "folder-archive-open",
"_archives": "folder-archive-open",
+ "-archives": "folder-archive-open",
"__archives__": "folder-archive-open",
"archival": "folder-archive-open",
".archival": "folder-archive-open",
"_archival": "folder-archive-open",
+ "-archival": "folder-archive-open",
"__archival__": "folder-archive-open",
"bkp": "folder-backup-open",
".bkp": "folder-backup-open",
"_bkp": "folder-backup-open",
+ "-bkp": "folder-backup-open",
"__bkp__": "folder-backup-open",
"bkps": "folder-backup-open",
".bkps": "folder-backup-open",
"_bkps": "folder-backup-open",
+ "-bkps": "folder-backup-open",
"__bkps__": "folder-backup-open",
"bak": "folder-backup-open",
".bak": "folder-backup-open",
"_bak": "folder-backup-open",
+ "-bak": "folder-backup-open",
"__bak__": "folder-backup-open",
"baks": "folder-backup-open",
".baks": "folder-backup-open",
"_baks": "folder-backup-open",
+ "-baks": "folder-backup-open",
"__baks__": "folder-backup-open",
"backup": "folder-backup-open",
".backup": "folder-backup-open",
"_backup": "folder-backup-open",
+ "-backup": "folder-backup-open",
"__backup__": "folder-backup-open",
"backups": "folder-backup-open",
".backups": "folder-backup-open",
"_backups": "folder-backup-open",
+ "-backups": "folder-backup-open",
"__backups__": "folder-backup-open",
"back-up": "folder-backup-open",
".back-up": "folder-backup-open",
"_back-up": "folder-backup-open",
+ "-back-up": "folder-backup-open",
"__back-up__": "folder-backup-open",
"back-ups": "folder-backup-open",
".back-ups": "folder-backup-open",
"_back-ups": "folder-backup-open",
+ "-back-ups": "folder-backup-open",
"__back-ups__": "folder-backup-open",
"history": "folder-backup-open",
".history": "folder-backup-open",
"_history": "folder-backup-open",
+ "-history": "folder-backup-open",
"__history__": "folder-backup-open",
"histories": "folder-backup-open",
".histories": "folder-backup-open",
"_histories": "folder-backup-open",
+ "-histories": "folder-backup-open",
"__histories__": "folder-backup-open",
"batch": "folder-batch-open",
".batch": "folder-batch-open",
"_batch": "folder-batch-open",
+ "-batch": "folder-batch-open",
"__batch__": "folder-batch-open",
"batchs": "folder-batch-open",
".batchs": "folder-batch-open",
"_batchs": "folder-batch-open",
+ "-batchs": "folder-batch-open",
"__batchs__": "folder-batch-open",
"batches": "folder-batch-open",
".batches": "folder-batch-open",
"_batches": "folder-batch-open",
+ "-batches": "folder-batch-open",
"__batches__": "folder-batch-open",
"buildkite": "folder-buildkite-open",
".buildkite": "folder-buildkite-open",
"_buildkite": "folder-buildkite-open",
+ "-buildkite": "folder-buildkite-open",
"__buildkite__": "folder-buildkite-open",
"cluster": "folder-cluster-open",
".cluster": "folder-cluster-open",
"_cluster": "folder-cluster-open",
+ "-cluster": "folder-cluster-open",
"__cluster__": "folder-cluster-open",
"clusters": "folder-cluster-open",
".clusters": "folder-cluster-open",
"_clusters": "folder-cluster-open",
+ "-clusters": "folder-cluster-open",
"__clusters__": "folder-cluster-open",
"command": "folder-command-open",
".command": "folder-command-open",
"_command": "folder-command-open",
+ "-command": "folder-command-open",
"__command__": "folder-command-open",
"commands": "folder-command-open",
".commands": "folder-command-open",
"_commands": "folder-command-open",
+ "-commands": "folder-command-open",
"__commands__": "folder-command-open",
"commandline": "folder-command-open",
".commandline": "folder-command-open",
"_commandline": "folder-command-open",
+ "-commandline": "folder-command-open",
"__commandline__": "folder-command-open",
"cmd": "folder-command-open",
".cmd": "folder-command-open",
"_cmd": "folder-command-open",
+ "-cmd": "folder-command-open",
"__cmd__": "folder-command-open",
"cli": "folder-command-open",
".cli": "folder-command-open",
"_cli": "folder-command-open",
+ "-cli": "folder-command-open",
"__cli__": "folder-command-open",
"clis": "folder-command-open",
".clis": "folder-command-open",
"_clis": "folder-command-open",
+ "-clis": "folder-command-open",
"__clis__": "folder-command-open",
"constant": "folder-constant-open",
".constant": "folder-constant-open",
"_constant": "folder-constant-open",
+ "-constant": "folder-constant-open",
"__constant__": "folder-constant-open",
"constants": "folder-constant-open",
".constants": "folder-constant-open",
"_constants": "folder-constant-open",
+ "-constants": "folder-constant-open",
"__constants__": "folder-constant-open",
"const": "folder-constant-open",
".const": "folder-constant-open",
"_const": "folder-constant-open",
+ "-const": "folder-constant-open",
"__const__": "folder-constant-open",
"consts": "folder-constant-open",
".consts": "folder-constant-open",
"_consts": "folder-constant-open",
+ "-consts": "folder-constant-open",
"__consts__": "folder-constant-open",
"container": "folder-container-open",
".container": "folder-container-open",
"_container": "folder-container-open",
+ "-container": "folder-container-open",
"__container__": "folder-container-open",
"containers": "folder-container-open",
".containers": "folder-container-open",
"_containers": "folder-container-open",
+ "-containers": "folder-container-open",
"__containers__": "folder-container-open",
"devcontainer": "folder-container-open",
".devcontainer": "folder-container-open",
"_devcontainer": "folder-container-open",
+ "-devcontainer": "folder-container-open",
"__devcontainer__": "folder-container-open",
"content": "folder-content-open",
".content": "folder-content-open",
"_content": "folder-content-open",
+ "-content": "folder-content-open",
"__content__": "folder-content-open",
"contents": "folder-content-open",
".contents": "folder-content-open",
"_contents": "folder-content-open",
+ "-contents": "folder-content-open",
"__contents__": "folder-content-open",
"context": "folder-context-open",
".context": "folder-context-open",
"_context": "folder-context-open",
+ "-context": "folder-context-open",
"__context__": "folder-context-open",
"contexts": "folder-context-open",
".contexts": "folder-context-open",
"_contexts": "folder-context-open",
+ "-contexts": "folder-context-open",
"__contexts__": "folder-context-open",
"core": "folder-core-open",
".core": "folder-core-open",
"_core": "folder-core-open",
+ "-core": "folder-core-open",
"__core__": "folder-core-open",
"delta": "folder-delta-open",
".delta": "folder-delta-open",
"_delta": "folder-delta-open",
+ "-delta": "folder-delta-open",
"__delta__": "folder-delta-open",
"deltas": "folder-delta-open",
".deltas": "folder-delta-open",
"_deltas": "folder-delta-open",
+ "-deltas": "folder-delta-open",
"__deltas__": "folder-delta-open",
"changes": "folder-delta-open",
".changes": "folder-delta-open",
"_changes": "folder-delta-open",
+ "-changes": "folder-delta-open",
"__changes__": "folder-delta-open",
"dump": "folder-dump-open",
".dump": "folder-dump-open",
"_dump": "folder-dump-open",
+ "-dump": "folder-dump-open",
"__dump__": "folder-dump-open",
"dumps": "folder-dump-open",
".dumps": "folder-dump-open",
"_dumps": "folder-dump-open",
+ "-dumps": "folder-dump-open",
"__dumps__": "folder-dump-open",
"demo": "folder-examples-open",
".demo": "folder-examples-open",
"_demo": "folder-examples-open",
+ "-demo": "folder-examples-open",
"__demo__": "folder-examples-open",
"demos": "folder-examples-open",
".demos": "folder-examples-open",
"_demos": "folder-examples-open",
+ "-demos": "folder-examples-open",
"__demos__": "folder-examples-open",
"example": "folder-examples-open",
".example": "folder-examples-open",
"_example": "folder-examples-open",
+ "-example": "folder-examples-open",
"__example__": "folder-examples-open",
"examples": "folder-examples-open",
".examples": "folder-examples-open",
"_examples": "folder-examples-open",
+ "-examples": "folder-examples-open",
"__examples__": "folder-examples-open",
"sample": "folder-examples-open",
".sample": "folder-examples-open",
"_sample": "folder-examples-open",
+ "-sample": "folder-examples-open",
"__sample__": "folder-examples-open",
"samples": "folder-examples-open",
".samples": "folder-examples-open",
"_samples": "folder-examples-open",
+ "-samples": "folder-examples-open",
"__samples__": "folder-examples-open",
"sample-data": "folder-examples-open",
".sample-data": "folder-examples-open",
"_sample-data": "folder-examples-open",
+ "-sample-data": "folder-examples-open",
"__sample-data__": "folder-examples-open",
"env": "folder-environment-open",
".env": "folder-environment-open",
"_env": "folder-environment-open",
+ "-env": "folder-environment-open",
"__env__": "folder-environment-open",
"envs": "folder-environment-open",
".envs": "folder-environment-open",
"_envs": "folder-environment-open",
+ "-envs": "folder-environment-open",
"__envs__": "folder-environment-open",
"environment": "folder-environment-open",
".environment": "folder-environment-open",
"_environment": "folder-environment-open",
+ "-environment": "folder-environment-open",
"__environment__": "folder-environment-open",
"environments": "folder-environment-open",
".environments": "folder-environment-open",
"_environments": "folder-environment-open",
+ "-environments": "folder-environment-open",
"__environments__": "folder-environment-open",
"venv": "folder-environment-open",
".venv": "folder-environment-open",
"_venv": "folder-environment-open",
+ "-venv": "folder-environment-open",
"__venv__": "folder-environment-open",
"func": "folder-functions-open",
".func": "folder-functions-open",
"_func": "folder-functions-open",
+ "-func": "folder-functions-open",
"__func__": "folder-functions-open",
"funcs": "folder-functions-open",
".funcs": "folder-functions-open",
"_funcs": "folder-functions-open",
+ "-funcs": "folder-functions-open",
"__funcs__": "folder-functions-open",
"function": "folder-functions-open",
".function": "folder-functions-open",
"_function": "folder-functions-open",
+ "-function": "folder-functions-open",
"__function__": "folder-functions-open",
"functions": "folder-functions-open",
".functions": "folder-functions-open",
"_functions": "folder-functions-open",
+ "-functions": "folder-functions-open",
"__functions__": "folder-functions-open",
"lambda": "folder-functions-open",
".lambda": "folder-functions-open",
"_lambda": "folder-functions-open",
+ "-lambda": "folder-functions-open",
"__lambda__": "folder-functions-open",
"lambdas": "folder-functions-open",
".lambdas": "folder-functions-open",
"_lambdas": "folder-functions-open",
+ "-lambdas": "folder-functions-open",
"__lambdas__": "folder-functions-open",
"logic": "folder-functions-open",
".logic": "folder-functions-open",
"_logic": "folder-functions-open",
+ "-logic": "folder-functions-open",
"__logic__": "folder-functions-open",
"math": "folder-functions-open",
".math": "folder-functions-open",
"_math": "folder-functions-open",
+ "-math": "folder-functions-open",
"__math__": "folder-functions-open",
"maths": "folder-functions-open",
".maths": "folder-functions-open",
"_maths": "folder-functions-open",
+ "-maths": "folder-functions-open",
"__maths__": "folder-functions-open",
"calc": "folder-functions-open",
".calc": "folder-functions-open",
"_calc": "folder-functions-open",
+ "-calc": "folder-functions-open",
"__calc__": "folder-functions-open",
"calcs": "folder-functions-open",
".calcs": "folder-functions-open",
"_calcs": "folder-functions-open",
+ "-calcs": "folder-functions-open",
"__calcs__": "folder-functions-open",
"calculation": "folder-functions-open",
".calculation": "folder-functions-open",
"_calculation": "folder-functions-open",
+ "-calculation": "folder-functions-open",
"__calculation__": "folder-functions-open",
"calculations": "folder-functions-open",
".calculations": "folder-functions-open",
"_calculations": "folder-functions-open",
+ "-calculations": "folder-functions-open",
"__calculations__": "folder-functions-open",
"composable": "folder-functions-open",
".composable": "folder-functions-open",
"_composable": "folder-functions-open",
+ "-composable": "folder-functions-open",
"__composable__": "folder-functions-open",
"composables": "folder-functions-open",
".composables": "folder-functions-open",
"_composables": "folder-functions-open",
+ "-composables": "folder-functions-open",
"__composables__": "folder-functions-open",
"generator": "folder-generator-open",
".generator": "folder-generator-open",
"_generator": "folder-generator-open",
+ "-generator": "folder-generator-open",
"__generator__": "folder-generator-open",
"generators": "folder-generator-open",
".generators": "folder-generator-open",
"_generators": "folder-generator-open",
+ "-generators": "folder-generator-open",
"__generators__": "folder-generator-open",
"generated": "folder-generator-open",
".generated": "folder-generator-open",
"_generated": "folder-generator-open",
+ "-generated": "folder-generator-open",
"__generated__": "folder-generator-open",
"cfn-gen": "folder-generator-open",
".cfn-gen": "folder-generator-open",
"_cfn-gen": "folder-generator-open",
+ "-cfn-gen": "folder-generator-open",
"__cfn-gen__": "folder-generator-open",
"gen": "folder-generator-open",
".gen": "folder-generator-open",
"_gen": "folder-generator-open",
+ "-gen": "folder-generator-open",
"__gen__": "folder-generator-open",
"gens": "folder-generator-open",
".gens": "folder-generator-open",
"_gens": "folder-generator-open",
+ "-gens": "folder-generator-open",
"__gens__": "folder-generator-open",
"auto": "folder-generator-open",
".auto": "folder-generator-open",
"_auto": "folder-generator-open",
+ "-auto": "folder-generator-open",
"__auto__": "folder-generator-open",
"hook": "folder-hook-open",
".hook": "folder-hook-open",
"_hook": "folder-hook-open",
+ "-hook": "folder-hook-open",
"__hook__": "folder-hook-open",
"hooks": "folder-hook-open",
".hooks": "folder-hook-open",
"_hooks": "folder-hook-open",
+ "-hooks": "folder-hook-open",
"__hooks__": "folder-hook-open",
"trigger": "folder-trigger-open",
".trigger": "folder-trigger-open",
"_trigger": "folder-trigger-open",
+ "-trigger": "folder-trigger-open",
"__trigger__": "folder-trigger-open",
"triggers": "folder-trigger-open",
".triggers": "folder-trigger-open",
"_triggers": "folder-trigger-open",
+ "-triggers": "folder-trigger-open",
"__triggers__": "folder-trigger-open",
"job": "folder-job-open",
".job": "folder-job-open",
"_job": "folder-job-open",
+ "-job": "folder-job-open",
"__job__": "folder-job-open",
"jobs": "folder-job-open",
".jobs": "folder-job-open",
"_jobs": "folder-job-open",
+ "-jobs": "folder-job-open",
"__jobs__": "folder-job-open",
"key": "folder-keys-open",
".key": "folder-keys-open",
"_key": "folder-keys-open",
+ "-key": "folder-keys-open",
"__key__": "folder-keys-open",
"keys": "folder-keys-open",
".keys": "folder-keys-open",
"_keys": "folder-keys-open",
+ "-keys": "folder-keys-open",
"__keys__": "folder-keys-open",
"token": "folder-keys-open",
".token": "folder-keys-open",
"_token": "folder-keys-open",
+ "-token": "folder-keys-open",
"__token__": "folder-keys-open",
"tokens": "folder-keys-open",
".tokens": "folder-keys-open",
"_tokens": "folder-keys-open",
+ "-tokens": "folder-keys-open",
"__tokens__": "folder-keys-open",
"jwt": "folder-keys-open",
".jwt": "folder-keys-open",
"_jwt": "folder-keys-open",
+ "-jwt": "folder-keys-open",
"__jwt__": "folder-keys-open",
"secret": "folder-keys-open",
".secret": "folder-keys-open",
"_secret": "folder-keys-open",
+ "-secret": "folder-keys-open",
"__secret__": "folder-keys-open",
"secrets": "folder-keys-open",
".secrets": "folder-keys-open",
"_secrets": "folder-keys-open",
+ "-secrets": "folder-keys-open",
"__secrets__": "folder-keys-open",
"layout": "folder-layout-open",
".layout": "folder-layout-open",
"_layout": "folder-layout-open",
+ "-layout": "folder-layout-open",
"__layout__": "folder-layout-open",
"layouts": "folder-layout-open",
".layouts": "folder-layout-open",
"_layouts": "folder-layout-open",
+ "-layouts": "folder-layout-open",
"__layouts__": "folder-layout-open",
"mail": "folder-mail-open",
".mail": "folder-mail-open",
"_mail": "folder-mail-open",
+ "-mail": "folder-mail-open",
"__mail__": "folder-mail-open",
"mails": "folder-mail-open",
".mails": "folder-mail-open",
"_mails": "folder-mail-open",
+ "-mails": "folder-mail-open",
"__mails__": "folder-mail-open",
"email": "folder-mail-open",
".email": "folder-mail-open",
"_email": "folder-mail-open",
+ "-email": "folder-mail-open",
"__email__": "folder-mail-open",
"emails": "folder-mail-open",
".emails": "folder-mail-open",
"_emails": "folder-mail-open",
+ "-emails": "folder-mail-open",
"__emails__": "folder-mail-open",
"smtp": "folder-mail-open",
".smtp": "folder-mail-open",
"_smtp": "folder-mail-open",
+ "-smtp": "folder-mail-open",
"__smtp__": "folder-mail-open",
"mailers": "folder-mail-open",
".mailers": "folder-mail-open",
"_mailers": "folder-mail-open",
+ "-mailers": "folder-mail-open",
"__mailers__": "folder-mail-open",
"mappings": "folder-mappings-open",
".mappings": "folder-mappings-open",
"_mappings": "folder-mappings-open",
+ "-mappings": "folder-mappings-open",
"__mappings__": "folder-mappings-open",
"mapping": "folder-mappings-open",
".mapping": "folder-mappings-open",
"_mapping": "folder-mappings-open",
+ "-mapping": "folder-mappings-open",
"__mapping__": "folder-mappings-open",
"meta": "folder-meta-open",
".meta": "folder-meta-open",
"_meta": "folder-meta-open",
+ "-meta": "folder-meta-open",
"__meta__": "folder-meta-open",
"metadata": "folder-meta-open",
".metadata": "folder-meta-open",
"_metadata": "folder-meta-open",
+ "-metadata": "folder-meta-open",
"__metadata__": "folder-meta-open",
"changesets": "folder-changesets-open",
".changesets": "folder-changesets-open",
"_changesets": "folder-changesets-open",
+ "-changesets": "folder-changesets-open",
"__changesets__": "folder-changesets-open",
"changeset": "folder-changesets-open",
".changeset": "folder-changesets-open",
"_changeset": "folder-changesets-open",
+ "-changeset": "folder-changesets-open",
"__changeset__": "folder-changesets-open",
"package": "folder-packages-open",
".package": "folder-packages-open",
"_package": "folder-packages-open",
+ "-package": "folder-packages-open",
"__package__": "folder-packages-open",
"packages": "folder-packages-open",
".packages": "folder-packages-open",
"_packages": "folder-packages-open",
+ "-packages": "folder-packages-open",
"__packages__": "folder-packages-open",
"pkg": "folder-packages-open",
".pkg": "folder-packages-open",
"_pkg": "folder-packages-open",
+ "-pkg": "folder-packages-open",
"__pkg__": "folder-packages-open",
"pkgs": "folder-packages-open",
".pkgs": "folder-packages-open",
"_pkgs": "folder-packages-open",
+ "-pkgs": "folder-packages-open",
"__pkgs__": "folder-packages-open",
"serverpackages": "folder-packages-open",
".serverpackages": "folder-packages-open",
"_serverpackages": "folder-packages-open",
+ "-serverpackages": "folder-packages-open",
"__serverpackages__": "folder-packages-open",
"devpackages": "folder-packages-open",
".devpackages": "folder-packages-open",
"_devpackages": "folder-packages-open",
+ "-devpackages": "folder-packages-open",
"__devpackages__": "folder-packages-open",
"dependencies": "folder-packages-open",
".dependencies": "folder-packages-open",
"_dependencies": "folder-packages-open",
+ "-dependencies": "folder-packages-open",
"__dependencies__": "folder-packages-open",
"shared": "folder-shared-open",
".shared": "folder-shared-open",
"_shared": "folder-shared-open",
+ "-shared": "folder-shared-open",
"__shared__": "folder-shared-open",
"common": "folder-shared-open",
".common": "folder-shared-open",
"_common": "folder-shared-open",
+ "-common": "folder-shared-open",
"__common__": "folder-shared-open",
"glsl": "folder-shader-open",
".glsl": "folder-shader-open",
"_glsl": "folder-shader-open",
+ "-glsl": "folder-shader-open",
"__glsl__": "folder-shader-open",
"hlsl": "folder-shader-open",
".hlsl": "folder-shader-open",
"_hlsl": "folder-shader-open",
+ "-hlsl": "folder-shader-open",
"__hlsl__": "folder-shader-open",
"shader": "folder-shader-open",
".shader": "folder-shader-open",
"_shader": "folder-shader-open",
+ "-shader": "folder-shader-open",
"__shader__": "folder-shader-open",
"shaders": "folder-shader-open",
".shaders": "folder-shader-open",
"_shaders": "folder-shader-open",
+ "-shaders": "folder-shader-open",
"__shaders__": "folder-shader-open",
"stack": "folder-stack-open",
".stack": "folder-stack-open",
"_stack": "folder-stack-open",
+ "-stack": "folder-stack-open",
"__stack__": "folder-stack-open",
"stacks": "folder-stack-open",
".stacks": "folder-stack-open",
"_stacks": "folder-stack-open",
+ "-stacks": "folder-stack-open",
"__stacks__": "folder-stack-open",
"template": "folder-template-open",
".template": "folder-template-open",
"_template": "folder-template-open",
+ "-template": "folder-template-open",
"__template__": "folder-template-open",
"templates": "folder-template-open",
".templates": "folder-template-open",
"_templates": "folder-template-open",
+ "-templates": "folder-template-open",
"__templates__": "folder-template-open",
"github/ISSUE_TEMPLATE": "folder-template-open",
".github/ISSUE_TEMPLATE": "folder-template-open",
"_github/ISSUE_TEMPLATE": "folder-template-open",
+ "-github/ISSUE_TEMPLATE": "folder-template-open",
"__github/ISSUE_TEMPLATE__": "folder-template-open",
"github/PULL_REQUEST_TEMPLATE": "folder-template-open",
".github/PULL_REQUEST_TEMPLATE": "folder-template-open",
"_github/PULL_REQUEST_TEMPLATE": "folder-template-open",
+ "-github/PULL_REQUEST_TEMPLATE": "folder-template-open",
"__github/PULL_REQUEST_TEMPLATE__": "folder-template-open",
"util": "folder-utils-open",
".util": "folder-utils-open",
"_util": "folder-utils-open",
+ "-util": "folder-utils-open",
"__util__": "folder-utils-open",
"utils": "folder-utils-open",
".utils": "folder-utils-open",
"_utils": "folder-utils-open",
+ "-utils": "folder-utils-open",
"__utils__": "folder-utils-open",
"utility": "folder-utils-open",
".utility": "folder-utils-open",
"_utility": "folder-utils-open",
+ "-utility": "folder-utils-open",
"__utility__": "folder-utils-open",
"utilities": "folder-utils-open",
".utilities": "folder-utils-open",
"_utilities": "folder-utils-open",
+ "-utilities": "folder-utils-open",
"__utilities__": "folder-utils-open",
"supabase": "folder-supabase-open",
".supabase": "folder-supabase-open",
"_supabase": "folder-supabase-open",
+ "-supabase": "folder-supabase-open",
"__supabase__": "folder-supabase-open",
"private": "folder-private-open",
".private": "folder-private-open",
"_private": "folder-private-open",
+ "-private": "folder-private-open",
"__private__": "folder-private-open",
"linux": "folder-linux-open",
".linux": "folder-linux-open",
"_linux": "folder-linux-open",
+ "-linux": "folder-linux-open",
"__linux__": "folder-linux-open",
"linuxbsd": "folder-linux-open",
".linuxbsd": "folder-linux-open",
"_linuxbsd": "folder-linux-open",
+ "-linuxbsd": "folder-linux-open",
"__linuxbsd__": "folder-linux-open",
"unix": "folder-linux-open",
".unix": "folder-linux-open",
"_unix": "folder-linux-open",
+ "-unix": "folder-linux-open",
"__unix__": "folder-linux-open",
"wsl": "folder-linux-open",
".wsl": "folder-linux-open",
"_wsl": "folder-linux-open",
+ "-wsl": "folder-linux-open",
"__wsl__": "folder-linux-open",
"ubuntu": "folder-linux-open",
".ubuntu": "folder-linux-open",
"_ubuntu": "folder-linux-open",
+ "-ubuntu": "folder-linux-open",
"__ubuntu__": "folder-linux-open",
"deb": "folder-linux-open",
".deb": "folder-linux-open",
"_deb": "folder-linux-open",
+ "-deb": "folder-linux-open",
"__deb__": "folder-linux-open",
"debian": "folder-linux-open",
".debian": "folder-linux-open",
"_debian": "folder-linux-open",
+ "-debian": "folder-linux-open",
"__debian__": "folder-linux-open",
"deepin": "folder-linux-open",
".deepin": "folder-linux-open",
"_deepin": "folder-linux-open",
+ "-deepin": "folder-linux-open",
"__deepin__": "folder-linux-open",
"centos": "folder-linux-open",
".centos": "folder-linux-open",
"_centos": "folder-linux-open",
+ "-centos": "folder-linux-open",
"__centos__": "folder-linux-open",
"popos": "folder-linux-open",
".popos": "folder-linux-open",
"_popos": "folder-linux-open",
+ "-popos": "folder-linux-open",
"__popos__": "folder-linux-open",
"mint": "folder-linux-open",
".mint": "folder-linux-open",
"_mint": "folder-linux-open",
+ "-mint": "folder-linux-open",
"__mint__": "folder-linux-open",
"windows": "folder-windows-open",
".windows": "folder-windows-open",
"_windows": "folder-windows-open",
+ "-windows": "folder-windows-open",
"__windows__": "folder-windows-open",
"win": "folder-windows-open",
".win": "folder-windows-open",
"_win": "folder-windows-open",
+ "-win": "folder-windows-open",
"__win__": "folder-windows-open",
"win32": "folder-windows-open",
".win32": "folder-windows-open",
"_win32": "folder-windows-open",
+ "-win32": "folder-windows-open",
"__win32__": "folder-windows-open",
"windows11": "folder-windows-open",
".windows11": "folder-windows-open",
"_windows11": "folder-windows-open",
+ "-windows11": "folder-windows-open",
"__windows11__": "folder-windows-open",
"windows10": "folder-windows-open",
".windows10": "folder-windows-open",
"_windows10": "folder-windows-open",
+ "-windows10": "folder-windows-open",
"__windows10__": "folder-windows-open",
"windowsxp": "folder-windows-open",
".windowsxp": "folder-windows-open",
"_windowsxp": "folder-windows-open",
+ "-windowsxp": "folder-windows-open",
"__windowsxp__": "folder-windows-open",
"windowsnt": "folder-windows-open",
".windowsnt": "folder-windows-open",
"_windowsnt": "folder-windows-open",
+ "-windowsnt": "folder-windows-open",
"__windowsnt__": "folder-windows-open",
"win11": "folder-windows-open",
".win11": "folder-windows-open",
"_win11": "folder-windows-open",
+ "-win11": "folder-windows-open",
"__win11__": "folder-windows-open",
"win10": "folder-windows-open",
".win10": "folder-windows-open",
"_win10": "folder-windows-open",
+ "-win10": "folder-windows-open",
"__win10__": "folder-windows-open",
"winxp": "folder-windows-open",
".winxp": "folder-windows-open",
"_winxp": "folder-windows-open",
+ "-winxp": "folder-windows-open",
"__winxp__": "folder-windows-open",
"winnt": "folder-windows-open",
".winnt": "folder-windows-open",
"_winnt": "folder-windows-open",
+ "-winnt": "folder-windows-open",
"__winnt__": "folder-windows-open",
"macos": "folder-macos-open",
".macos": "folder-macos-open",
"_macos": "folder-macos-open",
+ "-macos": "folder-macos-open",
"__macos__": "folder-macos-open",
"mac": "folder-macos-open",
".mac": "folder-macos-open",
"_mac": "folder-macos-open",
+ "-mac": "folder-macos-open",
"__mac__": "folder-macos-open",
"osx": "folder-macos-open",
".osx": "folder-macos-open",
"_osx": "folder-macos-open",
+ "-osx": "folder-macos-open",
"__osx__": "folder-macos-open",
"DS_Store": "folder-macos-open",
".DS_Store": "folder-macos-open",
"_DS_Store": "folder-macos-open",
+ "-DS_Store": "folder-macos-open",
"__DS_Store__": "folder-macos-open",
"iPhone": "folder-macos-open",
".iPhone": "folder-macos-open",
"_iPhone": "folder-macos-open",
+ "-iPhone": "folder-macos-open",
"__iPhone__": "folder-macos-open",
"iPad": "folder-macos-open",
".iPad": "folder-macos-open",
"_iPad": "folder-macos-open",
+ "-iPad": "folder-macos-open",
"__iPad__": "folder-macos-open",
"iPod": "folder-macos-open",
".iPod": "folder-macos-open",
"_iPod": "folder-macos-open",
+ "-iPod": "folder-macos-open",
"__iPod__": "folder-macos-open",
"macbook": "folder-macos-open",
".macbook": "folder-macos-open",
"_macbook": "folder-macos-open",
+ "-macbook": "folder-macos-open",
"__macbook__": "folder-macos-open",
"macbook-air": "folder-macos-open",
".macbook-air": "folder-macos-open",
"_macbook-air": "folder-macos-open",
+ "-macbook-air": "folder-macos-open",
"__macbook-air__": "folder-macos-open",
"macosx": "folder-macos-open",
".macosx": "folder-macos-open",
"_macosx": "folder-macos-open",
+ "-macosx": "folder-macos-open",
"__macosx__": "folder-macos-open",
"apple": "folder-macos-open",
".apple": "folder-macos-open",
"_apple": "folder-macos-open",
+ "-apple": "folder-macos-open",
"__apple__": "folder-macos-open",
"error": "folder-error-open",
".error": "folder-error-open",
"_error": "folder-error-open",
+ "-error": "folder-error-open",
"__error__": "folder-error-open",
"errors": "folder-error-open",
".errors": "folder-error-open",
"_errors": "folder-error-open",
+ "-errors": "folder-error-open",
"__errors__": "folder-error-open",
"err": "folder-error-open",
".err": "folder-error-open",
"_err": "folder-error-open",
+ "-err": "folder-error-open",
"__err__": "folder-error-open",
"errs": "folder-error-open",
".errs": "folder-error-open",
"_errs": "folder-error-open",
+ "-errs": "folder-error-open",
"__errs__": "folder-error-open",
"crash": "folder-error-open",
".crash": "folder-error-open",
"_crash": "folder-error-open",
+ "-crash": "folder-error-open",
"__crash__": "folder-error-open",
"crashes": "folder-error-open",
".crashes": "folder-error-open",
"_crashes": "folder-error-open",
+ "-crashes": "folder-error-open",
"__crashes__": "folder-error-open",
"event": "folder-event-open",
".event": "folder-event-open",
"_event": "folder-event-open",
+ "-event": "folder-event-open",
"__event__": "folder-event-open",
"events": "folder-event-open",
".events": "folder-event-open",
"_events": "folder-event-open",
+ "-events": "folder-event-open",
"__events__": "folder-event-open",
"auth": "folder-secure-open",
".auth": "folder-secure-open",
"_auth": "folder-secure-open",
+ "-auth": "folder-secure-open",
"__auth__": "folder-secure-open",
"authentication": "folder-secure-open",
".authentication": "folder-secure-open",
"_authentication": "folder-secure-open",
+ "-authentication": "folder-secure-open",
"__authentication__": "folder-secure-open",
"secure": "folder-secure-open",
".secure": "folder-secure-open",
"_secure": "folder-secure-open",
+ "-secure": "folder-secure-open",
"__secure__": "folder-secure-open",
"security": "folder-secure-open",
".security": "folder-secure-open",
"_security": "folder-secure-open",
+ "-security": "folder-secure-open",
"__security__": "folder-secure-open",
"cert": "folder-secure-open",
".cert": "folder-secure-open",
"_cert": "folder-secure-open",
+ "-cert": "folder-secure-open",
"__cert__": "folder-secure-open",
"certs": "folder-secure-open",
".certs": "folder-secure-open",
"_certs": "folder-secure-open",
+ "-certs": "folder-secure-open",
"__certs__": "folder-secure-open",
"certificate": "folder-secure-open",
".certificate": "folder-secure-open",
"_certificate": "folder-secure-open",
+ "-certificate": "folder-secure-open",
"__certificate__": "folder-secure-open",
"certificates": "folder-secure-open",
".certificates": "folder-secure-open",
"_certificates": "folder-secure-open",
+ "-certificates": "folder-secure-open",
"__certificates__": "folder-secure-open",
"ssl": "folder-secure-open",
".ssl": "folder-secure-open",
"_ssl": "folder-secure-open",
+ "-ssl": "folder-secure-open",
"__ssl__": "folder-secure-open",
"cipher": "folder-secure-open",
".cipher": "folder-secure-open",
"_cipher": "folder-secure-open",
+ "-cipher": "folder-secure-open",
"__cipher__": "folder-secure-open",
"cypher": "folder-secure-open",
".cypher": "folder-secure-open",
"_cypher": "folder-secure-open",
+ "-cypher": "folder-secure-open",
"__cypher__": "folder-secure-open",
"tls": "folder-secure-open",
".tls": "folder-secure-open",
"_tls": "folder-secure-open",
+ "-tls": "folder-secure-open",
"__tls__": "folder-secure-open",
"custom": "folder-custom-open",
".custom": "folder-custom-open",
"_custom": "folder-custom-open",
+ "-custom": "folder-custom-open",
"__custom__": "folder-custom-open",
"customs": "folder-custom-open",
".customs": "folder-custom-open",
"_customs": "folder-custom-open",
+ "-customs": "folder-custom-open",
"__customs__": "folder-custom-open",
"draft": "folder-mock-open",
".draft": "folder-mock-open",
"_draft": "folder-mock-open",
+ "-draft": "folder-mock-open",
"__draft__": "folder-mock-open",
"drafts": "folder-mock-open",
".drafts": "folder-mock-open",
"_drafts": "folder-mock-open",
+ "-drafts": "folder-mock-open",
"__drafts__": "folder-mock-open",
"mock": "folder-mock-open",
".mock": "folder-mock-open",
"_mock": "folder-mock-open",
+ "-mock": "folder-mock-open",
"__mock__": "folder-mock-open",
"mocks": "folder-mock-open",
".mocks": "folder-mock-open",
"_mocks": "folder-mock-open",
+ "-mocks": "folder-mock-open",
"__mocks__": "folder-mock-open",
"fixture": "folder-mock-open",
".fixture": "folder-mock-open",
"_fixture": "folder-mock-open",
+ "-fixture": "folder-mock-open",
"__fixture__": "folder-mock-open",
"fixtures": "folder-mock-open",
".fixtures": "folder-mock-open",
"_fixtures": "folder-mock-open",
+ "-fixtures": "folder-mock-open",
"__fixtures__": "folder-mock-open",
"concept": "folder-mock-open",
".concept": "folder-mock-open",
"_concept": "folder-mock-open",
+ "-concept": "folder-mock-open",
"__concept__": "folder-mock-open",
"concepts": "folder-mock-open",
".concepts": "folder-mock-open",
"_concepts": "folder-mock-open",
+ "-concepts": "folder-mock-open",
"__concepts__": "folder-mock-open",
"sketch": "folder-mock-open",
".sketch": "folder-mock-open",
"_sketch": "folder-mock-open",
+ "-sketch": "folder-mock-open",
"__sketch__": "folder-mock-open",
"sketches": "folder-mock-open",
".sketches": "folder-mock-open",
"_sketches": "folder-mock-open",
+ "-sketches": "folder-mock-open",
"__sketches__": "folder-mock-open",
"syntax": "folder-syntax-open",
".syntax": "folder-syntax-open",
"_syntax": "folder-syntax-open",
+ "-syntax": "folder-syntax-open",
"__syntax__": "folder-syntax-open",
"syntaxes": "folder-syntax-open",
".syntaxes": "folder-syntax-open",
"_syntaxes": "folder-syntax-open",
+ "-syntaxes": "folder-syntax-open",
"__syntaxes__": "folder-syntax-open",
"spellcheck": "folder-syntax-open",
".spellcheck": "folder-syntax-open",
"_spellcheck": "folder-syntax-open",
+ "-spellcheck": "folder-syntax-open",
"__spellcheck__": "folder-syntax-open",
"spellcheckers": "folder-syntax-open",
".spellcheckers": "folder-syntax-open",
"_spellcheckers": "folder-syntax-open",
+ "-spellcheckers": "folder-syntax-open",
"__spellcheckers__": "folder-syntax-open",
"vm": "folder-vm-open",
".vm": "folder-vm-open",
"_vm": "folder-vm-open",
+ "-vm": "folder-vm-open",
"__vm__": "folder-vm-open",
"vms": "folder-vm-open",
".vms": "folder-vm-open",
"_vms": "folder-vm-open",
+ "-vms": "folder-vm-open",
"__vms__": "folder-vm-open",
"stylus": "folder-stylus-open",
".stylus": "folder-stylus-open",
"_stylus": "folder-stylus-open",
+ "-stylus": "folder-stylus-open",
"__stylus__": "folder-stylus-open",
"flow-typed": "folder-flow-open",
".flow-typed": "folder-flow-open",
"_flow-typed": "folder-flow-open",
+ "-flow-typed": "folder-flow-open",
"__flow-typed__": "folder-flow-open",
"rule": "folder-rules-open",
".rule": "folder-rules-open",
"_rule": "folder-rules-open",
+ "-rule": "folder-rules-open",
"__rule__": "folder-rules-open",
"rules": "folder-rules-open",
".rules": "folder-rules-open",
"_rules": "folder-rules-open",
+ "-rules": "folder-rules-open",
"__rules__": "folder-rules-open",
"validation": "folder-rules-open",
".validation": "folder-rules-open",
"_validation": "folder-rules-open",
+ "-validation": "folder-rules-open",
"__validation__": "folder-rules-open",
"validations": "folder-rules-open",
".validations": "folder-rules-open",
"_validations": "folder-rules-open",
+ "-validations": "folder-rules-open",
"__validations__": "folder-rules-open",
"validator": "folder-rules-open",
".validator": "folder-rules-open",
"_validator": "folder-rules-open",
+ "-validator": "folder-rules-open",
"__validator__": "folder-rules-open",
"validators": "folder-rules-open",
".validators": "folder-rules-open",
"_validators": "folder-rules-open",
+ "-validators": "folder-rules-open",
"__validators__": "folder-rules-open",
"review": "folder-review-open",
".review": "folder-review-open",
"_review": "folder-review-open",
+ "-review": "folder-review-open",
"__review__": "folder-review-open",
"reviews": "folder-review-open",
".reviews": "folder-review-open",
"_reviews": "folder-review-open",
+ "-reviews": "folder-review-open",
"__reviews__": "folder-review-open",
"revisal": "folder-review-open",
".revisal": "folder-review-open",
"_revisal": "folder-review-open",
+ "-revisal": "folder-review-open",
"__revisal__": "folder-review-open",
"revisals": "folder-review-open",
".revisals": "folder-review-open",
"_revisals": "folder-review-open",
+ "-revisals": "folder-review-open",
"__revisals__": "folder-review-open",
"reviewed": "folder-review-open",
".reviewed": "folder-review-open",
"_reviewed": "folder-review-open",
+ "-reviewed": "folder-review-open",
"__reviewed__": "folder-review-open",
"preview": "folder-review-open",
".preview": "folder-review-open",
"_preview": "folder-review-open",
+ "-preview": "folder-review-open",
"__preview__": "folder-review-open",
"previews": "folder-review-open",
".previews": "folder-review-open",
"_previews": "folder-review-open",
+ "-previews": "folder-review-open",
"__previews__": "folder-review-open",
"anim": "folder-animation-open",
".anim": "folder-animation-open",
"_anim": "folder-animation-open",
+ "-anim": "folder-animation-open",
"__anim__": "folder-animation-open",
"anims": "folder-animation-open",
".anims": "folder-animation-open",
"_anims": "folder-animation-open",
+ "-anims": "folder-animation-open",
"__anims__": "folder-animation-open",
"animation": "folder-animation-open",
".animation": "folder-animation-open",
"_animation": "folder-animation-open",
+ "-animation": "folder-animation-open",
"__animation__": "folder-animation-open",
"animations": "folder-animation-open",
".animations": "folder-animation-open",
"_animations": "folder-animation-open",
+ "-animations": "folder-animation-open",
"__animations__": "folder-animation-open",
"animated": "folder-animation-open",
".animated": "folder-animation-open",
"_animated": "folder-animation-open",
+ "-animated": "folder-animation-open",
"__animated__": "folder-animation-open",
"motion": "folder-animation-open",
".motion": "folder-animation-open",
"_motion": "folder-animation-open",
+ "-motion": "folder-animation-open",
"__motion__": "folder-animation-open",
"motions": "folder-animation-open",
".motions": "folder-animation-open",
"_motions": "folder-animation-open",
+ "-motions": "folder-animation-open",
"__motions__": "folder-animation-open",
"transition": "folder-animation-open",
".transition": "folder-animation-open",
"_transition": "folder-animation-open",
+ "-transition": "folder-animation-open",
"__transition__": "folder-animation-open",
"transitions": "folder-animation-open",
".transitions": "folder-animation-open",
"_transitions": "folder-animation-open",
+ "-transitions": "folder-animation-open",
"__transitions__": "folder-animation-open",
"easing": "folder-animation-open",
".easing": "folder-animation-open",
"_easing": "folder-animation-open",
+ "-easing": "folder-animation-open",
"__easing__": "folder-animation-open",
"easings": "folder-animation-open",
".easings": "folder-animation-open",
"_easings": "folder-animation-open",
+ "-easings": "folder-animation-open",
"__easings__": "folder-animation-open",
"guard": "folder-guard-open",
".guard": "folder-guard-open",
"_guard": "folder-guard-open",
+ "-guard": "folder-guard-open",
"__guard__": "folder-guard-open",
"guards": "folder-guard-open",
".guards": "folder-guard-open",
"_guards": "folder-guard-open",
+ "-guards": "folder-guard-open",
"__guards__": "folder-guard-open",
"prisma": "folder-prisma-open",
".prisma": "folder-prisma-open",
"_prisma": "folder-prisma-open",
+ "-prisma": "folder-prisma-open",
"__prisma__": "folder-prisma-open",
"prisma/schema": "folder-prisma-open",
".prisma/schema": "folder-prisma-open",
"_prisma/schema": "folder-prisma-open",
+ "-prisma/schema": "folder-prisma-open",
"__prisma/schema__": "folder-prisma-open",
"pipe": "folder-pipe-open",
".pipe": "folder-pipe-open",
"_pipe": "folder-pipe-open",
+ "-pipe": "folder-pipe-open",
"__pipe__": "folder-pipe-open",
"pipes": "folder-pipe-open",
".pipes": "folder-pipe-open",
"_pipes": "folder-pipe-open",
+ "-pipes": "folder-pipe-open",
"__pipes__": "folder-pipe-open",
"pipeline": "folder-pipe-open",
".pipeline": "folder-pipe-open",
"_pipeline": "folder-pipe-open",
+ "-pipeline": "folder-pipe-open",
"__pipeline__": "folder-pipe-open",
"pipelines": "folder-pipe-open",
".pipelines": "folder-pipe-open",
"_pipelines": "folder-pipe-open",
+ "-pipelines": "folder-pipe-open",
"__pipelines__": "folder-pipe-open",
"interceptor": "folder-interceptor-open",
".interceptor": "folder-interceptor-open",
"_interceptor": "folder-interceptor-open",
+ "-interceptor": "folder-interceptor-open",
"__interceptor__": "folder-interceptor-open",
"interceptors": "folder-interceptor-open",
".interceptors": "folder-interceptor-open",
"_interceptors": "folder-interceptor-open",
+ "-interceptors": "folder-interceptor-open",
"__interceptors__": "folder-interceptor-open",
"svg": "folder-svg-open",
".svg": "folder-svg-open",
"_svg": "folder-svg-open",
+ "-svg": "folder-svg-open",
"__svg__": "folder-svg-open",
"svgs": "folder-svg-open",
".svgs": "folder-svg-open",
"_svgs": "folder-svg-open",
+ "-svgs": "folder-svg-open",
"__svgs__": "folder-svg-open",
"vector": "folder-svg-open",
".vector": "folder-svg-open",
"_vector": "folder-svg-open",
+ "-vector": "folder-svg-open",
"__vector__": "folder-svg-open",
"vectors": "folder-svg-open",
".vectors": "folder-svg-open",
"_vectors": "folder-svg-open",
+ "-vectors": "folder-svg-open",
"__vectors__": "folder-svg-open",
"nuxt": "folder-nuxt-open",
".nuxt": "folder-nuxt-open",
"_nuxt": "folder-nuxt-open",
+ "-nuxt": "folder-nuxt-open",
"__nuxt__": "folder-nuxt-open",
"terraform": "folder-terraform-open",
".terraform": "folder-terraform-open",
"_terraform": "folder-terraform-open",
+ "-terraform": "folder-terraform-open",
"__terraform__": "folder-terraform-open",
"mobile": "folder-mobile-open",
".mobile": "folder-mobile-open",
"_mobile": "folder-mobile-open",
+ "-mobile": "folder-mobile-open",
"__mobile__": "folder-mobile-open",
"mobiles": "folder-mobile-open",
".mobiles": "folder-mobile-open",
"_mobiles": "folder-mobile-open",
+ "-mobiles": "folder-mobile-open",
"__mobiles__": "folder-mobile-open",
"portable": "folder-mobile-open",
".portable": "folder-mobile-open",
"_portable": "folder-mobile-open",
+ "-portable": "folder-mobile-open",
"__portable__": "folder-mobile-open",
"portability": "folder-mobile-open",
".portability": "folder-mobile-open",
"_portability": "folder-mobile-open",
+ "-portability": "folder-mobile-open",
"__portability__": "folder-mobile-open",
"phone": "folder-mobile-open",
".phone": "folder-mobile-open",
"_phone": "folder-mobile-open",
+ "-phone": "folder-mobile-open",
"__phone__": "folder-mobile-open",
"phones": "folder-mobile-open",
".phones": "folder-mobile-open",
"_phones": "folder-mobile-open",
+ "-phones": "folder-mobile-open",
"__phones__": "folder-mobile-open",
"stencil": "folder-stencil-open",
".stencil": "folder-stencil-open",
"_stencil": "folder-stencil-open",
+ "-stencil": "folder-stencil-open",
"__stencil__": "folder-stencil-open",
"firebase": "folder-firebase-open",
".firebase": "folder-firebase-open",
"_firebase": "folder-firebase-open",
+ "-firebase": "folder-firebase-open",
"__firebase__": "folder-firebase-open",
"firestore": "folder-firestore-open",
".firestore": "folder-firestore-open",
"_firestore": "folder-firestore-open",
+ "-firestore": "folder-firestore-open",
"__firestore__": "folder-firestore-open",
"cloud-firestore": "folder-firestore-open",
".cloud-firestore": "folder-firestore-open",
"_cloud-firestore": "folder-firestore-open",
+ "-cloud-firestore": "folder-firestore-open",
"__cloud-firestore__": "folder-firestore-open",
"firebase-firestore": "folder-firestore-open",
".firebase-firestore": "folder-firestore-open",
"_firebase-firestore": "folder-firestore-open",
+ "-firebase-firestore": "folder-firestore-open",
"__firebase-firestore__": "folder-firestore-open",
"cloud-functions": "folder-cloud-functions-open",
".cloud-functions": "folder-cloud-functions-open",
"_cloud-functions": "folder-cloud-functions-open",
+ "-cloud-functions": "folder-cloud-functions-open",
"__cloud-functions__": "folder-cloud-functions-open",
"cloudfunctions": "folder-cloud-functions-open",
".cloudfunctions": "folder-cloud-functions-open",
"_cloudfunctions": "folder-cloud-functions-open",
+ "-cloudfunctions": "folder-cloud-functions-open",
"__cloudfunctions__": "folder-cloud-functions-open",
"firebase-cloud-functions": "folder-cloud-functions-open",
".firebase-cloud-functions": "folder-cloud-functions-open",
"_firebase-cloud-functions": "folder-cloud-functions-open",
+ "-firebase-cloud-functions": "folder-cloud-functions-open",
"__firebase-cloud-functions__": "folder-cloud-functions-open",
"firebase-cloudfunctions": "folder-cloud-functions-open",
".firebase-cloudfunctions": "folder-cloud-functions-open",
"_firebase-cloudfunctions": "folder-cloud-functions-open",
+ "-firebase-cloudfunctions": "folder-cloud-functions-open",
"__firebase-cloudfunctions__": "folder-cloud-functions-open",
"svelte": "folder-svelte-open",
".svelte": "folder-svelte-open",
"_svelte": "folder-svelte-open",
+ "-svelte": "folder-svelte-open",
"__svelte__": "folder-svelte-open",
"svelte-kit": "folder-svelte-open",
".svelte-kit": "folder-svelte-open",
"_svelte-kit": "folder-svelte-open",
+ "-svelte-kit": "folder-svelte-open",
"__svelte-kit__": "folder-svelte-open",
"update": "folder-update-open",
".update": "folder-update-open",
"_update": "folder-update-open",
+ "-update": "folder-update-open",
"__update__": "folder-update-open",
"updates": "folder-update-open",
".updates": "folder-update-open",
"_updates": "folder-update-open",
+ "-updates": "folder-update-open",
"__updates__": "folder-update-open",
"upgrade": "folder-update-open",
".upgrade": "folder-update-open",
"_upgrade": "folder-update-open",
+ "-upgrade": "folder-update-open",
"__upgrade__": "folder-update-open",
"upgrades": "folder-update-open",
".upgrades": "folder-update-open",
"_upgrades": "folder-update-open",
+ "-upgrades": "folder-update-open",
"__upgrades__": "folder-update-open",
"idea": "folder-intellij-open",
".idea": "folder-intellij-open",
"_idea": "folder-intellij-open",
+ "-idea": "folder-intellij-open",
"__idea__": "folder-intellij-open",
"azure-pipelines": "folder-azure-pipelines-open",
".azure-pipelines": "folder-azure-pipelines-open",
"_azure-pipelines": "folder-azure-pipelines-open",
+ "-azure-pipelines": "folder-azure-pipelines-open",
"__azure-pipelines__": "folder-azure-pipelines-open",
"azure-pipelines-ci": "folder-azure-pipelines-open",
".azure-pipelines-ci": "folder-azure-pipelines-open",
"_azure-pipelines-ci": "folder-azure-pipelines-open",
+ "-azure-pipelines-ci": "folder-azure-pipelines-open",
"__azure-pipelines-ci__": "folder-azure-pipelines-open",
"mjml": "folder-mjml-open",
".mjml": "folder-mjml-open",
"_mjml": "folder-mjml-open",
+ "-mjml": "folder-mjml-open",
"__mjml__": "folder-mjml-open",
"admin": "folder-admin-open",
".admin": "folder-admin-open",
"_admin": "folder-admin-open",
+ "-admin": "folder-admin-open",
"__admin__": "folder-admin-open",
"admins": "folder-admin-open",
".admins": "folder-admin-open",
"_admins": "folder-admin-open",
+ "-admins": "folder-admin-open",
"__admins__": "folder-admin-open",
"manager": "folder-admin-open",
".manager": "folder-admin-open",
"_manager": "folder-admin-open",
+ "-manager": "folder-admin-open",
"__manager__": "folder-admin-open",
"managers": "folder-admin-open",
".managers": "folder-admin-open",
"_managers": "folder-admin-open",
+ "-managers": "folder-admin-open",
"__managers__": "folder-admin-open",
"moderator": "folder-admin-open",
".moderator": "folder-admin-open",
"_moderator": "folder-admin-open",
+ "-moderator": "folder-admin-open",
"__moderator__": "folder-admin-open",
"moderators": "folder-admin-open",
".moderators": "folder-admin-open",
"_moderators": "folder-admin-open",
+ "-moderators": "folder-admin-open",
"__moderators__": "folder-admin-open",
"jupyter": "folder-jupyter-open",
".jupyter": "folder-jupyter-open",
"_jupyter": "folder-jupyter-open",
+ "-jupyter": "folder-jupyter-open",
"__jupyter__": "folder-jupyter-open",
"notebook": "folder-jupyter-open",
".notebook": "folder-jupyter-open",
"_notebook": "folder-jupyter-open",
+ "-notebook": "folder-jupyter-open",
"__notebook__": "folder-jupyter-open",
"notebooks": "folder-jupyter-open",
".notebooks": "folder-jupyter-open",
"_notebooks": "folder-jupyter-open",
+ "-notebooks": "folder-jupyter-open",
"__notebooks__": "folder-jupyter-open",
"ipynb": "folder-jupyter-open",
".ipynb": "folder-jupyter-open",
"_ipynb": "folder-jupyter-open",
+ "-ipynb": "folder-jupyter-open",
"__ipynb__": "folder-jupyter-open",
"scala": "folder-scala-open",
".scala": "folder-scala-open",
"_scala": "folder-scala-open",
+ "-scala": "folder-scala-open",
"__scala__": "folder-scala-open",
"connection": "folder-connection-open",
".connection": "folder-connection-open",
"_connection": "folder-connection-open",
+ "-connection": "folder-connection-open",
"__connection__": "folder-connection-open",
"connections": "folder-connection-open",
".connections": "folder-connection-open",
"_connections": "folder-connection-open",
+ "-connections": "folder-connection-open",
"__connections__": "folder-connection-open",
"integration": "folder-connection-open",
".integration": "folder-connection-open",
"_integration": "folder-connection-open",
+ "-integration": "folder-connection-open",
"__integration__": "folder-connection-open",
"integrations": "folder-connection-open",
".integrations": "folder-connection-open",
"_integrations": "folder-connection-open",
+ "-integrations": "folder-connection-open",
"__integrations__": "folder-connection-open",
"remote": "folder-connection-open",
".remote": "folder-connection-open",
"_remote": "folder-connection-open",
+ "-remote": "folder-connection-open",
"__remote__": "folder-connection-open",
"remotes": "folder-connection-open",
".remotes": "folder-connection-open",
"_remotes": "folder-connection-open",
+ "-remotes": "folder-connection-open",
"__remotes__": "folder-connection-open",
"quasar": "folder-quasar-open",
".quasar": "folder-quasar-open",
"_quasar": "folder-quasar-open",
+ "-quasar": "folder-quasar-open",
"__quasar__": "folder-quasar-open",
"next": "folder-next-open",
".next": "folder-next-open",
"_next": "folder-next-open",
+ "-next": "folder-next-open",
"__next__": "folder-next-open",
"dal": "folder-dal-open",
".dal": "folder-dal-open",
"_dal": "folder-dal-open",
+ "-dal": "folder-dal-open",
"__dal__": "folder-dal-open",
"data-access": "folder-dal-open",
".data-access": "folder-dal-open",
"_data-access": "folder-dal-open",
+ "-data-access": "folder-dal-open",
"__data-access__": "folder-dal-open",
"data-access-layer": "folder-dal-open",
".data-access-layer": "folder-dal-open",
"_data-access-layer": "folder-dal-open",
+ "-data-access-layer": "folder-dal-open",
"__data-access-layer__": "folder-dal-open",
"cobol": "folder-cobol-open",
".cobol": "folder-cobol-open",
"_cobol": "folder-cobol-open",
+ "-cobol": "folder-cobol-open",
"__cobol__": "folder-cobol-open",
"yarn": "folder-yarn-open",
".yarn": "folder-yarn-open",
"_yarn": "folder-yarn-open",
+ "-yarn": "folder-yarn-open",
"__yarn__": "folder-yarn-open",
"husky": "folder-husky-open",
".husky": "folder-husky-open",
"_husky": "folder-husky-open",
+ "-husky": "folder-husky-open",
"__husky__": "folder-husky-open",
"storybook": "folder-storybook-open",
".storybook": "folder-storybook-open",
"_storybook": "folder-storybook-open",
+ "-storybook": "folder-storybook-open",
"__storybook__": "folder-storybook-open",
"stories": "folder-storybook-open",
".stories": "folder-storybook-open",
"_stories": "folder-storybook-open",
+ "-stories": "folder-storybook-open",
"__stories__": "folder-storybook-open",
"base": "folder-base-open",
".base": "folder-base-open",
"_base": "folder-base-open",
+ "-base": "folder-base-open",
"__base__": "folder-base-open",
"bases": "folder-base-open",
".bases": "folder-base-open",
"_bases": "folder-base-open",
+ "-bases": "folder-base-open",
"__bases__": "folder-base-open",
"cart": "folder-cart-open",
".cart": "folder-cart-open",
"_cart": "folder-cart-open",
+ "-cart": "folder-cart-open",
"__cart__": "folder-cart-open",
"shopping-cart": "folder-cart-open",
".shopping-cart": "folder-cart-open",
"_shopping-cart": "folder-cart-open",
+ "-shopping-cart": "folder-cart-open",
"__shopping-cart__": "folder-cart-open",
"shopping": "folder-cart-open",
".shopping": "folder-cart-open",
"_shopping": "folder-cart-open",
+ "-shopping": "folder-cart-open",
"__shopping__": "folder-cart-open",
"shop": "folder-cart-open",
".shop": "folder-cart-open",
"_shop": "folder-cart-open",
+ "-shop": "folder-cart-open",
"__shop__": "folder-cart-open",
"home": "folder-home-open",
".home": "folder-home-open",
"_home": "folder-home-open",
+ "-home": "folder-home-open",
"__home__": "folder-home-open",
"start": "folder-home-open",
".start": "folder-home-open",
"_start": "folder-home-open",
+ "-start": "folder-home-open",
"__start__": "folder-home-open",
"main": "folder-home-open",
".main": "folder-home-open",
"_main": "folder-home-open",
+ "-main": "folder-home-open",
"__main__": "folder-home-open",
"landing": "folder-home-open",
".landing": "folder-home-open",
"_landing": "folder-home-open",
+ "-landing": "folder-home-open",
"__landing__": "folder-home-open",
"project": "folder-project-open",
".project": "folder-project-open",
"_project": "folder-project-open",
+ "-project": "folder-project-open",
"__project__": "folder-project-open",
"projects": "folder-project-open",
".projects": "folder-project-open",
"_projects": "folder-project-open",
+ "-projects": "folder-project-open",
"__projects__": "folder-project-open",
"proj": "folder-project-open",
".proj": "folder-project-open",
"_proj": "folder-project-open",
+ "-proj": "folder-project-open",
"__proj__": "folder-project-open",
"projs": "folder-project-open",
".projs": "folder-project-open",
"_projs": "folder-project-open",
+ "-projs": "folder-project-open",
"__projs__": "folder-project-open",
"prompt": "folder-prompts-open",
".prompt": "folder-prompts-open",
"_prompt": "folder-prompts-open",
+ "-prompt": "folder-prompts-open",
"__prompt__": "folder-prompts-open",
"prompts": "folder-prompts-open",
".prompts": "folder-prompts-open",
"_prompts": "folder-prompts-open",
+ "-prompts": "folder-prompts-open",
"__prompts__": "folder-prompts-open",
"interface": "folder-interface-open",
".interface": "folder-interface-open",
"_interface": "folder-interface-open",
+ "-interface": "folder-interface-open",
"__interface__": "folder-interface-open",
"interfaces": "folder-interface-open",
".interfaces": "folder-interface-open",
"_interfaces": "folder-interface-open",
+ "-interfaces": "folder-interface-open",
"__interfaces__": "folder-interface-open",
"netlify": "folder-netlify-open",
".netlify": "folder-netlify-open",
"_netlify": "folder-netlify-open",
+ "-netlify": "folder-netlify-open",
"__netlify__": "folder-netlify-open",
"enum": "folder-enum-open",
".enum": "folder-enum-open",
"_enum": "folder-enum-open",
+ "-enum": "folder-enum-open",
"__enum__": "folder-enum-open",
"enums": "folder-enum-open",
".enums": "folder-enum-open",
"_enums": "folder-enum-open",
+ "-enums": "folder-enum-open",
"__enums__": "folder-enum-open",
"pact": "folder-contract-open",
".pact": "folder-contract-open",
"_pact": "folder-contract-open",
+ "-pact": "folder-contract-open",
"__pact__": "folder-contract-open",
"pacts": "folder-contract-open",
".pacts": "folder-contract-open",
"_pacts": "folder-contract-open",
+ "-pacts": "folder-contract-open",
"__pacts__": "folder-contract-open",
"contract": "folder-contract-open",
".contract": "folder-contract-open",
"_contract": "folder-contract-open",
+ "-contract": "folder-contract-open",
"__contract__": "folder-contract-open",
"contracts": "folder-contract-open",
".contracts": "folder-contract-open",
"_contracts": "folder-contract-open",
+ "-contracts": "folder-contract-open",
"__contracts__": "folder-contract-open",
"contract-testing": "folder-contract-open",
".contract-testing": "folder-contract-open",
"_contract-testing": "folder-contract-open",
+ "-contract-testing": "folder-contract-open",
"__contract-testing__": "folder-contract-open",
"contract-test": "folder-contract-open",
".contract-test": "folder-contract-open",
"_contract-test": "folder-contract-open",
+ "-contract-test": "folder-contract-open",
"__contract-test__": "folder-contract-open",
"contract-tests": "folder-contract-open",
".contract-tests": "folder-contract-open",
"_contract-tests": "folder-contract-open",
+ "-contract-tests": "folder-contract-open",
"__contract-tests__": "folder-contract-open",
"helm": "folder-helm-open",
".helm": "folder-helm-open",
"_helm": "folder-helm-open",
+ "-helm": "folder-helm-open",
"__helm__": "folder-helm-open",
"helmchart": "folder-helm-open",
".helmchart": "folder-helm-open",
"_helmchart": "folder-helm-open",
+ "-helmchart": "folder-helm-open",
"__helmchart__": "folder-helm-open",
"helmcharts": "folder-helm-open",
".helmcharts": "folder-helm-open",
"_helmcharts": "folder-helm-open",
+ "-helmcharts": "folder-helm-open",
"__helmcharts__": "folder-helm-open",
"queue": "folder-queue-open",
".queue": "folder-queue-open",
"_queue": "folder-queue-open",
+ "-queue": "folder-queue-open",
"__queue__": "folder-queue-open",
"queues": "folder-queue-open",
".queues": "folder-queue-open",
"_queues": "folder-queue-open",
+ "-queues": "folder-queue-open",
"__queues__": "folder-queue-open",
"bull": "folder-queue-open",
".bull": "folder-queue-open",
"_bull": "folder-queue-open",
+ "-bull": "folder-queue-open",
"__bull__": "folder-queue-open",
"mq": "folder-queue-open",
".mq": "folder-queue-open",
"_mq": "folder-queue-open",
+ "-mq": "folder-queue-open",
"__mq__": "folder-queue-open",
"vercel": "folder-vercel-open",
".vercel": "folder-vercel-open",
"_vercel": "folder-vercel-open",
+ "-vercel": "folder-vercel-open",
"__vercel__": "folder-vercel-open",
"now": "folder-vercel-open",
".now": "folder-vercel-open",
"_now": "folder-vercel-open",
+ "-now": "folder-vercel-open",
"__now__": "folder-vercel-open",
"cypress": "folder-cypress-open",
".cypress": "folder-cypress-open",
"_cypress": "folder-cypress-open",
+ "-cypress": "folder-cypress-open",
"__cypress__": "folder-cypress-open",
"decorator": "folder-decorators-open",
".decorator": "folder-decorators-open",
"_decorator": "folder-decorators-open",
+ "-decorator": "folder-decorators-open",
"__decorator__": "folder-decorators-open",
"decorators": "folder-decorators-open",
".decorators": "folder-decorators-open",
"_decorators": "folder-decorators-open",
+ "-decorators": "folder-decorators-open",
"__decorators__": "folder-decorators-open",
"java": "folder-java-open",
".java": "folder-java-open",
"_java": "folder-java-open",
+ "-java": "folder-java-open",
"__java__": "folder-java-open",
"resolver": "folder-resolver-open",
".resolver": "folder-resolver-open",
"_resolver": "folder-resolver-open",
+ "-resolver": "folder-resolver-open",
"__resolver__": "folder-resolver-open",
"resolvers": "folder-resolver-open",
".resolvers": "folder-resolver-open",
"_resolvers": "folder-resolver-open",
+ "-resolvers": "folder-resolver-open",
"__resolvers__": "folder-resolver-open",
"angular": "folder-angular-open",
".angular": "folder-angular-open",
"_angular": "folder-angular-open",
+ "-angular": "folder-angular-open",
"__angular__": "folder-angular-open",
"unity": "folder-unity-open",
".unity": "folder-unity-open",
"_unity": "folder-unity-open",
+ "-unity": "folder-unity-open",
"__unity__": "folder-unity-open",
"pdf": "folder-pdf-open",
".pdf": "folder-pdf-open",
"_pdf": "folder-pdf-open",
+ "-pdf": "folder-pdf-open",
"__pdf__": "folder-pdf-open",
"pdfs": "folder-pdf-open",
".pdfs": "folder-pdf-open",
"_pdfs": "folder-pdf-open",
+ "-pdfs": "folder-pdf-open",
"__pdfs__": "folder-pdf-open",
"protobuf": "folder-proto-open",
".protobuf": "folder-proto-open",
"_protobuf": "folder-proto-open",
+ "-protobuf": "folder-proto-open",
"__protobuf__": "folder-proto-open",
"protobufs": "folder-proto-open",
".protobufs": "folder-proto-open",
"_protobufs": "folder-proto-open",
+ "-protobufs": "folder-proto-open",
"__protobufs__": "folder-proto-open",
"proto": "folder-proto-open",
".proto": "folder-proto-open",
"_proto": "folder-proto-open",
+ "-proto": "folder-proto-open",
"protos": "folder-proto-open",
".protos": "folder-proto-open",
"_protos": "folder-proto-open",
+ "-protos": "folder-proto-open",
"__protos__": "folder-proto-open",
"plastic": "folder-plastic-open",
".plastic": "folder-plastic-open",
"_plastic": "folder-plastic-open",
+ "-plastic": "folder-plastic-open",
"__plastic__": "folder-plastic-open",
"gamemaker": "folder-gamemaker-open",
".gamemaker": "folder-gamemaker-open",
"_gamemaker": "folder-gamemaker-open",
+ "-gamemaker": "folder-gamemaker-open",
"__gamemaker__": "folder-gamemaker-open",
"gamemaker2": "folder-gamemaker-open",
".gamemaker2": "folder-gamemaker-open",
"_gamemaker2": "folder-gamemaker-open",
+ "-gamemaker2": "folder-gamemaker-open",
"__gamemaker2__": "folder-gamemaker-open",
"hg": "folder-mercurial-open",
".hg": "folder-mercurial-open",
"_hg": "folder-mercurial-open",
+ "-hg": "folder-mercurial-open",
"__hg__": "folder-mercurial-open",
"hghooks": "folder-mercurial-open",
".hghooks": "folder-mercurial-open",
"_hghooks": "folder-mercurial-open",
+ "-hghooks": "folder-mercurial-open",
"__hghooks__": "folder-mercurial-open",
"hgext": "folder-mercurial-open",
".hgext": "folder-mercurial-open",
"_hgext": "folder-mercurial-open",
+ "-hgext": "folder-mercurial-open",
"__hgext__": "folder-mercurial-open",
"godot": "folder-godot-open",
".godot": "folder-godot-open",
"_godot": "folder-godot-open",
+ "-godot": "folder-godot-open",
"__godot__": "folder-godot-open",
"godot-cpp": "folder-godot-open",
".godot-cpp": "folder-godot-open",
"_godot-cpp": "folder-godot-open",
+ "-godot-cpp": "folder-godot-open",
"__godot-cpp__": "folder-godot-open",
"lottie": "folder-lottie-open",
".lottie": "folder-lottie-open",
"_lottie": "folder-lottie-open",
+ "-lottie": "folder-lottie-open",
"__lottie__": "folder-lottie-open",
"lotties": "folder-lottie-open",
".lotties": "folder-lottie-open",
"_lotties": "folder-lottie-open",
+ "-lotties": "folder-lottie-open",
"__lotties__": "folder-lottie-open",
"lottiefiles": "folder-lottie-open",
".lottiefiles": "folder-lottie-open",
"_lottiefiles": "folder-lottie-open",
+ "-lottiefiles": "folder-lottie-open",
"__lottiefiles__": "folder-lottie-open",
"taskfile": "folder-taskfile-open",
".taskfile": "folder-taskfile-open",
"_taskfile": "folder-taskfile-open",
+ "-taskfile": "folder-taskfile-open",
"__taskfile__": "folder-taskfile-open",
"taskfiles": "folder-taskfile-open",
".taskfiles": "folder-taskfile-open",
"_taskfiles": "folder-taskfile-open",
+ "-taskfiles": "folder-taskfile-open",
"__taskfiles__": "folder-taskfile-open",
"drizzle": "folder-drizzle-open",
".drizzle": "folder-drizzle-open",
"_drizzle": "folder-drizzle-open",
+ "-drizzle": "folder-drizzle-open",
"__drizzle__": "folder-drizzle-open",
"cloudflare": "folder-cloudflare-open",
".cloudflare": "folder-cloudflare-open",
"_cloudflare": "folder-cloudflare-open",
+ "-cloudflare": "folder-cloudflare-open",
"__cloudflare__": "folder-cloudflare-open",
"seeds": "folder-seeders-open",
".seeds": "folder-seeders-open",
"_seeds": "folder-seeders-open",
+ "-seeds": "folder-seeders-open",
"__seeds__": "folder-seeders-open",
"seeders": "folder-seeders-open",
".seeders": "folder-seeders-open",
"_seeders": "folder-seeders-open",
+ "-seeders": "folder-seeders-open",
"__seeders__": "folder-seeders-open",
"seed": "folder-seeders-open",
".seed": "folder-seeders-open",
"_seed": "folder-seeders-open",
+ "-seed": "folder-seeders-open",
"__seed__": "folder-seeders-open",
"seeding": "folder-seeders-open",
".seeding": "folder-seeders-open",
"_seeding": "folder-seeders-open",
+ "-seeding": "folder-seeders-open",
"__seeding__": "folder-seeders-open",
"store": "folder-store-open",
".store": "folder-store-open",
"_store": "folder-store-open",
+ "-store": "folder-store-open",
"__store__": "folder-store-open",
"stores": "folder-store-open",
".stores": "folder-store-open",
"_stores": "folder-store-open",
+ "-stores": "folder-store-open",
"__stores__": "folder-store-open",
"bicep": "folder-bicep-open",
".bicep": "folder-bicep-open",
"_bicep": "folder-bicep-open",
+ "-bicep": "folder-bicep-open",
"__bicep__": "folder-bicep-open",
"snap": "folder-snapcraft-open",
".snap": "folder-snapcraft-open",
"_snap": "folder-snapcraft-open",
+ "-snap": "folder-snapcraft-open",
"__snap__": "folder-snapcraft-open",
"snapcraft": "folder-snapcraft-open",
".snapcraft": "folder-snapcraft-open",
"_snapcraft": "folder-snapcraft-open",
+ "-snapcraft": "folder-snapcraft-open",
"__snapcraft__": "folder-snapcraft-open",
"dev": "folder-development-open",
".dev": "folder-development-open",
"_dev": "folder-development-open",
+ "-dev": "folder-development-open",
"__dev__": "folder-development-open",
"development": "folder-development-open",
".development": "folder-development-open",
"_development": "folder-development-open",
+ "-development": "folder-development-open",
"__development__": "folder-development-open",
"flutter": "folder-flutter-open",
".flutter": "folder-flutter-open",
"_flutter": "folder-flutter-open",
+ "-flutter": "folder-flutter-open",
"__flutter__": "folder-flutter-open",
"snippet": "folder-snippet-open",
".snippet": "folder-snippet-open",
"_snippet": "folder-snippet-open",
+ "-snippet": "folder-snippet-open",
"__snippet__": "folder-snippet-open",
"snippets": "folder-snippet-open",
".snippets": "folder-snippet-open",
"_snippets": "folder-snippet-open",
+ "-snippets": "folder-snippet-open",
"__snippets__": "folder-snippet-open",
"element": "folder-element-open",
".element": "folder-element-open",
"_element": "folder-element-open",
+ "-element": "folder-element-open",
"__element__": "folder-element-open",
"elements": "folder-element-open",
".elements": "folder-element-open",
"_elements": "folder-element-open",
+ "-elements": "folder-element-open",
"__elements__": "folder-element-open",
"src-tauri": "folder-src-tauri-open",
".src-tauri": "folder-src-tauri-open",
"_src-tauri": "folder-src-tauri-open",
+ "-src-tauri": "folder-src-tauri-open",
"__src-tauri__": "folder-src-tauri-open",
"favicon": "folder-favicon-open",
".favicon": "folder-favicon-open",
"_favicon": "folder-favicon-open",
+ "-favicon": "folder-favicon-open",
"__favicon__": "folder-favicon-open",
"favicons": "folder-favicon-open",
".favicons": "folder-favicon-open",
"_favicons": "folder-favicon-open",
+ "-favicons": "folder-favicon-open",
"__favicons__": "folder-favicon-open",
"feature": "folder-features-open",
".feature": "folder-features-open",
"_feature": "folder-features-open",
+ "-feature": "folder-features-open",
"__feature__": "folder-features-open",
"features": "folder-features-open",
".features": "folder-features-open",
"_features": "folder-features-open",
+ "-features": "folder-features-open",
"__features__": "folder-features-open",
"feat": "folder-features-open",
".feat": "folder-features-open",
"_feat": "folder-features-open",
+ "-feat": "folder-features-open",
"__feat__": "folder-features-open",
"feats": "folder-features-open",
".feats": "folder-features-open",
"_feats": "folder-features-open",
+ "-feats": "folder-features-open",
"__feats__": "folder-features-open",
"lefthook": "folder-lefthook-open",
".lefthook": "folder-lefthook-open",
"_lefthook": "folder-lefthook-open",
+ "-lefthook": "folder-lefthook-open",
"__lefthook__": "folder-lefthook-open",
"lefthook-local": "folder-lefthook-open",
".lefthook-local": "folder-lefthook-open",
"_lefthook-local": "folder-lefthook-open",
+ "-lefthook-local": "folder-lefthook-open",
"__lefthook-local__": "folder-lefthook-open",
"bloc": "folder-bloc-open",
".bloc": "folder-bloc-open",
"_bloc": "folder-bloc-open",
+ "-bloc": "folder-bloc-open",
"__bloc__": "folder-bloc-open",
"cubit": "folder-bloc-open",
".cubit": "folder-bloc-open",
"_cubit": "folder-bloc-open",
+ "-cubit": "folder-bloc-open",
"__cubit__": "folder-bloc-open",
"blocs": "folder-bloc-open",
".blocs": "folder-bloc-open",
"_blocs": "folder-bloc-open",
+ "-blocs": "folder-bloc-open",
"__blocs__": "folder-bloc-open",
"cubits": "folder-bloc-open",
".cubits": "folder-bloc-open",
"_cubits": "folder-bloc-open",
+ "-cubits": "folder-bloc-open",
"__cubits__": "folder-bloc-open",
"powershell": "folder-powershell-open",
".powershell": "folder-powershell-open",
"_powershell": "folder-powershell-open",
+ "-powershell": "folder-powershell-open",
"__powershell__": "folder-powershell-open",
"ps": "folder-powershell-open",
".ps": "folder-powershell-open",
"_ps": "folder-powershell-open",
+ "-ps": "folder-powershell-open",
"__ps__": "folder-powershell-open",
"ps1": "folder-powershell-open",
".ps1": "folder-powershell-open",
"_ps1": "folder-powershell-open",
+ "-ps1": "folder-powershell-open",
"__ps1__": "folder-powershell-open",
"repository": "folder-repository-open",
".repository": "folder-repository-open",
"_repository": "folder-repository-open",
+ "-repository": "folder-repository-open",
"__repository__": "folder-repository-open",
"repositories": "folder-repository-open",
".repositories": "folder-repository-open",
"_repositories": "folder-repository-open",
+ "-repositories": "folder-repository-open",
"__repositories__": "folder-repository-open",
"repo": "folder-repository-open",
".repo": "folder-repository-open",
"_repo": "folder-repository-open",
+ "-repo": "folder-repository-open",
"__repo__": "folder-repository-open",
"repos": "folder-repository-open",
".repos": "folder-repository-open",
"_repos": "folder-repository-open",
+ "-repos": "folder-repository-open",
"__repos__": "folder-repository-open",
"luau": "folder-luau-open",
".luau": "folder-luau-open",
"_luau": "folder-luau-open",
+ "-luau": "folder-luau-open",
"__luau__": "folder-luau-open",
"obsidian": "folder-obsidian-open",
".obsidian": "folder-obsidian-open",
"_obsidian": "folder-obsidian-open",
+ "-obsidian": "folder-obsidian-open",
"__obsidian__": "folder-obsidian-open",
"trash": "folder-trash-open",
".trash": "folder-trash-open",
"_trash": "folder-trash-open",
+ "-trash": "folder-trash-open",
"__trash__": "folder-trash-open",
"cline_docs": "folder-cline-open",
".cline_docs": "folder-cline-open",
"_cline_docs": "folder-cline-open",
+ "-cline_docs": "folder-cline-open",
"__cline_docs__": "folder-cline-open",
"liquibase": "folder-liquibase-open",
".liquibase": "folder-liquibase-open",
"_liquibase": "folder-liquibase-open",
+ "-liquibase": "folder-liquibase-open",
"__liquibase__": "folder-liquibase-open",
"dart": "folder-dart-open",
".dart": "folder-dart-open",
"_dart": "folder-dart-open",
+ "-dart": "folder-dart-open",
"__dart__": "folder-dart-open",
"dart_tool": "folder-dart-open",
".dart_tool": "folder-dart-open",
"_dart_tool": "folder-dart-open",
+ "-dart_tool": "folder-dart-open",
"__dart_tool__": "folder-dart-open",
"dart_tools": "folder-dart-open",
".dart_tools": "folder-dart-open",
"_dart_tools": "folder-dart-open",
+ "-dart_tools": "folder-dart-open",
"__dart_tools__": "folder-dart-open",
"zeabur": "folder-zeabur-open",
".zeabur": "folder-zeabur-open",
"_zeabur": "folder-zeabur-open",
+ "-zeabur": "folder-zeabur-open",
"__zeabur__": "folder-zeabur-open",
"kusto": "folder-kusto-open",
".kusto": "folder-kusto-open",
"_kusto": "folder-kusto-open",
+ "-kusto": "folder-kusto-open",
"__kusto__": "folder-kusto-open",
"kql": "folder-kusto-open",
".kql": "folder-kusto-open",
"_kql": "folder-kusto-open",
+ "-kql": "folder-kusto-open",
"__kql__": "folder-kusto-open",
"policy": "folder-policy-open",
".policy": "folder-policy-open",
"_policy": "folder-policy-open",
+ "-policy": "folder-policy-open",
"__policy__": "folder-policy-open",
"policies": "folder-policy-open",
".policies": "folder-policy-open",
"_policies": "folder-policy-open",
+ "-policies": "folder-policy-open",
"__policies__": "folder-policy-open",
"attachment": "folder-attachment-open",
".attachment": "folder-attachment-open",
"_attachment": "folder-attachment-open",
+ "-attachment": "folder-attachment-open",
"__attachment__": "folder-attachment-open",
"attachments": "folder-attachment-open",
".attachments": "folder-attachment-open",
"_attachments": "folder-attachment-open",
+ "-attachments": "folder-attachment-open",
"__attachments__": "folder-attachment-open",
"bibliography": "folder-bibliography-open",
".bibliography": "folder-bibliography-open",
"_bibliography": "folder-bibliography-open",
+ "-bibliography": "folder-bibliography-open",
"__bibliography__": "folder-bibliography-open",
"bibliographies": "folder-bibliography-open",
".bibliographies": "folder-bibliography-open",
"_bibliographies": "folder-bibliography-open",
+ "-bibliographies": "folder-bibliography-open",
"__bibliographies__": "folder-bibliography-open",
"book": "folder-bibliography-open",
".book": "folder-bibliography-open",
"_book": "folder-bibliography-open",
+ "-book": "folder-bibliography-open",
"__book__": "folder-bibliography-open",
"books": "folder-bibliography-open",
".books": "folder-bibliography-open",
"_books": "folder-bibliography-open",
+ "-books": "folder-bibliography-open",
"__books__": "folder-bibliography-open",
"link": "folder-link-open",
".link": "folder-link-open",
"_link": "folder-link-open",
+ "-link": "folder-link-open",
"__link__": "folder-link-open",
"links": "folder-link-open",
".links": "folder-link-open",
"_links": "folder-link-open",
+ "-links": "folder-link-open",
"__links__": "folder-link-open",
"pytorch": "folder-pytorch-open",
".pytorch": "folder-pytorch-open",
"_pytorch": "folder-pytorch-open",
+ "-pytorch": "folder-pytorch-open",
"__pytorch__": "folder-pytorch-open",
"torch": "folder-pytorch-open",
".torch": "folder-pytorch-open",
"_torch": "folder-pytorch-open",
+ "-torch": "folder-pytorch-open",
"__torch__": "folder-pytorch-open",
"blender": "folder-blender-open",
".blender": "folder-blender-open",
"_blender": "folder-blender-open",
+ "-blender": "folder-blender-open",
"__blender__": "folder-blender-open",
"blender-assets": "folder-blender-open",
".blender-assets": "folder-blender-open",
"_blender-assets": "folder-blender-open",
+ "-blender-assets": "folder-blender-open",
"__blender-assets__": "folder-blender-open",
"blender-files": "folder-blender-open",
".blender-files": "folder-blender-open",
"_blender-files": "folder-blender-open",
+ "-blender-files": "folder-blender-open",
"__blender-files__": "folder-blender-open",
"blender-project": "folder-blender-open",
".blender-project": "folder-blender-open",
"_blender-project": "folder-blender-open",
+ "-blender-project": "folder-blender-open",
"__blender-project__": "folder-blender-open",
"blender-models": "folder-blender-open",
".blender-models": "folder-blender-open",
"_blender-models": "folder-blender-open",
+ "-blender-models": "folder-blender-open",
"__blender-models__": "folder-blender-open",
"atoms": "folder-atom-open",
".atoms": "folder-atom-open",
"_atoms": "folder-atom-open",
+ "-atoms": "folder-atom-open",
"__atoms__": "folder-atom-open",
"atom": "folder-atom-open",
".atom": "folder-atom-open",
"_atom": "folder-atom-open",
+ "-atom": "folder-atom-open",
"__atom__": "folder-atom-open",
"molecules": "folder-molecule-open",
".molecules": "folder-molecule-open",
"_molecules": "folder-molecule-open",
+ "-molecules": "folder-molecule-open",
"__molecules__": "folder-molecule-open",
"molecule": "folder-molecule-open",
".molecule": "folder-molecule-open",
"_molecule": "folder-molecule-open",
+ "-molecule": "folder-molecule-open",
"__molecule__": "folder-molecule-open",
"organisms": "folder-organism-open",
".organisms": "folder-organism-open",
"_organisms": "folder-organism-open",
+ "-organisms": "folder-organism-open",
"__organisms__": "folder-organism-open",
"organism": "folder-organism-open",
".organism": "folder-organism-open",
"_organism": "folder-organism-open",
+ "-organism": "folder-organism-open",
"__organism__": "folder-organism-open",
".claude": "folder-claude-open",
"..claude": "folder-claude-open",
"_.claude": "folder-claude-open",
+ "-.claude": "folder-claude-open",
"__.claude__": "folder-claude-open",
".cursor": "folder-cursor-open",
"..cursor": "folder-cursor-open",
"_.cursor": "folder-cursor-open",
+ "-.cursor": "folder-cursor-open",
"__.cursor__": "folder-cursor-open",
".gemini": "folder-gemini-ai-open",
"..gemini": "folder-gemini-ai-open",
"_.gemini": "folder-gemini-ai-open",
+ "-.gemini": "folder-gemini-ai-open",
"__.gemini__": "folder-gemini-ai-open",
+ "gemini": "folder-gemini-ai-open",
+ "_gemini": "folder-gemini-ai-open",
+ "-gemini": "folder-gemini-ai-open",
+ "__gemini__": "folder-gemini-ai-open",
+ "gemini-ai": "folder-gemini-ai-open",
+ ".gemini-ai": "folder-gemini-ai-open",
+ "_gemini-ai": "folder-gemini-ai-open",
+ "-gemini-ai": "folder-gemini-ai-open",
+ "__gemini-ai__": "folder-gemini-ai-open",
+ "geminiai": "folder-gemini-ai-open",
+ ".geminiai": "folder-gemini-ai-open",
+ "_geminiai": "folder-gemini-ai-open",
+ "-geminiai": "folder-gemini-ai-open",
+ "__geminiai__": "folder-gemini-ai-open",
"input": "folder-input-open",
".input": "folder-input-open",
"_input": "folder-input-open",
+ "-input": "folder-input-open",
"__input__": "folder-input-open",
"inputs": "folder-input-open",
".inputs": "folder-input-open",
"_inputs": "folder-input-open",
+ "-inputs": "folder-input-open",
"__inputs__": "folder-input-open",
"io": "folder-input-open",
".io": "folder-input-open",
"_io": "folder-input-open",
+ "-io": "folder-input-open",
"__io__": "folder-input-open",
"in": "folder-input-open",
".in": "folder-input-open",
"_in": "folder-input-open",
+ "-in": "folder-input-open",
"__in__": "folder-input-open",
"salt": "folder-salt-open",
".salt": "folder-salt-open",
"_salt": "folder-salt-open",
+ "-salt": "folder-salt-open",
"__salt__": "folder-salt-open",
"saltstack": "folder-salt-open",
".saltstack": "folder-salt-open",
"_saltstack": "folder-salt-open",
+ "-saltstack": "folder-salt-open",
"__saltstack__": "folder-salt-open",
"simulations": "folder-simulations-open",
".simulations": "folder-simulations-open",
"_simulations": "folder-simulations-open",
+ "-simulations": "folder-simulations-open",
"__simulations__": "folder-simulations-open",
"simulation": "folder-simulations-open",
".simulation": "folder-simulations-open",
"_simulation": "folder-simulations-open",
+ "-simulation": "folder-simulations-open",
"__simulation__": "folder-simulations-open",
"sim": "folder-simulations-open",
".sim": "folder-simulations-open",
"_sim": "folder-simulations-open",
+ "-sim": "folder-simulations-open",
"__sim__": "folder-simulations-open",
"sims": "folder-simulations-open",
".sims": "folder-simulations-open",
"_sims": "folder-simulations-open",
+ "-sims": "folder-simulations-open",
"__sims__": "folder-simulations-open",
"metro": "folder-metro-open",
".metro": "folder-metro-open",
"_metro": "folder-metro-open",
+ "-metro": "folder-metro-open",
"__metro__": "folder-metro-open",
"filter": "folder-filter-open",
".filter": "folder-filter-open",
"_filter": "folder-filter-open",
+ "-filter": "folder-filter-open",
"__filter__": "folder-filter-open",
"filters": "folder-filter-open",
".filters": "folder-filter-open",
"_filters": "folder-filter-open",
+ "-filters": "folder-filter-open",
"__filters__": "folder-filter-open",
"toc": "folder-toc-open",
".toc": "folder-toc-open",
"_toc": "folder-toc-open",
+ "-toc": "folder-toc-open",
"__toc__": "folder-toc-open",
"table-of-contents": "folder-toc-open",
".table-of-contents": "folder-toc-open",
"_table-of-contents": "folder-toc-open",
+ "-table-of-contents": "folder-toc-open",
"__table-of-contents__": "folder-toc-open",
"cue": "folder-cue-open",
".cue": "folder-cue-open",
"_cue": "folder-cue-open",
+ "-cue": "folder-cue-open",
"__cue__": "folder-cue-open",
"cues": "folder-cue-open",
".cues": "folder-cue-open",
"_cues": "folder-cue-open",
+ "-cues": "folder-cue-open",
"__cues__": "folder-cue-open",
"license": "folder-license-open",
".license": "folder-license-open",
"_license": "folder-license-open",
+ "-license": "folder-license-open",
"__license__": "folder-license-open",
"licenses": "folder-license-open",
".licenses": "folder-license-open",
"_licenses": "folder-license-open",
- "__licenses__": "folder-license-open"
+ "-licenses": "folder-license-open",
+ "__licenses__": "folder-license-open",
+ "form": "folder-form-open",
+ ".form": "folder-form-open",
+ "_form": "folder-form-open",
+ "-form": "folder-form-open",
+ "__form__": "folder-form-open",
+ "forms": "folder-form-open",
+ ".forms": "folder-form-open",
+ "_forms": "folder-form-open",
+ "-forms": "folder-form-open",
+ "__forms__": "folder-form-open"
},
"rootFolderNames": {},
"rootFolderNamesExpanded": {},
@@ -7212,6 +9098,7 @@
"jrxml": "xml",
"xmp": "xml",
"toml": "toml",
+ "toon": "toon",
"png": "image",
"jpeg": "image",
"jpg": "image",
@@ -7934,6 +9821,7 @@
"story.tsx": "storybook",
"stories.svelte": "storybook",
"story.mdx": "storybook",
+ "stories.vue": "storybook",
"wpy": "wepy",
"hcl": "hcl",
"san": "san",
@@ -8317,6 +10205,7 @@
"cue": "cue",
"lean": "lean",
"sls": "salt",
+ "m2": "macaulay2",
"cljx": "clojure",
"clojure": "clojure",
"edn": "clojure",
@@ -8574,6 +10463,8 @@
".clang-tidy": "settings",
".conf": "settings",
"compile_flags.txt": "settings",
+ "typedoc.js": "typedoc",
+ "typedoc.json": "typedoc",
"markdoc.config.js": "markdoc-config",
"markdoc.config.mjs": "markdoc-config",
"markdoc.config.cjs": "markdoc-config",
@@ -10294,6 +12185,8 @@
"panda.config.cts": "panda",
"biome.json": "biome",
"biome.jsonc": "biome",
+ ".biome.json": "biome",
+ ".biome.jsonc": "biome",
"esbuild.js": "esbuild",
"esbuild.mjs": "esbuild",
"esbuild.cjs": "esbuild",
@@ -10533,6 +12426,7 @@
".oxlintrc.jsonc": "oxc",
".oxfmtrc.json": "oxc",
".oxfmtrc.jsonc": "oxc",
+ "oxlint.config.ts": "oxc",
"claude.md": "claude",
"claude.local.md": "claude",
".cursorignore": "cursor",
@@ -10979,44 +12873,54 @@
"jinja": "folder-jinja_light",
".jinja": "folder-jinja_light",
"_jinja": "folder-jinja_light",
+ "-jinja": "folder-jinja_light",
"__jinja__": "folder-jinja_light",
"jinja2": "folder-jinja_light",
".jinja2": "folder-jinja_light",
"_jinja2": "folder-jinja_light",
+ "-jinja2": "folder-jinja_light",
"__jinja2__": "folder-jinja_light",
"j2": "folder-jinja_light",
".j2": "folder-jinja_light",
"_j2": "folder-jinja_light",
+ "-j2": "folder-jinja_light",
"__j2__": "folder-jinja_light",
"idea": "folder-intellij_light",
".idea": "folder-intellij_light",
"_idea": "folder-intellij_light",
+ "-idea": "folder-intellij_light",
"__idea__": "folder-intellij_light",
".cursor": "folder-cursor_light",
"..cursor": "folder-cursor_light",
"_.cursor": "folder-cursor_light",
+ "-.cursor": "folder-cursor_light",
"__.cursor__": "folder-cursor_light"
},
"folderNamesExpanded": {
"jinja": "folder-jinja-open_light",
".jinja": "folder-jinja-open_light",
"_jinja": "folder-jinja-open_light",
+ "-jinja": "folder-jinja-open_light",
"__jinja__": "folder-jinja-open_light",
"jinja2": "folder-jinja-open_light",
".jinja2": "folder-jinja-open_light",
"_jinja2": "folder-jinja-open_light",
+ "-jinja2": "folder-jinja-open_light",
"__jinja2__": "folder-jinja-open_light",
"j2": "folder-jinja-open_light",
".j2": "folder-jinja-open_light",
"_j2": "folder-jinja-open_light",
+ "-j2": "folder-jinja-open_light",
"__j2__": "folder-jinja-open_light",
"idea": "folder-intellij-open_light",
".idea": "folder-intellij-open_light",
"_idea": "folder-intellij-open_light",
+ "-idea": "folder-intellij-open_light",
"__idea__": "folder-intellij-open_light",
".cursor": "folder-cursor-open_light",
"..cursor": "folder-cursor-open_light",
"_.cursor": "folder-cursor-open_light",
+ "-.cursor": "folder-cursor-open_light",
"__.cursor__": "folder-cursor-open_light"
},
"rootFolderNames": {},
diff --git a/options/fileicon/material-icon-svgs.json b/options/fileicon/material-icon-svgs.json
index 6713c4afa9c..4e476816212 100644
--- a/options/fileicon/material-icon-svgs.json
+++ b/options/fileicon/material-icon-svgs.json
@@ -375,6 +375,8 @@
"folder-font": "",
"folder-forgejo-open": "",
"folder-forgejo": "",
+ "folder-form-open": "",
+ "folder-form": "",
"folder-functions-open": "",
"folder-functions": "",
"folder-gamemaker-open": "",
@@ -590,6 +592,8 @@
"folder-redux-selector.clone": "",
"folder-redux-store-open.clone": "",
"folder-redux-store.clone": "",
+ "folder-redux-toolkit-open.clone": "",
+ "folder-redux-toolkit.clone": "",
"folder-repository-open": "",
"folder-repository": "",
"folder-resolver-open": "",
@@ -860,6 +864,7 @@
"luau": "",
"lynx": "",
"lyric": "",
+ "macaulay2": "",
"makefile": "",
"markdoc-config": "",
"markdoc": "",
@@ -935,7 +940,7 @@
"opentofu": "",
"opentofu_light": "",
"otne": "",
- "oxc": "",
+ "oxc": "",
"packship": "",
"palette": "",
"panda": "",
@@ -1122,6 +1127,7 @@
"todo": "",
"toml": "",
"toml_light": "",
+ "toon": "",
"travis": "",
"tree": "",
"trigger": "",
@@ -1133,6 +1139,7 @@
"turborepo_light": "",
"twig": "",
"twine": "",
+ "typedoc": "",
"typescript-def": "",
"typescript": "",
"typst": "",
@@ -1163,8 +1170,8 @@
"vim": "",
"virtual": "",
"visualstudio": "",
- "vite": "",
- "vitest": "",
+ "vite": "",
+ "vitest": "",
"vlang": "",
"vscode": "",
"vue-config": "",
diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json
index 97e2ebe0d1d..27695a8f5ac 100644
--- a/options/locale/locale_en-US.json
+++ b/options/locale/locale_en-US.json
@@ -84,6 +84,7 @@
"save": "Save",
"add": "Add",
"add_all": "Add All",
+ "dismiss": "Dismiss",
"remove": "Remove",
"remove_all": "Remove All",
"remove_label_str": "Remove item \"%s\"",
@@ -224,7 +225,7 @@
"startpage.lightweight": "Lightweight",
"startpage.lightweight_desc": "Gitea has low minimal requirements and can run on an inexpensive Raspberry Pi. Save your machine energy!",
"startpage.license": "Open Source",
- "startpage.license_desc": "Go get %[2]s! Join us by contributing to make this project even better. Don't be shy to be a contributor!",
+ "startpage.license_desc": "Go get %[2]s! Join us by contributing to make this project even better. Don't hesitate to contribute!",
"install.install": "Installation",
"install.installing_desc": "Installing now, please wait…",
"install.title": "Initial Configuration",
@@ -284,12 +285,6 @@
"install.register_confirm": "Require Email Confirmation to Register",
"install.mail_notify": "Enable Email Notifications",
"install.server_service_title": "Server and Third-Party Service Settings",
- "install.offline_mode": "Enable Local Mode",
- "install.offline_mode_popup": "Disable third-party content delivery networks and serve all resources locally.",
- "install.disable_gravatar": "Disable Gravatar",
- "install.disable_gravatar_popup": "Disable Gravatar and third-party avatar sources. A default avatar will be used unless a user locally uploads an avatar.",
- "install.federated_avatar_lookup": "Enable Federated Avatars",
- "install.federated_avatar_lookup_popup": "Enable federated avatar lookup using Libravatar.",
"install.disable_registration": "Disable Self-Registration",
"install.disable_registration_popup": "Disable user self-registration. Only administrators will be able to create new user accounts.",
"install.allow_only_external_registration_popup": "Allow Registration Only Through External Services",
@@ -871,7 +866,7 @@
"settings.permissions_list": "Permissions:",
"settings.manage_oauth2_applications": "Manage OAuth2 Applications",
"settings.edit_oauth2_application": "Edit OAuth2 Application",
- "settings.oauth2_applications_desc": "OAuth2 applications enables your third-party application to securely authenticate users at this Gitea instance.",
+ "settings.oauth2_applications_desc": "OAuth2 applications enable your third-party application to securely authenticate users at this Gitea instance.",
"settings.remove_oauth2_application": "Remove OAuth2 Application",
"settings.remove_oauth2_application_desc": "Removing an OAuth2 application will revoke access to all signed access tokens. Continue?",
"settings.remove_oauth2_application_success": "The application has been deleted.",
@@ -890,7 +885,7 @@
"settings.oauth2_regenerate_secret_hint": "Lost your secret?",
"settings.oauth2_client_secret_hint": "The secret will not be shown again after you leave or refresh this page. Please ensure that you have saved it.",
"settings.oauth2_application_edit": "Edit",
- "settings.oauth2_application_create_description": "OAuth2 applications gives your third-party application access to user accounts on this instance.",
+ "settings.oauth2_application_create_description": "OAuth2 applications give your third-party application access to user accounts on this instance.",
"settings.oauth2_application_remove_description": "Removing an OAuth2 application will prevent it from accessing authorized user accounts on this instance. Continue?",
"settings.oauth2_application_locked": "Gitea pre-registers some OAuth2 applications on startup if enabled in config. To prevent unexpected behavior, these can neither be edited nor removed. Please refer to the OAuth2 documentation for more information.",
"settings.authorized_oauth2_applications": "Authorized OAuth2 Applications",
@@ -1524,6 +1519,7 @@
"repo.issues.commented_at": "commented %s",
"repo.issues.delete_comment_confirm": "Are you sure you want to delete this comment?",
"repo.issues.context.copy_link": "Copy Link",
+ "repo.issues.context.copy_source": "Copy Source",
"repo.issues.context.quote_reply": "Quote Reply",
"repo.issues.context.reference_issue": "Reference in New Issue",
"repo.issues.context.edit": "Edit",
@@ -3192,7 +3188,6 @@
"admin.config.custom_conf": "Configuration File Path",
"admin.config.custom_file_root_path": "Custom File Root Path",
"admin.config.domain": "Server Domain",
- "admin.config.offline_mode": "Local Mode",
"admin.config.disable_router_log": "Disable Router Log",
"admin.config.run_user": "Run As Username",
"admin.config.run_mode": "Run Mode",
@@ -3278,6 +3273,13 @@
"admin.config.cache_test_failed": "Failed to probe the cache: %v.",
"admin.config.cache_test_slow": "Cache test successful, but response is slow: %s.",
"admin.config.cache_test_succeeded": "Cache test successful, got a response in %s.",
+ "admin.config.common.start_time": "Start time",
+ "admin.config.common.end_time": "End time",
+ "admin.config.common.skip_time_check": "Leave time empty (clear the field) to skip time check",
+ "admin.config.instance_maintenance": "Instance Maintenance",
+ "admin.config.instance_maintenance_mode.admin_web_access_only": "Only allow admin to access the web UI",
+ "admin.config.instance_web_banner.enabled": "Show banner",
+ "admin.config.instance_web_banner.message_placeholder": "Banner message (supports markdown)",
"admin.config.session_config": "Session Configuration",
"admin.config.session_provider": "Session Provider",
"admin.config.provider_config": "Provider Config",
@@ -3288,7 +3290,7 @@
"admin.config.cookie_life_time": "Cookie Life Time",
"admin.config.picture_config": "Picture and Avatar Configuration",
"admin.config.picture_service": "Picture Service",
- "admin.config.disable_gravatar": "Disable Gravatar",
+ "admin.config.enable_gravatar": "Enable Gravatar",
"admin.config.enable_federated_avatar": "Enable Federated Avatars",
"admin.config.open_with_editor_app_help": "The \"Open with\" editors for the clone menu. If left empty, the default will be used. Expand to see the default.",
"admin.config.git_guide_remote_name": "Repository remote name for git commands in the guide",
@@ -3672,6 +3674,8 @@
"actions.runners.reset_registration_token_confirm": "Would you like to invalidate the current token and generate a new one?",
"actions.runners.reset_registration_token_success": "Runner registration token reset successfully",
"actions.runs.all_workflows": "All Workflows",
+ "actions.runs.workflow_run_count_1": "%d workflow run",
+ "actions.runs.workflow_run_count_n": "%d workflow runs",
"actions.runs.commit": "Commit",
"actions.runs.scheduled": "Scheduled",
"actions.runs.pushed_by": "pushed by",
diff --git a/options/locale/locale_ga-IE.json b/options/locale/locale_ga-IE.json
index ad00325b02a..4669252a6e8 100644
--- a/options/locale/locale_ga-IE.json
+++ b/options/locale/locale_ga-IE.json
@@ -84,6 +84,7 @@
"save": "Sábháil",
"add": "Cuir",
"add_all": "Cuir Gach",
+ "dismiss": "Díbhe",
"remove": "Bain",
"remove_all": "Bain Gach",
"remove_label_str": "Bain mír “%s”",
@@ -224,7 +225,7 @@
"startpage.lightweight": "Éadrom",
"startpage.lightweight_desc": "Tá íosta riachtanais íseal ag Gitea agus is féidir leo rith ar Raspberry Pi saor. Sábháil fuinneamh do mheaisín!",
"startpage.license": "Foinse Oscailte",
- "startpage.license_desc": "Téigh go bhfaighidh %[2]s! Bí linn trí cur leis chun an tionscadal seo a fheabhsú fós. Ná bíodh cúthail ort a bheith i do rannpháirtí!",
+ "startpage.license_desc": "Téigh agus faigh %[2]s! Bí linn trí cur leis chun an tionscadal seo a dhéanamh níos fearr fós. Ná bíodh leisce ort cur leis!",
"install.install": "Suiteáil",
"install.installing_desc": "Suiteáil anois, fan go fóill…",
"install.title": "Cumraíocht Tosaigh",
@@ -284,12 +285,6 @@
"install.register_confirm": "Deimhniú Ríomhphoist a cheangal le Clárú",
"install.mail_notify": "Cumasaigh Fógraí Ríomhphoist",
"install.server_service_title": "Socruithe Freastalaí agus Seirbhíse Tríú Páirtí",
- "install.offline_mode": "Cumasaigh Mód Áitiúil",
- "install.offline_mode_popup": "Díchumasaigh líonraí seachadta ábhair tríú páirtí agus freastal ar na hacmhainní go léir go háitiúil.",
- "install.disable_gravatar": "Díchumasaigh Gravatar",
- "install.disable_gravatar_popup": "Díchumasaigh foinsí abhatár Gravatar agus tríú páirtí. Úsáidfear abhatár réamhshocraithe mura n-uaslódálann úsáideoir abhatár go háitiúil.",
- "install.federated_avatar_lookup": "Cumasaigh Abhatáir Chónaidhme",
- "install.federated_avatar_lookup_popup": "Cumasaigh cuardach avatar cónaidhme ag baint úsáide as Libravatar.",
"install.disable_registration": "Díchumasaigh Féin-Chlárú",
"install.disable_registration_popup": "Díchumasaigh féinchlárú úsáideora. Ní bheidh ach riarthóirí in ann cuntais úsáideora nua a chruthú.",
"install.allow_only_external_registration_popup": "Ceadaigh Clárú Trí Sheirbhísí Seachtracha amháin",
@@ -871,7 +866,7 @@
"settings.permissions_list": "Ceadanna:",
"settings.manage_oauth2_applications": "Bainistigh Feidhmchláir OAuth2",
"settings.edit_oauth2_application": "Cuir Feidhmchlár OAuth2 in eagar",
- "settings.oauth2_applications_desc": "Cumasaíonn feidhmchláir OAuth2 d’fheidhmchlár tríú páirtí úsáideoirí a fhíordheimhniú go slán ag an ásc Gitea seo.",
+ "settings.oauth2_applications_desc": "Cuireann feidhmchláir OAuth2 ar chumas d’fheidhmchlár tríú páirtí úsáideoirí a fhíordheimhniú go slán ag an gcás Gitea seo.",
"settings.remove_oauth2_application": "Bain Feidhmchlár OAuth2",
"settings.remove_oauth2_application_desc": "Ag baint feidhmchlár OAuth2, cúlghairfear rochtain ar gach comhartha rochtana sínithe. Lean ar aghaidh?",
"settings.remove_oauth2_application_success": "Scriosadh an feidhmchlár.",
@@ -890,7 +885,7 @@
"settings.oauth2_regenerate_secret_hint": "Chaill tú do rún?",
"settings.oauth2_client_secret_hint": "Ní thaispeánfar an rún arís tar éis duit an leathanach seo a fhágáil nó a athnuachan. Déan cinnte le do thoil gur shábháil tú é.",
"settings.oauth2_application_edit": "Cuir in eagar",
- "settings.oauth2_application_create_description": "Tugann feidhmchláir OAuth2 rochtain d'iarratas tríú páirtí ar chuntais úsáideora ar an gcás seo.",
+ "settings.oauth2_application_create_description": "Tugann feidhmchláir OAuth2 rochtain do d’fheidhmchlár tríú páirtí ar chuntais úsáideora ar an gcás seo.",
"settings.oauth2_application_remove_description": "Cuirfear feidhmchlár OAuth2 a bhaint cosc air rochtain a fháil ar chuntais úsáideora údaraithe ar an gcás seo. Lean ar aghaidh?",
"settings.oauth2_application_locked": "Réamhchláraíonn Gitea roinnt feidhmchlár OAuth2 ar thosú má tá sé cumasaithe i gcumraíocht. Chun iompar gan choinne a chosc, ní féidir iad seo a chur in eagar ná a bhaint. Féach do thoil do dhoiciméadú OAuth2 le haghaidh tuilleadh faisnéise.",
"settings.authorized_oauth2_applications": "Feidhmchláir Údaraithe OAuth2",
@@ -1524,6 +1519,7 @@
"repo.issues.commented_at": "trácht %s ",
"repo.issues.delete_comment_confirm": "An bhfuil tú cinnte gur mhaith leat an trácht seo a scriosadh?",
"repo.issues.context.copy_link": "Cóipeáil Nasc",
+ "repo.issues.context.copy_source": "Cóipeáil Foinse",
"repo.issues.context.quote_reply": "Luaigh Freagra",
"repo.issues.context.reference_issue": "Tagairt in Eagrán Nua",
"repo.issues.context.edit": "Cuir in eagar",
@@ -3192,7 +3188,6 @@
"admin.config.custom_conf": "Cosán Comhad Cumraíochta",
"admin.config.custom_file_root_path": "Cosán Fréamh Comhad Saincheaptha",
"admin.config.domain": "Fearann Freastalaí",
- "admin.config.offline_mode": "Mód Áitiúil",
"admin.config.disable_router_log": "Díchumasaigh Loga an Ródaire",
"admin.config.run_user": "Rith Mar Ainm úsáideora",
"admin.config.run_mode": "Mód Rith",
@@ -3278,6 +3273,13 @@
"admin.config.cache_test_failed": "Theip ar an taisce a thaiscéaladh: %v.",
"admin.config.cache_test_slow": "D'éirigh leis an tástáil taisce, ach tá an freagra mall: %s.",
"admin.config.cache_test_succeeded": "D'éirigh leis an tástáil taisce, fuair sé freagra i %s.",
+ "admin.config.common.start_time": "Am tosaithe",
+ "admin.config.common.end_time": "Am deiridh",
+ "admin.config.common.skip_time_check": "Fág an t-am folamh (glan an réimse) chun seiceáil ama a scipeáil",
+ "admin.config.instance_maintenance": "Cothabháil Cásanna",
+ "admin.config.instance_maintenance_mode.admin_web_access_only": "Lig don riarthóir amháin rochtain a fháil ar chomhéadan gréasáin",
+ "admin.config.instance_web_banner.enabled": "Taispeáin meirge",
+ "admin.config.instance_web_banner.message_placeholder": "Teachtaireacht meirge (tacaíonn sé le Markdown)",
"admin.config.session_config": "Cumraíocht Seisiúin",
"admin.config.session_provider": "Soláthraí Seisiúin",
"admin.config.provider_config": "Cumraíocht Soláthraí",
@@ -3288,7 +3290,7 @@
"admin.config.cookie_life_time": "Am Saoil Fianán",
"admin.config.picture_config": "Cumraíocht Pictiúr agus Avatar",
"admin.config.picture_service": "Seirbhís Pictiúr",
- "admin.config.disable_gravatar": "Díchumasaigh Gravatar",
+ "admin.config.enable_gravatar": "Cumasaigh Gravatar",
"admin.config.enable_federated_avatar": "Cumasaigh Avatars Cónaidhme",
"admin.config.open_with_editor_app_help": "Na heagarthóirí \"Oscailte le\" don roghchlár Clón. Má fhágtar folamh é, úsáidfear an réamhshocrú. Leathnaigh chun an réamhshocrú a fheiceáil.",
"admin.config.git_guide_remote_name": "Ainm iargúlta stórais le haghaidh orduithe git sa treoir",
@@ -3672,6 +3674,8 @@
"actions.runners.reset_registration_token_confirm": "Ar mhaith leat an comhartha reatha a neamhbhailiú agus ceann nua a ghiniúint?",
"actions.runners.reset_registration_token_success": "D'éirigh le hathshocrú comhartha clárúcháin an dara háit",
"actions.runs.all_workflows": "Gach Sreafaí Oibre",
+ "actions.runs.workflow_run_count_1": "%d rith sreabha oibre",
+ "actions.runs.workflow_run_count_n": "%d rith sreabha oibre",
"actions.runs.commit": "Tiomantas",
"actions.runs.scheduled": "Sceidealaithe",
"actions.runs.pushed_by": "bhrú ag",
diff --git a/options/locale/locale_zh-CN.json b/options/locale/locale_zh-CN.json
index 861090cea71..2f0dced6e0b 100644
--- a/options/locale/locale_zh-CN.json
+++ b/options/locale/locale_zh-CN.json
@@ -84,6 +84,7 @@
"save": "保存",
"add": "添加",
"add_all": "添加所有",
+ "dismiss": "忽略",
"remove": "移除",
"remove_all": "移除所有",
"remove_label_str": "删除标签「%s」",
@@ -216,15 +217,15 @@
"error.report_message": "如果您确定这是一个 Gitea bug,请在 这里 搜索问题,或在必要时创建一个新工单。",
"error.not_found": "找不到目标。",
"error.network_error": "网络错误",
- "startpage.app_desc": "一款极易搭建的自助 Git 服务",
+ "startpage.app_desc": "一款极易搭建的自托管 Git 服务",
"startpage.install": "易安装",
- "startpage.install_desc": "通过 二进制 来运行;或者通过 Docker 来运行;或者通过 安装包 来运行。",
+ "startpage.install_desc": "直接运行适合您平台的二进制文件,通过 Docker 部署,或使用软件包安装。",
"startpage.platform": "跨平台",
"startpage.platform_desc": "任何 Go 语言 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行!",
"startpage.lightweight": "轻量级",
- "startpage.lightweight_desc": "一个廉价的树莓派的配置足以满足 Gitea 的最低系统硬件要求。最大程度上节省您的服务器资源!",
+ "startpage.lightweight_desc": "一个廉价的树莓派就足以满足 Gitea 的最低系统硬件要求。最大程度节省您的服务器资源!",
"startpage.license": "开源化",
- "startpage.license_desc": "所有的代码都开源在 %[2]s 上,赶快加入我们来共同发展这个伟大的项目!还等什么?成为贡献者吧!",
+ "startpage.license_desc": "所有代码都开源在 %[2]s,还等什么?赶快加入我们来共同发展这个伟大的项目,成为贡献者吧!",
"install.install": "安装页面",
"install.installing_desc": "正在安装,请稍候…",
"install.title": "初始配置",
@@ -284,12 +285,6 @@
"install.register_confirm": "需要邮件确认注册",
"install.mail_notify": "启用邮件通知提醒",
"install.server_service_title": "服务器和第三方服务设置",
- "install.offline_mode": "启用本地模式",
- "install.offline_mode_popup": "禁用第三方 CDN 并在本地服务所有资源。",
- "install.disable_gravatar": "禁用 Gravatar 头像",
- "install.disable_gravatar_popup": "禁用 Gravatar 和第三方头像源。除非用户在本地上传头像,否则将使用默认头像。",
- "install.federated_avatar_lookup": "启用 Federated 头像",
- "install.federated_avatar_lookup_popup": "启用 Federated 头像查找以使用开源的 Libravatar 服务。",
"install.disable_registration": "禁止用户自助注册",
"install.disable_registration_popup": "禁用用户自助注册。只有管理员才能创建新的用户帐户。",
"install.allow_only_external_registration_popup": "仅允许通过外部服务注册",
@@ -1877,6 +1872,7 @@
"repo.pulls.update_not_allowed": "您无权更新分支",
"repo.pulls.outdated_with_base_branch": "此分支相比基础分支已过期",
"repo.pulls.close": "关闭合并请求",
+ "repo.pulls.reopen": "重新打开",
"repo.pulls.closed_at": "于 %[2]s 关闭此合并请求 ",
"repo.pulls.reopened_at": "于 %[2]s 重新打开此合并请求",
"repo.pulls.cmd_instruction_hint": "查看命令行提示",
@@ -3191,7 +3187,6 @@
"admin.config.custom_conf": "配置文件路径",
"admin.config.custom_file_root_path": "自定义文件根路径",
"admin.config.domain": "服务器域名",
- "admin.config.offline_mode": "离线模式",
"admin.config.disable_router_log": "关闭路由日志",
"admin.config.run_user": "以用户名运行",
"admin.config.run_mode": "运行模式",
@@ -3277,6 +3272,13 @@
"admin.config.cache_test_failed": "缓存测试失败:%v。",
"admin.config.cache_test_slow": "缓存测试成功,但响应缓慢:%s。",
"admin.config.cache_test_succeeded": "缓存测试成功,在 %s 时间内得到响应。",
+ "admin.config.common.start_time": "开始时间",
+ "admin.config.common.end_time": "结束时间",
+ "admin.config.common.skip_time_check": "留空(清除)时间字段以跳过时间检查",
+ "admin.config.instance_maintenance": "实例维护",
+ "admin.config.instance_maintenance_mode.admin_web_access_only": "仅允许管理员访问 web 界面",
+ "admin.config.instance_web_banner.enabled": "显示横幅",
+ "admin.config.instance_web_banner.message_placeholder": "横幅消息(支持 Markdown)",
"admin.config.session_config": "会话配置",
"admin.config.session_provider": "会话提供者",
"admin.config.provider_config": "提供者配置",
@@ -3287,7 +3289,7 @@
"admin.config.cookie_life_time": "Cookie 生命周期",
"admin.config.picture_config": "图片和头像配置",
"admin.config.picture_service": "图片服务",
- "admin.config.disable_gravatar": "禁用 Gravatar 头像",
+ "admin.config.enable_gravatar": "启用 Gravatar",
"admin.config.enable_federated_avatar": "启用 Federated 头像",
"admin.config.open_with_editor_app_help": "用于克隆菜单的编辑器。如果为空将使用默认值。展开可以查看默认值。",
"admin.config.git_guide_remote_name": "指南中 git 命令使用的仓库远程名称",
@@ -3694,6 +3696,7 @@
"actions.runs.delete.description": "您确定要永久删除此工作流运行吗?此操作无法撤消。",
"actions.runs.not_done": "此工作流运行尚未完成。",
"actions.runs.view_workflow_file": "查看工作流文件",
+ "actions.runs.workflow_graph": "工作流程图",
"actions.workflow.disable": "禁用工作流",
"actions.workflow.disable_success": "工作流「%s」已成功禁用。",
"actions.workflow.enable": "启用工作流",
diff --git a/package.json b/package.json
index fac174242a4..d55223c9a8d 100644
--- a/package.json
+++ b/package.json
@@ -101,8 +101,8 @@
"globals": "17.3.0",
"happy-dom": "20.7.0",
"jiti": "2.6.1",
- "markdownlint-cli": "0.47.0",
- "material-icon-theme": "5.31.0",
+ "markdownlint-cli": "0.48.0",
+ "material-icon-theme": "5.32.0",
"nolyfill": "1.0.44",
"postcss-html": "1.8.1",
"spectral-cli-bundle": "1.0.7",
@@ -111,7 +111,7 @@
"stylelint-declaration-block-no-ignored-properties": "3.0.0",
"stylelint-declaration-strict-value": "1.11.0",
"stylelint-value-no-unknown-custom-properties": "6.1.1",
- "svgo": "4.0.0",
+ "svgo": "4.0.1",
"typescript": "5.9.3",
"typescript-eslint": "8.56.0",
"updates": "17.6.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 40f5def8550..c41bd3421cc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -307,11 +307,11 @@ importers:
specifier: 2.6.1
version: 2.6.1
markdownlint-cli:
- specifier: 0.47.0
- version: 0.47.0
+ specifier: 0.48.0
+ version: 0.48.0
material-icon-theme:
- specifier: 5.31.0
- version: 5.31.0
+ specifier: 5.32.0
+ version: 5.32.0
nolyfill:
specifier: 1.0.44
version: 1.0.44
@@ -337,8 +337,8 @@ importers:
specifier: 6.1.1
version: 6.1.1(stylelint@17.3.0(typescript@5.9.3))
svgo:
- specifier: 4.0.0
- version: 4.0.0
+ specifier: 4.0.1
+ version: 4.0.1
typescript:
specifier: 5.9.3
version: 5.9.3
@@ -2007,6 +2007,10 @@ packages:
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+ css-tree@3.2.1:
+ resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+
css-what@6.2.2:
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
engines: {node: '>= 6'}
@@ -3117,8 +3121,8 @@ packages:
resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==}
hasBin: true
- markdownlint-cli@0.47.0:
- resolution: {integrity: sha512-HOcxeKFAdDoldvoYDofd85vI8LgNWy8vmYpCwnlLV46PJcodmGzD7COSSBlhHwsfT4o9KrAStGodImVBus31Bg==}
+ markdownlint-cli@0.48.0:
+ resolution: {integrity: sha512-NkZQNu2E0Q5qLEEHwWj674eYISTLD4jMHkBzDobujXd1kv+yCxi8jOaD/rZoQNW1FBBMMGQpuW5So8B51N/e0A==}
engines: {node: '>=20'}
hasBin: true
@@ -3141,8 +3145,8 @@ packages:
engines: {node: '>= 12'}
hasBin: true
- material-icon-theme@5.31.0:
- resolution: {integrity: sha512-PPeGSRa+8stQEKvCr2Xym9KIqf2SPwl1chc7cxbK+aY6ORpwOcowtARQEXstZBjQwXTE5GnfE0zg0MFFy+XPzA==}
+ material-icon-theme@5.32.0:
+ resolution: {integrity: sha512-SxJxCcnk6cJIbd+AxmoeghXJ24joXGmUzjiGci16sX4mXZdXprGEzM6ZZ0VHGAofxNlMqznEbExINwFLsxf8eQ==}
engines: {vscode: ^1.55.0}
mathml-tag-names@4.0.0:
@@ -3154,6 +3158,9 @@ packages:
mdn-data@2.12.2:
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
+ mdn-data@2.27.1:
+ resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==}
+
mdurl@2.0.0:
resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==}
@@ -3264,23 +3271,19 @@ packages:
peerDependencies:
webpack: ^5.0.0
- minimatch@10.1.3:
- resolution: {integrity: sha512-IF6URNyBX7Z6XfvjpaNy5meRxPZiIf2OqtOoSLs+hLJ9pJAScnM1RjrFcbCaD85y42KcI+oZmKjFIJKYDFjQfg==}
- engines: {node: 20 || >=22}
-
minimatch@10.2.1:
resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==}
engines: {node: 20 || >=22}
- minimatch@10.2.2:
- resolution: {integrity: sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==}
+ minimatch@10.2.4:
+ resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==}
engines: {node: 18 || 20 || >=22}
- minimatch@3.1.3:
- resolution: {integrity: sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==}
+ minimatch@3.1.5:
+ resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==}
- minimatch@9.0.6:
- resolution: {integrity: sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==}
+ minimatch@9.0.8:
+ resolution: {integrity: sha512-reYkDYtj/b19TeqbNZCV4q9t+Yxylf/rYBsLb42SXJatTv4/ylq5lEiAmhA/IToxO7NI2UzNMghHoHuaqDkAjw==}
engines: {node: '>=16 || 14 >=14.17'}
minimist@1.2.8:
@@ -3715,8 +3718,8 @@ packages:
sax@1.2.4:
resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==}
- sax@1.4.4:
- resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==}
+ sax@1.5.0:
+ resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==}
engines: {node: '>=11.0.0'}
schema-utils@4.3.3:
@@ -3776,8 +3779,8 @@ packages:
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
engines: {node: '>=10'}
- smol-toml@1.5.2:
- resolution: {integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==}
+ smol-toml@1.6.0:
+ resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==}
engines: {node: '>= 18'}
solid-js@1.9.11:
@@ -3870,6 +3873,10 @@ packages:
resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==}
engines: {node: '>=12'}
+ strip-ansi@7.2.0:
+ resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==}
+ engines: {node: '>=12'}
+
strip-bom@3.0.0:
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
engines: {node: '>=4'}
@@ -3955,8 +3962,8 @@ packages:
svg-tags@1.0.0:
resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==}
- svgo@4.0.0:
- resolution: {integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==}
+ svgo@4.0.1:
+ resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==}
engines: {node: '>=16'}
hasBin: true
@@ -4654,7 +4661,7 @@ snapshots:
dependencies:
'@eslint/object-schema': 2.1.7
debug: 4.4.3
- minimatch: 3.1.3
+ minimatch: 3.1.5
transitivePeerDependencies:
- supports-color
@@ -4675,7 +4682,7 @@ snapshots:
ignore: 5.3.2
import-fresh: 3.3.1
js-yaml: 4.1.1
- minimatch: 3.1.3
+ minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
@@ -4999,7 +5006,7 @@ snapshots:
dependencies:
glob: 7.2.3
lodash: 4.17.23
- minimatch: 3.1.3
+ minimatch: 3.1.5
semver: 6.3.1
spdx-expression-validate: 2.0.0
spdx-satisfies: 5.0.1
@@ -5281,7 +5288,7 @@ snapshots:
'@typescript-eslint/types': 8.56.0
'@typescript-eslint/visitor-keys': 8.56.0
debug: 4.4.3
- minimatch: 9.0.6
+ minimatch: 9.0.8
semver: 7.7.4
tinyglobby: 0.2.15
ts-api-utils: 2.4.0(typescript@5.9.3)
@@ -5917,6 +5924,11 @@ snapshots:
mdn-data: 2.12.2
source-map-js: 1.2.1
+ css-tree@3.2.1:
+ dependencies:
+ mdn-data: 2.27.1
+ source-map-js: 1.2.1
+
css-what@6.2.2: {}
css@3.0.0:
@@ -6395,7 +6407,7 @@ snapshots:
eslint: 9.39.2(jiti@2.6.1)
eslint-import-context: 0.1.9(unrs-resolver@1.11.1)
is-glob: 4.0.3
- minimatch: 10.2.2
+ minimatch: 10.2.4
semver: 7.7.4
stable-hash-x: 0.2.0
unrs-resolver: 1.11.1
@@ -6420,7 +6432,7 @@ snapshots:
hasown: '@nolyfill/hasown@1.0.44'
is-core-module: '@nolyfill/is-core-module@1.0.39'
is-glob: 4.0.3
- minimatch: 3.1.3
+ minimatch: 3.1.5
object.fromentries: '@nolyfill/object.fromentries@1.0.44'
object.groupby: '@nolyfill/object.groupby@1.0.44'
object.values: '@nolyfill/object.values@1.0.44'
@@ -6448,7 +6460,7 @@ snapshots:
hasown: '@nolyfill/hasown@1.0.44'
jsx-ast-utils: 3.3.5
language-tags: 1.0.9
- minimatch: 3.1.3
+ minimatch: 3.1.5
object.fromentries: '@nolyfill/object.fromentries@1.0.44'
safe-regex-test: '@nolyfill/safe-regex-test@1.0.44'
string.prototype.includes: '@nolyfill/string.prototype.includes@1.0.44'
@@ -6610,7 +6622,7 @@ snapshots:
is-glob: 4.0.3
json-stable-stringify-without-jsonify: 1.0.1
lodash.merge: 4.6.2
- minimatch: 3.1.3
+ minimatch: 3.1.5
natural-compare: 1.4.0
optionator: 0.9.4
optionalDependencies:
@@ -6762,7 +6774,7 @@ snapshots:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
- minimatch: 3.1.3
+ minimatch: 3.1.5
once: 1.4.0
path-is-absolute: 1.0.1
@@ -7095,7 +7107,7 @@ snapshots:
punycode.js: 2.3.1
uc.micro: 2.1.0
- markdownlint-cli@0.47.0:
+ markdownlint-cli@0.48.0:
dependencies:
commander: 14.0.3
deep-extend: 0.6.0
@@ -7105,9 +7117,9 @@ snapshots:
jsonpointer: 5.0.1
markdown-it: 14.1.1
markdownlint: 0.40.0
- minimatch: 10.1.3
+ minimatch: 10.2.4
run-con: 1.3.2
- smol-toml: 1.5.2
+ smol-toml: 1.6.0
tinyglobby: 0.2.15
transitivePeerDependencies:
- supports-color
@@ -7132,7 +7144,7 @@ snapshots:
marked@4.3.0: {}
- material-icon-theme@5.31.0:
+ material-icon-theme@5.32.0:
dependencies:
chroma-js: 3.2.0
events: 3.3.0
@@ -7145,6 +7157,8 @@ snapshots:
mdn-data@2.12.2: {}
+ mdn-data@2.27.1: {}
+
mdurl@2.0.0: {}
meow@14.1.0: {}
@@ -7365,23 +7379,19 @@ snapshots:
tapable: 2.3.0
webpack: 5.105.2(webpack-cli@6.0.1)
- minimatch@10.1.3:
- dependencies:
- brace-expansion: 5.0.3
-
minimatch@10.2.1:
dependencies:
brace-expansion: 5.0.3
- minimatch@10.2.2:
+ minimatch@10.2.4:
dependencies:
brace-expansion: 5.0.3
- minimatch@3.1.3:
+ minimatch@3.1.5:
dependencies:
brace-expansion: 1.1.12
- minimatch@9.0.6:
+ minimatch@9.0.8:
dependencies:
brace-expansion: 5.0.3
@@ -7795,7 +7805,7 @@ snapshots:
sax@1.2.4: {}
- sax@1.4.4: {}
+ sax@1.5.0: {}
schema-utils@4.3.3:
dependencies:
@@ -7846,7 +7856,7 @@ snapshots:
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
- smol-toml@1.5.2: {}
+ smol-toml@1.6.0: {}
solid-js@1.9.11:
dependencies:
@@ -7926,7 +7936,7 @@ snapshots:
string-width@8.1.0:
dependencies:
get-east-asian-width: 1.5.0
- strip-ansi: 7.1.2
+ strip-ansi: 7.2.0
string-width@8.2.0:
dependencies:
@@ -7941,6 +7951,10 @@ snapshots:
dependencies:
ansi-regex: 6.2.2
+ strip-ansi@7.2.0:
+ dependencies:
+ ansi-regex: 6.2.2
+
strip-bom@3.0.0: {}
strip-indent@4.1.1: {}
@@ -8058,15 +8072,15 @@ snapshots:
svg-tags@1.0.0: {}
- svgo@4.0.0:
+ svgo@4.0.1:
dependencies:
commander: 11.1.0
css-select: 5.2.2
- css-tree: 3.1.0
+ css-tree: 3.2.1
css-what: 6.2.2
csso: 5.0.5
picocolors: 1.1.1
- sax: 1.4.4
+ sax: 1.5.0
svgson@5.3.1:
dependencies:
diff --git a/routers/api/actions/artifacts.go b/routers/api/actions/artifacts.go
index d71a6f487cb..6bef6c03c06 100644
--- a/routers/api/actions/artifacts.go
+++ b/routers/api/actions/artifacts.go
@@ -112,7 +112,7 @@ func ArtifactsRoutes(prefix string) *web.Router {
m.Group(artifactRouteBase, func() {
// retrieve, list and confirm artifacts
- m.Combo("").Get(r.listArtifacts).Post(r.getUploadArtifactURL).Patch(r.comfirmUploadArtifact)
+ m.Combo("").Get(r.listArtifacts).Post(r.getUploadArtifactURL).Patch(r.confirmUploadArtifact)
// handle container artifacts list and download
m.Put("/{artifact_hash}/upload", r.uploadArtifact)
// handle artifacts download
@@ -241,7 +241,7 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) {
}
// get upload file size
- fileRealTotalSize, contentLength := getUploadFileSize(ctx)
+ fileRealTotalSize := getUploadFileSize(ctx)
// get artifact retention days
expiredDays := setting.Actions.ArtifactRetentionDays
@@ -265,17 +265,17 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) {
return
}
- // save chunk to storage, if success, return chunk stotal size
+ // save chunk to storage, if success, return chunks total size
// if artifact is not gzip when uploading, chunksTotalSize == fileRealTotalSize
// if artifact is gzip when uploading, chunksTotalSize < fileRealTotalSize
- chunksTotalSize, err := saveUploadChunk(ar.fs, ctx, artifact, contentLength, runID)
+ chunksTotalSize, err := saveUploadChunkV3GetTotalSize(ar.fs, ctx, artifact, runID)
if err != nil {
log.Error("Error save upload chunk: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "Error save upload chunk")
return
}
- // update artifact size if zero or not match, over write artifact size
+ // update artifact size if zero or not match, overwrite artifact size
if artifact.FileSize == 0 ||
artifact.FileCompressedSize == 0 ||
artifact.FileSize != fileRealTotalSize ||
@@ -297,9 +297,9 @@ func (ar artifactRoutes) uploadArtifact(ctx *ArtifactContext) {
})
}
-// comfirmUploadArtifact confirm upload artifact.
+// confirmUploadArtifact confirm upload artifact.
// if all chunks are uploaded, merge them to one file.
-func (ar artifactRoutes) comfirmUploadArtifact(ctx *ArtifactContext) {
+func (ar artifactRoutes) confirmUploadArtifact(ctx *ArtifactContext) {
_, runID, ok := validateRunID(ctx)
if !ok {
return
@@ -419,8 +419,8 @@ func (ar artifactRoutes) getDownloadArtifactURL(ctx *ArtifactContext) {
}
if itemPath != artifacts[0].ArtifactName {
- log.Error("Error dismatch artifact name, itemPath: %v, artifact: %v", itemPath, artifacts[0].ArtifactName)
- ctx.HTTPError(http.StatusBadRequest, "Error dismatch artifact name")
+ log.Error("Error mismatch artifact name, itemPath: %v, artifact: %v", itemPath, artifacts[0].ArtifactName)
+ ctx.HTTPError(http.StatusBadRequest, "Error mismatch artifact name")
return
}
diff --git a/routers/api/actions/artifacts_chunks.go b/routers/api/actions/artifacts_chunks.go
index 708931d1ac1..86a51d6ca64 100644
--- a/routers/api/actions/artifacts_chunks.go
+++ b/routers/api/actions/artifacts_chunks.go
@@ -12,7 +12,7 @@ import (
"fmt"
"hash"
"io"
- "path/filepath"
+ "path"
"sort"
"strings"
"time"
@@ -20,18 +20,73 @@ import (
"code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
)
-func saveUploadChunkBase(st storage.ObjectStorage, ctx *ArtifactContext,
- artifact *actions.ActionArtifact,
- contentSize, runID, start, end, length int64, checkMd5 bool,
-) (int64, error) {
+type saveUploadChunkOptions struct {
+ start int64
+ end *int64
+ checkMd5 bool
+}
+
+func makeTmpPathNameV3(runID int64) string {
+ return fmt.Sprintf("tmp-upload/run-%d", runID)
+}
+
+func makeTmpPathNameV4(runID int64) string {
+ return fmt.Sprintf("tmp-upload/run-%d-v4", runID)
+}
+
+func makeChunkFilenameV3(runID, artifactID, start int64, endPtr *int64) string {
+ var end int64
+ if endPtr != nil {
+ end = *endPtr
+ }
+ return fmt.Sprintf("%d-%d-%d-%d.chunk", runID, artifactID, start, end)
+}
+
+func parseChunkFileItemV3(st storage.ObjectStorage, fpath string) (*chunkFileItem, error) {
+ baseName := path.Base(fpath)
+ if !strings.HasSuffix(baseName, ".chunk") {
+ return nil, errSkipChunkFile
+ }
+
+ var item chunkFileItem
+ var unusedRunID int64
+ if _, err := fmt.Sscanf(baseName, "%d-%d-%d-%d.chunk", &unusedRunID, &item.ArtifactID, &item.Start, &item.End); err != nil {
+ return nil, err
+ }
+
+ item.Path = fpath
+ if item.End == 0 {
+ fi, err := st.Stat(item.Path)
+ if err != nil {
+ return nil, err
+ }
+ item.Size = fi.Size()
+ item.End = item.Start + item.Size - 1
+ } else {
+ item.Size = item.End - item.Start + 1
+ }
+ return &item, nil
+}
+
+func saveUploadChunkV3(st storage.ObjectStorage, ctx *ArtifactContext, artifact *actions.ActionArtifact,
+ runID int64, opts saveUploadChunkOptions,
+) (writtenSize int64, retErr error) {
// build chunk store path
- storagePath := fmt.Sprintf("tmp%d/%d-%d-%d-%d.chunk", runID, runID, artifact.ID, start, end)
+ storagePath := fmt.Sprintf("%s/%s", makeTmpPathNameV3(runID), makeChunkFilenameV3(runID, artifact.ID, opts.start, opts.end))
+
+ // "end" is optional, so "contentSize=-1" means read until EOF
+ contentSize := int64(-1)
+ if opts.end != nil {
+ contentSize = *opts.end - opts.start + 1
+ }
+
var r io.Reader = ctx.Req.Body
var hasher hash.Hash
- if checkMd5 {
+ if opts.checkMd5 {
// 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
@@ -41,76 +96,81 @@ func saveUploadChunkBase(st storage.ObjectStorage, ctx *ArtifactContext,
// save chunk to storage
writtenSize, err := st.Save(storagePath, r, contentSize)
if err != nil {
- return -1, fmt.Errorf("save chunk to storage error: %v", err)
+ return 0, fmt.Errorf("save chunk to storage error: %v", err)
}
- var checkErr error
- if checkMd5 {
+
+ defer func() {
+ if retErr != nil {
+ if err := st.Delete(storagePath); err != nil {
+ log.Error("Error deleting chunk: %s, %v", storagePath, err)
+ }
+ }
+ }()
+
+ if contentSize != -1 && writtenSize != contentSize {
+ return writtenSize, fmt.Errorf("writtenSize %d does not match contentSize %d", writtenSize, contentSize)
+ }
+ if opts.checkMd5 {
// check md5
reqMd5String := ctx.Req.Header.Get(artifactXActionsResultsMD5Header)
chunkMd5String := base64.StdEncoding.EncodeToString(hasher.Sum(nil))
- log.Info("[artifact] check chunk md5, sum: %s, header: %s", chunkMd5String, reqMd5String)
+ log.Debug("[artifact] check chunk md5, sum: %s, header: %s", chunkMd5String, reqMd5String)
// if md5 not match, delete the chunk
if reqMd5String != chunkMd5String {
- checkErr = errors.New("md5 not match")
+ return writtenSize, errors.New("md5 not match")
}
}
- if writtenSize != contentSize {
- checkErr = errors.Join(checkErr, fmt.Errorf("writtenSize %d not match contentSize %d", writtenSize, contentSize))
- }
- if checkErr != nil {
- if err := st.Delete(storagePath); err != nil {
- log.Error("Error deleting chunk: %s, %v", storagePath, err)
- }
- return -1, checkErr
- }
- log.Info("[artifact] save chunk %s, size: %d, artifact id: %d, start: %d, end: %d",
- storagePath, contentSize, artifact.ID, start, end)
- // return chunk total size
- return length, nil
+ log.Debug("[artifact] save chunk %s, size: %d, artifact id: %d, start: %d, size: %d", storagePath, writtenSize, artifact.ID, opts.start, contentSize)
+ return writtenSize, nil
}
-func saveUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
- artifact *actions.ActionArtifact,
- contentSize, runID int64,
-) (int64, error) {
+func saveUploadChunkV3GetTotalSize(st storage.ObjectStorage, ctx *ArtifactContext, artifact *actions.ActionArtifact, runID int64) (totalSize int64, _ error) {
// parse content-range header, format: bytes 0-1023/146515
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)
+ var start, end int64
+ if _, err := fmt.Sscanf(contentRange, "bytes %d-%d/%d", &start, &end, &totalSize); err != nil {
+ return 0, fmt.Errorf("parse content range error: %v", err)
}
- return saveUploadChunkBase(st, ctx, artifact, contentSize, runID, start, end, length, true)
+ _, err := saveUploadChunkV3(st, ctx, artifact, runID, saveUploadChunkOptions{start: start, end: &end, checkMd5: true})
+ if err != nil {
+ return 0, err
+ }
+ return totalSize, nil
}
-func appendUploadChunk(st storage.ObjectStorage, ctx *ArtifactContext,
- artifact *actions.ActionArtifact,
- start, contentSize, runID int64,
-) (int64, error) {
- end := start + contentSize - 1
- return saveUploadChunkBase(st, ctx, artifact, contentSize, runID, start, end, contentSize, false)
+// Returns uploaded length
+func appendUploadChunkV3(st storage.ObjectStorage, ctx *ArtifactContext, artifact *actions.ActionArtifact, runID, start int64) (int64, error) {
+ opts := saveUploadChunkOptions{start: start}
+ if ctx.Req.ContentLength > 0 {
+ end := start + ctx.Req.ContentLength - 1
+ opts.end = &end
+ }
+ return saveUploadChunkV3(st, ctx, artifact, runID, opts)
}
type chunkFileItem struct {
- RunID int64
ArtifactID int64
- Start int64
- End int64
Path string
+
+ // these offset/size related fields might be missing when parsing, they will be filled in the listing functions
+ Size int64
+ Start int64
+ End int64 // inclusive: Size=10, Start=0, End=9
+
+ ChunkName string // v4 only
}
-func listChunksByRunID(st storage.ObjectStorage, runID int64) (map[int64][]*chunkFileItem, error) {
- storageDir := fmt.Sprintf("tmp%d", runID)
+func listV3UnorderedChunksMapByRunID(st storage.ObjectStorage, runID int64) (map[int64][]*chunkFileItem, error) {
+ storageDir := makeTmpPathNameV3(runID)
var chunks []*chunkFileItem
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)
+ item, err := parseChunkFileItemV3(st, fpath)
+ if errors.Is(err, errSkipChunkFile) {
+ return nil
+ } else if err != nil {
+ return fmt.Errorf("unable to parse chunk name: %v", fpath)
}
- chunks = append(chunks, &item)
+ chunks = append(chunks, item)
return nil
}); err != nil {
return nil, err
@@ -123,52 +183,78 @@ func listChunksByRunID(st storage.ObjectStorage, runID int64) (map[int64][]*chun
return chunksMap, nil
}
-func listChunksByRunIDV4(st storage.ObjectStorage, runID, artifactID int64, blist *BlockList) ([]*chunkFileItem, error) {
- storageDir := fmt.Sprintf("tmpv4%d", runID)
- var chunks []*chunkFileItem
- chunkMap := map[string]*chunkFileItem{}
- dummy := &chunkFileItem{}
- for _, name := range blist.Latest {
- chunkMap[name] = dummy
+func listOrderedChunksForArtifact(st storage.ObjectStorage, runID, artifactID int64, blist *BlockList) ([]*chunkFileItem, error) {
+ emptyListAsError := func(chunks []*chunkFileItem) ([]*chunkFileItem, error) {
+ if len(chunks) == 0 {
+ return nil, fmt.Errorf("no chunk found for artifact id: %d", artifactID)
+ }
+ return chunks, nil
}
+
+ storageDir := makeTmpPathNameV4(runID)
+ var chunks []*chunkFileItem
+ var chunkMapV4 map[string]*chunkFileItem
+
+ if blist != nil {
+ // make a dummy map for quick lookup of chunk names, the values are nil now and will be filled after iterating storage objects
+ chunkMapV4 = map[string]*chunkFileItem{}
+ for _, name := range blist.Latest {
+ chunkMapV4[name] = nil
+ }
+ }
+
if err := st.IterateObjects(storageDir, func(fpath string, obj storage.Object) error {
- baseName := filepath.Base(fpath)
- if !strings.HasPrefix(baseName, "block-") {
+ item, err := parseChunkFileItemV4(st, artifactID, fpath)
+ if errors.Is(err, errSkipChunkFile) {
return nil
+ } else if err != nil {
+ return fmt.Errorf("unable to parse chunk name: %v", 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, ArtifactID: artifactID}
- var size int64
- var b64chunkName string
- if _, err := fmt.Sscanf(baseName, "block-%d-%d-%s", &item.RunID, &size, &b64chunkName); err != nil {
- return fmt.Errorf("parse content range error: %v", err)
- }
- rchunkName, err := base64.URLEncoding.DecodeString(b64chunkName)
- if err != nil {
- return fmt.Errorf("failed to parse chunkName: %v", err)
- }
- chunkName := string(rchunkName)
- item.End = item.Start + size - 1
- if _, ok := chunkMap[chunkName]; ok {
- chunkMap[chunkName] = &item
+
+ // Single chunk upload with block id
+ if _, ok := chunkMapV4[item.ChunkName]; ok {
+ chunkMapV4[item.ChunkName] = item
+ } else if chunkMapV4 == nil {
+ if chunks != nil {
+ return errors.New("blockmap is required for chunks > 1")
+ }
+ chunks = []*chunkFileItem{item}
}
return nil
}); err != nil {
return nil, err
}
- for i, name := range blist.Latest {
- chunk, ok := chunkMap[name]
- if !ok || chunk.Path == "" {
- return nil, fmt.Errorf("missing Chunk (%d/%d): %s", i, len(blist.Latest), name)
+
+ if blist == nil && chunks == nil {
+ chunkUnorderedItemsMapV3, err := listV3UnorderedChunksMapByRunID(st, runID)
+ if err != nil {
+ return nil, err
}
- chunks = append(chunks, chunk)
- if i > 0 {
- chunk.Start = chunkMap[blist.Latest[i-1]].End + 1
- chunk.End += chunk.Start
+ chunks = chunkUnorderedItemsMapV3[artifactID]
+ sort.Slice(chunks, func(i, j int) bool {
+ return chunks[i].Start < chunks[j].Start
+ })
+ return emptyListAsError(chunks)
+ }
+
+ if len(chunks) == 0 && blist != nil {
+ for i, name := range blist.Latest {
+ chunk := chunkMapV4[name]
+ if chunk == nil {
+ return nil, fmt.Errorf("missing chunk (%d/%d): %s", i, len(blist.Latest), name)
+ }
+ chunks = append(chunks, chunk)
}
}
- return chunks, nil
+ for i, chunk := range chunks {
+ if i == 0 {
+ chunk.End += chunk.Size - 1
+ } else {
+ chunk.Start = chunkMapV4[blist.Latest[i-1]].End + 1
+ chunk.End = chunk.Start + chunk.Size - 1
+ }
+ }
+ return emptyListAsError(chunks)
}
func mergeChunksForRun(ctx *ArtifactContext, st storage.ObjectStorage, runID int64, artifactName string) error {
@@ -181,13 +267,13 @@ func mergeChunksForRun(ctx *ArtifactContext, st storage.ObjectStorage, runID int
return err
}
// read all uploading chunks from storage
- chunksMap, err := listChunksByRunID(st, runID)
+ unorderedChunksMap, err := listV3UnorderedChunksMapByRunID(st, runID)
if err != nil {
return err
}
// range db artifacts to merge chunks
for _, art := range artifacts {
- chunks, ok := chunksMap[art.ID]
+ chunks, ok := unorderedChunksMap[art.ID]
if !ok {
log.Debug("artifact %d chunks not found", art.ID)
continue
@@ -239,12 +325,14 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
}
mergedReader := io.MultiReader(readers...)
shaPrefix := "sha256:"
- var hash hash.Hash
+ var hashSha256 hash.Hash
if strings.HasPrefix(checksum, shaPrefix) {
- hash = sha256.New()
+ hashSha256 = sha256.New()
+ } else if checksum != "" {
+ setting.PanicInDevOrTesting("unsupported checksum format: %s, will skip the checksum verification", checksum)
}
- if hash != nil {
- mergedReader = io.TeeReader(mergedReader, hash)
+ if hashSha256 != nil {
+ mergedReader = io.TeeReader(mergedReader, hashSha256)
}
// if chunk is gzip, use gz as extension
@@ -274,8 +362,8 @@ func mergeChunksForArtifact(ctx *ArtifactContext, chunks []*chunkFileItem, st st
}
}()
- if hash != nil {
- rawChecksum := hash.Sum(nil)
+ if hashSha256 != nil {
+ rawChecksum := hashSha256.Sum(nil)
actualChecksum := hex.EncodeToString(rawChecksum)
if !strings.HasSuffix(checksum, actualChecksum) {
return fmt.Errorf("update artifact error checksum is invalid %v vs %v", checksum, actualChecksum)
diff --git a/routers/api/actions/artifacts_utils.go b/routers/api/actions/artifacts_utils.go
index 35868c290e9..db62f0061b9 100644
--- a/routers/api/actions/artifacts_utils.go
+++ b/routers/api/actions/artifacts_utils.go
@@ -20,8 +20,8 @@ const (
artifactXActionsResultsMD5Header = "x-actions-results-md5"
)
-// The rules are from https://github.com/actions/toolkit/blob/main/packages/artifact/src/internal/path-and-artifact-name-validation.ts#L32
-var invalidArtifactNameChars = strings.Join([]string{"\\", "/", "\"", ":", "<", ">", "|", "*", "?", "\r", "\n"}, "")
+// The rules are from https://github.com/actions/toolkit/blob/main/packages/artifact/src/internal/upload/path-and-artifact-name-validation.ts
+const invalidArtifactNameChars = "\\/\":<>|*?\r\n"
func validateArtifactName(ctx *ArtifactContext, artifactName string) bool {
if strings.ContainsAny(artifactName, invalidArtifactNameChars) {
@@ -84,11 +84,10 @@ func parseArtifactItemPath(ctx *ArtifactContext) (string, string, bool) {
// getUploadFileSize returns the size of the file to be uploaded.
// The raw size is the size of the file as reported by the header X-TFS-FileLength.
-func getUploadFileSize(ctx *ArtifactContext) (int64, int64) {
- contentLength := ctx.Req.ContentLength
+func getUploadFileSize(ctx *ArtifactContext) int64 {
xTfsLength, _ := strconv.ParseInt(ctx.Req.Header.Get(artifactXTfsFileLengthHeader), 10, 64)
if xTfsLength > 0 {
- return xTfsLength, contentLength
+ return xTfsLength
}
- return contentLength, contentLength
+ return ctx.Req.ContentLength
}
diff --git a/routers/api/actions/artifactsv4.go b/routers/api/actions/artifactsv4.go
index 6d274796285..d208785f638 100644
--- a/routers/api/actions/artifactsv4.go
+++ b/routers/api/actions/artifactsv4.go
@@ -90,10 +90,12 @@ import (
"crypto/sha256"
"encoding/base64"
"encoding/xml"
+ "errors"
"fmt"
"io"
"net/http"
"net/url"
+ "path"
"strconv"
"strings"
"time"
@@ -109,7 +111,7 @@ import (
"code.gitea.io/gitea/services/context"
"google.golang.org/protobuf/encoding/protojson"
- protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/known/timestamppb"
)
@@ -157,33 +159,81 @@ func ArtifactsV4Routes(prefix string) *web.Router {
return m
}
-func (r artifactV4Routes) buildSignature(endp, expires, artifactName string, taskID, artifactID int64) []byte {
+func (r *artifactV4Routes) buildSignature(endpoint, expires, artifactName string, taskID, artifactID int64) []byte {
mac := hmac.New(sha256.New, setting.GetGeneralTokenSigningSecret())
- mac.Write([]byte(endp))
+ mac.Write([]byte(endpoint))
mac.Write([]byte(expires))
mac.Write([]byte(artifactName))
- fmt.Fprint(mac, taskID)
- fmt.Fprint(mac, artifactID)
+ _, _ = fmt.Fprint(mac, taskID)
+ _, _ = fmt.Fprint(mac, artifactID)
return mac.Sum(nil)
}
-func (r artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endp, artifactName string, taskID, artifactID int64) string {
+func (r *artifactV4Routes) buildArtifactURL(ctx *ArtifactContext, endpoint, artifactName string, taskID, artifactID int64) string {
expires := time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04:05.999999999 -0700 MST")
uploadURL := strings.TrimSuffix(httplib.GuessCurrentAppURL(ctx), "/") + strings.TrimSuffix(r.prefix, "/") +
- "/" + endp + "?sig=" + base64.URLEncoding.EncodeToString(r.buildSignature(endp, expires, artifactName, taskID, artifactID)) + "&expires=" + url.QueryEscape(expires) + "&artifactName=" + url.QueryEscape(artifactName) + "&taskID=" + strconv.FormatInt(taskID, 10) + "&artifactID=" + strconv.FormatInt(artifactID, 10)
+ "/" + endpoint +
+ "?sig=" + base64.RawURLEncoding.EncodeToString(r.buildSignature(endpoint, expires, artifactName, taskID, artifactID)) +
+ "&expires=" + url.QueryEscape(expires) +
+ "&artifactName=" + url.QueryEscape(artifactName) +
+ "&taskID=" + strconv.FormatInt(taskID, 10) +
+ "&artifactID=" + strconv.FormatInt(artifactID, 10)
return uploadURL
}
-func (r artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (*actions.ActionTask, string, bool) {
+func makeBlockFilenameV4(runID, artifactID, size int64, blockID string) string {
+ sizeInName := max(size, 0) // do not use "-1" in filename
+ return fmt.Sprintf("block-%d-%d-%d-%s", runID, artifactID, sizeInName, base64.URLEncoding.EncodeToString([]byte(blockID)))
+}
+
+var errSkipChunkFile = errors.New("skip this chunk file")
+
+func parseChunkFileItemV4(st storage.ObjectStorage, artifactID int64, fpath string) (*chunkFileItem, error) {
+ baseName := path.Base(fpath)
+ if !strings.HasPrefix(baseName, "block-") {
+ return nil, errSkipChunkFile
+ }
+ var item chunkFileItem
+ var unusedRunID int64
+ var b64chunkName string
+ _, err := fmt.Sscanf(baseName, "block-%d-%d-%d-%s", &unusedRunID, &item.ArtifactID, &item.Size, &b64chunkName)
+ if err != nil {
+ return nil, err
+ }
+ if item.ArtifactID != artifactID {
+ return nil, errSkipChunkFile
+ }
+ chunkName, err := base64.URLEncoding.DecodeString(b64chunkName)
+ if err != nil {
+ return nil, err
+ }
+ item.ChunkName = string(chunkName)
+ item.Path = fpath
+ if item.Size <= 0 {
+ fi, err := st.Stat(item.Path)
+ if err != nil {
+ return nil, err
+ }
+ item.Size = fi.Size()
+ }
+ return &item, nil
+}
+
+func (r *artifactV4Routes) verifySignature(ctx *ArtifactContext, endp string) (*actions.ActionTask, string, bool) {
rawTaskID := ctx.Req.URL.Query().Get("taskID")
rawArtifactID := ctx.Req.URL.Query().Get("artifactID")
sig := ctx.Req.URL.Query().Get("sig")
expires := ctx.Req.URL.Query().Get("expires")
artifactName := ctx.Req.URL.Query().Get("artifactName")
- dsig, _ := base64.URLEncoding.DecodeString(sig)
- taskID, _ := strconv.ParseInt(rawTaskID, 10, 64)
- artifactID, _ := strconv.ParseInt(rawArtifactID, 10, 64)
-
+ dsig, errSig := base64.RawURLEncoding.DecodeString(sig)
+ taskID, errTask := strconv.ParseInt(rawTaskID, 10, 64)
+ artifactID, errArtifactID := strconv.ParseInt(rawArtifactID, 10, 64)
+ err := errors.Join(errSig, errTask, errArtifactID)
+ if err != nil {
+ log.Error("Error decoding signature values: %v", err)
+ ctx.HTTPError(http.StatusBadRequest, "Error decoding signature values")
+ return nil, "", false
+ }
expecedsig := r.buildSignature(endp, expires, artifactName, taskID, artifactID)
if !hmac.Equal(dsig, expecedsig) {
log.Error("Error unauthorized")
@@ -226,7 +276,7 @@ func (r *artifactV4Routes) getArtifactByName(ctx *ArtifactContext, runID int64,
return &art, nil
}
-func (r *artifactV4Routes) parseProtbufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) bool {
+func (r *artifactV4Routes) parseProtobufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) bool {
body, err := io.ReadAll(ctx.Req.Body)
if err != nil {
log.Error("Error decode request body: %v", err)
@@ -242,7 +292,7 @@ func (r *artifactV4Routes) parseProtbufBody(ctx *ArtifactContext, req protorefle
return true
}
-func (r *artifactV4Routes) sendProtbufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) {
+func (r *artifactV4Routes) sendProtobufBody(ctx *ArtifactContext, req protoreflect.ProtoMessage) {
resp, err := protojson.Marshal(req)
if err != nil {
log.Error("Error encode response body: %v", err)
@@ -257,7 +307,7 @@ func (r *artifactV4Routes) sendProtbufBody(ctx *ArtifactContext, req protoreflec
func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
var req CreateArtifactRequest
- if ok := r.parseProtbufBody(ctx, &req); !ok {
+ if ok := r.parseProtobufBody(ctx, &req); !ok {
return
}
_, _, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
@@ -267,12 +317,12 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
artifactName := req.Name
- rententionDays := setting.Actions.ArtifactRetentionDays
+ retentionDays := setting.Actions.ArtifactRetentionDays
if req.ExpiresAt != nil {
- rententionDays = int64(time.Until(req.ExpiresAt.AsTime()).Hours() / 24)
+ retentionDays = int64(time.Until(req.ExpiresAt.AsTime()).Hours() / 24)
}
// create or get artifact with name and path
- artifact, err := actions.CreateArtifact(ctx, ctx.ActionTask, artifactName, artifactName+".zip", rententionDays)
+ artifact, err := actions.CreateArtifact(ctx, ctx.ActionTask, artifactName, artifactName+".zip", retentionDays)
if err != nil {
log.Error("Error create or get artifact: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "Error create or get artifact")
@@ -291,7 +341,7 @@ func (r *artifactV4Routes) createArtifact(ctx *ArtifactContext) {
Ok: true,
SignedUploadUrl: r.buildArtifactURL(ctx, "UploadArtifact", artifactName, ctx.ActionTask.ID, artifact.ID),
}
- r.sendProtbufBody(ctx, &respData)
+ r.sendProtobufBody(ctx, &respData)
}
func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
@@ -303,34 +353,34 @@ func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
comp := ctx.Req.URL.Query().Get("comp")
switch comp {
case "block", "appendBlock":
- blockid := ctx.Req.URL.Query().Get("blockid")
- if blockid == "" {
- // get artifact by name
- artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
+ // get artifact by name
+ artifact, err := r.getArtifactByName(ctx, task.Job.RunID, artifactName)
+ if err != nil {
+ log.Error("Error artifact not found: %v", err)
+ ctx.HTTPError(http.StatusNotFound, "Error artifact not found")
+ return
+ }
+ blockID := ctx.Req.URL.Query().Get("blockid")
+ if blockID == "" {
+ uploadedLength, err := appendUploadChunkV3(r.fs, ctx, artifact, artifact.RunID, artifact.FileSize)
if err != nil {
- log.Error("Error artifact not found: %v", err)
- ctx.HTTPError(http.StatusNotFound, "Error artifact not found")
+ log.Error("Error appending chunk %v", err)
+ ctx.HTTPError(http.StatusInternalServerError, "Error appending Chunk")
return
}
-
- _, err = appendUploadChunk(r.fs, ctx, artifact, artifact.FileSize, ctx.Req.ContentLength, artifact.RunID)
- if err != nil {
- log.Error("Error runner api getting task: task is not running")
- ctx.HTTPError(http.StatusInternalServerError, "Error runner api getting task: task is not running")
- return
- }
- artifact.FileCompressedSize += ctx.Req.ContentLength
- artifact.FileSize += ctx.Req.ContentLength
+ artifact.FileCompressedSize += uploadedLength
+ artifact.FileSize += uploadedLength
if err := actions.UpdateArtifactByID(ctx, artifact.ID, artifact); err != nil {
log.Error("Error UpdateArtifactByID: %v", err)
ctx.HTTPError(http.StatusInternalServerError, "Error UpdateArtifactByID")
return
}
} else {
- _, err := r.fs.Save(fmt.Sprintf("tmpv4%d/block-%d-%d-%s", task.Job.RunID, task.Job.RunID, ctx.Req.ContentLength, base64.URLEncoding.EncodeToString([]byte(blockid))), ctx.Req.Body, -1)
+ blockFilename := makeBlockFilenameV4(task.Job.RunID, artifact.ID, ctx.Req.ContentLength, blockID)
+ _, err := r.fs.Save(fmt.Sprintf("%s/%s", makeTmpPathNameV4(task.Job.RunID), blockFilename), ctx.Req.Body, ctx.Req.ContentLength)
if err != nil {
- log.Error("Error runner api getting task: task is not running")
- ctx.HTTPError(http.StatusInternalServerError, "Error runner api getting task: task is not running")
+ log.Error("Error uploading block blob %v", err)
+ ctx.HTTPError(http.StatusInternalServerError, "Error uploading block blob")
return
}
}
@@ -338,10 +388,10 @@ func (r *artifactV4Routes) uploadArtifact(ctx *ArtifactContext) {
case "blocklist":
rawArtifactID := ctx.Req.URL.Query().Get("artifactID")
artifactID, _ := strconv.ParseInt(rawArtifactID, 10, 64)
- _, err := r.fs.Save(fmt.Sprintf("tmpv4%d/%d-%d-blocklist", task.Job.RunID, task.Job.RunID, artifactID), ctx.Req.Body, -1)
+ _, err := r.fs.Save(fmt.Sprintf("%s/%d-%d-blocklist", makeTmpPathNameV4(task.Job.RunID), task.Job.RunID, artifactID), ctx.Req.Body, -1)
if err != nil {
- log.Error("Error runner api getting task: task is not running")
- ctx.HTTPError(http.StatusInternalServerError, "Error runner api getting task: task is not running")
+ log.Error("Error uploading blocklist %v", err)
+ ctx.HTTPError(http.StatusInternalServerError, "Error uploading blocklist")
return
}
ctx.JSON(http.StatusCreated, "created")
@@ -357,7 +407,7 @@ type Latest struct {
}
func (r *artifactV4Routes) readBlockList(runID, artifactID int64) (*BlockList, error) {
- blockListName := fmt.Sprintf("tmpv4%d/%d-%d-blocklist", runID, runID, artifactID)
+ blockListName := fmt.Sprintf("%s/%d-%d-blocklist", makeTmpPathNameV4(runID), runID, artifactID)
s, err := r.fs.Open(blockListName)
if err != nil {
return nil, err
@@ -367,17 +417,22 @@ func (r *artifactV4Routes) readBlockList(runID, artifactID int64) (*BlockList, e
blockList := &BlockList{}
err = xdec.Decode(blockList)
+ _ = s.Close()
+
delerr := r.fs.Delete(blockListName)
if delerr != nil {
log.Warn("Failed to delete blockList %s: %v", blockListName, delerr)
}
- return blockList, err
+ if err != nil {
+ return nil, err
+ }
+ return blockList, nil
}
func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
var req FinalizeArtifactRequest
- if ok := r.parseProtbufBody(ctx, &req); !ok {
+ if ok := r.parseProtobufBody(ctx, &req); !ok {
return
}
_, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
@@ -394,30 +449,20 @@ func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
}
var chunks []*chunkFileItem
- blockList, err := r.readBlockList(runID, artifact.ID)
+ blockList, blockListErr := r.readBlockList(runID, artifact.ID)
+ chunks, err = listOrderedChunksForArtifact(r.fs, runID, artifact.ID, blockList)
if err != nil {
- log.Warn("Failed to read BlockList, fallback to old behavior: %v", err)
- chunkMap, err := listChunksByRunID(r.fs, runID)
- if err != nil {
- log.Error("Error merge chunks: %v", err)
- ctx.HTTPError(http.StatusInternalServerError, "Error merge chunks")
- return
- }
- chunks, ok = chunkMap[artifact.ID]
- if !ok {
- log.Error("Error merge chunks")
- ctx.HTTPError(http.StatusInternalServerError, "Error merge chunks")
- return
- }
- } else {
- chunks, err = listChunksByRunIDV4(r.fs, runID, artifact.ID, blockList)
- if err != nil {
- log.Error("Error merge chunks: %v", err)
- ctx.HTTPError(http.StatusInternalServerError, "Error merge chunks")
- return
- }
- artifact.FileSize = chunks[len(chunks)-1].End + 1
- artifact.FileCompressedSize = chunks[len(chunks)-1].End + 1
+ log.Error("Error list chunks: %v", errors.Join(blockListErr, err))
+ ctx.HTTPError(http.StatusInternalServerError, "Error list chunks")
+ return
+ }
+ artifact.FileSize = chunks[len(chunks)-1].End + 1
+ artifact.FileCompressedSize = chunks[len(chunks)-1].End + 1
+
+ if req.Size != artifact.FileSize {
+ log.Error("Error merge chunks size mismatch")
+ ctx.HTTPError(http.StatusInternalServerError, "Error merge chunks size mismatch")
+ return
}
checksum := ""
@@ -434,13 +479,13 @@ func (r *artifactV4Routes) finalizeArtifact(ctx *ArtifactContext) {
Ok: true,
ArtifactId: artifact.ID,
}
- r.sendProtbufBody(ctx, &respData)
+ r.sendProtobufBody(ctx, &respData)
}
func (r *artifactV4Routes) listArtifacts(ctx *ArtifactContext) {
var req ListArtifactsRequest
- if ok := r.parseProtbufBody(ctx, &req); !ok {
+ if ok := r.parseProtobufBody(ctx, &req); !ok {
return
}
_, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
@@ -485,13 +530,13 @@ func (r *artifactV4Routes) listArtifacts(ctx *ArtifactContext) {
respData := ListArtifactsResponse{
Artifacts: list,
}
- r.sendProtbufBody(ctx, &respData)
+ r.sendProtobufBody(ctx, &respData)
}
func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
var req GetSignedArtifactURLRequest
- if ok := r.parseProtbufBody(ctx, &req); !ok {
+ if ok := r.parseProtobufBody(ctx, &req); !ok {
return
}
_, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
@@ -525,7 +570,7 @@ func (r *artifactV4Routes) getSignedArtifactURL(ctx *ArtifactContext) {
if respData.SignedUrl == "" {
respData.SignedUrl = r.buildArtifactURL(ctx, "DownloadArtifact", artifactName, ctx.ActionTask.ID, artifact.ID)
}
- r.sendProtbufBody(ctx, &respData)
+ r.sendProtobufBody(ctx, &respData)
}
func (r *artifactV4Routes) downloadArtifact(ctx *ArtifactContext) {
@@ -555,7 +600,7 @@ func (r *artifactV4Routes) downloadArtifact(ctx *ArtifactContext) {
func (r *artifactV4Routes) deleteArtifact(ctx *ArtifactContext) {
var req DeleteArtifactRequest
- if ok := r.parseProtbufBody(ctx, &req); !ok {
+ if ok := r.parseProtobufBody(ctx, &req); !ok {
return
}
_, runID, ok := validateRunIDV4(ctx, req.WorkflowRunBackendId)
@@ -582,5 +627,5 @@ func (r *artifactV4Routes) deleteArtifact(ctx *ArtifactContext) {
Ok: true,
ArtifactId: artifact.ID,
}
- r.sendProtbufBody(ctx, &respData)
+ r.sendProtobufBody(ctx, &respData)
}
diff --git a/routers/api/packages/arch/arch.go b/routers/api/packages/arch/arch.go
index 061484785da..5a124f6918d 100644
--- a/routers/api/packages/arch/arch.go
+++ b/routers/api/packages/arch/arch.go
@@ -91,7 +91,7 @@ func UploadPackageFile(ctx *context.Context) {
return
}
- release, err := arch_service.AquireRegistryLock(ctx, ctx.Package.Owner.ID)
+ release, err := arch_service.AcquireRegistryLock(ctx, ctx.Package.Owner.ID)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
@@ -257,7 +257,7 @@ func DeletePackageVersion(ctx *context.Context) {
name := ctx.PathParam("name")
version := ctx.PathParam("version")
- release, err := arch_service.AquireRegistryLock(ctx, ctx.Package.Owner.ID)
+ release, err := arch_service.AcquireRegistryLock(ctx, ctx.Package.Owner.ID)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go
index f2ba2baf7fa..2ee3368a87e 100644
--- a/routers/api/v1/activitypub/person.go
+++ b/routers/api/v1/activitypub/person.go
@@ -4,103 +4,11 @@
package activitypub
import (
- "fmt"
"net/http"
- "strings"
- "code.gitea.io/gitea/modules/activitypub"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/context"
-
- ap "github.com/go-ap/activitypub"
- "github.com/go-ap/jsonld"
)
-// Person function returns the Person actor for a user
-func Person(ctx *context.APIContext) {
- // swagger:operation GET /activitypub/user-id/{user-id} activitypub activitypubPerson
- // ---
- // summary: Returns the Person actor for a user
- // produces:
- // - application/json
- // parameters:
- // - name: user-id
- // in: path
- // description: user ID of the user
- // type: integer
- // required: true
- // responses:
- // "200":
- // "$ref": "#/responses/ActivityPub"
-
- // TODO: the setting.AppURL during the test doesn't follow the definition: "It always has a '/' suffix"
- link := fmt.Sprintf("%s/api/v1/activitypub/user-id/%d", strings.TrimSuffix(setting.AppURL, "/"), ctx.ContextUser.ID)
- person := ap.PersonNew(ap.IRI(link))
-
- person.Name = ap.NaturalLanguageValuesNew()
- err := person.Name.Set("en", ap.Content(ctx.ContextUser.FullName))
- if err != nil {
- ctx.APIErrorInternal(err)
- return
- }
-
- person.PreferredUsername = ap.NaturalLanguageValuesNew()
- err = person.PreferredUsername.Set("en", ap.Content(ctx.ContextUser.Name))
- if err != nil {
- ctx.APIErrorInternal(err)
- return
- }
-
- person.URL = ap.IRI(ctx.ContextUser.HTMLURL(ctx))
-
- person.Icon = ap.Image{
- Type: ap.ImageType,
- MediaType: "image/png",
- URL: ap.IRI(ctx.ContextUser.AvatarLink(ctx)),
- }
-
- person.Inbox = ap.IRI(link + "/inbox")
- person.Outbox = ap.IRI(link + "/outbox")
-
- person.PublicKey.ID = ap.IRI(link + "#main-key")
- person.PublicKey.Owner = ap.IRI(link)
-
- publicKeyPem, err := activitypub.GetPublicKey(ctx, ctx.ContextUser)
- if err != nil {
- ctx.APIErrorInternal(err)
- return
- }
- person.PublicKey.PublicKeyPem = publicKeyPem
-
- binary, err := jsonld.WithContext(jsonld.IRI(ap.ActivityBaseURI), jsonld.IRI(ap.SecurityContextURI)).Marshal(person)
- if err != nil {
- ctx.APIErrorInternal(err)
- return
- }
- ctx.Resp.Header().Add("Content-Type", activitypub.ActivityStreamsContentType)
- ctx.Resp.WriteHeader(http.StatusOK)
- if _, err = ctx.Resp.Write(binary); err != nil {
- log.Error("write to resp err: %v", err)
- }
-}
-
-// PersonInbox function handles the incoming data for a user inbox
-func PersonInbox(ctx *context.APIContext) {
- // swagger:operation POST /activitypub/user-id/{user-id}/inbox activitypub activitypubPersonInbox
- // ---
- // summary: Send to the inbox
- // produces:
- // - application/json
- // parameters:
- // - name: user-id
- // in: path
- // description: user ID of the user
- // type: integer
- // required: true
- // responses:
- // "204":
- // "$ref": "#/responses/empty"
-
- ctx.Status(http.StatusNoContent)
+func NotImplemented(ctx *context.APIContext) {
+ http.Error(ctx.Resp, "Not implemented", http.StatusNotImplemented)
}
diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go
deleted file mode 100644
index 4eff51782f0..00000000000
--- a/routers/api/v1/activitypub/reqsignature.go
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package activitypub
-
-import (
- "crypto"
- "crypto/x509"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
-
- "code.gitea.io/gitea/modules/activitypub"
- "code.gitea.io/gitea/modules/httplib"
- "code.gitea.io/gitea/modules/setting"
- gitea_context "code.gitea.io/gitea/services/context"
-
- "github.com/42wim/httpsig"
- ap "github.com/go-ap/activitypub"
-)
-
-func getPublicKeyFromResponse(b []byte, keyID *url.URL) (p crypto.PublicKey, err error) {
- person := ap.PersonNew(ap.IRI(keyID.String()))
- err = person.UnmarshalJSON(b)
- if err != nil {
- return nil, fmt.Errorf("ActivityStreams type cannot be converted to one known to have publicKey property: %w", err)
- }
- pubKey := person.PublicKey
- if pubKey.ID.String() != keyID.String() {
- return nil, fmt.Errorf("cannot find publicKey with id: %s in %s", keyID, string(b))
- }
- pubKeyPem := pubKey.PublicKeyPem
- block, _ := pem.Decode([]byte(pubKeyPem))
- if block == nil || block.Type != "PUBLIC KEY" {
- return nil, errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type")
- }
- p, err = x509.ParsePKIXPublicKey(block.Bytes)
- return p, err
-}
-
-func fetch(iri *url.URL) (b []byte, err error) {
- req := httplib.NewRequest(iri.String(), http.MethodGet)
- req.Header("Accept", activitypub.ActivityStreamsContentType)
- req.Header("User-Agent", "Gitea/"+setting.AppVer)
- resp, err := req.Response()
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
-
- if resp.StatusCode != http.StatusOK {
- return nil, fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
- }
- b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize))
- return b, err
-}
-
-func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, err error) {
- r := ctx.Req
-
- // 1. Figure out what key we need to verify
- v, err := httpsig.NewVerifier(r)
- if err != nil {
- return false, err
- }
- ID := v.KeyId()
- idIRI, err := url.Parse(ID)
- if err != nil {
- return false, err
- }
- // 2. Fetch the public key of the other actor
- b, err := fetch(idIRI)
- if err != nil {
- return false, err
- }
- pubKey, err := getPublicKeyFromResponse(b, idIRI)
- if err != nil {
- return false, err
- }
- // 3. Verify the other actor's key
- algo := httpsig.Algorithm(setting.Federation.Algorithms[0])
- authenticated = v.Verify(pubKey, algo) == nil
- return authenticated, err
-}
-
-// ReqHTTPSignature function
-func ReqHTTPSignature() func(ctx *gitea_context.APIContext) {
- return func(ctx *gitea_context.APIContext) {
- if authenticated, err := verifyHTTPSignatures(ctx); err != nil {
- ctx.APIErrorInternal(err)
- } else if !authenticated {
- ctx.APIError(http.StatusForbidden, "request signature verification failed")
- }
- }
-}
diff --git a/routers/api/v1/admin/runners.go b/routers/api/v1/admin/runners.go
index 1e15b240761..f5aaea2c328 100644
--- a/routers/api/v1/admin/runners.go
+++ b/routers/api/v1/admin/runners.go
@@ -10,21 +10,6 @@ import (
// 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 a global actions runner registration token
- // produces:
- // - application/json
- // parameters:
- // responses:
- // "200":
- // "$ref": "#/responses/RegistrationToken"
-
- shared.GetRegistrationToken(ctx, 0, 0)
-}
-
// CreateRegistrationToken returns the token to register global runners
func CreateRegistrationToken(ctx *context.APIContext) {
// swagger:operation POST /admin/actions/runners/registration-token admin adminCreateRunnerRegistrationToken
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index cb88a0a5203..5a6da089dee 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -895,35 +895,35 @@ func Routes() *web.Router {
addActionsRoutes := func(
m *web.Router,
- reqChecker func(ctx *context.APIContext),
+ reqReaderCheck func(ctx *context.APIContext),
+ reqOwnerCheck func(ctx *context.APIContext),
act actions.API,
) {
m.Group("/actions", func() {
m.Group("/secrets", func() {
- m.Get("", reqToken(), reqChecker, act.ListActionsSecrets)
+ m.Get("", reqToken(), reqOwnerCheck, act.ListActionsSecrets)
m.Combo("/{secretname}").
- Put(reqToken(), reqChecker, bind(api.CreateOrUpdateSecretOption{}), act.CreateOrUpdateSecret).
- Delete(reqToken(), reqChecker, act.DeleteSecret)
+ Put(reqToken(), reqOwnerCheck, bind(api.CreateOrUpdateSecretOption{}), act.CreateOrUpdateSecret).
+ Delete(reqToken(), reqOwnerCheck, act.DeleteSecret)
})
m.Group("/variables", func() {
- m.Get("", reqToken(), reqChecker, act.ListVariables)
+ m.Get("", reqToken(), reqOwnerCheck, act.ListVariables)
m.Combo("/{variablename}").
- Get(reqToken(), reqChecker, act.GetVariable).
- Delete(reqToken(), reqChecker, act.DeleteVariable).
- Post(reqToken(), reqChecker, bind(api.CreateVariableOption{}), act.CreateVariable).
- Put(reqToken(), reqChecker, bind(api.UpdateVariableOption{}), act.UpdateVariable)
+ Get(reqToken(), reqOwnerCheck, act.GetVariable).
+ Delete(reqToken(), reqOwnerCheck, act.DeleteVariable).
+ Post(reqToken(), reqOwnerCheck, bind(api.CreateVariableOption{}), act.CreateVariable).
+ Put(reqToken(), reqOwnerCheck, bind(api.UpdateVariableOption{}), act.UpdateVariable)
})
m.Group("/runners", func() {
- m.Get("", reqToken(), reqChecker, act.ListRunners)
- m.Get("/registration-token", reqToken(), reqChecker, act.GetRegistrationToken)
- m.Post("/registration-token", reqToken(), reqChecker, act.CreateRegistrationToken)
- m.Get("/{runner_id}", reqToken(), reqChecker, act.GetRunner)
- m.Delete("/{runner_id}", reqToken(), reqChecker, act.DeleteRunner)
+ m.Get("", reqToken(), reqOwnerCheck, act.ListRunners)
+ m.Post("/registration-token", reqToken(), reqOwnerCheck, act.CreateRegistrationToken)
+ m.Get("/{runner_id}", reqToken(), reqOwnerCheck, act.GetRunner)
+ m.Delete("/{runner_id}", reqToken(), reqOwnerCheck, act.DeleteRunner)
})
- m.Get("/runs", reqToken(), reqChecker, act.ListWorkflowRuns)
- m.Get("/jobs", reqToken(), reqChecker, act.ListWorkflowJobs)
+ m.Get("/runs", reqToken(), reqReaderCheck, act.ListWorkflowRuns)
+ m.Get("/jobs", reqToken(), reqReaderCheck, act.ListWorkflowJobs)
})
}
@@ -936,18 +936,8 @@ func Routes() *web.Router {
}
if setting.Federation.Enabled {
- m.Get("/nodeinfo", misc.NodeInfo)
- m.Group("/activitypub", func() {
- // deprecated, remove in 1.20, use /user-id/{user-id} instead
- m.Group("/user/{username}", func() {
- m.Get("", activitypub.Person)
- m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
- }, context.UserAssignmentAPI(), checkTokenPublicOnly())
- m.Group("/user-id/{user-id}", func() {
- m.Get("", activitypub.Person)
- m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
- }, context.UserIDAssignmentAPI(), checkTokenPublicOnly())
- }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub))
+ m.Get("/nodeinfo", activitypub.NotImplemented)
+ m.Any("/activitypub/*", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub), activitypub.NotImplemented)
}
// Misc (public accessible)
@@ -1055,7 +1045,6 @@ func Routes() *web.Router {
m.Group("/runners", func() {
m.Get("", reqToken(), user.ListRunners)
- m.Get("/registration-token", reqToken(), user.GetRegistrationToken)
m.Post("/registration-token", reqToken(), user.CreateRegistrationToken)
m.Get("/{runner_id}", reqToken(), user.GetRunner)
m.Delete("/{runner_id}", reqToken(), user.DeleteRunner)
@@ -1176,7 +1165,8 @@ func Routes() *web.Router {
m.Post("/reject", repo.RejectTransfer)
}, reqToken())
- addActionsRoutes(m, reqOwner(), repo.NewAction()) // it adds the routes for secrets/variables and runner management
+ // Adds the routes for secrets/variables and runner management
+ addActionsRoutes(m, reqRepoReader(unit.TypeActions), reqOwner(), repo.NewAction())
m.Group("/actions/workflows", func() {
m.Get("", repo.ActionsListRepositoryWorkflows)
@@ -1271,7 +1261,9 @@ func Routes() *web.Router {
m.Group("/{run}", func() {
m.Get("", repo.GetWorkflowRun)
m.Delete("", reqToken(), reqRepoWriter(unit.TypeActions), repo.DeleteActionRun)
+ m.Post("/rerun", reqToken(), reqRepoWriter(unit.TypeActions), repo.RerunWorkflowRun)
m.Get("/jobs", repo.ListWorkflowRunJobs)
+ m.Post("/jobs/{job_id}/rerun", reqToken(), reqRepoWriter(unit.TypeActions), repo.RerunWorkflowJob)
m.Get("/artifacts", repo.GetArtifactsOfRun)
})
})
@@ -1630,6 +1622,7 @@ func Routes() *web.Router {
})
addActionsRoutes(
m,
+ reqOrgMembership(),
reqOrgOwnership(),
org.NewAction(),
)
@@ -1745,9 +1738,6 @@ func Routes() *web.Router {
m.Get("/runs", admin.ListWorkflowRuns)
m.Get("/jobs", admin.ListWorkflowJobs)
})
- m.Group("/runners", func() {
- m.Get("/registration-token", admin.GetRegistrationToken)
- })
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryAdmin), reqToken(), reqSiteAdmin())
m.Group("/topics", func() {
diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go
deleted file mode 100644
index ffe50e9fda4..00000000000
--- a/routers/api/v1/misc/nodeinfo.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2021 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package misc
-
-import (
- "net/http"
- "time"
-
- issues_model "code.gitea.io/gitea/models/issues"
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/structs"
- "code.gitea.io/gitea/services/context"
-)
-
-const cacheKeyNodeInfoUsage = "API_NodeInfoUsage"
-
-// NodeInfo returns the NodeInfo for the Gitea instance to allow for federation
-func NodeInfo(ctx *context.APIContext) {
- // swagger:operation GET /nodeinfo miscellaneous getNodeInfo
- // ---
- // summary: Returns the nodeinfo of the Gitea application
- // produces:
- // - application/json
- // responses:
- // "200":
- // "$ref": "#/responses/NodeInfo"
-
- nodeInfoUsage := structs.NodeInfoUsage{}
- if setting.Federation.ShareUserStatistics {
- cached, _ := ctx.Cache.GetJSON(cacheKeyNodeInfoUsage, &nodeInfoUsage)
- if !cached {
- usersTotal := int(user_model.CountUsers(ctx, nil))
- now := time.Now()
- timeOneMonthAgo := now.AddDate(0, -1, 0).Unix()
- timeHaveYearAgo := now.AddDate(0, -6, 0).Unix()
- usersActiveMonth := int(user_model.CountUsers(ctx, &user_model.CountUserFilter{LastLoginSince: &timeOneMonthAgo}))
- usersActiveHalfyear := int(user_model.CountUsers(ctx, &user_model.CountUserFilter{LastLoginSince: &timeHaveYearAgo}))
-
- allIssues, _ := issues_model.CountIssues(ctx, &issues_model.IssuesOptions{})
- allComments, _ := issues_model.CountComments(ctx, &issues_model.FindCommentsOptions{})
-
- nodeInfoUsage = structs.NodeInfoUsage{
- Users: structs.NodeInfoUsageUsers{
- Total: usersTotal,
- ActiveMonth: usersActiveMonth,
- ActiveHalfyear: usersActiveHalfyear,
- },
- LocalPosts: int(allIssues),
- LocalComments: int(allComments),
- }
-
- if err := ctx.Cache.PutJSON(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil {
- ctx.APIErrorInternal(err)
- return
- }
- }
- }
-
- nodeInfo := &structs.NodeInfo{
- Version: "2.1",
- Software: structs.NodeInfoSoftware{
- Name: "gitea",
- Version: setting.AppVer,
- Repository: "https://github.com/go-gitea/gitea.git",
- Homepage: "https://gitea.io/",
- },
- Protocols: []string{"activitypub"},
- Services: structs.NodeInfoServices{
- Inbound: []string{},
- Outbound: []string{"rss2.0"},
- },
- OpenRegistrations: setting.Service.ShowRegistrationButton,
- Usage: nodeInfoUsage,
- }
- ctx.JSON(http.StatusOK, nodeInfo)
-}
diff --git a/routers/api/v1/org/action.go b/routers/api/v1/org/action.go
index 59d8d3f2b4d..d058964f52d 100644
--- a/routers/api/v1/org/action.go
+++ b/routers/api/v1/org/action.go
@@ -170,27 +170,6 @@ func (Action) DeleteSecret(ctx *context.APIContext) {
ctx.Status(http.StatusNoContent)
}
-// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
-// GetRegistrationToken returns the token to register org runners
-func (Action) GetRegistrationToken(ctx *context.APIContext) {
- // swagger:operation GET /orgs/{org}/actions/runners/registration-token organization orgGetRunnerRegistrationToken
- // ---
- // summary: Get an organization's actions runner registration token
- // produces:
- // - application/json
- // parameters:
- // - name: org
- // in: path
- // description: name of the organization
- // type: string
- // required: true
- // responses:
- // "200":
- // "$ref": "#/responses/RegistrationToken"
-
- shared.GetRegistrationToken(ctx, ctx.Org.Organization.ID, 0)
-}
-
// https://docs.github.com/en/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-registration-token-for-an-organization
// CreateRegistrationToken returns the token to register org runners
func (Action) CreateRegistrationToken(ctx *context.APIContext) {
diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go
index f9e0684a97b..b07e902f6e0 100644
--- a/routers/api/v1/org/hook.go
+++ b/routers/api/v1/org/hook.go
@@ -13,7 +13,7 @@ import (
webhook_service "code.gitea.io/gitea/services/webhook"
)
-// ListHooks list an organziation's webhooks
+// ListHooks list an organization's webhooks
func ListHooks(ctx *context.APIContext) {
// swagger:operation GET /orgs/{org}/hooks organization orgListHooks
// ---
diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go
index e498c2c0de5..4d4e2ef269b 100644
--- a/routers/api/v1/org/org.go
+++ b/routers/api/v1/org/org.go
@@ -139,7 +139,7 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
op := api.OrganizationPermissions{}
- if !organization.HasOrgOrUserVisible(ctx, o, ctx.ContextUser) {
+ if !organization.HasOrgOrUserVisible(ctx, o, ctx.Doer) {
ctx.APIErrorNotFound("HasOrgOrUserVisible", nil)
return
}
diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go
index 7d43db1e9be..211b7a15b25 100644
--- a/routers/api/v1/org/team.go
+++ b/routers/api/v1/org/team.go
@@ -806,7 +806,7 @@ func SearchTeam(ctx *context.APIContext) {
ListOptions: listOptions,
}
- // Only admin is allowd to search for all teams
+ // Only admin is allowed to search for all teams
if !ctx.Doer.IsAdmin {
opts.UserID = ctx.Doer.ID
}
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index 03ce0d3aab4..13da5aa8151 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -12,6 +12,7 @@ import (
"fmt"
"net/http"
"net/url"
+ "slices"
"strconv"
"strings"
"time"
@@ -510,31 +511,6 @@ func (Action) ListVariables(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, variables)
}
-// GetRegistrationToken returns the token to register repo runners
-func (Action) GetRegistrationToken(ctx *context.APIContext) {
- // swagger:operation GET /repos/{owner}/{repo}/actions/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, 0, ctx.Repo.Repository.ID)
-}
-
// CreateRegistrationToken returns the token to register repo runners
func (Action) CreateRegistrationToken(ctx *context.APIContext) {
// swagger:operation POST /repos/{owner}/{repo}/actions/runners/registration-token repository repoCreateRunnerRegistrationToken
@@ -1004,9 +980,15 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
// in: body
// schema:
// "$ref": "#/definitions/CreateActionWorkflowDispatch"
+ // - name: return_run_details
+ // description: Whether the response should include the workflow run ID and URLs.
+ // in: query
+ // type: boolean
// responses:
+ // "200":
+ // "$ref": "#/responses/RunDetails"
// "204":
- // description: No Content
+ // description: No Content, if return_run_details is missing or false
// "400":
// "$ref": "#/responses/error"
// "403":
@@ -1023,7 +1005,7 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
return
}
- err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, opt.Ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
+ runID, err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, opt.Ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
if strings.Contains(ctx.Req.Header.Get("Content-Type"), "form-urlencoded") {
// The chi framework's "Binding" doesn't support to bind the form map values into a map[string]string
// So we have to manually read the `inputs[key]` from the form
@@ -1054,7 +1036,22 @@ func ActionsDispatchWorkflow(ctx *context.APIContext) {
return
}
- ctx.Status(http.StatusNoContent)
+ if !ctx.FormBool("return_run_details") {
+ ctx.Status(http.StatusNoContent)
+ return
+ }
+
+ workflowRun, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
+
+ ctx.JSON(http.StatusOK, &api.RunDetails{
+ WorkflowRunID: runID,
+ HTMLURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.HTMLURL(ctx), workflowRun.Index),
+ RunURL: fmt.Sprintf("%s/actions/runs/%d", ctx.Repo.Repository.APIURL(), runID),
+ })
}
func ActionsEnableWorkflow(ctx *context.APIContext) {
@@ -1107,6 +1104,33 @@ func ActionsEnableWorkflow(ctx *context.APIContext) {
ctx.Status(http.StatusNoContent)
}
+func getCurrentRepoActionRunByID(ctx *context.APIContext) *actions_model.ActionRun {
+ runID := ctx.PathParamInt64("run")
+ run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID)
+ if errors.Is(err, util.ErrNotExist) {
+ ctx.APIErrorNotFound(err)
+ return nil
+ } else if err != nil {
+ ctx.APIErrorInternal(err)
+ return nil
+ }
+ return run
+}
+
+func getCurrentRepoActionRunJobsByID(ctx *context.APIContext) (*actions_model.ActionRun, actions_model.ActionJobList) {
+ run := getCurrentRepoActionRunByID(ctx)
+ if ctx.Written() {
+ return nil, nil
+ }
+
+ jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return nil, nil
+ }
+ return run, jobs
+}
+
// GetWorkflowRun Gets a specific workflow run.
func GetWorkflowRun(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs/{run} repository GetWorkflowRun
@@ -1138,19 +1162,12 @@ func GetWorkflowRun(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- runID := ctx.PathParamInt64("run")
- job, has, err := db.GetByID[actions_model.ActionRun](ctx, runID)
- if err != nil {
- ctx.APIErrorInternal(err)
+ run := getCurrentRepoActionRunByID(ctx)
+ if ctx.Written() {
return
}
- if !has || job.RepoID != ctx.Repo.Repository.ID {
- ctx.APIErrorNotFound(util.ErrNotExist)
- return
- }
-
- convertedRun, err := convert.ToActionWorkflowRun(ctx, ctx.Repo.Repository, job)
+ convertedRun, err := convert.ToActionWorkflowRun(ctx, ctx.Repo.Repository, run)
if err != nil {
ctx.APIErrorInternal(err)
return
@@ -1158,6 +1175,133 @@ func GetWorkflowRun(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, convertedRun)
}
+// RerunWorkflowRun Reruns an entire workflow run.
+func RerunWorkflowRun(ctx *context.APIContext) {
+ // swagger:operation POST /repos/{owner}/{repo}/actions/runs/{run}/rerun repository rerunWorkflowRun
+ // ---
+ // summary: Reruns an entire workflow run
+ // 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 repository
+ // type: string
+ // required: true
+ // - name: run
+ // in: path
+ // description: id of the run
+ // type: integer
+ // required: true
+ // responses:
+ // "201":
+ // "$ref": "#/responses/WorkflowRun"
+ // "400":
+ // "$ref": "#/responses/error"
+ // "403":
+ // "$ref": "#/responses/forbidden"
+ // "404":
+ // "$ref": "#/responses/notFound"
+ // "422":
+ // "$ref": "#/responses/validationError"
+
+ run, jobs := getCurrentRepoActionRunJobsByID(ctx)
+ if ctx.Written() {
+ return
+ }
+
+ if err := actions_service.RerunWorkflowRunJobs(ctx, ctx.Repo.Repository, run, jobs, nil); err != nil {
+ handleWorkflowRerunError(ctx, err)
+ return
+ }
+
+ convertedRun, err := convert.ToActionWorkflowRun(ctx, ctx.Repo.Repository, run)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
+ ctx.JSON(http.StatusCreated, convertedRun)
+}
+
+// RerunWorkflowJob Reruns a specific workflow job in a run.
+func RerunWorkflowJob(ctx *context.APIContext) {
+ // swagger:operation POST /repos/{owner}/{repo}/actions/runs/{run}/jobs/{job_id}/rerun repository rerunWorkflowJob
+ // ---
+ // summary: Reruns a specific workflow job in a run
+ // 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 repository
+ // type: string
+ // required: true
+ // - name: run
+ // in: path
+ // description: id of the run
+ // type: integer
+ // required: true
+ // - name: job_id
+ // in: path
+ // description: id of the job
+ // type: integer
+ // required: true
+ // responses:
+ // "201":
+ // "$ref": "#/responses/WorkflowJob"
+ // "400":
+ // "$ref": "#/responses/error"
+ // "403":
+ // "$ref": "#/responses/forbidden"
+ // "404":
+ // "$ref": "#/responses/notFound"
+ // "422":
+ // "$ref": "#/responses/validationError"
+
+ run, jobs := getCurrentRepoActionRunJobsByID(ctx)
+ if ctx.Written() {
+ return
+ }
+
+ jobID := ctx.PathParamInt64("job_id")
+ jobIdx := slices.IndexFunc(jobs, func(job *actions_model.ActionRunJob) bool { return job.ID == jobID })
+ if jobIdx == -1 {
+ ctx.APIErrorNotFound(util.NewNotExistErrorf("workflow job with id %d", jobID))
+ return
+ }
+
+ targetJob := jobs[jobIdx]
+ if err := actions_service.RerunWorkflowRunJobs(ctx, ctx.Repo.Repository, run, jobs, targetJob); err != nil {
+ handleWorkflowRerunError(ctx, err)
+ return
+ }
+
+ convertedJob, err := convert.ToActionWorkflowJob(ctx, ctx.Repo.Repository, nil, targetJob)
+ if err != nil {
+ ctx.APIErrorInternal(err)
+ return
+ }
+ ctx.JSON(http.StatusCreated, convertedJob)
+}
+
+func handleWorkflowRerunError(ctx *context.APIContext, err error) {
+ if errors.Is(err, util.ErrInvalidArgument) {
+ ctx.APIError(http.StatusBadRequest, err)
+ return
+ }
+ ctx.APIErrorInternal(err)
+}
+
// ListWorkflowRunJobs Lists all jobs for a workflow run.
func ListWorkflowRunJobs(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/actions/runs/{run}/jobs repository listWorkflowRunJobs
@@ -1202,9 +1346,7 @@ func ListWorkflowRunJobs(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- repoID := ctx.Repo.Repository.ID
-
- runID := ctx.PathParamInt64("run")
+ repoID, runID := ctx.Repo.Repository.ID, ctx.PathParamInt64("run")
// Avoid the list all jobs functionality for this api route to be used with a runID == 0.
if runID <= 0 {
@@ -1304,10 +1446,8 @@ func GetArtifactsOfRun(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- repoID := ctx.Repo.Repository.ID
artifactName := ctx.Req.URL.Query().Get("name")
-
- runID := ctx.PathParamInt64("run")
+ repoID, runID := ctx.Repo.Repository.ID, ctx.PathParamInt64("run")
artifacts, total, err := db.FindAndCount[actions_model.ActionArtifact](ctx, actions_model.FindArtifactsOptions{
RepoID: repoID,
@@ -1368,15 +1508,11 @@ func DeleteActionRun(ctx *context.APIContext) {
// "404":
// "$ref": "#/responses/notFound"
- runID := ctx.PathParamInt64("run")
- run, err := actions_model.GetRunByRepoAndID(ctx, ctx.Repo.Repository.ID, runID)
- if errors.Is(err, util.ErrNotExist) {
- ctx.APIErrorNotFound(err)
- return
- } else if err != nil {
- ctx.APIErrorInternal(err)
+ run := getCurrentRepoActionRunByID(ctx)
+ if ctx.Written() {
return
}
+
if !run.Status.IsDone() {
ctx.APIError(http.StatusBadRequest, "this workflow run is not done")
return
diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go
index 82fd68bdece..eaa8afb1e13 100644
--- a/routers/api/v1/repo/branch.go
+++ b/routers/api/v1/repo/branch.go
@@ -150,7 +150,7 @@ func DeleteBranch(ctx *context.APIContext) {
}
}
- if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName, nil); err != nil {
+ if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
switch {
case git.IsErrBranchNotExist(err):
ctx.APIErrorNotFound(err)
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index deb68963c20..e31bc24eef6 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -138,7 +138,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
// LFS Pointer files are at most 1024 bytes - so any blob greater than 1024 bytes cannot be an LFS file
if blob.Size() > lfs.MetaFileMaxSize {
// First handle caching for the blob
- if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return
}
@@ -174,7 +174,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
// if it's not a pointer, just serve the data directly
if !pointer.IsValid() {
// First handle caching for the blob
- if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return
}
@@ -189,7 +189,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
// If there isn't one, just serve the data directly
if errors.Is(err, git_model.ErrLFSObjectNotExist) {
// Handle caching for the blob SHA (not the LFS object OID)
- if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return
}
@@ -201,7 +201,7 @@ func GetRawFileOrLFS(ctx *context.APIContext) {
}
// Handle caching for the LFS object OID
- if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`, meta.UpdatedUnix.AsTimePtr()) {
return
}
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index 41076fd99c8..22324e19233 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -157,6 +157,10 @@ func SearchIssues(ctx *context.APIContext) {
// in: query
// description: Filter by repository owner
// type: string
+ // - name: created_by
+ // in: query
+ // description: Only show items which were created by the given user
+ // type: string
// - name: team
// in: query
// description: Filter by team (requires organization owner parameter)
@@ -257,6 +261,14 @@ func SearchIssues(ctx *context.APIContext) {
searchOpt.UpdatedBeforeUnix = optional.Some(before)
}
+ createdByID := getUserIDForFilter(ctx, "created_by")
+ if ctx.Written() {
+ return
+ }
+ if createdByID > 0 {
+ searchOpt.PosterID = strconv.FormatInt(createdByID, 10)
+ }
+
if ctx.IsSigned {
ctxUserID := ctx.Doer.ID
if ctx.FormBool("created") {
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index bb6bda587db..cfdcf7b374e 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -884,77 +884,44 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
}
}
- if opts.HasPullRequests != nil && !unit_model.TypePullRequests.UnitGlobalDisabled() {
- if *opts.HasPullRequests {
- // We do allow setting individual PR settings through the API, so
- // we get the config settings and then set them
- // if those settings were provided in the opts.
- unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests)
- var config *repo_model.PullRequestsConfig
- if err != nil {
- // Unit type doesn't exist so we make a new config file with default values
- config = &repo_model.PullRequestsConfig{
- IgnoreWhitespaceConflicts: false,
- AllowMerge: true,
- AllowRebase: true,
- AllowRebaseMerge: true,
- AllowSquash: true,
- AllowFastForwardOnly: true,
- AllowManualMerge: true,
- AutodetectManualMerge: false,
- AllowRebaseUpdate: true,
- DefaultDeleteBranchAfterMerge: false,
- DefaultMergeStyle: repo_model.MergeStyleMerge,
- DefaultAllowMaintainerEdit: false,
- }
- } else {
- config = unit.PullRequestsConfig()
- }
-
- if opts.IgnoreWhitespaceConflicts != nil {
- config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
- }
- if opts.AllowMerge != nil {
- config.AllowMerge = *opts.AllowMerge
- }
- if opts.AllowRebase != nil {
- config.AllowRebase = *opts.AllowRebase
- }
- if opts.AllowRebaseMerge != nil {
- config.AllowRebaseMerge = *opts.AllowRebaseMerge
- }
- if opts.AllowSquash != nil {
- config.AllowSquash = *opts.AllowSquash
- }
- if opts.AllowFastForwardOnly != nil {
- config.AllowFastForwardOnly = *opts.AllowFastForwardOnly
- }
- if opts.AllowManualMerge != nil {
- config.AllowManualMerge = *opts.AllowManualMerge
- }
- if opts.AutodetectManualMerge != nil {
- config.AutodetectManualMerge = *opts.AutodetectManualMerge
- }
- if opts.AllowRebaseUpdate != nil {
- config.AllowRebaseUpdate = *opts.AllowRebaseUpdate
- }
- if opts.DefaultDeleteBranchAfterMerge != nil {
- config.DefaultDeleteBranchAfterMerge = *opts.DefaultDeleteBranchAfterMerge
- }
- if opts.DefaultMergeStyle != nil {
- config.DefaultMergeStyle = repo_model.MergeStyle(*opts.DefaultMergeStyle)
- }
- if opts.DefaultAllowMaintainerEdit != nil {
- config.DefaultAllowMaintainerEdit = *opts.DefaultAllowMaintainerEdit
- }
-
- units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypePullRequests,
- Config: config,
- })
- } else {
+ if !unit_model.TypePullRequests.UnitGlobalDisabled() {
+ mustDeletePullRequestUnit := opts.HasPullRequests != nil && !*opts.HasPullRequests
+ mustInsertPullRequestUnit := opts.HasPullRequests != nil && *opts.HasPullRequests
+ if mustDeletePullRequestUnit {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
+ } else {
+ // We do allow setting individual PR settings through the API,
+ // so we get the config settings and then set them if those settings were provided in the opts.
+ unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests)
+ if err != nil && !errors.Is(err, util.ErrNotExist) {
+ return err
+ }
+ if unit == nil {
+ // Unit doesn't exist yet but is being enabled, create with defaults
+ unit = new(repo_model.DefaultPullRequestsUnit(repo.ID))
+ }
+
+ changed := new(false)
+ config := unit.PullRequestsConfig()
+ optional.AssignPtrValue(changed, &config.IgnoreWhitespaceConflicts, opts.IgnoreWhitespaceConflicts)
+ optional.AssignPtrValue(changed, &config.AllowMerge, opts.AllowMerge)
+ optional.AssignPtrValue(changed, &config.AllowRebase, opts.AllowRebase)
+ optional.AssignPtrValue(changed, &config.AllowRebaseMerge, opts.AllowRebaseMerge)
+ optional.AssignPtrValue(changed, &config.AllowSquash, opts.AllowSquash)
+ optional.AssignPtrValue(changed, &config.AllowFastForwardOnly, opts.AllowFastForwardOnly)
+ optional.AssignPtrValue(changed, &config.AllowManualMerge, opts.AllowManualMerge)
+ optional.AssignPtrValue(changed, &config.AutodetectManualMerge, opts.AutodetectManualMerge)
+ optional.AssignPtrValue(changed, &config.AllowRebaseUpdate, opts.AllowRebaseUpdate)
+ optional.AssignPtrValue(changed, &config.DefaultDeleteBranchAfterMerge, opts.DefaultDeleteBranchAfterMerge)
+ optional.AssignPtrValue(changed, &config.DefaultAllowMaintainerEdit, opts.DefaultAllowMaintainerEdit)
+ optional.AssignPtrString(changed, &config.DefaultMergeStyle, opts.DefaultMergeStyle)
+ if *changed || mustInsertPullRequestUnit {
+ units = append(units, repo_model.RepoUnit{
+ RepoID: repo.ID,
+ Type: unit_model.TypePullRequests,
+ Config: config,
+ })
+ }
}
}
diff --git a/routers/api/v1/swagger/action.go b/routers/api/v1/swagger/action.go
index 06065059502..328998db211 100644
--- a/routers/api/v1/swagger/action.go
+++ b/routers/api/v1/swagger/action.go
@@ -46,3 +46,10 @@ type swaggerResponseActionWorkflowList struct {
// in:body
Body api.ActionWorkflowResponse `json:"body"`
}
+
+// RunDetails
+// swagger:response RunDetails
+type swaggerResponseRunDetails struct {
+ // in:body
+ Body api.RunDetails `json:"body"`
+}
diff --git a/routers/api/v1/swagger/activitypub.go b/routers/api/v1/swagger/activitypub.go
deleted file mode 100644
index 91341669da9..00000000000
--- a/routers/api/v1/swagger/activitypub.go
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package swagger
-
-import (
- api "code.gitea.io/gitea/modules/structs"
-)
-
-// ActivityPub
-// swagger:response ActivityPub
-type swaggerResponseActivityPub struct {
- // in:body
- Body api.ActivityPub `json:"body"`
-}
diff --git a/routers/api/v1/user/runners.go b/routers/api/v1/user/runners.go
index be3f63cc5e1..77b0f59c1ed 100644
--- a/routers/api/v1/user/runners.go
+++ b/routers/api/v1/user/runners.go
@@ -10,21 +10,6 @@ import (
// 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)
-}
-
// CreateRegistrationToken returns the token to register user runners
func CreateRegistrationToken(ctx *context.APIContext) {
// swagger:operation POST /user/actions/runners/registration-token user userCreateRunnerRegistrationToken
diff --git a/routers/common/errpage.go b/routers/common/errpage.go
index b14ab8bcf80..2406cf443fa 100644
--- a/routers/common/errpage.go
+++ b/routers/common/errpage.go
@@ -13,6 +13,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/reqctx"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/web/middleware"
@@ -36,9 +37,7 @@ func renderServerErrorPage(w http.ResponseWriter, req *http.Request, respCode in
w.Header().Set(`X-Frame-Options`, setting.Security.XFrameOptions)
}
- tmplCtx := context.NewTemplateContext(req.Context(), req)
- tmplCtx["Locale"] = middleware.Locale(w, req)
-
+ tmplCtx := context.NewTemplateContextForWeb(reqctx.FromContext(req.Context()), req, middleware.Locale(w, req))
w.WriteHeader(respCode)
outBuf := &bytes.Buffer{}
diff --git a/routers/common/maintenancemode.go b/routers/common/maintenancemode.go
new file mode 100644
index 00000000000..b5827ac94f4
--- /dev/null
+++ b/routers/common/maintenancemode.go
@@ -0,0 +1,43 @@
+// Copyright 2026 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package common
+
+import (
+ "net/http"
+ "strings"
+
+ "code.gitea.io/gitea/modules/setting"
+)
+
+func isMaintenanceModeAllowedRequest(req *http.Request) bool {
+ if strings.HasPrefix(req.URL.Path, "/-/") {
+ // URLs like "/-/admin", "/-/fetch-redirect" and "/-/markup" are still accessible in maintenance mode
+ return true
+ }
+ if strings.HasPrefix(req.URL.Path, "/api/internal/") {
+ // internal APIs should be allowed
+ return true
+ }
+ if strings.HasPrefix(req.URL.Path, "/user/") {
+ // URLs like "/user/signin" and "/user/signup" are still accessible in maintenance mode
+ return true
+ }
+ if strings.HasPrefix(req.URL.Path, "/assets/") {
+ return true
+ }
+ return false
+}
+
+func MaintenanceModeHandler() func(h http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+ maintenanceMode := setting.Config().Instance.MaintenanceMode.Value(req.Context())
+ if maintenanceMode.IsActive() && !isMaintenanceModeAllowedRequest(req) {
+ renderServiceUnavailable(resp, req)
+ return
+ }
+ next.ServeHTTP(resp, req)
+ })
+ }
+}
diff --git a/routers/common/markup.go b/routers/common/markup.go
index e189bcdecf4..27c95eedb86 100644
--- a/routers/common/markup.go
+++ b/routers/common/markup.go
@@ -46,7 +46,7 @@ func RenderMarkup(ctx *context.Base, ctxRepo *context.Repository, mode, text, ur
return
}
- // Ideally, this handler should be called with RepoAssigment and get the related repo from context "/owner/repo/markup"
+ // Ideally, this handler should be called with RepoAssignment and get the related repo from context "/owner/repo/markup"
// then render could use the repo to do various things (the permission check has passed)
//
// However, this handler is also exposed as "/markup" without any repo context,
diff --git a/routers/common/serve.go b/routers/common/serve.go
index 862230b30f0..4bb1a48b0da 100644
--- a/routers/common/serve.go
+++ b/routers/common/serve.go
@@ -20,7 +20,7 @@ import (
// ServeBlob download a git.Blob
func ServeBlob(ctx *context.Base, repo *repo_model.Repository, filePath string, blob *git.Blob, lastModified *time.Time) error {
- if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return nil
}
diff --git a/routers/init.go b/routers/init.go
index 82a5378263d..8874236a607 100644
--- a/routers/init.go
+++ b/routers/init.go
@@ -181,6 +181,7 @@ func InitWebInstalled(ctx context.Context) {
func NormalRoutes() *web.Router {
r := web.NewRouter()
r.Use(common.ProtocolMiddlewares()...)
+ r.Use(common.MaintenanceModeHandler())
r.Mount("/", web_routers.Routes())
r.Mount("/api/v1", apiv1.Routes())
diff --git a/routers/install/install.go b/routers/install/install.go
index 399128b6ed4..81fcdfa384c 100644
--- a/routers/install/install.go
+++ b/routers/install/install.go
@@ -17,7 +17,6 @@ import (
"code.gitea.io/gitea/models/db"
db_install "code.gitea.io/gitea/models/db/install"
- system_model "code.gitea.io/gitea/models/system"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/generate"
@@ -114,11 +113,6 @@ func Install(ctx *context.Context) {
form.RegisterConfirm = setting.Service.RegisterEmailConfirm
form.MailNotify = setting.Service.EnableNotifyMail
- // Server and other services settings
- form.OfflineMode = setting.OfflineMode
- form.DisableGravatar = setting.DisableGravatar // when installing, there is no database connection so that given a default value
- form.EnableFederatedAvatar = setting.EnableFederatedAvatar // when installing, there is no database connection so that given a default value
-
form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn
form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp
form.DisableRegistration = setting.Service.DisableRegistration
@@ -141,7 +135,7 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
if (setting.Database.Type == "sqlite3") &&
len(setting.Database.Path) == 0 {
ctx.Data["Err_DbPath"] = true
- ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.err_empty_db_path"), tplInstall, form)
return false
}
@@ -152,10 +146,10 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
if err = db.InitEngine(ctx); err != nil {
if strings.Contains(err.Error(), `Unknown database type: sqlite3`) {
ctx.Data["Err_DbType"] = true
- ctx.RenderWithErr(ctx.Tr("install.sqlite3_not_available", "https://docs.gitea.com/installation/install-from-binary"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.sqlite3_not_available", "https://docs.gitea.com/installation/install-from-binary"), tplInstall, form)
} else {
ctx.Data["Err_DbSetting"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
}
return false
}
@@ -163,20 +157,20 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
err = db_install.CheckDatabaseConnection(ctx)
if err != nil {
ctx.Data["Err_DbSetting"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_setting", err), tplInstall, form)
return false
}
hasPostInstallationUser, err := db_install.HasPostInstallationUsers(ctx)
if err != nil {
ctx.Data["Err_DbSetting"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_db_table", "user", err), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_table", "user", err), tplInstall, form)
return false
}
dbMigrationVersion, err := db_install.GetMigrationVersion(ctx)
if err != nil {
ctx.Data["Err_DbSetting"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_db_table", "version", err), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_table", "version", err), tplInstall, form)
return false
}
@@ -185,7 +179,7 @@ func checkDatabase(ctx *context.Context, form *forms.InstallForm) bool {
confirmed := form.ReinstallConfirmFirst && form.ReinstallConfirmSecond && form.ReinstallConfirmThird
if !confirmed {
ctx.Data["Err_DbInstalledBefore"] = true
- ctx.RenderWithErr(ctx.Tr("install.reinstall_error"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.reinstall_error"), tplInstall, form)
return false
}
@@ -225,7 +219,7 @@ func SubmitInstall(ctx *context.Context) {
}
if _, err = exec.LookPath("git"); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.test_git_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.test_git_failed", err), tplInstall, &form)
return
}
@@ -248,7 +242,7 @@ func SubmitInstall(ctx *context.Context) {
// Prepare AppDataPath, it is very important for Gitea
if err = setting.PrepareAppDataPath(); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.invalid_app_data_path", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_app_data_path", err), tplInstall, &form)
return
}
@@ -256,7 +250,7 @@ func SubmitInstall(ctx *context.Context) {
form.RepoRootPath = strings.ReplaceAll(form.RepoRootPath, "\\", "/")
if err = os.MkdirAll(form.RepoRootPath, os.ModePerm); err != nil {
ctx.Data["Err_RepoRootPath"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_repo_path", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_repo_path", err), tplInstall, &form)
return
}
@@ -265,7 +259,7 @@ func SubmitInstall(ctx *context.Context) {
form.LFSRootPath = strings.ReplaceAll(form.LFSRootPath, "\\", "/")
if err := os.MkdirAll(form.LFSRootPath, os.ModePerm); err != nil {
ctx.Data["Err_LFSRootPath"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_lfs_path", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_lfs_path", err), tplInstall, &form)
return
}
}
@@ -274,14 +268,14 @@ func SubmitInstall(ctx *context.Context) {
form.LogRootPath = strings.ReplaceAll(form.LogRootPath, "\\", "/")
if err = os.MkdirAll(form.LogRootPath, os.ModePerm); err != nil {
ctx.Data["Err_LogRootPath"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_log_root_path", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_log_root_path", err), tplInstall, &form)
return
}
currentUser, match := setting.IsRunUserMatchCurrentUser(form.RunUser)
if !match {
ctx.Data["Err_RunUser"] = true
- ctx.RenderWithErr(ctx.Tr("install.run_user_not_match", form.RunUser, currentUser), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.run_user_not_match", form.RunUser, currentUser), tplInstall, &form)
return
}
@@ -289,7 +283,7 @@ func SubmitInstall(ctx *context.Context) {
if form.DisableRegistration && len(form.AdminName) == 0 {
ctx.Data["Err_Services"] = true
ctx.Data["Err_Admin"] = true
- ctx.RenderWithErr(ctx.Tr("install.no_admin_and_disable_registration"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.no_admin_and_disable_registration"), tplInstall, form)
return
}
@@ -300,33 +294,33 @@ func SubmitInstall(ctx *context.Context) {
ctx.Data["Err_Admin"] = true
ctx.Data["Err_AdminName"] = true
if db.IsErrNameReserved(err) {
- ctx.RenderWithErr(ctx.Tr("install.err_admin_name_is_reserved"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.err_admin_name_is_reserved"), tplInstall, form)
return
} else if db.IsErrNamePatternNotAllowed(err) {
- ctx.RenderWithErr(ctx.Tr("install.err_admin_name_pattern_not_allowed"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.err_admin_name_pattern_not_allowed"), tplInstall, form)
return
}
- ctx.RenderWithErr(ctx.Tr("install.err_admin_name_is_invalid"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.err_admin_name_is_invalid"), tplInstall, form)
return
}
// Check Admin email
if len(form.AdminEmail) == 0 {
ctx.Data["Err_Admin"] = true
ctx.Data["Err_AdminEmail"] = true
- ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_email"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.err_empty_admin_email"), tplInstall, form)
return
}
// Check admin password.
if len(form.AdminPasswd) == 0 {
ctx.Data["Err_Admin"] = true
ctx.Data["Err_AdminPasswd"] = true
- ctx.RenderWithErr(ctx.Tr("install.err_empty_admin_password"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.err_empty_admin_password"), tplInstall, form)
return
}
if form.AdminPasswd != form.AdminConfirmPasswd {
ctx.Data["Err_Admin"] = true
ctx.Data["Err_AdminPasswd"] = true
- ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplInstall, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.password_not_match"), tplInstall, form)
return
}
}
@@ -335,7 +329,7 @@ func SubmitInstall(ctx *context.Context) {
if err = db.InitEngineWithMigration(ctx, versioned_migration.Migrate); err != nil {
db.UnsetDefaultEngine()
ctx.Data["Err_DbSetting"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_db_setting", err), tplInstall, &form)
return
}
@@ -379,7 +373,7 @@ func SubmitInstall(ctx *context.Context) {
cfg.Section("lfs").Key("PATH").SetValue(form.LFSRootPath)
var lfsJwtSecret string
if _, lfsJwtSecret, err = generate.NewJwtSecretWithBase64(); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.lfs_jwt_secret_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.lfs_jwt_secret_failed", err), tplInstall, &form)
return
}
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(lfsJwtSecret)
@@ -389,7 +383,7 @@ func SubmitInstall(ctx *context.Context) {
if len(strings.TrimSpace(form.SMTPAddr)) > 0 {
if _, err := mail.ParseAddress(form.SMTPFrom); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.smtp_from_invalid"), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.smtp_from_invalid"), tplInstall, &form)
return
}
@@ -405,15 +399,6 @@ func SubmitInstall(ctx *context.Context) {
cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(strconv.FormatBool(form.RegisterConfirm))
cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(strconv.FormatBool(form.MailNotify))
- cfg.Section("server").Key("OFFLINE_MODE").SetValue(strconv.FormatBool(form.OfflineMode))
- if err := system_model.SetSettings(ctx, map[string]string{
- setting.Config().Picture.DisableGravatar.DynKey(): strconv.FormatBool(form.DisableGravatar),
- setting.Config().Picture.EnableFederatedAvatar.DynKey(): strconv.FormatBool(form.EnableFederatedAvatar),
- }); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
- return
- }
-
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(strconv.FormatBool(form.EnableOpenIDSignIn))
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(strconv.FormatBool(form.EnableOpenIDSignUp))
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(strconv.FormatBool(form.DisableRegistration))
@@ -443,7 +428,7 @@ func SubmitInstall(ctx *context.Context) {
if setting.InternalToken == "" {
var internalToken string
if internalToken, err = generate.NewInternalToken(); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.internal_token_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.internal_token_failed", err), tplInstall, &form)
return
}
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(internalToken)
@@ -454,7 +439,7 @@ func SubmitInstall(ctx *context.Context) {
if !cfg.Section("oauth2").HasKey("JWT_SECRET") && !cfg.Section("oauth2").HasKey("JWT_SECRET_URI") {
_, jwtSecretBase64, err := generate.NewJwtSecretWithBase64()
if err != nil {
- ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
return
}
cfg.Section("oauth2").Key("JWT_SECRET").SetValue(jwtSecretBase64)
@@ -464,7 +449,7 @@ func SubmitInstall(ctx *context.Context) {
if setting.SecretKey == "" {
var secretKey string
if secretKey, err = generate.NewSecretKey(); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
return
}
cfg.Section("security").Key("SECRET_KEY").SetValue(secretKey)
@@ -474,7 +459,7 @@ func SubmitInstall(ctx *context.Context) {
var algorithm *hash.PasswordHashAlgorithm
setting.PasswordHashAlgo, algorithm = hash.SetDefaultPasswordHashAlgorithm(form.PasswordAlgorithm)
if algorithm == nil {
- ctx.RenderWithErr(ctx.Tr("install.invalid_password_algorithm"), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_password_algorithm"), tplInstall, &form)
return
}
cfg.Section("security").Key("PASSWORD_HASH_ALGO").SetValue(form.PasswordAlgorithm)
@@ -484,14 +469,14 @@ func SubmitInstall(ctx *context.Context) {
err = os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm)
if err != nil {
- ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return
}
setting.EnvironmentToConfig(cfg, os.Environ())
if err = cfg.SaveTo(setting.CustomConf); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return
}
@@ -527,7 +512,7 @@ func SubmitInstall(ctx *context.Context) {
setting.InstallLock = false
ctx.Data["Err_AdminName"] = true
ctx.Data["Err_AdminEmail"] = true
- ctx.RenderWithErr(ctx.Tr("install.invalid_admin_setting", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.invalid_admin_setting", err), tplInstall, &form)
return
}
log.Info("Admin account already exist")
@@ -544,16 +529,16 @@ func SubmitInstall(ctx *context.Context) {
// Auto-login for admin
if err = ctx.Session.Set("uid", u.ID); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return
}
if err = ctx.Session.Set("uname", u.Name); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return
}
if err = ctx.Session.Release(); err != nil {
- ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return
}
}
diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go
index e8bef7d6c14..b595a95b23f 100644
--- a/routers/private/hook_post_receive.go
+++ b/routers/private/hook_post_receive.go
@@ -106,10 +106,10 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) {
}
if update.IsDelRef() {
- if err := git_model.AddDeletedBranch(ctx, repo.ID, update.RefFullName.BranchName(), update.PusherID); err != nil {
- log.Error("Failed to add deleted branch: %s/%s Error: %v", ownerName, repoName, err)
+ if err := git_model.MarkBranchAsDeleted(ctx, repo.ID, update.RefFullName.BranchName(), update.PusherID); err != nil {
+ log.Error("Failed to mark branch as deleted: %s/%s Error: %v", ownerName, repoName, err)
ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{
- Err: fmt.Sprintf("Failed to add deleted branch: %s/%s Error: %v", ownerName, repoName, err),
+ Err: fmt.Sprintf("Failed to mark branch as deleted: %s/%s Error: %v", ownerName, repoName, err),
})
return
}
diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go
index 39955116c42..704b777dbf7 100644
--- a/routers/private/hook_pre_receive.go
+++ b/routers/private/hook_pre_receive.go
@@ -151,7 +151,11 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID string, r
gitRepo := ctx.Repo.GitRepo
objectFormat := ctx.Repo.GetObjectFormat()
- if branchName == repo.DefaultBranch && newCommitID == objectFormat.EmptyObjectID().String() {
+ defaultBranch := repo.DefaultBranch
+ if ctx.opts.IsWiki && repo.DefaultWikiBranch != "" {
+ defaultBranch = repo.DefaultWikiBranch
+ }
+ if branchName == 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),
diff --git a/routers/private/internal.go b/routers/private/internal.go
index 55a11aa3dda..2d5436468b6 100644
--- a/routers/private/internal.go
+++ b/routers/private/internal.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/common"
+ "code.gitea.io/gitea/routers/web/misc"
"code.gitea.io/gitea/services/context"
"gitea.com/go-chi/binding"
@@ -59,6 +60,7 @@ func Routes() *web.Router {
// Since internal API will be sent only from Gitea sub commands and it's under control (checked by InternalToken), we can trust the headers.
r.Use(chi_middleware.RealIP)
+ r.Get("/dummy", misc.DummyOK)
r.Post("/ssh/authorized_keys", AuthorizedPublicKeyByContent)
r.Post("/ssh/{id}/update/{repoid}", UpdatePublicKeyInRepo)
r.Post("/ssh/log", bind(private.SSHLogOption{}), SSHLog)
diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go
index 3407789f2f9..e29aca127c8 100644
--- a/routers/web/admin/auths.go
+++ b/routers/web/admin/auths.go
@@ -273,7 +273,7 @@ func NewAuthSourcePost(ctx *context.Context) {
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
ctx.Data["Err_DiscoveryURL"] = true
- ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
return
}
}
@@ -281,13 +281,13 @@ func NewAuthSourcePost(ctx *context.Context) {
var err error
config, err = parseSSPIConfig(ctx, form)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplAuthNew, form)
+ ctx.RenderWithErrDeprecated(err.Error(), tplAuthNew, form)
return
}
existing, err := db.Find[auth.Source](ctx, auth.FindSourcesOptions{LoginType: auth.SSPI})
if err != nil || len(existing) > 0 {
ctx.Data["Err_Type"] = true
- ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_of_type_exist"), tplAuthNew, form)
return
}
default:
@@ -311,11 +311,11 @@ func NewAuthSourcePost(ctx *context.Context) {
}); err != nil {
if auth.IsErrSourceAlreadyExist(err) {
ctx.Data["Err_Name"] = true
- ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
} else if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Data["Err_DiscoveryURL"] = true
unwrapped := err.(oauth2.ErrOpenIDConnectInitialize).Unwrap()
- ctx.RenderWithErr(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
} else {
ctx.ServerError("auth.CreateSource", err)
}
@@ -403,14 +403,14 @@ func EditAuthSourcePost(ctx *context.Context) {
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
ctx.Data["Err_DiscoveryURL"] = true
- ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
return
}
}
case auth.SSPI:
config, err = parseSSPIConfig(ctx, form)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplAuthEdit, form)
+ ctx.RenderWithErrDeprecated(err.Error(), tplAuthEdit, form)
return
}
default:
@@ -426,7 +426,7 @@ func EditAuthSourcePost(ctx *context.Context) {
if err := auth.UpdateSource(ctx, source); err != nil {
if auth.IsErrSourceAlreadyExist(err) {
ctx.Data["Err_Name"] = true
- ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthEdit, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthEdit, form)
} else if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Flash.Error(err.Error(), true)
ctx.Data["Err_DiscoveryURL"] = true
diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go
index 774b31ab984..a449796ec12 100644
--- a/routers/web/admin/config.go
+++ b/routers/web/admin/config.go
@@ -5,9 +5,9 @@
package admin
import (
+ "errors"
"net/http"
"net/url"
- "strconv"
"strings"
system_model "code.gitea.io/gitea/models/system"
@@ -126,7 +126,6 @@ func Config(ctx *context.Context) {
ctx.Data["AppUrl"] = setting.AppURL
ctx.Data["AppBuiltWith"] = setting.AppBuiltWith
ctx.Data["Domain"] = setting.Domain
- ctx.Data["OfflineMode"] = setting.OfflineMode
ctx.Data["RunUser"] = setting.RunUser
ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode)
ctx.Data["GitVersion"] = git.DefaultFeatures().VersionInfo()
@@ -145,7 +144,6 @@ func Config(ctx *context.Context) {
ctx.Data["Service"] = setting.Service
ctx.Data["DbCfg"] = setting.Database
ctx.Data["Webhook"] = setting.Webhook
-
ctx.Data["MailerEnabled"] = false
if setting.MailService != nil {
ctx.Data["MailerEnabled"] = true
@@ -191,52 +189,27 @@ func ConfigSettings(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.config_settings")
ctx.Data["PageIsAdminConfig"] = true
ctx.Data["PageIsAdminConfigSettings"] = true
- ctx.Data["DefaultOpenWithEditorAppsString"] = setting.DefaultOpenWithEditorApps().ToTextareaString()
ctx.HTML(http.StatusOK, tplConfigSettings)
}
+func validateConfigKeyValue(dynKey, input string) error {
+ opt := config.GetConfigOption(dynKey)
+ if opt == nil {
+ return util.NewInvalidArgumentErrorf("unknown config key: %s", dynKey)
+ }
+
+ const limit = 64 * 1024
+ if len(input) > limit {
+ return util.NewInvalidArgumentErrorf("value length exceeds limit of %d", limit)
+ }
+
+ if !json.Valid([]byte(input)) {
+ return util.NewInvalidArgumentErrorf("invalid json value for key: %s", dynKey)
+ }
+ return nil
+}
+
func ChangeConfig(ctx *context.Context) {
- cfg := setting.Config()
-
- marshalBool := func(v string) ([]byte, error) {
- b, _ := strconv.ParseBool(v)
- return json.Marshal(b)
- }
-
- marshalString := func(emptyDefault string) func(v string) ([]byte, error) {
- return func(v string) ([]byte, error) {
- return json.Marshal(util.IfZero(v, emptyDefault))
- }
- }
-
- marshalOpenWithApps := func(value string) ([]byte, error) {
- // TODO: move the block alongside OpenWithEditorAppsType.ToTextareaString
- lines := strings.Split(value, "\n")
- var openWithEditorApps setting.OpenWithEditorAppsType
- for _, line := range lines {
- line = strings.TrimSpace(line)
- if line == "" {
- continue
- }
- displayName, openURL, ok := strings.Cut(line, "=")
- displayName, openURL = strings.TrimSpace(displayName), strings.TrimSpace(openURL)
- if !ok || displayName == "" || openURL == "" {
- continue
- }
- openWithEditorApps = append(openWithEditorApps, setting.OpenWithEditorApp{
- DisplayName: strings.TrimSpace(displayName),
- OpenURL: strings.TrimSpace(openURL),
- })
- }
- return json.Marshal(openWithEditorApps)
- }
- marshallers := map[string]func(string) ([]byte, error){
- cfg.Picture.DisableGravatar.DynKey(): marshalBool,
- cfg.Picture.EnableFederatedAvatar.DynKey(): marshalBool,
- cfg.Repository.OpenWithEditorApps.DynKey(): marshalOpenWithApps,
- cfg.Repository.GitGuideRemoteName.DynKey(): marshalString(cfg.Repository.GitGuideRemoteName.DefaultValue()),
- }
-
_ = ctx.Req.ParseForm()
configKeys := ctx.Req.Form["key"]
configValues := ctx.Req.Form["value"]
@@ -249,18 +222,16 @@ loop:
}
value := configValues[i]
- marshaller, hasMarshaller := marshallers[key]
- if !hasMarshaller {
- ctx.JSONError(ctx.Tr("admin.config.set_setting_failed", key))
- break loop
- }
-
- marshaledValue, err := marshaller(value)
+ err := validateConfigKeyValue(key, value)
if err != nil {
- ctx.JSONError(ctx.Tr("admin.config.set_setting_failed", key))
+ if errors.Is(err, util.ErrInvalidArgument) {
+ ctx.JSONError(err.Error())
+ } else {
+ ctx.JSONError(ctx.Tr("admin.config.set_setting_failed", key))
+ }
break loop
}
- configSettings[key] = string(marshaledValue)
+ configSettings[key] = value
}
if ctx.Written() {
return
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index ed0eecf90a6..19499fdab56 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -151,12 +151,12 @@ func NewUserPost(ctx *context.Context) {
if u.LoginType == auth.NoType || u.LoginType == auth.Plain {
if len(form.Password) < setting.MinPasswordLength {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserNew, &form)
return
}
if !password.IsComplexEnough(form.Password) {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplUserNew, &form)
return
}
if err := password.IsPwned(ctx, form.Password); err != nil {
@@ -166,7 +166,7 @@ func NewUserPost(ctx *context.Context) {
log.Error(err.Error())
errMsg = ctx.Tr("auth.password_pwned_err")
}
- ctx.RenderWithErr(errMsg, tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(errMsg, tplUserNew, &form)
return
}
u.MustChangePassword = form.MustChangePassword
@@ -176,22 +176,22 @@ func NewUserPost(ctx *context.Context) {
switch {
case user_model.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_been_taken"), tplUserNew, &form)
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_been_used"), tplUserNew, &form)
case user_model.IsErrEmailInvalid(err), user_model.IsErrEmailCharIsNotSupported(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tplUserNew, &form)
case db.IsErrNameReserved(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tplUserNew, &form)
case db.IsErrNamePatternNotAllowed(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplUserNew, &form)
case db.IsErrNameCharsNotAllowed(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tplUserNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tplUserNew, &form)
default:
ctx.ServerError("CreateUser", err)
}
@@ -349,19 +349,19 @@ func EditUserPost(ctx *context.Context) {
switch {
case user_model.IsErrUserIsNotLocal(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("form.username_change_not_local_user"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_change_not_local_user"), tplUserEdit, &form)
case user_model.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_been_taken"), tplUserEdit, &form)
case db.IsErrNameReserved(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", form.UserName), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", form.UserName), tplUserEdit, &form)
case db.IsErrNamePatternNotAllowed(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", form.UserName), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", form.UserName), tplUserEdit, &form)
case db.IsErrNameCharsNotAllowed(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", form.UserName), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", form.UserName), tplUserEdit, &form)
default:
ctx.ServerError("RenameUser", err)
}
@@ -392,16 +392,16 @@ func EditUserPost(ctx *context.Context) {
switch {
case errors.Is(err, password.ErrMinLength):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplUserEdit, &form)
case errors.Is(err, password.ErrComplexity):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplUserEdit, &form)
case errors.Is(err, password.ErrIsPwned):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplUserEdit, &form)
case password.IsErrIsPwnedRequest(err):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form)
default:
ctx.ServerError("UpdateUser", err)
}
@@ -413,10 +413,10 @@ func EditUserPost(ctx *context.Context) {
switch {
case user_model.IsErrEmailCharIsNotSupported(err), user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
default:
ctx.ServerError("AddOrSetPrimaryEmailAddress", err)
}
@@ -444,7 +444,7 @@ func EditUserPost(ctx *context.Context) {
if err := user_service.UpdateUser(ctx, u, opts); err != nil {
if user_model.IsErrDeleteLastAdminUser(err) {
- ctx.RenderWithErr(ctx.Tr("auth.last_admin"), tplUserEdit, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.last_admin"), tplUserEdit, &form)
} else {
ctx.ServerError("UpdateUser", err)
}
diff --git a/routers/web/auth/2fa.go b/routers/web/auth/2fa.go
index a19c9d7aca3..73b218d92df 100644
--- a/routers/web/auth/2fa.go
+++ b/routers/web/auth/2fa.go
@@ -92,7 +92,7 @@ func TwoFactorPost(ctx *context.Context) {
return
}
- ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplTwofa, forms.TwoFactorAuthForm{})
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.twofa_passcode_incorrect"), tplTwofa, forms.TwoFactorAuthForm{})
}
// TwoFactorScratch shows the scratch code form for two-factor authentication.
@@ -160,5 +160,5 @@ func TwoFactorScratchPost(ctx *context.Context) {
return
}
- ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplTwofaScratch, forms.TwoFactorScratchAuthForm{})
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplTwofaScratch, forms.TwoFactorScratchAuthForm{})
}
diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go
index bc0939d92a1..fbc3f9f07db 100644
--- a/routers/web/auth/auth.go
+++ b/routers/web/auth/auth.go
@@ -162,6 +162,11 @@ func consumeAuthRedirectLink(ctx *context.Context) string {
}
func redirectAfterAuth(ctx *context.Context) {
+ if setting.Config().Instance.MaintenanceMode.Value(ctx).IsActive() {
+ // in maintenance mode, redirect to admin dashboard, it is the only accessible page
+ ctx.Redirect(setting.AppSubURL + "/-/admin")
+ return
+ }
ctx.RedirectToCurrentSite(consumeAuthRedirectLink(ctx))
}
@@ -240,10 +245,10 @@ func SignInPost(ctx *context.Context) {
u, source, err := auth_service.UserSignIn(ctx, form.UserName, form.Password)
if err != nil {
if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
- ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrEmailAlreadyUsed(err) {
- ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_been_used"), tplSignIn, &form)
log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if user_model.IsErrUserProhibitLogin(err) {
log.Warn("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
@@ -420,8 +425,21 @@ func SignOut(ctx *context.Context) {
Data: ctx.Session.ID(),
})
}
+
+ // prepare the sign-out URL before destroying the session
+ redirectTo := buildSignOutRedirectURL(ctx)
HandleSignOut(ctx)
- ctx.JSONRedirect(setting.AppSubURL + "/")
+ ctx.Redirect(redirectTo)
+}
+
+func buildSignOutRedirectURL(ctx *context.Context) string {
+ // TODO: can also support REVERSE_PROXY_AUTHENTICATION logout URL in the future
+ if ctx.Doer != nil && ctx.Doer.LoginType == auth.OAuth2 {
+ if s := buildOIDCEndSessionURL(ctx, ctx.Doer); s != "" {
+ return s
+ }
+ }
+ return setting.AppSubURL + "/"
}
// SignUp render the register page
@@ -486,23 +504,23 @@ func SignUpPost(ctx *context.Context) {
}
if !form.IsEmailDomainAllowed() {
- ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.email_domain_blacklisted"), tplSignUp, &form)
return
}
if form.Password != form.Retype {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplSignUp, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.password_not_match"), tplSignUp, &form)
return
}
if len(form.Password) < setting.MinPasswordLength {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplSignUp, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplSignUp, &form)
return
}
if !password.IsComplexEnough(form.Password) {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplSignUp, &form)
+ ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplSignUp, &form)
return
}
if err := password.IsPwned(ctx, form.Password); err != nil {
@@ -512,7 +530,7 @@ func SignUpPost(ctx *context.Context) {
errMsg = ctx.Tr("auth.password_pwned_err")
}
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(errMsg, tplSignUp, &form)
+ ctx.RenderWithErrDeprecated(errMsg, tplSignUp, &form)
return
}
@@ -582,25 +600,25 @@ func createUserInContext(ctx *context.Context, tpl templates.TplName, form any,
switch {
case user_model.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_been_taken"), tpl, form)
case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_been_used"), tpl, form)
case user_model.IsErrEmailCharIsNotSupported(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tpl, form)
case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tpl, form)
case db.IsErrNameReserved(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
case db.IsErrNamePatternNotAllowed(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
case db.IsErrNameCharsNotAllowed(err):
ctx.Data["Err_UserName"] = true
- ctx.RenderWithErr(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("user.form.name_chars_not_allowed", err.(db.ErrNameCharsNotAllowed).Name), tpl, form)
default:
ctx.ServerError("CreateUser", err)
}
diff --git a/routers/web/auth/auth_test.go b/routers/web/auth/auth_test.go
index 5ccffe0d505..d1f808181aa 100644
--- a/routers/web/auth/auth_test.go
+++ b/routers/web/auth/auth_test.go
@@ -5,10 +5,12 @@ package auth
import (
"net/http"
+ "net/http/httptest"
"net/url"
"testing"
auth_model "code.gitea.io/gitea/models/auth"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
@@ -19,6 +21,7 @@ import (
"github.com/markbates/goth"
"github.com/markbates/goth/gothic"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) {
@@ -29,10 +32,10 @@ func addOAuth2Source(t *testing.T, authName string, cfg oauth2.Source) {
IsActive: true,
Cfg: &cfg,
})
- assert.NoError(t, err)
+ require.NoError(t, err)
}
-func TestUserLogin(t *testing.T) {
+func TestWebAuthUserLogin(t *testing.T) {
ctx, resp := contexttest.MockContext(t, "/user/login")
SignIn(ctx)
assert.Equal(t, http.StatusOK, resp.Code)
@@ -60,7 +63,7 @@ func TestUserLogin(t *testing.T) {
assert.Equal(t, "/", test.RedirectURL(resp))
}
-func TestSignUpOAuth2Login(t *testing.T) {
+func TestWebAuthOAuth2(t *testing.T) {
defer test.MockVariableValue(&setting.OAuth2Client.EnableAutoRegistration, true)()
_ = oauth2.Init(t.Context())
@@ -92,4 +95,43 @@ func TestSignUpOAuth2Login(t *testing.T) {
assert.Equal(t, "/user/login", test.RedirectURL(resp))
assert.Contains(t, ctx.Flash.ErrorMsg, "auth.oauth.signin.error.general")
})
+
+ t.Run("OIDCLogout", func(t *testing.T) {
+ var mockServer *httptest.Server
+ mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ switch r.URL.Path {
+ case "/.well-known/openid-configuration":
+ _, _ = w.Write([]byte(`{
+ "issuer": "` + mockServer.URL + `",
+ "authorization_endpoint": "` + mockServer.URL + `/authorize",
+ "token_endpoint": "` + mockServer.URL + `/token",
+ "userinfo_endpoint": "` + mockServer.URL + `/userinfo",
+ "end_session_endpoint": "https://example.com/oidc-logout?oidc-key=oidc-val"
+ }`))
+ default:
+ http.NotFound(w, r)
+ }
+ }))
+ defer mockServer.Close()
+
+ addOAuth2Source(t, "oidc-auth-source", oauth2.Source{
+ Provider: "openidConnect",
+ ClientID: "mock-client-id",
+ OpenIDConnectAutoDiscoveryURL: mockServer.URL + "/.well-known/openid-configuration",
+ })
+ authSource, err := auth_model.GetActiveOAuth2SourceByAuthName(t.Context(), "oidc-auth-source")
+ require.NoError(t, err)
+
+ mockOpt := contexttest.MockContextOption{SessionStore: session.NewMockMemStore("dummy-sid")}
+ ctx, resp := contexttest.MockContext(t, "/user/logout", mockOpt)
+ ctx.Doer = &user_model.User{ID: 1, LoginType: auth_model.OAuth2, LoginSource: authSource.ID}
+ SignOut(ctx)
+ assert.Equal(t, http.StatusSeeOther, resp.Code)
+ u, err := url.Parse(test.RedirectURL(resp))
+ require.NoError(t, err)
+ expectedValues := url.Values{"oidc-key": []string{"oidc-val"}, "post_logout_redirect_uri": []string{setting.AppURL}, "client_id": []string{"mock-client-id"}}
+ assert.Equal(t, expectedValues, u.Query())
+ u.RawQuery = ""
+ assert.Equal(t, "https://example.com/oidc-logout", u.String())
+ })
}
diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go
index c624d896ca7..faa712471f4 100644
--- a/routers/web/auth/linkaccount.go
+++ b/routers/web/auth/linkaccount.go
@@ -99,10 +99,10 @@ func LinkAccount(ctx *context.Context) {
func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl templates.TplName, invoker string, err error) {
if errors.Is(err, util.ErrNotExist) {
- ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm)
} else if errors.Is(err, util.ErrInvalidArgument) {
ctx.Data["user_exists"] = true
- ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm)
} else if user_model.IsErrUserProhibitLogin(err) {
ctx.Data["user_exists"] = true
log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err)
@@ -266,7 +266,7 @@ func LinkAccountPostRegister(ctx *context.Context) {
}
if !form.IsEmailDomainAllowed() {
- ctx.RenderWithErr(ctx.Tr("auth.email_domain_blacklisted"), tplLinkAccount, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.email_domain_blacklisted"), tplLinkAccount, &form)
return
}
@@ -280,12 +280,12 @@ func LinkAccountPostRegister(ctx *context.Context) {
} else {
if (len(strings.TrimSpace(form.Password)) > 0 || len(strings.TrimSpace(form.Retype)) > 0) && form.Password != form.Retype {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplLinkAccount, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.password_not_match"), tplLinkAccount, &form)
return
}
if len(strings.TrimSpace(form.Password)) > 0 && len(form.Password) < setting.MinPasswordLength {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplLinkAccount, &form)
return
}
}
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index b96ea17bc34..bb0784e434e 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -10,6 +10,7 @@ import (
"html"
"io"
"net/http"
+ "net/url"
"sort"
"strings"
@@ -17,6 +18,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
auth_module "code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/container"
+ "code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/session"
@@ -506,3 +508,38 @@ func oAuth2UserLoginCallback(ctx *context.Context, authSource *auth.Source, requ
// no user found to login
return nil, gothUser, nil
}
+
+// buildOIDCEndSessionURL constructs an OIDC RP-Initiated Logout URL for the
+// given user. Returns "" if the user's auth source is not OIDC or doesn't
+// advertise an end_session_endpoint.
+func buildOIDCEndSessionURL(ctx *context.Context, doer *user_model.User) string {
+ authSource, err := auth.GetSourceByID(ctx, doer.LoginSource)
+ if err != nil {
+ log.Error("Failed to get auth source for OIDC logout (source=%d): %v", doer.LoginSource, err)
+ return ""
+ }
+
+ oauth2Cfg, ok := authSource.Cfg.(*oauth2.Source)
+ if !ok {
+ return ""
+ }
+
+ endSessionEndpoint := oauth2.GetOIDCEndSessionEndpoint(authSource.Name)
+ if endSessionEndpoint == "" {
+ return ""
+ }
+
+ endSessionURL, err := url.Parse(endSessionEndpoint)
+ if err != nil {
+ log.Error("Failed to parse end_session_endpoint %q: %v", endSessionEndpoint, err)
+ return ""
+ }
+
+ // RP-Initiated Logout 1.0: use client_id to identify the client to the IdP.
+ // https://openid.net/specs/openid-connect-rpinitiated-1_0.html#RPLogout
+ params := endSessionURL.Query()
+ params.Set("client_id", oauth2Cfg.ClientID)
+ params.Set("post_logout_redirect_uri", httplib.GuessCurrentAppURL(ctx))
+ endSessionURL.RawQuery = params.Encode()
+ return endSessionURL.String()
+}
diff --git a/routers/web/auth/oauth2_provider.go b/routers/web/auth/oauth2_provider.go
index e09469526e9..05931d8f596 100644
--- a/routers/web/auth/oauth2_provider.go
+++ b/routers/web/auth/oauth2_provider.go
@@ -4,6 +4,7 @@
package auth
import (
+ "errors"
"fmt"
"html"
"html/template"
@@ -613,6 +614,14 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
})
return
}
+ if authorizationCode.IsExpired() {
+ _ = authorizationCode.Invalidate(ctx)
+ handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
+ ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidGrant,
+ ErrorDescription: "authorization code expired",
+ })
+ return
+ }
// check if code verifier authorizes the client, PKCE support
if !authorizationCode.ValidateCodeChallenge(form.CodeVerifier) {
handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
@@ -631,9 +640,15 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
}
// remove token from database to deny duplicate usage
if err := authorizationCode.Invalidate(ctx); err != nil {
+ errDescription := "cannot process your request"
+ errCode := oauth2_provider.AccessTokenErrorCodeInvalidRequest
+ if errors.Is(err, auth.ErrOAuth2AuthorizationCodeInvalidated) {
+ errDescription = "authorization code already used"
+ errCode = oauth2_provider.AccessTokenErrorCodeInvalidGrant
+ }
handleAccessTokenError(ctx, oauth2_provider.AccessTokenError{
- ErrorCode: oauth2_provider.AccessTokenErrorCodeInvalidRequest,
- ErrorDescription: "cannot proceed your request",
+ ErrorCode: errCode,
+ ErrorDescription: errDescription,
})
return
}
diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go
index 948e65366e5..c9843146d45 100644
--- a/routers/web/auth/openid.go
+++ b/routers/web/auth/openid.go
@@ -82,7 +82,7 @@ func SignInOpenIDPost(ctx *context.Context) {
id, err := openid.Normalize(form.Openid)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &form)
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &form)
return
}
form.Openid = id
@@ -91,7 +91,7 @@ func SignInOpenIDPost(ctx *context.Context) {
err = allowedOpenIDURI(id)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &form)
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &form)
return
}
@@ -99,7 +99,7 @@ func SignInOpenIDPost(ctx *context.Context) {
url, err := openid.RedirectURL(id, redirectTo, setting.AppURL)
if err != nil {
log.Error("Error in OpenID redirect URL: %s, %v", redirectTo, err.Error())
- ctx.RenderWithErr("Unable to find OpenID provider in "+redirectTo, tplSignInOpenID, &form)
+ ctx.RenderWithErrDeprecated("Unable to find OpenID provider in "+redirectTo, tplSignInOpenID, &form)
return
}
@@ -129,7 +129,7 @@ func signInOpenIDVerify(ctx *context.Context) {
id, err := openid.Verify(fullURL)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
Openid: id,
})
return
@@ -143,7 +143,7 @@ func signInOpenIDVerify(ctx *context.Context) {
u, err := user_model.GetUserByOpenID(ctx, id)
if err != nil {
if !user_model.IsErrUserNotExist(err) {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
Openid: id,
})
return
@@ -162,14 +162,14 @@ func signInOpenIDVerify(ctx *context.Context) {
parsedURL, err := url.Parse(fullURL)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
Openid: id,
})
return
}
values, err := url.ParseQuery(parsedURL.RawQuery)
if err != nil {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
Openid: id,
})
return
@@ -183,7 +183,7 @@ func signInOpenIDVerify(ctx *context.Context) {
u, err = user_model.GetUserByEmail(ctx, email)
if err != nil {
if !user_model.IsErrUserNotExist(err) {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
Openid: id,
})
return
@@ -199,7 +199,7 @@ func signInOpenIDVerify(ctx *context.Context) {
u, _ = user_model.GetUserByName(ctx, nickname)
if err != nil {
if !user_model.IsErrUserNotExist(err) {
- ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{
Openid: id,
})
return
@@ -273,7 +273,7 @@ func ConnectOpenIDPost(ctx *context.Context) {
userOID := &user_model.UserOpenID{UID: u.ID, URI: oid}
if err = user_model.AddUserOpenID(ctx, userOID); err != nil {
if user_model.IsErrOpenIDAlreadyUsed(err) {
- ctx.RenderWithErr(ctx.Tr("form.openid_been_used", oid), tplConnectOID, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.openid_been_used", oid), tplConnectOID, &form)
return
}
ctx.ServerError("AddUserOpenID", err)
@@ -352,7 +352,7 @@ func RegisterOpenIDPost(ctx *context.Context) {
length := max(setting.MinPasswordLength, 256)
password, err := util.CryptoRandomString(int64(length))
if err != nil {
- ctx.RenderWithErr(err.Error(), tplSignUpOID, form)
+ ctx.RenderWithErrDeprecated(err.Error(), tplSignUpOID, form)
return
}
@@ -370,7 +370,7 @@ func RegisterOpenIDPost(ctx *context.Context) {
userOID := &user_model.UserOpenID{UID: u.ID, URI: oid}
if err = user_model.AddUserOpenID(ctx, userOID); err != nil {
if user_model.IsErrOpenIDAlreadyUsed(err) {
- ctx.RenderWithErr(ctx.Tr("form.openid_been_used", oid), tplSignUpOID, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.openid_been_used", oid), tplSignUpOID, &form)
return
}
ctx.ServerError("AddUserOpenID", err)
diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go
index 61c6119470d..11e085f5b1e 100644
--- a/routers/web/auth/password.go
+++ b/routers/web/auth/password.go
@@ -74,7 +74,7 @@ func ForgotPasswdPost(ctx *context.Context) {
if !u.IsLocal() && !u.IsOAuth2() {
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("auth.non_local_account"), tplForgotPassword, nil)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.non_local_account"), tplForgotPassword, nil)
return
}
@@ -171,7 +171,7 @@ func ResetPasswdPost(ctx *context.Context) {
if !twofa.VerifyScratchToken(ctx.FormString("token")) {
ctx.Data["IsResetForm"] = true
ctx.Data["Err_Token"] = true
- ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplResetPassword, nil)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplResetPassword, nil)
return
}
regenerateScratchToken = true
@@ -185,7 +185,7 @@ func ResetPasswdPost(ctx *context.Context) {
if !ok || twofa.LastUsedPasscode == passcode {
ctx.Data["IsResetForm"] = true
ctx.Data["Err_Passcode"] = true
- ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplResetPassword, nil)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.twofa_passcode_incorrect"), tplResetPassword, nil)
return
}
@@ -206,13 +206,13 @@ func ResetPasswdPost(ctx *context.Context) {
ctx.Data["Err_Password"] = true
switch {
case errors.Is(err, password.ErrMinLength):
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplResetPassword, nil)
case errors.Is(err, password.ErrComplexity):
- ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplResetPassword, nil)
+ ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplResetPassword, nil)
case errors.Is(err, password.ErrIsPwned):
- ctx.RenderWithErr(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplResetPassword, nil)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplResetPassword, nil)
case password.IsErrIsPwnedRequest(err):
- ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil)
default:
ctx.ServerError("UpdateAuth", err)
}
@@ -275,7 +275,7 @@ func MustChangePasswordPost(ctx *context.Context) {
if form.Password != form.Retype {
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("form.password_not_match"), tplMustChangePassword, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.password_not_match"), tplMustChangePassword, &form)
return
}
@@ -287,16 +287,16 @@ func MustChangePasswordPost(ctx *context.Context) {
switch {
case errors.Is(err, password.ErrMinLength):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplMustChangePassword, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplMustChangePassword, &form)
case errors.Is(err, password.ErrComplexity):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(password.BuildComplexityError(ctx.Locale), tplMustChangePassword, &form)
+ ctx.RenderWithErrDeprecated(password.BuildComplexityError(ctx.Locale), tplMustChangePassword, &form)
case errors.Is(err, password.ErrIsPwned):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplMustChangePassword, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned", "https://haveibeenpwned.com/Passwords"), tplMustChangePassword, &form)
case password.IsErrIsPwnedRequest(err):
ctx.Data["Err_Password"] = true
- ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form)
default:
ctx.ServerError("UpdateAuth", err)
}
diff --git a/routers/web/base.go b/routers/web/base.go
index 0f06cb5e4b9..db96432bedc 100644
--- a/routers/web/base.go
+++ b/routers/web/base.go
@@ -6,11 +6,14 @@ package web
import (
"errors"
"fmt"
+ "image/png"
"net/http"
"os"
"path"
"strings"
+ "code.gitea.io/gitea/modules/assetfs"
+ "code.gitea.io/gitea/modules/avatar"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -22,79 +25,70 @@ import (
func avatarStorageHandler(storageSetting *setting.Storage, prefix string, objStore storage.ObjectStorage) http.HandlerFunc {
prefix = strings.Trim(prefix, "/")
funcInfo := routing.GetFuncInfo(avatarStorageHandler, prefix)
+ exeModTime := assetfs.GetExecutableModTime()
+ fallbackEtag := fmt.Sprintf(`"avatar-%s"`, exeModTime.Format("20060102150405"))
- if storageSetting.ServeDirect() {
- return func(w http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodGet && req.Method != http.MethodHead {
- http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
- return
- }
-
- if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
- return
- }
- defer routing.RecordFuncInfo(req.Context(), funcInfo)()
-
- rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
- rPath = util.PathJoinRelX(rPath)
-
- u, err := objStore.URL(rPath, path.Base(rPath), req.Method, nil)
- if err != nil {
- if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
- log.Warn("Unable to find %s %s", prefix, rPath)
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
- return
- }
- log.Error("Error whilst getting URL for %s %s. Error: %v", prefix, rPath, err)
- http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), http.StatusInternalServerError)
- return
- }
-
- http.Redirect(w, req, u.String(), http.StatusTemporaryRedirect)
+ handleError := func(w http.ResponseWriter, req *http.Request, avatarPath string, err error) bool {
+ if err == nil {
+ return false
}
+
+ if errors.Is(err, os.ErrNotExist) || errors.Is(err, util.ErrNotExist) {
+ // if avatar doesn't exist, generate a random one and serve it with proper cache control headers
+ w.Header().Set("Content-Type", "image/png")
+ if !httpcache.HandleGenericETagPublicCache(req, w, fallbackEtag, &exeModTime) {
+ if req.Method == http.MethodGet {
+ img := avatar.RandomImageWithSize(96, []byte(avatarPath))
+ _ = png.Encode(w, img)
+ } // else: for HEAD request, just return the headers without body
+ }
+ } else {
+ // for internal errors, log the error and return 500
+ log.Error("Error when serving avatar %s: %s", req.URL.Path, err)
+ http.Error(w, "unable to serve avatar image", http.StatusInternalServerError)
+ }
+ return true
}
return func(w http.ResponseWriter, req *http.Request) {
- if req.Method != http.MethodGet && req.Method != http.MethodHead {
- http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
- return
- }
-
- if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
- return
- }
defer routing.RecordFuncInfo(req.Context(), funcInfo)()
- rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
- rPath = util.PathJoinRelX(rPath)
- if rPath == "" || rPath == "." {
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ avatarPath, ok := strings.CutPrefix(req.URL.Path, "/"+prefix+"/")
+ if !ok {
+ http.Error(w, "invalid avatar path", http.StatusBadRequest)
+ return
+ }
+ avatarPath = util.PathJoinRelX(avatarPath)
+ if avatarPath == "" || avatarPath == "." {
+ http.Error(w, "not found", http.StatusNotFound)
return
}
- fi, err := objStore.Stat(rPath)
- if err != nil {
- if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
- log.Warn("Unable to find %s %s", prefix, rPath)
- http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
+ if storageSetting.ServeDirect() {
+ // Old logic: no check for existence by Stat, so old code's "errors.Is(err, os.ErrNotExist)" didn't work.
+ // So in theory, it doesn't work with the non-existing avatar fallback, it just gets the URL and redirects to it.
+ // Checking "stat" requires one more request to the storage, which is inefficient.
+ // Workaround: disable "SERVE_DIRECT". Leave the problem to the future.
+ u, err := objStore.URL(avatarPath, path.Base(avatarPath), req.Method, nil)
+ if handleError(w, req, avatarPath, err) {
return
}
- log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err)
- http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError)
+ http.Redirect(w, req, u.String(), http.StatusTemporaryRedirect)
return
}
- fr, err := objStore.Open(rPath)
- if err != nil {
- log.Error("Error whilst opening %s %s. Error: %v", prefix, rPath, err)
- http.Error(w, fmt.Sprintf("Error whilst opening %s %s", prefix, rPath), http.StatusInternalServerError)
+ fr, err := objStore.Open(avatarPath)
+ if handleError(w, req, avatarPath, err) {
return
}
defer fr.Close()
+ fi, err := fr.Stat()
+ if handleError(w, req, avatarPath, err) {
+ return
+ }
+
httpcache.SetCacheControlInHeader(w.Header(), httpcache.CacheControlForPublicStatic())
- http.ServeContent(w, req, path.Base(rPath), fi.ModTime(), fr)
+ http.ServeContent(w, req, path.Base(avatarPath), fi.ModTime(), fr)
}
}
diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go
index 0eea1e1ff7b..de9b2c8ec17 100644
--- a/routers/web/healthcheck/check.go
+++ b/routers/web/healthcheck/check.go
@@ -72,7 +72,7 @@ type componentStatus struct {
// And keep in mind: this health check should NEVER be used as a "restart" trigger, for example: Docker's "HEALTHCHECK".
// * If Gitea is upgrading and migrating database, there will be a long time before this endpoint starts to return "pass" status.
// In this case, if the checker restarts Gitea just because it doesn't get "pass" status in short time,
-// the instance will just be restarted again and again before the migation finishes and the sitution just goes worse.
+// the instance will just be restarted again and again before the migration finishes and the situation just goes worse.
func Check(w http.ResponseWriter, r *http.Request) {
rsp := response{
Status: pass,
diff --git a/routers/web/misc/misc.go b/routers/web/misc/misc.go
index 59b97c17175..3d2f624263b 100644
--- a/routers/web/misc/misc.go
+++ b/routers/web/misc/misc.go
@@ -6,12 +6,15 @@ package misc
import (
"net/http"
"path"
+ "strconv"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/web/middleware"
+ "code.gitea.io/gitea/services/context"
)
func SSHInfo(rw http.ResponseWriter, req *http.Request) {
@@ -47,3 +50,9 @@ func StaticRedirect(target string) func(w http.ResponseWriter, req *http.Request
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, target), http.StatusMovedPermanently)
}
}
+
+func WebBannerDismiss(ctx *context.Context) {
+ _, rev, _ := setting.Config().Instance.WebBanner.ValueRevision(ctx)
+ middleware.SetSiteCookie(ctx.Resp, middleware.CookieWebBannerDismissed, strconv.Itoa(rev), 48*3600)
+ ctx.JSONOK()
+}
diff --git a/routers/web/misc/webtheme.go b/routers/web/misc/webtheme.go
index 076bdf8fda2..76ddf4b567a 100644
--- a/routers/web/misc/webtheme.go
+++ b/routers/web/misc/webtheme.go
@@ -37,6 +37,6 @@ func WebThemeApply(ctx *context.Context) {
opts := &user_service.UpdateOptions{Theme: optional.Some(themeName)}
_ = user_service.UpdateUser(ctx, ctx.Doer, opts)
} else {
- middleware.SetSiteCookie(ctx.Resp, "gitea_theme", themeName, 0)
+ middleware.SetSiteCookie(ctx.Resp, middleware.CookieTheme, themeName, 0)
}
}
diff --git a/routers/web/org/org.go b/routers/web/org/org.go
index 0540d5c591e..36978ba65bd 100644
--- a/routers/web/org/org.go
+++ b/routers/web/org/org.go
@@ -65,13 +65,13 @@ func CreatePost(ctx *context.Context) {
ctx.Data["Err_OrgName"] = true
switch {
case user_model.IsErrUserAlreadyExist(err):
- ctx.RenderWithErr(ctx.Tr("form.org_name_been_taken"), tplCreateOrg, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.org_name_been_taken"), tplCreateOrg, &form)
case db.IsErrNameReserved(err):
- ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(db.ErrNameReserved).Name), tplCreateOrg, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("org.form.name_reserved", err.(db.ErrNameReserved).Name), tplCreateOrg, &form)
case db.IsErrNamePatternNotAllowed(err):
- ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplCreateOrg, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("org.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tplCreateOrg, &form)
case organization.IsErrUserNotAllowedCreateOrg(err):
- ctx.RenderWithErr(ctx.Tr("org.form.create_org_not_allowed"), tplCreateOrg, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("org.form.create_org_not_allowed"), tplCreateOrg, &form)
default:
ctx.ServerError("CreateOrganization", err)
}
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index 0e4dab8fb68..04baa58b734 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -73,7 +73,7 @@ func SettingsPost(ctx *context.Context) {
if form.Email != "" {
if err := user_service.ReplacePrimaryEmailAddress(ctx, org.AsUser(), form.Email); err != nil {
ctx.Data["Err_Email"] = true
- ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsOptions, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.email_invalid"), tplSettingsOptions, &form)
return
}
}
diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go
index 0ec7cfddc5f..1e22a670320 100644
--- a/routers/web/org/teams.go
+++ b/routers/web/org/teams.go
@@ -359,7 +359,7 @@ func NewTeamPost(ctx *context.Context) {
}
if t.AccessMode < perm.AccessModeAdmin && len(unitPerms) == 0 {
- ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
return
}
@@ -367,7 +367,7 @@ func NewTeamPost(ctx *context.Context) {
ctx.Data["Err_TeamName"] = true
switch {
case org_model.IsErrTeamAlreadyExist(err):
- ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
default:
ctx.ServerError("NewTeam", err)
}
@@ -536,7 +536,7 @@ func EditTeamPost(ctx *context.Context) {
}
if t.AccessMode < perm.AccessModeAdmin && len(unitPerms) == 0 {
- ctx.RenderWithErr(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.team_no_units_error"), tplTeamNew, &form)
return
}
@@ -544,7 +544,7 @@ func EditTeamPost(ctx *context.Context) {
ctx.Data["Err_TeamName"] = true
switch {
case org_model.IsErrTeamAlreadyExist(err):
- ctx.RenderWithErr(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.team_name_been_taken"), tplTeamNew, &form)
default:
ctx.ServerError("UpdateTeam", err)
}
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index 33c1e73aa43..0eaa6cab41b 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -36,8 +36,6 @@ import (
notify_service "code.gitea.io/gitea/services/notify"
"github.com/nektos/act/pkg/model"
- "go.yaml.in/yaml/v4"
- "xorm.io/builder"
)
func getRunIndex(ctx *context_module.Context) int64 {
@@ -53,7 +51,7 @@ func getRunIndex(ctx *context_module.Context) int64 {
func View(ctx *context_module.Context) {
ctx.Data["PageIsActions"] = true
runIndex := getRunIndex(ctx)
- jobIndex := ctx.PathParamInt64("job")
+ jobIndex := ctx.PathParamInt("job")
ctx.Data["RunIndex"] = runIndex
ctx.Data["JobIndex"] = jobIndex
ctx.Data["ActionsURL"] = ctx.Repo.RepoLink + "/actions"
@@ -211,7 +209,7 @@ func getActionsViewArtifacts(ctx context.Context, repoID, runIndex int64) (artif
func ViewPost(ctx *context_module.Context) {
req := web.GetForm(ctx).(*ViewRequest)
runIndex := getRunIndex(ctx)
- jobIndex := ctx.PathParamInt64("job")
+ jobIndex := ctx.PathParamInt("job")
current, jobs := getRunJobs(ctx, runIndex, jobIndex)
if ctx.Written() {
@@ -405,11 +403,8 @@ func convertToViewModel(ctx context.Context, locale translation.Locale, cursors
// If jobIndexStr is a blank string, it means rerun all jobs
func Rerun(ctx *context_module.Context) {
runIndex := getRunIndex(ctx)
- jobIndexStr := ctx.PathParam("job")
- var jobIndex int64
- if jobIndexStr != "" {
- jobIndex, _ = strconv.ParseInt(jobIndexStr, 10, 64)
- }
+ jobIndexHas := ctx.PathParam("job") != ""
+ jobIndex := ctx.PathParamInt("job")
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
if err != nil {
@@ -431,130 +426,29 @@ func Rerun(ctx *context_module.Context) {
return
}
- // reset run's start and stop time
- run.PreviousDuration = run.Duration()
- run.Started = 0
- run.Stopped = 0
- run.Status = actions_model.StatusWaiting
-
- vars, err := actions_model.GetVariablesOfRun(ctx, run)
+ jobs, err := actions_model.GetRunJobsByRunID(ctx, run.ID)
if err != nil {
- ctx.ServerError("GetVariablesOfRun", fmt.Errorf("get run %d variables: %w", run.ID, err))
+ ctx.ServerError("GetRunJobsByRunID", err)
return
}
- if run.RawConcurrency != "" {
- var rawConcurrency model.RawConcurrency
- if err := yaml.Unmarshal([]byte(run.RawConcurrency), &rawConcurrency); err != nil {
- ctx.ServerError("UnmarshalRawConcurrency", fmt.Errorf("unmarshal raw concurrency: %w", err))
- return
- }
-
- err = actions_service.EvaluateRunConcurrencyFillModel(ctx, run, &rawConcurrency, vars, nil)
- if err != nil {
- ctx.ServerError("EvaluateRunConcurrencyFillModel", err)
- return
- }
-
- run.Status, err = actions_service.PrepareToStartRunWithConcurrency(ctx, run)
- if err != nil {
- ctx.ServerError("PrepareToStartRunWithConcurrency", err)
+ var targetJob *actions_model.ActionRunJob // nil means rerun all jobs
+ if jobIndexHas {
+ if jobIndex < 0 || jobIndex >= len(jobs) {
+ ctx.JSONError(ctx.Locale.Tr("error.not_found"))
return
}
+ targetJob = jobs[jobIndex] // only rerun the selected job
}
- if err := actions_model.UpdateRun(ctx, run, "started", "stopped", "previous_duration", "status", "concurrency_group", "concurrency_cancel"); err != nil {
- ctx.ServerError("UpdateRun", err)
+
+ if err := actions_service.RerunWorkflowRunJobs(ctx, ctx.Repo.Repository, run, jobs, targetJob); err != nil {
+ ctx.ServerError("RerunWorkflowRunJobs", err)
return
}
- if err := run.LoadAttributes(ctx); err != nil {
- ctx.ServerError("run.LoadAttributes", err)
- return
- }
- notify_service.WorkflowRunStatusUpdate(ctx, run.Repo, run.TriggerUser, run)
-
- job, jobs := getRunJobs(ctx, runIndex, jobIndex)
- if ctx.Written() {
- return
- }
-
- isRunBlocked := run.Status == actions_model.StatusBlocked
- if jobIndexStr == "" { // rerun all jobs
- for _, j := range jobs {
- // if the job has needs, it should be set to "blocked" status to wait for other jobs
- shouldBlockJob := len(j.Needs) > 0 || isRunBlocked
- if err := rerunJob(ctx, j, shouldBlockJob); err != nil {
- ctx.ServerError("RerunJob", err)
- return
- }
- }
- ctx.JSONOK()
- return
- }
-
- rerunJobs := actions_service.GetAllRerunJobs(job, jobs)
-
- for _, j := range rerunJobs {
- // jobs other than the specified one should be set to "blocked" status
- shouldBlockJob := j.JobID != job.JobID || isRunBlocked
- if err := rerunJob(ctx, j, shouldBlockJob); err != nil {
- ctx.ServerError("RerunJob", err)
- return
- }
- }
-
ctx.JSONOK()
}
-func rerunJob(ctx *context_module.Context, job *actions_model.ActionRunJob, shouldBlock bool) error {
- status := job.Status
- if !status.IsDone() {
- return nil
- }
-
- job.TaskID = 0
- job.Status = util.Iif(shouldBlock, actions_model.StatusBlocked, actions_model.StatusWaiting)
- job.Started = 0
- job.Stopped = 0
-
- job.ConcurrencyGroup = ""
- job.ConcurrencyCancel = false
- job.IsConcurrencyEvaluated = false
- if err := job.LoadRun(ctx); err != nil {
- return err
- }
-
- vars, err := actions_model.GetVariablesOfRun(ctx, job.Run)
- if err != nil {
- return fmt.Errorf("get run %d variables: %w", job.Run.ID, err)
- }
-
- if job.RawConcurrency != "" && !shouldBlock {
- err = actions_service.EvaluateJobConcurrencyFillModel(ctx, job.Run, job, vars, nil)
- if err != nil {
- return fmt.Errorf("evaluate job concurrency: %w", err)
- }
-
- job.Status, err = actions_service.PrepareToStartJobWithConcurrency(ctx, job)
- if err != nil {
- return err
- }
- }
-
- if err := db.WithTx(ctx, func(ctx context.Context) error {
- updateCols := []string{"task_id", "status", "started", "stopped", "concurrency_group", "concurrency_cancel", "is_concurrency_evaluated"}
- _, err := actions_model.UpdateRunJob(ctx, job, builder.Eq{"status": status}, updateCols...)
- return err
- }); err != nil {
- return err
- }
-
- actions_service.CreateCommitStatusForRunJobs(ctx, job.Run, job)
- notify_service.WorkflowJobStatusUpdate(ctx, job.Run.Repo, job.Run.TriggerUser, job, nil)
-
- return nil
-}
-
func Logs(ctx *context_module.Context) {
runIndex := getRunIndex(ctx)
jobIndex := ctx.PathParamInt64("job")
@@ -715,7 +609,7 @@ func Delete(ctx *context_module.Context) {
// getRunJobs gets the jobs of runIndex, and returns jobs[jobIndex], jobs.
// Any error will be written to the ctx.
// It never returns a nil job of an empty jobs, if the jobIndex is out of range, it will be treated as 0.
-func getRunJobs(ctx *context_module.Context, runIndex, jobIndex int64) (*actions_model.ActionRunJob, []*actions_model.ActionRunJob) {
+func getRunJobs(ctx *context_module.Context, runIndex int64, jobIndex int) (*actions_model.ActionRunJob, []*actions_model.ActionRunJob) {
run, err := actions_model.GetRunByIndex(ctx, ctx.Repo.Repository.ID, runIndex)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
@@ -740,7 +634,7 @@ func getRunJobs(ctx *context_module.Context, runIndex, jobIndex int64) (*actions
v.Run = run
}
- if jobIndex >= 0 && jobIndex < int64(len(jobs)) {
+ if jobIndex >= 0 && jobIndex < len(jobs) {
return jobs[jobIndex], jobs
}
return jobs[0], jobs
@@ -936,7 +830,7 @@ func Run(ctx *context_module.Context) {
ctx.ServerError("ref", nil)
return
}
- err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
+ _, err := actions_service.DispatchActionWorkflow(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, workflowID, ref, func(workflowDispatch *model.WorkflowDispatch, inputs map[string]any) error {
for name, config := range workflowDispatch.Inputs {
value := ctx.Req.PostFormValue(name)
if config.Type == "boolean" {
diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go
index a83f0f40ec8..be711afe6dd 100644
--- a/routers/web/repo/attachment.go
+++ b/routers/web/repo/attachment.go
@@ -187,7 +187,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
}
}
- if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+attach.UUID+`"`) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+attach.UUID+`"`, attach.CreatedUnix.AsTimePtr()) {
return
}
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index f5630356004..1d6961f6fc8 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -95,7 +95,7 @@ func DeleteBranchPost(ctx *context.Context) {
defer jsonRedirectBranches(ctx)
branchName := ctx.FormString("name")
- if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName, nil); err != nil {
+ if err := repo_service.DeleteBranch(ctx, ctx.Doer, ctx.Repo.Repository, ctx.Repo.GitRepo, branchName); err != nil {
switch {
case git.IsErrBranchNotExist(err):
log.Debug("DeleteBranch: Can't delete non existing branch '%s'", branchName)
diff --git a/routers/web/repo/download.go b/routers/web/repo/download.go
index 6f394aae27d..9412d2045d4 100644
--- a/routers/web/repo/download.go
+++ b/routers/web/repo/download.go
@@ -20,7 +20,7 @@ import (
// ServeBlobOrLFS download a git.Blob redirecting to LFS if necessary
func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Time) error {
- if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) {
return nil
}
@@ -48,7 +48,7 @@ func ServeBlobOrLFS(ctx *context.Context, blob *git.Blob, lastModified *time.Tim
closed = true
return common.ServeBlob(ctx.Base, ctx.Repo.Repository, ctx.Repo.TreePath, blob, lastModified)
}
- if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`) {
+ if httpcache.HandleGenericETagPrivateCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`, meta.UpdatedUnix.AsTimePtr()) {
return nil
}
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index eaec3b57890..a295a3c9036 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -21,6 +21,7 @@ import (
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/htmlutil"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/optional"
@@ -369,7 +370,7 @@ func UpdateIssueContent(ctx *context.Context) {
}
ctx.JSON(http.StatusOK, map[string]any{
- "content": content,
+ "content": commentContentHTML(ctx, content),
"contentVersion": issue.ContentVersion,
"attachments": attachmentsHTML(ctx, issue.Attachments, issue.Content),
})
@@ -629,6 +630,13 @@ func updateAttachments(ctx *context.Context, item any, files []string) error {
return err
}
+func commentContentHTML(ctx *context.Context, content template.HTML) template.HTML {
+ if strings.TrimSpace(string(content)) == "" {
+ return htmlutil.HTMLFormat(`%s`, ctx.Tr("repo.issues.no_content"))
+ }
+ return content
+}
+
func attachmentsHTML(ctx *context.Context, attachments []*repo_model.Attachment, content string) template.HTML {
attachHTML, err := ctx.RenderToHTML(tplAttachment, map[string]any{
"ctxData": ctx.Data,
diff --git a/routers/web/repo/issue_comment.go b/routers/web/repo/issue_comment.go
index a3cb88e76a6..7f8cc23a3f9 100644
--- a/routers/web/repo/issue_comment.go
+++ b/routers/web/repo/issue_comment.go
@@ -9,7 +9,6 @@ import (
"html/template"
"net/http"
"strconv"
- "strings"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
@@ -17,7 +16,6 @@ import (
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
- "code.gitea.io/gitea/modules/htmlutil"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markup/markdown"
repo_module "code.gitea.io/gitea/modules/repository"
@@ -291,12 +289,8 @@ func UpdateCommentContent(ctx *context.Context) {
}
}
- if strings.TrimSpace(string(renderedContent)) == "" {
- renderedContent = htmlutil.HTMLFormat(`%s`, ctx.Tr("repo.issues.no_content"))
- }
-
ctx.JSON(http.StatusOK, map[string]any{
- "content": renderedContent,
+ "content": commentContentHTML(ctx, renderedContent),
"contentVersion": comment.ContentVersion,
"attachments": attachmentsHTML(ctx, comment.Attachments, comment.Content),
})
diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go
index a56df78163d..23cedfcb80a 100644
--- a/routers/web/repo/issue_content_history.go
+++ b/routers/web/repo/issue_content_history.go
@@ -6,13 +6,14 @@ package repo
import (
"bytes"
"html"
+ "html/template"
"net/http"
"strings"
"code.gitea.io/gitea/models/avatars"
issues_model "code.gitea.io/gitea/models/issues"
+ "code.gitea.io/gitea/modules/htmlutil"
"code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/services/context"
@@ -53,29 +54,25 @@ func GetContentHistoryList(ctx *context.Context) {
// value is historyId
var results []map[string]any
for _, item := range items {
- var actionText string
+ var actionHTML template.HTML
if item.IsDeleted {
- actionTextDeleted := ctx.Locale.TrString("repo.issues.content_history.deleted")
- actionText = "" + actionTextDeleted + ""
+ actionHTML = htmlutil.HTMLFormat(`%s`, ctx.Locale.TrString("repo.issues.content_history.deleted"))
} else if item.IsFirstCreated {
- actionText = ctx.Locale.TrString("repo.issues.content_history.created")
+ actionHTML = ctx.Locale.Tr("repo.issues.content_history.created")
} else {
- actionText = ctx.Locale.TrString("repo.issues.content_history.edited")
+ actionHTML = ctx.Locale.Tr("repo.issues.content_history.edited")
}
- username := item.UserName
- if setting.UI.DefaultShowFullName && strings.TrimSpace(item.UserFullName) != "" {
- username = strings.TrimSpace(item.UserFullName)
+ var fullNameHTML template.HTML
+ userName, fullName := item.UserName, strings.TrimSpace(item.UserFullName)
+ if fullName != "" {
+ fullNameHTML = htmlutil.HTMLFormat(` (%s)`, fullName)
}
- src := html.EscapeString(item.UserAvatarLink)
- class := avatars.DefaultAvatarClass + " tw-mr-2"
- name := html.EscapeString(username)
- avatarHTML := string(templates.AvatarHTML(src, 28, class, username))
- timeSinceHTML := string(templates.TimeSince(item.EditedUnix))
-
+ avatarHTML := templates.AvatarHTML(item.UserAvatarLink, 24, avatars.DefaultAvatarClass+" tw-mr-2", userName)
+ timeSinceHTML := templates.TimeSince(item.EditedUnix)
results = append(results, map[string]any{
- "name": avatarHTML + "" + name + " " + actionText + " " + timeSinceHTML,
+ "name": htmlutil.HTMLFormat("%s %s%s %s %s", avatarHTML, userName, fullNameHTML, actionHTML, timeSinceHTML),
"value": item.HistoryID,
})
}
diff --git a/routers/web/repo/issue_dependency.go b/routers/web/repo/issue_dependency.go
index 73298958c05..bb2dc5b0fdb 100644
--- a/routers/web/repo/issue_dependency.go
+++ b/routers/web/repo/issue_dependency.go
@@ -119,7 +119,7 @@ func RemoveDependency(ctx *context.Context) {
case "blocking":
depType = issues_model.DependencyTypeBlocking
default:
- ctx.HTTPError(http.StatusBadRequest, "GetDependecyType")
+ ctx.HTTPError(http.StatusBadRequest, "GetDependencyType")
return
}
diff --git a/routers/web/repo/issue_poster.go b/routers/web/repo/issue_poster.go
index 07059b9b7bf..4f00f40a91f 100644
--- a/routers/web/repo/issue_poster.go
+++ b/routers/web/repo/issue_poster.go
@@ -10,7 +10,6 @@ import (
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/setting"
shared_user "code.gitea.io/gitea/routers/web/shared/user"
"code.gitea.io/gitea/services/context"
)
@@ -34,7 +33,7 @@ func IssuePullPosters(ctx *context.Context) {
func issuePosters(ctx *context.Context, isPullList bool) {
repo := ctx.Repo.Repository
search := strings.TrimSpace(ctx.FormString("q"))
- posters, err := repo_model.GetIssuePostersWithSearch(ctx, repo, isPullList, search, setting.UI.DefaultShowFullName)
+ posters, err := repo_model.GetIssuePostersWithSearch(ctx, repo, isPullList, search)
if err != nil {
ctx.JSON(http.StatusInternalServerError, err)
return
@@ -54,9 +53,7 @@ func issuePosters(ctx *context.Context, isPullList bool) {
resp.Results = make([]*userSearchInfo, len(posters))
for i, user := range posters {
resp.Results[i] = &userSearchInfo{UserID: user.ID, UserName: user.Name, AvatarLink: user.AvatarLink(ctx)}
- if setting.UI.DefaultShowFullName {
- resp.Results[i].FullName = user.FullName
- }
+ resp.Results[i].FullName = user.FullName
}
ctx.JSON(http.StatusOK, resp)
}
diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go
index 1354c2d6f9b..2cd8be45332 100644
--- a/routers/web/repo/issue_view.go
+++ b/routers/web/repo/issue_view.go
@@ -905,9 +905,8 @@ func preparePullViewReviewAndMerge(ctx *context.Context, issue *issues_model.Iss
// Check correct values and select default
if ms, ok := ctx.Data["MergeStyle"].(repo_model.MergeStyle); !ok ||
!prConfig.IsMergeStyleAllowed(ms) {
- defaultMergeStyle := prConfig.GetDefaultMergeStyle()
- if prConfig.IsMergeStyleAllowed(defaultMergeStyle) && !ok {
- mergeStyle = defaultMergeStyle
+ if prConfig.IsMergeStyleAllowed(prConfig.DefaultMergeStyle) && !ok {
+ mergeStyle = prConfig.DefaultMergeStyle
} else if prConfig.AllowMerge {
mergeStyle = repo_model.MergeStyleMerge
} else if prConfig.AllowRebase {
diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go
index 8f4adb2ad22..bb6f1e6b7eb 100644
--- a/routers/web/repo/migrate.go
+++ b/routers/web/repo/migrate.go
@@ -79,44 +79,44 @@ func handleMigrateError(ctx *context.Context, owner *user_model.User, err error,
switch {
case migrations.IsRateLimitError(err):
- ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.visit_rate_limit"), tpl, form)
case migrations.IsTwoFactorAuthError(err):
- ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.2fa_auth_required"), tpl, form)
case repo_model.IsErrReachLimitOfRepo(err):
maxCreationLimit := owner.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
- ctx.RenderWithErr(msg, tpl, form)
+ ctx.RenderWithErrDeprecated(msg, tpl, form)
case repo_model.IsErrRepoAlreadyExist(err):
ctx.Data["Err_RepoName"] = true
- ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repo_name_been_taken"), tpl, form)
case repo_model.IsErrRepoFilesAlreadyExist(err):
ctx.Data["Err_RepoName"] = true
switch {
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tpl, form)
case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist.adopt"), tpl, form)
case setting.Repository.AllowDeleteOfUnadoptedRepositories:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist.delete"), tpl, form)
default:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist"), tpl, form)
}
case db.IsErrNameReserved(err):
ctx.Data["Err_RepoName"] = true
- ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
case db.IsErrNamePatternNotAllowed(err):
ctx.Data["Err_RepoName"] = true
- ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
default:
err = util.SanitizeErrorCredentialURLs(err)
if strings.Contains(err.Error(), "Authentication failed") ||
strings.Contains(err.Error(), "Bad credentials") ||
strings.Contains(err.Error(), "could not read Username") {
ctx.Data["Err_Auth"] = true
- ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.auth_failed", err.Error()), tpl, form)
} else if strings.Contains(err.Error(), "fatal:") {
ctx.Data["Err_CloneAddr"] = true
- ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form)
} else {
ctx.ServerError(name, err)
}
@@ -128,24 +128,24 @@ func handleMigrateRemoteAddrError(ctx *context.Context, err error, tpl templates
addrErr := err.(*git.ErrInvalidCloneAddr)
switch {
case addrErr.IsProtocolInvalid:
- ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.mirror_address_protocol_invalid"), tpl, form)
case addrErr.IsURLError:
- ctx.RenderWithErr(ctx.Tr("form.url_error", addrErr.Host), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.url_error", addrErr.Host), tpl, form)
case addrErr.IsPermissionDenied:
if addrErr.LocalPath {
- ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.migrate.permission_denied"), tpl, form)
} else {
- ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied_blocked"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.migrate.permission_denied_blocked"), tpl, form)
}
case addrErr.IsInvalidPath:
- ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.migrate.invalid_local_path"), tpl, form)
default:
log.Error("Error whilst updating url: %v", err)
- ctx.RenderWithErr(ctx.Tr("form.url_error", "unknown"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.url_error", "unknown"), tpl, form)
}
} else {
log.Error("Error whilst updating url: %v", err)
- ctx.RenderWithErr(ctx.Tr("form.url_error", "unknown"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.url_error", "unknown"), tpl, form)
}
}
@@ -193,7 +193,7 @@ func MigratePost(ctx *context.Context) {
ep := lfs.DetermineEndpoint("", form.LFSEndpoint)
if ep == nil {
ctx.Data["Err_LFSEndpoint"] = true
- ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tpl, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.migrate.invalid_lfs_endpoint"), tpl, &form)
return
}
err = migrations.IsMigrateURLAllowed(ep.String(), ctx.Doer)
diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go
index dd53b1d3f10..09196d4bc20 100644
--- a/routers/web/repo/milestone.go
+++ b/routers/web/repo/milestone.go
@@ -118,7 +118,7 @@ func NewMilestonePost(ctx *context.Context) {
deadlineUnix, err := common.ParseDeadlineDateToEndOfDay(form.Deadline)
if err != nil {
ctx.Data["Err_Deadline"] = true
- ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
return
}
@@ -174,7 +174,7 @@ func EditMilestonePost(ctx *context.Context) {
deadlineUnix, err := common.ParseDeadlineDateToEndOfDay(form.Deadline)
if err != nil {
ctx.Data["Err_Deadline"] = true
- ctx.RenderWithErr(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.milestones.invalid_due_date_format"), tplMilestoneNew, &form)
return
}
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 1b36dc4d442..891af4c2d5c 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -452,13 +452,13 @@ func NewReleasePost(ctx *context.Context) {
}
if exist, _ := git_model.IsBranchExist(ctx, ctx.Repo.Repository.ID, form.Target); !exist {
- ctx.RenderWithErr(ctx.Tr("form.target_branch_not_exist"), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.target_branch_not_exist"), tplReleaseNew, &form)
return
}
if !form.TagOnly && form.Title == "" {
// if not "tag only", then the title of the release cannot be empty
- ctx.RenderWithErr(ctx.Tr("repo.release.title_empty"), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.release.title_empty"), tplReleaseNew, &form)
return
}
@@ -466,13 +466,13 @@ func NewReleasePost(ctx *context.Context) {
ctx.Data["Err_TagName"] = true
switch {
case release_service.IsErrTagAlreadyExists(err):
- ctx.RenderWithErr(ctx.Tr("repo.branch.tag_collision", form.TagName), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.branch.tag_collision", form.TagName), tplReleaseNew, &form)
case repo_model.IsErrReleaseAlreadyExist(err):
- ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
case release_service.IsErrInvalidTagName(err):
- ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.release.tag_name_invalid"), tplReleaseNew, &form)
case release_service.IsErrProtectedTagName(err):
- ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_protected"), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.release.tag_name_protected"), tplReleaseNew, &form)
default:
ctx.ServerError("handleTagReleaseError", err)
}
@@ -525,7 +525,7 @@ func NewReleasePost(ctx *context.Context) {
// add new logic: if tag-only, do not convert the tag to a release
if form.TagOnly || !rel.IsTag {
ctx.Data["Err_TagName"] = true
- ctx.RenderWithErr(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.release.tag_name_already_exist"), tplReleaseNew, &form)
return
}
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index bc2b0264c0a..57937be83e2 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -186,28 +186,28 @@ func handleCreateError(ctx *context.Context, owner *user_model.User, err error,
case repo_model.IsErrReachLimitOfRepo(err):
maxCreationLimit := owner.MaxCreationLimit()
msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit)
- ctx.RenderWithErr(msg, tpl, form)
+ ctx.RenderWithErrDeprecated(msg, tpl, form)
case repo_model.IsErrRepoAlreadyExist(err):
ctx.Data["Err_RepoName"] = true
- ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repo_name_been_taken"), tpl, form)
case repo_model.IsErrRepoFilesAlreadyExist(err):
ctx.Data["Err_RepoName"] = true
switch {
case ctx.IsUserSiteAdmin() || (setting.Repository.AllowAdoptionOfUnadoptedRepositories && setting.Repository.AllowDeleteOfUnadoptedRepositories):
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist.adopt_or_delete"), tpl, form)
case setting.Repository.AllowAdoptionOfUnadoptedRepositories:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.adopt"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist.adopt"), tpl, form)
case setting.Repository.AllowDeleteOfUnadoptedRepositories:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist.delete"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist.delete"), tpl, form)
default:
- ctx.RenderWithErr(ctx.Tr("form.repository_files_already_exist"), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("form.repository_files_already_exist"), tpl, form)
}
case db.IsErrNameReserved(err):
ctx.Data["Err_RepoName"] = true
- ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_reserved", err.(db.ErrNameReserved).Name), tpl, form)
case db.IsErrNamePatternNotAllowed(err):
ctx.Data["Err_RepoName"] = true
- ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.form.name_pattern_not_allowed", err.(db.ErrNamePatternNotAllowed).Pattern), tpl, form)
default:
ctx.ServerError(name, err)
}
@@ -254,7 +254,7 @@ func CreatePost(ctx *context.Context) {
}
if !opts.IsValid() {
- ctx.RenderWithErr(ctx.Tr("repo.template.one_item"), tplCreate, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.template.one_item"), tplCreate, form)
return
}
@@ -264,7 +264,7 @@ func CreatePost(ctx *context.Context) {
}
if !templateRepo.IsTemplate {
- ctx.RenderWithErr(ctx.Tr("repo.template.invalid"), tplCreate, form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.template.invalid"), tplCreate, form)
return
}
@@ -526,9 +526,9 @@ func SearchRepo(ctx *context.Context) {
ctx.SetTotalCountHeader(count)
- latestCommitStatuses, err := commitstatus_service.FindReposLastestCommitStatuses(ctx, repos)
+ latestCommitStatuses, err := commitstatus_service.FindReposLatestCommitStatuses(ctx, repos)
if err != nil {
- log.Error("FindReposLastestCommitStatuses: %v", err)
+ log.Error("FindReposLatestCommitStatuses: %v", err)
ctx.JSON(http.StatusInternalServerError, nil)
return
}
diff --git a/routers/web/repo/setting/collaboration.go b/routers/web/repo/setting/collaboration.go
index df7cc5e39b6..dbfd6e08b61 100644
--- a/routers/web/repo/setting/collaboration.go
+++ b/routers/web/repo/setting/collaboration.go
@@ -208,7 +208,7 @@ func DeleteTeam(ctx *context.Context) {
}
if err = repo_service.RemoveRepositoryFromTeam(ctx, team, ctx.Repo.Repository.ID); err != nil {
- ctx.ServerError("team.RemoveRepositorys", err)
+ ctx.ServerError("team.RemoveRepositories", err)
return
}
diff --git a/routers/web/repo/setting/deploy_key.go b/routers/web/repo/setting/deploy_key.go
index 193562528bf..ab54b8ccf5a 100644
--- a/routers/web/repo/setting/deploy_key.go
+++ b/routers/web/repo/setting/deploy_key.go
@@ -76,16 +76,16 @@ func DeployKeysPost(ctx *context.Context) {
switch {
case asymkey_model.IsErrDeployKeyAlreadyExist(err):
ctx.Data["Err_Content"] = true
- ctx.RenderWithErr(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.key_been_used"), tplDeployKeys, &form)
case asymkey_model.IsErrKeyAlreadyExist(err):
ctx.Data["Err_Content"] = true
- ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplDeployKeys, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("settings.ssh_key_been_used"), tplDeployKeys, &form)
case asymkey_model.IsErrKeyNameAlreadyUsed(err):
ctx.Data["Err_Title"] = true
- ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
case asymkey_model.IsErrDeployKeyNameAlreadyUsed(err):
ctx.Data["Err_Title"] = true
- ctx.RenderWithErr(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
+ ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.key_name_used"), tplDeployKeys, &form)
default:
ctx.ServerError("AddDeployKey", err)
}
diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go
index 8a8015035f4..a3a60963d43 100644
--- a/routers/web/repo/setting/lfs.go
+++ b/routers/web/repo/setting/lfs.go
@@ -301,13 +301,13 @@ func LFSFileGet(ctx *context.Context) {
if index != len(lines)-1 {
line += "\n"
}
- output.WriteString(fmt.Sprintf(`