diff --git a/.deadcode-out b/.deadcode-out
index e63e4a3dc3..61c5bcb055 100644
--- a/.deadcode-out
+++ b/.deadcode-out
@@ -13,6 +13,13 @@ forgejo.org/models
IsErrSHANotFound
IsErrMergeDivergingFastForwardOnly
+forgejo.org/models/activities
+ GetActivityByID
+ NewFederatedUserActivity
+ CreateUserActivity
+ GetFollowingFeeds
+ FederatedUserActivity.loadActor
+
forgejo.org/models/auth
WebAuthnCredentials
@@ -54,9 +61,17 @@ forgejo.org/models/user
IsErrExternalLoginUserAlreadyExist
IsErrExternalLoginUserNotExist
NewFederatedUser
+ NewFederatedUserFollower
IsErrUserSettingIsNotExist
GetUserAllSettings
DeleteUserSetting
+ GetFederatedUser
+ GetFederatedUserByUserID
+ UpdateFederatedUser
+ GetFollowersForUser
+ AddFollower
+ RemoveFollower
+ IsFollowingAp
forgejo.org/modules/activitypub
NewContext
diff --git a/.dockerignore b/.dockerignore
index 5e7a893014..807c70b000 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -37,13 +37,9 @@ coverage.all
coverage/
cpu.out
-/modules/migration/bindata.go
/modules/migration/bindata.go.hash
-/modules/options/bindata.go
/modules/options/bindata.go.hash
-/modules/public/bindata.go
/modules/public/bindata.go.hash
-/modules/templates/bindata.go
/modules/templates/bindata.go.hash
*.db
diff --git a/.forgejo/issue_template/bug-report-ui.yaml b/.forgejo/issue_template/bug-report-ui.yaml
index 57d578b232..8bb7bf1d49 100644
--- a/.forgejo/issue_template/bug-report-ui.yaml
+++ b/.forgejo/issue_template/bug-report-ui.yaml
@@ -6,7 +6,7 @@ body:
- type: markdown
attributes:
value: |
- **NOTE: If your issue is a security concern, please email email@domain..com
Enter an absolute path if you run Forgejo as a service.")))
assert.Empty(t, checkLocaleContent([]byte("hi_user_x = Hi %s,")))
+ assert.Empty(t, checkLocaleContent([]byte("key = Press Shift")))
assert.Equal(t, []string{"error404: The page you are trying to reach either does not exist or you are not authorized to view it."}, checkLocaleContent([]byte("error404 = The page you are trying to reach either does not exist or you are not authorized to view it.")))
})
diff --git a/contrib/environment-to-ini/README b/contrib/environment-to-ini/README
index f1d3f2ae83..e4caf25666 100644
--- a/contrib/environment-to-ini/README
+++ b/contrib/environment-to-ini/README
@@ -1,45 +1,46 @@
Environment To Ini
==================
-Multiple docker users have requested that the Gitea docker is changed
-to permit arbitrary configuration via environment variables.
+This tool allows defining Forgejo's entire configuration via environment
+variables, mostly geared towards usage in Docker.
-Gitea needs to use an ini file for configuration because the running
-environment that starts the docker may not be the same as that used
-by the hooks. An ini file also gives a good default and means that
-users do not have to completely provide a full environment.
+Forgejo needs to use an INI file for configuration because the running
+environment that starts the container may not be the same as the one used
+by the hooks. An INI file also gives a good default and means that
+users do not have to provide the entire set of environment variables.
With those caveats above, this command provides a generic way of
converting suitably structured environment variables into any ini
value.
-To use the command is very simple just run it and the default gitea
-app.ini will be rewritten to take account of the variables provided,
-however there are various options to give slightly different
-behavior and these can be interrogated with the `-h` option.
+When run, `environment-to-ini` will write the config files based on the
+environment variables provided.
+Check with the `-h` flag for several options to alter this behaviour.
-The environment variables should be of the form:
+Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME"
+will be mapped to the ini section "[section_name]" and the key
+"KEY_NAME" with the value as provided.
- GITEA__SECTION_NAME__KEY_NAME
-
-Note, SECTION_NAME in the notation above is case-insensitive.
+Environment variables of the form "FORGEJO__SECTION_NAME__KEY_NAME__FILE"
+will be mapped to the ini section "[section_name]" and the key
+"KEY_NAME" with the value loaded from the specified file.
Environment variables are usually restricted to a reduced character
set "0-9A-Z_" - in order to allow the setting of sections with
characters outside of that set, they should be escaped as following:
-"_0X2E_" for "." and "_0X2D_" for "-". The entire section and key names
-can be escaped as a UTF8 byte string if necessary. E.g. to configure:
+"_0X2E_" for ".". The entire section and key names can be escaped as
+a UTF8 byte string if necessary. E.g. to configure:
- """
- ...
- [log.console]
- COLORIZE=false
- STDERR=true
- ...
- """
+ """
+ ...
+ [log.console]
+ COLORIZE=false
+ STDERR=true
+ ...
+ """
-You would set the environment variables: "GITEA__LOG_0x2E_CONSOLE__COLORIZE=false"
-and "GITEA__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
+You would set the environment variables: "FORGEJO__LOG_0x2E_CONSOLE__COLORIZE=false"
+and "FORGEJO__LOG_0x2E_CONSOLE__STDERR=false". Other examples can be found
on the configuration cheat sheet.
To build locally, run:
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 5737bed623..28cfa80089 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -1,5 +1,5 @@
import eslintCommunityEslintPluginEslintComments from '@eslint-community/eslint-plugin-eslint-comments';
-import stylisticEslintPluginJs from '@stylistic/eslint-plugin-js';
+import stylisticEslintPlugin from '@stylistic/eslint-plugin';
import vitest from '@vitest/eslint-plugin';
import arrayFunc from 'eslint-plugin-array-func';
import eslintPluginImportX from 'eslint-plugin-import-x';
@@ -26,7 +26,7 @@ export default tseslint.config(
{
plugins: {
'@eslint-community/eslint-comments': eslintCommunityEslintPluginEslintComments,
- '@stylistic/js': stylisticEslintPluginJs,
+ '@stylistic': stylisticEslintPlugin,
'@vitest': vitest,
'array-func': arrayFunc,
'no-jquery': noJquery,
@@ -69,62 +69,62 @@ export default tseslint.config(
'@eslint-community/eslint-comments/no-unused-enable': [2],
'@eslint-community/eslint-comments/no-use': [0],
'@eslint-community/eslint-comments/require-description': [0],
- '@stylistic/js/array-bracket-newline': [0],
- '@stylistic/js/array-bracket-spacing': [2, 'never'],
- '@stylistic/js/array-element-newline': [0],
- '@stylistic/js/arrow-parens': [2, 'always'],
+ '@stylistic/array-bracket-newline': [0],
+ '@stylistic/array-bracket-spacing': [2, 'never'],
+ '@stylistic/array-element-newline': [0],
+ '@stylistic/arrow-parens': [2, 'always'],
- '@stylistic/js/arrow-spacing': [2, {
+ '@stylistic/arrow-spacing': [2, {
before: true,
after: true,
}],
- '@stylistic/js/block-spacing': [0],
+ '@stylistic/block-spacing': [0],
- '@stylistic/js/brace-style': [2, '1tbs', {
+ '@stylistic/brace-style': [2, '1tbs', {
allowSingleLine: true,
}],
- '@stylistic/js/comma-dangle': [2, 'always-multiline'],
+ '@stylistic/comma-dangle': [2, 'always-multiline'],
- '@stylistic/js/comma-spacing': [2, {
+ '@stylistic/comma-spacing': [2, {
before: false,
after: true,
}],
- '@stylistic/js/comma-style': [2, 'last'],
- '@stylistic/js/computed-property-spacing': [2, 'never'],
- '@stylistic/js/dot-location': [2, 'property'],
- '@stylistic/js/eol-last': [2],
- '@stylistic/js/function-call-spacing': [2, 'never'],
- '@stylistic/js/function-call-argument-newline': [0],
- '@stylistic/js/function-paren-newline': [0],
- '@stylistic/js/generator-star-spacing': [0],
- '@stylistic/js/implicit-arrow-linebreak': [0],
+ '@stylistic/comma-style': [2, 'last'],
+ '@stylistic/computed-property-spacing': [2, 'never'],
+ '@stylistic/dot-location': [2, 'property'],
+ '@stylistic/eol-last': [2],
+ '@stylistic/function-call-spacing': [2, 'never'],
+ '@stylistic/function-call-argument-newline': [0],
+ '@stylistic/function-paren-newline': [0],
+ '@stylistic/generator-star-spacing': [0],
+ '@stylistic/implicit-arrow-linebreak': [0],
- '@stylistic/js/indent': [2, 2, {
+ '@stylistic/indent': [2, 2, {
ignoreComments: true,
SwitchCase: 1,
}],
- '@stylistic/js/key-spacing': [2],
- '@stylistic/js/keyword-spacing': [2],
- '@stylistic/js/linebreak-style': [2, 'unix'],
- '@stylistic/js/lines-around-comment': [0],
- '@stylistic/js/lines-between-class-members': [0],
- '@stylistic/js/max-len': [0],
- '@stylistic/js/max-statements-per-line': [0],
- '@stylistic/js/multiline-ternary': [0],
- '@stylistic/js/new-parens': [2],
- '@stylistic/js/newline-per-chained-call': [0],
- '@stylistic/js/no-confusing-arrow': [0],
- '@stylistic/js/no-extra-parens': [0],
- '@stylistic/js/no-extra-semi': [2],
- '@stylistic/js/no-floating-decimal': [0],
- '@stylistic/js/no-mixed-operators': [0],
- '@stylistic/js/no-mixed-spaces-and-tabs': [2],
+ '@stylistic/key-spacing': [2],
+ '@stylistic/keyword-spacing': [2],
+ '@stylistic/linebreak-style': [2, 'unix'],
+ '@stylistic/lines-around-comment': [0],
+ '@stylistic/lines-between-class-members': [0],
+ '@stylistic/max-len': [0],
+ '@stylistic/max-statements-per-line': [0],
+ '@stylistic/multiline-ternary': [0],
+ '@stylistic/new-parens': [2],
+ '@stylistic/newline-per-chained-call': [0],
+ '@stylistic/no-confusing-arrow': [0],
+ '@stylistic/no-extra-parens': [0],
+ '@stylistic/no-extra-semi': [2],
+ '@stylistic/no-floating-decimal': [0],
+ '@stylistic/no-mixed-operators': [0],
+ '@stylistic/no-mixed-spaces-and-tabs': [2],
- '@stylistic/js/no-multi-spaces': [2, {
+ '@stylistic/no-multi-spaces': [2, {
ignoreEOLComments: true,
exceptions: {
@@ -132,60 +132,60 @@ export default tseslint.config(
},
}],
- '@stylistic/js/no-multiple-empty-lines': [2, {
+ '@stylistic/no-multiple-empty-lines': [2, {
max: 1,
maxEOF: 0,
maxBOF: 0,
}],
- '@stylistic/js/no-tabs': [2],
- '@stylistic/js/no-trailing-spaces': [2],
- '@stylistic/js/no-whitespace-before-property': [2],
- '@stylistic/js/nonblock-statement-body-position': [2],
- '@stylistic/js/object-curly-newline': [0],
- '@stylistic/js/object-curly-spacing': [2, 'never'],
- '@stylistic/js/object-property-newline': [0],
- '@stylistic/js/one-var-declaration-per-line': [0],
- '@stylistic/js/operator-linebreak': [2, 'after'],
- '@stylistic/js/padded-blocks': [2, 'never'],
- '@stylistic/js/padding-line-between-statements': [0],
- '@stylistic/js/quote-props': [0],
+ '@stylistic/no-tabs': [2],
+ '@stylistic/no-trailing-spaces': [2],
+ '@stylistic/no-whitespace-before-property': [2],
+ '@stylistic/nonblock-statement-body-position': [2],
+ '@stylistic/object-curly-newline': [0],
+ '@stylistic/object-curly-spacing': [2, 'never'],
+ '@stylistic/object-property-newline': [0],
+ '@stylistic/one-var-declaration-per-line': [0],
+ '@stylistic/operator-linebreak': [2, 'after'],
+ '@stylistic/padded-blocks': [2, 'never'],
+ '@stylistic/padding-line-between-statements': [0],
+ '@stylistic/quote-props': [0],
- '@stylistic/js/quotes': [2, 'single', {
+ '@stylistic/quotes': [2, 'single', {
avoidEscape: true,
allowTemplateLiterals: true,
}],
- '@stylistic/js/rest-spread-spacing': [2, 'never'],
+ '@stylistic/rest-spread-spacing': [2, 'never'],
- '@stylistic/js/semi': [2, 'always', {
+ '@stylistic/semi': [2, 'always', {
omitLastInOneLineBlock: true,
}],
- '@stylistic/js/semi-spacing': [2, {
+ '@stylistic/semi-spacing': [2, {
before: false,
after: true,
}],
- '@stylistic/js/semi-style': [2, 'last'],
- '@stylistic/js/space-before-blocks': [2, 'always'],
+ '@stylistic/semi-style': [2, 'last'],
+ '@stylistic/space-before-blocks': [2, 'always'],
- '@stylistic/js/space-before-function-paren': [2, {
+ '@stylistic/space-before-function-paren': [2, {
anonymous: 'ignore',
named: 'never',
asyncArrow: 'always',
}],
- '@stylistic/js/space-in-parens': [2, 'never'],
- '@stylistic/js/space-infix-ops': [2],
- '@stylistic/js/space-unary-ops': [2],
- '@stylistic/js/spaced-comment': [2, 'always'],
- '@stylistic/js/switch-colon-spacing': [2],
- '@stylistic/js/template-curly-spacing': [2, 'never'],
- '@stylistic/js/template-tag-spacing': [2, 'never'],
- '@stylistic/js/wrap-iife': [2, 'inside'],
- '@stylistic/js/wrap-regex': [0],
- '@stylistic/js/yield-star-spacing': [2, 'after'],
+ '@stylistic/space-in-parens': [2, 'never'],
+ '@stylistic/space-infix-ops': [2],
+ '@stylistic/space-unary-ops': [2],
+ '@stylistic/spaced-comment': [2, 'always'],
+ '@stylistic/switch-colon-spacing': [2],
+ '@stylistic/template-curly-spacing': [2, 'never'],
+ '@stylistic/template-tag-spacing': [2, 'never'],
+ '@stylistic/wrap-iife': [2, 'inside'],
+ '@stylistic/wrap-regex': [0],
+ '@stylistic/yield-star-spacing': [2, 'after'],
'accessor-pairs': [2],
'array-callback-return': [2, {
diff --git a/go.mod b/go.mod
index 0f47839420..510ec9c3ae 100644
--- a/go.mod
+++ b/go.mod
@@ -41,14 +41,14 @@ require (
github.com/gliderlabs/ssh v0.3.8
github.com/go-ap/activitypub v0.0.0-20231114162308-e219254dc5c9
github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73
- github.com/go-chi/chi/v5 v5.2.1
+ github.com/go-chi/chi/v5 v5.2.2
github.com/go-chi/cors v1.2.1
github.com/go-co-op/gocron v1.37.0
github.com/go-enry/go-enry/v2 v2.9.2
github.com/go-git/go-git/v5 v5.13.2
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-openapi/spec v0.21.0
- github.com/go-sql-driver/mysql v1.9.2
+ github.com/go-sql-driver/mysql v1.9.3
github.com/go-webauthn/webauthn v0.13.0
github.com/gobwas/glob v0.2.3
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
@@ -63,8 +63,8 @@ require (
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/huandu/xstrings v1.5.0
- github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056
- github.com/jhillyerd/enmime/v2 v2.1.0
+ github.com/inbucket/html2text v0.9.0
+ github.com/jhillyerd/enmime/v2 v2.2.0
github.com/json-iterator/go v1.1.12
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/klauspost/compress v1.18.0
@@ -76,7 +76,7 @@ require (
github.com/meilisearch/meilisearch-go v0.31.0
github.com/mholt/archiver/v3 v3.5.1
github.com/microcosm-cc/bluemonday v1.0.27
- github.com/minio/minio-go/v7 v7.0.93
+ github.com/minio/minio-go/v7 v7.0.94
github.com/msteinert/pam/v2 v2.1.0
github.com/nektos/act v0.2.52
github.com/niklasfasching/go-org v1.8.0
@@ -92,7 +92,6 @@ require (
github.com/stretchr/testify v1.10.0
github.com/syndtr/goleveldb v1.0.0
github.com/ulikunitz/xz v0.5.12
- github.com/urfave/cli/v2 v2.27.6
github.com/urfave/cli/v3 v3.3.3
github.com/valyala/fastjson v1.6.4
github.com/yohcop/openid-go v1.0.1
@@ -152,7 +151,6 @@ require (
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/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/davidmz/go-pageant v1.0.2 // indirect
@@ -160,7 +158,7 @@ require (
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
- github.com/fatih/color v1.16.0 // indirect
+ github.com/fatih/color v1.18.0 // indirect
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
github.com/go-ap/errors v0.0.0-20231003111023-183eef4b31b7 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
@@ -194,7 +192,7 @@ require (
github.com/libdns/libdns v1.0.0-beta.1 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/markbates/going v1.0.3 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mholt/acmez/v3 v3.1.2 // indirect
github.com/miekg/dns v1.1.63 // indirect
@@ -207,7 +205,9 @@ require (
github.com/mschoch/smat v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
- github.com/olekukonko/tablewriter v0.0.5 // indirect
+ github.com/olekukonko/errors v1.1.0 // indirect
+ github.com/olekukonko/ll v0.0.9 // indirect
+ github.com/olekukonko/tablewriter v1.0.7 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
@@ -221,7 +221,6 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/rs/xid v1.6.0 // indirect
- github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
@@ -229,7 +228,6 @@ require (
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
- github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/zeebo/assert v1.3.0 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.etcd.io/bbolt v1.4.0 // indirect
@@ -246,7 +244,7 @@ require (
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
-replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.26.0
+replace github.com/nektos/act => code.forgejo.org/forgejo/act v1.28.0
replace github.com/mholt/archiver/v3 => code.forgejo.org/forgejo/archiver/v3 v3.5.1
diff --git a/go.sum b/go.sum
index 9a93fa8359..53558fddd7 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,8 @@ code.forgejo.org/f3/gof3/v3 v3.11.0 h1:f/xToKwqTgxG6PYxvewywjDQyCcyHEEJ6sZqUitFs
code.forgejo.org/f3/gof3/v3 v3.11.0/go.mod h1:4FaRUNSQGBiD1M0DuB0yNv+Z2wMtlOeckgygHSSq4KQ=
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251 h1:HTZl3CBk3ABNYtFI6TPLvJgGKFIhKT5CBk0sbOtkDKU=
code.forgejo.org/forgejo-contrib/go-libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:PphB88CPbx601QrWPMZATeorACeVmQlyv3u+uUMbSaM=
-code.forgejo.org/forgejo/act v1.26.0 h1:6mTmoaw7d/WpYiw/Pw6AaypxFdgJog5OFi/PMEgEbxs=
-code.forgejo.org/forgejo/act v1.26.0/go.mod h1:HFDFrXPrqfM9aH2RCnMiBdo/3ThxDmZjp58InPjGOfo=
+code.forgejo.org/forgejo/act v1.28.0 h1:96njNC7C1YNyjWq5OWvLZMF/nw0PMthzIA8Nwbnn7jo=
+code.forgejo.org/forgejo/act v1.28.0/go.mod h1:dFuiwAmD5vyrzecysHB2kL/GM3wRpoVPl+WdbCTC8Bs=
code.forgejo.org/forgejo/archiver/v3 v3.5.1 h1:UmmbA7D5550uf71SQjarmrn6yKwOGxtEjb3jaYYtmSE=
code.forgejo.org/forgejo/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
code.forgejo.org/forgejo/go-rpmutils v1.0.0 h1:RZGGeKt70p/WaIEL97pyT6uiiEIoN8/aLmS5Z6WmX0M=
@@ -152,8 +152,6 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
-github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
-github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
@@ -194,8 +192,8 @@ github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTe
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
-github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
-github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
+github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
@@ -215,8 +213,8 @@ github.com/go-ap/jsonld v0.0.0-20221030091449-f2a191312c73/go.mod h1:jyveZeGw5La
github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
-github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
+github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618=
+github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0=
@@ -247,8 +245,8 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
-github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
-github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
+github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
+github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
@@ -343,12 +341,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
-github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 h1:iCHtR9CQyktQ5+f3dMVZfwD2KWJUgm7M0gdL9NGr8KA=
-github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
+github.com/inbucket/html2text v0.9.0 h1:ULJmVcBEMAcmLE+/rN815KG1Fx6+a4HhbUxiDiN+qks=
+github.com/inbucket/html2text v0.9.0/go.mod h1:QDaumzl+/OzlSVbNohhmg+yAy5pKjUjzCKW2BMvztKE=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/jhillyerd/enmime/v2 v2.1.0 h1:c8Qwi5Xq5EdtMN6byQWoZ/8I2RMTo6OJ7Xay+s1oPO0=
-github.com/jhillyerd/enmime/v2 v2.1.0/go.mod h1:EJ74dcRbBcqHSP2TBu08XRoy6y3Yx0cevwb1YkGMEmQ=
+github.com/jhillyerd/enmime/v2 v2.2.0 h1:Pe35MB96eZK5Q0XjlvPftOgWypQpd1gcbfJKAt7rsB8=
+github.com/jhillyerd/enmime/v2 v2.2.0/go.mod h1:SOBXlCemjhiV2DvHhAKnJiWrtJGS/Ffuw4Iy7NjBTaI=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@@ -391,12 +389,10 @@ github.com/markbates/going v1.0.3 h1:mY45T5TvW+Xz5A6jY7lf4+NLg9D8+iuStIHyR7M8qsE
github.com/markbates/going v1.0.3/go.mod h1:fQiT6v6yQar9UD6bd/D4Z5Afbk9J6BBVBtLiyY4gp2o=
github.com/markbates/goth v1.80.0 h1:NnvatczZDzOs1hn9Ug+dVYf2Viwwkp/ZDX5K+GLjan8=
github.com/markbates/goth v1.80.0/go.mod h1:4/GYHo+W6NWisrMPZnq0Yr2Q70UntNLn7KXEFhrIdAY=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.28 h1:ThEiQrnbtumT+QMknw63Befp/ce/nUPgBPMlRFEum7A=
@@ -413,8 +409,8 @@ github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
-github.com/minio/minio-go/v7 v7.0.93 h1:lAB4QJp8Nq3vDMOU0eKgMuyBiEGMNlXQ5Glc8qAxqSU=
-github.com/minio/minio-go/v7 v7.0.93/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc=
+github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM=
+github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -438,8 +434,12 @@ github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWk
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
-github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
-github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
+github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
+github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
+github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
+github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
+github.com/olekukonko/tablewriter v1.0.7 h1:HCC2e3MM+2g72M81ZcJU11uciw6z/p82aEnm4/ySDGw=
+github.com/olekukonko/tablewriter v1.0.7/go.mod h1:H428M+HzoUXC6JU2Abj9IT9ooRmdq9CxuDmKMtrOCMs=
github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E=
github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@@ -497,8 +497,6 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
-github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
@@ -533,8 +531,6 @@ github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oW
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
-github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
-github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/urfave/cli/v3 v3.3.3 h1:byCBaVdIXuLPIDm5CYZRVG6NvT7tv1ECqdU4YzlEa3I=
github.com/urfave/cli/v3 v3.3.3/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ=
@@ -545,8 +541,6 @@ github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
-github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
-github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yohcop/openid-go v1.0.1 h1:DPRd3iPO5F6O5zX2e62XpVAbPT6wV51cuucH0z9g3js=
@@ -653,7 +647,6 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/main.go b/main.go
index 3f0283db7f..ade43881cf 100644
--- a/main.go
+++ b/main.go
@@ -21,7 +21,7 @@ import (
_ "forgejo.org/modules/markup/markdown"
_ "forgejo.org/modules/markup/orgmode"
- "github.com/urfave/cli/v2"
+ "github.com/urfave/cli/v3"
)
// these flags will be set by the build flags
diff --git a/models/actions/run.go b/models/actions/run.go
index 48756b7a08..55def805ed 100644
--- a/models/actions/run.go
+++ b/models/actions/run.go
@@ -55,6 +55,7 @@ type ActionRun struct {
PreviousDuration time.Duration
Created timeutil.TimeStamp `xorm:"created"`
Updated timeutil.TimeStamp `xorm:"updated"`
+ NotifyEmail bool
}
func init() {
diff --git a/models/activities/action.go b/models/activities/action.go
index a309637d04..8592f81414 100644
--- a/models/activities/action.go
+++ b/models/activities/action.go
@@ -442,6 +442,12 @@ func (a *Action) GetIssueContent(ctx context.Context) string {
return a.Issue.Content
}
+func GetActivityByID(ctx context.Context, id int64) (*Action, error) {
+ var act Action
+ _, err := db.GetEngine(ctx).ID(id).Get(&act)
+ return &act, err
+}
+
// GetFeedsOptions options for retrieving feeds
type GetFeedsOptions struct {
db.ListOptions
@@ -467,11 +473,8 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
return nil, 0, err
}
- sess := db.GetEngine(ctx).Where(cond).
- Select("`action`.*"). // this line will avoid select other joined table's columns
- Join("INNER", "repository", "`repository`.id = `action`.repo_id")
-
opts.SetDefaultValues()
+ sess := db.GetEngine(ctx).Where(cond)
sess = db.SetSessionPagination(sess, &opts)
actions := make([]*Action, 0, opts.PageSize)
@@ -598,13 +601,14 @@ func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error)
}
// NotifyWatchers creates batch of actions for every watcher.
-func NotifyWatchers(ctx context.Context, actions ...*Action) error {
+func NotifyWatchers(ctx context.Context, actions ...*Action) ([]Action, error) {
var watchers []*repo_model.Watch
var repo *repo_model.Repository
var err error
var permCode []bool
var permIssue []bool
var permPR []bool
+ var out []Action
e := db.GetEngine(ctx)
@@ -615,14 +619,14 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
// Add feeds for user self and all watchers.
watchers, err = repo_model.GetWatchers(ctx, act.RepoID)
if err != nil {
- return fmt.Errorf("get watchers: %w", err)
+ return nil, fmt.Errorf("get watchers: %w", err)
}
// Be aware that optimizing this correctly into the `GetWatchers` SQL
// query is for most cases less performant than doing this.
blockedDoerUserIDs, err := user_model.ListBlockedByUsersID(ctx, act.ActUserID)
if err != nil {
- return fmt.Errorf("user_model.ListBlockedByUsersID: %w", err)
+ return nil, fmt.Errorf("user_model.ListBlockedByUsersID: %w", err)
}
if len(blockedDoerUserIDs) > 0 {
@@ -637,8 +641,9 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
// Add feed for actioner.
act.UserID = act.ActUserID
if _, err = e.Insert(act); err != nil {
- return fmt.Errorf("insert new actioner: %w", err)
+ return nil, fmt.Errorf("insert new actioner: %w", err)
}
+ out = append(out, *act)
if repoChanged {
act.loadRepo(ctx)
@@ -646,7 +651,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
// check repo owner exist.
if err := act.Repo.LoadOwner(ctx); err != nil {
- return fmt.Errorf("can't get repo owner: %w", err)
+ return nil, fmt.Errorf("can't get repo owner: %w", err)
}
} else if act.Repo == nil {
act.Repo = repo
@@ -657,7 +662,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
act.ID = 0
act.UserID = act.Repo.Owner.ID
if err = db.Insert(ctx, act); err != nil {
- return fmt.Errorf("insert new actioner: %w", err)
+ return nil, fmt.Errorf("insert new actioner: %w", err)
}
}
@@ -710,26 +715,29 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error {
}
if err = db.Insert(ctx, act); err != nil {
- return fmt.Errorf("insert new action: %w", err)
+ return nil, fmt.Errorf("insert new action: %w", err)
}
}
}
- return nil
+ return out, nil
}
// NotifyWatchersActions creates batch of actions for every watcher.
-func NotifyWatchersActions(ctx context.Context, acts []*Action) error {
+func NotifyWatchersActions(ctx context.Context, acts []*Action) ([]Action, error) {
ctx, committer, err := db.TxContext(ctx)
if err != nil {
- return err
+ return nil, err
}
defer committer.Close()
+ var out []Action
for _, act := range acts {
- if err := NotifyWatchers(ctx, act); err != nil {
- return err
+ as, err := NotifyWatchers(ctx, act)
+ if err != nil {
+ return nil, err
}
+ out = append(out, as...)
}
- return committer.Commit()
+ return out, committer.Commit()
}
// DeleteIssueActions delete all actions related with issueID
diff --git a/models/activities/action_test.go b/models/activities/action_test.go
index 8b9b2f6929..47dbd8ac2d 100644
--- a/models/activities/action_test.go
+++ b/models/activities/action_test.go
@@ -197,7 +197,8 @@ func TestNotifyWatchers(t *testing.T) {
RepoID: 1,
OpType: activities_model.ActionStarRepo,
}
- require.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action))
+ _, err := activities_model.NotifyWatchers(db.DefaultContext, action)
+ require.NoError(t, err)
// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
@@ -226,24 +227,6 @@ func TestNotifyWatchers(t *testing.T) {
})
}
-func TestGetFeedsCorrupted(t *testing.T) {
- require.NoError(t, unittest.PrepareTestDatabase())
- user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
- unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
- ID: 8,
- RepoID: 1700,
- })
-
- actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
- RequestedUser: user,
- Actor: user,
- IncludePrivate: true,
- })
- require.NoError(t, err)
- assert.Empty(t, actions)
- assert.Equal(t, int64(0), count)
-}
-
func TestConsistencyUpdateAction(t *testing.T) {
if !setting.Database.Type.IsSQLite3() {
t.Skip("Test is only for SQLite database.")
diff --git a/models/activities/federated_user_activity.go b/models/activities/federated_user_activity.go
new file mode 100644
index 0000000000..1ff3a855d0
--- /dev/null
+++ b/models/activities/federated_user_activity.go
@@ -0,0 +1,106 @@
+// Copyright 2024 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package activities
+
+import (
+ "context"
+ "fmt"
+
+ "forgejo.org/models/db"
+ user_model "forgejo.org/models/user"
+ "forgejo.org/modules/json"
+ "forgejo.org/modules/log"
+ "forgejo.org/modules/timeutil"
+ "forgejo.org/modules/validation"
+
+ ap "github.com/go-ap/activitypub"
+)
+
+type FederatedUserActivity struct {
+ ID int64 `xorm:"pk autoincr"`
+ UserID int64 `xorm:"NOT NULL"`
+ ActorID int64
+ ActorURI string
+ Actor *user_model.User `xorm:"-"` // transient
+ NoteContent string `xorm:"TEXT"`
+ NoteURL string `xorm:"VARCHAR(255)"`
+ OriginalNote string `xorm:"TEXT"`
+ Created timeutil.TimeStamp `xorm:"created"`
+}
+
+func init() {
+ db.RegisterModel(new(FederatedUserActivity))
+}
+
+func NewFederatedUserActivity(userID, actorID int64, actorURI, noteContent, noteURL string, originalNote ap.Activity) (FederatedUserActivity, error) {
+ jsonString, err := json.Marshal(originalNote)
+ if err != nil {
+ return FederatedUserActivity{}, err
+ }
+ result := FederatedUserActivity{
+ UserID: userID,
+ ActorID: actorID,
+ ActorURI: actorURI,
+ NoteContent: noteContent,
+ NoteURL: noteURL,
+ OriginalNote: string(jsonString),
+ }
+ if valid, err := validation.IsValid(result); !valid {
+ return FederatedUserActivity{}, err
+ }
+ return result, nil
+}
+
+func (federatedUserActivity FederatedUserActivity) Validate() []string {
+ var result []string
+ result = append(result, validation.ValidateNotEmpty(federatedUserActivity.UserID, "UserID")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUserActivity.ActorID, "ActorID")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUserActivity.ActorURI, "ActorURI")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUserActivity.NoteContent, "NoteContent")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUserActivity.NoteURL, "NoteURL")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUserActivity.OriginalNote, "OriginalNote")...)
+ return result
+}
+
+func CreateUserActivity(ctx context.Context, federatedUserActivity *FederatedUserActivity) error {
+ if valid, err := validation.IsValid(federatedUserActivity); !valid {
+ return err
+ }
+ _, err := db.GetEngine(ctx).Insert(federatedUserActivity)
+ return err
+}
+
+type GetFollowingFeedsOptions struct {
+ db.ListOptions
+}
+
+func GetFollowingFeeds(ctx context.Context, actorID int64, opts GetFollowingFeedsOptions) ([]*FederatedUserActivity, int64, error) {
+ log.Debug("user_id = %s", actorID)
+ sess := db.GetEngine(ctx).Where("user_id = ?", actorID)
+ opts.SetDefaultValues()
+ sess = db.SetSessionPagination(sess, &opts)
+
+ actions := make([]*FederatedUserActivity, 0, opts.PageSize)
+ count, err := sess.FindAndCount(&actions)
+ if err != nil {
+ return nil, 0, fmt.Errorf("FindAndCount: %w", err)
+ }
+ for _, act := range actions {
+ if err := act.loadActor(ctx); err != nil {
+ return nil, 0, err
+ }
+ }
+ return actions, count, err
+}
+
+func (federatedUserActivity *FederatedUserActivity) loadActor(ctx context.Context) error {
+ log.Debug("for activity %s", federatedUserActivity)
+ actorUser, _, err := user_model.GetFederatedUserByUserID(ctx, federatedUserActivity.ActorID)
+ if err != nil {
+ return err
+ }
+ federatedUserActivity.Actor = actorUser
+
+ return nil
+}
diff --git a/models/activities/federated_user_activity_test.go b/models/activities/federated_user_activity_test.go
new file mode 100644
index 0000000000..9bf4f77984
--- /dev/null
+++ b/models/activities/federated_user_activity_test.go
@@ -0,0 +1,24 @@
+// Copyright 2024 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package activities
+
+import (
+ "testing"
+
+ "forgejo.org/modules/validation"
+)
+
+func Test_FederatedUserActivityValidation(t *testing.T) {
+ sut := FederatedUserActivity{}
+ sut.UserID = 13
+ sut.ActorID = 33
+ sut.ActorURI = "33"
+ sut.NoteContent = "Any content!"
+ sut.NoteURL = "https://example.org/note/17"
+ sut.OriginalNote = "federatedUserActivityNote-17"
+
+ if res, _ := validation.IsValid(sut); !res {
+ t.Errorf("sut expected to be valid: %v\n", sut.Validate())
+ }
+}
diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml
index f1592d4569..a97e94fbf4 100644
--- a/models/fixtures/action.yml
+++ b/models/fixtures/action.yml
@@ -59,14 +59,6 @@
created_unix: 1603011540 # grouped with id:7
- id: 8
- user_id: 1
- op_type: 12 # close issue
- act_user_id: 1
- repo_id: 1700 # dangling intentional
- is_private: false
- created_unix: 1603011541
-
-- id: 9
user_id: 34
op_type: 12 # close issue
act_user_id: 34
diff --git a/models/fixtures/comment.yml b/models/fixtures/comment.yml
index f4121284a6..34407d6f81 100644
--- a/models/fixtures/comment.yml
+++ b/models/fixtures/comment.yml
@@ -113,3 +113,344 @@
review_id: 22
assignee_id: 5
created_unix: 946684817
+
+-
+ id: 13
+ type: 29 # push
+ poster_id: 2
+ issue_id: 19 # in repo_id 58
+ content: '{"is_force_push":false,"commit_ids":["4ca8bcaf27e28504df7bf996819665986b01c847","96cef4a7b72b3c208340ae6f0cf55a93e9077c93","c5626fc9eff57eb1bb7b796b01d4d0f2f3f792a2"]}'
+ created_unix: 1688672373
+
+-
+ id: 14
+ type: 29 # push
+ poster_id: 2
+ issue_id: 19 # in repo_id 58
+ content: '{"is_force_push":false,"commit_ids":["23576dd018294e476c06e569b6b0f170d0558705"]}'
+ created_unix: 1688672374
+
+-
+ id: 15
+ type: 29 # push
+ poster_id: 2
+ issue_id: 19 # in repo_id 58
+ content: '{"is_force_push":false,"commit_ids":["3e64625bd6eb5bcba69ac97de6c8f507402df861", "c704db5794097441aa2d9dd834d5b7e2f8f08108"]}'
+ created_unix: 1688672375
+
+-
+ id: 16
+ type: 29 # push
+ poster_id: 2
+ issue_id: 19 # in repo_id 58
+ content: '{"is_force_push":false,"commit_ids":["811d46c7e518f4f180afb862c0db5cb8c80529ce", "747ddb3506a4fa04a7747808eb56ae16f9e933dc", "837d5c8125633d7d258f93b998e867eab0145520", "1978192d98bb1b65e11c2cf37da854fbf94bffd6"]}'
+ created_unix: 1688672376
+
+-
+ id: 17
+ type: 29 # push
+ poster_id: 2
+ issue_id: 19 # in repo_id 58
+ content: '{"is_force_push":true,"commit_ids":["1978192d98bb1b65e11c2cf37da854fbf94bffd6", "9b93963cf6de4dc33f915bb67f192d099c301f43"]}'
+ created_unix: 1749734240
+
+-
+ id: 2000
+ type: 8 # milestone
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ milestone_id: 1
+ old_milestone_id: 0
+ created_unix: 946684820
+
+-
+ id: 2001
+ type: 8 # milestone
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ milestone_id: 2
+ old_milestone_id: 1
+ created_unix: 946684920
+
+-
+ id: 2002
+ type: 8 # milestone
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ milestone_id: 0
+ old_milestone_id: 2
+ created_unix: 946685020
+
+-
+ id: 2003
+ type: 8 # milestone
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ milestone_id: 10 # not exsting milestone
+ old_milestone_id: 0
+ created_unix: 946685080
+
+-
+ id: 2010
+ type: 30 # project
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ project_id: 1
+ old_project_id: 0
+ created_unix: 946685120
+
+-
+ id: 2011
+ type: 30 # project
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ project_id: 2
+ old_project_id: 1
+ created_unix: 946685220
+
+-
+ id: 2012
+ type: 30 # project
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ project_id: 0
+ old_project_id: 2
+ created_unix: 946685320
+
+-
+ id: 2013
+ type: 30 # project
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ project_id: 10 # not existing project
+ old_project_id: 0
+ created_unix: 946685420
+
+-
+ id: 2020
+ type: 7 # label
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ label_id: 1
+ content: 1 # add label
+ created_unix: 946685520
+
+-
+ id: 2021
+ type: 7 # label
+ poster_id: 1
+ issue_id: 1
+ label_id: 2
+ content: 1 # add label
+ created_unix: 946685620
+
+-
+ id: 2022
+ type: 7 # label
+ poster_id: 2
+ issue_id: 1 # in repo_id 1
+ label_id: 1
+ content: 0 # remove label
+ created_unix: 946685720
+
+-
+ id: 2023
+ type: 7 # label
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ label_id: 1
+ content: 1 # add label
+ created_unix: 946685720
+
+-
+ id: 2024
+ type: 7 # label
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ label_id: 2
+ content: 0 # remove label
+ created_unix: 946685720
+
+-
+ id: 2025
+ type: 7 # label
+ poster_id: 2
+ issue_id: 1 # in repo_id 1
+ label_id: 2
+ content: 1 # add label
+ created_unix: 946685820
+
+-
+ id: 2026
+ type: 7 # label
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ label_id: 1
+ content: 0 # remove label
+ created_unix: 946685920
+
+-
+ id: 2027
+ type: 7 # label
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ label_id: 2
+ content: 0 # remove label
+ created_unix: 946685920
+
+- id: 2040
+ type: 9 # assignee
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ assignee_id: 1 # self
+ removed_assignee: false # add assignee
+ created_unix: 946688020
+
+- id: 2041
+ type: 9 # assignee
+ poster_id: 2
+ issue_id: 1 # in repo_id 1
+ assignee_id: 1
+ removed_assignee: true # remove assignee
+ created_unix: 946688120
+
+- id: 2042
+ type: 9 # assignee
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ assignee_id: 2
+ removed_assignee: false # add assignee
+ created_unix: 946688220
+
+- id: 2043
+ type: 9 # assignee
+ poster_id: 2
+ issue_id: 1 # in repo_id 1
+ assignee_id: 2 # self
+ removed_assignee: true # remove assignee
+ created_unix: 946688320
+
+- id: 2050
+ type: 23 # lock
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ created_unix: 946688420
+
+- id: 2051
+ type: 24 # unlock
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ created_unix: 946688520
+
+- id: 2052
+ type: 23 # lock
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ content: "Too heated"
+ created_unix: 946688620
+
+- id: 2053
+ type: 24 # unlock
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ created_unix: 946688720
+
+- id: 2060
+ type: 36 # pin
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ created_unix: 946688820
+
+- id: 2061
+ type: 37 # unpin
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ created_unix: 946688920
+
+- id: 2070
+ type: 2 # close
+ poster_id: 1
+ issue_id: 1 # in repo_id 1
+ created_unix: 946689020
+
+- id: 2071
+ type: 1 # reopen
+ poster_id: 2
+ issue_id: 1 # in repo_id 1
+ created_unix: 946689220
+
+- id: 2072
+ type: 2 # close
+ poster_id: 1
+ issue_id: 2 # pull in repo_id 1
+ created_unix: 946689320
+
+- id: 2073
+ type: 1 # reopen
+ poster_id: 2
+ issue_id: 2 # pull in repo_id 1
+ created_unix: 946689420
+
+- id: 2080
+ type: 3 # issue reference
+ poster_id: 1
+ issue_id: 1 # issue in repo_id 1
+ ref_repo_id: 1
+ ref_issue_id: 5 # issue in repo_id 1
+ created_unix: 946689500
+
+- id: 2081
+ type: 3 # issue reference
+ poster_id: 1
+ issue_id: 1 # issue in repo_id 1
+ ref_repo_id: 1
+ ref_issue_id: 2 # pull in repo_id 1
+ created_unix: 946689600
+
+- id: 2082
+ type: 3 # issue reference
+ poster_id: 1
+ issue_id: 1 # issue in repo_id 1
+ ref_repo_id: 32
+ ref_issue_id: 16 # issue in repo_id 32
+ created_unix: 946689700
+
+- id: 2083
+ type: 3 # issue reference
+ poster_id: 1
+ issue_id: 1 # issue in repo_id 1
+ ref_repo_id: 10
+ ref_issue_id: 8 # pull in repo_id 10
+ created_unix: 946689800
+
+- id: 2090
+ type: 6 # pull reference
+ poster_id: 1
+ issue_id: 2 # pull in repo_id 1
+ ref_repo_id: 1
+ ref_issue_id: 1 # issue in repo_id 1
+ created_unix: 946689900
+
+- id: 2091
+ type: 6 # pull reference
+ poster_id: 1
+ issue_id: 2 # pull in repo_id 1
+ ref_repo_id: 1
+ ref_issue_id: 2 # pull in repo_id 1
+ created_unix: 946690000
+
+- id: 2092
+ type: 6 # pull reference
+ poster_id: 1
+ issue_id: 2 # pull in repo_id 1
+ ref_repo_id: 32
+ ref_issue_id: 16 # issue in repo_id 32
+ created_unix: 946690050
+
+- id: 2093
+ type: 6 # pull reference
+ poster_id: 1
+ issue_id: 2 # pull in repo_id 1
+ ref_repo_id: 10
+ ref_issue_id: 8 # pull in repo_id 10
+ created_unix: 946690100
diff --git a/models/fixtures/pull_auto_merge.yml b/models/fixtures/pull_auto_merge.yml
new file mode 100644
index 0000000000..ca780a73aa
--- /dev/null
+++ b/models/fixtures/pull_auto_merge.yml
@@ -0,0 +1 @@
+[] # empty
diff --git a/models/forgefed/federationhost.go b/models/forgefed/federationhost.go
index 29f1b7d28e..978847bd95 100644
--- a/models/forgefed/federationhost.go
+++ b/models/forgefed/federationhost.go
@@ -6,6 +6,7 @@ package forgefed
import (
"database/sql"
"fmt"
+ "net/url"
"strings"
"time"
@@ -17,9 +18,9 @@ import (
// swagger:model
type FederationHost struct {
ID int64 `xorm:"pk autoincr"`
- HostFqdn string `xorm:"host_fqdn UNIQUE INDEX VARCHAR(255) NOT NULL"`
+ HostFqdn string `xorm:"host_fqdn UNIQUE(federation_host) INDEX VARCHAR(255) NOT NULL"`
+ HostPort uint16 `xorm:" UNIQUE(federation_host) INDEX NOT NULL DEFAULT 443"`
NodeInfo NodeInfo `xorm:"extends NOT NULL"`
- HostPort uint16 `xorm:"NOT NULL DEFAULT 443"`
HostSchema string `xorm:"NOT NULL DEFAULT 'https'"`
LatestActivity time.Time `xorm:"NOT NULL"`
KeyID sql.NullString `xorm:"key_id UNIQUE"`
@@ -42,6 +43,13 @@ func NewFederationHost(hostFqdn string, nodeInfo NodeInfo, port uint16, schema s
return result, nil
}
+func (host FederationHost) AsURL() url.URL {
+ return url.URL{
+ Scheme: host.HostSchema,
+ Host: fmt.Sprintf("%v:%v", host.HostFqdn, host.HostPort),
+ }
+}
+
// Validate collects error strings in a slice and returns this
func (host FederationHost) Validate() []string {
var result []string
diff --git a/models/forgefed/nodeinfo.go b/models/forgefed/nodeinfo.go
index 2461b5e499..38f51304c5 100644
--- a/models/forgefed/nodeinfo.go
+++ b/models/forgefed/nodeinfo.go
@@ -17,12 +17,14 @@ type (
)
const (
- ForgejoSourceType SoftwareNameType = "forgejo"
- GiteaSourceType SoftwareNameType = "gitea"
+ ForgejoSourceType SoftwareNameType = "forgejo"
+ GiteaSourceType SoftwareNameType = "gitea"
+ MastodonSourceType SoftwareNameType = "mastodon"
+ GoToSocialSourceType SoftwareNameType = "gotosocial"
)
var KnownSourceTypes = []any{
- ForgejoSourceType, GiteaSourceType,
+ ForgejoSourceType, GiteaSourceType, MastodonSourceType, GoToSocialSourceType,
}
// ------------------------------------------------ NodeInfoWellKnown ------------------------------------------------
diff --git a/models/forgejo_migrations/migrate.go b/models/forgejo_migrations/migrate.go
index 21a2077d06..737350b019 100644
--- a/models/forgejo_migrations/migrate.go
+++ b/models/forgejo_migrations/migrate.go
@@ -103,6 +103,12 @@ var migrations = []*Migration{
NewMigration("Normalize repository.topics to empty slice instead of null", SetTopicsAsEmptySlice),
// v31 -> v32
NewMigration("Migrate maven package name concatenation", ChangeMavenArtifactConcatenation),
+ // v32 -> v33
+ NewMigration("Add federated user activity tables, update the `federated_user` table & add indexes", FederatedUserActivityMigration),
+ // v33 -> v34
+ NewMigration("Add `notify-email` column to `action_run` table", AddNotifyEmailToActionRun),
+ // v34 -> v35
+ NewMigration("Add index to `stopped` column in `action_run` table", AddIndexToActionRunStopped),
}
// GetCurrentDBVersion returns the current Forgejo database version.
diff --git a/models/forgejo_migrations/v33.go b/models/forgejo_migrations/v33.go
new file mode 100644
index 0000000000..272035fc23
--- /dev/null
+++ b/models/forgejo_migrations/v33.go
@@ -0,0 +1,126 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package forgejo_migrations //nolint:revive
+
+import (
+ "fmt"
+
+ "forgejo.org/modules/log"
+ "forgejo.org/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func dropOldFederationHostIndexes(x *xorm.Engine) {
+ // drop unique index on HostFqdn
+ type FederationHost struct {
+ ID int64 `xorm:"pk autoincr"`
+ HostFqdn string `xorm:"host_fqdn UNIQUE INDEX VARCHAR(255) NOT NULL"`
+ }
+
+ err := x.DropIndexes(FederationHost{})
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+}
+
+func addFederatedUserActivityTables(x *xorm.Engine) {
+ type FederatedUserActivity struct {
+ ID int64 `xorm:"pk autoincr"`
+ UserID int64 `xorm:"NOT NULL INDEX user_id"`
+ ActorID int64
+ ActorURI string
+ NoteContent string `xorm:"TEXT"`
+ NoteURL string `xorm:"VARCHAR(255)"`
+ OriginalNote string `xorm:"TEXT"`
+ Created timeutil.TimeStamp `xorm:"created"`
+ }
+
+ // add unique index on HostFqdn+HostPort
+ type FederationHost struct {
+ ID int64 `xorm:"pk autoincr"`
+ HostFqdn string `xorm:"host_fqdn UNIQUE(federation_host) INDEX VARCHAR(255) NOT NULL"`
+ HostPort uint16 `xorm:"UNIQUE(federation_host) INDEX NOT NULL DEFAULT 443"`
+ }
+
+ type FederatedUserFollower struct {
+ ID int64 `xorm:"pk autoincr"`
+
+ FollowedUserID int64 `xorm:"NOT NULL unique(fuf_rel)"`
+ FollowingUserID int64 `xorm:"NOT NULL unique(fuf_rel)"`
+ }
+
+ // Add InboxPath to FederatedUser & add index fo UserID
+ type FederatedUser struct {
+ ID int64 `xorm:"pk autoincr"`
+ UserID int64 `xorm:"NOT NULL INDEX user_id"`
+ InboxPath string
+ }
+
+ var err error
+
+ err = x.Sync(&FederationHost{})
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+
+ err = x.Sync(&FederatedUserActivity{})
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+
+ err = x.Sync(&FederatedUserFollower{})
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+
+ err = x.Sync(&FederatedUser{})
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+
+ // Migrate
+ sessMigration := x.NewSession()
+ defer sessMigration.Close()
+ if err := sessMigration.Begin(); err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+ federatedUsers := make([]*FederatedUser, 0)
+ err = sessMigration.OrderBy("id").Find(&federatedUsers)
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+
+ for _, federatedUser := range federatedUsers {
+ if federatedUser.InboxPath != "" {
+ log.Info("migration[33]: This user was already migrated: %v", federatedUser)
+ } else {
+ // Migrate User.InboxPath
+ sql := "UPDATE `federated_user` SET `inbox_path` = ? WHERE `id` = ?"
+ if _, err := sessMigration.Exec(sql, fmt.Sprintf("/api/v1/activitypub/user-id/%v/inbox", federatedUser.UserID), federatedUser.ID); err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+ }
+ }
+
+ err = sessMigration.Commit()
+ if err != nil {
+ log.Warn("migration[33]: There was an issue: %v", err)
+ return
+ }
+}
+
+func FederatedUserActivityMigration(x *xorm.Engine) error {
+ dropOldFederationHostIndexes(x)
+ addFederatedUserActivityTables(x)
+ return nil
+}
diff --git a/models/forgejo_migrations/v33_test.go b/models/forgejo_migrations/v33_test.go
new file mode 100644
index 0000000000..664c704bbc
--- /dev/null
+++ b/models/forgejo_migrations/v33_test.go
@@ -0,0 +1,46 @@
+// Copyright 2025 The Forgejo Authors.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package forgejo_migrations //nolint:revive
+
+import (
+ "testing"
+ "time"
+
+ migration_tests "forgejo.org/models/migrations/test"
+ "forgejo.org/modules/log"
+ ft "forgejo.org/modules/test"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func Test_FederatedUserActivityMigration(t *testing.T) {
+ lc, cl := ft.NewLogChecker(log.DEFAULT, log.WARN)
+ lc.Filter("migration[33]")
+ defer cl()
+
+ // intentionally conflicting definition
+ type FederatedUser struct {
+ ID int64 `xorm:"pk autoincr"`
+ UserID string
+ }
+
+ // Prepare TestEnv
+ x, deferable := migration_tests.PrepareTestEnv(t, 0,
+ new(FederatedUser),
+ )
+ sessTest := x.NewSession()
+ sessTest.Insert(FederatedUser{UserID: "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
+ "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
+ "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"})
+ sessTest.Commit()
+ defer deferable()
+ if x == nil || t.Failed() {
+ return
+ }
+
+ require.NoError(t, FederatedUserActivityMigration(x))
+ logFiltered, _ := lc.Check(5 * time.Second)
+ assert.NotEmpty(t, logFiltered)
+}
diff --git a/models/forgejo_migrations/v34.go b/models/forgejo_migrations/v34.go
new file mode 100644
index 0000000000..9e958b934f
--- /dev/null
+++ b/models/forgejo_migrations/v34.go
@@ -0,0 +1,14 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package forgejo_migrations //nolint:revive
+
+import "xorm.io/xorm"
+
+func AddNotifyEmailToActionRun(x *xorm.Engine) error {
+ type ActionRun struct {
+ ID int64
+ NotifyEmail bool
+ }
+ return x.Sync(new(ActionRun))
+}
diff --git a/models/forgejo_migrations/v35.go b/models/forgejo_migrations/v35.go
new file mode 100644
index 0000000000..0fb3b43e2c
--- /dev/null
+++ b/models/forgejo_migrations/v35.go
@@ -0,0 +1,19 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package forgejo_migrations //nolint:revive
+
+import (
+ "forgejo.org/modules/timeutil"
+
+ "xorm.io/xorm"
+)
+
+func AddIndexToActionRunStopped(x *xorm.Engine) error {
+ type ActionRun struct {
+ ID int64
+ Stopped timeutil.TimeStamp `xorm:"index"`
+ }
+
+ return x.Sync(&ActionRun{})
+}
diff --git a/models/git/commit_status.go b/models/git/commit_status.go
index a679703ffd..60a0aa5a4f 100644
--- a/models/git/commit_status.go
+++ b/models/git/commit_status.go
@@ -179,25 +179,6 @@ func (status *CommitStatus) LocaleString(lang translation.Locale) string {
return lang.TrString("repo.commitstatus." + status.State.String())
}
-// HideActionsURL set `TargetURL` to an empty string if the status comes from Gitea Actions
-func (status *CommitStatus) HideActionsURL(ctx context.Context) {
- if status.RepoID == 0 {
- return
- }
-
- if status.Repo == nil {
- if err := status.loadRepository(ctx); err != nil {
- log.Error("loadRepository: %v", err)
- return
- }
- }
-
- prefix := fmt.Sprintf("%s/actions", status.Repo.Link())
- if strings.HasPrefix(status.TargetURL, prefix) {
- status.TargetURL = ""
- }
-}
-
// CalcCommitStatus returns commit status state via some status, the commit statues should order by id desc
func CalcCommitStatus(statuses []*CommitStatus) *CommitStatus {
if len(statuses) == 0 {
@@ -453,11 +434,19 @@ type SignCommitWithStatuses struct {
*asymkey_model.SignCommit
}
-// ParseCommitsWithStatus checks commits latest statuses and calculates its worst status state
-func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.SignCommit, repo *repo_model.Repository) []*SignCommitWithStatuses {
- newCommits := make([]*SignCommitWithStatuses, 0, len(oldCommits))
+// ParseCommitsWithStatus converts git commits into SignCommitWithStatuses (checks signature and calculates its worst status state)
+func ParseCommitsWithStatus(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses {
+ commitsWithSignature := asymkey_model.ParseCommitsWithSignature(
+ ctx,
+ user_model.ValidateCommitsWithEmails(ctx, commits),
+ repo.GetTrustModel(),
+ func(user *user_model.User) (bool, error) {
+ return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID)
+ },
+ )
- for _, c := range oldCommits {
+ commitsWithStatus := make([]*SignCommitWithStatuses, 0, len(commitsWithSignature))
+ for _, c := range commitsWithSignature {
commit := &SignCommitWithStatuses{
SignCommit: c,
}
@@ -469,43 +458,12 @@ func ParseCommitsWithStatus(ctx context.Context, oldCommits []*asymkey_model.Sig
commit.Status = CalcCommitStatus(statuses)
}
- newCommits = append(newCommits, commit)
+ commitsWithStatus = append(commitsWithStatus, commit)
}
- return newCommits
+ return commitsWithStatus
}
// hashCommitStatusContext hash context
func hashCommitStatusContext(context string) string {
return fmt.Sprintf("%x", sha1.Sum([]byte(context)))
}
-
-// ConvertFromGitCommit converts git commits into SignCommitWithStatuses
-func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo_model.Repository) []*SignCommitWithStatuses {
- return ParseCommitsWithStatus(ctx,
- asymkey_model.ParseCommitsWithSignature(
- ctx,
- user_model.ValidateCommitsWithEmails(ctx, commits),
- repo.GetTrustModel(),
- func(user *user_model.User) (bool, error) {
- return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID)
- },
- ),
- repo,
- )
-}
-
-// CommitStatusesHideActionsURL hide Gitea Actions urls
-func CommitStatusesHideActionsURL(ctx context.Context, statuses []*CommitStatus) {
- idToRepos := make(map[int64]*repo_model.Repository)
- for _, status := range statuses {
- if status == nil {
- continue
- }
-
- if status.Repo == nil {
- status.Repo = idToRepos[status.RepoID]
- }
- status.HideActionsURL(ctx)
- idToRepos[status.RepoID] = status.Repo
- }
-}
diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go
index c062bbbbb9..ce6c0d4673 100644
--- a/models/git/commit_status_test.go
+++ b/models/git/commit_status_test.go
@@ -4,11 +4,9 @@
package git_test
import (
- "fmt"
"testing"
"time"
- actions_model "forgejo.org/models/actions"
"forgejo.org/models/db"
git_model "forgejo.org/models/git"
repo_model "forgejo.org/models/repo"
@@ -246,26 +244,3 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
assert.Equal(t, "compliance/lint-backend", contexts[0])
}
}
-
-func TestCommitStatusesHideActionsURL(t *testing.T) {
- require.NoError(t, unittest.PrepareTestDatabase())
-
- repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
- run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{ID: 791, RepoID: repo.ID})
- require.NoError(t, run.LoadAttributes(db.DefaultContext))
-
- statuses := []*git_model.CommitStatus{
- {
- RepoID: repo.ID,
- TargetURL: fmt.Sprintf("%s/jobs/%d", run.Link(), run.Index),
- },
- {
- RepoID: repo.ID,
- TargetURL: "https://mycicd.org/1",
- },
- }
-
- git_model.CommitStatusesHideActionsURL(db.DefaultContext, statuses)
- assert.Empty(t, statuses[0].TargetURL)
- assert.Equal(t, "https://mycicd.org/1", statuses[1].TargetURL)
-}
diff --git a/models/issues/comment.go b/models/issues/comment.go
index c44f65e29c..a81221caf4 100644
--- a/models/issues/comment.go
+++ b/models/issues/comment.go
@@ -802,7 +802,7 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) {
}
defer closer.Close()
- c.Commits = git_model.ConvertFromGitCommit(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo)
+ c.Commits = git_model.ParseCommitsWithStatus(ctx, gitRepo.GetCommitsFromIDs(data.CommitIDs), c.Issue.Repo)
c.CommitsNum = int64(len(c.Commits))
}
diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go
index bf4b89ee0b..91a69c26a7 100644
--- a/models/issues/issue_search.go
+++ b/models/issues/issue_search.go
@@ -66,6 +66,8 @@ func applySorts(sess *xorm.Session, sortType string, priorityRepoID int64) {
sess.Asc("issue.created_unix").Asc("issue.id")
case "recentupdate":
sess.Desc("issue.updated_unix").Desc("issue.created_unix").Desc("issue.id")
+ case "recentclose":
+ sess.Desc("issue.closed_unix").Desc("issue.created_unix").Desc("issue.id")
case "leastupdate":
sess.Asc("issue.updated_unix").Asc("issue.created_unix").Asc("issue.id")
case "mostcomment":
diff --git a/models/issues/milestone.go b/models/issues/milestone.go
index 52433e735d..67a23246cf 100644
--- a/models/issues/milestone.go
+++ b/models/issues/milestone.go
@@ -67,6 +67,13 @@ type Milestone struct {
TotalTrackedTime int64 `xorm:"-"`
}
+// Ghost milestone is a milestone which has been deleted
+const GhostMilestoneID = -1
+
+func (m *Milestone) IsGhost() bool {
+ return m.ID == GhostMilestoneID
+}
+
func init() {
db.RegisterModel(new(Milestone))
}
diff --git a/models/issues/pull.go b/models/issues/pull.go
index 0781fd0a2d..188ef00814 100644
--- a/models/issues/pull.go
+++ b/models/issues/pull.go
@@ -5,6 +5,7 @@
package issues
import (
+ "bufio"
"context"
"errors"
"fmt"
@@ -923,31 +924,30 @@ func MergeBlockedByOutdatedBranch(protectBranch *git_model.ProtectedBranch, pr *
return protectBranch.BlockOnOutdatedBranch && pr.CommitsBehind > 0
}
-// GetCodeOwnersFromContent returns the code owners configuration
-// Return empty slice if files missing
+// GetCodeOwnersFromReader returns the code owners configuration
// Return warning messages on parsing errors
// We're trying to do the best we can when parsing a file.
// Invalid lines are skipped. Non-existent users and teams too.
-func GetCodeOwnersFromContent(ctx context.Context, data string) ([]*CodeOwnerRule, []string) {
- if len(data) == 0 {
- return nil, nil
- }
+func GetCodeOwnersFromReader(ctx context.Context, rc io.ReadCloser, truncated bool) ([]*CodeOwnerRule, []string) {
+ defer rc.Close()
+ scanner := bufio.NewScanner(rc)
- rules := make([]*CodeOwnerRule, 0)
- lines := strings.Split(data, "\n")
- warnings := make([]string, 0)
+ var rules []*CodeOwnerRule
+ var warnings []string
+ line := 0
+ for scanner.Scan() {
+ line++
- for i, line := range lines {
- tokens := TokenizeCodeOwnersLine(line)
+ tokens := TokenizeCodeOwnersLine(scanner.Text())
if len(tokens) == 0 {
continue
} else if len(tokens) < 2 {
- warnings = append(warnings, fmt.Sprintf("Line: %d: incorrect format", i+1))
+ warnings = append(warnings, fmt.Sprintf("Line: %d: incorrect format", line))
continue
}
rule, wr := ParseCodeOwnersLine(ctx, tokens)
for _, w := range wr {
- warnings = append(warnings, fmt.Sprintf("Line: %d: %s", i+1, w))
+ warnings = append(warnings, fmt.Sprintf("Line: %d: %s", line, w))
}
if rule == nil {
continue
@@ -955,6 +955,12 @@ func GetCodeOwnersFromContent(ctx context.Context, data string) ([]*CodeOwnerRul
rules = append(rules, rule)
}
+ if err := scanner.Err(); err != nil {
+ warnings = append(warnings, err.Error())
+ }
+ if truncated {
+ warnings = append(warnings, fmt.Sprintf("File too big: truncated while on line %d", line))
+ }
return rules, warnings
}
diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go
index a448673454..8fc0491026 100644
--- a/models/issues/pull_list.go
+++ b/models/issues/pull_list.go
@@ -152,7 +152,8 @@ func PullRequests(ctx context.Context, baseRepoID int64, opts *PullRequestsOptio
applySorts(findSession, opts.SortType, 0)
findSession = db.SetSessionPagination(findSession, opts)
prs := make([]*PullRequest, 0, opts.PageSize)
- return prs, maxResults, findSession.Find(&prs)
+ found := findSession.Find(&prs)
+ return prs, maxResults, found
}
// PullRequestList defines a list of pull requests
diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go
index 5a8e8d8aaf..3682f6fd25 100644
--- a/models/issues/pull_test.go
+++ b/models/issues/pull_test.go
@@ -79,6 +79,47 @@ func TestPullRequestsNewest(t *testing.T) {
}
}
+func TestPullRequests_Closed_RecentSortType(t *testing.T) {
+ // Issue ID | Closed At. | Updated At
+ // 2 | 1707270001 | 1707270001
+ // 3 | 1707271000 | 1707279999
+ // 11 | 1707279999 | 1707275555
+ tests := []struct {
+ sortType string
+ expectedIssueIDOrder []int64
+ }{
+ {"recentupdate", []int64{3, 11, 2}},
+ {"recentclose", []int64{11, 3, 2}},
+ }
+
+ require.NoError(t, unittest.PrepareTestDatabase())
+ _, err := db.Exec(db.DefaultContext, "UPDATE issue SET closed_unix = 1707270001, updated_unix = 1707270001, is_closed = true WHERE id = 2")
+ require.NoError(t, err)
+ _, err = db.Exec(db.DefaultContext, "UPDATE issue SET closed_unix = 1707271000, updated_unix = 1707279999, is_closed = true WHERE id = 3")
+ require.NoError(t, err)
+ _, err = db.Exec(db.DefaultContext, "UPDATE issue SET closed_unix = 1707279999, updated_unix = 1707275555, is_closed = true WHERE id = 11")
+ require.NoError(t, err)
+
+ for _, test := range tests {
+ t.Run(test.sortType, func(t *testing.T) {
+ prs, _, err := issues_model.PullRequests(db.DefaultContext, 1, &issues_model.PullRequestsOptions{
+ ListOptions: db.ListOptions{
+ Page: 1,
+ },
+ State: "closed",
+ SortType: test.sortType,
+ })
+ require.NoError(t, err)
+
+ if assert.Len(t, prs, len(test.expectedIssueIDOrder)) {
+ for i := range test.expectedIssueIDOrder {
+ assert.Equal(t, test.expectedIssueIDOrder[i], prs[i].IssueID)
+ }
+ }
+ })
+ }
+}
+
func TestLoadRequestedReviewers(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
diff --git a/models/pull/automerge.go b/models/pull/automerge.go
index 63f572309b..dcc1f39271 100644
--- a/models/pull/automerge.go
+++ b/models/pull/automerge.go
@@ -10,6 +10,7 @@ import (
"forgejo.org/models/db"
repo_model "forgejo.org/models/repo"
user_model "forgejo.org/models/user"
+ "forgejo.org/modules/log"
"forgejo.org/modules/timeutil"
)
@@ -58,13 +59,15 @@ func ScheduleAutoMerge(ctx context.Context, doer *user_model.User, pullID int64,
return ErrAlreadyScheduledToAutoMerge{PullID: pullID}
}
- _, err := db.GetEngine(ctx).Insert(&AutoMerge{
+ scheduledPRM, err := db.GetEngine(ctx).Insert(&AutoMerge{
DoerID: doer.ID,
PullID: pullID,
MergeStyle: style,
Message: message,
DeleteBranchAfterMerge: deleteBranch,
})
+ log.Trace("ScheduleAutoMerge %+v for PR %d", scheduledPRM, pullID)
+
return err
}
@@ -81,6 +84,8 @@ func GetScheduledMergeByPullID(ctx context.Context, pullID int64) (bool, *AutoMe
return false, nil, err
}
+ log.Trace("GetScheduledMergeByPullID found %+v for PR %d", scheduledPRM, pullID)
+
scheduledPRM.Doer = doer
return true, scheduledPRM, nil
}
@@ -94,6 +99,8 @@ func DeleteScheduledAutoMerge(ctx context.Context, pullID int64) error {
return db.ErrNotExist{Resource: "auto_merge", ID: pullID}
}
+ log.Trace("DeleteScheduledAutoMerge %+v for PR %d", scheduledPRM, pullID)
+
_, err = db.GetEngine(ctx).ID(scheduledPRM.ID).Delete(&AutoMerge{})
return err
}
diff --git a/models/user/federated_user.go b/models/user/federated_user.go
index c1833c7de3..d2a9c34c9e 100644
--- a/models/user/federated_user.go
+++ b/models/user/federated_user.go
@@ -11,19 +11,21 @@ import (
type FederatedUser struct {
ID int64 `xorm:"pk autoincr"`
- UserID int64 `xorm:"NOT NULL"`
+ UserID int64 `xorm:"NOT NULL INDEX user_id"`
ExternalID string `xorm:"UNIQUE(federation_user_mapping) NOT NULL"`
FederationHostID int64 `xorm:"UNIQUE(federation_user_mapping) NOT NULL"`
KeyID sql.NullString `xorm:"key_id UNIQUE"`
PublicKey sql.Null[sql.RawBytes] `xorm:"BLOB"`
- NormalizedOriginalURL string // This field is just to keep original information. Pls. do not use for search or as ID!
+ InboxPath string
+ NormalizedOriginalURL string // This field is just to keep original information. Pls. do not use for search or as ID!
}
-func NewFederatedUser(userID int64, externalID string, federationHostID int64, normalizedOriginalURL string) (FederatedUser, error) {
+func NewFederatedUser(userID int64, externalID string, federationHostID int64, inboxPath, normalizedOriginalURL string) (FederatedUser, error) {
result := FederatedUser{
UserID: userID,
ExternalID: externalID,
FederationHostID: federationHostID,
+ InboxPath: inboxPath,
NormalizedOriginalURL: normalizedOriginalURL,
}
if valid, err := validation.IsValid(result); !valid {
@@ -32,10 +34,11 @@ func NewFederatedUser(userID int64, externalID string, federationHostID int64, n
return result, nil
}
-func (user FederatedUser) Validate() []string {
+func (federatedUser FederatedUser) Validate() []string {
var result []string
- result = append(result, validation.ValidateNotEmpty(user.UserID, "UserID")...)
- result = append(result, validation.ValidateNotEmpty(user.ExternalID, "ExternalID")...)
- result = append(result, validation.ValidateNotEmpty(user.FederationHostID, "FederationHostID")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUser.UserID, "UserID")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUser.ExternalID, "ExternalID")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUser.FederationHostID, "FederationHostID")...)
+ result = append(result, validation.ValidateNotEmpty(federatedUser.InboxPath, "InboxPath")...)
return result
}
diff --git a/models/user/federated_user_follower.go b/models/user/federated_user_follower.go
new file mode 100644
index 0000000000..db72c9b5ce
--- /dev/null
+++ b/models/user/federated_user_follower.go
@@ -0,0 +1,30 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package user
+
+import "forgejo.org/modules/validation"
+
+type FederatedUserFollower struct {
+ ID int64 `xorm:"pk autoincr"`
+ FollowedUserID int64 `xorm:"NOT NULL unique(fuf_rel)"`
+ FollowingUserID int64 `xorm:"NOT NULL unique(fuf_rel)"`
+}
+
+func NewFederatedUserFollower(followedUserID, federatedUserID int64) (FederatedUserFollower, error) {
+ result := FederatedUserFollower{
+ FollowedUserID: followedUserID,
+ FollowingUserID: federatedUserID,
+ }
+ if valid, err := validation.IsValid(result); !valid {
+ return FederatedUserFollower{}, err
+ }
+ return result, nil
+}
+
+func (user FederatedUserFollower) Validate() []string {
+ var result []string
+ result = append(result, validation.ValidateNotEmpty(user.FollowedUserID, "FollowedUserID")...)
+ result = append(result, validation.ValidateNotEmpty(user.FollowingUserID, "FollowingUserID")...)
+ return result
+}
diff --git a/models/user/federated_user_follower_test.go b/models/user/federated_user_follower_test.go
new file mode 100644
index 0000000000..e57ba01308
--- /dev/null
+++ b/models/user/federated_user_follower_test.go
@@ -0,0 +1,27 @@
+// Copyright 2024 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package user
+
+import (
+ "testing"
+
+ "forgejo.org/modules/validation"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func Test_FederatedUserFollowerValidation(t *testing.T) {
+ sut := FederatedUserFollower{
+ FollowedUserID: 12,
+ FollowingUserID: 1,
+ }
+ res, err := validation.IsValid(sut)
+ assert.Truef(t, res, "sut should be valid but was %q", err)
+
+ sut = FederatedUserFollower{
+ FollowedUserID: 1,
+ }
+ res, _ = validation.IsValid(sut)
+ assert.False(t, res, "sut should be invalid")
+}
diff --git a/models/user/federated_user_test.go b/models/user/federated_user_test.go
index 542798c9bc..be18339670 100644
--- a/models/user/federated_user_test.go
+++ b/models/user/federated_user_test.go
@@ -14,6 +14,7 @@ func Test_FederatedUserValidation(t *testing.T) {
UserID: 12,
ExternalID: "12",
FederationHostID: 1,
+ InboxPath: "/api/v1/activitypub/user-id/12/inbox",
}
if res, err := validation.IsValid(sut); !res {
t.Errorf("sut should be valid but was %q", err)
@@ -22,6 +23,7 @@ func Test_FederatedUserValidation(t *testing.T) {
sut = FederatedUser{
ExternalID: "12",
FederationHostID: 1,
+ InboxPath: "/api/v1/activitypub/user-id/12/inbox",
}
if res, _ := validation.IsValid(sut); res {
t.Error("sut should be invalid")
diff --git a/models/user/follow.go b/models/user/follow.go
index 5be0f73c35..e32c226385 100644
--- a/models/user/follow.go
+++ b/models/user/follow.go
@@ -11,6 +11,7 @@ import (
)
// Follow represents relations of user and their followers.
+// TODO: We should unify Activity-pub-following and classical following (see models/user/user_repository.go#IsFollowingAp)
type Follow struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"UNIQUE(follow)"`
diff --git a/models/user/user_repository.go b/models/user/user_repository.go
index 299d3af64a..3f24efb1fb 100644
--- a/models/user/user_repository.go
+++ b/models/user/user_repository.go
@@ -1,4 +1,4 @@
-// Copyright 2024 The Forgejo Authors. All rights reserved.
+// Copyright 2024, 2025 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
@@ -8,12 +8,14 @@ import (
"fmt"
"forgejo.org/models/db"
+ "forgejo.org/modules/log"
"forgejo.org/modules/optional"
"forgejo.org/modules/validation"
)
func init() {
db.RegisterModel(new(FederatedUser))
+ db.RegisterModel(new(FederatedUserFollower))
}
func CreateFederatedUser(ctx context.Context, user *User, federatedUser *FederatedUser) error {
@@ -30,7 +32,12 @@ func CreateFederatedUser(ctx context.Context, user *User, federatedUser *Federat
if err != nil {
return err
}
- defer committer.Close()
+ defer func() {
+ err := committer.Close()
+ if err != nil {
+ log.Error("Error closing committer: %v", err)
+ }
+ }()
if err := CreateUser(ctx, user, &overwrite); err != nil {
return err
@@ -50,6 +57,14 @@ func CreateFederatedUser(ctx context.Context, user *User, federatedUser *Federat
return committer.Commit()
}
+func (federatedUser *FederatedUser) UpdateFederatedUser(ctx context.Context) error {
+ if _, err := validation.IsValid(federatedUser); err != nil {
+ return err
+ }
+ _, err := db.GetEngine(ctx).ID(federatedUser.ID).Cols("inbox_path").Update(federatedUser)
+ return err
+}
+
func FindFederatedUser(ctx context.Context, externalID string, federationHostID int64) (*User, *FederatedUser, error) {
federatedUser := new(FederatedUser)
user := new(User)
@@ -75,6 +90,41 @@ func FindFederatedUser(ctx context.Context, externalID string, federationHostID
return user, federatedUser, nil
}
+func GetFederatedUser(ctx context.Context, externalID string, federationHostID int64) (*User, *FederatedUser, error) {
+ user, federatedUser, err := FindFederatedUser(ctx, externalID, federationHostID)
+ if err != nil {
+ return nil, nil, err
+ } else if federatedUser == nil {
+ return nil, nil, fmt.Errorf("FederatedUser for externalId = %v and federationHostId = %v does not exist", externalID, federationHostID)
+ }
+ return user, federatedUser, nil
+}
+
+func GetFederatedUserByUserID(ctx context.Context, userID int64) (*User, *FederatedUser, error) {
+ federatedUser := new(FederatedUser)
+ user := new(User)
+ has, err := db.GetEngine(ctx).Where("user_id=?", userID).Get(federatedUser)
+ if err != nil {
+ return nil, nil, err
+ } else if !has {
+ return nil, nil, fmt.Errorf("Federated user %v does not exist", federatedUser.UserID)
+ }
+ has, err = db.GetEngine(ctx).ID(federatedUser.UserID).Get(user)
+ if err != nil {
+ return nil, nil, err
+ } else if !has {
+ return nil, nil, fmt.Errorf("User %v for federated user is missing", federatedUser.UserID)
+ }
+
+ if res, err := validation.IsValid(*user); !res {
+ return nil, nil, err
+ }
+ if res, err := validation.IsValid(*federatedUser); !res {
+ return nil, nil, err
+ }
+ return user, federatedUser, nil
+}
+
func FindFederatedUserByKeyID(ctx context.Context, keyID string) (*User, *FederatedUser, error) {
federatedUser := new(FederatedUser)
user := new(User)
@@ -101,7 +151,85 @@ func FindFederatedUserByKeyID(ctx context.Context, keyID string) (*User, *Federa
return user, federatedUser, nil
}
+func UpdateFederatedUser(ctx context.Context, federatedUser *FederatedUser) error {
+ if res, err := validation.IsValid(federatedUser); !res {
+ return err
+ }
+ _, err := db.GetEngine(ctx).ID(federatedUser.ID).Update(federatedUser)
+ return err
+}
+
func DeleteFederatedUser(ctx context.Context, userID int64) error {
_, err := db.GetEngine(ctx).Delete(&FederatedUser{UserID: userID})
return err
}
+
+func GetFollowersForUser(ctx context.Context, user *User) ([]*FederatedUserFollower, error) {
+ if res, err := validation.IsValid(user); !res {
+ return nil, err
+ }
+ followers := make([]*FederatedUserFollower, 0, 8)
+
+ err := db.GetEngine(ctx).
+ Where("followed_user_id = ?", user.ID).
+ Find(&followers)
+ if err != nil {
+ return nil, err
+ }
+ for _, element := range followers {
+ if res, err := validation.IsValid(*element); !res {
+ return nil, err
+ }
+ }
+ return followers, nil
+}
+
+func AddFollower(ctx context.Context, followedUser *User, followingUser *FederatedUser) (*FederatedUserFollower, error) {
+ if res, err := validation.IsValid(followedUser); !res {
+ return nil, err
+ }
+ if res, err := validation.IsValid(followingUser); !res {
+ return nil, err
+ }
+
+ federatedUserFollower, err := NewFederatedUserFollower(followedUser.ID, followingUser.UserID)
+ if err != nil {
+ return nil, err
+ }
+ _, err = db.GetEngine(ctx).Insert(&federatedUserFollower)
+ if err != nil {
+ return nil, err
+ }
+
+ return &federatedUserFollower, err
+}
+
+func RemoveFollower(ctx context.Context, followedUser *User, followingUser *FederatedUser) error {
+ if res, err := validation.IsValid(followedUser); !res {
+ return err
+ }
+ if res, err := validation.IsValid(followingUser); !res {
+ return err
+ }
+
+ _, err := db.GetEngine(ctx).Delete(&FederatedUserFollower{
+ FollowedUserID: followedUser.ID,
+ FollowingUserID: followingUser.UserID,
+ })
+ return err
+}
+
+// TODO: We should unify Activity-pub-following and classical following (see models/user/follow.go)
+func IsFollowingAp(ctx context.Context, followedUser *User, followingUser *FederatedUser) (bool, error) {
+ if res, err := validation.IsValid(followedUser); !res {
+ return false, err
+ }
+ if res, err := validation.IsValid(followingUser); !res {
+ return false, err
+ }
+
+ return db.GetEngine(ctx).Get(&FederatedUserFollower{
+ FollowedUserID: followedUser.ID,
+ FollowingUserID: followingUser.UserID,
+ })
+}
diff --git a/models/user/user_system.go b/models/user/user_system.go
index 82805cc8ee..11f54591b7 100644
--- a/models/user/user_system.go
+++ b/models/user/user_system.go
@@ -12,6 +12,13 @@ import (
"forgejo.org/modules/structs"
)
+// IsSystem returns true if the user has a fixed
+// negative ID, is never stored in the database and
+// is generated on the fly when needed.
+func (u *User) IsSystem() bool {
+ return u.IsGhost() || u.IsActions()
+}
+
const (
GhostUserID = -1
GhostUserName = "Ghost"
diff --git a/models/user/user_test.go b/models/user/user_test.go
index 2a9e652a35..fd9d05653f 100644
--- a/models/user/user_test.go
+++ b/models/user/user_test.go
@@ -148,7 +148,7 @@ func TestAPActorID_APActorID(t *testing.T) {
assert.Equal(t, expected, url)
}
-func TestAPActorKeyID(t *testing.T) {
+func TestKeyID(t *testing.T) {
user := user_model.User{ID: 1}
url := user.APActorKeyID()
expected := "https://try.gitea.io/api/v1/activitypub/user-id/1#main-key"
diff --git a/modules/actions/workflows.go b/modules/actions/workflows.go
index daf453fb47..7ae4557ed6 100644
--- a/modules/actions/workflows.go
+++ b/modules/actions/workflows.go
@@ -323,6 +323,10 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
matchTimes++
}
case "paths":
+ if refName.IsTag() {
+ matchTimes++
+ break
+ }
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
@@ -336,6 +340,10 @@ func matchPushEvent(commit *git.Commit, pushPayload *api.PushPayload, evt *jobpa
}
}
case "paths-ignore":
+ if refName.IsTag() {
+ matchTimes++
+ break
+ }
filesChanged, err := commit.GetFilesChangedSinceCommit(pushPayload.Before)
if err != nil {
log.Error("GetFilesChangedSinceCommit [commit_sha1: %s]: %v", commit.ID.String(), err)
diff --git a/modules/actions/workflows_test.go b/modules/actions/workflows_test.go
index b85ed7fd56..9068ce31c3 100644
--- a/modules/actions/workflows_test.go
+++ b/modules/actions/workflows_test.go
@@ -150,6 +150,24 @@ func TestDetectMatched(t *testing.T) {
yamlOn: "on: workflow_dispatch",
expected: true,
},
+ {
+ desc: "push to tag matches workflow with paths condition (should skip paths check)",
+ triggeredEvent: webhook_module.HookEventPush,
+ payload: &api.PushPayload{
+ Ref: "refs/tags/v1.0.0",
+ Before: "0000000",
+ Commits: []*api.PayloadCommit{
+ {
+ ID: "abcdef123456",
+ Added: []string{"src/main.go"},
+ Message: "Release v1.0.0",
+ },
+ },
+ },
+ commit: nil,
+ yamlOn: "on:\n push:\n paths:\n - src/**",
+ expected: true,
+ },
}
for _, tc := range testCases {
diff --git a/modules/git/blob.go b/modules/git/blob.go
index 3fda358938..30615afe32 100644
--- a/modules/git/blob.go
+++ b/modules/git/blob.go
@@ -12,7 +12,6 @@ import (
"forgejo.org/modules/log"
"forgejo.org/modules/typesniffer"
- "forgejo.org/modules/util"
)
// Blob represents a Git object.
@@ -25,42 +24,25 @@ type Blob struct {
repo *Repository
}
-// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
-// Calling the Close function on the result will discard all unread output.
-func (b *Blob) DataAsync() (io.ReadCloser, error) {
+func (b *Blob) newReader() (*bufio.Reader, int64, func(), error) {
wr, rd, cancel, err := b.repo.CatFileBatch(b.repo.Ctx)
if err != nil {
- return nil, err
+ return nil, 0, nil, err
}
_, err = wr.Write([]byte(b.ID.String() + "\n"))
if err != nil {
cancel()
- return nil, err
+ return nil, 0, nil, err
}
_, _, size, err := ReadBatchLine(rd)
if err != nil {
cancel()
- return nil, err
+ return nil, 0, nil, err
}
b.gotSize = true
b.size = size
-
- if size < 4096 {
- bs, err := io.ReadAll(io.LimitReader(rd, size))
- defer cancel()
- if err != nil {
- return nil, err
- }
- _, err = rd.Discard(1)
- return io.NopCloser(bytes.NewReader(bs)), err
- }
-
- return &blobReader{
- rd: rd,
- n: size,
- cancel: cancel,
- }, nil
+ return rd, size, cancel, err
}
// Size returns the uncompressed size of the blob
@@ -91,10 +73,36 @@ func (b *Blob) Size() int64 {
return b.size
}
+// DataAsync gets a ReadCloser for the contents of a blob without reading it all.
+// Calling the Close function on the result will discard all unread output.
+func (b *Blob) DataAsync() (io.ReadCloser, error) {
+ rd, size, cancel, err := b.newReader()
+ if err != nil {
+ return nil, err
+ }
+
+ if size < 4096 {
+ bs, err := io.ReadAll(io.LimitReader(rd, size))
+ defer cancel()
+ if err != nil {
+ return nil, err
+ }
+ _, err = rd.Discard(1)
+ return io.NopCloser(bytes.NewReader(bs)), err
+ }
+
+ return &blobReader{
+ rd: rd,
+ n: size,
+ cancel: cancel,
+ }, nil
+}
+
type blobReader struct {
- rd *bufio.Reader
- n int64
- cancel func()
+ rd *bufio.Reader
+ n int64 // number of bytes to read
+ additionalDiscard int64 // additional number of bytes to discard
+ cancel func()
}
func (b *blobReader) Read(p []byte) (n int, err error) {
@@ -117,7 +125,8 @@ func (b *blobReader) Close() error {
defer b.cancel()
- if err := DiscardFull(b.rd, b.n+1); err != nil {
+ // discard the unread bytes, the truncated bytes and the trailing newline
+ if err := DiscardFull(b.rd, b.n+b.additionalDiscard+1); err != nil {
return err
}
@@ -131,47 +140,38 @@ func (b *Blob) Name() string {
return b.name
}
-// GetBlobContent Gets the limited content of the blob as raw text
+// NewTruncatedReader return a blob-reader which silently truncates when the limit is reached (io.EOF will be returned)
+func (b *Blob) NewTruncatedReader(limit int64) (rc io.ReadCloser, fullSize int64, err error) {
+ r, fullSize, cancel, err := b.newReader()
+ if err != nil {
+ return nil, fullSize, err
+ }
+
+ limit = min(limit, fullSize)
+ return &blobReader{
+ rd: r,
+ n: limit,
+ additionalDiscard: fullSize - limit,
+ cancel: cancel,
+ }, fullSize, nil
+}
+
+// GetBlobContent Gets the truncated content of the blob as raw text
func (b *Blob) GetBlobContent(limit int64) (string, error) {
if limit <= 0 {
return "", nil
}
- dataRc, err := b.DataAsync()
+ rc, fullSize, err := b.NewTruncatedReader(limit)
if err != nil {
return "", err
}
- defer dataRc.Close()
- buf, err := util.ReadWithLimit(dataRc, int(limit))
+ defer rc.Close()
+
+ buf := make([]byte, min(fullSize, limit))
+ _, err = io.ReadFull(rc, buf)
return string(buf), err
}
-// GetBlobLineCount gets line count of the blob
-func (b *Blob) GetBlobLineCount() (int, error) {
- reader, err := b.DataAsync()
- if err != nil {
- return 0, err
- }
- defer reader.Close()
- buf := make([]byte, 32*1024)
- count := 1
- lineSep := []byte{'\n'}
-
- c, err := reader.Read(buf)
- if c == 0 && err == io.EOF {
- return 0, nil
- }
- for {
- count += bytes.Count(buf[:c], lineSep)
- switch {
- case err == io.EOF:
- return count, nil
- case err != nil:
- return count, err
- }
- c, err = reader.Read(buf)
- }
-}
-
// GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string
func (b *Blob) GetBlobContentBase64() (string, error) {
dataRc, err := b.DataAsync()
diff --git a/modules/git/blob_test.go b/modules/git/blob_test.go
index 810964b33d..54115013d3 100644
--- a/modules/git/blob_test.go
+++ b/modules/git/blob_test.go
@@ -35,6 +35,106 @@ func TestBlob_Data(t *testing.T) {
assert.Equal(t, output, string(data))
}
+func TestBlob(t *testing.T) {
+ bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
+ repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
+ require.NoError(t, err)
+
+ defer repo.Close()
+
+ testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375")
+ require.NoError(t, err)
+
+ t.Run("GetBlobContent", func(t *testing.T) {
+ r, err := testBlob.GetBlobContent(100)
+ require.NoError(t, err)
+ require.Equal(t, "file2\n", r)
+
+ r, err = testBlob.GetBlobContent(-1)
+ require.NoError(t, err)
+ require.Empty(t, r)
+
+ r, err = testBlob.GetBlobContent(4)
+ require.NoError(t, err)
+ require.Equal(t, "file", r)
+
+ r, err = testBlob.GetBlobContent(6)
+ require.NoError(t, err)
+ require.Equal(t, "file2\n", r)
+ })
+
+ t.Run("NewTruncatedReader", func(t *testing.T) {
+ // read fewer than available
+ rc, size, err := testBlob.NewTruncatedReader(100)
+ require.NoError(t, err)
+ require.Equal(t, int64(6), size)
+
+ buf := make([]byte, 1)
+ n, err := rc.Read(buf)
+ require.NoError(t, err)
+ require.Equal(t, 1, n)
+ require.Equal(t, "f", string(buf))
+ n, err = rc.Read(buf)
+ require.NoError(t, err)
+ require.Equal(t, 1, n)
+ require.Equal(t, "i", string(buf))
+
+ require.NoError(t, rc.Close())
+
+ // read more than available
+ rc, size, err = testBlob.NewTruncatedReader(100)
+ require.NoError(t, err)
+ require.Equal(t, int64(6), size)
+
+ buf = make([]byte, 100)
+ n, err = rc.Read(buf)
+ require.NoError(t, err)
+ require.Equal(t, 6, n)
+ require.Equal(t, "file2\n", string(buf[:n]))
+
+ n, err = rc.Read(buf)
+ require.Error(t, err)
+ require.Equal(t, io.EOF, err)
+ require.Equal(t, 0, n)
+
+ require.NoError(t, rc.Close())
+
+ // read more than truncated
+ rc, size, err = testBlob.NewTruncatedReader(4)
+ require.NoError(t, err)
+ require.Equal(t, int64(6), size)
+
+ buf = make([]byte, 10)
+ n, err = rc.Read(buf)
+ require.NoError(t, err)
+ require.Equal(t, 4, n)
+ require.Equal(t, "file", string(buf[:n]))
+
+ n, err = rc.Read(buf)
+ require.Error(t, err)
+ require.Equal(t, io.EOF, err)
+ require.Equal(t, 0, n)
+
+ require.NoError(t, rc.Close())
+ })
+
+ t.Run("NonExisting", func(t *testing.T) {
+ nonExistingBlob, err := repo.GetBlob("00003ff740f9380390d5c9ddef4af18690000000")
+ require.NoError(t, err)
+
+ r, err := nonExistingBlob.GetBlobContent(100)
+ require.Error(t, err)
+ require.IsType(t, ErrNotExist{}, err)
+ require.Empty(t, r)
+
+ rc, size, err := nonExistingBlob.NewTruncatedReader(100)
+ require.Error(t, err)
+ require.IsType(t, ErrNotExist{}, err)
+ require.Empty(t, rc)
+ require.Empty(t, size)
+ })
+}
+
func Benchmark_Blob_Data(b *testing.B) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
repo, err := openRepositoryWithDefaultContext(bareRepo1Path)
diff --git a/modules/git/git.go b/modules/git/git.go
index 743ff59ddd..1dfd0b5134 100644
--- a/modules/git/git.go
+++ b/modules/git/git.go
@@ -38,6 +38,7 @@ var (
InvertedGitFlushEnv bool // 2.43.1
SupportCheckAttrOnBare bool // >= 2.40
SupportGitMergeTree bool // >= 2.38
+ SupportGrepMaxCount bool // >= 2.38
HasSSHExecutable bool
@@ -191,6 +192,7 @@ func InitFull(ctx context.Context) (err error) {
InvertedGitFlushEnv = CheckGitVersionEqual("2.43.1") == nil
SupportGitMergeTree = CheckGitVersionAtLeast("2.38") == nil
+ SupportGrepMaxCount = CheckGitVersionAtLeast("2.38") == nil
if setting.LFS.StartServer {
if CheckGitVersionAtLeast("2.1.2") != nil {
diff --git a/modules/git/grep.go b/modules/git/grep.go
index 117b09fc83..3703b13660 100644
--- a/modules/git/grep.go
+++ b/modules/git/grep.go
@@ -98,8 +98,7 @@ func GrepSearch(ctx context.Context, repo *Repository, search string, opts GrepO
cmd.AddOptionValues("--context", fmt.Sprint(opts.ContextLineNumber))
- // --max-count requires at least git 2.38
- if CheckGitVersionAtLeast("2.38.0") == nil {
+ if SupportGrepMaxCount {
cmd.AddOptionValues("--max-count", fmt.Sprint(opts.MatchesPerFile))
} else {
log.Warn("git-grep: --max-count requires at least git 2.38")
diff --git a/modules/git/grep_test.go b/modules/git/grep_test.go
index 534468e268..83ddb766af 100644
--- a/modules/git/grep_test.go
+++ b/modules/git/grep_test.go
@@ -59,48 +59,55 @@ func TestGrepSearch(t *testing.T) {
},
}, res)
- res, err = GrepSearch(t.Context(), repo, "world", GrepOptions{MatchesPerFile: 1})
- require.NoError(t, err)
- assert.Equal(t, []*GrepResult{
- {
- Filename: "i-am-a-python.p",
- LineNumbers: []int{1},
- LineCodes: []string{"## This is a simple file to do a hello world"},
- HighlightedRanges: [][3]int{{0, 39, 44}},
- },
- {
- Filename: "java-hello/main.java",
- LineNumbers: []int{1},
- LineCodes: []string{"public class HelloWorld"},
- HighlightedRanges: [][3]int{{0, 18, 23}},
- },
- {
- Filename: "main.vendor.java",
- LineNumbers: []int{1},
- LineCodes: []string{"public class HelloWorld"},
- HighlightedRanges: [][3]int{{0, 18, 23}},
- },
- {
- Filename: "python-hello/hello.py",
- LineNumbers: []int{1},
- LineCodes: []string{"## This is a simple file to do a hello world"},
- HighlightedRanges: [][3]int{{0, 39, 44}},
- },
- }, res)
+ t.Run("Max count", func(t *testing.T) {
+ if !SupportGrepMaxCount {
+ t.Skip("Skipping, git grep --max-count is not supported")
+ return
+ }
- res, err = GrepSearch(t.Context(), repo, "world", GrepOptions{
- MatchesPerFile: 1,
- Filename: "java-hello/",
+ res, err = GrepSearch(t.Context(), repo, "world", GrepOptions{MatchesPerFile: 1})
+ require.NoError(t, err)
+ assert.Equal(t, []*GrepResult{
+ {
+ Filename: "i-am-a-python.p",
+ LineNumbers: []int{1},
+ LineCodes: []string{"## This is a simple file to do a hello world"},
+ HighlightedRanges: [][3]int{{0, 39, 44}},
+ },
+ {
+ Filename: "java-hello/main.java",
+ LineNumbers: []int{1},
+ LineCodes: []string{"public class HelloWorld"},
+ HighlightedRanges: [][3]int{{0, 18, 23}},
+ },
+ {
+ Filename: "main.vendor.java",
+ LineNumbers: []int{1},
+ LineCodes: []string{"public class HelloWorld"},
+ HighlightedRanges: [][3]int{{0, 18, 23}},
+ },
+ {
+ Filename: "python-hello/hello.py",
+ LineNumbers: []int{1},
+ LineCodes: []string{"## This is a simple file to do a hello world"},
+ HighlightedRanges: [][3]int{{0, 39, 44}},
+ },
+ }, res)
+
+ res, err = GrepSearch(t.Context(), repo, "world", GrepOptions{
+ MatchesPerFile: 1,
+ Filename: "java-hello/",
+ })
+ require.NoError(t, err)
+ assert.Equal(t, []*GrepResult{
+ {
+ Filename: "java-hello/main.java",
+ LineNumbers: []int{1},
+ LineCodes: []string{"public class HelloWorld"},
+ HighlightedRanges: [][3]int{{0, 18, 23}},
+ },
+ }, res)
})
- require.NoError(t, err)
- assert.Equal(t, []*GrepResult{
- {
- Filename: "java-hello/main.java",
- LineNumbers: []int{1},
- LineCodes: []string{"public class HelloWorld"},
- HighlightedRanges: [][3]int{{0, 18, 23}},
- },
- }, res)
res, err = GrepSearch(t.Context(), repo, "no-such-content", GrepOptions{})
require.NoError(t, err)
diff --git a/modules/git/repo_attribute_test.go b/modules/git/repo_attribute_test.go
index 0006559709..c69382e245 100644
--- a/modules/git/repo_attribute_test.go
+++ b/modules/git/repo_attribute_test.go
@@ -251,10 +251,14 @@ func TestGitAttributeCheckerError(t *testing.T) {
cancel()
ac, err := gitRepo.GitAttributeChecker("8fee858da5796dfb37704761701bb8e800ad9ef3", "linguist-language")
- require.NoError(t, err)
+ if SupportCheckAttrOnBare {
+ require.NoError(t, err)
- _, err = ac.CheckPath("i-am-a-python.p")
- require.Error(t, err)
+ _, err = ac.CheckPath("i-am-a-python.p")
+ require.Error(t, err)
+ } else {
+ require.Error(t, err)
+ }
})
t.Run("Cancelled/DuringRun", func(t *testing.T) {
diff --git a/modules/indexer/issues/elasticsearch/elasticsearch_test.go b/modules/indexer/issues/elasticsearch/elasticsearch_test.go
index 0c2635fd0c..1ad01352d3 100644
--- a/modules/indexer/issues/elasticsearch/elasticsearch_test.go
+++ b/modules/indexer/issues/elasticsearch/elasticsearch_test.go
@@ -16,16 +16,10 @@ import (
)
func TestElasticsearchIndexer(t *testing.T) {
- // The elasticsearch instance started by testing.yml > test-unit > services > elasticsearch
- url := "http://elastic:changeme@elasticsearch:9200"
-
- if os.Getenv("CI") == "" {
- // Make it possible to run tests against a local elasticsearch instance
- url = os.Getenv("TEST_ELASTICSEARCH_URL")
- if url == "" {
- t.Skip("TEST_ELASTICSEARCH_URL not set and not running in CI")
- return
- }
+ url := os.Getenv("TEST_ELASTICSEARCH_URL")
+ if url == "" {
+ t.Skip("TEST_ELASTICSEARCH_URL not set")
+ return
}
require.Eventually(t, func() bool {
diff --git a/modules/indexer/issues/internal/qstring.go b/modules/indexer/issues/internal/qstring.go
index 8115fc904f..6b60b4c5f6 100644
--- a/modules/indexer/issues/internal/qstring.go
+++ b/modules/indexer/issues/internal/qstring.go
@@ -25,7 +25,7 @@ type Token struct {
func (tk *Token) ParseIssueReference() (int64, error) {
term := tk.Term
- if term[0] == '#' || term[0] == '!' {
+ if len(term) > 1 && (term[0] == '#' || term[0] == '!') {
term = term[1:]
}
return strconv.ParseInt(term, 10, 64)
diff --git a/modules/indexer/issues/internal/qstring_test.go b/modules/indexer/issues/internal/qstring_test.go
index a911b86e2f..835491707c 100644
--- a/modules/indexer/issues/internal/qstring_test.go
+++ b/modules/indexer/issues/internal/qstring_test.go
@@ -169,3 +169,35 @@ func TestIssueQueryString(t *testing.T) {
})
}
}
+
+func TestToken_ParseIssueReference(t *testing.T) {
+ var tk Token
+ {
+ tk.Term = "123"
+ id, err := tk.ParseIssueReference()
+ require.NoError(t, err)
+ assert.Equal(t, int64(123), id)
+ }
+ {
+ tk.Term = "#123"
+ id, err := tk.ParseIssueReference()
+ require.NoError(t, err)
+ assert.Equal(t, int64(123), id)
+ }
+ {
+ tk.Term = "!123"
+ id, err := tk.ParseIssueReference()
+ require.NoError(t, err)
+ assert.Equal(t, int64(123), id)
+ }
+ {
+ tk.Term = "text"
+ _, err := tk.ParseIssueReference()
+ require.Error(t, err)
+ }
+ {
+ tk.Term = ""
+ _, err := tk.ParseIssueReference()
+ require.Error(t, err)
+ }
+}
diff --git a/modules/markup/html.go b/modules/markup/html.go
index c13ebab98a..7961c5c930 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -69,6 +69,10 @@ var (
// https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail)
emailRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+)(?:\\s|$|\\)|\\]|;|,|\\?|!|\\.(\\s|$))")
+ // Fediverse handle regex (same as emailRegex but with additonal @ or !
+ // at start)
+ fediRegex = regexp.MustCompile("(?:\\s|^|\\(|\\[)([@!]([a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+)@([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]{2,}(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+))(?:\\s|$|\\)|\\]|;|,|\\?|!|\\.(\\s|$))")
+
// blackfriday extensions create IDs like fn:user-content-footnote
blackfridayExtRegex = regexp.MustCompile(`[^:]*:user-content-`)
@@ -153,6 +157,7 @@ var defaultProcessors = []processor{
issueIndexPatternProcessor,
commitCrossReferencePatternProcessor,
hashCurrentPatternProcessor,
+ fediAddressProcessor,
emailAddressProcessor,
emojiProcessor,
emojiShortCodeProcessor,
@@ -1237,6 +1242,21 @@ func hashCurrentPatternProcessor(ctx *RenderContext, node *html.Node) {
}
}
+// fediAddressProcessor replaces raw fediverse handles with toolforge links
+func fediAddressProcessor(ctx *RenderContext, node *html.Node) {
+ next := node.NextSibling
+ for node != nil && node != next {
+ m := fediRegex.FindStringSubmatchIndex(node.Data)
+ if m == nil {
+ return
+ }
+
+ fedihandle := node.Data[m[2]:m[3]]
+ replaceContent(node, m[2], m[3], createLink("https://fedirect.toolforge.org/?id="+url.QueryEscape(fedihandle), fedihandle, "fedihandle"))
+ node = node.NextSibling.NextSibling
+ }
+}
+
// emailAddressProcessor replaces raw email addresses with a mailto: link.
func emailAddressProcessor(ctx *RenderContext, node *html.Node) {
next := node.NextSibling
diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go
index 9d0c40c9e8..2bc929bb04 100644
--- a/modules/markup/html_test.go
+++ b/modules/markup/html_test.go
@@ -307,6 +307,19 @@ func TestRender_email(t *testing.T) {
test(
"email@domain..com",
`
local link
remote link
-
-
-
-
+
+
+
+
https://example.com/user/repo/compare/88fc37a3c0a4dda553bdcfc80c178a58247f42fb...12fc37a3c0a4dda553bdcfc80c178a58247f42fb#hash
@@ -872,10 +872,10 @@ space
88fc37a3c0...12fc37a3c0 (hash)
diff --git a/modules/typesniffer/typesniffer.go b/modules/typesniffer/typesniffer.go
index a8fc70e54c..262feb2b05 100644
--- a/modules/typesniffer/typesniffer.go
+++ b/modules/typesniffer/typesniffer.go
@@ -24,6 +24,16 @@ const (
AvifMimeType = "image/avif"
// ApplicationOctetStream MIME type of binary files.
ApplicationOctetStream = "application/octet-stream"
+ // GLTFMimeType MIME type of GLTF files.
+ GLTFMimeType = "model/gltf+json"
+ // GLBMimeType MIME type of GLB files.
+ GLBMimeType = "model/gltf-binary"
+ // OBJMimeType MIME type of OBJ files.
+ OBJMimeType = "model/obj"
+ // STLMimeType MIME type of STL files.
+ STLMimeType = "model/stl"
+ // 3MFMimeType MIME type of 3MF files.
+ ThreeMFMimeType = "model/3mf"
)
var (
@@ -67,6 +77,36 @@ func (ct SniffedType) IsAudio() bool {
return strings.Contains(ct.contentType, "audio/")
}
+// Is3DModel detects if data is a 3D format
+func (ct SniffedType) Is3DModel() bool {
+ return strings.Contains(ct.contentType, "model/")
+}
+
+// IsGLTFFile detects if data is an SVG image format
+func (ct SniffedType) IsGLTF() bool {
+ return strings.Contains(ct.contentType, GLTFMimeType)
+}
+
+// IsGLBFile detects if data is an GLB image format
+func (ct SniffedType) IsGLB() bool {
+ return strings.Contains(ct.contentType, GLBMimeType)
+}
+
+// IsOBJFile detects if data is an OBJ image format
+func (ct SniffedType) IsOBJ() bool {
+ return strings.Contains(ct.contentType, OBJMimeType)
+}
+
+// IsSTLTextFile detects if data is an STL text format
+func (ct SniffedType) IsSTL() bool {
+ return strings.Contains(ct.contentType, STLMimeType)
+}
+
+// Is3MFFile detects if data is an 3MF image format
+func (ct SniffedType) Is3MF() bool {
+ return strings.Contains(ct.contentType, ThreeMFMimeType)
+}
+
// IsRepresentableAsText returns true if file content can be represented as
// plain text or is empty.
func (ct SniffedType) IsRepresentableAsText() bool {
@@ -75,7 +115,7 @@ func (ct SniffedType) IsRepresentableAsText() bool {
// IsBrowsableBinaryType returns whether a non-text type can be displayed in a browser
func (ct SniffedType) IsBrowsableBinaryType() bool {
- return ct.IsImage() || ct.IsSvgImage() || ct.IsPDF() || ct.IsVideo() || ct.IsAudio()
+ return ct.IsImage() || ct.IsSvgImage() || ct.IsPDF() || ct.IsVideo() || ct.IsAudio() || ct.Is3DModel()
}
// GetMimeType returns the mime type
@@ -135,6 +175,13 @@ func DetectContentType(data []byte) SniffedType {
ct = "audio/ogg" // for most cases, it is used as an audio container
}
}
+
+ // GLTF is unsupported by http.DetectContentType
+ // hexdump -n 4 -C glTF.glb
+ if bytes.HasPrefix(data, []byte("glTF")) {
+ ct = GLBMimeType
+ }
+
return SniffedType{ct}
}
diff --git a/modules/typesniffer/typesniffer_test.go b/modules/typesniffer/typesniffer_test.go
index 8d80b4ddb4..176d3658bb 100644
--- a/modules/typesniffer/typesniffer_test.go
+++ b/modules/typesniffer/typesniffer_test.go
@@ -117,6 +117,14 @@ func TestIsAudio(t *testing.T) {
assert.True(t, DetectContentType([]byte("ID3Toy\n====\t* hi 🌞, ..."+"🌛"[0:2])).IsText()) // test ID3 tag with incomplete UTF8 char
}
+func TestIsGLB(t *testing.T) {
+ glb, _ := hex.DecodeString("676c5446")
+ assert.True(t, DetectContentType(glb).IsGLB())
+ assert.True(t, DetectContentType(glb).Is3DModel())
+ assert.False(t, DetectContentType([]byte("plain text")).IsGLB())
+ assert.False(t, DetectContentType([]byte("plain text")).Is3DModel())
+}
+
func TestDetectContentTypeFromReader(t *testing.T) {
mp3, _ := base64.StdEncoding.DecodeString("SUQzBAAAAAABAFRYWFgAAAASAAADbWFqb3JfYnJhbmQAbXA0MgBUWFhYAAAAEQAAA21pbm9yX3Zl")
st, err := DetectContentTypeFromReader(bytes.NewReader(mp3))
@@ -145,3 +153,15 @@ func TestDetectContentTypeAvif(t *testing.T) {
assert.True(t, st.IsImage())
}
+
+func TestDetectContentTypeModelGLB(t *testing.T) {
+ glb, err := hex.DecodeString("676c5446")
+ require.NoError(t, err)
+
+ st, err := DetectContentTypeFromReader(bytes.NewReader(glb))
+ require.NoError(t, err)
+
+ // print st for debugging
+ assert.Equal(t, "model/gltf-binary", st.GetMimeType())
+ assert.True(t, st.IsGLB())
+}
diff --git a/modules/util/io.go b/modules/util/io.go
index 1559b019a0..4c99004c0c 100644
--- a/modules/util/io.go
+++ b/modules/util/io.go
@@ -4,7 +4,6 @@
package util
import (
- "bytes"
"errors"
"io"
)
@@ -20,42 +19,6 @@ func ReadAtMost(r io.Reader, buf []byte) (n int, err error) {
return n, err
}
-// ReadWithLimit reads at most "limit" bytes from r into buf.
-// If EOF or ErrUnexpectedEOF occurs while reading, err will be nil.
-func ReadWithLimit(r io.Reader, n int) (buf []byte, err error) {
- return readWithLimit(r, 1024, n)
-}
-
-func readWithLimit(r io.Reader, batch, limit int) ([]byte, error) {
- if limit <= batch {
- buf := make([]byte, limit)
- n, err := ReadAtMost(r, buf)
- if err != nil {
- return nil, err
- }
- return buf[:n], nil
- }
- res := bytes.NewBuffer(make([]byte, 0, batch))
- bufFix := make([]byte, batch)
- eof := false
- for res.Len() < limit && !eof {
- bufTmp := bufFix
- if res.Len()+batch > limit {
- bufTmp = bufFix[:limit-res.Len()]
- }
- n, err := io.ReadFull(r, bufTmp)
- if err == io.EOF || err == io.ErrUnexpectedEOF {
- eof = true
- } else if err != nil {
- return nil, err
- }
- if _, err = res.Write(bufTmp[:n]); err != nil {
- return nil, err
- }
- }
- return res.Bytes(), nil
-}
-
// ErrNotEmpty is an error reported when there is a non-empty reader
var ErrNotEmpty = errors.New("not-empty")
diff --git a/modules/util/io_test.go b/modules/util/io_test.go
deleted file mode 100644
index 870e713646..0000000000
--- a/modules/util/io_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2023 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-package util
-
-import (
- "bytes"
- "errors"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-type readerWithError struct {
- buf *bytes.Buffer
-}
-
-func (r *readerWithError) Read(p []byte) (n int, err error) {
- if r.buf.Len() < 2 {
- return 0, errors.New("test error")
- }
- return r.buf.Read(p)
-}
-
-func TestReadWithLimit(t *testing.T) {
- bs := []byte("0123456789abcdef")
-
- // normal test
- buf, err := readWithLimit(bytes.NewBuffer(bs), 5, 2)
- require.NoError(t, err)
- assert.Equal(t, []byte("01"), buf)
-
- buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 5)
- require.NoError(t, err)
- assert.Equal(t, []byte("01234"), buf)
-
- buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 6)
- require.NoError(t, err)
- assert.Equal(t, []byte("012345"), buf)
-
- buf, err = readWithLimit(bytes.NewBuffer(bs), 5, len(bs))
- require.NoError(t, err)
- assert.Equal(t, []byte("0123456789abcdef"), buf)
-
- buf, err = readWithLimit(bytes.NewBuffer(bs), 5, 100)
- require.NoError(t, err)
- assert.Equal(t, []byte("0123456789abcdef"), buf)
-
- // test with error
- buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 10)
- require.NoError(t, err)
- assert.Equal(t, []byte("0123456789"), buf)
-
- buf, err = readWithLimit(&readerWithError{bytes.NewBuffer(bs)}, 5, 100)
- require.ErrorContains(t, err, "test error")
- assert.Empty(t, buf)
-
- // test public function
- buf, err = ReadWithLimit(bytes.NewBuffer(bs), 2)
- require.NoError(t, err)
- assert.Equal(t, []byte("01"), buf)
-
- buf, err = ReadWithLimit(bytes.NewBuffer(bs), 9999999)
- require.NoError(t, err)
- assert.Equal(t, []byte("0123456789abcdef"), buf)
-}
diff --git a/modules/util/truncate.go b/modules/util/truncate.go
index f2edbdc673..7207a89177 100644
--- a/modules/util/truncate.go
+++ b/modules/util/truncate.go
@@ -54,3 +54,12 @@ func SplitTrimSpace(input, sep string) []string {
return stringList
}
+
+// TruncateRunes returns a truncated string with given rune limit,
+// it returns input string if its rune length doesn't exceed the limit.
+func TruncateRunes(str string, limit int) string {
+ if utf8.RuneCountInString(str) < limit {
+ return str
+ }
+ return string([]rune(str)[:limit])
+}
diff --git a/modules/util/truncate_test.go b/modules/util/truncate_test.go
index dfe1230fd4..8187b13eb2 100644
--- a/modules/util/truncate_test.go
+++ b/modules/util/truncate_test.go
@@ -44,3 +44,18 @@ func TestSplitString(t *testing.T) {
}
test(tc, SplitStringAtByteN)
}
+
+func TestTruncateRunes(t *testing.T) {
+ assert.Empty(t, TruncateRunes("", 0))
+ assert.Empty(t, TruncateRunes("", 1))
+
+ assert.Empty(t, TruncateRunes("ab", 0))
+ assert.Equal(t, "a", TruncateRunes("ab", 1))
+ assert.Equal(t, "ab", TruncateRunes("ab", 2))
+ assert.Equal(t, "ab", TruncateRunes("ab", 3))
+
+ assert.Empty(t, TruncateRunes("测试", 0))
+ assert.Equal(t, "测", TruncateRunes("测试", 1))
+ assert.Equal(t, "测试", TruncateRunes("测试", 2))
+ assert.Equal(t, "测试", TruncateRunes("测试", 3))
+}
diff --git a/options/locale/locale_ar.ini b/options/locale/locale_ar.ini
index f4ac1a0e3d..15d614e8bc 100644
--- a/options/locale/locale_ar.ini
+++ b/options/locale/locale_ar.ini
@@ -699,7 +699,7 @@ issues.filter_milestone_all = كل الأهداف
issues.unlock.notice_2 = - يمكنك دوما إقفال هذه المسألة من جديد في المستقبل.
issues.num_participants_few = %d متحاور
release.title = عنوان الإصدار
-issues.closed_at = `أغلق هذه المسألة %[2]s`
+issues.closed_at = `أغلق هذه المسألة %s`
issues.lock.title = إقفال التحاور في هذه المسألة.
issues.new.no_label = بلا تصنيف
issues.filter_sort.mostforks = الأعلى اشتقاقا
@@ -759,7 +759,7 @@ branch.renamed = غُيّر اسم الفرع %s إلى %s.
delete_preexisting = احذف الملفات الموجودة سابقا
branch.included_desc = هذا الفرع جزء من الفرع المبدئي
trust_model_helper_collaborator_committer = مشترك+مودع: ثق بتوقيعات المشتركين التي تطابق المودع
-issues.reopened_at = `أعاد فتح هذه المسألة %[2]s`
+issues.reopened_at = `أعاد فتح هذه المسألة %s`
issues.action_milestone = هدف
issues.new.assignees = المكلَّفون
release.tag_name_protected = اسم الوسم محمي.
@@ -1166,7 +1166,7 @@ pulls.status_checking = في انتظار بعض الفحوص
pulls.status_checks_failure = بعض الفحوص فشلت
pulls.status_checks_success = جميع الفحوص ناجحة
pulls.status_checks_warning = بعض الفحوص تعطي تحذيرات
-pulls.commit_ref_at = `أشار إلى طلب الدمج من إيداع %[2]s`
+pulls.commit_ref_at = `أشار إلى طلب الدمج من إيداع %s`
pulls.cmd_instruction_hint = `أظهر شرح استخدام سطر الأوامر.`
pulls.cmd_instruction_checkout_title = اسحب
pulls.cmd_instruction_checkout_desc = من مستودع مشروعك، اسحب (check out) فرعا جديدا واختبر التغييرات.
@@ -1257,8 +1257,8 @@ pulls.status_checks_details = تفاصيل
pulls.status_checks_hide_all = أخفِ كل الفحوص
pulls.status_checks_show_all = أظهر كل الفحوص
pulls.close = أغلق طلب الدمج
-pulls.closed_at = `أغلق طلب الدمج %[2]s`
-pulls.reopened_at = `أعاد فتح طلب الدمج %[2]s`
+pulls.closed_at = `أغلق طلب الدمج %s`
+pulls.reopened_at = `أعاد فتح طلب الدمج %s`
milestones.title = العنوان
milestones.desc = الوصف
milestones.edit = عدّل الهدف
@@ -1302,11 +1302,11 @@ issues.closed_by_fake = من %[2]s أُغلقت %[1]s
issues.num_comments_1 = %d تعليق
issues.num_comments = %d تعليقا
issues.commented_at = `علّق %s`
-issues.commit_ref_at = `أشار إلى هذه المسألة من إيداع %[2]s`
-issues.ref_issue_from = `أشار إلى هذه المسألة %[4]s %[2]s`
-issues.ref_pull_from = `أشار إلى هذا الطلب %[4]s %[2]s`
-issues.ref_closing_from = `أشار إلى طلب دمج %[4]s سيغلق هذه المسألة %[2]s`
-issues.ref_reopening_from = `أشار إلى طلب دمج %[4]s سيعيد فتح هذه المسألة %[2]s`
+issues.commit_ref_at = `أشار إلى هذه المسألة من إيداع %s`
+issues.ref_issue_from = `أشار إلى هذه المسألة %[3]s %[1]s`
+issues.ref_pull_from = `أشار إلى هذا الطلب %[3]s %[1]s`
+issues.ref_closing_from = `أشار إلى طلب دمج %[3]s سيغلق هذه المسألة %[1]s`
+issues.ref_reopening_from = `أشار إلى طلب دمج %[3]s سيعيد فتح هذه المسألة %[1]s`
issues.ref_closed_from = `أغلق هذه المسألة %[4]s %[2]s`
issues.ref_reopened_from = `أعاد فتح هذه المسألة %[4]s %[2]s`
issues.reference_issue.body = المحتوى
diff --git a/options/locale/locale_bg.ini b/options/locale/locale_bg.ini
index abce4f1133..1b9767f674 100644
--- a/options/locale/locale_bg.ini
+++ b/options/locale/locale_bg.ini
@@ -749,7 +749,7 @@ settings.admin_settings = Администраторски настройки
issues.role.owner = Притежател
settings.transfer.title = Прехвърляне на притежанието
issues.author = Автор
-issues.closed_at = `затвори тази задача %[2]s`
+issues.closed_at = `затвори тази задача %s`
settings.collaborator_deletion_desc = Премахването на сътрудник ще отнеме достъпа му до това хранилище. Продължаване?
commits.message = Съобщение
issues.due_date_not_set = Няма зададен краен срок.
@@ -773,9 +773,9 @@ issues.filter_type.all_issues = Всички задачи
issues.filter_poster_no_select = Всички автори
issues.opened_by = отворена %[1]s от %[3]s
issues.action_open = Отваряне
-pulls.closed_at = `затвори тази заявка за сливане %[2]s`
-pulls.reopened_at = `отвори наново тази заявка за сливане %[2]s`
-issues.reopened_at = `отвори наново тази задача %[2]s`
+pulls.closed_at = `затвори тази заявка за сливане %s`
+pulls.reopened_at = `отвори наново тази заявка за сливане %s`
+issues.reopened_at = `отвори наново тази задача %s`
projects.column.edit = Редактиране на колоната
issues.close = Затваряне на задачата
issues.ref_reopened_from = `отвори наново тази задача %[4]s %[2]s`
@@ -1205,7 +1205,7 @@ issues.dependency.cancel = Отказ
issues.dependency.add_error_dep_exists = Зависимостта вече съществува.
issues.dependency.add_error_dep_not_exist = Зависимостта не съществува.
issues.remove_ref_at = `премахна препратката %s %s`
-issues.ref_pull_from = `спомена тази заявка за сливане %[4]s %[2]s`
+issues.ref_pull_from = `спомена тази заявка за сливане %[3]s %[1]s`
issues.dependency.pr_no_dependencies = Няма зададени зависимости.
issues.dependency.remove_info = Премахване на тази зависимост
issues.dependency.removed_dependency = `премахна зависимостта %s`
@@ -1230,11 +1230,11 @@ issues.dependency.title = Зависимости
issues.dependency.issue_no_dependencies = Няма зададени зависимости.
issues.dependency.pr_close_blocked = Трябва да затворите всички задачи, блокиращи тази заявка за сливане, преди да можете да я слеете.
issues.dependency.pr_close_blocks = Тази заявка за сливане блокира затварянето на следните задачи
-issues.ref_issue_from = `спомена тази задача %[4]s %[2]s`
-issues.commit_ref_at = `спомена тази задача в подаване %[2]s`
+issues.ref_issue_from = `спомена тази задача %[3]s %[1]s`
+issues.commit_ref_at = `спомена тази задача в подаване %s`
issues.add_ref_at = `добави препратка %s %s`
pulls.merged_info_text = Клонът %s вече може да бъде изтрит.
-pulls.commit_ref_at = `спомена тази заявка за сливане в подаване %[2]s`
+pulls.commit_ref_at = `спомена тази заявка за сливане в подаване %s`
issues.change_ref_at = `промени препратката от Alt
+ Klick/Enter
verwenden, um Labels auszuschließen`
+issues.filter_label_exclude=`Verwende Alt + Klick/Enter, um Labels auszuschließen`
issues.filter_label_no_select=Alle Labels
issues.filter_label_select_no_label=Kein Label
issues.filter_milestone=Meilenstein
@@ -1651,13 +1651,13 @@ issues.close_comment_issue=Mit Kommentar schließen
issues.reopen_issue=Wieder öffnen
issues.reopen_comment_issue=Mit Kommentar wieder öffnen
issues.create_comment=Kommentieren
-issues.closed_at=`hat diesen Issue %[2]s geschlossen`
-issues.reopened_at=`hat dieses Issue %[2]s wieder geöffnet`
-issues.commit_ref_at=`hat dieses Issue %[2]s aus einem Commit referenziert`
-issues.ref_issue_from=`hat %[2]s auf dieses Issue verwiesen %[4]s`
-issues.ref_pull_from=`hat %[2]s auf diesen Pull-Request verwiesen %[4]s`
-issues.ref_closing_from=`hat %[2]s in einem Pull-Request %[4]s auf dieses Issue verwiesen, welcher es schließen wird`
-issues.ref_reopening_from=`hat %[2]s in einem Pull-Request %[4]s auf dieses Issue verwiesen, welcher es erneut öffnen wird`
+issues.closed_at=`hat dieses Issue %s geschlossen`
+issues.reopened_at=`hat dieses Issue %s wieder geöffnet`
+issues.commit_ref_at=`hat dieses Issue %s aus einem Commit referenziert`
+issues.ref_issue_from=`hat %[1]s auf dieses Issue verwiesen %[3]s`
+issues.ref_pull_from=`referenzierte diesen Pull-Request %[3]s %[1]s`
+issues.ref_closing_from=`referenzierte dieses Issue aus einem Pull-Request %[3]s der es schließen wird, %[1]s`
+issues.ref_reopening_from=`referenzierte dieses Issue aus einem Pull-Request %[3]s der es wieder öffnen wird, %[1]s`
issues.ref_closed_from=`hat dieses Issue %[4]s geschlossen %[2]s`
issues.ref_reopened_from=`hat dieses Issue %[4]s %[2]s wieder geöffnet`
issues.ref_from=`von %[1]s`
@@ -1962,8 +1962,8 @@ pulls.update_branch_success=Branch-Aktualisierung erfolgreich
pulls.update_not_allowed=Du hast keine Berechtigung, den Branch zu updaten
pulls.outdated_with_base_branch=Dieser Branch enthält nicht die neusten Commits des Basis-Branches
pulls.close=Pull-Request schließen
-pulls.closed_at=`hat diesen Pull-Request %[2]s geschlossen`
-pulls.reopened_at=`hat diesen Pull-Request %[2]s wieder geöffnet`
+pulls.closed_at=`hat diesen Pull-Request %s geschlossen`
+pulls.reopened_at=`hat diesen Pull-Request %s wieder geöffnet`
pulls.clear_merge_message=Merge-Nachricht löschen
pulls.clear_merge_message_hint=Das Löschen der Merge-Nachricht wird nur den Inhalt der Commit-Nachricht entfernen und generierte Git-Trailer wie „Co-Authored-By …“ erhalten.
@@ -2767,7 +2767,7 @@ settings.wiki_globally_editable = Allen erlauben, das Wiki zu bearbeiten
settings.protect_branch_name_pattern_desc = Geschützte Branch-Namens-Patterns. Siehe die Dokumentation für Pattern-Syntax. Beispiele: main, release/**
settings.ignore_stale_approvals = Abgestandene Genehmigungen ignorieren
settings.ignore_stale_approvals_desc = Genehmigungen, welche für ältere Commits gemacht wurden (abgestandene Reviews), nicht in die Gesamtzahl der Genehmigung des PRs mitzählen. Irrelevant, falls abgestandene Reviews bereits verworfen werden.
-pulls.commit_ref_at = `hat sich auf diesen Pull-Request von einem Commit %[2]s bezogen`
+pulls.commit_ref_at = `referenzierte diesen Pull-Request aus einem Commit %s`
pulls.fast_forward_only_merge_pull_request = Nur Fast-forward
pulls.cmd_instruction_checkout_desc = Checke einen neuen Branch aus deinem Projekt-Repository aus und teste die Änderungen.
pulls.cmd_instruction_merge_title = Zusammenführen
@@ -2924,6 +2924,7 @@ settings.event_action_success = Erfolg
settings.event_header_action = Action-Run-Ereignisse
settings.event_action_recover_desc = Action-Run war erfolgreich, nachdem der letzte Action-Run im selben Arbeitsablauf fehlgeschlagen ist.
settings.event_action_recover = Wiederherstellen
+issues.filter_type.all_pull_requests = Alle Pull-Requests
[graphs]
component_loading_failed = Konnte %s nicht laden
@@ -3060,8 +3061,8 @@ teams.invite.by=Von %s eingeladen
teams.invite.description=Bitte klicke auf die folgende Schaltfläche, um dem Team beizutreten.
follow_blocked_user = Du kannst dieser Organisation nicht folgen, weil diese Organisation dich blockiert hat.
open_dashboard = Übersicht öffnen
-settings.change_orgname_redirect_prompt.with_cooldown.one = Der alte Organisationsname ist nach einer Abkühldauer von einem Tag wieder für alle verfügbar. Du kannst den alten Namen während dieser Abkühldauer erneut beanspruchen.
-settings.change_orgname_redirect_prompt.with_cooldown.few = Der alte Organisationsname ist nach einer Abkühldauer von %[1]d Tagen wieder für alle verfügbar. Du kannst den alten Namen während dieser Abkühldauer erneut beanspruchen.
+settings.change_orgname_redirect_prompt.with_cooldown.one = Der alte Organisationsname ist nach einer Schutzzeit von einem Tag wieder für alle verfügbar. Du kannst den alten Namen während dieser Schutzzeit erneut beanspruchen.
+settings.change_orgname_redirect_prompt.with_cooldown.few = Der alte Organisationsname ist nach einer Schutzzeit von %[1]d Tagen wieder für alle verfügbar. Du kannst den alten Namen während dieser Schutzzeit erneut beanspruchen.
[admin]
dashboard=Übersicht
diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini
index 29085aebf1..398a0d9ce4 100644
--- a/options/locale/locale_el-GR.ini
+++ b/options/locale/locale_el-GR.ini
@@ -1626,13 +1626,13 @@ issues.close_comment_issue=Αποστολή σχολίου και κλείσιμ
issues.reopen_issue=Ανοίξτε ξανά
issues.reopen_comment_issue=Αποστολή σχολίου και επανάνοιγμα ζητήματος
issues.create_comment=Προσθήκη Σχολίου
-issues.closed_at=`αυτό το ζήτημα έκλεισε %[2]s`
-issues.reopened_at=`ξανά άνοιξε αυτό το ζήτημα %[2]s`
-issues.commit_ref_at=`αναφορά σε αυτό το ζήτημα από την παραπομπή %[2]s`
-issues.ref_issue_from=`αναφέρθηκε σε αυτό το ζήτημα %[4]s %[2]s`
-issues.ref_pull_from=`αναφέρθηκε σε αυτό το pull request %[4]s %[2]s`
-issues.ref_closing_from=`ανέφερε αυτό το ζήτημα σε ένα pull request %[4]s που στοχεύει να κλείσει το ζήτημα %[2]s`
-issues.ref_reopening_from=`αναφέρθηκε σε αυτό το ζήτημα σε ένα pull request %[4]s που θα ξαναανοίξει αυτό το ζήτημα %[2]s`
+issues.closed_at=`αυτό το ζήτημα έκλεισε %s`
+issues.reopened_at=`ξανά άνοιξε αυτό το ζήτημα %s`
+issues.commit_ref_at=`αναφορά σε αυτό το ζήτημα από την παραπομπή %s`
+issues.ref_issue_from=`αναφέρθηκε σε αυτό το ζήτημα %[3]s %[1]s`
+issues.ref_pull_from=`αναφέρθηκε σε αυτό το pull request %[3]s %[1]s`
+issues.ref_closing_from=`ανέφερε αυτό το ζήτημα σε ένα pull request %[3]s που στοχεύει να κλείσει το ζήτημα %[1]s`
+issues.ref_reopening_from=`αναφέρθηκε σε αυτό το ζήτημα σε ένα pull request %[3]s που θα ξαναανοίξει αυτό το ζήτημα %[1]s`
issues.ref_closed_from=`έκλεισε αυτό το ζήτημα %[4]s %[2]s`
issues.ref_reopened_from=`άνοιξε ξανά αυτό το ζήτημα %[4]s %[2]s`
issues.ref_from=`από %[1]s`
@@ -1939,8 +1939,8 @@ pulls.update_branch_success=Η ενημέρωση του κλάδου ήταν
pulls.update_not_allowed=Δεν επιτρέπεται να ενημερώσετε τον κλάδο
pulls.outdated_with_base_branch=Αυτός ο κλάδος δεν είναι ενημερωμένος με τον βασικό κλάδο
pulls.close=Κλείσιμο pull request
-pulls.closed_at=`έκλεισε αυτό το pull request %[2]s`
-pulls.reopened_at=`άνοιξε ξανά αυτό το pull request %[2]s`
+pulls.closed_at=`έκλεισε αυτό το pull request %s`
+pulls.reopened_at=`άνοιξε ξανά αυτό το pull request %s`
pulls.cmd_instruction_hint=Προβολή οδηγιών γραμμής εντολών
pulls.cmd_instruction_checkout_title=Έλεγχος
pulls.cmd_instruction_checkout_desc=Από το repository του έργου σας, ελέγξτε έναν νέο κλάδο και δοκιμάστε τις αλλαγές.
@@ -2720,7 +2720,7 @@ settings.new_owner_blocked_doer = Ο νέος κάτοχος του αποθετ
settings.enter_repo_name = Γράψτε το όνομα του κατόχου και του αποθετηρίου ακριβώς όπως το βλέπετε:
settings.confirmation_string = Κείμενο επιβεβαίωσης
settings.units.overview = Επισκόπηση
-pulls.commit_ref_at = `ανέφερε το pull request στο commit %[2]s`
+pulls.commit_ref_at = `ανέφερε το pull request στο commit %s`
contributors.contribution_type.filter_label = Είδος συνεισφοράς:
settings.wiki_rename_branch_main_notices_1 = Αυτή η ενέργεια ΔΕΝ αναιρείται.
activity.navbar.contributors = Συνεισφέροντες
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 7479ab80af..5fd2ebd163 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -768,8 +768,8 @@ update_profile_success = Your profile has been updated.
change_username = Your username has been changed.
change_username_prompt = Note: Changing your username also changes your account URL.
change_username_redirect_prompt = The old username will redirect until someone claims it.
-change_username_redirect_prompt.with_cooldown.one = The old username will be available to everyone after a cooldown period of %[1]d day, you can still reclaim the old username during the cooldown period.
-change_username_redirect_prompt.with_cooldown.few = The old username will be available to everyone after a cooldown period of %[1]d days, you can still reclaim the old username during the cooldown period.
+change_username_redirect_prompt.with_cooldown.one = The old username will be available to everyone after a cooldown period of %[1]d day. You can still reclaim the old username during the cooldown period.
+change_username_redirect_prompt.with_cooldown.few = The old username will be available to everyone after a cooldown period of %[1]d days. You can still reclaim the old username during the cooldown period.
continue = Continue
cancel = Cancel
language = Language
@@ -1610,7 +1610,7 @@ issues.remove_ref_at = `removed reference %s %s`
issues.add_ref_at = `added reference %s %s`
issues.delete_branch_at = `deleted branch %s %s`
issues.filter_label = Label
-issues.filter_label_exclude = `Use alt
+ click/enter
to exclude labels`
+issues.filter_label_exclude = Use Alt + Click to exclude labels
issues.filter_label_no_select = All labels
issues.filter_label_select_no_label = No label
issues.filter_milestone = Milestone
@@ -1628,6 +1628,7 @@ issues.filter_poster = Author
issues.filter_poster_no_select = All authors
issues.filter_type = Type
issues.filter_type.all_issues = All issues
+issues.filter_type.all_pull_requests = All pull requests
issues.filter_type.assigned_to_you = Assigned to you
issues.filter_type.created_by_you = Created by you
issues.filter_type.mentioning_you = Mentioning you
@@ -1693,15 +1694,13 @@ issues.close_comment_issue = Close with comment
issues.reopen_issue = Reopen
issues.reopen_comment_issue = Reopen with comment
issues.create_comment = Comment
-issues.closed_at = `closed this issue %[2]s`
-issues.reopened_at = `reopened this issue %[2]s`
-issues.commit_ref_at = `referenced this issue from a commit %[2]s`
-issues.ref_issue_from = `referenced this issue %[4]s %[2]s`
-issues.ref_pull_from = `referenced this pull request %[4]s %[2]s`
-issues.ref_closing_from = `referenced this issue from a pull request %[4]s that will close it, %[2]s`
-issues.ref_reopening_from = `referenced this issue from a pull request %[4]s that will reopen it, %[2]s`
-issues.ref_closed_from = `closed this issue %[4]s %[2]s`
-issues.ref_reopened_from = `reopened this issue %[4]s %[2]s`
+issues.closed_at = `closed this issue %s`
+issues.reopened_at = `reopened this issue %s`
+issues.commit_ref_at = `referenced this issue from a commit %s`
+issues.ref_issue_from = `referenced this issue %[3]s %[1]s`
+issues.ref_pull_from = `referenced this pull request %[3]s %[1]s`
+issues.ref_closing_from = `referenced this issue from a pull request %[3]s that will close it, %[1]s`
+issues.ref_reopening_from = `referenced this issue from a pull request %[3]s that will reopen it, %[1]s`
issues.ref_from = `from %[1]s`
issues.author = Author
issues.author.tooltip.issue = This user is the author of this issue.
@@ -2013,9 +2012,9 @@ pulls.update_branch_success = Branch update was successful
pulls.update_not_allowed = You are not allowed to update branch
pulls.outdated_with_base_branch = This branch is out-of-date with the base branch
pulls.close = Close pull request
-pulls.closed_at = `closed this pull request %[2]s`
-pulls.reopened_at = `reopened this pull request %[2]s`
-pulls.commit_ref_at = `referenced this pull request from a commit %[2]s`
+pulls.closed_at = `closed this pull request %s`
+pulls.reopened_at = `reopened this pull request %s`
+pulls.commit_ref_at = `referenced this pull request from a commit %s`
pulls.cmd_instruction_hint = View command line instructions
pulls.cmd_instruction_checkout_title = Checkout
pulls.cmd_instruction_checkout_desc = From your project repository, check out a new branch and test the changes.
@@ -2932,8 +2931,8 @@ settings.update_settings = Update settings
settings.update_setting_success = Organization settings have been updated.
settings.change_orgname_prompt = Note: Changing the organization name will also change your organization's URL and free the old name.
settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed.
-settings.change_orgname_redirect_prompt.with_cooldown.one = The old organization name will be available to everyone after a cooldown period of %[1]d day, you can still reclaim the old name during the cooldown period.
-settings.change_orgname_redirect_prompt.with_cooldown.few = The old organization name will be available to everyone after a cooldown period of %[1]d days, you can still reclaim the old name during the cooldown period.
+settings.change_orgname_redirect_prompt.with_cooldown.one = The old organization name will be available to everyone after a cooldown period of %[1]d day. You can still reclaim the old name during the cooldown period.
+settings.change_orgname_redirect_prompt.with_cooldown.few = The old organization name will be available to everyone after a cooldown period of %[1]d days. You can still reclaim the old name during the cooldown period.
settings.update_avatar_success = The organization's avatar has been updated.
settings.delete = Delete organization
settings.delete_account = Delete this organization
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index f912409cc9..bdafba93b4 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -1648,13 +1648,13 @@ issues.close_comment_issue=Cerrar con comentario
issues.reopen_issue=Reabrir
issues.reopen_comment_issue=Reabrir con comentario
issues.create_comment=Comentar
-issues.closed_at=`cerró esta incidencia %[2]s`
-issues.reopened_at=`reabrió esta incidencia %[2]s`
-issues.commit_ref_at=`referenció esta incidencia en un commit %[2]s`
-issues.ref_issue_from=`referenció esta incidencia %[4]s %[2]s`
-issues.ref_pull_from=`referenció este pull request %[4]s %[2]s`
-issues.ref_closing_from=`hizo referencia a esta incidencia desde un pull request %[4]s que lo cerrará , %[2]s`
-issues.ref_reopening_from=`hizo referencia a esta incidencia desde un pull request %[4]s que lo reabrirá, %[2]s`
+issues.closed_at=`cerró esta incidencia %s`
+issues.reopened_at=`reabrió esta incidencia %s`
+issues.commit_ref_at=`referenció esta incidencia en un commit %s`
+issues.ref_issue_from=`referenció esta incidencia %[3]s %[1]s`
+issues.ref_pull_from=`referenció este pull request %[3]s %[1]s`
+issues.ref_closing_from=`hizo referencia a esta incidencia desde un pull request %[3]s que lo cerrará , %[1]s`
+issues.ref_reopening_from=`hizo referencia a esta incidencia desde un pull request %[3]s que lo reabrirá, %[1]s`
issues.ref_closed_from=`cerró esta incidencia %[4]s %[2]s`
issues.ref_reopened_from=`reabrió esta incidencia %[4]s %[2]s`
issues.ref_from=`de %[1]s`
@@ -1959,8 +1959,8 @@ pulls.update_branch_success=La actualización de la rama ha finalizado correctam
pulls.update_not_allowed=No tiene permisos para actualizar esta rama
pulls.outdated_with_base_branch=Esta rama está desactualizada con la rama base
pulls.close=Cerrar pull request
-pulls.closed_at=`cerró este pull request %[2]s`
-pulls.reopened_at=`reabrió este pull request %[2]s`
+pulls.closed_at=`cerró este pull request %s`
+pulls.reopened_at=`reabrió este pull request %s`
pulls.clear_merge_message=Borrar mensaje de fusión
pulls.clear_merge_message_hint=Limpiar el mensaje de fusión solo eliminará el contenido del mensaje de commit y mantendrá frases generadas como "Co-Autorizado por …".
@@ -2789,7 +2789,7 @@ pulls.status_checks_hide_all = Ocultar todas las verificaciones
settings.federation_not_enabled = La federación no está habilitada en tu instancia.
wiki.search = Buscar en wiki
pulls.status_checks_show_all = Mostrar todas las verificaciones
-pulls.commit_ref_at = `hizo referencia a este pull request desde un commit %[2]s`
+pulls.commit_ref_at = `hizo referencia a este pull request desde un commit %s`
pulls.cmd_instruction_merge_title = Fusionar
contributors.contribution_type.deletions = Eliminaciones
contributors.contribution_type.filter_label = Tipo de contribución:
diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini
index 804b48b2b2..dae0695495 100644
--- a/options/locale/locale_fa-IR.ini
+++ b/options/locale/locale_fa-IR.ini
@@ -1250,13 +1250,13 @@ issues.close_comment_issue=ثبت دیدگاه و بستن
issues.reopen_issue=بازگشایی
issues.reopen_comment_issue=ثبت دیدگاه و بازگشایی
issues.create_comment=دیدگاه
-issues.closed_at=`%[2]s این موضوع را بست`
-issues.reopened_at=`%[2]s این موضوع را دوباره باز کرد`
-issues.commit_ref_at=`ارجاع این مسئله به کامیت %[2]s`
-issues.ref_issue_from=` ارجاعات این مسائله %[4] %[2]s`
-issues.ref_pull_from=` ارجاعات این تقاضای ادغام %[4] %[2]s`
-issues.ref_closing_from=` ارجاعات این تقاضای واکشی %[4] %[2]s`
-issues.ref_reopening_from=` تقاضای واکشی ارجاع شده %[4] که مسائله بازگشایی خواهد کرد %[2] `
+issues.closed_at=`%s این موضوع را بست`
+issues.reopened_at=`%s این موضوع را دوباره باز کرد`
+issues.commit_ref_at=`ارجاع این مسئله به کامیت %s`
+issues.ref_issue_from=` ارجاعات این مسائله %[3] %[1]s`
+issues.ref_pull_from=` ارجاعات این تقاضای ادغام %[4] %[1]s`
+issues.ref_closing_from=` ارجاعات این تقاضای واکشی %[4] %[1]s`
+issues.ref_reopening_from=` تقاضای واکشی ارجاع شده %[3]sکه مسائله بازگشایی خواهد کرد %[2] `
issues.ref_closed_from=` بسته شده این مسائله %[4] %[2]s`
issues.ref_reopened_from=` بازگشایی این مسائله %[4] %[2]s`
issues.ref_from=`از %[1]`
@@ -1493,8 +1493,8 @@ pulls.update_branch_rebase=بروزآوری شاخه با بازسازی مجد
pulls.update_branch_success=شاخه به موفقیت بروز شد
pulls.update_not_allowed=شما اجازه بروزرسانی شاخه را ندارید
pulls.outdated_with_base_branch=این شاخه با شاخه پایه منسوخ شده است
-pulls.closed_at=`این درخواست pull بسته شده %[2]s`
-pulls.reopened_at=`این درخواست pull را بازگشایی کرد %[2]s`
+pulls.closed_at=`این درخواست pull بسته شده %s`
+pulls.reopened_at=`این درخواست pull را بازگشایی کرد %s`
diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini
index cff940a05a..164a60cc8d 100644
--- a/options/locale/locale_fi-FI.ini
+++ b/options/locale/locale_fi-FI.ini
@@ -1293,9 +1293,9 @@ issues.close_comment_issue=Kommentoi ja sulje
issues.reopen_issue=Avaa uudelleen
issues.reopen_comment_issue=Kommentoi ja avaa uudelleen
issues.create_comment=Kommentoi
-issues.closed_at=`sulki tämän ongelman %[2]s`
-issues.reopened_at=`uudelleenavasi tämän ongelman %[2]s`
-issues.commit_ref_at=`viittasi tähän ongelmaan kommitissa %[2]s`
+issues.closed_at=`sulki tämän ongelman %s`
+issues.reopened_at=`uudelleenavasi tämän ongelman %s`
+issues.commit_ref_at=`viittasi tähän ongelmaan kommitissa %s`
issues.author=Tekijä
issues.role.owner=Omistaja
issues.role.member=Jäsen
@@ -2185,7 +2185,7 @@ settings.confirmation_string = Vahvistusteksti
settings.delete_notices_2 = - Tämä toiminto poistaa pysyvästi tietovaraston %s mukaan lukien koodin, ongelmat, kommentit, wikidatan ja avustaja-asetukset.
issues.filter_assginee_no_select = Kaikki käsittelijät
issues.new.assign_to_me = Osoita itselle
-pulls.closed_at = `sulki tämän vetopyynnön %[2]s`
+pulls.closed_at = `sulki tämän vetopyynnön %s`
tree_path_not_found_branch = Polkua %[1]s ei ole olemassa haarassa %[2]s
transfer.no_permission_to_reject = Sinulla ei ole oikeutta hylätä tätä siirtoa.
generate_repo = Luo tietovarasto
@@ -2199,8 +2199,8 @@ issues.new.no_reviewers = Ei katselmoijia
issues.add_label = lisäsi nimilapun %s %s
issues.due_date_added = lisäsi eräpäivän %s %s
issues.review.add_review_request = pyysi katselmointia käyttäjältä %[1]s %[2]s
-issues.ref_pull_from = `viittasi tähän vetopyyntöön %[4]s %[2]s`
-pulls.commit_ref_at = `viittasi tähän vetopyyntöön kommitista %[2]s`
+issues.ref_pull_from = `viittasi tähän vetopyyntöön %[3]s %[1]s`
+pulls.commit_ref_at = `viittasi tähän vetopyyntöön kommitista %s`
issues.review.comment = katselmoi %s
issues.add_labels = lisäsi nimilaput %s %s
issues.review.add_review_requests = pyysi katselmointeja käyttäjiltä %[1]s %[2]s
@@ -2381,7 +2381,7 @@ wiki.page_name_desc = Kirjoita tämän wikisivun nimi. Joitain erikoisnimiä ova
pulls.blocked_by_changed_protected_files_1 = Tämä vetopyyntö sisältää suojatun tiedoston ja on siksi estetty:
pulls.status_checks_warning = Jotkin tarkistukset raportoivat varoituksia
pulls.status_checks_error = Jotkin tarkistukset raportoivat virheitä
-pulls.reopened_at = `avasi uudelleen tämän vetopyynnön %[2]s`
+pulls.reopened_at = `avasi uudelleen tämän vetopyynnön %s`
pulls.auto_merge_when_succeed = Yhdistä automaatisesti kun kaikki tarkistukset onnistuvat
signing.wont_sign.error = Tapahtui virhe tarkistaessa voiko kommitin allekirjoittaa.
signing.wont_sign.twofa = Sinulla tulee olla kaksivaiheinen todennus käytössä, jotta kommitit voi allekirjoittaa.
diff --git a/options/locale/locale_fil.ini b/options/locale/locale_fil.ini
index 1dbfb588f0..8c9badb04b 100644
--- a/options/locale/locale_fil.ini
+++ b/options/locale/locale_fil.ini
@@ -365,7 +365,7 @@ table_modal.label.columns = Mga Column
link_modal.header = Magdagdag ng link
link_modal.url = Url
link_modal.description = Deskripsyon
-link_modal.paste_reminder = Pahiwatig: Kapag may URL sa clipboard, maari mong direktang i-paste sa editor para gumawa ng link.
+link_modal.paste_reminder = Pahiwatig: Kapag may URL sa clipboard, maaari mong direktang i-paste sa editor para gumawa ng link.
[filter]
string.asc = A - Z
@@ -432,7 +432,7 @@ openid_connect_desc = Ang piniling OpenID URI ay hindi alam. Iugnay iyan sa bago
invalid_code = Ang iyong confirmation code ay hindi wasto o nag-expire na.
oauth_signin_title = Mag-sign in para pahintulutan ang naka-link na account
invalid_code_forgot_password = Ang iyong confirmation code ay hindi wasto o nag-expire na. Mag-click dito para magsimula ng bagong session.
-confirmation_mail_sent_prompt = Ang isang bagong email na pang-kumpirma ay ipinadala sa %s. Para kumpletuhin ang proseso ng pagrehistro, pakisuri ang iyong inbox at sundan ang ibinigay na link sa loob ng %s. Kung mali ang email, maari kang mag-log in, at humingi ng isa pang email pang-kumpirma na ipapadala sa ibang address.
+confirmation_mail_sent_prompt = Ang isang bagong email na pang-kumpirma ay ipinadala sa %s. Para kumpletuhin ang proseso ng pagrehistro, pakisuri ang iyong inbox at sundan ang ibinigay na link sa loob ng %s. Kung mali ang email, maaari kang mag-log in, at humingi ng isa pang email pang-kumpirma na ipapadala sa ibang address.
invalid_password = Ang iyong password ay hindi tugma sa password na ginamit para gawin ang account.
twofa_scratch_used = Ginamit mo na ang scratch code. Na-redirect ka sa two-factor settings page para tanggalin ang device enrollment o mag-generate ng bagong scratch code.
manual_activation_only = Makipag-ugnayan sa tagapangangasiwa ng site para kumpletuhin ang pagrehistro.
@@ -484,7 +484,7 @@ admin.new_user.text = Mangyaring mag-click dito para ipamahala
register_notify = Maligayang Pagdating sa %s
register_notify.title = %[1]s, maligayang pagdating sa %[2]s
register_notify.text_1 = ito ang iyong registration confirmation email para sa %s!
-register_notify.text_2 = Maari kang mag-sign in sa iyong account gamit ng iyong username: %s
+register_notify.text_2 = Maaari kang mag-sign in sa iyong account gamit ng iyong username: %s
reset_password = I-recover ang iyong account
reset_password.title = %s, nagkaroon kami ng hiling para i-recover ang iyong account
reset_password.text = Kung ikaw ito, paki-click ang sumusunod na link para i-recover ang iyong account sa loob ng %s:
@@ -535,7 +535,7 @@ totp_disabled.text_1 = Ngayon lang na-disable ang Time-based one-time password (
totp_disabled.no_2fa = Wala nang mga ibang paraan ng 2FA ang naka-configure, nangangahulugan na hindi na kailangang mag-log in sa iyong account gamit ang 2FA.
removed_security_key.subject = May tinanggal na security key
removed_security_key.text_1 = Tinanggal ngayon lang ang security key na "%[1]s" sa iyong account.
-account_security_caution.text_1 = Kung ikaw ito, maari mong ligtas na huwag pansinin ang mail na ito.
+account_security_caution.text_1 = Kung ikaw ito, maaari mong ligtas na huwag pansinin ang mail na ito.
account_security_caution.text_2 = Kung hindi ito ikaw, nakompromiso ang iyong account. Mangyaring makipag-ugnayan sa mga tagapangasiwa ng site na ito.
totp_enrolled.subject = Nag-activate ka ng TOTP bilang paraan ng 2FA
totp_enrolled.text_1.has_webauthn = Na-enable mo lang ang TOTP para sa iyong account. Nangangahulugan ito na para sa lahat ng mga hinaharap na pag-login sa iyong account, kailangan mong gumamit ng TOTP bilang paraan ng 2FA o gamitin ang iyong mga security key.
@@ -644,7 +644,7 @@ AccessToken = Token ng pag-access
Biography = Byograpya
Location = Lokasyon
visit_rate_limit = Natugunan ang limitasyon sa rate ng malayuang pagbisita.
-username_claiming_cooldown = Hindi ma-claim ang username na ito, dahil hindi pa tapos ang panahon ng cooldown. Maari itong i-claim sa %[1]s.
+username_claiming_cooldown = Hindi ma-claim ang username na ito, dahil hindi pa tapos ang panahon ng cooldown. Maaari itong i-claim sa %[1]s.
email_domain_is_not_allowed = Sumasalungat ang domain ng email address ng user %s sa EMAIL_DOMAIN_ALLOWLIST o EMAIL_DOMAIN_BLOCKLIST. Siguraduhing natakda mo ang email address nang tama.
[user]
@@ -685,7 +685,7 @@ followers.title.few = Mga tagasunod
following.title.one = Sinusundan
followers.title.one = Tagasunod
public_activity.visibility_hint.self_public = Nakikita ng lahat ang iyong aktibidad, maliban sa mga interaksyon sa pribadong espasyo. I-configure.
-public_activity.visibility_hint.admin_public = Nakikita ng lahat ang aktibidad na ito, ngunit bilang tagapangasiwa maari mo ring makita ang mga interaksyon sa mga pribadong espasyo.
+public_activity.visibility_hint.admin_public = Nakikita ng lahat ang aktibidad na ito, ngunit bilang tagapangasiwa maaari mo ring makita ang mga interaksyon sa mga pribadong espasyo.
public_activity.visibility_hint.self_private = Nakikita mo lang at mga tagapangasiwa ng instansya ang iyong aktibidad. I-configure.
public_activity.visibility_hint.admin_private = Nakikita mo ang aktibidad na ito dahil isa kang tagapangasiwa, ngunit gusto ng user na panatilihin itong pribado.
public_activity.visibility_hint.self_private_profile = Ikaw lang at ang mga tagapangasiwa ng instansya ang makakakita ng iyong aktibidad dahil pribado ang iyong profile. I-configure.
@@ -842,7 +842,7 @@ gpg_key_verify = I-verify
gpg_invalid_token_signature = Ang ibinigay na GPG key, signature, at token ay hindi tumutugma o luma.
gpg_token_required = Kailangan mong magbigay ng signature para sa token sa ibaba
gpg_token = Token
-gpg_token_help = Maari kang mag-generate ng signature gamit ng:
+gpg_token_help = Maaari kang mag-generate ng signature gamit ng:
gpg_token_signature = Naka-armor na GPG signature
key_signature_gpg_placeholder = Nagsisimula sa "-----BEGIN PGP SIGNATURE-----"
verify_gpg_key_success = Na-verify na ang GPG key na "%s".
@@ -851,7 +851,7 @@ ssh_key_verify = I-verify
ssh_invalid_token_signature = Ang ibinigay na SSH key, signature, o token ay hindi tumutugma o luma.
ssh_token_required = Kailangan mong magbigay ng signature para sa token sa ibaba
ssh_token = Token
-ssh_token_help = Maari kang mag-generate ng signature gamit ng:
+ssh_token_help = Maaari kang mag-generate ng signature gamit ng:
ssh_token_signature = Naka-armor na SSH signature
key_signature_ssh_placeholder = Nagsisimula sa "-----BEGIN SSH SIGNATURE-----"
verify_ssh_key_success = Na-verify na ang SSH key na "%s".
@@ -912,10 +912,10 @@ create_oauth2_application_success = Matagumpay kang gumawa ang bagong OAuth2 app
oauth2_confidential_client = Kumpidensyal na kliyente. Piliin para sa mga app na pinapatilihing kumpidensyal ang sikreto, tulad ng mga web app. Huwag piliin para sa mga web app kasama ang mga desktop at mobile app.
twofa_desc = Para protektahin ang iyong account laban sa pagnanakaw ng password, pwede mo gamitin ang iyong smartphone o ibang device para sa pagtanggap ng time-based one-time password ("TOTP").
twofa_scratch_token_regenerated = Ang iyong isang-beses na paggamit na recovery key ngayon ay %s. Ilagay ito sa ligtas na lugar, dahil hindi na ito ipapakita muli.
-regenerate_scratch_token_desc = Kapag nawala mo ang iyong recovery key o ginamit mo na oara mag-sign in, maari mong i-reset dito.
+regenerate_scratch_token_desc = Kapag nawala mo ang iyong recovery key o ginamit mo na oara mag-sign in, maaari mong i-reset dito.
twofa_disable_desc = Ang pag-disable ng authentikasyong two-factor ay gagawing hindi gaanong ligtas ang iyong account. Magpatuloy?
twofa_enrolled = Matagumpay na na-enroll ang iyong account. Ilagay ang iyong isang-beses na paggamit na recovery key (%s) sa isang ligtas na lugar, dahil hindi na ito ipapakita muli.
-webauthn_desc = Ang mga security key ay isang hardware device na naglalaman ng mga cryptographic key. Maari silang gamitin para sa authentikasyong two-factor. Ang mga security key ay dapat suportahan ang WebAuthn Authenticator na standard.
+webauthn_desc = Ang mga security key ay isang hardware device na naglalaman ng mga cryptographic key. Maaari silang gamitin para sa authentikasyong two-factor. Ang mga security key ay dapat suportahan ang WebAuthn Authenticator na standard.
remove_oauth2_application = Tanggalin ang OAuth2 Application
remove_oauth2_application_desc = Ang pagtanggal ng OAuth2 application ay babawiin ang access sa lahat ng mga naka-sign na access token. Magpatuloy?
remove_oauth2_application_success = Binura na ang application.
@@ -931,13 +931,13 @@ oauth2_regenerate_secret = I-regenerate ang sikreto
oauth2_regenerate_secret_hint = Nawala mo ang iyong sikreto?
oauth2_client_secret_hint = Ang sikreto ay hindi ipapakita muli pagkatapos umalis ka o i-refresh ang page na ito. Mangyaring siguraduhin na na-save mo iyan.
oauth2_application_edit = I-edit
-twofa_recovery_tip = Kapag mawala mo ang iyong device, maari kang gumamit ng isang isang-beses na paggamit na recovery key para makakuha muli ng access sa iyong account.
+twofa_recovery_tip = Kapag mawala mo ang iyong device, maaari kang gumamit ng isang isang-beses na paggamit na recovery key para makakuha muli ng access sa iyong account.
twofa_is_enrolled = Ang iyong account ay kasalukuyang naka-enroll sa autentikasyong two-factor.
twofa_not_enrolled = Kasalukuyang hindi naka-enroll ang iyong account sa authentikasyong two-factor.
twofa_disable = I-disable ang authentikasyong two-factor
twofa_scratch_token_regenerate = I-regenerate ang isang-beses na paggamit na recovery key
twofa_enroll = Mag-enroll sa authentikasyong two-factor
-twofa_disable_note = Maari mong i-disable ang authentikasyong two-factor kapag kinakailangan.
+twofa_disable_note = Maaari mong i-disable ang authentikasyong two-factor kapag kinakailangan.
twofa_disabled = Na-disable na ang authentikasyong two-factor.
scan_this_image = I-scan ang image na ito gamit ng iyong aplikasyong pang-authentikasyon:
or_enter_secret = O ilagay ang sikreto: %s
@@ -1005,8 +1005,8 @@ language.description = Mase-save ang wika sa iyong account at gagamitin bilang d
language.localization_project = Tulungan kaming isalin ang Forgejo sa iyong wika! Matuto pa.
pronouns_custom_label = Mga pasadyang pronoun
user_block_yourself = Hindi mo maaaring harangan ang sarili mo.
-change_username_redirect_prompt.with_cooldown.one = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
-change_username_redirect_prompt.with_cooldown.few = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
+change_username_redirect_prompt.with_cooldown.one = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw. Maaari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
+change_username_redirect_prompt.with_cooldown.few = Magiging available ang lumang username sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw. Maaari mo pa ring ma-claim muli ang lumang username sa panahon ng panahon ng cooldown.
keep_pronouns_private = Ipakita lang ang mga panghalip sa mga naka-authenticate na user
keep_pronouns_private.description = Itatago nito ang iyong mga panghalip mula sa mga bisita na hindi naka-log in.
quota.applies_to_user = Nag-aapply ang mga sumusunod na panuntunan ng quota sa iyong account
@@ -1071,7 +1071,7 @@ readme_helper_desc = Ito ang lugar kung saan makakasulat ka ng kumpletong deskri
trust_model_helper_collaborator_committer = Katulong+Committer: I-trust ang mga signature batay sa mga katulong na tumutugma sa committer
mirror_interval = Interval ng mirror (ang mga wastong unit ng oras ay "h", "m", "s"). 0 para i-disable ang periodic sync. (Pinakamababang interval: %s)
transfer.reject_desc = Kanselahin ang pag-transfer mula sa "%s"
-mirror_lfs_endpoint_desc = Ang sync ay susubukang gamitin ang clone url upang matukoy ang LFS server. Maari ka rin tumukoy ng isang custom na endpoint kapag ang LFS data ng repositoryo ay nilalagay sa ibang lugar.
+mirror_lfs_endpoint_desc = Ang sync ay susubukang gamitin ang clone url upang matukoy ang LFS server. Maaari ka rin tumukoy ng isang custom na endpoint kapag ang LFS data ng repositoryo ay nilalagay sa ibang lugar.
adopt_search = Ilagay ang username para maghanap ng mga unadopted na repositoryo… (iwanang walang laman para hanapin lahat)
object_format = Format ng object
readme_helper = Pumili ng README file template
@@ -1164,8 +1164,8 @@ tree_path_not_found_commit = Hindi umiiral ang path na %[1]s sa commit %[2]s
tree_path_not_found_branch = Hindi umiiral ang daanang %[1]s sa branch %[2]s
migrate_items_pullrequests = Mga hiling sa paghila
archive.pull.nocomment = Naka-archive ang repositoryong ito. Hindi ka makakakomento sa mga pull request.
-archive.title = Naka-archive ang repositoryong ito. Maari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado ito, tulad ng pagtulak at paggawa ng mga isyu, pull request o mga komento.
-archive.title_date = Naka-archive ang repositoryo na ito noong %s. Maari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado nito, tulad ng pagtulak o paggawa ng mga bagong isyu, mga pull request, o komento.
+archive.title = Naka-archive ang repositoryong ito. Maaari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado ito, tulad ng pagtulak at paggawa ng mga isyu, pull request o mga komento.
+archive.title_date = Naka-archive ang repositoryo na ito noong %s. Maaari mong itignan ang mga file at i-clone ito, pero hindi ka makakagawa ng anumang pagbabago sa estado nito, tulad ng pagtulak o paggawa ng mga bagong isyu, mga pull request, o komento.
pulls = Mga hiling sa paghila
activity.merged_prs_count_n = Mga naisamang hiling sa paghila
wiki.last_updated = Huling binago %s
@@ -1183,7 +1183,7 @@ issues.action_open = Buksan
issues.closed_title = Sarado
issues.reopen_issue = Buksang muli
pulls.merged = Naisama na
-pulls.merged_info_text = Maari nang burahin ang branch %s.
+pulls.merged_info_text = Maaari nang burahin ang branch %s.
milestones.update_ago = Binago %s
activity.closed_issue_label = Sarado
activity.merged_prs_label = Naisama
@@ -1205,7 +1205,7 @@ migrate.clone_address_desc = Ang HTTP(S) o Git "clone" URL ng umiiral na reposit
need_auth = Awtorisasyon
migrate.github_token_desc = Maaari kang maglagay ng isa o higit pang mga token na hinihiwalay ng kuwit dito upang gawing mas-mabilis ang pagmigrate dahil sa rate limit ng GitHub API. BABALA: Ang pagabuso ng feature na ito ay maaaring maglabag sa patakaran ng tagapagbigay ng serbisyo at maaaring magdulot ng pag-block ng account.
template.invalid = Kailangang pumili ng kahit isang template na repositoryo
-migrate_options_lfs_endpoint.description = Susubukan ng migration na gamitin ang iyong Git remote upang matukoy ang LFS server. Maari mong magtiyak ng custom na endpoint kapag ang LFS data ng repositoryo ay nakalagay sa ibang lugar.
+migrate_options_lfs_endpoint.description = Susubukan ng migration na gamitin ang iyong Git remote upang matukoy ang LFS server. Maaari mong magtiyak ng custom na endpoint kapag ang LFS data ng repositoryo ay nakalagay sa ibang lugar.
blame.ignore_revs.failed = Nabigong hindi pansinin ang mga rebisyon sa .git-blame-ignore-revs.
tree_path_not_found_tag = Hindi umiiral ang path na %[1]s sa tag %[2]s
form.reach_limit_of_creation_n = Naabot na ng may-ari ang limitasyon na %d mga repositoryo.
@@ -1471,10 +1471,10 @@ activity.new_issue_label = Nabuksan
activity.merged_prs_count_1 = Naisamang hiling sa paghila
activity.opened_prs_count_1 = Inimungkahing hiling sa paghila
activity.opened_prs_label = Inimungkahi
-pulls.reopened_at = `nabuksang muli ang hiling sa paghatak na %[2]s`
+pulls.reopened_at = `binuksan muli ang hiling sa paghila %s`
issues.opened_by_fake = binuksan ang %[1]s ni/ng %[2]s
pulls.reopen_failed.base_branch = Hindi mabuksang muli ang hiling sa paghatak na ito dahil hindi na umiiral ang base branch.
-issues.reopened_at = `binuksang muli ang isyung ito %[2]s`
+issues.reopened_at = `binuksang muli ang isyung ito %s`
pulls.reopen_failed.head_branch = Hindi mabubuksan muli ang hiling sa paghila, dahil hindi na umiiral ang head branch.
settings.event_pull_request_desc = Binuksan, sinara, muling binuksan, o binago ang hiling sa paghatak.
activity.opened_prs_count_n = Mga inimungkahing hiling sa paghila
@@ -1500,7 +1500,7 @@ issues.content_history.created = ginawa
editor.patching = Pina-patch:
editor.fail_to_apply_patch = Hindi malapat ang patch na "%s"
settings.danger_zone = Mapanganib na lugar
-issues.closed_at = `isinara ang isyung %[2]s`
+issues.closed_at = `isinara ang isyung ito %s`
settings.collaboration.admin = Tagapangasiwa
settings.admin_settings = Mga setting ng tagapangasiwa
issues.start_tracking_history = `sinimulan ang trabaho %s`
@@ -1627,7 +1627,7 @@ projects.column.edit_title = Pangalan
projects.column.new_title = Pangalan
projects.card_type.desc = Mga preview ng card
commits.desc = I-browse ang history ng pagbabago ng source code.
-commits.search.tooltip = Maari kang mag-prefix ng mga keyword gamit ang "author:", "committer:", "after:", o "before:", hal. "revert author:Nijika before:2022-10-09".
+commits.search.tooltip = Maaari kang mag-prefix ng mga keyword gamit ang "author:", "committer:", "after:", o "before:", hal. "revert author:Nijika before:2022-10-09".
issues.force_push_codes = `puwersahang itinulak ang %[1]s mula %[2]s
sa %[4]s
%[6]s`
issues.push_commit_1 = idinagdag ang %d commit %s
issues.push_commits_n = idinagdag ang %d mga commit %s
@@ -1707,7 +1707,7 @@ issues.action_milestone = Milestone
issues.action_milestone_no_select = Walang milestone
issues.delete_branch_at = `binura ang branch na %s %s`
issues.filter_label = Label
-issues.filter_label_exclude = `Gamitin ang alt
+ click/enter
para hindi isama ang mga label`
+issues.filter_label_exclude = `Gamitin ang Alt + Click para hindi isama ang mga label`
issues.filter_label_no_select = Lahat ng mga label
issues.filter_milestone_closed = Mga nakasarang milestone
issues.filter_assignee = Mangangasiwa
@@ -1771,7 +1771,7 @@ issues.lock = I-lock ang usapan
issues.unlock = I-unlock ang usapan
issues.unlock_comment = na-unlock ang usapang ito %s
issues.unlock.notice_1 = - Makakakomento muli ang lahat ng mga tao sa isyung ito.
-issues.unlock.notice_2 = - Maari mong i-lock muli ang isyung ito sa hinaharap.
+issues.unlock.notice_2 = - Maaari mong i-lock muli ang isyung ito sa hinaharap.
issues.comment_on_locked = Hindi ka makakakomento sa naka-lock na isyu.
issues.closed_by_fake = ni/ng %[2]s ay isinara %[1]s
issues.comment_manually_pull_merged_at = manwal na isinama ang commit %[1]s sa %[2]s %[3]s
@@ -1787,10 +1787,10 @@ issues.label_archive_tooltip = Ang mga naka-archive na label ay hindi isasama bi
issues.is_stale = May mga pagbabago sa PR na ito mula sa pagsuri na ito
issues.role.first_time_contributor = Unang-beses na contributor
issues.lock.notice_1 = - Hindi makakadagdag ng mga bagong komento ang mga ibang user sa isyu na ito.
-issues.lock.notice_3 = - Maari mong i-unlock muli ang isyung ito sa hinaharap.
+issues.lock.notice_3 = - Maaari mong i-unlock muli ang isyung ito sa hinaharap.
issues.label_deletion_desc = Ang pagbura ng label ay tatanggalin ito sa lahat ng mga isyu. Magpatuloy?
-issues.commit_ref_at = `isinangguni ang isyu na ito mula sa commit %[2]s`
-issues.ref_issue_from = `isinangguni ang isyu na ito sa %[4]s %[2]s`
+issues.commit_ref_at = `isinangguni ang isyu na ito mula sa commit %s`
+issues.ref_issue_from = `isinangguni ang isyu na ito sa %[3]s %[1]s`
issues.num_participants_one = %d kasali
issues.attachment.download = `I-click para i-download ang "%s" `
issues.num_participants_few = %d mga kasali
@@ -1815,10 +1815,10 @@ issues.sign_in_require_desc = Mag-sign in upang sumali sa usapa
issues.num_comments = %d mga komento
issues.role.contributor_helper = Nakaraang nag-commit ang user na ito sa repositoryo na ito.
issues.comment_pull_merged_at = isinama ang commit %[1]s sa %[2]s %[3]s
-pulls.commit_ref_at = `isinangguni ang hiling sa paghila mula sa isang commit %[2]s`
+pulls.commit_ref_at = `isinangguni ang hiling sa paghila mula sa isang commit %s`
wiki.last_commit_info = Binago ni %s ang pahinang ito %s
issues.content_history.edited = binago
-issues.ref_pull_from = `isinangguni ang hiling sa paghila na ito %[4]s %[2]s`
+issues.ref_pull_from = `isinangguni ang hiling sa paghila na ito %[3]s %[1]s`
pulls.merged_title_desc_few = isinali ang %[1]d mga commit mula sa %[2]s
patungong %[3]s
%[4]s
settings.org_not_allowed_to_be_collaborator = Hindi maaaring idagdag ang mga organisasyon bilang tagatulong.
settings.add_collaborator_success = Naidagdag ang tagatulong.
@@ -1828,7 +1828,7 @@ pulls.create = Gumawa ng hiling sa paghila
issues.dependency.pr_close_blocked = Kailangan mong isara ang lahat ng mga isyu na humaharang sa hiling sa paghila na ito bago mo ito isama.
pulls.delete.title = Burahin ang hiling sa paghila na ito?
issues.dependency.pr_closing_blockedby = Hinarang ng mga sumusunod na isyu mula sa pagsara ng hiling sa paghila na ito
-pulls.closed_at = `isinara ang hiling sa paghila na %[2]s`
+pulls.closed_at = `isinara ang hiling sa paghila na ito %s`
pulls.close = Isara ang hiling sa paghila
pulls.cmd_instruction_hint = Tingnan ang mga panuto para sa command line
project = Mga proyekto
@@ -1836,8 +1836,8 @@ issues.content_history.deleted = binura
pulls.no_results = Walang mga nahanap na resulta.
pulls.closed = Sarado ang hiling sa paghila
pulls.is_closed = Naisara na ang hiling sa paghila.
-issues.ref_closing_from = `nagsangguni ang isyu mula sa hiling sa paghila %[4]s na magsasara sa isyu, %[2]s`
-issues.ref_reopening_from = `nagsangguni ang isyu na ito mula sa hiling sa paghila %[4]s na muling bubukas, %[2]s`
+issues.ref_closing_from = `nagsangguni ang isyu mula sa hiling sa paghila %[3]s na magsasara sa isyu, %[1]s`
+issues.ref_reopening_from = `nagsangguni ang isyu na ito mula sa hiling sa paghila %[3]s na muling bubukas nito, %[1]s`
issues.ref_closed_from = `isinara ang isyung ito %[4]s%[2]s`
issues.review.wait = hiniling sa pagsuri %s
issues.review.reject = hinihiling ang mga pagbago %s
@@ -2015,14 +2015,14 @@ wiki.cancel = Kanselahin
settings.collaboration.undefined = Hindi Natukoy
settings.federation_settings = Mga Setting ng Federation
settings = Mga Setting
-settings.desc = Ang mga setting ang lugar kung saan maari mong ipamahala ang mga setting para sa repositoryo
+settings.desc = Ang mga setting ang lugar kung saan maaari mong ipamahala ang mga setting para sa repositoryo
pulls.collapse_files = I-collapse ang lahat ng mga file
pulls.add_prefix = Magdagdag ng %s na prefix
pulls.still_in_progress = Ginagawa pa?
activity.title.prs_1 = %d hiling sa paghila
activity.active_issues_count_n = %d mga aktibong isyu
pulls.required_status_check_missing = Nawawala ang ilang mga kinakailangang pagsusuri.
-pulls.required_status_check_administrator = Bilang tagapangasiwa, maari mo pa ring isama ang hiling sa paghila na ito.
+pulls.required_status_check_administrator = Bilang tagapangasiwa, maaari mo pa ring isama ang hiling sa paghila na ito.
pulls.blocked_by_approvals = Wala pang sapat na pag-apruba ang hiling sa paghila na ito. %d ng %d na pag-apruba ang ibinigay.
settings.options = Repositoryo
wiki.back_to_wiki = Bumalik sa pahina ng wiki
@@ -2110,7 +2110,7 @@ settings.actions_desc = I-enable ang mga kasamang CI/CD pipeline gamit ang Forge
settings.admin_indexer_commit_sha = Huling na-index na commit
settings.admin_indexer_unindexed = Hindi naka-index
settings.transfer_notices_3 = - Kung pribado ang repositoryo at ilipat sa isang indibidwal na user, ang aksyon na ito ay sinisigurado na ang user ay may pahintulot na basahin (at palitan ang mga pahintulot kung kailangan).
-settings.convert_desc = Maari mong i-convert ang repositoryo na ito sa regular na repositoryo. Hindi ito mababawi.
+settings.convert_desc = Maaari mong i-convert ang repositoryo na ito sa regular na repositoryo. Hindi ito mababawi.
settings.transfer.button = Ilipat ang pagmamay-ari
settings.signing_settings = Mga setting sa pagpapatunay ng pag-sign
settings.admin_enable_close_issues_via_commit_in_any_branch = Isara ang isyu sa pamamagitan ng commit na ginawa sa hindi default na branch
@@ -2137,7 +2137,7 @@ settings.deploy_key_deletion = Tanggalin ang deploy key
settings.protect_enable_push = I-enable ang pagtulak
settings.discord_icon_url.exceeds_max_length = Kailangang bababa o equal sa 2048 characters ang URL ng icon
settings.protected_branch.save_rule = I-save ang rule
-settings.mirror_settings.docs.can_still_use = Bagama't na hindi ka makakabago ng mga umiiral na mirror o gumawa ng bago, maari mo pa rin gamitin ang iyong umiiral na mirror.
+settings.mirror_settings.docs.can_still_use = Bagama't na hindi ka makakabago ng mga umiiral na mirror o gumawa ng bago, maaari mo pa rin gamitin ang iyong umiiral na mirror.
settings.slack_color = Kulay
settings.discord_icon_url = URL ng icon
settings.convert_fork_confirm = I-convert ang repositoryo
@@ -2254,7 +2254,7 @@ settings.pulls.allow_rebase_update = I-enable ang pag-update ng hiling sa paghil
settings.admin_enable_health_check = I-enable ang pagsusuri ng kalusugan ng repositoryo (git fsck)
settings.new_owner_has_same_repo = Ang bagong may-ari ay may repositoryo na may katulad na pangalan. Mangyaring pumili ng ibang pangalan.
settings.convert = I-convert sa regular na repositoryo
-settings.convert_fork_desc = Maari mong i-convert ang fork na ito bilang regular na repositoryo. Hindi ito mababawi.
+settings.convert_fork_desc = Maaari mong i-convert ang fork na ito bilang regular na repositoryo. Hindi ito mababawi.
settings.convert_fork_notices_1 = Ang operasyon na ito ay ico-convert ang fork bilang regular na repositoryo at hindi mababawi.
settings.transfer_abort_invalid = Hindi mo makakansela ang isang hindi umiiral na paglipat ng repositoryo.
settings.transfer_quota_exceeded = Ang bagong may-ari (%s) ay lumalagpas sa quota. Hindi nailipat ang repositoryo.
@@ -2290,8 +2290,8 @@ settings.webhook.headers = Mga header
settings.webhook.payload = Nilalaman
settings.webhook.body = Katawan
settings.webhook.replay.description = I-replay ang webhook na ito.
-settings.webhook.delivery.success = May nadagdag na event sa delivery queue. Maari magtagal ng ilang segundo bago makita sa delivery history.
-settings.githooks_desc = Pinapagana ng Git ang mga Git hook. Maari mong baguhin ang mga hook file sa ibaba para mag-set up ng mga custom na operasyon.
+settings.webhook.delivery.success = May nadagdag na event sa delivery queue. Maaari magtagal ng ilang segundo bago makita sa delivery history.
+settings.githooks_desc = Pinapagana ng Git ang mga Git hook. Maaari mong baguhin ang mga hook file sa ibaba para mag-set up ng mga custom na operasyon.
settings.githook_name = Pangalan ng hook
settings.githook_content = Nilalaman ng hook
settings.update_githook = I-update ang hook
@@ -2362,7 +2362,7 @@ settings.mirror_settings.docs.pull_mirror_instructions = Para mag-set up ng pull
milestones.invalid_due_date_format = Kailangang "yyyy-mm-dd" na format ang takdang petsa.
signing.wont_sign.nokey = Walang key ang instansya na ito para i-sign ang commit na ito.
activity.title.releases_1 = %d paglabas
-settings.mirror_settings.docs.more_information_if_disabled = Maari kang matuto pa tungkol sa mga push at pull na mirror dito:
+settings.mirror_settings.docs.more_information_if_disabled = Maaari kang matuto pa tungkol sa mga push at pull na mirror dito:
settings.branches.switch_default_branch = Magpalit ng default branch
settings.convert_notices_1 = Ang operasyon na ito ay ico-covert ang mirror sa regular na repositoryo at hindi mababawi.
settings.convert_fork_succeed = Na-convert na ang fork sa regular na repositoryo.
@@ -2732,7 +2732,7 @@ settings.protect_protected_file_patterns = Mga pattern ng nakaprotektang file (h
settings.update_protect_branch_success = Binago na ang branch protection rule na "%s".
settings.remove_protected_branch_success = Tinanggal ang branch protection rule na "%s".
settings.tags.protection.pattern = Pattern ng tag
-settings.tags.protection.pattern.description = Maari kang gumamit ng iisang pangalan o glob pattern o regular expression para magtugma ng maraming tag. Magbasa pa sa guide ng mga nakaprotektang tag.
+settings.tags.protection.pattern.description = Maaari kang gumamit ng iisang pangalan o glob pattern o regular expression para magtugma ng maraming tag. Magbasa pa sa guide ng mga nakaprotektang tag.
settings.thread_id = ID ng thread
settings.matrix.room_id = ID ng room
diff.has_escaped = May mga nakatagong Unicode character ang linya na ito
@@ -2746,7 +2746,7 @@ diff.bin = BIN
settings.default_update_style_desc = Ang default na istilio na gagamitin sa pag-update ng mga hiling sa paghila na nalilipas sa base branch.
pulls.sign_in_require = Mag-sign in para gumawa ng bagong hiling sa paghila.
new_from_template = Gumamit ng template
-new_from_template_description = Maari kang pumili ng umiiral na repository template sa instansya na ito at i-apply ang mga setting nito.
+new_from_template_description = Maaari kang pumili ng umiiral na repository template sa instansya na ito at i-apply ang mga setting nito.
new_advanced = Mga advanced na setting
new_advanced_expand = I-click para i-expand
auto_init_description = Simulan ang kasaysayan ng Git gamit ang README at opsyonal na magdagdag ng mga lisensya at .gitignore na file.
@@ -2777,6 +2777,10 @@ settings.event_header_action = Mga event sa run ng aksyon
settings.event_action_failure = Pagkabigo
settings.event_action_failure_desc = Natapos ang action run bilang pagkabigo.
settings.event_action_recover = I-recover
+settings.event_action_success = Matagumpay
+settings.event_action_success_desc = Matagumpay na natapos ang Action Run.
+settings.event_action_recover_desc = Matagumpay na natapos ang Action Run pagkatapos na nabigo ang huling Action Run sa katulad na workflow.
+issues.filter_type.all_pull_requests = Lahat ng mga hiling sa paghila
[search]
commit_kind = Maghanap ng mga commit…
@@ -3202,7 +3206,7 @@ self_check.database_collation_mismatch = Inaasahan ang database na gamitin ang c
auths.oauth2_admin_group = Group claim value para sa mga tagapangasiwa. (Opsyonal - kinakailangan ang claim name sa itaas)
auths.tip.facebook = Magrehistro ng bagong application sa %s at idagdag ang produktong "Facebook Login"
users.restricted.description = Payagan lamang ang interaksyon sa mga repositoryo at organisasyon kung saan ang user ay dinagdag bilang tagatulong. Iniiwasan nito ang pag-access sa publikong repositoryo sa instansya na ito.
-users.local_import.description = Payagan ang pag-import ng mga repositoryo mula sa local file system ng user. Maari itong maging isyu sa seguridad.
+users.local_import.description = Payagan ang pag-import ng mga repositoryo mula sa local file system ng user. Maaari itong maging isyu sa seguridad.
emails.delete = Burahin ang Email
emails.deletion_success = Binura na ang email address.
auths.oauth2_required_claim_value = Kinakailangan na claim value
@@ -3447,8 +3451,8 @@ teams.owners_permission_desc = Ang mga owner ay may punong access sa lah
teams.add_nonexistent_repo = Hindi pa umiiral ang repositoryo na sinusubukan mong idagdag. Mangyaring gawin iyan muna.
teams.all_repositories = Lahat ng mga repositoryo
teams.all_repositories_helper = Ang koponan ay may access sa lahat ng mga repositoryo. Ang pagpili nito ay idadagdag ang lahat ng mga umiiral na repositoryo sa koponan.
-settings.change_orgname_redirect_prompt.with_cooldown.few = Magiging available ang lumang pangalan ng organisasyon sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang pangalan sa panahon ng cooldown.
-settings.change_orgname_redirect_prompt.with_cooldown.one = Magiging available ang lumang pangalan ng organisasyon sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw, maari mo pa ring ma-claim muli ang lumang pangalan ng panahon ng cooldown.
+settings.change_orgname_redirect_prompt.with_cooldown.few = Magiging available ang lumang pangalan ng organisasyon sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw. Maaari mo pa ring ma-claim muli ang lumang pangalan sa panahon ng cooldown.
+settings.change_orgname_redirect_prompt.with_cooldown.one = Magiging available ang lumang pangalan ng organisasyon sa lahat pagkatapos ng panahon ng cooldown ng %[1]d araw. Maaari mo pa ring ma-claim muli ang lumang pangalan ng panahon ng cooldown.
[packages]
diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini
index 9ba91fc3a9..1cb7103bc0 100644
--- a/options/locale/locale_fr-FR.ini
+++ b/options/locale/locale_fr-FR.ini
@@ -1062,8 +1062,8 @@ language.localization_project = Aidez-nous à traduire Forgejo dans votre langue
language.description = Cette langue sera enregistrée dans votre compte et utilisée comme langue par défaut après votre connexion.
user_block_yourself = Vous ne pouvez pas vous bloquer vous même.
pronouns_custom_label = Pronoms personnalisés
-change_username_redirect_prompt.with_cooldown.one = L'ancien pseudonyme sera disponible pour n'importe qui après une période d'%[1]d jour, vous pouvez toujours réclamer votre ancien pseudonyme pendant cette période.
-change_username_redirect_prompt.with_cooldown.few = L'ancien pseudonyme sera disponible pour n'importe qui après une période de %[1]d jours, vous pouvez toujours réclamer votre ancien pseudonyme pendant cette période.
+change_username_redirect_prompt.with_cooldown.one = L'ancien pseudonyme sera disponible pour n'importe qui après une période d'%[1]d jour. Vous pouvez toujours réclamer votre ancien pseudonyme pendant cette période.
+change_username_redirect_prompt.with_cooldown.few = L'ancien pseudonyme sera disponible pour n'importe qui après une période de %[1]d jours. Vous pouvez toujours réclamer votre ancien pseudonyme pendant cette période.
quota.rule.exceeded = Dépassé
regenerate_token = Régénérer
access_token_regeneration = Régénérer le token d'accès
@@ -1653,13 +1653,13 @@ issues.close_comment_issue=Fermer avec le commentaire
issues.reopen_issue=Rouvrir
issues.reopen_comment_issue=Réouvrir avec le commentaire
issues.create_comment=Commenter
-issues.closed_at=`a fermé ce ticket %[2]s.`
-issues.reopened_at=`a rouvert ce ticket %[2]s.`
-issues.commit_ref_at=`a référencé ce ticket depuis une révision %[2]s.`
-issues.ref_issue_from=`a fait référence à %[4]s ce ticket %[2]s.`
-issues.ref_pull_from=`a fait référence à cette demande d'ajout %[4]s %[2]s.`
-issues.ref_closing_from=`a fait référence à une demande d'ajout %[4]s qui clora ce ticket, %[2]s.`
-issues.ref_reopening_from=`a référencé une pull request %[4]s qui va ré-ouvrir ce ticket %[2]s`
+issues.closed_at=`a fermé ce ticket %s`
+issues.reopened_at=`a rouvert ce ticket %s`
+issues.commit_ref_at=`a référencé ce ticket depuis une révision %s`
+issues.ref_issue_from=`a fait référence à ce ticket %[3]s %[1]s`
+issues.ref_pull_from=`a fait référence à cette demande d'ajout %[3]s %[1]s`
+issues.ref_closing_from=`a fait référence à une demande d'ajout %[3]s qui clora ce ticket, %[1]s`
+issues.ref_reopening_from=`a référencé ce ticket dans une pull request %[3]s qui va ré-ouvrir ce ticket, %[1]s`
issues.ref_closed_from=`a fermé ce ticket %[4]s %[2]s`
issues.ref_reopened_from=`a rouvert ce ticket %[4]s %[2]s.`
issues.ref_from=`de %[1]s`
@@ -1967,8 +1967,8 @@ pulls.update_branch_success=La mise à jour de la branche a réussi
pulls.update_not_allowed=Vous n'êtes pas autorisé à mettre à jour la branche
pulls.outdated_with_base_branch=Cette branche est désynchronisée avec la branche de base
pulls.close=Fermer la demande d’ajout
-pulls.closed_at=`a fermé cette demande d'ajout %[2]s.`
-pulls.reopened_at=`a rouvert cette demande d'ajout %[2]s.`
+pulls.closed_at=`a fermé cette demande d'ajout %s`
+pulls.reopened_at=`a rouvert cette demande d'ajout %s`
pulls.cmd_instruction_hint=Voir les instructions en ligne de commande
pulls.cmd_instruction_checkout_title=Basculer
pulls.cmd_instruction_checkout_desc=Depuis votre dépôt, basculer sur une nouvelle branche et tester des modifications.
@@ -2762,7 +2762,7 @@ issues.blocked_by_user = Vous ne pouvez pas créer de tickets sur ce dépôt car
pulls.blocked_by_user = Vous ne pouvez pas créer une pull request sur ce dépôt car vous êtes bloqué par son propriétaire.
wiki.cancel = Annuler
settings.wiki_globally_editable = Permettre l'édition du wiki a tout le monde
-pulls.commit_ref_at = `a référencé cette pull request depuis le commit %[2]s`
+pulls.commit_ref_at = `a référencé cette pull request depuis un commit %s`
settings.new_owner_blocked_doer = Le nouveau propriétaire vous a bloqué.
settings.enter_repo_name = Confirmez en entrant le propriétaire et le nom du dépôt exactement comme affiché :
settings.wiki_rename_branch_main = Normalise le nom de la branche du Wiki
@@ -2920,6 +2920,7 @@ settings.event_header_action = Événements d'exécution d'action
settings.event_action_success_desc = L'exécution de l'action a réussi.
settings.event_action_failure_desc = L'exécution de l'action a échoué.
settings.event_action_recover_desc = L'exécution de l'action a réussi après l'échec de la dernière exécution de l'action dans le même workflow.
+issues.filter_type.all_pull_requests = Toutes les demandes d'ajout
[graphs]
component_loading = Chargement %s…
@@ -3057,8 +3058,8 @@ teams.invite.by=Invité par %s
teams.invite.description=Veuillez cliquer sur le bouton ci-dessous pour rejoindre l’équipe.
follow_blocked_user = Vous ne pouvez pas suivre cette organisation car elle vous a bloqué.
open_dashboard = Ouvrir le tableau de bord
-settings.change_orgname_redirect_prompt.with_cooldown.few = L'ancien nom d'organisation sera disponible pour n'importe qui après une période de %[1]d jours, vous pouvez toujours réclamer votre ancien nom d'organisation pendant cette période.
-settings.change_orgname_redirect_prompt.with_cooldown.one = L'ancien nom d'organisation sera disponible pour n'importe qui après une période d'%[1]d jour, vous pouvez toujours réclamer votre ancien nom d'organisation pendant cette période.
+settings.change_orgname_redirect_prompt.with_cooldown.few = L'ancien nom d'organisation sera disponible pour n'importe qui après une période de %[1]d jours. Vous pouvez toujours réclamer votre ancien nom d'organisation pendant cette période.
+settings.change_orgname_redirect_prompt.with_cooldown.one = L'ancien nom d'organisation sera disponible pour n'importe qui après une période d'%[1]d jour. Vous pouvez toujours réclamer votre ancien nom d'organisation pendant cette période.
[admin]
dashboard=Tableau de bord
diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini
index d2d960b627..3bb06e8c21 100644
--- a/options/locale/locale_ga-IE.ini
+++ b/options/locale/locale_ga-IE.ini
@@ -1219,11 +1219,11 @@ issues.close_comment_issue = Dún le trácht
issues.reopen_issue = Athoscail
issues.reopen_comment_issue = Athoscail le trácht
issues.create_comment = Trácht
-issues.closed_at = `dhún an cheist seo %[2]s`
-issues.reopened_at = `athoscail an t-eagrán seo %[2]s`
-issues.commit_ref_at = `rinne tagairt don cheist seo ó ghealltanas %[2]s`
-issues.ref_issue_from = `rinne dagairt don cheist seo %[4]s %[2]s`
-issues.ref_pull_from = `rinne dagairt don iarratas tarraingthe seo %[4]s %[ 2]s`
+issues.closed_at = `dhún an cheist seo %s`
+issues.reopened_at = `athoscail an t-eagrán seo %s`
+issues.commit_ref_at = `rinne tagairt don cheist seo ó ghealltanas %s`
+issues.ref_issue_from = `rinne dagairt don cheist seo %[3]s %[1]s`
+issues.ref_pull_from = `rinne dagairt don iarratas tarraingthe seo %[3]s %[1]s`
issues.ref_closed_from = `dhún an cheist seo %[4]s %[2]s`
issues.ref_reopened_from = `d'athoscail an eagrán seo %[4]s %[2]s`
issues.ref_from = `ó %[1]s`
@@ -1456,8 +1456,8 @@ pulls.update_branch_success = Bhí nuashonrú brainse rathúil
pulls.update_not_allowed = Ní cheadaítear duit brainse a nuashonrú
pulls.outdated_with_base_branch = Tá an brainse seo as dáta leis an mbunbhrainse
pulls.close = Dún Iarratas Tarraing
-pulls.closed_at = `dhún an t-iarratas tarraingthe seo %[2]s`
-pulls.reopened_at = `athoscail an t-iarratas tarraingthe seo %[2]s`
+pulls.closed_at = `dhún an t-iarratas tarraingthe seo %s`
+pulls.reopened_at = `athoscail an t-iarratas tarraingthe seo %s`
pulls.cmd_instruction_checkout_title = Seiceáil
pulls.cmd_instruction_checkout_desc = Ó stór tionscadail, seiceáil brainse nua agus déan tástáil ar na hathruithe.
pulls.cmd_instruction_merge_title = Cumaisc
diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini
index 411bad835a..3e93ee8ba9 100644
--- a/options/locale/locale_hu-HU.ini
+++ b/options/locale/locale_hu-HU.ini
@@ -932,7 +932,7 @@ issues.close_comment_issue=Hozzászólás és lezárás
issues.reopen_issue=Újranyitás
issues.reopen_comment_issue=Hozzászólás és újranyitás
issues.create_comment=Hozzászólás
-issues.commit_ref_at=`hivatkozott erre a hibajegyre egy commit-ból %[2]s`
+issues.commit_ref_at=`hivatkozott erre a hibajegyre egy commit-ból %s`
issues.role.owner=Tulajdonos
issues.role.member=Tag
issues.re_request_review=Véleményezés újrakérése
diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini
index 673d1464b1..f1a392105e 100644
--- a/options/locale/locale_id-ID.ini
+++ b/options/locale/locale_id-ID.ini
@@ -796,7 +796,7 @@ issues.close_comment_issue=Komentar dan Tutup
issues.reopen_issue=Buka kembali
issues.reopen_comment_issue=Komentar dan Buka Kembali
issues.create_comment=Komentar
-issues.commit_ref_at=`merujuk masalah dari komit %[2]s`
+issues.commit_ref_at=`merujuk masalah dari komit %s`
issues.role.owner=Pemilik
issues.role.member=Anggota
issues.sign_in_require_desc=Masuk untuk bergabung dengan percakapan ini.
diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini
index 9b1d56fed9..baf8286923 100644
--- a/options/locale/locale_is-IS.ini
+++ b/options/locale/locale_is-IS.ini
@@ -805,8 +805,8 @@ issues.close_comment_issue=Senda ummæli og Loka
issues.reopen_issue=Enduropna
issues.reopen_comment_issue=Senda ummæli og Enduropna
issues.create_comment=Senda Ummæli
-issues.closed_at=`lokaði þessu vandamáli %[2]s`
-issues.reopened_at=`enduropnaði þetta vandamál %[2]s`
+issues.closed_at=`lokaði þessu vandamáli %s`
+issues.reopened_at=`enduropnaði þetta vandamál %s`
issues.ref_reopened_from=`enduropnaði þetta vandamál %[4]s %[2]s`
issues.author=Höfundur
issues.role.owner=Eigandi
diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini
index 48995e951f..d46f709cde 100644
--- a/options/locale/locale_it-IT.ini
+++ b/options/locale/locale_it-IT.ini
@@ -54,7 +54,7 @@ mirror=Mirror
new_repo=Nuovo repository
new_migrate=Nuova migrazione
new_mirror=Nuovo mirror
-new_fork=Nuova derivazione
+new_fork=Nuova biforcazione
new_org=Nuova organizzazione
new_project=Nuovo progetto
manage_org=Gestisci le organizzazioni
@@ -143,12 +143,12 @@ confirm_delete_selected = Confermare l'eliminazione di tutti gli elementi selezi
sign_in_with_provider = Accedi con %s
new_project_column = Nuova colonna
toggle_menu = Mostra/Nascondi menu
-filter.not_fork = Non fork
+filter.not_fork = Non biforcazioni
filter = Filtro
filter.clear = Rimuovi filtri
filter.is_archived = Archiviato
filter.not_archived = Non archiviato
-filter.is_fork = Da fork
+filter.is_fork = Biforcazioni
filter.is_mirror = Mirror
filter.not_mirror = Non mirror
filter.is_template = Modelli
@@ -209,6 +209,7 @@ table_modal.label.columns = Colonne
link_modal.header = Aggiungi collegamento
link_modal.url = Url
link_modal.description = Descrizione
+link_modal.paste_reminder = Suggerimento: se hai già copiato un URL negli appunti, puoi incollarlo direttamente nell’editor per creare un collegamento.
[filter]
string.asc = A - Z
@@ -232,6 +233,7 @@ lightweight_desc=Forgejo ha requisiti minimi bassi e può funzionare su un econo
license=Open Source
license_desc=Ottieni Forgejo! Partecipa per contribuire a rendere questo progetto ancora più bello. Non aver paura di diventare collaborante!
install_desc = Semplicemente avvia l'eseguibile per la tua piattaforma, distribuiscilo con Docker, oppure scarica il pacchetto.
+platform_desc = È stato verificato che Forgejo è pienamente compatibile con sistemi operativi liberi, come Linux e FreeBSD, nonché con diverse architetture CPU. Scegli liberamente la piattaforma che preferisci!
[install]
install=Installazione
@@ -396,12 +398,12 @@ go_to = Vai a
search.type.tooltip = Tipo di ricerca
search.fuzzy.tooltip = Includi anche i risultati che corrispondono parzialmente ai termini di ricerca
code_search_results = Risultati di ricerca per "%s"
-relevant_repositories_tooltip = I repositori derivati o che non hanno argomento, icona, né descrizione sono nascosti.
+relevant_repositories_tooltip = I repositori che sono biforcazioni o che non hanno argomento, icona, né descrizione sono nascosti.
relevant_repositories = Sono visibili solo i repositori pertinenti, mostra risultati non filtrati.
search.match.tooltip = Includi solo risultati che combaciano perfettamente con i termini di ricerca
stars_few = %d stelle
-forks_one = %d fork
-forks_few = %d fork
+forks_one = %d biforcazioni
+forks_few = %d biforcazioni
stars_one = %d stella
[auth]
@@ -485,6 +487,8 @@ sign_in_openid = Procedi con OpenID
hint_login = Hai già un'utenza? Accedi!
hint_register = Non hai un'utenza? Registrati ora.
sign_up_button = Registrati ora.
+unauthorized_credentials = Le credenziali non sono corrette o sono scadute. Controlla il comando o vedi %s per maggiori informazioni
+use_onetime_code = Usa un codice monouso
[mail]
view_it_on=Visualizza su %s
@@ -680,6 +684,8 @@ Location = Posizione
AccessToken = Token di accesso
FullName = Nome e cognome
To = Nome del ramo
+email_domain_is_not_allowed = Il dominio dell'indirizzo email dell'utente %s è in conflitto con EMAIL_DOMAIN_ALLOWLIST o EMAIL_DOMAIN_BLOCKLIST. Assicurati di aver inserito correttamente l'indirizzo email.
+username_claiming_cooldown = Il nome utente non può essere assegnato, poiché il periodo di attesa non è ancora terminato. Sarà disponibile il %[1]s.
[user]
@@ -723,6 +729,7 @@ followers.title.one = Seguace
followers.title.few = Seguaci
following.title.one = Seguito
following.title.few = Osservato
+public_activity.visibility_hint.self_private_profile = Poiché il tuo profilo è privato, la tua attività è visibile solo a te e agli amministratori dell'istanza. Configura.
[settings]
@@ -1045,7 +1052,7 @@ added_on = Aggiunto su %s
additional_repo_units_hint = Suggerisci l'attivazione di unità aggiuntive nel repositorio
update_hints = Aggiorna suggerimenti
update_hints_success = I suggerimenti sono stati aggiornati.
-additional_repo_units_hint_description = Mostra un pulsante "Aggiungi più sezioni..." per i repositori che non hanno tutte le sezioni disponibili aggiunte.
+additional_repo_units_hint_description = Visualizza un suggerimento “Abilita altro” per i repositori che non hanno tutte le unità disponibili abilitate.
hints = Suggerimenti
pronouns = Pronomi
pronouns_custom = Personalizzato
@@ -1053,6 +1060,34 @@ pronouns_unspecified = Non specificato
language.title = Lingua predefinita
language.description = Questa lingua verrà salvata nella tua utenza e verrà usata come predefinita ogni volta che farai l'accesso.
language.localization_project = Aiutaci a tradurre Forgejo nella tua lingua! Più informazioni.
+quota.sizes.assets.attachments.all = Allegati
+quota.rule.no_limit = Illimitato
+quota.sizes.assets.attachments.releases = Allegati del rilascio
+quota.rule.exceeded = Superato
+regenerate_token = Rigenera
+access_token_regeneration = Rigenera il token d'accesso
+access_token_regeneration_desc = Rigenerare un token comporterà la revoca dell'accesso al tuo account per tutte le applicazioni che lo utilizzano. Questa operazione è irreversibile. Vuoi procedere?
+regenerate_token_success = Il token è stato rigenerato. Le applicazioni che lo utilizzano non hanno più accesso alla tua utenza e devono essere aggiornate con il nuovo token.
+user_block_yourself = Non puoi bloccare te stesso.
+quota.applies_to_user = Le seguenti regole di quota si applicano al tuo account
+quota.applies_to_org = Le seguenti regole di quota si applicano a questa organizzazione
+quota.rule.exceeded.helper = La dimensione totale degli oggetti per questa regola ha superato la quota.
+quota.sizes.all = Tutti
+quota.sizes.repos.all = Repositori
+quota.sizes.repos.public = Repositori pubblici
+quota.sizes.repos.private = Repositori privati
+quota.sizes.git.all = Contenuto git
+quota.sizes.git.lfs = Git LFS
+quota.sizes.assets.all = Risorse
+quota.sizes.assets.attachments.issues = Allegati della segnalazione
+quota.sizes.assets.artifacts = Artefatti
+quota.sizes.assets.packages.all = Pacchetti
+quota.sizes.wiki = Wiki
+keep_pronouns_private = Mostra i pronomi solo agli utenti che hanno effettuato il login
+keep_pronouns_private.description = Questa impostazione nasconderà i tuoi pronomi agli utenti non ancora autenticati.
+storage_overview = Panoramica spazio di archiviazione
+quota = Quota
+change_username_redirect_prompt.with_cooldown.one = Il vecchio nome utente sarà disponibile per tutti dopo un periodo di protezione di %\[1]d giorni. Durante questo periodo di attesa potrai comunque tornare al vecchio nome utente.
[repo]
owner=Proprietario
@@ -1067,10 +1102,10 @@ template_description=I modelli di repositori consentono allɜ utenti di generare
visibility=Visibilità
visibility_description=Solo il proprietario o i membri dell'organizzazione se hanno diritti, saranno in grado di vederlo.
visibility_helper_forced=L'amministratorə del sito impone che i nuovi repositori siano privati.
-visibility_fork_helper=(Questa modifica influenzerà la visibilità di tutti i fork.)
+visibility_fork_helper=(Questa modifica influenzerà la visibilità di tutte le biforcazioni.)
clone_helper=Hai bisogno di aiuto per la clonazione? Visita Help.
fork_repo=Deriva repositorio
-fork_from=Deriva da
+fork_from=Biforcazione di
already_forked=Hai già fatto il fork di %s
fork_to_different_account=Fai Fork a un account diverso
fork_visibility_helper=La visibilità di un repositorio derivato non può essere modificata.
@@ -1514,13 +1549,13 @@ issues.close_comment_issue=Commenta e chiudi
issues.reopen_issue=Riapri
issues.reopen_comment_issue=Commenta e riapri
issues.create_comment=Commento
-issues.closed_at=`ha chiuso questa segnalazione %[2]s`
-issues.reopened_at=`ha riaperto questa segnalazione %[2]s`
-issues.commit_ref_at=`ha fatto riferimento a questa segnalazione dal commit %[2]s`
-issues.ref_issue_from=`ha fatto riferimento a questa segnalazione %[4]s %[2]s`
-issues.ref_pull_from=`ha fatto riferimento a questa richiesta di modifica %[4]s %[2]s`
-issues.ref_closing_from=`ha fatto riferimento a questa segnalazione da una richiesta di modifica %[4]s che la chiuderà, %[2]s`
-issues.ref_reopening_from=`ha fatto riferimento a questa segnalazione da una richiesta di modifica %[4]s che la riaprirà, %[2]s`
+issues.closed_at=`ha chiuso questa segnalazione %s`
+issues.reopened_at=`ha riaperto questa segnalazione %s`
+issues.commit_ref_at=`ha fatto riferimento a questa segnalazione dal commit %s`
+issues.ref_issue_from=`ha fatto riferimento a questa segnalazione %[3]s %[1]s`
+issues.ref_pull_from=`ha fatto riferimento a questa richiesta di modifica %[3]s %[1]s`
+issues.ref_closing_from=`ha fatto riferimento a questa segnalazione da una richiesta di modifica %[3]s che la chiuderà, %[1]s`
+issues.ref_reopening_from=`ha fatto riferimento a questa segnalazione da una richiesta di modifica %[3]s che la riaprirà, %[1]s`
issues.ref_closed_from=`chiuso questa segnalazione %[4]s %[2]s`
issues.ref_reopened_from=`ha riaperto questa segnalazione %[4]s %[2]s`
issues.ref_from=`da %[1]s`
@@ -1718,7 +1753,7 @@ pulls.cannot_merge_work_in_progress=Questa richiesta di modifica è contrassegna
pulls.still_in_progress=Ancora in corso?
pulls.add_prefix=Aggiungi prefisso %s
pulls.remove_prefix=Rimuovi il prefisso %s
-pulls.data_broken=Questa richiesta di modifica è rovinata a causa di informazioni mancanti riguardo la derivazione.
+pulls.data_broken=Questa richiesta di modifica non è valida a causa di informazioni mancanti sulla biforcazione.
pulls.files_conflicted=Questa richiesta di modifica va in conflitto con il ramo di destinazione.
pulls.is_checking=Verifica dei conflitti di fusione in corso. Riprova tra qualche istante.
pulls.is_ancestor=Questo ramo è già incluso nel ramo di destinazione. Non c'è nulla da fondere.
@@ -1776,8 +1811,8 @@ pulls.update_branch_rebase=Aggiorna il ramo per cambio base
pulls.update_branch_success=Ramo aggiornato con successo
pulls.update_not_allowed=Non ti è permesso aggiornare il ramo
pulls.outdated_with_base_branch=Questo ramo non è aggiornato con il ramo di base
-pulls.closed_at=`ha chiuso questa richiesta di modifica %[2]s`
-pulls.reopened_at=`ha riaperto questa richiesta di modifica %[2]s`
+pulls.closed_at=`ha chiuso questa richiesta di modifica %s`
+pulls.reopened_at=`ha riaperto questa richiesta di modifica %s`
pulls.auto_merge_button_when_succeed=(Quando i controlli sono superati)
pulls.auto_merge_when_succeed=Unione automatica quando tutti i controlli sono superati
@@ -2100,7 +2135,7 @@ settings.event_create_desc=Ramo o etichetta creati.
settings.event_delete=Elimina
settings.event_delete_desc=Ramo o etichetta eliminati.
settings.event_fork=Deriva
-settings.event_fork_desc=Repository derivato.
+settings.event_fork_desc=Creata una biforcazione del repositorio.
settings.event_wiki=Wiki
settings.event_release=Release
settings.event_release_desc=Release pubblicata, aggiornata o rimossa in una repository.
@@ -2137,7 +2172,7 @@ settings.event_pull_request_sync_desc=Pull request sincronizzata.
settings.event_package=Pacchetto
settings.event_package_desc=Pacchetto creato o eliminato in un repository.
settings.branch_filter=Filtro rami
-settings.branch_filter_desc=Whitelist dei rami per gli eventi di spinta, creazione dei rami e cancellazione dei rami, specificati come modello globo. Se vuoto o *
, gli eventi per tutti i rami sono segnalati. Vedi la documentazione %[2]s per la sintassi. Esempi: master
, {master,release*}
.
+settings.branch_filter_desc=Filtro, scritto come pattern glob, da applicare ai rami per gli eventi di tipo immissione, creazione di rami e rimozione di rami. Se vuoto o *
, vengono considerati tutti gli eventi di tutti i rami. Maggiori dettagli sulla sintassi presso %[2]s. Esempi: master
, {master,release*}
.
settings.active=Attivo
settings.active_helper=Le informazioni sugli eventi innescati saranno inviate a questo URL del webhook.
settings.add_hook_success=Il webhook è stato aggiunto.
@@ -2167,8 +2202,8 @@ settings.web_hook_name_packagist=Packagist
settings.packagist_username=Nome utente Packagist
settings.packagist_api_token=API token
settings.packagist_package_url=Url pacchetto pacchetti
-settings.deploy_keys=Dispiega chiavi
-settings.add_deploy_key=Aggiungi chiave di dispiego
+settings.deploy_keys=Chiavi di distribuzione
+settings.add_deploy_key=Aggiungi chiave di distribuzione
settings.deploy_key_desc=Le deploy key possiedono l'accesso solamente alla lettura di un repository.
settings.is_writable=Abilita accesso scrittura
settings.is_writable_info=Permetti a questa deploy key di pushare nella repository.
@@ -2177,7 +2212,7 @@ settings.title=Titolo
settings.deploy_key_content=Contenuto
settings.key_been_used=Una deploy key con contenuto identico è già in uso.
settings.key_name_used=Esiste già una deploy key con questo nome.
-settings.deploy_key_deletion=Rimuovi chiave di dispiego
+settings.deploy_key_deletion=Rimuovi chiave di distribuzione
settings.deploy_key_deletion_desc=Rimuovere una chiave di distribuzione ne revocherà l'accesso a questo repository. Continuare?
settings.deploy_key_deletion_success=La chiave di distribuzione è stata rimossa.
settings.branches=Rami
@@ -2620,7 +2655,7 @@ issues.filter_type.reviewed_by_you = Revisionati da te
projects.edit_success = Il progetto "%s" è stato aggiornato.
issues.keyword_search_unavailable = La ricerca per parola chiave non è attualmente disponibile. Contatta l'amministratore del sito.
issues.role.collaborator_helper = Quest*utente è statə invitatə a collaborare al progetto.
-pulls.commit_ref_at = `ha fatto riferimento a questa richiesta di modifica da un commit %[2]s`
+pulls.commit_ref_at = `ha fatto riferimento a questa richiesta di modifica da un commit %s`
settings.thread_id = ID della discussione
release.title = Titolo del rilascio
visibility_helper = Rendi il repositorio privato
@@ -2660,7 +2695,7 @@ wiki.page_title = Titolo della pagina
wiki.page_content = Contenuto della pagina
settings.mirror_settings.pushed_repository = Repositorio immesso
settings.mirror_settings.push_mirror.edit_sync_time = Modifica intervallo di sincronizzazione degli specchi
-settings.units.units = Unità della repository
+settings.units.units = Sezioni del repositorio
settings.units.add_more = Aggiungi ancora...
settings.wiki_globally_editable = Consenti a tutti di modificare la wiki
settings.pull_mirror_sync_in_progress = Prelevando cambiamenti dal progetto remoto %s.
@@ -2732,7 +2767,7 @@ pulls.merged_title_desc_one = ha fuso %[1]d commit da %[2]s
in /etc/pacman.conf
:
+alt.setup = Aggiungi il repositorio alla lista dei repositori in rete (seleziona l'architettura necessaria al posto di "_arch_"):
+container.images.title = Immagini
+arch.version.properties = Proprietà della versione
+alt.registry.install = Per installare il pacchetto, esegui il comando seguente:
+alt.install = Installa pacchetto
+alt.registry = Configura questo registro dalla riga di comando:
+arch.pacman.helper.gpg = Aggiungi il certificato a pacman:
+arch.pacman.repo.multi = %s ha la stessa versione in diverse distribuzioni.
+arch.pacman.repo.multi.item = Configurazione per %s
+arch.pacman.sync = Sincronizza il paccketto con pacman:
+arch.version.description = Descrizione
+alt.repository = Informazioni del repositorio
+alt.repository.architectures = Architetture
+alt.repository.multiple_groups = Questo pacchetto è disponibile per più gruppi.
[secrets]
secrets = Segreti
@@ -3834,7 +3973,7 @@ runs.empty_commit_message = (messaggio di commit vuoto)
runs.no_runs = Il flusso di lavoro non è stato ancora eseguito.
variables.creation.success = La variabile "%s" è stata aggiunta.
variables.description = Le variabili saranno passate a determinate azioni e non possono essere lette altrimenti.
-need_approval_desc = È necessaria l'approvazione per eseguire flussi di lavoro per richieste di modifica da derivazioni.
+need_approval_desc = È necessaria l'approvazione per eseguire flussi di lavoro per richieste di modifica da biforcazioni.
runs.no_workflows.documentation = Per ulteriori informazioni sulle Forgejo Actions vedi la documentazione.
runs.no_workflows.quick_start = Non sai come iniziare con le Forgejo Actions? Vedi la guida rapida.
runners.delete_runner_notice = Se un'attività è in esecuzione su questo esecutore sarà terminata ed etichettata fallito. Potrebbe rompere flussi di lavoro di costruzione.
@@ -3848,6 +3987,8 @@ workflow.dispatch.invalid_input_type = Tipo ingresso "%s" non valido.
workflow.dispatch.warn_input_limit = Visualizzati solo i primi %d ingressi.
runs.no_job = Il flusso di lavoro deve contenere almeno un incarico
workflow.dispatch.use_from = Usa flusso di lavoro da
+variables.not_found = Non è stato possibile trovare la variabile.
+runs.expire_log_message = I log sono stati eliminati in quanto troppo vecchi.
@@ -3856,6 +3997,7 @@ workflow.dispatch.use_from = Usa flusso di lavoro da
type-3.display_name = Progetto dell'organizzazione
type-1.display_name = Progetto individuale
type-2.display_name = Progetto
+deleted.display_name = Progetto eliminato
[git.filemode]
symbolic_link=Link Simbolico
@@ -3896,6 +4038,7 @@ milestone_kind = Ricerca tappe...
regexp_tooltip = Interpreta i termini di ricerca come un'espressione regolare
regexp = Espressione Regolare
union_tooltip = Include i risultati che combaciano con una qualsiasi delle parole chiave separata da spazi
+union = Parole chiavi
[munits.data]
gib = GiB
@@ -3914,4 +4057,16 @@ filepreview.line = Linea %[1]d in %[2]s
[repo.permissions]
issues.write = Scrittura: Chiudere segnalazioni e gestire metadati come etichette, traguardi, assegnatarɜ, scadenze e dipendenze.
-pulls.write = Scrittura: Chiudere richieste di modifica e gestire metadati come etichette, traguardi, assegnatarɜ, scadenze e dipendenze.
\ No newline at end of file
+pulls.write = Scrittura: Chiudere richieste di modifica e gestire metadati come etichette, traguardi, assegnatarɜ, scadenze e dipendenze.
+releases.write = Scrittura: Può pubblicare, modificare ed eliminare rilasci e le risorse ad essi allegate.
+code.write = Scrittura: Può aggiungere commit al repositorio, creare rami ed etichette.
+wiki.read = Lettura: Può leggere la wiki integrata e la sua cronologia.
+releases.read = Lettura: Può visualizzare e scaricare i rilasci.
+projects.read = Lettura: Può accedere alle board di progetto del repositorio.
+code.read = Lettura: Può accedere e clonare il codice del repositorio.
+wiki.write = Scrittura: Può creare, aggiornare ed eliminare pagine nella wiki integrata.
+issues.read = Lettura: Può leggere e creare segnalazioni e commenti.
+pulls.read = Lettura: Può leggere e creare richieste di modifica.
+
+[translation_meta]
+test = daje Roma
\ No newline at end of file
diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini
index d4d7024f5d..555f5c6a75 100644
--- a/options/locale/locale_ja-JP.ini
+++ b/options/locale/locale_ja-JP.ini
@@ -1610,13 +1610,13 @@ issues.close_comment_issue=コメントしてクローズ
issues.reopen_issue=再オープンする
issues.reopen_comment_issue=コメントして再オープン
issues.create_comment=コメントする
-issues.closed_at=`がイシューをクローズ %[2]s`
-issues.reopened_at=`がイシューを再オープン %[2]s`
-issues.commit_ref_at=`がコミットでこのイシューを参照 %[2]s`
-issues.ref_issue_from=`が%[4]s、このイシューを参照 %[2]s`
-issues.ref_pull_from=`が%[4]s、このプルリクエストを参照 %[2]s`
-issues.ref_closing_from=`が%[4]s、プルリクエストがこのイシューをクローズするよう参照 %[2]s`
-issues.ref_reopening_from=`が%[4]s、プルリクエストがこのイシューを再オープンするよう参照 %[2]s`
+issues.closed_at=`がイシューをクローズ %s`
+issues.reopened_at=`がイシューを再オープン %s`
+issues.commit_ref_at=`がコミットでこのイシューを参照 %s`
+issues.ref_issue_from=`が%[3]s、このイシューを参照 %[1]s`
+issues.ref_pull_from=`が%[3]s、このプルリクエストを参照 %[1]s`
+issues.ref_closing_from=`が%[3]s、プルリクエストがこのイシューをクローズするよう参照 %[1]s`
+issues.ref_reopening_from=`が%[3]s、プルリクエストがこのイシューを再オープンするよう参照 %[1]s`
issues.ref_closed_from=`が%[4]s、このイシューをクローズ %[2]s`
issues.ref_reopened_from=`が%[4]s、このイシューを再オープン %[2]s`
issues.ref_from=` %[1]s にて`
@@ -1923,8 +1923,8 @@ pulls.update_branch_success=ブランチの更新が成功しました
pulls.update_not_allowed=ブランチを更新する権限がありません
pulls.outdated_with_base_branch=このブランチはベースブランチに対して最新ではありません
pulls.close=プルリクエストをクローズ
-pulls.closed_at=`がプルリクエストをクローズ %[2]s`
-pulls.reopened_at=`がプルリクエストを再オープン %[2]s`
+pulls.closed_at=`がプルリクエストをクローズ %s`
+pulls.reopened_at=`がプルリクエストを再オープン %s`
pulls.cmd_instruction_hint=コマンドラインの手順を表示
pulls.cmd_instruction_checkout_title=チェックアウト
pulls.cmd_instruction_checkout_desc=プロジェクトリポジトリから新しいブランチをチェックアウトし、変更内容をテストします。
@@ -2721,7 +2721,7 @@ settings.wiki_rename_branch_main = wikiのブランチ名を正規化する
settings.wiki_rename_branch_main_desc = wikiによって内部的に使われているブランチ名を "%s" に変更します。これは恒久的で元に戻すことはできません。
contributors.contribution_type.additions = 追加
vendored = vendor済み
-pulls.commit_ref_at = `このプルリクエストを言及するコミット %[2]s`
+pulls.commit_ref_at = `このプルリクエストを言及するコミット %s`
pulls.fast_forward_only_merge_pull_request = Fast-forwardのみ
admin.manage_flags = フラグ管理
admin.update_flags = フラグを更新
diff --git a/options/locale/locale_jbo.ini b/options/locale/locale_jbo.ini
index 6124dc4d22..947bb298de 100644
--- a/options/locale/locale_jbo.ini
+++ b/options/locale/locale_jbo.ini
@@ -2,4 +2,12 @@
[common]
-home = zdani
\ No newline at end of file
+home = zdani
+dashboard = jitypalna
+explore = sisku
+help = se sidju
+logo = se'isni
+sign_in = co'a nerkla
+sign_in_with_provider = co'a nerka sepi'o la .%s.
+sign_out = co'a cliva
+sign_up = co'a gumri
\ No newline at end of file
diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini
index 433ec01828..be0400bea4 100644
--- a/options/locale/locale_ko-KR.ini
+++ b/options/locale/locale_ko-KR.ini
@@ -943,7 +943,7 @@ issues.close_comment_issue=클로즈 및 코멘트
issues.reopen_issue=다시 열기
issues.reopen_comment_issue=다시 오픈 및 코멘트
issues.create_comment=코멘트
-issues.commit_ref_at=` 커밋 %[2]s에서 이 이슈 언급`
+issues.commit_ref_at=` 커밋 %s에서 이 이슈 언급`
issues.role.owner=소유자
issues.role.member=멤버
issues.sign_in_require_desc=로그인하여 이 대화에 참여하세요.
@@ -1378,7 +1378,7 @@ issues.closed_by_fake = %[2]s님이 %[1]s에 닫음
issues.new.closed_projects = 닫힌 프로젝트
pulls.merged_by_fake = %[2]s님이 %[1]s 병합함
issues.closed_by = %[3]s님이 %[1]s에 닫음
-issues.closed_at = `%[2]s`에 이 이슈를 닫음
+issues.closed_at = `%s`에 이 이슈를 닫음
issues.filter_milestone_closed = 닫힌 마일스톤
issues.opened_by_fake = %[2]s님이 %[1]s에 열음
issues.filter_project_none = 프로젝트 없음
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index b53c0faa9b..98baff217b 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -1651,13 +1651,13 @@ issues.close_comment_issue=Aizvērt ar piebildi
issues.reopen_issue=Atvērt atkārtoti
issues.reopen_comment_issue=Atkārtoti atvērt ar piebildi
issues.create_comment=Pievienot piebildi
-issues.closed_at=`aizvēra šo pieteikumu %[2]s`
-issues.reopened_at=`atkārtoti atvēra šo pieteikumu %[2]s`
-issues.commit_ref_at=`atsaucās uz šo pieteikumu iesūtījumā %[2]s`
-issues.ref_issue_from=`atsaucās uz šo pieteikumu %[4]s %[2]s`
-issues.ref_pull_from=`atsaucās uz šo izmaiņu pieprasījumu %[4]s %[2]s`
-issues.ref_closing_from=`atsaucās uz šo pieteikumu izmaiņu pieprasījumā %[4]s, kas aizvērs to, %[2]s`
-issues.ref_reopening_from=`atsaucās uz šo pieteikumu izmaiņu pieprasījumā %[4]s, kas atkārtoti atvērs to, %[2]s`
+issues.closed_at=`aizvēra šo pieteikumu %s`
+issues.reopened_at=`atkārtoti atvēra šo pieteikumu %s`
+issues.commit_ref_at=`atsaucās uz šo pieteikumu iesūtījumā %s`
+issues.ref_issue_from=`atsaucās uz šo pieteikumu %[3]s %[1]s`
+issues.ref_pull_from=`atsaucās uz šo izmaiņu pieprasījumu %[3]s %[1]s`
+issues.ref_closing_from=`atsaucās uz šo pieteikumu izmaiņu pieprasījumā %[3]s, kas aizvērs to, %[1]s`
+issues.ref_reopening_from=`atsaucās uz šo pieteikumu izmaiņu pieprasījumā %[3]s, kas atkārtoti atvērs to, %[1]s`
issues.ref_closed_from=`aizvēra pieteikumu %[4]s %[2]s`
issues.ref_reopened_from=`atkārtoti atvēra pieteikumu %[4]s %[2]s`
issues.ref_from=`no %[1]s`
@@ -1964,8 +1964,8 @@ pulls.update_branch_success=Zara atjaunināšana bija sekmīga
pulls.update_not_allowed=Nav ļauts atjaunināt zaru
pulls.outdated_with_base_branch=Šis zars ir novecojis salīdzinājumā ar pamata zaru
pulls.close=Aizvērt izmaiņu pieprasījumu
-pulls.closed_at=`aizvēra šo izmaiņu pieprasījumu %[2]s`
-pulls.reopened_at=`atkārtoti atvēra šo izmaiņu pieprasījumu %[2]s`
+pulls.closed_at=`aizvēra šo izmaiņu pieprasījumu %s`
+pulls.reopened_at=`atkārtoti atvēra šo izmaiņu pieprasījumu %s`
pulls.cmd_instruction_hint=Apskatīt komandrindas izmantošanas norādes
pulls.cmd_instruction_checkout_title=Paņemt
pulls.cmd_instruction_checkout_desc=Projekta glabātavā jāizveido jauns zars un jāpārbauda izmaiņas.
@@ -2826,7 +2826,7 @@ issues.author.tooltip.pr = Šis lietotājs ir šī izmaiņu pieprasījuma izveid
pulls.edit.already_changed = Neizdevās saglabāt izmaiņu pieprasījuma izmaiņas. Izskatās, ka saturu jau ir mainījis kāds cits lietotājs. Lūgums atsvaidzināt lapu un mēģināt labot vēlreiz, lai izvairītos no izmaiņu pārrakstīšanas
pulls.blocked_by_user = Tu nevari izveidot izmaiņu pieprasījumu šajā glabātavā, jo tās īpašnieks ir Tevi liedzis.
issues.all_title = Visi
-pulls.commit_ref_at = ` atsaucāš uz šo izmaiņu pieprasījumu iesūtījumā %[2]s`
+pulls.commit_ref_at = ` atsaucās uz šo izmaiņu pieprasījumu iesūtījumā %s`
issues.num_participants_one = %d dalībnieks
pulls.title_desc_one = vēlas iekļaut %[1]d iesūtījumu no %[2]s
%[3]s
issues.archived_label_description = (Arhivēts) %s
@@ -2920,6 +2920,7 @@ settings.event_action_recover = Atgūt
settings.event_action_recover_desc = Darbības izpilde bija sekmīga pēc kļūmes iepriekšējā darbības izpildē tajā pašā darbplūsmā.
settings.event_action_success = Sekmīgi
settings.event_action_success_desc = Darbības izpilde bija sekmīga.
+issues.filter_type.all_pull_requests = Visi izmaiņu pieprasījumi
[graphs]
component_loading=Ielādē %s…
diff --git a/options/locale/locale_nds.ini b/options/locale/locale_nds.ini
index 2175e11b02..68fe899d6e 100644
--- a/options/locale/locale_nds.ini
+++ b/options/locale/locale_nds.ini
@@ -1347,7 +1347,7 @@ issues.change_title_at = `hett %[3]s de Titel vun Alt
+Klick/Enter
, um Vermarkens uttosluten`
+issues.filter_label_exclude = Bruuk Alt + Klick, um Vermarkens uttosluten
issues.filter_label_no_select = All Vermarkens
issues.filter_label_select_no_label = Keen Vermark
issues.filter_milestone = Marksteen
@@ -1434,12 +1434,12 @@ issues.comment_pull_merged_at = hett Kommitteren %[1]s in %[2]s %[3]s tosamenfö
issues.close_comment_issue = Mit Kommentaar dichtmaken
issues.reopen_comment_issue = Mit Kommentaar weer opmaken
issues.create_comment = Kommenteren
-issues.reopened_at = `hett deeses Gefall %[2]s weer opmaakt`
+issues.reopened_at = `hett deeses Gefall %s weer opmaakt`
issues.comment_manually_pull_merged_at = hett Kommitteren %[1]s in %[2]s %[3]s vun Hand tosamenföhrt
issues.reopen_issue = Weer opmaken
-issues.closed_at = `hett deeses Gefall %[2]s dichtmaakt`
-issues.commit_ref_at = `hett deeses Gefall %[2]s vun eenem Kommitteren benöömt`
-issues.ref_closing_from = `hett deeses Gefall %[2]s vun eenem Haalvörslag, wat ’t %[4]s dichtmaken word, benöömt`
+issues.closed_at = `hett deeses Gefall %s dichtmaakt`
+issues.commit_ref_at = `hett deeses Gefall %s vun eenem Kommitteren benöömt`
+issues.ref_closing_from = `hett deeses Gefall %[1]s vun eenem Haalvörslag, wat ’t %[3]s dichtmaken word, benöömt`
issues.ref_closed_from = `hett deeses Gefall %[4]s %[2]s dichtmaakt`
issues.ref_reopened_from = `hett deeses Gefall %[4]s %[2]s weer opmaakt`
issues.ref_from = `vun %[1]s`
@@ -1477,12 +1477,12 @@ issues.label.filter_sort.reverse_alphabetically = Umdreiht na de Alphabeet
issues.label.filter_sort.by_size = Lüttste Grött
issues.num_participants_one = %d Mitmaker
issues.num_participants_few = %d Mitmakers
-issues.ref_pull_from = `hett deesen Haalvörslag %[4]s %[2]s benöömt`
+issues.ref_pull_from = `hett deesen Haalvörslag %[3]s %[1]s benöömt`
issues.label_title = Naam
issues.label_archived_filter = Archiveert Vermarkens wiesen
issues.archived_label_description = (Archiveert) %s
-issues.ref_issue_from = `hett deeses Gefall %[4]s %[2]s benöömt`
-issues.ref_reopening_from = `hett deeses Gefall vun eenem Haalvörslag, wat ’t %[4]s weer opmaken word, %[2]s benöömt`
+issues.ref_issue_from = `hett deeses Gefall %[3]s %[1]s benöömt`
+issues.ref_reopening_from = `hett deeses Gefall vun eenem Haalvörslag, wat ’t %[3]s weer opmaken word, %[1]s benöömt`
issues.author.tooltip.issue = Deeser Bruker is de Autor vun deesem Gefall.
issues.role.member_helper = Deeser Bruker is een Liddmaat vun de Vereenigung, wat de Eegner vun deesem Repositorium is.
issues.role.collaborator_helper = Deeser Bruuker is inladen worden, in deesem Repositorium mittoarbeiden.
@@ -1740,8 +1740,8 @@ pulls.status_checks_show_all = All Överprüfens wiesen
pulls.update_branch_rebase = Twieg mit Umbaseren vernejen
pulls.outdated_with_base_branch = De Twieg is tegen de Grund-Twieg verollt
pulls.close = Haalvörslag dichtmaken
-pulls.closed_at = `hett deesen Haalvörslag %[2]s dichtmaakt`
-pulls.reopened_at = `hett deesen Haalvörslag %[2]s weer opmaakt`
+pulls.closed_at = `hett deesen Haalvörslag %s dichtmaakt`
+pulls.reopened_at = `hett deesen Haalvörslag %s weer opmaakt`
pulls.cmd_instruction_hint = Wies Oorderreeg-Instruksjes
pulls.cmd_instruction_checkout_title = Utchecken
pulls.cmd_instruction_merge_title = Tosamenföhren
@@ -1771,7 +1771,7 @@ milestones.deletion = Marksteen lösken
pulls.has_merged = Fehlslagen: De Haalvörslag is tosamenföhrt worden, du kannst nich noch eenmaal tosamenföhren of de Enn-Twieg ännern.
pulls.unrelated_histories = Tosamenföhren fehlslagen: De Tosamenföhrens-Kopp un -Grund hebben keene gemeensame Histoorje. Wenk: Versöök eene anner Tosamenföhrens-Aard
pulls.update_not_allowed = Du düürst deesen Twieg nich vernejen
-pulls.commit_ref_at = `hett deesen Haalvörslag %[2]s vun eenem Kommitteren benöömt`
+pulls.commit_ref_at = `hett deesen Haalvörslag %s vun eenem Kommitteren benöömt`
pulls.auto_merge_newly_scheduled = De Haalvörslag weer sett, sik tosamentoföhren, wenn all Överprüfens kumpleet sünd.
milestones.clear = Leeg maken
pulls.push_rejected_no_message = Schuven fehlslagen: Dat Schuven is sünner feerne Naricht oflehnt worden. Bidde överprüüf de Git-Hakens för deeses Repositorium
@@ -2621,6 +2621,7 @@ settings.event_action_recover = Verhaalt
settings.event_header_action = Aktioons-Loop-Vörfallen
settings.event_action_failure_desc = Aktioons-Loop is as fehlslagen ennt.
settings.event_action_recover_desc = Aktioons-Loop is daankregen worden, nadeem de leste Aktioons-Loop in de sülven Warkwies fehlslagen is.
+issues.filter_type.all_pull_requests = All Haalvörslagen
[repo.permissions]
code.read = Lesen: De Quelltext vun deesem Repositorium ankieken un klonen.
diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini
index 549718ce23..48442bc39f 100644
--- a/options/locale/locale_nl-NL.ini
+++ b/options/locale/locale_nl-NL.ini
@@ -1554,13 +1554,13 @@ issues.close_comment_issue=Sluit met commentaar
issues.reopen_issue=Heropen
issues.reopen_comment_issue=Heropen met commentaar
issues.create_comment=Reageer
-issues.closed_at=`heeft dit probleem gesloten %[2]s`
-issues.reopened_at=`heropende dit probleem %[2]s`
-issues.commit_ref_at=`verwees naar dit probleem vanuit commit %[2]s'`
-issues.ref_issue_from=`refereerde aan dit issue %[4]s %[2]s`
-issues.ref_pull_from=`refereerde aan deze pull request %[4]s %[2]s`
-issues.ref_closing_from=`verwees naar deze issue van een pull request %[4]s dat het zal sluiten, %[2]s`
-issues.ref_reopening_from=`verwees naar een pull request %[4]s dat dit issue heropent %[2]s `
+issues.closed_at=`heeft dit probleem gesloten %s`
+issues.reopened_at=`heropende dit probleem %s`
+issues.commit_ref_at=`verwees naar dit probleem vanuit commit %s`
+issues.ref_issue_from=`refereerde aan dit issue %[3]s %[1]s`
+issues.ref_pull_from=`refereerde aan deze pull request %[3]s %[1]s`
+issues.ref_closing_from=`verwees naar deze issue van een pull request %[3]s dat het zal sluiten, %[1]s`
+issues.ref_reopening_from=`verwees naar een pull request %[3]s dat dit issue heropent %[1]s `
issues.ref_closed_from=`sloot dit issue %[4]s %[2]s`
issues.ref_reopened_from=`heropende dit issue %[4]s %[2]s`
issues.ref_from=`van %[1]s`
@@ -1815,8 +1815,8 @@ pulls.update_branch_rebase=Update branch via herbaseren
pulls.update_branch_success=Branch update is geslaagd
pulls.update_not_allowed=Je hebt geen toestemming om branch bij te werken
pulls.outdated_with_base_branch=Deze branch is verouderd met de basis branch
-pulls.closed_at=`heeft deze pull request gesloten %[2]s`
-pulls.reopened_at=`heropende deze pull request %[2]s`
+pulls.closed_at=`heeft deze pull request gesloten %s`
+pulls.reopened_at=`heropende deze pull request %s`
pulls.auto_merge_button_when_succeed=(Bij geslaagde controles)
pulls.auto_merge_when_succeed=Automatisch samenvoegen wanneer alle controles gelukt zijn
@@ -2627,7 +2627,7 @@ projects.column.set_default_desc = Stel deze kolom in als standaard voor ongecat
issues.action_check = Aanvinken/uitvinken
issues.dependency.issue_batch_close_blocked = Het is niet mogelijk om de issues die u gekozen heeft in bulk te sluiten, omdat issue #%d nog open afhankelijkheden heeft
pulls.review_only_possible_for_full_diff = Beoordeling is alleen mogelijk bij het bekijken van de volledige diff
-pulls.commit_ref_at = `heeft naar deze pull request verwezen vanuit een commit %[2]s`
+pulls.commit_ref_at = `heeft naar deze pull request verwezen vanuit een commit %s`
pulls.cmd_instruction_hint = Bekijk opdrachtregelinstructies
pulls.cmd_instruction_checkout_desc = Vanuit uw project repository, schakel over naar een nieuwe branch en test de veranderingen.
pulls.showing_specified_commit_range = Alleen veranderingen weergeven tussen %[1]s..%[2]s
diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini
index 86a333a886..189e663618 100644
--- a/options/locale/locale_pl-PL.ini
+++ b/options/locale/locale_pl-PL.ini
@@ -1460,13 +1460,13 @@ issues.close_comment_issue=Zamknij z komentarzem
issues.reopen_issue=Otwórz ponownie
issues.reopen_comment_issue=Otwórz ponownie z komentarzem
issues.create_comment=Skomentuj
-issues.closed_at=`zamknął(-ęła) to zgłoszenie %[2]s`
-issues.reopened_at=`otworzył(-a) ponownie to zgłoszenie %[2]s`
-issues.commit_ref_at=`wspomniał(-a) to zgłoszenie z commita %[2]s`
-issues.ref_issue_from=`odwołał(-a) się do tego zgłoszenia %[4]s %[2]s`
-issues.ref_pull_from=`odwołał(-a) się do tego Pull Requesta %[4]s %[2]s`
-issues.ref_closing_from=`odwołał(-a) się do pull requesta %[4]s, który zamknie to zgłoszenie %[2]s`
-issues.ref_reopening_from=`odwołał(-a) się z pull requesta %[4]s, który otworzy na nowo to zgłoszenie %[2]s`
+issues.closed_at=`zamknął(-ęła) to zgłoszenie %s`
+issues.reopened_at=`otworzył(-a) ponownie to zgłoszenie %s`
+issues.commit_ref_at=`wspomniał(-a) to zgłoszenie z commita %s`
+issues.ref_issue_from=`odwołał(-a) się do tego zgłoszenia %[3]s %[1]s`
+issues.ref_pull_from=`odwołał(-a) się do tego Pull Requesta %[3]s %[1]s`
+issues.ref_closing_from=`odwołał(-a) się do pull requesta %[3]s, który zamknie to zgłoszenie %[1]s`
+issues.ref_reopening_from=`odwołał(-a) się z pull requesta %[3]s, który otworzy na nowo to zgłoszenie %[1]s`
issues.ref_closed_from=`zamknął(-ęła) to zgłoszenie %[4]s %[2]s`
issues.ref_reopened_from=`ponownie otworzył(-a) to zgłoszenie %[4]s %[2]s`
issues.ref_from=`z %[1]s`
@@ -1679,8 +1679,8 @@ pulls.update_branch_rebase=Aktualizuj branch przez rebase
pulls.update_branch_success=Aktualizacja gałęzi powiodła się
pulls.update_not_allowed=Nie masz uprawnień do aktualizacji gałęzi
pulls.outdated_with_base_branch=Ta gałąź jest przestarzała w stosunku do gałęzi bazowej
-pulls.closed_at=`zamknął(-ęła) ten pull request %[2]s`
-pulls.reopened_at=`otworzył(-a) ponownie ten Pull Request %[2]s`
+pulls.closed_at=`zamknął(-ęła) ten pull request %s`
+pulls.reopened_at=`otworzył(-a) ponownie ten Pull Request %s`
@@ -2643,7 +2643,7 @@ pulls.closed = Pull request zamknięty
pulls.blocked_by_outdated_branch = Ten pull request jest zablokowany ponieważ jest przedawniony.
pulls.blocked_by_changed_protected_files_1 = Ten pull request jest zablokowany ponieważ wprowadza zmiany do chronionego pliku:
pulls.push_rejected_no_message = Wypchnięcie nie powiodło się: Wypchnięcie zostało odrzucone, ale nie otrzymano zdalnej wiadomości. Sprawdź hooki Git dla tego repozytorium.=
-pulls.commit_ref_at = `odniósł się do tego pull requesta z commita %[2]s`
+pulls.commit_ref_at = `odniósł się do tego pull requesta z commita %s`
pulls.cmd_instruction_checkout_desc = Ze swojego repozytorium projektu, utwórz nową gałąź i przetestuj zmiany.
pulls.clear_merge_message_hint = Wyczyszczenie wiadomości scalenia usunie tylko treść wiadomości commitu pozostawiając wygenerowane przez git dopiski takie jak "Co-Authored-By ...".
pulls.delete_after_merge.head_branch.insufficient_branch = Nie masz uprawnień by usunąć head gałęzi.
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index 26bdd35420..8de0374eb2 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -1063,8 +1063,8 @@ language.localization_project = Ajude-nos a traduzir Forgejo para o seu idioma!
language.description = Essa língua será salva em sua conta e será usada como padrão após você iniciar a sessão.
user_block_yourself = Você não pode se bloquear.
pronouns_custom_label = Pronomes personalizados
-change_username_redirect_prompt.with_cooldown.one = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dia, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
-change_username_redirect_prompt.with_cooldown.few = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dias, você ainda pode recuperar o nome de usuário antigo durante este período de espera.
+change_username_redirect_prompt.with_cooldown.one = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de proteção de %[1]d dia. Você ainda pode recuperar o nome de usuário antigo durante este período de proteção.
+change_username_redirect_prompt.with_cooldown.few = O nome de usuário antigo ficará disponível para qualquer pessoa após um período de proteção de %[1]d dias. Você ainda pode recuperar o nome de usuário antigo durante este período de proteção.
quota.applies_to_user = As seguintes regras de cota se aplicam à sua conta
quota.rule.exceeded.helper = O tamanho total de objetos para esta regra excedeu a cota.
keep_pronouns_private = Mostrar pronomes apenas para usuários autenticados
@@ -1568,7 +1568,7 @@ issues.remove_ref_at=`removeu a referência %s %s`
issues.add_ref_at=`adicionou a referência %s %s`
issues.delete_branch_at=`excluiu branch %s %s`
issues.filter_label=Etiqueta
-issues.filter_label_exclude=`Use alt
+ clique/enter
para excluir etiquetas`
+issues.filter_label_exclude=Use Alt + Clique para excluir etiquetas
issues.filter_label_no_select=Todas as etiquetas
issues.filter_label_select_no_label=Sem etiqueta
issues.filter_milestone=Marco
@@ -1642,13 +1642,13 @@ issues.close_comment_issue=Comentar e fechar
issues.reopen_issue=Reabrir
issues.reopen_comment_issue=Comentar e reabrir
issues.create_comment=Comentar
-issues.closed_at=`fechou esta issue %[2]s`
-issues.reopened_at=`reabriu esta issue %[2]s`
-issues.commit_ref_at=`citou esta issue em um commit %[2]s`
-issues.ref_issue_from=`referenciado esta issue %[4]s %[2]s`
-issues.ref_pull_from=`referenciado este pull request %[4]s %[2]s`
-issues.ref_closing_from=`referenciado esta issue de um pull request %[4]s que a fechará %[2]s`
-issues.ref_reopening_from=`referenciado esta issue de um pull request %[4]s que a reabrirá %[2]s`
+issues.closed_at=`fechou esta issue %s`
+issues.reopened_at=`reabriu esta issue %s`
+issues.commit_ref_at=`citou esta issue de um commit %s`
+issues.ref_issue_from=`citou esta issue %[3]s %[1]s`
+issues.ref_pull_from=`citou este pull request %[3]s %[1]s`
+issues.ref_closing_from=`citou esta issue de um pull request %[3]s que a fechará %[1]s`
+issues.ref_reopening_from=`citou esta issue de um pull request %[3]s que a reabrirá, %[1]s`
issues.ref_closed_from=`fechou esta issue %[4]s %[2]s`
issues.ref_reopened_from=`reabriu esta issue %[4]s %[2]s`
issues.ref_from=`de %[1]s`
@@ -1942,8 +1942,8 @@ pulls.update_branch_success=Atualização do branch foi bem-sucedida
pulls.update_not_allowed=Você não tem permissão para atualizar o branch
pulls.outdated_with_base_branch=Este branch está desatualizado com o branch base
pulls.close=Fechar pull request
-pulls.closed_at=`fechou este pull request %[2]s`
-pulls.reopened_at=`reabriu este pull request %[2]s`
+pulls.closed_at=`fechou este pull request %s`
+pulls.reopened_at=`reabriu este pull request %s`
pulls.clear_merge_message=Limpar mensagem do merge
pulls.clear_merge_message_hint=Limpar a mensagem de merge só irá remover o conteúdo da mensagem de commit e manter trailers git gerados, como "Co-Authored-By …".
@@ -2719,7 +2719,7 @@ issues.label_archive_tooltip = Etiquetas arquivadas não serão exibidas nas sug
activity.navbar.pulse = Recente
settings.units.overview = Geral
settings.units.add_more = Habilitar mais
-pulls.commit_ref_at = `referenciou este pedido de mesclagem no commit %[2]s`
+pulls.commit_ref_at = `citou este pull request de um commit %s`
pulls.cmd_instruction_merge_title = Mesclar
settings.units.units = Unidades
vendored = Externo
@@ -2920,6 +2920,7 @@ settings.event_action_recover = Recuperar
settings.event_action_recover_desc = A execução da Action teve sucesso após a última execução no mesmo workflow ter falhado.
settings.event_action_success = Sucesso
settings.event_action_success_desc = A execução da Action foi bem sucedida.
+issues.filter_type.all_pull_requests = Todos os pull requests
[graphs]
component_loading = Carregando %s…
@@ -3056,8 +3057,8 @@ open_dashboard = Abrir painel
settings.change_orgname_prompt = Obs.: Alterar o nome de uma organização resultará na alteração do URL dela e disponibilizará o nome antigo para uso.
follow_blocked_user = Não foi possível seguir esta organização porque ela bloqueou-o(a).
form.name_pattern_not_allowed = O padrão "%s" não é permitido no nome de uma organização.
-settings.change_orgname_redirect_prompt.with_cooldown.one = O nome de organização antigo ficará disponível para qualquer pessoa após um período de proteção de %[1]d dia, você ainda pode recuperar o nome antigo durante este período de proteção.
-settings.change_orgname_redirect_prompt.with_cooldown.few = O nome de organização antigo ficará disponível para qualquer pessoa após um período de espera de %[1]d dia, você ainda pode recuperar o nome antigo durante este período de espera.
+settings.change_orgname_redirect_prompt.with_cooldown.one = O nome de organização antigo ficará disponível para qualquer pessoa após um período de proteção de %[1]d dia. Você ainda pode recuperar o nome antigo durante este período de proteção.
+settings.change_orgname_redirect_prompt.with_cooldown.few = O nome de organização antigo ficará disponível para qualquer pessoa após um período de proteção de %[1]d dia. Você ainda pode recuperar o nome antigo durante este período de proteção.
[admin]
dashboard=Painel
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 7f36d164b3..0e8f2d485e 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -1657,13 +1657,13 @@ issues.close_comment_issue=Fechar com comentário
issues.reopen_issue=Reabrir
issues.reopen_comment_issue=Reabrir com comentário
issues.create_comment=Comentar
-issues.closed_at=`encerrou esta questão %[2]s`
-issues.reopened_at=`reabriu esta questão %[2]s`
-issues.commit_ref_at=`referenciou esta questão num cometimento %[2]s`
-issues.ref_issue_from=`referiu esta questão %[4]s %[2]s`
-issues.ref_pull_from=`referiu este pedido de integração %[4]s %[2]s`
-issues.ref_closing_from=`referiu esta questão a partir de um pedido de integração %[4]s que a fechará %[2]s`
-issues.ref_reopening_from=`referiu esta questão a partir de um pedido de integração %[4]s que a reabrirá %[2]s`
+issues.closed_at=`encerrou esta questão %s`
+issues.reopened_at=`reabriu esta questão %s`
+issues.commit_ref_at=`referenciou esta questão num cometimento %s`
+issues.ref_issue_from=`referiu esta questão %[3]s %[1]s`
+issues.ref_pull_from=`referiu este pedido de integração %[3]s %[1]s`
+issues.ref_closing_from=`referiu esta questão a partir de um pedido de integração %[3]s que a fechará %[1]s`
+issues.ref_reopening_from=`referiu esta questão a partir de um pedido de integração %[3]s que a reabrirá %[1]s`
issues.ref_closed_from=`encerrou esta questão %[4]s %[2]s`
issues.ref_reopened_from=`reabriu esta questão %[4]s %[2]s`
issues.ref_from=`de %[1]s`
@@ -1972,8 +1972,8 @@ pulls.update_branch_success=A sincronização do ramo foi bem sucedida
pulls.update_not_allowed=Não tem autorização para sincronizar o ramo
pulls.outdated_with_base_branch=Este ramo é obsoleto em relação ao ramo base
pulls.close=Encerrar pedido de integração
-pulls.closed_at=`fechou este pedido de integração %[2]s`
-pulls.reopened_at=`reabriu este pedido de integração %[2]s`
+pulls.closed_at=`fechou este pedido de integração %s`
+pulls.reopened_at=`reabriu este pedido de integração %s`
pulls.cmd_instruction_hint=Ver instruções para a linha de comandos
pulls.cmd_instruction_checkout_title=Conferir
pulls.cmd_instruction_checkout_desc=No seu repositório, irá criar um novo ramo para que possa testar as modificações.
@@ -2785,7 +2785,7 @@ settings.wiki_rename_branch_main_desc = Renomear o ramo usado internamente pelo
settings.add_collaborator_blocked_our = Não foi possível adicionar o/a colaborador/a porque o/a proprietário/a do repositório bloqueou-os.
settings.add_webhook.invalid_path = A localização não pode conter "." ou ".." ou ficar em branco. Não pode começar ou terminar com uma barra.
settings.graphql_url = URL do GraphQL
-pulls.commit_ref_at = `referiu este pedido de integração a partir de um cometimento %[2]s`
+pulls.commit_ref_at = `referiu este pedido de integração a partir de um cometimento %s`
settings.confirm_wiki_branch_rename = Renomear o ramo do wiki
settings.wiki_branch_rename_success = O nome do ramo do wiki do repositório foi normalizado com sucesso.
settings.wiki_branch_rename_failure = Falhou a normalização do nome do ramo do wiki do repositório.
diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini
index bcb62eb23b..2ef1b868d4 100644
--- a/options/locale/locale_ru-RU.ini
+++ b/options/locale/locale_ru-RU.ini
@@ -1408,7 +1408,7 @@ editor.fail_to_update_file=Не удалось обновить/создать
editor.fail_to_update_file_summary=Ошибка:
editor.push_rejected_no_message=Изменение отклонено сервером без сообщения. Пожалуйста, проверьте Git-хуки.
editor.push_rejected=Изменение отклонено сервером. Пожалуйста, проверьте Git-хуки.
-editor.push_rejected_summary=Причина отклонения:
+editor.push_rejected_summary=Полная причина отклонения:
editor.add_subdir=Добавить каталог…
editor.unable_to_upload_files=Не удалось загрузить файлы в «%s» из-за ошибки: %v
editor.upload_file_is_locked=Файл «%s» заблокирован %s.
@@ -1545,27 +1545,27 @@ issues.add_labels=добавлены метки %s %s
issues.remove_label=удалил(а) метку %s %s
issues.remove_labels=удалил(а) метки %s %s
issues.add_remove_labels=добавлены метки %s и убраны метки %s %s
-issues.add_milestone_at=`добавлено в этап %s %s`
-issues.add_project_at=`добавлено в проект %s %s`
-issues.change_milestone_at=`изменил(а) целевой этап с %s на %s %s`
-issues.change_project_at=`изменил(а) проект с %s на %s %s`
-issues.remove_milestone_at=`удалил(а) это из этапа %s %s`
-issues.remove_project_at=`удалил(а) это из проекта %s %s`
+issues.add_milestone_at=`добавление в этап %s %s`
+issues.add_project_at=`добавление в проект %s %s`
+issues.change_milestone_at=`этап изменён с %s на %s %s`
+issues.change_project_at=`проект изменён с %s на %s %s`
+issues.remove_milestone_at=`удаление из этапа %s %s`
+issues.remove_project_at=`удаление из проекта %s %s`
issues.deleted_milestone=`(удалено)`
issues.deleted_project=`(удалено)`
-issues.self_assign_at=`назначил(а) на себя %s`
-issues.add_assignee_at=`был(а) назначен(а) %s %s`
-issues.remove_assignee_at=`был снят с назначения %s %s`
-issues.remove_self_assignment=`убрал(а) их назначение %s`
-issues.change_title_at=`изменил(а) заголовок с alt
+ click/enter
, чтобы исключить метки`
-issues.filter_label_no_select=Все метки
-issues.filter_label_select_no_label=Нет метки
+issues.filter_label=Метки
+issues.filter_label_exclude=Исключайте метки с помощью Alt + ЛКМ
+issues.filter_label_no_select=Любые метки
+issues.filter_label_select_no_label=Без меток
issues.filter_milestone=Этап
issues.filter_milestone_all=Все этапы
issues.filter_milestone_none=Нет этапов
@@ -1637,13 +1637,13 @@ issues.close_comment_issue=Закрыть комментарием
issues.reopen_issue=Открыть снова
issues.reopen_comment_issue=Открыть снова комментарием
issues.create_comment=Комментировать
-issues.closed_at=`задача была закрыта %[2]s`
-issues.reopened_at=`задача была открыта снова %[2]s`
-issues.commit_ref_at=`упоминание этой задачи в коммите %[2]s`
-issues.ref_issue_from=`упоминание этой задачи %[4]s %[2]s`
-issues.ref_pull_from=`упоминание этого запроса слияния %[4]s %[2]s`
-issues.ref_closing_from=`упоминание из запроса на слияние %[4]s, который закроет эту задачу %[2]s`
-issues.ref_reopening_from=`упоминание из запроса на слияние %[4]s, который повторно откроет эту задачу %[2]s`
+issues.closed_at=`задача была закрыта %s`
+issues.reopened_at=`задача была открыта снова %s`
+issues.commit_ref_at=`упоминание этой задачи в коммите %s`
+issues.ref_issue_from=`упоминание этой задачи %[3]s %[1]s`
+issues.ref_pull_from=`упоминание этого запроса слияния %[3]s %[1]s`
+issues.ref_closing_from=`упоминание из запроса на слияние %[3]s, который закроет эту задачу %[1]s`
+issues.ref_reopening_from=`упоминание из запроса на слияние %[3]s, который повторно откроет эту задачу %[1]s`
issues.ref_closed_from=`закрыл этот запрос %[4]s %[2]s`
issues.ref_reopened_from=`задача была открыта снова %[4]s %[2]s`
issues.ref_from=`из %[1]s`
@@ -1943,8 +1943,8 @@ pulls.update_branch_success=Ветвь успешно обновлена
pulls.update_not_allowed=Недостаточно прав для обновления ветви
pulls.outdated_with_base_branch=Эта ветвь отстает от базовой ветви
pulls.close=Закрыть запрос слияния
-pulls.closed_at=`закрыл этот запрос на слияние %[2]s`
-pulls.reopened_at=`переоткрыл этот запрос на слияние %[2]s`
+pulls.closed_at=`закрыл этот запрос на слияние %s`
+pulls.reopened_at=`переоткрыл этот запрос на слияние %s`
pulls.cmd_instruction_hint=Показать инструкции для командной строки
pulls.cmd_instruction_merge_title=Слейте изменения
pulls.cmd_instruction_merge_desc=Слейте изменения и отправьте их обратно.
@@ -2772,7 +2772,7 @@ settings.ignore_stale_approvals = Игнорировать устаревшие
contributors.contribution_type.additions = Добавления
contributors.contribution_type.deletions = Удаления
contributors.contribution_type.filter_label = Вид деятельности:
-pulls.commit_ref_at = `упоминание этого запроса слияния в коммите %[2]s`
+pulls.commit_ref_at = `сослался на этот запрос слияния в коммите %s`
settings.thread_id = ИД обсуждения
pulls.made_using_agit = AGit
activity.navbar.contributors = Соавторы
@@ -2923,6 +2923,7 @@ settings.event_action_recover = Восстановлен
settings.event_action_recover_desc = После неудачи повторное выполнение рабочего потока было успешно.
settings.event_action_success = Успех
settings.event_action_success_desc = Выполнение завершилось успешно.
+issues.filter_type.all_pull_requests = Все запросы на слияние
[graphs]
component_loading_failed = Не удалось загрузить %s
diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini
index d55b238b1c..54b0b246db 100644
--- a/options/locale/locale_si-LK.ini
+++ b/options/locale/locale_si-LK.ini
@@ -1100,12 +1100,12 @@ issues.close_comment_issue=අදහස් දක්වා වසන්න
issues.reopen_issue=නැවත විවෘත කරන්න
issues.reopen_comment_issue=අදහස් දක්වා විවෘත කරන්න
issues.create_comment=අදහස
-issues.closed_at=`මෙම ගැටළුව වසා %[2]s`
-issues.reopened_at=`මෙම ගැටළුව නැවත විවෘත කරන ලදි %[2]s`
-issues.ref_issue_from=`මෙම නිකුතුව %[4]s හි %[2]s`
-issues.ref_pull_from=`මෙම අදින්න ඉල්ලීම%[4]s %[2]s`
-issues.ref_closing_from=`මෙම ගැටළුව වසා දමනු ඇත%[4]s මෙම ගැටළුව %[2]s`
-issues.ref_reopening_from=`මෙම ගැටළුව නැවත විවෘත කරනු ඇත%[4]s මෙම ගැටළුව %[2]s`
+issues.closed_at=`මෙම ගැටළුව වසා %s`
+issues.reopened_at=`මෙම ගැටළුව නැවත විවෘත කරන ලදි %s`
+issues.ref_issue_from=`මෙම නිකුතුව %[3]s හි %[1]s`
+issues.ref_pull_from=`මෙම අදින්න ඉල්ලීම%[3]s %[1]s`
+issues.ref_closing_from=`මෙම ගැටළුව වසා දමනු ඇත%[3]s මෙම ගැටළුව %[1]s`
+issues.ref_reopening_from=`මෙම ගැටළුව නැවත විවෘත කරනු ඇත%[3]s මෙම ගැටළුව %[1]s`
issues.ref_closed_from=`මෙම නිකුතුව%[4]s %[2]s`
issues.ref_reopened_from=`මෙම නිකුතුව%[4]s %[2]sනැවත විවෘත කරන ලදි`
issues.ref_from=`හිම%[1]s`
@@ -1342,8 +1342,8 @@ pulls.update_branch_rebase=රිබේස් මගින් ශාඛාව
pulls.update_branch_success=ශාඛා යාවත්කාලීන කිරීම සාර්ථක විය
pulls.update_not_allowed=ශාඛාව යාවත්කාලීන කිරීමට ඔබට අවසර නැත
pulls.outdated_with_base_branch=මෙම ශාඛාව මූලික ශාඛාව සමඟ දිවයයි
-pulls.closed_at=`මෙම අදින්න ඉල්ලීම වසා %[2]s`
-pulls.reopened_at=`මෙම අදින්න ඉල්ලීම නැවත විවෘත කරන ලදි %[2]s`
+pulls.closed_at=`මෙම අදින්න ඉල්ලීම වසා %s`
+pulls.reopened_at=`මෙම අදින්න ඉල්ලීම නැවත විවෘත කරන ලදි %s`
diff --git a/options/locale/locale_sr-SP.ini b/options/locale/locale_sr-SP.ini
index 56c1a7e650..b14fdc1a35 100644
--- a/options/locale/locale_sr-SP.ini
+++ b/options/locale/locale_sr-SP.ini
@@ -326,7 +326,7 @@ issues.no_content=Још нема садржаја.
issues.close_issue=Затвори
issues.reopen_issue=Поново отвори
issues.create_comment=Коментирај
-issues.commit_ref_at=`поменуо овај задатак у комит %[2]s`
+issues.commit_ref_at=`поменуо овај задатак у комит %s`
issues.poster=Аутор
issues.collaborator=Коаутор
issues.owner=Власник
diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini
index a4999e9751..8b43cb29b8 100644
--- a/options/locale/locale_sv-SE.ini
+++ b/options/locale/locale_sv-SE.ini
@@ -201,6 +201,9 @@ table_modal.placeholder.content = Innehåll
table_modal.label.rows = Rader
table_modal.label.columns = Kolumner
buttons.switch_to_legacy.tooltip = Använd legacy-redigeraren istället
+link_modal.url = Url
+link_modal.description = Beskrivning
+link_modal.header = Lägg till en länk
[filter]
string.asc = A - Ö
@@ -329,6 +332,7 @@ invalid_app_data_path = Sökvägen för appdata är ogiltig: %v
internal_token_failed = Misslyckades att generera intern token: %v
password_algorithm = Hashalgoritm för lösenord
invalid_password_algorithm = Ogiltig hashalgoritm för lösenord
+env_config_keys_prompt = Följande miljövariabler kommer också att tillämpas på din konfigurationsfil:
[home]
uname_holder=Användarnamn eller e-postadress
@@ -462,6 +466,41 @@ reply = eller svara på detta e-postmeddelande direkt
hi_user_x = Hej %s,
admin.new_user.user_info = Användarinformation
admin.new_user.text = Vänligen klicka här för att hantera denna användare från administratörspanelen.
+admin.new_user.subject = Ny användare %s har just registrerat sig
+totp_disabled.no_2fa = Det finns inga andra 2FA-metoder konfigurerade längre, vilket innebär att det inte längre är nödvändigt att logga in på ditt konto med 2FA.
+removed_security_key.text_1 = Säkerhetsnyckeln ”%[1]s” har just tagits bort från ditt konto.
+repo.transfer.to_you = dig
+repo.transfer.body = För att acceptera eller avvisa det, besök %s eller ignorera det helt enkelt.
+removed_security_key.no_2fa = Det finns inga andra 2FA-metoder konfigurerade längre, vilket innebär att det inte längre är nödvändigt att logga in på ditt konto med 2FA.
+release.note = Notera:
+totp_enrolled.subject = Du har aktiverat TOTP som 2FA-metod
+totp_enrolled.text_1.no_webauthn = Du har just aktiverat TOTP för ditt konto. Det innebär att du måste använda TOTP som 2FA-metod vid alla framtida inloggningar på ditt konto.
+totp_enrolled.text_1.has_webauthn = Du har just aktiverat TOTP för ditt konto. Det innebär att du vid alla framtida inloggningar på ditt konto kan använda TOTP som 2FA-metod eller någon av dina säkerhetsnycklar.
+link_not_working_do_paste = Fungerar inte länken? Prova att kopiera och klistra in den i webbläsarens adressfält.
+primary_mail_change.text_1 = Den primära e-postadressen för ditt konto har just ändrats till %[1]s. Det innebär att denna e-postadress inte längre kommer att ta emot e-postmeddelanden för ditt konto.
+totp_disabled.subject = TOTP har inaktiverats
+totp_disabled.text_1 = Tidsbaserat engångslösenord (TOTP) på ditt konto har just inaktiverats.
+account_security_caution.text_2 = Om detta inte var du, har ditt konto blivit kompromitterat. Kontakta administratören för denna webbplats.
+account_security_caution.text_1 = Om detta var du, kan du tryggt ignorera detta meddelande.
+activate_account.text_2 = Klicka på följande länk för att aktivera ditt konto inom %s:
+activate_email.text = Klicka på följande länk för att verifiera din e-postadress inom %s:
+register_notify.text_3 = Om någon annan har skapat det här kontot åt dig måste du först ställa in ditt lösenord.
+issue.x_mentioned_you = @%s2 nämnde dig:
+repo.collaborator.added.subject = %s har lagt till dig som medarbetare i %s
+repo.collaborator.added.text = Du har lagts till som medarbetare i förrådet:
+team_invite.subject = %[1]s har bjudit in dig att gå med i organisationen %[2]s
+register_notify.text_1 = detta är din registreringsbekräftelse via e-post för %s!
+release.downloads = Hämtningar:
+release.download.zip = Källkod (ZIP)
+release.download.targz = Källkod (TAR.GZ)
+repo.transfer.subject_to = %s vill överföra förrådet ”%s” till %s
+removed_security_key.subject = En säkerhetsnyckel har tagits bort
+issue_assigned.pull = @%[1] har tilldelat dig pull-begäran %[2]s i förrådet %[3]s.
+issue_assigned.issue = @%[1] har tilldelat dig ärendet %[2] i förrådet %[3].
+register_notify.text_2 = Du kan logga in på ditt konto med ditt användarnamn: %s
+reset_password.text = Om detta var du, klicka på följande länk för att återställa ditt konto inom %s:
+issue.action.force_push = %[1]s2 gjorde en force-push av %[2]s från %[3]s till %[4]s.
+repo.transfer.subject_to_you = %s vill överföra förrådet ”%s” till dig
@@ -545,6 +584,12 @@ auth_failed=Autentisering misslyckades: %v
target_branch_not_exist=Målgrenen finns inte.
+org_still_own_repo = Denna organisation äger fortfarande ett eller flera förråd, ta bort eller överför dem först.
+must_use_public_key = Den nyckel du angav är en privat nyckel. Skicka inte upp din privata nyckel någonstans. Använd istället din publika nyckel.
+unable_verify_ssh_key = SSH-nyckeln kan inte verifieras. Kontrollera att den är korrekt.
+still_own_repo = Ditt konto äger ett eller flera förråd, ta bort eller överför dem först.
+still_has_org = Ditt konto är medlem i en eller flera organisationer. Lämna dem först.
+still_own_packages = Ditt konto har ett eller flera paket, ta bort dem först.
[user]
@@ -560,6 +605,13 @@ follow=Följ
unfollow=Sluta följa
user_bio=Biografi
disabled_public_activity=Den här användaren har inaktiverat den publika synligheten av aktiviteten.
+code = Kod
+watched = Övervakade förråd
+unblock = Avblockera
+email_visibility.limited = Din e-postadress är synlig för alla autentiserade användare
+show_on_map = Visa denna plats på en karta
+settings = Användarinställningar
+block = Blockera
[settings]
@@ -760,6 +812,17 @@ email_notifications.submit=Ställ in e-postpreferenser
visibility.public=Offentlig
visibility.private=Privat
change_password = Byt lösenord
+user_block_success = Användaren har blockerats.
+blocked_since = Blockerad sedan %s
+user_unblock_success = Användaren har blivit avblockerad.
+visibility.limited = Begränsad
+visibility.limited_tooltip = Synlig endast för inloggade användare
+visibility.private_tooltip = Synlig endast för medlemmar i organisationer som du har gått med i
+select_permissions = Välj behörigheter
+permission_no_access = Ingen åtkomst
+permission_write = Läs och skriv
+user_block_yourself = Du kan inte blockera dig själv.
+gpg_token_help = Du kan skapa en signatur med hjälp av:
[repo]
owner=Ägare
@@ -1094,13 +1157,13 @@ issues.close_comment_issue=Stäng med kommentar
issues.reopen_issue=Återöppna
issues.reopen_comment_issue=Öppna igen med kommentar
issues.create_comment=Kommentera
-issues.closed_at=`stängde ärendet %[2]s`
-issues.reopened_at=`återöppnade detta ärende %[2]s`
-issues.commit_ref_at=`refererade till detta ärende från en incheckning %[2]s`
-issues.ref_issue_from=`refererade till detta ärende %[4]s %[2]s`
-issues.ref_pull_from=`refererade till denna pull-förfrågan %[4]s %[2]s`
-issues.ref_closing_from=`hänvisade till detta ärende från en pull-förfrågan %[4]s som kommer att stänga det %[2]s`
-issues.ref_reopening_from=`hänvisade till detta ärende från en pull-förfrågan %[4]s som kommer att öppna ärendet på nytt %[2]s`
+issues.closed_at=`stängde ärendet %s`
+issues.reopened_at=`återöppnade detta ärende %s`
+issues.commit_ref_at=`refererade till detta ärende från en incheckning %s`
+issues.ref_issue_from=`refererade till detta ärende %[3]s %[1]s`
+issues.ref_pull_from=`refererade till denna pull-förfrågan %[3]s %[1]s`
+issues.ref_closing_from=`hänvisade till detta ärende från en pull-förfrågan %[3]s som kommer att stänga det %[1]s`
+issues.ref_reopening_from=`hänvisade till detta ärende från en pull-förfrågan %[3]s som kommer att öppna ärendet på nytt %[1]s`
issues.ref_closed_from=`stängde detta ärende %[4]s %[2]s`
issues.ref_reopened_from=`öpnnade detta ärende igen %[4]s %[2]s`
issues.ref_from=`från %[1]s`
@@ -1693,6 +1756,21 @@ topic.manage_topics=Hantera ämnen
topic.done=Klar
topic.count_prompt=Du kan inte välja fler än 25 ämnen
settings.enter_repo_name = Ange ägar- och utvecklingskatalog-namnet exakt som det visas:
+release = Utgåva
+commitstatus.success = Lyckades
+visibility_helper = Gör förrådet privat
+download_bundle = Hämta BUNDLE
+download_zip = Hämta ZIP
+download_tar = Hämta TAR.GZ
+repo_desc_helper = Ange kort beskrivning (valfritt)
+all_branches = Alla grenar
+fork_no_valid_owners = Detta förråd kan inte förgrenas eftersom det inte finns några giltiga ägare.
+fork_to_different_account = Förgrena till ett annat konto
+size_format = %[1]s: %[2]s, %[3]s: %[4]s
+already_forked = Du har redan förgrenat %s
+commitstatus.failure = Fel
+ext_issues = Externa fel
+open_with_editor = Öppna med %s
@@ -2255,7 +2333,7 @@ project_kind = Sök projekt...
search = Sök…
type_tooltip = Söktyp
team_kind = Sök lag...
-org_kind = Sök organisationer...
+org_kind = Sök organisationer…
issue_kind = Sök ärenden...
regexp_tooltip = Tolka söktermen som ett reguljärt uttryck
code_search_unavailable = Kodsökning är för närvarande inte tillgänglig. Vänligen kontakta webbplatsadministratören.
diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini
index 2f749dfd1e..c07cefdab9 100644
--- a/options/locale/locale_tr-TR.ini
+++ b/options/locale/locale_tr-TR.ini
@@ -668,6 +668,7 @@ username_error_no_dots = ` sadece alfanumerik karakterler ("0-9","a-z","A-Z"), t
unset_password = Oturum açma kullanıcısı parola belirlemedi.
unsupported_login_type = Oturum açma türü hesap silmeyi desteklemiyor.
+email_domain_is_not_allowed = Kullanıcı e-posta adresi %s alan adı EMAIL_DOMAIN_ALLOWLIST veya EMAIL_DOMAIN_BLOCKLIST ile çelişiyor. Lütfen işleminizin beklendiğinden emin olun.
[user]
change_avatar=Profil resmini değiştir…
@@ -1593,13 +1594,13 @@ issues.close_comment_issue=Yorum Yap ve Kapat
issues.reopen_issue=Yeniden aç
issues.reopen_comment_issue=Yorum Yap ve Yeniden Aç
issues.create_comment=Yorum yap
-issues.closed_at=`%[2]s konusunu kapattı`
-issues.reopened_at=`%[2]s konusunu yeniden açtı`
-issues.commit_ref_at=`%[2]s işlemesinde bu konuyu işaret etti`
-issues.ref_issue_from=`bu konuya referansta bulundu %[4]s %[2]s`
-issues.ref_pull_from=`bu değişiklik isteğine referansta bulundu %[4]s %[2]s`
-issues.ref_closing_from=`bir değişiklik isteğine referansta bulundu %[4]s bu konu kapatılacak %[2]s`
-issues.ref_reopening_from=`bir değişiklik isteğine referansta bulundu %[4]s bu konu yeniden açılacak %[2]s`
+issues.closed_at=`%s konusunu kapattı`
+issues.reopened_at=`%s konusunu yeniden açtı`
+issues.commit_ref_at=`%s işlemesinde bu konuyu işaret etti`
+issues.ref_issue_from=`bu konuya referansta bulundu %[3]s %[1]s`
+issues.ref_pull_from=`bu değişiklik isteğine referansta bulundu %[3]s %[1]s`
+issues.ref_closing_from=`bir değişiklik isteğine referansta bulundu %[3]s bu konu kapatılacak %[1]s`
+issues.ref_reopening_from=`bir değişiklik isteğine referansta bulundu %[3]s bu konu yeniden açılacak %[1]s`
issues.ref_closed_from=`bu konuyu kapat%[4]s %[2]s`
issues.ref_reopened_from=`konuyu yeniden aç%[4]s %[2]s`
issues.ref_from=`%[1]s'den`
@@ -1906,8 +1907,8 @@ pulls.update_branch_success=Dal güncellemesi başarıyla gerçekleştirildi
pulls.update_not_allowed=Dalı güncelleme izniniz yok
pulls.outdated_with_base_branch=Bu dal, temel dal ile güncel değil
pulls.close=Değişiklik İsteğini Kapat
-pulls.closed_at=`%[2]s değişiklik isteğini kapattı`
-pulls.reopened_at=`%[2]s değişiklik isteğini yeniden açtı`
+pulls.closed_at=`%s değişiklik isteğini kapattı`
+pulls.reopened_at=`%s değişiklik isteğini yeniden açtı`
pulls.cmd_instruction_hint=`Komut satırı talimatlarını görüntüleyin.`
pulls.cmd_instruction_checkout_title=Çekme
pulls.cmd_instruction_checkout_desc=Proje deponuzdan yeni bir dalı çekin ve değişiklikleri test edin.
@@ -2163,7 +2164,7 @@ settings.pulls.allow_rebase_update=Değişiklik isteği dalının yeniden yapıl
settings.pulls.default_delete_branch_after_merge=Varsayılan olarak birleştirmeden sonra değişiklik isteği dalını sil
settings.pulls.default_allow_edits_from_maintainers=Bakımcıların düzenlemelerine izin ver
settings.releases_desc=Depo Sürümlerini Etkinleştir
-settings.packages_desc=Depo Paket Kütüğünü Etkinleştir
+settings.packages_desc=Depo paket kütüğünü etkinleştir
settings.projects_desc=Depo Projelerini Etkinleştir
settings.actions_desc=Depo İşlemlerini Etkinleştir
settings.admin_settings=Yönetici Ayarları
@@ -3492,7 +3493,7 @@ error.unit_not_allowed=Bu depo bölümüne erişme izniniz yok.
title=Paketler
desc=Depo paketlerini yönet.
empty=Henüz hiçbir paket yok.
-empty.documentation=Paket kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz.
+empty.documentation=Paket deposu hakkında daha fazla bilgi için, belgeye bakabilirsiniz.
empty.repo=Bir paket yüklediniz ama burada gösterilmiyor mu? Paket ayarlarına gidin ve bu depoya bağlantı verin.
registry.documentation=%s kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz.
filter.type=Tür
@@ -3635,9 +3636,9 @@ owner.settings.cleanuprules.remove.days=Şundan eski sürümleri kaldır
owner.settings.cleanuprules.remove.pattern=Eşleşen sürümlari kaldır
owner.settings.cleanuprules.success.update=Temizleme kuralı güncellendi.
owner.settings.cleanuprules.success.delete=Temizleme kuralı silindi.
-owner.settings.chef.title=Chef Kütüğü
+owner.settings.chef.title=Chef deposu
owner.settings.chef.keypair=Anahtar çifti üret
-owner.settings.chef.keypair.description=Chef kütüğünde kimlik doğrulaması için bir anahtar çifti gereklidir. Eğer daha önce bir anahtar çifti ürettiyseniz, yeni bir anahtar çifti üretmek eski anahtar çiftini ıskartaya çıkartacaktır.
+owner.settings.chef.keypair.description=Chef kayıt defterine gönderilen istekler kimlik doğrulama yöntemi olarak kriptografik olarak imzalanmalıdır. Bir anahtar çifti oluştururken, yalnızca genel anahtar Forgejo'da saklanır. Özel anahtar size knife ile kullanılmak üzere sağlanır. Yeni bir anahtar çifti oluşturmak öncekini geçersiz kılar.
npm.dependencies.bundle = Paketlenmiş Bağımlılıklar
rpm.repository.multiple_groups = Bu paket birçok grupta mevcut.
diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini
index d2d7c58edc..faa3f2a56e 100644
--- a/options/locale/locale_uk-UA.ini
+++ b/options/locale/locale_uk-UA.ini
@@ -694,7 +694,7 @@ disabled_public_activity=Цей користувач вимкнув публіч
joined_on = Реєстрація %s
email_visibility.private = Ваш email видно лише вам і адміністраторам
email_visibility.limited = Вашу е-пошту видно всім авторизованим
-settings = Користувацькі параметри
+settings = Користувацькі налаштування
block_user.detail_3 = Ви не зможете додати один одного в якості співавтора репозиторію.
show_on_map = Показати це місце на мапі
block_user.detail_2 = Цей користувач не зможе взаємодіяти з репозиторіями, власником яких є ви, а також із задачами та коментарями, які ви створили.
@@ -1447,7 +1447,7 @@ issues.remove_ref_at=`видалив посилання %s %s`
issues.add_ref_at=`додав посилання %s %s`
issues.delete_branch_at=`видалена гілка %s %s`
issues.filter_label=Мітка
-issues.filter_label_exclude=`Використовуйте Alt
+ клік/Enter
для виключення міток`
+issues.filter_label_exclude=Використовуйте Alt + клік для виключення міток
issues.filter_label_no_select=Всі мітки
issues.filter_milestone=Етап
issues.filter_project=Проєкт
@@ -1496,17 +1496,17 @@ issues.context.quote_reply=Цитувати відповідь
issues.context.reference_issue=Послатися в новій задачі
issues.context.edit=Редагувати
issues.context.delete=Видалити
-issues.close_comment_issue=Прокоментувати і закрити
+issues.close_comment_issue=Закрити з коментарем
issues.reopen_issue=Відкрити знову
-issues.reopen_comment_issue=Прокоментувати та відкрити знову
+issues.reopen_comment_issue=Відкрити знову з коментарем
issues.create_comment=Коментар
-issues.closed_at=`закрив цю задачу %[2]s`
-issues.reopened_at=`повторно відкрив цю задачу %[2]s`
-issues.commit_ref_at=`згадано цю задачу в коміті %[2]s`
-issues.ref_issue_from=`посилається на цю задачу %[4]s %[2]s`
-issues.ref_pull_from=`послався на цей запит злиття %[4]s %[2]s`
-issues.ref_closing_from=`згадав запит на злиття %[4]s, які закриють цю задачу %[2]s`
-issues.ref_reopening_from=`згадав запит на злиття %[4]s, які повторно відкриють цю задачу %[2]s`
+issues.closed_at=`закриває цю задачу %s`
+issues.reopened_at=`повторно відкриває цю задачу %s`
+issues.commit_ref_at=`посилається на цю задачу в коміті %s`
+issues.ref_issue_from=`посилається на цю задачу %[3]s %[1]s`
+issues.ref_pull_from=`посилається на цей запит злиття %[3]s %[1]s`
+issues.ref_closing_from=`посилається в запиті на злиття %[3]s, який закриє цю задачу, %[1]s`
+issues.ref_reopening_from=`посилається в запиті на злиття %[3]s, який повторно відкриє цю задачу, %[1]s`
issues.ref_closed_from=`закрив цю задачу %[4]s %[2]s`
issues.ref_reopened_from=`повторно відкрито цю задачу %[4]s %[2]s`
issues.ref_from=`із %[1]s`
@@ -1743,8 +1743,8 @@ pulls.update_branch_rebase=Оновити гілку перебазування
pulls.update_branch_success=Оновлення гілки пройшло успішно
pulls.update_not_allowed=Ви не можете оновити гілку
pulls.outdated_with_base_branch=Ця гілка застаріла відносно базової гілки
-pulls.closed_at=`закрив цей запит на злиття %[2]s`
-pulls.reopened_at=`повторно відкрив цей запит на злиття %[2]s`
+pulls.closed_at=`закриває цей запит на злиття %s`
+pulls.reopened_at=`повторно відкриває цей запит на злиття %s`
@@ -1887,7 +1887,7 @@ settings.collaboration.owner=Власник
settings.collaboration.undefined=Не визначено
settings.hooks=Веб-хуки
settings.githooks=Git хуки
-settings.basic_settings=Базові налаштування
+settings.basic_settings=Основні налаштування
settings.mirror_settings=Налаштування дзеркала
settings.mirror_settings.mirrored_repository=Віддзеркалений репозиторій
settings.mirror_settings.direction=Напрямок
@@ -2055,12 +2055,12 @@ settings.event_issue_assign=Призначення
settings.event_issue_assign_desc=Задачу призначено або скасовано.
settings.event_issue_label=Мітки
settings.event_issue_label_desc=Додавання або видалення міток задач.
-settings.event_issue_milestone=Задача з етапом
+settings.event_issue_milestone=Етапи
settings.event_issue_milestone_desc=Етап призначено, видалено або змінено.
settings.event_issue_comment=Коментарі
settings.event_issue_comment_desc=Коментар задачі створено, видалено чи відредаговано.
settings.event_header_pull_request=Події запиту на злиття
-settings.event_pull_request=Запити до злиття
+settings.event_pull_request=Зміна
settings.event_pull_request_desc=Запит до злиття відкрито, закрито, перевідкрито або відредаговано.
settings.event_pull_request_assign=Призначення
settings.event_pull_request_assign_desc=Запит про злиття призначено або скасовано.
@@ -2485,7 +2485,7 @@ signing.will_sign = Коміт буде підписано ключем «%s».
signing.wont_sign.error = Під час перевірки можливості підписати коміт сталася помилка.
commits.search_branch = У цій гілці
ext_wiki = Зовнішня вікі
-pulls.commit_ref_at = `посилається на цей запит на злиття в коміті %[2]s`
+pulls.commit_ref_at = `посилається на цей запит на злиття в коміті %s`
pulls.cmd_instruction_hint = Переглянути інструкції для командного рядка
issues.max_pinned = Неможливо закріпити більше задач
issues.unpin_comment = відкріпив %s
@@ -2668,6 +2668,7 @@ settings.event_action_success = Успіх
settings.event_action_recover = Відновлено
commitstatus.success = Успіх
commitstatus.failure = Збій
+issues.filter_type.all_pull_requests = Усі запити на злиття
[graphs]
contributors.what = внески
@@ -2846,7 +2847,7 @@ dashboard.update_migration_poster_id=Оновити мігровані ID авт
dashboard.git_gc_repos=Виконати очистку сміття для всіх репозиторіїв
dashboard.resync_all_sshkeys=Оновити файл «.ssh/authorized_keys» з SSH-ключами Forgejo.
dashboard.resync_all_sshprincipals=Оновити файл «.ssh/authorized_principals» з SSH даними користувача Forgejo.
-dashboard.resync_all_hooks=Пересинхронізувати перед-прийнятні, оновлюючі та пост-прийнятні хуки в усіх репозиторіях
+dashboard.resync_all_hooks=Пересинхронізувати хуки pre-receive, update та post-receive в усіх репозиторіях
dashboard.reinit_missing_repos=Переініціалізувати усі репозитрії git-файли яких втрачено
dashboard.sync_external_users=Синхронізувати дані зовнішніх користувачів
dashboard.cleanup_hook_task_table=Очистити hook_task таблицю
@@ -2905,7 +2906,7 @@ users.edit_account=Редагувати обліковий запис
users.max_repo_creation=Максимальна кількість репозиторіїв
users.max_repo_creation_desc=(Введіть -1, щоб використовувати глобальний ліміт за замовчуванням.)
users.is_activated=Обліковий запис користувача увімкнено
-users.prohibit_login=Вимкнути вхід
+users.prohibit_login=Заблокований обліковий запис
users.is_admin=Обліковий запис адміністратора
users.is_restricted=Обмежений
users.allow_git_hook=Може створювати Git хуки
@@ -3231,7 +3232,7 @@ notices.view_detail_header=Переглянути деталі повідомл
notices.select_all=Вибрати все
notices.deselect_all=Скасувати виділення
notices.inverse_selection=Інвертувати виділене
-notices.delete_selected=Видалити обране
+notices.delete_selected=Видалити вибране
notices.delete_all=Видалити всі cповіщення
notices.type=Тип
notices.type_1=Репозиторій
@@ -3304,6 +3305,7 @@ dashboard.cron.cancelled = Cron: %[1]s скасовано: %[3]s
defaulthooks.desc = Вебхуки автоматично сповіщають HTTP-сервер POST-запитами, коли в Forgejo відбуваються певні події. Вказані тут вебхуки є типовими і будуть скопійовані до всіх нових репозиторіїв. Докладніше — в посібнику з вебхуків.
assets = Ресурси коду
auths.invalid_openIdConnectAutoDiscoveryURL = Неправильна URL-адреса автоматичного виявлення (повинна бути дійсна URL-адреса, що починається з http:// або https://)
+settings = Налаштування адміністратора
[action]
diff --git a/options/locale/locale_vi.ini b/options/locale/locale_vi.ini
index 57e592a209..28577bc3f7 100644
--- a/options/locale/locale_vi.ini
+++ b/options/locale/locale_vi.ini
@@ -9,7 +9,7 @@ sign_up = Đăng ký
link_account = Liên kết tài khoản
register = Đăng ký
version = Phiên bản
-powered_by = Sử dụng %s
+powered_by = Được cung cấp bởi %s
page = Trang
template = Mẫu
language = Ngôn ngữ
@@ -25,7 +25,7 @@ access_token = Mã truy cập
captcha = CAPTCHA
twofa = Xác thực hai lớp
webauthn_insert_key = Cắm khóa bảo mật của bạn vào
-copy_hash = Chép chuỗi băm
+copy_hash = Sao chép chuỗi băm
sign_in_with_provider = Đăng nhập bằng %s
webauthn_press_button = Hãy nhấn nút trên khóa bảo mật…
webauthn_use_twofa = Dùng mã xác thực hai lớp ở trên điện thoại
@@ -36,7 +36,7 @@ webauthn_error_insecure = WebAuthn chỉ hỗ trợ kết nối mã hóa. Nếu
webauthn_error_unable_to_process = Máy chủ không thể xử lý yêu cầu của bạn.
webauthn_error_empty = Bạn phải đặt tên cho khóa này.
webauthn_error_timeout = Hết thời gian đọc khóa mất rồi. Hãy tải lại trang và thử lại.
-copy_type_unsupported = Không chép được
+copy_type_unsupported = Không thể sao chép loại tệp này
repository = Kho mã
organization = Tổ chức
new_fork = Tạo một nhánh mới
@@ -55,17 +55,17 @@ all = Tất cả
sources = Nguồn
forks = Các phân nhánh
activities = Hoạt động
-pull_requests = Yêu cầu thêm mã
+pull_requests = Yêu cầu kéo mã
save = Lưu
-issues =
+issues =Vấn đề
enabled = Bật
disabled = Tắt
-copy = Chép
-copy_generic = Chép vào bộ nhớ tạm
-copy_url = Chép URL
-copy_content = Chép nội dung
-copy_success = Đã chép!
-copy_error = Không chép được
+copy = Sao chép
+copy_generic = Sao chép vào bộ nhớ tạm
+copy_url = Sao chép URL
+copy_content = Sao chép nội dung
+copy_success = Đã sao chép!
+copy_error = Sao chép thất bại
write = Viết
preview = Xem trước
error = Lỗi
@@ -73,7 +73,7 @@ error413 = Bạn đã dùng hết định mức.
go_back = Quay lại
invalid_data = Dữ liệu không hợp lệ: %v
never = Không bao giờ
-unknown = Không biết
+unknown = Không xác định
unpin = Bỏ ghim
pin = Ghim
archived = Đã lưu trữ
@@ -81,6 +81,60 @@ signed_in_as = Đăng nhập bằng
re_type = Xác nhận mật khẩu
webauthn_sign_in = Nhấn nút trên khóa bảo mật, nếu không có nút thì bạn hãy rút ra rồi cắm lại.
new_org.link = Tạo tổ chức
-error404 = Trang bạn đang tìm không tồn tại hoặc bạn không có quyền xem.
+error404 = Trang bạn đang tìm không tồn tại, đã bị xoá hoặc bạn không có quyền để xem nó.
edit = Chỉnh sửa
-filter = Lọc
\ No newline at end of file
+filter = Bộ lọc
+dashboard = Trang quản lý
+logo = Logo
+toc = Mục lục
+user_profile_and_more = Hồ sơ và cài đặt…
+passcode = Mã xác thực
+webauthn_error_duplicated = Khóa bảo mật không được phép cho yêu cầu này. Vui lòng đảm bảo rằng khóa chưa được đăng ký trước đó.
+mirror = Bản sao
+new_mirror = Tạo bản sao mới
+your_starred = Đã đánh sao
+mirrors = Các bản sao
+concept_system_global = Chung
+concept_user_individual = Cá nhân
+show_log_seconds = Hiện giây
+show_full_screen = Toàn màn hình
+download_logs = Tải xuống nhật ký
+confirm_delete_selected = Xác nhận xoá tất cả mục được chọn?
+name = Tên
+filter.clear = Xoá bộ lọc
+filter.not_fork = Không phải phân nhánh
+filter.not_archived = Không bị lưu trữ
+filter.is_archived = Bị lưu trữ
+filter.is_fork = Phân nhánh
+filter.is_mirror = Bản sao
+filter.is_template = Mẫu
+filter.not_template = Không phải mẫu
+filter.public = Công khai
+filter.private = Riêng tư
+twofa_scratch = Mã xác thực 2 lớp dự phòng
+collaborative = Cộng tác
+milestones = Cột mốc
+cancel = Huỷ bỏ
+retry = Thử lại
+rerun = Chạy lại
+rerun_all = Chạy lại tất cả
+ok = Đồng ý
+add = Thêm
+add_all = Thêm tất cả
+remove = Xoá
+remove_all = Xoá tất cả
+remove_label_str = Xoá "%s"
+locked = Bị khoá
+copy_branch = Sao chép tên nhánh
+loading = Đang tải…
+rss_feed = Nguồn RSS
+confirm_delete_artifact = Bạn có chắc muốn xoá "%s" ?
+value = Giá trị
+copy_path = Sao chép đường dẫn
+filter.not_mirror = Không phải bản sao
+show_timestamps = Hiện mốc thời gian
+concept_code_repository = Kho mã
+concept_user_organization = Tổ chức
+
+[search]
+search = Tìm kiếm…
\ No newline at end of file
diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini
index acdd4c0ced..c6c534df9f 100644
--- a/options/locale/locale_zh-CN.ini
+++ b/options/locale/locale_zh-CN.ini
@@ -1062,8 +1062,8 @@ language.description = 此语言将保存到您的账号中,并在您登录后
language.localization_project = 帮助我们将 Forgejo 翻译成您的语言!了解更多。
user_block_yourself = 您不能屏蔽自己。
pronouns_custom_label = 自定义代词
-change_username_redirect_prompt.with_cooldown.one = 旧的用户名将在%[1]d天的保护期后对所有人可用,您仍可以在此期间重新认领旧的用户名。
-change_username_redirect_prompt.with_cooldown.few = 旧的用户名将在%[1]d天的保护期后对所有人可用,您仍可以在此期间重新认领旧的用户名。
+change_username_redirect_prompt.with_cooldown.one = 旧用户名将在 %[1]d 天的保护期后对所有人可用,您仍可以在此期间重新认领旧用户名。
+change_username_redirect_prompt.with_cooldown.few = 旧用户名将在 %[1]d 天的保护期后对所有人可用,您仍可以在此期间重新认领旧用户名。
keep_pronouns_private = 仅向已认证用户显示代词
keep_pronouns_private.description = 这将对未登录的访问者隐藏您的代词。
quota = 配额
@@ -1581,7 +1581,7 @@ issues.remove_ref_at=`删除了引用 %s %s`
issues.add_ref_at=`添加了引用 %s %s`
issues.delete_branch_at=`于 %[2]s 删除了分支 %[1]s`
issues.filter_label=标签筛选
-issues.filter_label_exclude=`使用 alt
+ 鼠标左键 / 回车
排除标签`
+issues.filter_label_exclude=使用 Alt + 单击 排除标签
issues.filter_label_no_select=所有标签
issues.filter_label_select_no_label=无标签
issues.filter_milestone=里程碑筛选
@@ -1655,13 +1655,13 @@ issues.close_comment_issue=评论并关闭
issues.reopen_issue=重新开放
issues.reopen_comment_issue=重新打开并评论
issues.create_comment=评论
-issues.closed_at=`于%[2]s关闭此议题`
-issues.reopened_at=`重新打开此问题 %[2]s`
-issues.commit_ref_at=`于%[2]s在代码提交中引用了该议题`
-issues.ref_issue_from=`引用了议题 %[4]s %[2]s`
-issues.ref_pull_from=`引用了合并请求 %[4]s %[2]s`
-issues.ref_closing_from=`于 %[2]s 从合并请求 %[4]s引用了此议题,将关闭此议题`
-issues.ref_reopening_from=`于 %[2]s 引用了合并请求 %[4]s 将重新讨论此议题 `
+issues.closed_at=`于 %s 关闭了此议题`
+issues.reopened_at=`于 %s 重新打开了此议题`
+issues.commit_ref_at=`于 %s 从提交中引用了此议题`
+issues.ref_issue_from=`引用了此议题 %[3]s %[1]s`
+issues.ref_pull_from=`引用了此合并请求 %[3]s %[1]s`
+issues.ref_closing_from=`于 %[1]s 从合并请求 %[3]s 引用了此议题,将关闭此议题`
+issues.ref_reopening_from=`于 %[1]s 从合并请求 %[3]s 引用了此议题,将重新打开此议题 `
issues.ref_closed_from=`关闭了这个议题 %[4]s %[2]s`
issues.ref_reopened_from=`重新打开这个议题 %[4]s %[2]s`
issues.ref_from=`来自 %[1]s`
@@ -1969,8 +1969,8 @@ pulls.update_branch_success=分支更新成功
pulls.update_not_allowed=您无权更新分支
pulls.outdated_with_base_branch=此分支相比基础分支已过期
pulls.close=关闭
-pulls.closed_at=`于%[2]s关闭此合并请求 `
-pulls.reopened_at=`重新打开此合并请求 %[2]s`
+pulls.closed_at=`于 %s 关闭了此合并请求 `
+pulls.reopened_at=`于 %s 重新打开了此合并请求`
pulls.cmd_instruction_hint=查看命令行说明
pulls.cmd_instruction_checkout_title=检出
pulls.cmd_instruction_checkout_desc=从你的仓库中检出一个新的分支并测试变更。
@@ -2770,7 +2770,7 @@ settings.wiki_rename_branch_main = 标准化百科分支名称
settings.wiki_rename_branch_main_notices_1 = 此操作无法撤消。
settings.wiki_branch_rename_success = 百科仓库的分支名称已成功规范化。
settings.confirm_wiki_branch_rename = 重命名百科分支
-pulls.commit_ref_at = `在提交 %[2]s 中引用了此合并请求`
+pulls.commit_ref_at = `于 %s 从提交中引用了此合并请求`
settings.wiki_rename_branch_main_notices_2 = 这将永久重命名 %s 的仓库百科的内部分支。现存的检出方式需要更新。
settings.wiki_branch_rename_failure = 无法标准化仓库百科的分支名称。
settings.add_collaborator_blocked_our = 因仓库所有者已将其拉黑,不能添加该用户为协作者。
@@ -2922,6 +2922,7 @@ settings.event_action_success = 成功
settings.event_action_success_desc = Action运行以成功结束。
settings.event_action_failure_desc = Action运行以失败结束。
settings.event_header_action = Action运行事件
+issues.filter_type.all_pull_requests = 所有合并请求
[graphs]
component_loading=正在加载 %s…
@@ -3057,8 +3058,8 @@ teams.invite.by=邀请人 %s
teams.invite.description=请点击下面的按钮加入团队。
follow_blocked_user = 你无法关注此组织,因为此组织已屏蔽你。
open_dashboard = 打开仪表盘
-settings.change_orgname_redirect_prompt.with_cooldown.one = 旧的组织名将在%[1]d天的保护期后对所有人可用,您仍可以在此期间重新认领旧的名字。
-settings.change_orgname_redirect_prompt.with_cooldown.few = 旧的组织名将在%[1]d天的保护期后对所有人可用,您仍可以在此期间重新认领旧名字。
+settings.change_orgname_redirect_prompt.with_cooldown.one = 旧组织名将在 %[1]d 天的保护期后对所有人可用,您仍可以在此期间重新认领旧名称。
+settings.change_orgname_redirect_prompt.with_cooldown.few = 旧组织名将在 %[1]d 天的保护期后对所有人可用,您仍可以在此期间重新认领旧名称。
[admin]
dashboard=管理面板
diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini
index e2cb0d8b2c..45534801de 100644
--- a/options/locale/locale_zh-HK.ini
+++ b/options/locale/locale_zh-HK.ini
@@ -574,7 +574,7 @@ issues.delete_comment_confirm=您確定要刪除該條評論嗎?
issues.context.edit=編輯
issues.reopen_issue=重新開啟
issues.create_comment=評論
-issues.commit_ref_at=`在代碼提交 %[2]s 中引用了該問題`
+issues.commit_ref_at=`在代碼提交 %s 中引用了該問題`
issues.role.owner=管理員
issues.role.member=普通成員
issues.sign_in_require_desc= 登入 才能加入這對話。
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index b21e4c8f79..fba51a391e 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -1604,13 +1604,13 @@ issues.close_comment_issue=留言並關閉
issues.reopen_issue=重新開放
issues.reopen_comment_issue=留言並重新開放
issues.create_comment=留言
-issues.closed_at=`關閉了這個問題 %[2]s`
-issues.reopened_at=`重新開放了這個問題 %[2]s`
-issues.commit_ref_at=`在提交中關聯了這個問題 %[2]s`
-issues.ref_issue_from=`關聯了這個問題 %[4]s %[2]s`
-issues.ref_pull_from=`關聯了這個合併請求 %[4]s %[2]s`
-issues.ref_closing_from=從將關閉此問題的拉取請求 %[4]s 中提及了此問題,%[2]s
-issues.ref_reopening_from=從將重新開啟此問題的拉取請求 %[4]s 中提及了此問題,%[2]s
+issues.closed_at=`關閉了這個問題 %s`
+issues.reopened_at=`重新開放了這個問題 %s`
+issues.commit_ref_at=`在提交中關聯了這個問題 %s`
+issues.ref_issue_from=`關聯了這個問題 %[3]s %[1]s`
+issues.ref_pull_from=`關聯了這個合併請求 %[3]s %[1]s`
+issues.ref_closing_from=從將關閉此問題的拉取請求 %[3]s 中提及了此問題,%[1]s
+issues.ref_reopening_from=從將重新開啟此問題的拉取請求 %[3]s 中提及了此問題,%[1]s
issues.ref_closed_from=`關閉了這個問題 %[4]s %[2]s`
issues.ref_reopened_from=`重新開放了這個問題 %[4]s %[2]s`
issues.ref_from=`自 %[1]s`
@@ -1879,8 +1879,8 @@ pulls.update_branch_success=分支更新成功
pulls.update_not_allowed=您無權更新分支
pulls.outdated_with_base_branch=相對於基底分支,此分支已過時
pulls.close=關閉合併請求
-pulls.closed_at=`關閉了這個合併請求 %[2]s`
-pulls.reopened_at=`重新開放了這個合併請求 %[2]s`
+pulls.closed_at=`關閉了這個合併請求 %s`
+pulls.reopened_at=`重新開放了這個合併請求 %s`
pulls.clear_merge_message=清除合併訊息
pulls.clear_merge_message_hint=清除合併訊息將僅移除提交訊息內容,留下產生的 git 結尾,如「Co-Authored-By …」。
@@ -2634,7 +2634,7 @@ commits.search_branch = 此分支
commits.browse_further = 進一步瀏覽
commits.renamed_from = 自 %s 重新命名
issues.filter_milestone_none = 沒有里程碑
-issues.num_comments_1 = %s 則留言
+issues.num_comments_1 = %d 則留言
issues.no_content = 沒有提供敘述。
settings.new_owner_blocked_doer = 新的所有者已封鎖您。
new_repo_helper = 一個儲存庫包含專案的所有檔案和它們的修訂歷史。在別處已經有儲存庫了嗎?遷移儲存庫。
@@ -2693,7 +2693,7 @@ signing.wont_sign.never = 永不簽署提交。
editor.push_out_of_date = 該推送似乎過期了。
issues.cancel_tracking_history = `已取消時間追蹤 %s`
issues.due_date_not_writer = 您需要有寫入這個儲存庫的權限才能更新其問題的到期日。
-pulls.commit_ref_at = `在提交 %[2]s 引用了這個合併請求`
+pulls.commit_ref_at = `在提交 %s 引用了這個合併請求`
pulls.cmd_instruction_checkout_desc = 從您的專案儲存庫中,建立並切換到一個新分支以測試這些變更。
pulls.cmd_instruction_merge_title = 合併
pulls.ready_for_review = 可以開始審閱了嗎?
diff --git a/options/locale_next/locale_cs-CZ.json b/options/locale_next/locale_cs-CZ.json
index 0e3ea260de..97a8536d4f 100644
--- a/options/locale_next/locale_cs-CZ.json
+++ b/options/locale_next/locale_cs-CZ.json
@@ -102,5 +102,8 @@
"editor.textarea.tab_hint": "Řádek je již odsazen. Pro opuštění editoru stiskněte znovu Tab nebo Escape.",
"editor.textarea.shift_tab_hint": "Na tomto řádku není žádné odsazení. Pro opuštění editoru stiskněte znovu Shift + Tab nebo Escape.",
"admin.dashboard.cleanup_offline_runners": "Vymazat offline runnery",
- "settings.visibility.description": "Viditelnost profilu ovlivňuje možnost ostatních přistupovat k vašim veřejným repozitářům. Zjistit více"
+ "settings.visibility.description": "Viditelnost profilu ovlivňuje možnost ostatních přistupovat k vašim veřejným repozitářům. Zjistit více",
+ "avatar.constraints_hint": "Velikost vlastního avataru nesmí překročit %[1]s nebo být větší než %[2]dx%[3]d pixelů",
+ "repo.diff.commit.next-short": "Další",
+ "repo.diff.commit.previous-short": "Předchozí"
}
diff --git a/options/locale_next/locale_da.json b/options/locale_next/locale_da.json
index fe3c25ab2e..8315e06bcc 100644
--- a/options/locale_next/locale_da.json
+++ b/options/locale_next/locale_da.json
@@ -92,5 +92,10 @@
"followers.outgoing.list.self.none": "Du følger ikke nogen.",
"followers.outgoing.list.none": "%s følger ikke nogen.",
"editor.textarea.tab_hint": "Linjen er allerede indrykket. Tryk på Tab igen eller Escape for at forlade editoren.",
- "editor.textarea.shift_tab_hint": "Ingen indrykning på denne linje. Tryk på Shift + Tab igen eller Escape for at forlade editoren."
+ "editor.textarea.shift_tab_hint": "Ingen indrykning på denne linje. Tryk på Shift + Tab igen eller Escape for at forlade editoren.",
+ "admin.dashboard.cleanup_offline_runners": "Ryd op offline runners",
+ "settings.visibility.description": "Profilsynlighed påvirker andres adgang til dine ikke-private depoter. Læs mere",
+ "avatar.constraints_hint": "Brugerdefineret avatar må ikke overstige %[1]s i størrelse eller være større end %[2]dx%[3]d pixels",
+ "repo.diff.commit.next-short": "Næste",
+ "repo.diff.commit.previous-short": "Forrige"
}
diff --git a/options/locale_next/locale_de-DE.json b/options/locale_next/locale_de-DE.json
index 846e85d094..3847de2b43 100644
--- a/options/locale_next/locale_de-DE.json
+++ b/options/locale_next/locale_de-DE.json
@@ -93,5 +93,14 @@
"followers.incoming.list.none": "Niemand folgt diesem Benutzer.",
"editor.textarea.tab_hint": "Zeile bereits eingerückt. Drücke nochmals Tab oder Escape um den Editor zu verlassen.",
"editor.textarea.shift_tab_hint": "Keine Einrückung auf dieser Zeile. Drücke nochmals Shift + Tab oder Escape um den Editor zu verlassen.",
- "admin.dashboard.cleanup_offline_runners": "Aufräumen der offline Runner"
+ "admin.dashboard.cleanup_offline_runners": "Aufräumen der offline Runner",
+ "settings.visibility.description": "Die Profilsichtbarkeit beeinflusst die Möglichkeit anderer, auf deine nicht-privaten Repositorys zuzugreifen. Erfahre mehr",
+ "avatar.constraints_hint": "Individuelles Profilbild darf %[1]s in der Größe nicht überschreiten, und nicht größer als %[2]dx%[3]d Pixel sein",
+ "repo.diff.commit.next-short": "Nächste",
+ "repo.diff.commit.previous-short": "Vorherige",
+ "profile.edit.link": "Profil bearbeiten",
+ "feed.atom.link": "Atom-Feed",
+ "keys.ssh.link": "SSH-Schlüssel",
+ "keys.gpg.link": "GPG-Schlüssel",
+ "profile.actions.tooltip": "Mehr Aktionen"
}
diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json
index c7e9f65a68..b1c98e4551 100644
--- a/options/locale_next/locale_en-US.json
+++ b/options/locale_next/locale_en-US.json
@@ -63,6 +63,11 @@
"alert.asset_load_failed": "Failed to load asset files from {path}. Please make sure the asset files can be accessed.",
"alert.range_error": " must be a number between %[1]s and %[2]s.",
"install.invalid_lfs_path": "Unable to create the LFS root at the specified path: %[1]s",
+ "profile.actions.tooltip": "More actions",
+ "profile.edit.link": "Edit profile",
+ "feed.atom.link": "Atom feed",
+ "keys.ssh.link": "SSH keys",
+ "keys.gpg.link": "GPG keys",
"admin.config.moderation_config": "Moderation configuration",
"moderation.report_abuse": "Report abuse",
"moderation.report_content": "Report content",
@@ -89,10 +94,13 @@
"mail.actions.run_info_previous_status": "Previous Run's Status: %[1]s",
"mail.actions.run_info_ref": "Branch: %[1]s (%[2]s)",
"mail.actions.run_info_trigger": "Triggered because: %[1]s by: %[2]s",
+ "repo.diff.commit.next-short": "Next",
+ "repo.diff.commit.previous-short": "Prev",
"discussion.locked": "This discussion has been locked. Commenting is limited to contributors.",
"editor.textarea.tab_hint": "Line already indented. Press Tab again or Escape to leave the editor.",
"editor.textarea.shift_tab_hint": "No indentation on this line. Press Shift + Tab again or Escape to leave the editor.",
"admin.dashboard.cleanup_offline_runners": "Cleanup offline runners",
"settings.visibility.description": "Profile visibility affects others' ability to access your non-private repositories. Learn more",
+ "avatar.constraints_hint": "Custom avatar may not exceed %[1]s in size or be larger than %[2]dx%[3]d pixels",
"meta.last_line": "Thank you for translating Forgejo! This line isn't seen by the users but it serves other purposes in the translation management. You can place a fun fact in the translation instead of translating it."
}
diff --git a/options/locale_next/locale_fil.json b/options/locale_next/locale_fil.json
index 1f1e535dad..884a7b44eb 100644
--- a/options/locale_next/locale_fil.json
+++ b/options/locale_next/locale_fil.json
@@ -21,7 +21,7 @@
"alert.asset_load_failed": "Nabigong i-load ang mga asset file mula sa {path}. Siguraduhin na maa-access ang mga asset file.",
"install.invalid_lfs_path": "Nabigong gawin ang LFS root sa tinakdang path: %[1]s",
"alert.range_error": " dapat ay numero sa pagitan ng %[1]s at %[2]s.",
- "meta.last_line": "Sayori... I love you. — MC from Doki Doki Literature Club",
+ "meta.last_line": "Every day, I imagine a future where I can be with you. In my hand is a pen that will write a poem of me and you. The ink flows down into a dark puddle... Just move your hand, write the way into his heart. But in this world of infinite choices. What will it take just to find that special day? Have I found everybody a fun assignment to do today? When you're here, everything that we do is fun for them anyway... When I can't even read my own feelings. What good are words when a smile says it all? And if this world won't write me an ending... What will it take just for me to have it all? Does my pen only write bitter words for those who are dear to me? Is it love if I take you, or is it love if I set you free? The ink flows down into a dark puddle... How can I write love into reality? If I can't hear the sound of your heartbeat What do you call love in your reality? And in your reality, if I don't know how to love you... I'll leave you be.",
"mail.actions.successful_run_after_failure": "Na-recover ang workflow na %[1]s sa repositoryong %[2]s",
"mail.actions.not_successful_run": "Nabigo ang workflow na %[1]s sa repositoryong %[2]s",
"mail.actions.run_info_previous_status": "Nakaraang Status ng Run: %[1]s",
@@ -94,5 +94,13 @@
"editor.textarea.tab_hint": "Naka-indent na ang linya. Pindutin ulit ang Tab o Escape para umalis sa editor.",
"editor.textarea.shift_tab_hint": "Walang indentation sa linyang ito. Pindutin ang Shift + Tab ulit o Escape para umalis sa editor.",
"admin.dashboard.cleanup_offline_runners": "Linisin ang mga offline na runner",
- "settings.visibility.description": "Maaapektuhan ng visibility ng profile ang kakayahan ng iba na i-access ang iyong mga hindi pribadong repositoryo. Matuto pa"
+ "settings.visibility.description": "Maaapektuhan ng visibility ng profile ang kakayahan ng iba na i-access ang iyong mga hindi pribadong repositoryo. Matuto pa",
+ "avatar.constraints_hint": "Hindi maaaring lumagpas sa laking %[1]s o mas malaki sa %[2]dx%[3]d pixel ang custom na avatar",
+ "repo.diff.commit.next-short": "Susunod",
+ "repo.diff.commit.previous-short": "Nakaraan",
+ "profile.edit.link": "I-edit ang profile",
+ "feed.atom.link": "Atom feed",
+ "keys.ssh.link": "Mga SSH key",
+ "keys.gpg.link": "Mga GPG key",
+ "profile.actions.tooltip": "Higit pang mga aksyon"
}
diff --git a/options/locale_next/locale_fr-FR.json b/options/locale_next/locale_fr-FR.json
index 0792804bf2..da26d56107 100644
--- a/options/locale_next/locale_fr-FR.json
+++ b/options/locale_next/locale_fr-FR.json
@@ -6,7 +6,7 @@
},
"repo.pulls.title_desc": {
"one": "veut fusionner %[1]d commit depuis %[2]s
vers %[3]s
",
- "many": "souhaite fusionner %[1]d révision(s) depuis %[2]s
vers %[3]s
",
+ "many": "veut fusionner %[1]d commits depuis %[2]s
vers %[3]s
",
"other": ""
},
"search.milestone_kind": "Recherche dans les jalons…",
@@ -97,5 +97,11 @@
"repo.issue_indexer.title": "Indexeur de problèmes",
"stars.list.none": "Personne n'a mis d'étoiles sur ce dépôt.",
"watch.list.none": "Personne ne consulte ce dépôt.",
- "repo.form.cannot_create": "Tous les espaces dans lesquels vous pouvez créer des dépôts ont atteint la limite de dépôts."
+ "repo.form.cannot_create": "Tous les espaces dans lesquels vous pouvez créer des dépôts ont atteint la limite de dépôts.",
+ "admin.dashboard.cleanup_offline_runners": "Nettoyer les exécuteurs hors ligne",
+ "mail.actions.run_info_trigger": "Déclenché parce que : %[1]s par : %[2]s",
+ "settings.visibility.description": "La visibilité du profil affecte la capacité des autres à accéder à vos dépôts non-privés. Voir plus",
+ "editor.textarea.shift_tab_hint": "Pas d'indentation sur cette ligne. Appuyez sur Maj + Tab une nouvelle fois ou sur Échap pour quitter l'éditeur.",
+ "avatar.constraints_hint": "L'avatar personnalisé ne doit pas dépasser une taille de %[1]s ou être plus grand que %[2]dx%[3]d pixels",
+ "editor.textarea.tab_hint": "Ligne déjà indentée. Appuyez sur Tab une nouvelle fois ou sur Échap pour quitter l'éditeur."
}
diff --git a/options/locale_next/locale_it-IT.json b/options/locale_next/locale_it-IT.json
index 8bd6d811a0..8464d6244e 100644
--- a/options/locale_next/locale_it-IT.json
+++ b/options/locale_next/locale_it-IT.json
@@ -15,5 +15,83 @@
"home.welcome.no_activity": "Nessun'attività",
"home.explore_repos": "Esplora i repositori",
"home.explore_users": "Esplora l'utenza",
- "home.explore_orgs": "Esplora le organizzazioni"
+ "home.explore_orgs": "Esplora le organizzazioni",
+ "mail.actions.successful_run_after_failure_subject": "Il flusso di lavoro %[1] ha ripreso a funzionare nel repositorio %[2]s",
+ "mail.actions.not_successful_run_subject": "Il flusso di lavoro %[1]s è fallito nel repositorio %[2]s",
+ "relativetime.future": "nel futuro",
+ "relativetime.days": {
+ "one": "ieri",
+ "many": "%d giorni fa",
+ "other": "%d giorni fa"
+ },
+ "relativetime.1day": "ieri",
+ "repo.form.cannot_create": "Tutti gli spazi in cui puoi creare repositori hanno raggiunto il limite di repositori.",
+ "discussion.locked": "Questa discussione è stata bloccata. Solo i contributori possono commentare.",
+ "relativetime.hours": {
+ "one": "un'ora fa",
+ "many": "%d ore fa",
+ "other": "%d ore fa"
+ },
+ "relativetime.2years": "due anni fa",
+ "relativetime.now": "adesso",
+ "relativetime.weeks": {
+ "one": "una settimana fa",
+ "many": "%d settimane fa",
+ "other": "%d settimane fa"
+ },
+ "relativetime.months": {
+ "one": "un mese fa",
+ "many": "%d mesi fa",
+ "other": "%d mesi fa"
+ },
+ "relativetime.years": {
+ "one": "un anno fa",
+ "many": "%d anni fa",
+ "other": "%d anni fa"
+ },
+ "repo.issue_indexer.title": "Indicizzatore delle segnalazioni",
+ "admin.config.moderation_config": "Impostazioni di moderazione",
+ "moderation.report_abuse": "Segnala abuso",
+ "moderation.report_content": "Segnala contenuto",
+ "moderation.report_abuse_form.already_reported": "Hai già segnalato questo contenuto",
+ "moderation.abuse_category": "Categoria",
+ "moderation.abuse_category.placeholder": "Seleziona una categoria",
+ "moderation.abuse_category.spam": "Spam",
+ "moderation.abuse_category.malware": "Malware",
+ "moderation.abuse_category.illegal_content": "Contenuti illegali",
+ "moderation.abuse_category.other_violations": "Altre violazioni delle regole della piattaforma",
+ "moderation.report_remarks": "Note aggiuntive",
+ "moderation.report_remarks.placeholder": "Aggiungi dettagli riguardanti l'abuso che stai segnalando.",
+ "moderation.submit_report": "Invia segnalazione",
+ "error.not_found.title": "Pagina non trovata",
+ "themes.names.forgejo-auto": "Forgejo (segui le impostazioni di sistema)",
+ "stars.list.none": "Nessuno ha messo una stella a questo repo.",
+ "watch.list.none": "Nessuno sta osservando questo repo.",
+ "followers.incoming.list.self.none": "Nessuno sta seguendo il tuo profilo.",
+ "followers.incoming.list.none": "Nessuno sta seguendo questo utente.",
+ "followers.outgoing.list.self.none": "Non segui nessuno.",
+ "followers.outgoing.list.none": "%s non sta seguendo nessuno.",
+ "relativetime.2days": "due giorni fa",
+ "relativetime.2weeks": "due settimane fa",
+ "relativetime.1week": "la settimana scorsa",
+ "relativetime.1month": "il mese scorso",
+ "relativetime.2months": "due mesi fa",
+ "relativetime.1year": "l'anno scorso",
+ "moderation.report_abuse_form.header": "Segnala abuso all'amministratore",
+ "moderation.report_abuse_form.details": "Questo modulo dovrebbe essere utilizzato per segnalare utenti che creano profili, repositori, segnalazioni o commenti spam o che si comportano in modo non adeguato.",
+ "moderation.report_abuse_form.invalid": "Argomenti non validi",
+ "moderation.reporting_failed": "Impossibile inviare segnalazione: %v",
+ "moderation.reported_thank_you": "Grazie per la segnalazione. L'amministratore è stato avvertito.",
+ "mail.actions.run_info_ref": "Ramo: %[1]s (%[2]s)",
+ "alert.asset_load_failed": "Impossibile caricare i file di risorsa da {path}. Controlla che i file di risorsa siano accessibili.",
+ "install.invalid_lfs_path": "Non è possibile creare una root LFS nel percorso specificato: %[1]s",
+ "home.welcome.activity_hint": "Non c'è nulla nel tuo feed. Le tue azioni e le attività dei repositori che segui verranno mostrate qui.",
+ "relativetime.mins": {
+ "one": "un minuto fa",
+ "many": "%d minuti fa",
+ "other": "%d minuti fa"
+ },
+ "editor.textarea.tab_hint": "Linea già indentata. Premi di nuovo Tab o Esc per uscire dall'editor.",
+ "repo.diff.commit.previous-short": "Precedente",
+ "meta.last_line": "Ambaraba cicci cocco."
}
diff --git a/options/locale_next/locale_lv-LV.json b/options/locale_next/locale_lv-LV.json
index 6386f2163b..f71cfa227d 100644
--- a/options/locale_next/locale_lv-LV.json
+++ b/options/locale_next/locale_lv-LV.json
@@ -102,5 +102,8 @@
"editor.textarea.tab_hint": "Rinda jau ir ar atkāpi. Spied Tab vēlreiz vai Escape, lai izietu no redaktora!",
"editor.textarea.shift_tab_hint": "Šajā rindā nav atkāpes. Spied Shift + Tab vēlreiz vai Escape, lai izietu no redaktora!",
"admin.dashboard.cleanup_offline_runners": "Notīrīt bezsaistes izpildītājus",
- "settings.visibility.description": "Profila redzamība ietekmē iespēju citiem piekļūt Tavām glabātavām, kas nav privātas. Uzzināt vairāk"
+ "settings.visibility.description": "Profila redzamība ietekmē iespēju citiem piekļūt Tavām glabātavām, kas nav privātas. Uzzināt vairāk",
+ "avatar.constraints_hint": "Pielāgots profila attēls nevar pārsniegt %[1]s vai būt lielāks par %[2]dx%[3]d pikseļiem",
+ "repo.diff.commit.next-short": "Nāk.",
+ "repo.diff.commit.previous-short": "Iepr."
}
diff --git a/options/locale_next/locale_nds.json b/options/locale_next/locale_nds.json
index ba8d66a2da..24268e2082 100644
--- a/options/locale_next/locale_nds.json
+++ b/options/locale_next/locale_nds.json
@@ -94,5 +94,13 @@
"editor.textarea.tab_hint": "Rieg al inschuven. Drück weer Tab of Esc, um de Bewarker to verlaten.",
"editor.textarea.shift_tab_hint": "Keen Inschuuv in deeser Rieg. Drück weer Umschalt+Tab of Esc, um de Bewarker to verlaten.",
"admin.dashboard.cleanup_offline_runners": "Nich verbunnen Lopers uprümen",
- "settings.visibility.description": "De Profil-Sichtbaarkeid maakt daar wat an, of un wo anner Lüü diene nich-privaaten Repositoriums ankieken könen. Mehr unnerhören"
+ "settings.visibility.description": "De Profil-Sichtbaarkeid maakt daar wat an, of un wo anner Lüü diene nich-privaaten Repositoriums ankieken könen. Mehr unnerhören",
+ "avatar.constraints_hint": "Dat eegene Kontobill düür nich groter as %[1]s wesen of groter as %[2]d×%[3]d Billtüttels wesen",
+ "repo.diff.commit.next-short": "Anner",
+ "repo.diff.commit.previous-short": "Vörig",
+ "feed.atom.link": "Atom-Schuuv",
+ "keys.ssh.link": "SSH-Slötels",
+ "keys.gpg.link": "GPG-Slötels",
+ "profile.actions.tooltip": "Mehr Aktioonen",
+ "profile.edit.link": "Profil bewarken"
}
diff --git a/options/locale_next/locale_pt-BR.json b/options/locale_next/locale_pt-BR.json
index 909c9339d3..1a5eca6d34 100644
--- a/options/locale_next/locale_pt-BR.json
+++ b/options/locale_next/locale_pt-BR.json
@@ -100,5 +100,10 @@
"stars.list.none": "Ninguém favoritou este repositório.",
"followers.outgoing.list.self.none": "Você não está seguindo ninguém.",
"editor.textarea.tab_hint": "Linha já indentada. Pressione Tab novamente ou Esc para sair do editor.",
- "editor.textarea.shift_tab_hint": "Sem indentação nesta linha. Pressione Shift + Tab novamente ou Esc para sair do editor."
+ "editor.textarea.shift_tab_hint": "Sem indentação nesta linha. Pressione Shift + Tab novamente ou Esc para sair do editor.",
+ "admin.dashboard.cleanup_offline_runners": "Limpar runners desconectados",
+ "avatar.constraints_hint": "Imagem de perfil personalizada não pode exceder %[1]s em tamanho ou ser maior que %[2]dx%[3]d pixels",
+ "settings.visibility.description": "A visibilidade do perfil afeta a habilidade de acessarem seus repositórios não-privados. Saiba mais",
+ "repo.diff.commit.next-short": "Próximo",
+ "repo.diff.commit.previous-short": "Anterior"
}
diff --git a/options/locale_next/locale_pt-PT.json b/options/locale_next/locale_pt-PT.json
index da27faa2ce..78e6dc4493 100644
--- a/options/locale_next/locale_pt-PT.json
+++ b/options/locale_next/locale_pt-PT.json
@@ -101,5 +101,7 @@
"editor.textarea.tab_hint": "Linha já indentada. Pressione Tab novamente ou Escape para sair do editor.",
"editor.textarea.shift_tab_hint": "Sem indentação nesta linha. Pressione Shift + Tab novamente ou Escape para sair do editor.",
"stars.list.none": "Ninguém juntou este repositório aos favoritos.",
- "admin.dashboard.cleanup_offline_runners": "Limpeza de executores offline"
+ "admin.dashboard.cleanup_offline_runners": "Limpeza de executores offline",
+ "settings.visibility.description": "A visibilidade do perfil afecta a capacidade de outros acederem aos seus repositórios não privados. Ler mais",
+ "avatar.constraints_hint": "O avatar personalizado não pode exceder %[1]s de tamanho ou ser maior do que %[2]dx%[3]d pixéis"
}
diff --git a/options/locale_next/locale_ru-RU.json b/options/locale_next/locale_ru-RU.json
index 6dd2b6fb7e..922e2612af 100644
--- a/options/locale_next/locale_ru-RU.json
+++ b/options/locale_next/locale_ru-RU.json
@@ -23,7 +23,7 @@
"alert.asset_load_failed": "Не удалось получить ресурсы из {path}. Убедитесь, что файлы ресурсов доступны.",
"install.invalid_lfs_path": "Не удалось расположить корень LFS по указанному пути: %[1]s",
"alert.range_error": " - число должно быть в диапазоне от %[1]s-%[2]s.",
- "meta.last_line": "Unskip.",
+ "meta.last_line": "Unskip..",
"mail.actions.not_successful_run_subject": "Провал раб. потока %[1]s в репозитории %[2]s",
"mail.actions.successful_run_after_failure_subject": "Возобновление раб. потока %[1]s в репозитории %[2]s",
"mail.actions.run_info_ref": "Ветвь: %[1]s (%[2]s)",
@@ -101,5 +101,14 @@
"moderation.report_abuse_form.header": "Жалоба администрации",
"editor.textarea.tab_hint": "Отступ уже добавлен. Нажмите Tab снова или Escape, чтобы покинуть редактор.",
"editor.textarea.shift_tab_hint": "В строке нет отступов. Нажмите Shift + Tab снова или Escape, чтобы покинуть редактор.",
- "admin.dashboard.cleanup_offline_runners": "Удалить недоступных исполнителей"
+ "admin.dashboard.cleanup_offline_runners": "Удалить недоступных исполнителей",
+ "avatar.constraints_hint": "Изображение профиля не может быть более %[1]s и крупнее %[2]dx%[3]d пикселей",
+ "settings.visibility.description": "Видимость профиля влияет на доступ других до ваших не частных репозиториев. Подробнее",
+ "repo.diff.commit.previous-short": "Пред.",
+ "repo.diff.commit.next-short": "След.",
+ "profile.actions.tooltip": "Показать действия",
+ "feed.atom.link": "Atom-лента",
+ "keys.ssh.link": "Ключи SSH",
+ "keys.gpg.link": "Ключи GPG",
+ "profile.edit.link": "Изменить профиль"
}
diff --git a/options/locale_next/locale_sv-SE.json b/options/locale_next/locale_sv-SE.json
index 53b25dffcb..9a8762212c 100644
--- a/options/locale_next/locale_sv-SE.json
+++ b/options/locale_next/locale_sv-SE.json
@@ -56,7 +56,7 @@
"mail.actions.successful_run_after_failure": "Arbetsflöde %[1]s återställdes i förrådet %[2]s",
"mail.actions.not_successful_run": "Arbetsflödet %[1]s misslyckades i förrådet %[2]s",
"editor.textarea.shift_tab_hint": "Ingen indragning på den här raden. Tryck på Shift + Tab igen eller Escape för att lämna redigeringsläget.",
- "meta.last_line": "Tack för att du översatte Forgejo! Daniel Nylander heter jag. https://www.danielnylander.se",
+ "meta.last_line": "Daniel Nylander heter jag och har översatt Forgejo. Mer information om mig på https://www.danielnylander.se",
"editor.textarea.tab_hint": "Raden är redan indragen. Tryck på Tab igen eller Escape för att lämna redigeringsläget.",
"home.welcome.no_activity": "Ingen aktivitet",
"home.welcome.activity_hint": "Det finns inget i ditt flöde ännu. Dina åtgärder och aktivitet från förråd som du bevakar kommer att visas här.",
@@ -93,5 +93,7 @@
"moderation.abuse_category": "Kategori",
"moderation.abuse_category.placeholder": "Välj en kategori",
"moderation.abuse_category.spam": "Skräppost",
- "moderation.abuse_category.malware": "Skadlig kod"
+ "moderation.abuse_category.malware": "Skadlig kod",
+ "settings.visibility.description": "Profilens synlighet påverkar andras möjlighet att komma åt dina icke-privata förråd. Läs mer",
+ "avatar.constraints_hint": "Anpassade avatarer får inte vara större än %[1] eller %[2]dx%[3] bildpunkter"
}
diff --git a/options/locale_next/locale_uk-UA.json b/options/locale_next/locale_uk-UA.json
index a00d368f4a..33cb5a41a3 100644
--- a/options/locale_next/locale_uk-UA.json
+++ b/options/locale_next/locale_uk-UA.json
@@ -88,10 +88,10 @@
"moderation.report_abuse_form.details": "Використовуйте цю форму, щоб повідомити про користувачів, які створюють спам-профілі, репозиторії, задачі, коментарі або поводяться неналежним чином.",
"moderation.abuse_category": "Категорія",
"moderation.abuse_category.other_violations": "Інші порушення правил платформи",
- "moderation.reporting_failed": "Не вдалося надіслати нове повідомлення про порушення: %v",
+ "moderation.reporting_failed": "Не вдалося надіслати повідомлення про порушення: %v",
"moderation.report_remarks": "Подробиці",
"moderation.reported_thank_you": "Дякуємо за ваше повідомлення. Адміністрацію поінформовано про нього.",
- "repo.form.cannot_create": "Усі простори, в яких ви можете створювати репозиторії, досягли максимальної кількості репозиторіїв.",
+ "repo.form.cannot_create": "У всіх просторах, де ви можете створювати репозиторії, досягнуто обмеження кількості репозиторіїв.",
"repo.issue_indexer.title": "Індексатор задач",
"followers.incoming.list.self.none": "Ніхто не стежить за вашим профілем.",
"followers.incoming.list.none": "Ніхто не стежить за цим користувачем.",
@@ -102,5 +102,13 @@
"editor.textarea.tab_hint": "У рядку вже є відступ. Натисніть Tab ще раз або Esc, щоб вийти з редактора.",
"editor.textarea.shift_tab_hint": "У цьому рядку немає відступів. Натисніть Shift + Tab ще раз або Esc, щоб вийти з редактора.",
"admin.dashboard.cleanup_offline_runners": "Очистити неактивні раннери",
- "settings.visibility.description": "Видимість профілю впливає на можливість інших користувачів отримати доступ до ваших неприватних репозиторіїв. Дізнатися більше"
+ "settings.visibility.description": "Видимість профілю впливає на можливість інших користувачів отримати доступ до ваших неприватних репозиторіїв. Дізнатися більше",
+ "avatar.constraints_hint": "Розмір користувацького аватара не може перевищувати %[1]s або бути більшим за %[2]d×%[3]d пікселів",
+ "repo.diff.commit.next-short": "Наступний",
+ "repo.diff.commit.previous-short": "Попередній",
+ "keys.ssh.link": "Ключі SSH",
+ "keys.gpg.link": "Ключі GPG",
+ "profile.edit.link": "Редагувати профіль",
+ "feed.atom.link": "Стрічка Atom",
+ "profile.actions.tooltip": "Більше дій"
}
diff --git a/options/locale_next/locale_zh-CN.json b/options/locale_next/locale_zh-CN.json
index 721e2ad839..0f408997bf 100644
--- a/options/locale_next/locale_zh-CN.json
+++ b/options/locale_next/locale_zh-CN.json
@@ -69,5 +69,14 @@
"followers.incoming.list.self.none": "没有人关注你的个人资料。",
"editor.textarea.tab_hint": "此行已缩进。再次按 Tab 或按 Escape 退出编辑器。",
"editor.textarea.shift_tab_hint": "此行无缩进。再次按 Shift + Tab 或按 Escape 退出编辑器。",
- "admin.dashboard.cleanup_offline_runners": "清理离线运行器"
+ "admin.dashboard.cleanup_offline_runners": "清理离线运行器",
+ "settings.visibility.description": "个人资料可见性设置会影响他人对您的非私有仓库的访问。了解更多",
+ "avatar.constraints_hint": "自定义头像大小不得超过 %[1]s,或大于 %[2]d×%[3]d 像素",
+ "keys.ssh.link": "SSH 密钥",
+ "keys.gpg.link": "GPG 密钥",
+ "profile.actions.tooltip": "更多操作",
+ "repo.diff.commit.next-short": "下个",
+ "repo.diff.commit.previous-short": "上个",
+ "feed.atom.link": "Atom 订阅源",
+ "profile.edit.link": "编辑个人资料"
}
diff --git a/options/locale_next/locale_zh-TW.json b/options/locale_next/locale_zh-TW.json
index 5e3e43f66e..3ae0b00d2b 100644
--- a/options/locale_next/locale_zh-TW.json
+++ b/options/locale_next/locale_zh-TW.json
@@ -68,5 +68,10 @@
"moderation.report_abuse_form.details": "這個表單是用來檢舉用戶建立垃圾帳號、儲存庫、問題、留言,或其他不當行為。",
"moderation.report_abuse_form.invalid": "無效參數",
"moderation.report_abuse_form.already_reported": "您已檢舉此內容",
- "meta.last_line": "Rubi-chan? Hai! Nani ga suki? Choko minto yori mo a・na・ta♡ Ayumu-chan? Hai! Nani ga suki? Sutoroberii fureibaa yori mo a・na・ta♡ Shiki-chan! Hai! Nani ga suki? Kukkii and kuriimu yori mo a・na・ta♡ Minna? Hai! Nani ga suki? Mochiron daisuki AiScReam."
+ "meta.last_line": "Rubi-chan? Hai! Nani ga suki? Choko minto yori mo a・na・ta♡ Ayumu-chan? Hai! Nani ga suki? Sutoroberii fureibaa yori mo a・na・ta♡ Shiki-chan! Hai! Nani ga suki? Kukkii and kuriimu yori mo a・na・ta♡ Minna? Hai! Nani ga suki? Mochiron daisuki AiScReam.",
+ "admin.dashboard.cleanup_offline_runners": "清理離線 runners",
+ "settings.visibility.description": "個人資料的可見度會影響他人存取您非私人儲存庫的能力。了解更多",
+ "avatar.constraints_hint": "自定義大頭貼的大小不得超過 %[1]s,且解析度不得大於 %[2]d×%[3]d 像素",
+ "repo.diff.commit.next-short": "下一個",
+ "repo.diff.commit.previous-short": "上一個"
}
diff --git a/package-lock.json b/package-lock.json
index b73bc9099b..604ff38c18 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,11 +12,12 @@
"@github/markdown-toolbar-element": "2.2.3",
"@github/quote-selection": "2.1.0",
"@github/text-expander-element": "2.8.0",
+ "@google/model-viewer": "4.1.0",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.14.0",
"ansi_up": "6.0.5",
"asciinema-player": "3.8.2",
- "chart.js": "4.4.9",
+ "chart.js": "4.5.0",
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.7",
@@ -31,13 +32,13 @@
"idiomorph": "0.3.0",
"jquery": "3.7.1",
"katex": "0.16.22",
- "mermaid": "11.6.0",
+ "mermaid": "11.7.0",
"mini-css-extract-plugin": "2.9.2",
- "minimatch": "10.0.2",
+ "minimatch": "10.0.3",
"monaco-editor": "0.52.2",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.3.0",
- "postcss": "8.5.4",
+ "postcss": "8.5.5",
"postcss-loader": "8.1.1",
"postcss-nesting": "13.0.2",
"pretty-ms": "9.0.0",
@@ -62,9 +63,9 @@
"devDependencies": {
"@axe-core/playwright": "4.10.2",
"@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
- "@playwright/test": "1.53.0",
+ "@playwright/test": "1.52.0",
"@stoplight/spectral-cli": "6.15.0",
- "@stylistic/eslint-plugin-js": "4.4.1",
+ "@stylistic/eslint-plugin": "4.4.1",
"@stylistic/stylelint-plugin": "3.1.2",
"@vitejs/plugin-vue": "5.2.4",
"@vitest/coverage-v8": "3.2.3",
@@ -84,7 +85,7 @@
"eslint-plugin-vitest-globals": "1.5.0",
"eslint-plugin-vue": "10.2.0",
"eslint-plugin-vue-scoped-css": "2.10.0",
- "eslint-plugin-wc": "2.2.1",
+ "eslint-plugin-wc": "3.0.1",
"globals": "16.1.0",
"happy-dom": "18.0.0",
"license-checker-rseidelsohn": "4.4.2",
@@ -1020,9 +1021,9 @@
}
},
"node_modules/@eslint/config-array": {
- "version": "0.20.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz",
- "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==",
+ "version": "0.20.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
+ "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -1034,17 +1035,6 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
- "node_modules/@eslint/config-array/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
"node_modules/@eslint/config-array/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -1059,9 +1049,9 @@
}
},
"node_modules/@eslint/config-helpers": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz",
- "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==",
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz",
+ "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -1122,17 +1112,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
@@ -1190,19 +1169,32 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
- "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz",
+ "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.14.0",
+ "@eslint/core": "^0.15.0",
"levn": "^0.4.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
+ "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz",
+ "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/@github/combobox-nav": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.3.1.tgz",
@@ -1231,6 +1223,22 @@
"dom-input-range": "^1.2.0"
}
},
+ "node_modules/@google/model-viewer": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@google/model-viewer/-/model-viewer-4.1.0.tgz",
+ "integrity": "sha512-7WB/jS6wfBfRl/tWhsUUvDMKFE1KlKME97coDLlZQfvJD0nCwjhES1lJ+k7wnmf7T3zMvCfn9mIjM/mgZapuig==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@monogrid/gainmap-js": "^3.1.0",
+ "lit": "^3.2.1"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "peerDependencies": {
+ "three": "^0.172.0"
+ }
+ },
"node_modules/@humanfs/core": {
"version": "0.19.1",
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
@@ -1748,6 +1756,27 @@
"url": "https://opencollective.com/libvips"
}
},
+ "node_modules/@isaacs/balanced-match": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
+ "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/@isaacs/brace-expansion": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
+ "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
+ "license": "MIT",
+ "dependencies": {
+ "@isaacs/balanced-match": "^4.0.1"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
@@ -1992,6 +2021,21 @@
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
"license": "MIT"
},
+ "node_modules/@lit-labs/ssr-dom-shim": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.3.0.tgz",
+ "integrity": "sha512-nQIWonJ6eFAvUUrSlwyHDm/aE8PBDu5kRpL0vHMg6K8fK3Diq1xdPjTnsJSwxABhaZ+5eBi1btQB5ShUTKo4nQ==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@lit/reactive-element": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.0.tgz",
+ "integrity": "sha512-L2qyoZSQClcBmq0qajBVbhYEcG6iK0XfLn66ifLe/RfC0/ihpc+pl0Wdn8bJ8o+hj38cG0fGXRgSS20MuXn7qA==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@lit-labs/ssr-dom-shim": "^1.2.0"
+ }
+ },
"node_modules/@mcaptcha/core-glue": {
"version": "0.1.0-alpha-5",
"resolved": "https://registry.npmjs.org/@mcaptcha/core-glue/-/core-glue-0.1.0-alpha-5.tgz",
@@ -2044,14 +2088,26 @@
}
},
"node_modules/@mermaid-js/parser": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.4.0.tgz",
- "integrity": "sha512-wla8XOWvQAwuqy+gxiZqY+c7FokraOTHRWMsbB4AgRx9Sy7zKslNyejy7E+a77qHfey5GXw/ik3IXv/NHMJgaA==",
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-0.5.0.tgz",
+ "integrity": "sha512-AiaN7+VjXC+3BYE+GwNezkpjIcCI2qIMB/K4S2/vMWe0q/XJCBbx5+K7iteuz7VyltX9iAK4FmVTvGc9kjOV4w==",
"license": "MIT",
"dependencies": {
"langium": "3.3.1"
}
},
+ "node_modules/@monogrid/gainmap-js": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz",
+ "integrity": "sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==",
+ "license": "MIT",
+ "dependencies": {
+ "promise-worker-transferable": "^1.0.4"
+ },
+ "peerDependencies": {
+ "three": ">= 0.159.0"
+ }
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.11.tgz",
@@ -2131,13 +2187,13 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.53.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0.tgz",
- "integrity": "sha512-15hjKreZDcp7t6TL/7jkAo6Df5STZN09jGiv5dbP9A6vMVncXRqE7/B2SncsyOwrkZRBH2i6/TPOL8BVmm3c7w==",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz",
+ "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.53.0"
+ "playwright": "1.52.0"
},
"bin": {
"playwright": "cli.js"
@@ -2213,9 +2269,9 @@
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.42.0.tgz",
- "integrity": "sha512-gldmAyS9hpj+H6LpRNlcjQWbuKUtb94lodB9uCz71Jm+7BxK1VIOo7y62tZZwxhA7j1ylv/yQz080L5WkS+LoQ==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz",
+ "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==",
"cpu": [
"arm"
],
@@ -2227,9 +2283,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.42.0.tgz",
- "integrity": "sha512-bpRipfTgmGFdCZDFLRvIkSNO1/3RGS74aWkJJTFJBH7h3MRV4UijkaEUeOMbi9wxtxYmtAbVcnMtHTPBhLEkaw==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz",
+ "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==",
"cpu": [
"arm64"
],
@@ -2241,9 +2297,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.42.0.tgz",
- "integrity": "sha512-JxHtA081izPBVCHLKnl6GEA0w3920mlJPLh89NojpU2GsBSB6ypu4erFg/Wx1qbpUbepn0jY4dVWMGZM8gplgA==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz",
+ "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==",
"cpu": [
"arm64"
],
@@ -2255,9 +2311,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.42.0.tgz",
- "integrity": "sha512-rv5UZaWVIJTDMyQ3dCEK+m0SAn6G7H3PRc2AZmExvbDvtaDc+qXkei0knQWcI3+c9tEs7iL/4I4pTQoPbNL2SA==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz",
+ "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==",
"cpu": [
"x64"
],
@@ -2269,9 +2325,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.42.0.tgz",
- "integrity": "sha512-fJcN4uSGPWdpVmvLuMtALUFwCHgb2XiQjuECkHT3lWLZhSQ3MBQ9pq+WoWeJq2PrNxr9rPM1Qx+IjyGj8/c6zQ==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz",
+ "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==",
"cpu": [
"arm64"
],
@@ -2283,9 +2339,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.42.0.tgz",
- "integrity": "sha512-CziHfyzpp8hJpCVE/ZdTizw58gr+m7Y2Xq5VOuCSrZR++th2xWAz4Nqk52MoIIrV3JHtVBhbBsJcAxs6NammOQ==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz",
+ "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==",
"cpu": [
"x64"
],
@@ -2297,9 +2353,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.42.0.tgz",
- "integrity": "sha512-UsQD5fyLWm2Fe5CDM7VPYAo+UC7+2Px4Y+N3AcPh/LdZu23YcuGPegQly++XEVaC8XUTFVPscl5y5Cl1twEI4A==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz",
+ "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==",
"cpu": [
"arm"
],
@@ -2311,9 +2367,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.42.0.tgz",
- "integrity": "sha512-/i8NIrlgc/+4n1lnoWl1zgH7Uo0XK5xK3EDqVTf38KvyYgCU/Rm04+o1VvvzJZnVS5/cWSd07owkzcVasgfIkQ==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz",
+ "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==",
"cpu": [
"arm"
],
@@ -2325,9 +2381,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.42.0.tgz",
- "integrity": "sha512-eoujJFOvoIBjZEi9hJnXAbWg+Vo1Ov8n/0IKZZcPZ7JhBzxh2A+2NFyeMZIRkY9iwBvSjloKgcvnjTbGKHE44Q==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz",
+ "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==",
"cpu": [
"arm64"
],
@@ -2339,9 +2395,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.42.0.tgz",
- "integrity": "sha512-/3NrcOWFSR7RQUQIuZQChLND36aTU9IYE4j+TB40VU78S+RA0IiqHR30oSh6P1S9f9/wVOenHQnacs/Byb824g==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz",
+ "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==",
"cpu": [
"arm64"
],
@@ -2353,9 +2409,9 @@
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.42.0.tgz",
- "integrity": "sha512-O8AplvIeavK5ABmZlKBq9/STdZlnQo7Sle0LLhVA7QT+CiGpNVe197/t8Aph9bhJqbDVGCHpY2i7QyfEDDStDg==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz",
+ "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==",
"cpu": [
"loong64"
],
@@ -2367,9 +2423,9 @@
]
},
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.42.0.tgz",
- "integrity": "sha512-6Qb66tbKVN7VyQrekhEzbHRxXXFFD8QKiFAwX5v9Xt6FiJ3BnCVBuyBxa2fkFGqxOCSGGYNejxd8ht+q5SnmtA==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz",
+ "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==",
"cpu": [
"ppc64"
],
@@ -2381,9 +2437,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.42.0.tgz",
- "integrity": "sha512-KQETDSEBamQFvg/d8jajtRwLNBlGc3aKpaGiP/LvEbnmVUKlFta1vqJqTrvPtsYsfbE/DLg5CC9zyXRX3fnBiA==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz",
+ "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==",
"cpu": [
"riscv64"
],
@@ -2395,9 +2451,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.42.0.tgz",
- "integrity": "sha512-qMvnyjcU37sCo/tuC+JqeDKSuukGAd+pVlRl/oyDbkvPJ3awk6G6ua7tyum02O3lI+fio+eM5wsVd66X0jQtxw==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz",
+ "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==",
"cpu": [
"riscv64"
],
@@ -2409,9 +2465,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.42.0.tgz",
- "integrity": "sha512-I2Y1ZUgTgU2RLddUHXTIgyrdOwljjkmcZ/VilvaEumtS3Fkuhbw4p4hgHc39Ypwvo2o7sBFNl2MquNvGCa55Iw==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz",
+ "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==",
"cpu": [
"s390x"
],
@@ -2423,9 +2479,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.42.0.tgz",
- "integrity": "sha512-Gfm6cV6mj3hCUY8TqWa63DB8Mx3NADoFwiJrMpoZ1uESbK8FQV3LXkhfry+8bOniq9pqY1OdsjFWNsSbfjPugw==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz",
+ "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==",
"cpu": [
"x64"
],
@@ -2437,9 +2493,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.42.0.tgz",
- "integrity": "sha512-g86PF8YZ9GRqkdi0VoGlcDUb4rYtQKyTD1IVtxxN4Hpe7YqLBShA7oHMKU6oKTCi3uxwW4VkIGnOaH/El8de3w==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz",
+ "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==",
"cpu": [
"x64"
],
@@ -2451,9 +2507,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.42.0.tgz",
- "integrity": "sha512-+axkdyDGSp6hjyzQ5m1pgcvQScfHnMCcsXkx8pTgy/6qBmWVhtRVlgxjWwDp67wEXXUr0x+vD6tp5W4x6V7u1A==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz",
+ "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==",
"cpu": [
"arm64"
],
@@ -2465,9 +2521,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.42.0.tgz",
- "integrity": "sha512-F+5J9pelstXKwRSDq92J0TEBXn2nfUrQGg+HK1+Tk7VOL09e0gBqUHugZv7SW4MGrYj41oNCUe3IKCDGVlis2g==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz",
+ "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==",
"cpu": [
"ia32"
],
@@ -2479,9 +2535,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.42.0.tgz",
- "integrity": "sha512-LpHiJRwkaVz/LqjHjK8LCi8osq7elmpwujwbXKNW88bM8eeGxavJIKKjkjpMHAh/2xfnrt1ZSnhTv41WYUHYmA==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz",
+ "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==",
"cpu": [
"x64"
],
@@ -2701,17 +2757,6 @@
"node": "^12.20 || >=14.13"
}
},
- "node_modules/@stoplight/spectral-core/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
"node_modules/@stoplight/spectral-core/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -3010,15 +3055,18 @@
"node": "^12.20 || >=14.13"
}
},
- "node_modules/@stylistic/eslint-plugin-js": {
+ "node_modules/@stylistic/eslint-plugin": {
"version": "4.4.1",
- "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-4.4.1.tgz",
- "integrity": "sha512-eLisyHvx7Sel8vcFZOEwDEBGmYsYM1SqDn81BWgmbqEXfXRf8oe6Rwp+ryM/8odNjlxtaaxp0Ihmt86CnLAxKg==",
+ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-4.4.1.tgz",
+ "integrity": "sha512-CEigAk7eOLyHvdgmpZsKFwtiqS2wFwI1fn4j09IU9GmD4euFM4jEBAViWeCqaNLlbX2k2+A/Fq9cje4HQBXuJQ==",
"dev": true,
"license": "MIT",
"dependencies": {
+ "@typescript-eslint/utils": "^8.32.1",
"eslint-visitor-keys": "^4.2.0",
- "espree": "^10.3.0"
+ "espree": "^10.3.0",
+ "estraverse": "^5.3.0",
+ "picomatch": "^4.0.2"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3027,6 +3075,19 @@
"eslint": ">=9.0.0"
}
},
+ "node_modules/@stylistic/eslint-plugin/node_modules/picomatch": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/@stylistic/stylelint-plugin": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.2.tgz",
@@ -3448,9 +3509,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "20.19.0",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.0.tgz",
- "integrity": "sha512-hfrc+1tud1xcdVTABC2JiomZJEklMcXYNTVtZLAeqTVWD+qL5jkHKT+1lOtqDdGxt+mB53DTtiz673vfjU8D1Q==",
+ "version": "20.19.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.1.tgz",
+ "integrity": "sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
@@ -3476,8 +3537,7 @@
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
"integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
- "license": "MIT",
- "optional": true
+ "license": "MIT"
},
"node_modules/@types/unist": {
"version": "2.0.11",
@@ -3689,6 +3749,23 @@
"typescript": ">=4.8.4 <5.9.0"
}
},
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@@ -3747,10 +3824,38 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@unrs/resolver-binding-android-arm-eabi": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.9.1.tgz",
+ "integrity": "sha512-dd7yIp1hfJFX9ZlVLQRrh/Re9WMUHHmF9hrKD1yIvxcyNr2BhQ3xc1upAVhy8NijadnCswAxWQu8MkkSMC1qXQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-android-arm64": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.9.1.tgz",
+ "integrity": "sha512-EzUPcMFtDVlo5yrbzMqUsGq3HnLXw+3ZOhSd7CUaDmbTtnrzM+RO2ntw2dm2wjbbc5djWj3yX0wzbbg8pLhx8g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
"node_modules/@unrs/resolver-binding-darwin-arm64": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.11.tgz",
- "integrity": "sha512-i3/wlWjQJXMh1uiGtiv7k1EYvrrS3L1hdwmWJJiz1D8jWy726YFYPIxQWbEIVPVAgrfRR0XNlLrTQwq17cuCGw==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.9.1.tgz",
+ "integrity": "sha512-nB+dna3q4kOleKFcSZJ/wDXIsAd1kpMO9XrVAt8tG3RDWJ6vi+Ic6bpz4cmg5tWNeCfHEY4KuqJCB+pKejPEmQ==",
"cpu": [
"arm64"
],
@@ -3762,9 +3867,9 @@
]
},
"node_modules/@unrs/resolver-binding-darwin-x64": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.11.tgz",
- "integrity": "sha512-8XXyFvc6w6kmMmi6VYchZhjd5CDcp+Lv6Cn1YmUme0ypsZ/0Kzd+9ESrWtDrWibKPTgSteDTxp75cvBOY64FQQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.9.1.tgz",
+ "integrity": "sha512-aKWHCrOGaCGwZcekf3TnczQoBxk5w//W3RZ4EQyhux6rKDwBPgDU9Y2yGigCV1Z+8DWqZgVGQi+hdpnlSy3a1w==",
"cpu": [
"x64"
],
@@ -3776,9 +3881,9 @@
]
},
"node_modules/@unrs/resolver-binding-freebsd-x64": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.11.tgz",
- "integrity": "sha512-0qJBYzP8Qk24CZ05RSWDQUjdiQUeIJGfqMMzbtXgCKl/a5xa6thfC0MQkGIr55LCLd6YmMyO640ifYUa53lybQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.9.1.tgz",
+ "integrity": "sha512-4dIEMXrXt0UqDVgrsUd1I+NoIzVQWXy/CNhgpfS75rOOMK/4Abn0Mx2M2gWH4Mk9+ds/ASAiCmqoUFynmMY5hA==",
"cpu": [
"x64"
],
@@ -3790,9 +3895,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.11.tgz",
- "integrity": "sha512-1sGwpgvx+WZf0GFT6vkkOm6UJ+mlsVnjw+Yv9esK71idWeRAG3bbpkf3AoY8KIqKqmnzJExi0uKxXpakQ5Pcbg==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.9.1.tgz",
+ "integrity": "sha512-vtvS13IXPs1eE8DuS/soiosqMBeyh50YLRZ+p7EaIKAPPeevRnA9G/wu/KbVt01ZD5qiGjxS+CGIdVC7I6gTOw==",
"cpu": [
"arm"
],
@@ -3804,9 +3909,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.11.tgz",
- "integrity": "sha512-D/1F/2lTe+XAl3ohkYj51NjniVly8sIqkA/n1aOND3ZMO418nl2JNU95iVa1/RtpzaKcWEsNTtHRogykrUflJg==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.9.1.tgz",
+ "integrity": "sha512-BfdnN6aZ7NcX8djW8SR6GOJc+K+sFhWRF4vJueVE0vbUu5N1bLnBpxJg1TGlhSyo+ImC4SR0jcNiKN0jdoxt+A==",
"cpu": [
"arm"
],
@@ -3818,9 +3923,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.11.tgz",
- "integrity": "sha512-7vFWHLCCNFLEQlmwKQfVy066ohLLArZl+AV/AdmrD1/pD1FlmqM+FKbtnONnIwbHtgetFUCV/SRi1q4D49aTlw==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.9.1.tgz",
+ "integrity": "sha512-Jhge7lFtH0QqfRz2PyJjJXWENqywPteITd+nOS0L6AhbZli+UmEyGBd2Sstt1c+l9C+j/YvKTl9wJo9PPmsFNg==",
"cpu": [
"arm64"
],
@@ -3832,9 +3937,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-arm64-musl": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.11.tgz",
- "integrity": "sha512-tYkGIx8hjWPh4zcn17jLEHU8YMmdP2obRTGkdaB3BguGHh31VCS3ywqC4QjTODjmhhNyZYkj/1Dz/+0kKvg9YA==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.9.1.tgz",
+ "integrity": "sha512-ofdK/ow+ZSbSU0pRoB7uBaiRHeaAOYQFU5Spp87LdcPL/P1RhbCTMSIYVb61XWzsVEmYKjHFtoIE0wxP6AFvrA==",
"cpu": [
"arm64"
],
@@ -3846,9 +3951,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.11.tgz",
- "integrity": "sha512-6F328QIUev29vcZeRX6v6oqKxfUoGwIIAhWGD8wSysnBYFY0nivp25jdWmAb1GildbCCaQvOKEhCok7YfWkj4Q==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.9.1.tgz",
+ "integrity": "sha512-eC8SXVn8de67HacqU7PoGdHA+9tGbqfEdD05AEFRAB81ejeQtNi5Fx7lPcxpLH79DW0BnMAHau3hi4RVkHfSCw==",
"cpu": [
"ppc64"
],
@@ -3860,9 +3965,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.11.tgz",
- "integrity": "sha512-NqhWmiGJGdzbZbeucPZIG9Iav4lyYLCarEnxAceguMx9qlpeEF7ENqYKOwB8Zqk7/CeuYMEcLYMaW2li6HyDzQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.9.1.tgz",
+ "integrity": "sha512-fIkwvAAQ41kfoGWfzeJ33iLGShl0JEDZHrMnwTHMErUcPkaaZRJYjQjsFhMl315NEQ4mmTlC+2nfK/J2IszDOw==",
"cpu": [
"riscv64"
],
@@ -3874,9 +3979,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.11.tgz",
- "integrity": "sha512-J2RPIFKMdTrLtBdfR1cUMKl8Gcy05nlQ+bEs/6al7EdWLk9cs3tnDREHZ7mV9uGbeghpjo4i8neNZNx3PYUY9w==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.9.1.tgz",
+ "integrity": "sha512-RAAszxImSOFLk44aLwnSqpcOdce8sBcxASledSzuFAd8Q5ZhhVck472SisspnzHdc7THCvGXiUeZ2hOC7NUoBQ==",
"cpu": [
"riscv64"
],
@@ -3888,9 +3993,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.11.tgz",
- "integrity": "sha512-bDpGRerHvvHdhun7MmFUNDpMiYcJSqWckwAVVRTJf8F+RyqYJOp/mx04PDc7DhpNPeWdnTMu91oZRMV+gGaVcQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.9.1.tgz",
+ "integrity": "sha512-QoP9vkY+THuQdZi05bA6s6XwFd6HIz3qlx82v9bTOgxeqin/3C12Ye7f7EOD00RQ36OtOPWnhEMMm84sv7d1XQ==",
"cpu": [
"s390x"
],
@@ -3902,9 +4007,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-x64-gnu": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.11.tgz",
- "integrity": "sha512-G9U7bVmylzRLma3cK39RBm3guoD1HOvY4o0NS4JNm37AD0lS7/xyMt7kn0JejYyc0Im8J+rH69/dXGM9DAJcSQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.9.1.tgz",
+ "integrity": "sha512-/p77cGN/h9zbsfCseAP5gY7tK+7+DdM8fkPfr9d1ye1fsF6bmtGbtZN6e/8j4jCZ9NEIBBkT0GhdgixSelTK9g==",
"cpu": [
"x64"
],
@@ -3916,9 +4021,9 @@
]
},
"node_modules/@unrs/resolver-binding-linux-x64-musl": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.11.tgz",
- "integrity": "sha512-7qL20SBKomekSunm7M9Fe5L93bFbn+FbHiGJbfTlp0RKhPVoJDP73vOxf1QrmJHyDPECsGWPFnKa/f8fO2FsHw==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.9.1.tgz",
+ "integrity": "sha512-wInTqT3Bu9u50mDStEig1v8uxEL2Ht+K8pir/YhyyrM5ordJtxoqzsL1vR/CQzOJuDunUTrDkMM0apjW/d7/PA==",
"cpu": [
"x64"
],
@@ -3930,9 +4035,9 @@
]
},
"node_modules/@unrs/resolver-binding-wasm32-wasi": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.11.tgz",
- "integrity": "sha512-jisvIva8MidjI+B1lFRZZMfCPaCISePgTyR60wNT1MeQvIh5Ksa0G3gvI+Iqyj3jqYbvOHByenpa5eDGcSdoSg==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.9.1.tgz",
+ "integrity": "sha512-eNwqO5kUa+1k7yFIircwwiniKWA0UFHo2Cfm8LYgkh9km7uMad+0x7X7oXbQonJXlqfitBTSjhA0un+DsHIrhw==",
"cpu": [
"wasm32"
],
@@ -3940,16 +4045,16 @@
"license": "MIT",
"optional": true,
"dependencies": {
- "@napi-rs/wasm-runtime": "^0.2.10"
+ "@napi-rs/wasm-runtime": "^0.2.11"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.11.tgz",
- "integrity": "sha512-G+H5nQZ8sRZ8ebMY6mRGBBvTEzMYEcgVauLsNHpvTUavZoCCRVP1zWkCZgOju2dW3O22+8seTHniTdl1/uLz3g==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.9.1.tgz",
+ "integrity": "sha512-Eaz1xMUnoa2mFqh20mPqSdbYl6crnk8HnIXDu6nsla9zpgZJZO8w3c1gvNN/4Eb0RXRq3K9OG6mu8vw14gIqiA==",
"cpu": [
"arm64"
],
@@ -3961,9 +4066,9 @@
]
},
"node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.11.tgz",
- "integrity": "sha512-Hfy46DBfFzyv0wgR0MMOwFFib2W2+Btc8oE5h4XlPhpelnSyA6nFxkVIyTgIXYGTdFaLoZFNn62fmqx3rjEg3A==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.9.1.tgz",
+ "integrity": "sha512-H/+d+5BGlnEQif0gnwWmYbYv7HJj563PUKJfn8PlmzF8UmF+8KxdvXdwCsoOqh4HHnENnoLrav9NYBrv76x1wQ==",
"cpu": [
"ia32"
],
@@ -3975,9 +4080,9 @@
]
},
"node_modules/@unrs/resolver-binding-win32-x64-msvc": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.11.tgz",
- "integrity": "sha512-7L8NdsQlCJ8T106Gbz/AjzM4QKWVsoQbKpB9bMBGcIZswUuAnJMHpvbqGW3RBqLHCIwX4XZ5fxSBHEFcK2h9wA==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.9.1.tgz",
+ "integrity": "sha512-rS86wI4R6cknYM3is3grCb/laE8XBEbpWAMSIPjYfmYp75KL5dT87jXF2orDa4tQYg5aajP5G8Fgh34dRyR+Rw==",
"cpu": [
"x64"
],
@@ -4965,9 +5070,10 @@
}
},
"node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
+ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/base64-js": {
@@ -5019,14 +5125,23 @@
"license": "ISC"
},
"node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "balanced-match": "^1.0.0"
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
}
},
+ "node_modules/brace-expansion/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
@@ -5153,9 +5268,9 @@
}
},
"node_modules/cacheable/node_modules/keyv": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.3.3.tgz",
- "integrity": "sha512-Rwu4+nXI9fqcxiEHtbkvoes2X+QfkTRo1TMkPfwzipGsJlJO/z69vqB4FNl9xJ3xCpAcbkvmEabZfPzrwN3+gQ==",
+ "version": "5.3.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.3.4.tgz",
+ "integrity": "sha512-ypEvQvInNpUe+u+w8BIcPkQvEqXquyyibWE/1NB5T2BTzIpS5cGEV1LZskDzPSTvNAaT4+5FutvzlvnkxOSKlw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5231,9 +5346,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001721",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
- "integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
+ "version": "1.0.30001724",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz",
+ "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==",
"funding": [
{
"type": "opencollective",
@@ -5317,9 +5432,9 @@
}
},
"node_modules/chart.js": {
- "version": "4.4.9",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.9.tgz",
- "integrity": "sha512-EyZ9wWKgpAU0fLJ43YAEIF8sr5F2W3LqbS40ZJyHIner2lY14ufqv2VMp69MAiZ2rpwxEUxEhIH/0U3xyRynxg==",
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz",
+ "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==",
"license": "MIT",
"dependencies": {
"@kurkle/color": "^0.3.0"
@@ -5659,13 +5774,13 @@
}
},
"node_modules/core-js-compat": {
- "version": "3.42.0",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz",
- "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==",
+ "version": "3.43.0",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz",
+ "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "browserslist": "^4.24.4"
+ "browserslist": "^4.25.0"
},
"funding": {
"type": "opencollective",
@@ -6463,9 +6578,9 @@
}
},
"node_modules/decode-named-character-reference": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz",
- "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz",
+ "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6767,6 +6882,23 @@
"node": ">=14"
}
},
+ "node_modules/editorconfig/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/editorconfig/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/editorconfig/node_modules/minimatch": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz",
@@ -6784,9 +6916,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.5.165",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz",
- "integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==",
+ "version": "1.5.171",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz",
+ "integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==",
"license": "ISC"
},
"node_modules/emoji-regex": {
@@ -7423,6 +7555,23 @@
"eslint": "^8.0.0 || ^9.0.0"
}
},
+ "node_modules/eslint-plugin-sonarjs/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/eslint-plugin-sonarjs/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/eslint-plugin-sonarjs/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
@@ -7593,23 +7742,23 @@
}
},
"node_modules/eslint-plugin-wc": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.2.1.tgz",
- "integrity": "sha512-KstLqGmyQz088DvFlDYHg0sHih+w2QeulreCi1D1ftr357klO2zqHdG/bbnNMmuQdVFDuNkopNIyNhmG0XCT/g==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-3.0.1.tgz",
+ "integrity": "sha512-0p1wkSlA2Ue3FA4qW+5LZ+15sy0p1nUyVl1eyBMLq4rtN1LtE9IdI49BXNWMz8N8bM/y7Ulx8SWGAni5f8XO5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-valid-element-name": "^1.0.0",
- "js-levenshtein-esm": "^1.2.0"
+ "js-levenshtein-esm": "^2.0.0"
},
"peerDependencies": {
"eslint": ">=8.40.0"
}
},
"node_modules/eslint-scope": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz",
- "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==",
+ "version": "8.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+ "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
@@ -7624,9 +7773,9 @@
}
},
"node_modules/eslint-visitor-keys": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
- "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+ "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -7660,17 +7809,6 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
- "node_modules/eslint/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
"node_modules/eslint/node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -7692,15 +7830,15 @@
}
},
"node_modules/espree": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
- "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==",
+ "version": "10.4.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+ "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
"dev": true,
"license": "BSD-2-Clause",
"dependencies": {
- "acorn": "^8.14.0",
+ "acorn": "^8.15.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^4.2.0"
+ "eslint-visitor-keys": "^4.2.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -7789,9 +7927,9 @@
}
},
"node_modules/exsolve": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.5.tgz",
- "integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==",
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
+ "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==",
"license": "MIT"
},
"node_modules/fast-deep-equal": {
@@ -8271,17 +8409,6 @@
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"license": "BSD-2-Clause"
},
- "node_modules/glob/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
"node_modules/glob/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -8684,6 +8811,12 @@
"node": ">= 4"
}
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
+ },
"node_modules/immer": {
"version": "9.0.21",
"resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
@@ -9223,6 +9356,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/is-promise": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz",
+ "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==",
+ "license": "MIT"
+ },
"node_modules/is-proto-prop": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/is-proto-prop/-/is-proto-prop-3.0.1.tgz",
@@ -9559,6 +9698,23 @@
"node": ">=14"
}
},
+ "node_modules/js-beautify/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-beautify/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/js-beautify/node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -9607,9 +9763,9 @@
}
},
"node_modules/js-levenshtein-esm": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-1.2.0.tgz",
- "integrity": "sha512-fzreKVq1eD7eGcQr7MtRpQH94f8gIfhdrc7yeih38xh684TNMK9v5aAu2wxfIRMk/GpAJRrzcirMAPIaSDaByQ==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/js-levenshtein-esm/-/js-levenshtein-esm-2.0.0.tgz",
+ "integrity": "sha512-1n4LEPOL4wRXY8rOQcuA7Iuaphe5xCMayvufCzlLAi+hRsnBRDbSS6XPuV58CBVJxj5D9ApFLyjQ7KzFToyHBw==",
"dev": true,
"license": "MIT"
},
@@ -9922,6 +10078,15 @@
"npm": ">=8"
}
},
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
"node_modules/lilconfig": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
@@ -9950,6 +10115,37 @@
"uc.micro": "^2.0.0"
}
},
+ "node_modules/lit": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.0.tgz",
+ "integrity": "sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@lit/reactive-element": "^2.1.0",
+ "lit-element": "^4.2.0",
+ "lit-html": "^3.3.0"
+ }
+ },
+ "node_modules/lit-element": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.0.tgz",
+ "integrity": "sha512-MGrXJVAI5x+Bfth/pU9Kst1iWID6GHDLEzFEnyULB/sFiRLgkd8NPK/PeeXxktA3T6EIIaq8U3KcbTU5XFcP2Q==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@lit-labs/ssr-dom-shim": "^1.2.0",
+ "@lit/reactive-element": "^2.1.0",
+ "lit-html": "^3.3.0"
+ }
+ },
+ "node_modules/lit-html": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.0.tgz",
+ "integrity": "sha512-RHoswrFAxY2d8Cf2mm4OZ1DgzCoBKUKSPvA1fhtSELxUERq2aQQ2h05pO9j81gS1o7RIRJ+CePLogfyahwmynw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@types/trusted-types": "^2.0.2"
+ }
+ },
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
@@ -10055,9 +10251,9 @@
"license": "MIT"
},
"node_modules/loupe": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz",
- "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==",
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz",
+ "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==",
"dev": true,
"license": "MIT"
},
@@ -10207,15 +10403,15 @@
}
},
"node_modules/markdownlint-cli/node_modules/glob": {
- "version": "11.0.2",
- "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz",
- "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==",
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
+ "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==",
"dev": true,
"license": "ISC",
"dependencies": {
- "foreground-child": "^3.1.0",
- "jackspeak": "^4.0.1",
- "minimatch": "^10.0.0",
+ "foreground-child": "^3.3.1",
+ "jackspeak": "^4.1.1",
+ "minimatch": "^10.0.3",
"minipass": "^7.1.2",
"package-json-from-dist": "^1.0.0",
"path-scurry": "^2.0.0"
@@ -10366,14 +10562,14 @@
}
},
"node_modules/mermaid": {
- "version": "11.6.0",
- "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.6.0.tgz",
- "integrity": "sha512-PE8hGUy1LDlWIHWBP05SFdqUHGmRcCcK4IzpOKPE35eOw+G9zZgcnMpyunJVUEOgb//KBORPjysKndw8bFLuRg==",
+ "version": "11.7.0",
+ "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.7.0.tgz",
+ "integrity": "sha512-/1/5R0rt0Z1Ak0CuznAnCF3HtQgayRXUz6SguzOwN4L+DuCobz0UxnQ+ZdTSZ3AugKVVh78tiVmsHpHWV25TCw==",
"license": "MIT",
"dependencies": {
"@braintree/sanitize-url": "^7.0.4",
"@iconify/utils": "^2.1.33",
- "@mermaid-js/parser": "^0.4.0",
+ "@mermaid-js/parser": "^0.5.0",
"@types/d3": "^7.4.3",
"cytoscape": "^3.29.3",
"cytoscape-cose-bilkent": "^4.1.0",
@@ -10382,7 +10578,7 @@
"d3-sankey": "^0.12.3",
"dagre-d3-es": "7.0.11",
"dayjs": "^1.11.13",
- "dompurify": "^3.2.4",
+ "dompurify": "^3.2.5",
"katex": "^0.16.9",
"khroma": "^2.1.0",
"lodash-es": "^4.17.21",
@@ -11012,12 +11208,12 @@
}
},
"node_modules/minimatch": {
- "version": "10.0.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.2.tgz",
- "integrity": "sha512-+9TJCIYXgZ2Dm5LxVCFsa8jOm+evMwXHFI0JM1XROmkfkpz8/iLLDh+TwSmyIBrs6C6Xu9294/fq8cBA+P6AqA==",
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
+ "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
"license": "ISC",
"dependencies": {
- "brace-expansion": "^4.0.1"
+ "@isaacs/brace-expansion": "^5.0.0"
},
"engines": {
"node": "20 || >=22"
@@ -11026,27 +11222,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/minimatch/node_modules/balanced-match": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-3.0.1.tgz",
- "integrity": "sha512-vjtV3hiLqYDNRoiAv0zC4QaGAMPomEoq83PRmYIofPswwZurCeWR5LByXm7SyoL0Zh5+2z0+HC7jG8gSZJUh0w==",
- "license": "MIT",
- "engines": {
- "node": ">= 16"
- }
- },
- "node_modules/minimatch/node_modules/brace-expansion": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-4.0.1.tgz",
- "integrity": "sha512-YClrbvTCXGe70pU2JiEiPLYXO9gQkyxYeKpJIQHVS/gOs6EWMQP2RYBwjFLNT322Ji8TOC3IMPfsYCedNpzKfA==",
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^3.0.0"
- },
- "engines": {
- "node": ">= 18"
- }
- },
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
@@ -11779,13 +11954,13 @@
}
},
"node_modules/playwright": {
- "version": "1.53.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0.tgz",
- "integrity": "sha512-ghGNnIEYZC4E+YtclRn4/p6oYbdPiASELBIYkBXfaTVKreQUYbMUYQDwS12a8F0/HtIjr/CkGjtwABeFPGcS4Q==",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
+ "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.53.0"
+ "playwright-core": "1.52.0"
},
"bin": {
"playwright": "cli.js"
@@ -11798,9 +11973,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.53.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0.tgz",
- "integrity": "sha512-mGLg8m0pm4+mmtB7M89Xw/GSqoNC+twivl8ITteqvAndachozYe2ZA7srU6uleV1vEdAHYqjq+SV8SNxRRFYBw==",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
+ "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -11857,9 +12032,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
- "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
+ "version": "8.5.5",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.5.tgz",
+ "integrity": "sha512-d/jtm+rdNT8tpXuHY5MMtcbJFBkhXE6593XVR9UoGCH8jSFGci7jGvMGH5RYd5PBJW+00NZQt6gf7CbagJCrhg==",
"funding": [
{
"type": "opencollective",
@@ -12283,6 +12458,16 @@
"dev": true,
"license": "Unlicense"
},
+ "node_modules/promise-worker-transferable": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz",
+ "integrity": "sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "is-promise": "^2.1.0",
+ "lie": "^3.0.2"
+ }
+ },
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -12414,6 +12599,23 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
+ "node_modules/read-package-json/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/read-package-json/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/read-package-json/node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -13751,13 +13953,6 @@
"postcss-selector-parser": "^7.0.0"
}
},
- "node_modules/stylelint/node_modules/balanced-match": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
- "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/stylelint/node_modules/file-entry-cache": {
"version": "10.1.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.1.1.tgz",
@@ -13900,6 +14095,21 @@
"node": ">=16 || 14 >=14.17"
}
},
+ "node_modules/sucrase/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/sucrase/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/sucrase/node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -14166,9 +14376,9 @@
}
},
"node_modules/terser": {
- "version": "5.41.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.41.0.tgz",
- "integrity": "sha512-H406eLPXpZbAX14+B8psIuvIr8+3c+2hkuYzpMkoE0ij+NdsVATbA78vb8neA/eqrj7rywa2pIkdmWRsXW6wmw==",
+ "version": "5.43.1",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
+ "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
"license": "BSD-2-Clause",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
@@ -14238,6 +14448,23 @@
"node": ">=18"
}
},
+ "node_modules/test-exclude/node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/test-exclude/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
"node_modules/test-exclude/node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -14303,6 +14530,13 @@
"node": ">=0.8"
}
},
+ "node_modules/three": {
+ "version": "0.172.0",
+ "resolved": "https://registry.npmjs.org/three/-/three-0.172.0.tgz",
+ "integrity": "sha512-6HMgMlzU97MsV7D/tY8Va38b83kz8YJX+BefKjspMNAv0Vx6dxMogHOrnRl/sbMIs3BPUKijPqDqJ/+UwJbIow==",
+ "license": "MIT",
+ "peer": true
+ },
"node_modules/throttle-debounce": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.0.tgz",
@@ -14349,9 +14583,9 @@
}
},
"node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.4.5",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz",
- "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==",
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+ "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@@ -14377,9 +14611,9 @@
}
},
"node_modules/tinypool": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz",
- "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
+ "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -14721,9 +14955,9 @@
}
},
"node_modules/unrs-resolver": {
- "version": "1.7.11",
- "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.11.tgz",
- "integrity": "sha512-OhuAzBImFPjKNgZ2JwHMfGFUA6NSbRegd1+BPjC1Y0E6X9Y/vJ4zKeGmIMqmlYboj6cMNEwKI+xQisrg4J0HaQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.9.1.tgz",
+ "integrity": "sha512-4AZVxP05JGN6DwqIkSP4VKLOcwQa5l37SWHF/ahcuqBMbfxbpN1L1QKafEhWCziHhzKex9H/AR09H0OuVyU+9g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -14734,23 +14968,25 @@
"url": "https://opencollective.com/unrs-resolver"
},
"optionalDependencies": {
- "@unrs/resolver-binding-darwin-arm64": "1.7.11",
- "@unrs/resolver-binding-darwin-x64": "1.7.11",
- "@unrs/resolver-binding-freebsd-x64": "1.7.11",
- "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.11",
- "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.11",
- "@unrs/resolver-binding-linux-arm64-gnu": "1.7.11",
- "@unrs/resolver-binding-linux-arm64-musl": "1.7.11",
- "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.11",
- "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.11",
- "@unrs/resolver-binding-linux-riscv64-musl": "1.7.11",
- "@unrs/resolver-binding-linux-s390x-gnu": "1.7.11",
- "@unrs/resolver-binding-linux-x64-gnu": "1.7.11",
- "@unrs/resolver-binding-linux-x64-musl": "1.7.11",
- "@unrs/resolver-binding-wasm32-wasi": "1.7.11",
- "@unrs/resolver-binding-win32-arm64-msvc": "1.7.11",
- "@unrs/resolver-binding-win32-ia32-msvc": "1.7.11",
- "@unrs/resolver-binding-win32-x64-msvc": "1.7.11"
+ "@unrs/resolver-binding-android-arm-eabi": "1.9.1",
+ "@unrs/resolver-binding-android-arm64": "1.9.1",
+ "@unrs/resolver-binding-darwin-arm64": "1.9.1",
+ "@unrs/resolver-binding-darwin-x64": "1.9.1",
+ "@unrs/resolver-binding-freebsd-x64": "1.9.1",
+ "@unrs/resolver-binding-linux-arm-gnueabihf": "1.9.1",
+ "@unrs/resolver-binding-linux-arm-musleabihf": "1.9.1",
+ "@unrs/resolver-binding-linux-arm64-gnu": "1.9.1",
+ "@unrs/resolver-binding-linux-arm64-musl": "1.9.1",
+ "@unrs/resolver-binding-linux-ppc64-gnu": "1.9.1",
+ "@unrs/resolver-binding-linux-riscv64-gnu": "1.9.1",
+ "@unrs/resolver-binding-linux-riscv64-musl": "1.9.1",
+ "@unrs/resolver-binding-linux-s390x-gnu": "1.9.1",
+ "@unrs/resolver-binding-linux-x64-gnu": "1.9.1",
+ "@unrs/resolver-binding-linux-x64-musl": "1.9.1",
+ "@unrs/resolver-binding-wasm32-wasi": "1.9.1",
+ "@unrs/resolver-binding-win32-arm64-msvc": "1.9.1",
+ "@unrs/resolver-binding-win32-ia32-msvc": "1.9.1",
+ "@unrs/resolver-binding-win32-x64-msvc": "1.9.1"
}
},
"node_modules/update-browserslist-db": {
@@ -14962,16 +15198,16 @@
"license": "BSD-2-Clause"
},
"node_modules/vite/node_modules/@types/estree": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
- "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true,
"license": "MIT"
},
"node_modules/vite/node_modules/fdir": {
- "version": "6.4.5",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz",
- "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==",
+ "version": "6.4.6",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+ "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@@ -15012,13 +15248,13 @@
}
},
"node_modules/vite/node_modules/rollup": {
- "version": "4.42.0",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.42.0.tgz",
- "integrity": "sha512-LW+Vse3BJPyGJGAJt1j8pWDKPd73QM8cRXYK1IxOBgL2AGLu7Xd2YOW0M2sLUBCkF5MshXXtMApyEAEzMVMsnw==",
+ "version": "4.44.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz",
+ "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/estree": "1.0.7"
+ "@types/estree": "1.0.8"
},
"bin": {
"rollup": "dist/bin/rollup"
@@ -15028,26 +15264,26 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.42.0",
- "@rollup/rollup-android-arm64": "4.42.0",
- "@rollup/rollup-darwin-arm64": "4.42.0",
- "@rollup/rollup-darwin-x64": "4.42.0",
- "@rollup/rollup-freebsd-arm64": "4.42.0",
- "@rollup/rollup-freebsd-x64": "4.42.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.42.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.42.0",
- "@rollup/rollup-linux-arm64-gnu": "4.42.0",
- "@rollup/rollup-linux-arm64-musl": "4.42.0",
- "@rollup/rollup-linux-loongarch64-gnu": "4.42.0",
- "@rollup/rollup-linux-powerpc64le-gnu": "4.42.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.42.0",
- "@rollup/rollup-linux-riscv64-musl": "4.42.0",
- "@rollup/rollup-linux-s390x-gnu": "4.42.0",
- "@rollup/rollup-linux-x64-gnu": "4.42.0",
- "@rollup/rollup-linux-x64-musl": "4.42.0",
- "@rollup/rollup-win32-arm64-msvc": "4.42.0",
- "@rollup/rollup-win32-ia32-msvc": "4.42.0",
- "@rollup/rollup-win32-x64-msvc": "4.42.0",
+ "@rollup/rollup-android-arm-eabi": "4.44.0",
+ "@rollup/rollup-android-arm64": "4.44.0",
+ "@rollup/rollup-darwin-arm64": "4.44.0",
+ "@rollup/rollup-darwin-x64": "4.44.0",
+ "@rollup/rollup-freebsd-arm64": "4.44.0",
+ "@rollup/rollup-freebsd-x64": "4.44.0",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.44.0",
+ "@rollup/rollup-linux-arm-musleabihf": "4.44.0",
+ "@rollup/rollup-linux-arm64-gnu": "4.44.0",
+ "@rollup/rollup-linux-arm64-musl": "4.44.0",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.44.0",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0",
+ "@rollup/rollup-linux-riscv64-gnu": "4.44.0",
+ "@rollup/rollup-linux-riscv64-musl": "4.44.0",
+ "@rollup/rollup-linux-s390x-gnu": "4.44.0",
+ "@rollup/rollup-linux-x64-gnu": "4.44.0",
+ "@rollup/rollup-linux-x64-musl": "4.44.0",
+ "@rollup/rollup-win32-arm64-msvc": "4.44.0",
+ "@rollup/rollup-win32-ia32-msvc": "4.44.0",
+ "@rollup/rollup-win32-x64-msvc": "4.44.0",
"fsevents": "~2.3.2"
}
},
@@ -15315,6 +15551,12 @@
"node": ">=10.13.0"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/webpack": {
"version": "5.99.9",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
@@ -15466,9 +15708,9 @@
}
},
"node_modules/webpack/node_modules/webpack-sources": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.2.tgz",
- "integrity": "sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==",
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
+ "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
@@ -15494,12 +15736,6 @@
"webidl-conversions": "^3.0.0"
}
},
- "node_modules/whatwg-url/node_modules/webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
- "license": "BSD-2-Clause"
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index d602a2613c..3d71e94cd3 100644
--- a/package.json
+++ b/package.json
@@ -11,11 +11,12 @@
"@github/markdown-toolbar-element": "2.2.3",
"@github/quote-selection": "2.1.0",
"@github/text-expander-element": "2.8.0",
+ "@google/model-viewer": "4.1.0",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "19.14.0",
"ansi_up": "6.0.5",
"asciinema-player": "3.8.2",
- "chart.js": "4.4.9",
+ "chart.js": "4.5.0",
"chartjs-adapter-dayjs-4": "1.0.4",
"chartjs-plugin-zoom": "2.2.0",
"clippie": "4.1.7",
@@ -30,13 +31,13 @@
"idiomorph": "0.3.0",
"jquery": "3.7.1",
"katex": "0.16.22",
- "mermaid": "11.6.0",
+ "mermaid": "11.7.0",
"mini-css-extract-plugin": "2.9.2",
- "minimatch": "10.0.2",
+ "minimatch": "10.0.3",
"monaco-editor": "0.52.2",
"monaco-editor-webpack-plugin": "7.1.0",
"pdfobject": "2.3.0",
- "postcss": "8.5.4",
+ "postcss": "8.5.5",
"postcss-loader": "8.1.1",
"postcss-nesting": "13.0.2",
"pretty-ms": "9.0.0",
@@ -61,9 +62,9 @@
"devDependencies": {
"@axe-core/playwright": "4.10.2",
"@eslint-community/eslint-plugin-eslint-comments": "4.5.0",
- "@playwright/test": "1.53.0",
+ "@playwright/test": "1.52.0",
"@stoplight/spectral-cli": "6.15.0",
- "@stylistic/eslint-plugin-js": "4.4.1",
+ "@stylistic/eslint-plugin": "4.4.1",
"@stylistic/stylelint-plugin": "3.1.2",
"@vitejs/plugin-vue": "5.2.4",
"@vitest/coverage-v8": "3.2.3",
@@ -78,12 +79,12 @@
"eslint-plugin-playwright": "2.2.0",
"eslint-plugin-regexp": "2.9.0",
"eslint-plugin-sonarjs": "3.0.2",
- "eslint-plugin-unicorn": "59.0.1",
"eslint-plugin-toml": "0.12.0",
+ "eslint-plugin-unicorn": "59.0.1",
"eslint-plugin-vitest-globals": "1.5.0",
"eslint-plugin-vue": "10.2.0",
"eslint-plugin-vue-scoped-css": "2.10.0",
- "eslint-plugin-wc": "2.2.1",
+ "eslint-plugin-wc": "3.0.1",
"globals": "16.1.0",
"happy-dom": "18.0.0",
"license-checker-rseidelsohn": "4.4.2",
diff --git a/release-notes-published/11.0.2.md b/release-notes-published/11.0.2.md
new file mode 100644
index 0000000000..a1a8549984
--- /dev/null
+++ b/release-notes-published/11.0.2.md
@@ -0,0 +1,33 @@
+
+
+
+
+## Release notes
+
+- Features
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7986) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7991)): feat: make Forgejo Actions server logs less noisy
+- Bug fixes
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8155) ([backported](https://codeberg.org/forgejo/forgejo/pulls/8167)): fix: do not fail when release or wiki is set in `/repos/migrate` API
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7976) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7985)): fix: ignore expired artifacts for quota calculation
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7979) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7983)): fix: pull request cross references
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7883) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7886)): fix: quote reply in Chromium
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7775) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7779)): fix: make hash pattern more strict
+- Included for completeness but not worth a release note
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8112) ([backported](https://codeberg.org/forgejo/forgejo/pulls/8120)): fix: remove download attribute from external assets
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8110): Update bleve to v2.5.2 with changes made in backport of 2.5.0
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8094) ([backported](https://codeberg.org/forgejo/forgejo/pulls/8095)): fix: show membership of limited orgs
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8059): Update dependency go to v1.24.3 (v11.0/forgejo)
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8057): chore: drop unused `@typescript-eslint/parser` package
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/8021) ([backported](https://codeberg.org/forgejo/forgejo/pulls/8022)): chore(cleanup): suppress non actionable XORM warnings
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7987) ([backported](https://codeberg.org/forgejo/forgejo/pulls/8000)): fix: aggregate deleted team as ghost team
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7925) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7937)): fix(ui): center footer links
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7894) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7903)): fix(ui): fix force-push compare line layout
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7884) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7887)): fix: parse `change-id` in the git commit header
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7885): Update module github.com/blevesearch/bleve/v2 to v2.5.1 (v11.0/forgejo) - abandoned
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7746) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7871)): fix(ui): improve force-push compare line layout
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7640) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7869)): fix: Remove "create branch" button on mirrored repos
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7858): Update module github.com/msteinert/pam/v2 to v2.1.0 (v11.0/forgejo)
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7817) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7821)): fix: replace ß with ss in normalizeUserName
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7784) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7786)): fix(api): document `is_system_webhook` field
+ - [PR](https://codeberg.org/forgejo/forgejo/pulls/7773) ([backported](https://codeberg.org/forgejo/forgejo/pulls/7774)): fix: remove artificial delay for PR update
+
diff --git a/release-notes-published/12.0.0.md b/release-notes-published/12.0.0.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index e371ebb28b..bf08bdd249 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -1310,6 +1310,7 @@ func Routes() *web.Route {
m.Get("/refs", repo.GetGitAllRefs)
m.Get("/refs/*", repo.GetGitRefs)
m.Get("/trees/{sha}", repo.GetTree)
+ m.Get("/blobs", repo.GetBlobs)
m.Get("/blobs/{sha}", repo.GetBlob)
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
m.Group("/notes/{sha}", func() {
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index 03089a18d3..dbc4933de6 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -748,7 +748,7 @@ func ListActionRuns(ctx *context.APIContext) {
// type: string
// responses:
// "200":
- // "$ref": "#/responses/RepoActionRunList"
+ // "$ref": "#/responses/ActionRunList"
// "400":
// "$ref": "#/responses/error"
// "403":
@@ -779,16 +779,16 @@ func ListActionRuns(ctx *context.APIContext) {
return
}
- res := new(api.ListRepoActionRunResponse)
+ res := new(api.ListActionRunResponse)
res.TotalCount = total
- res.Entries = make([]*api.RepoActionRun, len(runs))
+ res.Entries = make([]*api.ActionRun, len(runs))
for i, r := range runs {
- cr, err := convert.ToRepoActionRun(ctx, r)
- if err != nil {
- ctx.Error(http.StatusInternalServerError, "ToActionRun", err)
+ if err := r.LoadAttributes(ctx); err != nil {
+ ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
+ cr := convert.ToActionRun(ctx, r, ctx.Doer)
res.Entries[i] = cr
}
@@ -821,7 +821,7 @@ func GetActionRun(ctx *context.APIContext) {
// required: true
// responses:
// "200":
- // "$ref": "#/responses/RepoActionRun"
+ // "$ref": "#/responses/ActionRun"
// "400":
// "$ref": "#/responses/error"
// "403":
@@ -839,16 +839,17 @@ func GetActionRun(ctx *context.APIContext) {
return
}
+ // Action runs lives in its own table, therefore we check that the
+ // run with the requested ID is owned by the repository
if ctx.Repo.Repository.ID != run.RepoID {
ctx.Error(http.StatusNotFound, "GetRunById", util.ErrNotExist)
return
}
- res, err := convert.ToRepoActionRun(ctx, run)
- if err != nil {
- ctx.Error(http.StatusInternalServerError, "ToRepoActionRun", err)
+ if err := run.LoadAttributes(ctx); err != nil {
+ ctx.Error(http.StatusInternalServerError, "LoadAttributes", err)
return
}
- ctx.JSON(http.StatusOK, res)
+ ctx.JSON(http.StatusOK, convert.ToActionRun(ctx, run, ctx.Doer))
}
diff --git a/routers/api/v1/repo/blob.go b/routers/api/v1/repo/blob.go
index 8ed57d4787..63baec2025 100644
--- a/routers/api/v1/repo/blob.go
+++ b/routers/api/v1/repo/blob.go
@@ -5,11 +5,54 @@ package repo
import (
"net/http"
+ "strings"
"forgejo.org/services/context"
files_service "forgejo.org/services/repository/files"
)
+// GetBlobs gets multiple blobs of a repository.
+func GetBlobs(ctx *context.APIContext) {
+ // swagger:operation GET /repos/{owner}/{repo}/git/blobs repository GetBlobs
+ // ---
+ // summary: Gets multiplbe blobs of a repository.
+ // 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
+ // - name: shas
+ // in: query
+ // description: a comma separated list of blob-sha (mind the overall URL-length limit of ~2,083 chars)
+ // type: string
+ // required: true
+ // responses:
+ // "200":
+ // "$ref": "#/responses/GitBlobList"
+ // "400":
+ // "$ref": "#/responses/error"
+
+ shas := ctx.FormString("shas")
+ if len(shas) == 0 {
+ ctx.Error(http.StatusBadRequest, "", "shas not provided")
+ return
+ }
+
+ if blobs, err := files_service.GetBlobsBySHA(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, strings.Split(shas, ",")); err != nil {
+ ctx.Error(http.StatusBadRequest, "", err)
+ } else {
+ ctx.JSON(http.StatusOK, blobs)
+ }
+}
+
// GetBlob get the blob of a repository file.
func GetBlob(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/git/blobs/{sha} repository GetBlob
@@ -30,12 +73,12 @@ func GetBlob(ctx *context.APIContext) {
// required: true
// - name: sha
// in: path
- // description: sha of the commit
+ // description: sha of the blob to retrieve
// type: string
// required: true
// responses:
// "200":
- // "$ref": "#/responses/GitBlobResponse"
+ // "$ref": "#/responses/GitBlob"
// "400":
// "$ref": "#/responses/error"
// "404":
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 75b4870e51..c9dda124de 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -71,7 +71,7 @@ func ListPullRequests(ctx *context.APIContext) {
// in: query
// description: Type of sort
// type: string
- // enum: [oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority]
+ // enum: [oldest, recentupdate, recentclose, leastupdate, mostcomment, leastcomment, priority]
// - name: milestone
// in: query
// description: ID of the milestone
diff --git a/routers/api/v1/swagger/repo.go b/routers/api/v1/swagger/repo.go
index a27e94253b..cd4832e15f 100644
--- a/routers/api/v1/swagger/repo.go
+++ b/routers/api/v1/swagger/repo.go
@@ -231,11 +231,18 @@ type swaggerGitTreeResponse struct {
Body api.GitTreeResponse `json:"body"`
}
-// GitBlobResponse
-// swagger:response GitBlobResponse
-type swaggerGitBlobResponse struct {
+// GitBlob
+// swagger:response GitBlob
+type swaggerGitBlob struct {
// in: body
- Body api.GitBlobResponse `json:"body"`
+ Body api.GitBlob `json:"body"`
+}
+
+// GitBlobList
+// swagger:response GitBlobList
+type swaggerGitBlobList struct {
+ // in: body
+ Body []api.GitBlob `json:"body"`
}
// Commit
@@ -456,16 +463,16 @@ type swaggerSyncForkInfo struct {
Body []api.SyncForkInfo `json:"body"`
}
-// RepoActionRunList
-// swagger:response RepoActionRunList
-type swaggerRepoActionRunList struct {
+// ActionRunList
+// swagger:response ActionRunList
+type swaggerActionRunList struct {
// in:body
- Body api.ListRepoActionRunResponse `json:"body"`
+ Body api.ListActionRunResponse `json:"body"`
}
-// RepoActionRun
-// swagger:response RepoActionRun
-type swaggerRepoActionRun struct {
+// ActionRun
+// swagger:response ActionRun
+type swaggerActionRun struct {
// in:body
- Body api.RepoActionRun `json:"body"`
+ Body api.ActionRun `json:"body"`
}
diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go
index 0188df17b4..964326291e 100644
--- a/routers/web/admin/users.go
+++ b/routers/web/admin/users.go
@@ -313,6 +313,9 @@ func editUserCommon(ctx *context.Context) {
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
+ ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
+ ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
+ ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
}
// EditUser show editing user page
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index 01e663a672..7b09c92ee5 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -25,7 +25,7 @@ import (
"forgejo.org/services/context"
"github.com/gorilla/feeds"
- "github.com/jaytaylor/html2text"
+ "github.com/inbucket/html2text"
)
func toBranchLink(ctx *context.Context, act *activities_model.Action) string {
diff --git a/routers/web/org/home.go b/routers/web/org/home.go
index a3823565ed..8f14f8899c 100644
--- a/routers/web/org/home.go
+++ b/routers/web/org/home.go
@@ -175,10 +175,12 @@ func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repositor
return
}
- if bytes, err := profileReadme.GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil {
- log.Error("failed to GetBlobContent: %v", err)
+ if rc, _, err := profileReadme.NewTruncatedReader(setting.UI.MaxDisplayFileSize); err != nil {
+ log.Error("failed to NewTruncatedReader: %v", err)
} else {
- if profileContent, err := markdown.RenderString(&markup.RenderContext{
+ defer rc.Close()
+
+ if profileContent, err := markdown.RenderReader(&markup.RenderContext{
Ctx: ctx,
GitRepo: profileGitRepo,
Links: markup.Links{
@@ -188,7 +190,7 @@ func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repositor
BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
},
Metas: map[string]string{"mode": "document"},
- }, bytes); err != nil {
+ }, rc); err != nil {
log.Error("failed to RenderString: %v", err)
} else {
ctx.Data["ProfileReadme"] = profileContent
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index 284f406413..c83242754b 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -50,6 +50,9 @@ func Settings(ctx *context.Context) {
ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
+ ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
+ ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
+ ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
err := shared_user.LoadHeaderCount(ctx)
if err != nil {
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index ccdd59f2dd..f4cc2a2cea 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -82,19 +82,19 @@ func RefBlame(ctx *context.Context) {
return
}
- ctx.Data["NumLinesSet"] = true
- ctx.Data["NumLines"], err = blob.GetBlobLineCount()
- if err != nil {
- ctx.ServerError("GetBlobLineCount", err)
- return
- }
-
result, err := performBlame(ctx, ctx.Repo.Commit, ctx.Repo.TreePath, ctx.FormBool("bypass-blame-ignore"))
if err != nil {
ctx.ServerError("performBlame", err)
return
}
+ ctx.Data["NumLinesSet"] = true
+ numLines := 0
+ for _, p := range result.Parts {
+ numLines += len(p.Lines)
+ }
+ ctx.Data["NumLines"] = numLines
+
ctx.Data["UsesIgnoreRevs"] = result.UsesIgnoreRevs
ctx.Data["FaultyIgnoreRevsFile"] = result.FaultyIgnoreRevsFile
diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go
index af8a838fc9..0fe52bfb48 100644
--- a/routers/web/repo/branch.go
+++ b/routers/web/repo/branch.go
@@ -70,11 +70,6 @@ func Branches(ctx *context.Context) {
ctx.ServerError("LoadBranches", err)
return
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- for key := range commitStatuses {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
- }
- }
commitStatus := make(map[string]*git_model.CommitStatus)
for commitID, cs := range commitStatuses {
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index 89463d9d03..f3192266ad 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -16,7 +16,6 @@ import (
"forgejo.org/models/db"
git_model "forgejo.org/models/git"
repo_model "forgejo.org/models/repo"
- unit_model "forgejo.org/models/unit"
user_model "forgejo.org/models/user"
"forgejo.org/modules/base"
"forgejo.org/modules/charset"
@@ -84,7 +83,7 @@ func Commits(ctx *context.Context) {
ctx.ServerError("CommitsByRange", err)
return
}
- ctx.Data["Commits"] = processGitCommits(ctx, commits)
+ ctx.Data["Commits"] = git_model.ParseCommitsWithStatus(ctx, commits, ctx.Repo.Repository)
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
@@ -202,7 +201,7 @@ func SearchCommits(ctx *context.Context) {
return
}
ctx.Data["CommitCount"] = len(commits)
- ctx.Data["Commits"] = processGitCommits(ctx, commits)
+ ctx.Data["Commits"] = git_model.ParseCommitsWithStatus(ctx, commits, ctx.Repo.Repository)
ctx.Data["Keyword"] = query
if all {
@@ -267,7 +266,7 @@ func FileHistory(ctx *context.Context) {
}
}
- ctx.Data["Commits"] = processGitCommits(ctx, commits)
+ ctx.Data["Commits"] = git_model.ParseCommitsWithStatus(ctx, commits, ctx.Repo.Repository)
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
@@ -375,9 +374,6 @@ func Diff(ctx *context.Context) {
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
}
- if !ctx.Repo.CanRead(unit_model.TypeActions) {
- git_model.CommitStatusesHideActionsURL(ctx, statuses)
- }
ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["CommitStatuses"] = statuses
@@ -456,20 +452,6 @@ func RawDiff(ctx *context.Context) {
}
}
-func processGitCommits(ctx *context.Context, gitCommits []*git.Commit) []*git_model.SignCommitWithStatuses {
- commits := git_model.ConvertFromGitCommit(ctx, gitCommits, ctx.Repo.Repository)
- if !ctx.Repo.CanRead(unit_model.TypeActions) {
- for _, commit := range commits {
- if commit.Status == nil {
- continue
- }
- commit.Status.HideActionsURL(ctx)
- git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
- }
- }
- return commits
-}
-
func SetCommitNotes(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CommitNotesForm)
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index f5826cf249..de2e29ab9f 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -654,7 +654,7 @@ func PrepareCompareDiff(
return false
}
- commits := processGitCommits(ctx, ci.CompareInfo.Commits)
+ commits := git_model.ParseCommitsWithStatus(ctx, ci.CompareInfo.Commits, ctx.Repo.Repository)
ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = len(commits)
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index b97c268ae2..5e228507c0 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -348,11 +348,6 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt
ctx.ServerError("GetIssuesAllCommitStatus", err)
return
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- for key := range commitStatuses {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
- }
- }
if err := issues.LoadAttributes(ctx); err != nil {
ctx.ServerError("issues.LoadAttributes", err)
@@ -1313,7 +1308,7 @@ func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *use
}
// Special user that can't have associated contributions and permissions in the repo.
- if poster.IsGhost() || poster.IsActions() || poster.IsAPServerActor() {
+ if poster.IsSystem() || poster.IsAPServerActor() {
return roleDescriptor, nil
}
@@ -1698,7 +1693,7 @@ func ViewIssue(ctx *context.Context) {
return
}
ghostMilestone := &issues_model.Milestone{
- ID: -1,
+ ID: issues_model.GhostMilestoneID,
Name: ctx.Locale.TrString("repo.issues.deleted_milestone"),
}
if comment.OldMilestoneID > 0 && comment.OldMilestone == nil {
@@ -1799,15 +1794,6 @@ func ViewIssue(ctx *context.Context) {
ctx.ServerError("LoadPushCommits", err)
return
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- for _, commit := range comment.Commits {
- if commit.Status == nil {
- continue
- }
- commit.Status.HideActionsURL(ctx)
- git_model.CommitStatusesHideActionsURL(ctx, commit.Statuses)
- }
- }
} else if comment.Type == issues_model.CommentTypeAddTimeManual ||
comment.Type == issues_model.CommentTypeStopTracking ||
comment.Type == issues_model.CommentTypeDeleteTimeManual {
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index bb89e30d54..fd18646211 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -10,13 +10,16 @@ import (
"errors"
"fmt"
"html"
+ "html/template"
"net/http"
"net/url"
+ "path"
"strconv"
"strings"
"forgejo.org/models"
activities_model "forgejo.org/models/activities"
+ asymkey_model "forgejo.org/models/asymkey"
"forgejo.org/models/db"
git_model "forgejo.org/models/git"
issues_model "forgejo.org/models/issues"
@@ -28,11 +31,13 @@ import (
"forgejo.org/models/unit"
user_model "forgejo.org/models/user"
"forgejo.org/modules/base"
+ "forgejo.org/modules/charset"
"forgejo.org/modules/emoji"
"forgejo.org/modules/git"
"forgejo.org/modules/gitrepo"
issue_template "forgejo.org/modules/issue/template"
"forgejo.org/modules/log"
+ "forgejo.org/modules/markup"
"forgejo.org/modules/optional"
"forgejo.org/modules/setting"
"forgejo.org/modules/structs"
@@ -498,6 +503,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
ctx.Data["IsPullRequestBroken"] = true
ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0
+ ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0
return nil
}
@@ -508,6 +514,12 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
ctx.Data["NumCommits"] = len(compareInfo.Commits)
ctx.Data["NumFiles"] = compareInfo.NumFiles
+ commitIDs := map[string]bool{}
+ for _, commit := range compareInfo.Commits {
+ commitIDs[commit.ID.String()] = true
+ }
+ ctx.Data["CommitIDs"] = commitIDs
+
if len(compareInfo.Commits) != 0 {
sha := compareInfo.Commits[0].ID.String()
commitStatuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptionsAll)
@@ -515,9 +527,6 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *issues_model.Issue)
ctx.ServerError("GetLatestCommitStatus", err)
return nil
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
- }
if len(commitStatuses) != 0 {
ctx.Data["LatestCommitStatuses"] = commitStatuses
@@ -581,9 +590,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.ServerError("GetLatestCommitStatus", err)
return nil
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
- }
if len(commitStatuses) > 0 {
ctx.Data["LatestCommitStatuses"] = commitStatuses
@@ -597,6 +603,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["IsPullRequestBroken"] = true
ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0
+ ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0
return nil
}
@@ -607,6 +614,13 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["NumCommits"] = len(compareInfo.Commits)
ctx.Data["NumFiles"] = compareInfo.NumFiles
+
+ commitIDs := map[string]bool{}
+ for _, commit := range compareInfo.Commits {
+ commitIDs[commit.ID.String()] = true
+ }
+ ctx.Data["CommitIDs"] = commitIDs
+
return compareInfo
}
@@ -665,6 +679,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
}
ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0
+ ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0
return nil
}
@@ -677,9 +692,6 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.ServerError("GetLatestCommitStatus", err)
return nil
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses)
- }
if len(commitStatuses) > 0 {
ctx.Data["LatestCommitStatuses"] = commitStatuses
@@ -745,6 +757,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["IsPullRequestBroken"] = true
ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["NumCommits"] = 0
+ ctx.Data["CommitIDs"] = map[string]bool{}
ctx.Data["NumFiles"] = 0
return nil
}
@@ -769,6 +782,13 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
ctx.Data["NumCommits"] = len(compareInfo.Commits)
ctx.Data["NumFiles"] = compareInfo.NumFiles
+
+ commitIDs := map[string]bool{}
+ for _, commit := range compareInfo.Commits {
+ commitIDs[commit.ID.String()] = true
+ }
+ ctx.Data["CommitIDs"] = commitIDs
+
return compareInfo
}
@@ -847,7 +867,7 @@ func ViewPullCommits(ctx *context.Context) {
ctx.Data["Username"] = ctx.Repo.Owner.Name
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
- commits := processGitCommits(ctx, prInfo.Commits)
+ commits := git_model.ParseCommitsWithStatus(ctx, prInfo.Commits, ctx.Repo.Repository)
ctx.Data["Commits"] = commits
ctx.Data["CommitCount"] = len(commits)
@@ -928,7 +948,78 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
ctx.Data["IsShowingOnlySingleCommit"] = willShowSpecifiedCommit
- if willShowSpecifiedCommit || willShowSpecifiedCommitRange {
+ if willShowSpecifiedCommit {
+ commitID := specifiedEndCommit
+
+ ctx.Data["CommitID"] = commitID
+
+ var prevCommit, curCommit, nextCommit *git.Commit
+
+ // Iterate in reverse to properly map "previous" and "next" buttons
+ for i := len(prInfo.Commits) - 1; i >= 0; i-- {
+ commit := prInfo.Commits[i]
+
+ if curCommit != nil {
+ nextCommit = commit
+ break
+ }
+
+ if commit.ID.String() == commitID {
+ curCommit = commit
+ } else {
+ prevCommit = commit
+ }
+ }
+
+ if curCommit == nil {
+ ctx.ServerError("Repo.GitRepo.viewPullFiles", git.ErrNotExist{ID: commitID})
+ return
+ }
+
+ ctx.Data["Commit"] = curCommit
+ if prevCommit != nil {
+ ctx.Data["PrevCommitLink"] = path.Join(ctx.Repo.RepoLink, "pulls", strconv.FormatInt(issue.Index, 10), "commits", prevCommit.ID.String())
+ }
+ if nextCommit != nil {
+ ctx.Data["NextCommitLink"] = path.Join(ctx.Repo.RepoLink, "pulls", strconv.FormatInt(issue.Index, 10), "commits", nextCommit.ID.String())
+ }
+
+ statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll)
+ if err != nil {
+ log.Error("GetLatestCommitStatus: %v", err)
+ }
+
+ ctx.Data["CommitStatus"] = git_model.CalcCommitStatus(statuses)
+ ctx.Data["CommitStatuses"] = statuses
+
+ verification := asymkey_model.ParseCommitWithSignature(ctx, curCommit)
+ ctx.Data["Verification"] = verification
+ ctx.Data["Author"] = user_model.ValidateCommitWithEmail(ctx, curCommit)
+
+ note := &git.Note{}
+ err = git.GetNote(ctx, ctx.Repo.GitRepo, specifiedEndCommit, note)
+ if err == nil {
+ ctx.Data["NoteCommit"] = note.Commit
+ ctx.Data["NoteAuthor"] = user_model.ValidateCommitWithEmail(ctx, note.Commit)
+ ctx.Data["NoteRendered"], err = markup.RenderCommitMessage(&markup.RenderContext{
+ Links: markup.Links{
+ Base: ctx.Repo.RepoLink,
+ BranchPath: path.Join("commit", util.PathEscapeSegments(commitID)),
+ },
+ Metas: ctx.Repo.Repository.ComposeMetas(ctx),
+ GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ }, template.HTMLEscapeString(string(charset.ToUTF8WithFallback(note.Message, charset.ConvertOpts{}))))
+ if err != nil {
+ ctx.ServerError("RenderCommitMessage", err)
+ return
+ }
+ }
+
+ endCommitID = commitID
+ startCommitID = prInfo.MergeBase
+ ctx.Data["IsShowingAllCommits"] = false
+ } else if willShowSpecifiedCommitRange {
if len(specifiedEndCommit) > 0 {
endCommitID = specifiedEndCommit
} else {
@@ -939,6 +1030,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
} else {
startCommitID = prInfo.MergeBase
}
+
ctx.Data["IsShowingAllCommits"] = false
} else {
endCommitID = headCommitID
@@ -946,10 +1038,10 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
ctx.Data["IsShowingAllCommits"] = true
}
- ctx.Data["Username"] = ctx.Repo.Owner.Name
- ctx.Data["Reponame"] = ctx.Repo.Repository.Name
ctx.Data["AfterCommitID"] = endCommitID
ctx.Data["BeforeCommitID"] = startCommitID
+ ctx.Data["Username"] = ctx.Repo.Owner.Name
+ ctx.Data["Reponame"] = ctx.Repo.Repository.Name
fileOnly := ctx.FormBool("file-only")
diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go
index 3c923c2c5e..493787ad8b 100644
--- a/routers/web/repo/repo.go
+++ b/routers/web/repo/repo.go
@@ -693,9 +693,6 @@ func SearchRepo(ctx *context.Context) {
ctx.JSON(http.StatusInternalServerError, nil)
return
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- git_model.CommitStatusesHideActionsURL(ctx, latestCommitStatuses)
- }
results := make([]*repo_service.WebSearchRepository, len(repos))
for i, repo := range repos {
diff --git a/routers/web/repo/setting/lfs.go b/routers/web/repo/setting/lfs.go
index 2e9c34e8a7..b9cb86bd08 100644
--- a/routers/web/repo/setting/lfs.go
+++ b/routers/web/repo/setting/lfs.go
@@ -342,6 +342,20 @@ func LFSFileGet(ctx *context.Context) {
ctx.Data["IsVideoFile"] = true
case st.IsAudio():
ctx.Data["IsAudioFile"] = true
+ case st.Is3DModel():
+ ctx.Data["Is3DModelFile"] = true
+ switch {
+ case st.IsGLB():
+ ctx.Data["IsGLBFile"] = true
+ case st.IsSTL():
+ ctx.Data["IsSTLFile"] = true
+ case st.IsGLTF():
+ ctx.Data["IsGLTFFile"] = true
+ case st.IsOBJ():
+ ctx.Data["IsOBJFile"] = true
+ case st.Is3MF():
+ ctx.Data["Is3MFFile"] = true
+ }
case st.IsImage() && (setting.UI.SVG.Enabled || !st.IsSvgImage()):
ctx.Data["IsImageFile"] = true
}
diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go
index c59225ba49..6f35e19880 100644
--- a/routers/web/repo/setting/setting.go
+++ b/routers/web/repo/setting/setting.go
@@ -64,6 +64,9 @@ func SettingsCtxData(ctx *context.Context) {
ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
+ ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
+ ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
+ ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
ctx.Data["SigningKeyAvailable"] = len(signing) > 0
@@ -150,11 +153,9 @@ func UnitsPost(ctx *context.Context) {
})
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeWiki)
} else if form.EnableWiki && !form.EnableExternalWiki && !unit_model.TypeWiki.UnitGlobalDisabled() {
- var wikiPermissions repo_model.UnitAccessMode
+ wikiPermissions := repo_model.UnitAccessModeUnset
if form.GloballyWriteableWiki {
wikiPermissions = repo_model.UnitAccessModeWrite
- } else {
- wikiPermissions = repo_model.UnitAccessModeRead
}
units = append(units, repo_model.RepoUnit{
RepoID: repo.ID,
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index de508509dc..bb3e1388a8 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -369,9 +369,6 @@ func loadLatestCommitData(ctx *context.Context, latestCommit *git.Commit) bool {
if err != nil {
log.Error("GetLatestCommitStatus: %v", err)
}
- if !ctx.Repo.CanRead(unit_model.TypeActions) {
- git_model.CommitStatusesHideActionsURL(ctx, statuses)
- }
ctx.Data["LatestCommitStatus"] = git_model.CalcCommitStatus(statuses)
ctx.Data["LatestCommitStatuses"] = statuses
@@ -442,8 +439,8 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["FileError"] = ctx.Locale.Tr("actions.runs.invalid_workflow_helper", workFlowErr.Error())
}
} else if slices.Contains([]string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"}, ctx.Repo.TreePath) {
- if data, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize); err == nil {
- _, warnings := issue_model.GetCodeOwnersFromContent(ctx, data)
+ if rc, size, err := blob.NewTruncatedReader(setting.UI.MaxDisplayFileSize); err == nil {
+ _, warnings := issue_model.GetCodeOwnersFromReader(ctx, rc, size > setting.UI.MaxDisplayFileSize)
if len(warnings) > 0 {
ctx.Data["FileWarning"] = strings.Join(warnings, "\n")
}
@@ -627,6 +624,20 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
ctx.Data["IsVideoFile"] = true
case fInfo.st.IsAudio():
ctx.Data["IsAudioFile"] = true
+ case fInfo.st.Is3DModel():
+ ctx.Data["Is3DModelFile"] = true
+ switch {
+ case fInfo.st.IsGLB():
+ ctx.Data["IsGLBFile"] = true
+ case fInfo.st.IsSTL():
+ ctx.Data["IsSTLFile"] = true
+ case fInfo.st.IsGLTF():
+ ctx.Data["IsGLTFFile"] = true
+ case fInfo.st.IsOBJ():
+ ctx.Data["IsOBJFile"] = true
+ case fInfo.st.Is3MF():
+ ctx.Data["Is3MFFile"] = true
+ }
case fInfo.st.IsImage() && (setting.UI.SVG.Enabled || !fInfo.st.IsSvgImage()):
ctx.Data["IsImageFile"] = true
ctx.Data["CanCopyContent"] = true
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index 9a21ac21a3..1b5265978a 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -393,7 +393,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
ctx.ServerError("CommitsByFileAndRange", err)
return nil, nil
}
- ctx.Data["Commits"] = git_model.ConvertFromGitCommit(ctx, commitsHistory, ctx.Repo.Repository)
+ ctx.Data["Commits"] = git_model.ParseCommitsWithStatus(ctx, commitsHistory, ctx.Repo.Repository)
pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5)
pager.SetDefaultParams(ctx)
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 2a93221c8f..d980fa393a 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -16,7 +16,6 @@ import (
activities_model "forgejo.org/models/activities"
asymkey_model "forgejo.org/models/asymkey"
"forgejo.org/models/db"
- git_model "forgejo.org/models/git"
issues_model "forgejo.org/models/issues"
"forgejo.org/models/organization"
repo_model "forgejo.org/models/repo"
@@ -611,11 +610,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
ctx.ServerError("GetIssuesLastCommitStatus", err)
return
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- for key := range commitStatuses {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
- }
- }
// -------------------------------
// Fill stats to post to ctx.Data.
diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go
index 9fa71add57..fdca1a2fdd 100644
--- a/routers/web/user/notification.go
+++ b/routers/web/user/notification.go
@@ -13,10 +13,8 @@ import (
activities_model "forgejo.org/models/activities"
"forgejo.org/models/db"
- git_model "forgejo.org/models/git"
issues_model "forgejo.org/models/issues"
repo_model "forgejo.org/models/repo"
- "forgejo.org/models/unit"
"forgejo.org/modules/base"
"forgejo.org/modules/log"
"forgejo.org/modules/optional"
@@ -311,11 +309,6 @@ func NotificationSubscriptions(ctx *context.Context) {
ctx.ServerError("GetIssuesAllCommitStatus", err)
return
}
- if !ctx.Repo.CanRead(unit.TypeActions) {
- for key := range commitStatuses {
- git_model.CommitStatusesHideActionsURL(ctx, commitStatuses[key])
- }
- }
ctx.Data["CommitLastStatus"] = lastStatus
ctx.Data["CommitStatuses"] = commitStatuses
ctx.Data["Issues"] = issues
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index 8068c1c6bc..78dd6c5e7c 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -70,17 +70,6 @@ func userProfile(ctx *context.Context) {
ctx.Data["OpenGraphURL"] = ctx.ContextUser.HTMLURL()
ctx.Data["OpenGraphDescription"] = ctx.ContextUser.Description
- // prepare heatmap data
- if setting.Service.EnableUserHeatmap {
- data, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer)
- if err != nil {
- ctx.ServerError("GetUserHeatmapDataByUser", err)
- return
- }
- ctx.Data["HeatmapData"] = data
- ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
- }
-
profileDbRepo, profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
defer profileClose()
@@ -186,6 +175,17 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
ctx.Data["CardsNoneMsg"] = ctx.Tr("followers.outgoing.list.none", ctx.ContextUser.Name)
}
case "activity":
+ // prepare heatmap data
+ if setting.Service.EnableUserHeatmap {
+ data, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer)
+ if err != nil {
+ ctx.ServerError("GetUserHeatmapDataByUser", err)
+ return
+ }
+ ctx.Data["HeatmapData"] = data
+ ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
+ }
+
date := ctx.FormString("date")
pagingNum = setting.UI.FeedPagingNum
items, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{
@@ -264,10 +264,12 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
total = int(count)
case "overview":
- if bytes, err := profileReadme.GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil {
- log.Error("failed to GetBlobContent: %v", err)
+ if rc, _, err := profileReadme.NewTruncatedReader(setting.UI.MaxDisplayFileSize); err != nil {
+ log.Error("failed to NewTruncatedReader: %v", err)
} else {
- if profileContent, err := markdown.RenderString(&markup.RenderContext{
+ defer rc.Close()
+
+ if profileContent, err := markdown.RenderReader(&markup.RenderContext{
Ctx: ctx,
GitRepo: profileGitRepo,
Links: markup.Links{
@@ -280,7 +282,7 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
},
Metas: map[string]string{"mode": "document"},
- }, bytes); err != nil {
+ }, rc); err != nil {
log.Error("failed to RenderString: %v", err)
} else {
ctx.Data["ProfileReadme"] = profileContent
diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go
index fe6ffb802d..400ee71f08 100644
--- a/routers/web/user/setting/profile.go
+++ b/routers/web/user/setting/profile.go
@@ -51,6 +51,9 @@ func Profile(ctx *context.Context) {
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
ctx.Data["CommonPronouns"] = commonPronouns
+ ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
+ ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
+ ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
ctx.HTML(http.StatusOK, tplSettingsProfile)
}
@@ -63,6 +66,9 @@ func ProfilePost(ctx *context.Context) {
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
ctx.Data["CommonPronouns"] = commonPronouns
+ ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
+ ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
+ ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplSettingsProfile)
diff --git a/routers/web/web.go b/routers/web/web.go
index 9be0af6fee..ba51b5c3f6 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1511,7 +1511,10 @@ func registerRoutes(m *web.Route) {
m.Group("/commits", func() {
m.Get("", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits)
m.Get("/list", context.RepoRef(), repo.GetPullCommits)
- m.Get("/{sha:[a-f0-9]{4,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
+ m.Group("/{sha:[a-f0-9]{4,40}}", func() {
+ m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit)
+ m.Post("/reviews/submit", context.RepoMustNotBeArchived(), web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview)
+ })
})
m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), context.EnforceQuotaWeb(quota_model.LimitSubjectSizeGitAll, context.QuotaTargetRepo), repo.MergePullRequest)
m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest)
diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go
index 9654186fbb..e240c996b5 100644
--- a/services/actions/notifier_helper.go
+++ b/services/actions/notifier_helper.go
@@ -345,6 +345,14 @@ func handleWorkflows(
Status: actions_model.StatusWaiting,
}
+ if workflow, err := model.ReadWorkflow(bytes.NewReader(dwf.Content)); err == nil {
+ notifications, err := workflow.Notifications()
+ if err != nil {
+ log.Error("Notifications: %w", err)
+ }
+ run.NotifyEmail = notifications
+ }
+
need, err := ifNeedApproval(ctx, run, input.Repo, input.Doer)
if err != nil {
log.Error("check if need approval for repo %d with user %d: %v", input.Repo.ID, input.Doer.ID, err)
diff --git a/services/actions/schedule_tasks.go b/services/actions/schedule_tasks.go
index 3ec0807d5f..cf8b29ead7 100644
--- a/services/actions/schedule_tasks.go
+++ b/services/actions/schedule_tasks.go
@@ -4,6 +4,7 @@
package actions
import (
+ "bytes"
"context"
"errors"
"fmt"
@@ -18,6 +19,7 @@ import (
webhook_module "forgejo.org/modules/webhook"
"github.com/nektos/act/pkg/jobparser"
+ act_model "github.com/nektos/act/pkg/model"
"xorm.io/builder"
)
@@ -140,6 +142,16 @@ func CreateScheduleTask(ctx context.Context, cron *actions_model.ActionSchedule)
return err
}
+ workflow, err := act_model.ReadWorkflow(bytes.NewReader(cron.Content))
+ if err != nil {
+ return err
+ }
+ notifications, err := workflow.Notifications()
+ if err != nil {
+ return err
+ }
+ run.NotifyEmail = notifications
+
// Parse the workflow specification from the cron schedule
workflows, err := jobparser.Parse(cron.Content, jobparser.WithVars(vars))
if err != nil {
diff --git a/services/actions/schedule_tasks_test.go b/services/actions/schedule_tasks_test.go
new file mode 100644
index 0000000000..7073985252
--- /dev/null
+++ b/services/actions/schedule_tasks_test.go
@@ -0,0 +1,121 @@
+// Copyright 2025 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package actions
+
+import (
+ "testing"
+
+ actions_model "forgejo.org/models/actions"
+ repo_model "forgejo.org/models/repo"
+ "forgejo.org/models/unittest"
+ webhook_module "forgejo.org/modules/webhook"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCreateScheduleTask(t *testing.T) {
+ require.NoError(t, unittest.PrepareTestDatabase())
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2, OwnerID: 2})
+
+ assertConstant := func(t *testing.T, cron *actions_model.ActionSchedule, run *actions_model.ActionRun) {
+ t.Helper()
+ assert.Equal(t, cron.Title, run.Title)
+ assert.Equal(t, cron.RepoID, run.RepoID)
+ assert.Equal(t, cron.OwnerID, run.OwnerID)
+ assert.Equal(t, cron.WorkflowID, run.WorkflowID)
+ assert.Equal(t, cron.TriggerUserID, run.TriggerUserID)
+ assert.Equal(t, cron.Ref, run.Ref)
+ assert.Equal(t, cron.CommitSHA, run.CommitSHA)
+ assert.Equal(t, cron.Event, run.Event)
+ assert.Equal(t, cron.EventPayload, run.EventPayload)
+ assert.Equal(t, cron.ID, run.ScheduleID)
+ assert.Equal(t, actions_model.StatusWaiting, run.Status)
+ }
+
+ assertMutable := func(t *testing.T, expected, run *actions_model.ActionRun) {
+ t.Helper()
+ assert.Equal(t, expected.NotifyEmail, run.NotifyEmail)
+ }
+
+ testCases := []struct {
+ name string
+ cron actions_model.ActionSchedule
+ want []actions_model.ActionRun
+ }{
+ {
+ name: "simple",
+ cron: actions_model.ActionSchedule{
+ Title: "scheduletitle1",
+ RepoID: repo.ID,
+ OwnerID: repo.OwnerID,
+ WorkflowID: "some.yml",
+ TriggerUserID: repo.OwnerID,
+ Ref: "branch",
+ CommitSHA: "fakeSHA",
+ Event: webhook_module.HookEventSchedule,
+ EventPayload: "fakepayload",
+ Content: []byte(
+ `
+name: test
+on: push
+jobs:
+ job2:
+ runs-on: ubuntu-latest
+ steps:
+ - run: true
+`),
+ },
+ want: []actions_model.ActionRun{
+ {
+ Title: "scheduletitle1",
+ NotifyEmail: false,
+ },
+ },
+ },
+ {
+ name: "enable-email-notifications is true",
+ cron: actions_model.ActionSchedule{
+ Title: "scheduletitle2",
+ RepoID: repo.ID,
+ OwnerID: repo.OwnerID,
+ WorkflowID: "some.yml",
+ TriggerUserID: repo.OwnerID,
+ Ref: "branch",
+ CommitSHA: "fakeSHA",
+ Event: webhook_module.HookEventSchedule,
+ EventPayload: "fakepayload",
+ Content: []byte(
+ `
+name: test
+enable-email-notifications: true
+on: push
+jobs:
+ job2:
+ runs-on: ubuntu-latest
+ steps:
+ - run: true
+`),
+ },
+ want: []actions_model.ActionRun{
+ {
+ Title: "scheduletitle2",
+ NotifyEmail: true,
+ },
+ },
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ require.NoError(t, CreateScheduleTask(t.Context(), &testCase.cron))
+ require.Equal(t, len(testCase.want), unittest.GetCount(t, actions_model.ActionRun{RepoID: repo.ID}))
+ for _, expected := range testCase.want {
+ run := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionRun{Title: expected.Title})
+ assertConstant(t, &testCase.cron, run)
+ assertMutable(t, &expected, run)
+ }
+ unittest.AssertSuccessfulDelete(t, actions_model.ActionRun{RepoID: repo.ID})
+ })
+ }
+}
diff --git a/services/actions/workflows.go b/services/actions/workflows.go
index 7ec7c3abed..fbba3fd667 100644
--- a/services/actions/workflows.go
+++ b/services/actions/workflows.go
@@ -111,6 +111,11 @@ func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGette
return nil, nil, err
}
+ notifications, err := wf.Notifications()
+ if err != nil {
+ return nil, nil, err
+ }
+
run := &actions_model.ActionRun{
Title: title,
RepoID: repo.ID,
@@ -125,6 +130,7 @@ func (entry *Workflow) Dispatch(ctx context.Context, inputGetter InputValueGette
EventPayload: string(p),
TriggerEvent: string(webhook.HookEventWorkflowDispatch),
Status: actions_model.StatusWaiting,
+ NotifyEmail: notifications,
}
vars, err := actions_model.GetVariablesOfRun(ctx, run)
diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go
index f183136907..cbfe3bd54e 100644
--- a/services/automerge/automerge.go
+++ b/services/automerge/automerge.go
@@ -107,6 +107,7 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
return
}
if !exists {
+ log.Trace("GetScheduledMergeByPullID found nothing for PR %d", pullID)
return
}
@@ -204,6 +205,10 @@ func handlePullRequestAutoMerge(pullID int64, sha string) {
return
}
+ if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) {
+ log.Error("DeleteScheduledAutoMerge[%d]: %v", pr.ID, err)
+ }
+
if err := pull_service.Merge(ctx, pr, doer, baseGitRepo, scheduledPRM.MergeStyle, "", scheduledPRM.Message, true); err != nil {
log.Error("pull_service.Merge: %v", err)
// FIXME: if merge failed, we should display some error message to the pull request page.
diff --git a/services/convert/action.go b/services/convert/action.go
index 5e17172b45..703c1f1261 100644
--- a/services/convert/action.go
+++ b/services/convert/action.go
@@ -8,22 +8,17 @@ import (
actions_model "forgejo.org/models/actions"
access_model "forgejo.org/models/perm/access"
+ user_model "forgejo.org/models/user"
api "forgejo.org/modules/structs"
)
// ToActionRun convert actions_model.User to api.ActionRun
// the run needs all attributes loaded
-func ToActionRun(ctx context.Context, run *actions_model.ActionRun) *api.ActionRun {
+func ToActionRun(ctx context.Context, run *actions_model.ActionRun, doer *user_model.User) *api.ActionRun {
if run == nil {
return nil
}
- // The doer is the one whose perspective is used to view this ActionRun.
- // In the best case we use the user that created the webhook.
- // Unfortunately we don't know who that was.
- // So instead we use the repo owner, who is able to create webhooks and allow others to do so by making them repo admins.
- // This is pretty close to perfect.
- doer := run.Repo.Owner
permissionInRepo, _ := access_model.GetUserRepoPermission(ctx, run.Repo, doer)
return &api.ActionRun{
diff --git a/services/convert/convert.go b/services/convert/convert.go
index 48da9d7623..2ea24a1b51 100644
--- a/services/convert/convert.go
+++ b/services/convert/convert.go
@@ -222,29 +222,6 @@ func ToActionTask(ctx context.Context, t *actions_model.ActionTask) (*api.Action
}, nil
}
-// ToRepoActionRun convert a actions_model.ActionRun to an api.RepoActionRun
-func ToRepoActionRun(ctx context.Context, r *actions_model.ActionRun) (*api.RepoActionRun, error) {
- if err := r.LoadAttributes(ctx); err != nil {
- return nil, err
- }
-
- url := strings.TrimSuffix(setting.AppURL, "/") + r.Link()
- actor := ToUser(ctx, r.TriggerUser, nil)
-
- return &api.RepoActionRun{
- ID: r.ID,
- Name: r.Title,
- HeadBranch: r.PrettyRef(),
- HeadSHA: r.CommitSHA,
- RunNumber: r.Index,
- Event: r.TriggerEvent,
- Status: r.Status.String(),
- WorkflowID: r.WorkflowID,
- URL: url,
- TriggeringActor: actor,
- }, nil
-}
-
// ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
func ToVerification(ctx context.Context, c *git.Commit) *api.PayloadCommitVerification {
verif := asymkey_model.ParseCommitWithSignature(ctx, c)
diff --git a/services/federation/federation_service.go b/services/federation/federation_service.go
index 174c175f86..a3b719d1a7 100644
--- a/services/federation/federation_service.go
+++ b/services/federation/federation_service.go
@@ -211,6 +211,11 @@ func CreateUserFromAP(ctx context.Context, personID fm.PersonID, federationHostI
return nil, nil, err
}
+ inbox, err := url.ParseRequestURI(person.Inbox.GetLink().String())
+ if err != nil {
+ return nil, nil, err
+ }
+
newUser := user.User{
LowerName: strings.ToLower(name),
Name: name,
@@ -227,6 +232,7 @@ func CreateUserFromAP(ctx context.Context, personID fm.PersonID, federationHostI
federatedUser := user.FederatedUser{
ExternalID: personID.ID,
FederationHostID: federationHostID,
+ InboxPath: inbox.Path,
NormalizedOriginalURL: personID.AsURI(),
}
diff --git a/services/feed/action.go b/services/feed/action.go
index a2cd0551a3..7d179bd1c8 100644
--- a/services/feed/action.go
+++ b/services/feed/action.go
@@ -39,6 +39,24 @@ func NewNotifier() notify_service.Notifier {
return &actionNotifier{}
}
+func notifyAll(ctx context.Context, action *activities_model.Action) error {
+ _, err := activities_model.NotifyWatchers(ctx, action)
+ if err != nil {
+ return err
+ }
+ return err
+ // return federation_service.NotifyActivityPubFollowers(ctx, out)
+}
+
+func notifyAllActions(ctx context.Context, acts []*activities_model.Action) error {
+ _, err := activities_model.NotifyWatchersActions(ctx, acts)
+ if err != nil {
+ return err
+ }
+ return nil
+ // return federation_service.NotifyActivityPubFollowers(ctx, out)
+}
+
func (a *actionNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue, mentions []*user_model.User) {
if err := issue.LoadPoster(ctx); err != nil {
log.Error("issue.LoadPoster: %v", err)
@@ -50,7 +68,7 @@ func (a *actionNotifier) NewIssue(ctx context.Context, issue *issues_model.Issue
}
repo := issue.Repo
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: issue.Poster.ID,
ActUser: issue.Poster,
OpType: activities_model.ActionCreateIssue,
@@ -91,7 +109,7 @@ func (a *actionNotifier) IssueChangeStatus(ctx context.Context, doer *user_model
}
// Notify watchers for whatever action comes in, ignore if no action type.
- if err := activities_model.NotifyWatchers(ctx, act); err != nil {
+ if err := notifyAll(ctx, act); err != nil {
log.Error("NotifyWatchers: %v", err)
}
}
@@ -127,7 +145,7 @@ func (a *actionNotifier) CreateIssueComment(ctx context.Context, doer *user_mode
}
// Notify watchers for whatever action comes in, ignore if no action type.
- if err := activities_model.NotifyWatchers(ctx, act); err != nil {
+ if err := notifyAll(ctx, act); err != nil {
log.Error("NotifyWatchers: %v", err)
}
}
@@ -146,7 +164,7 @@ func (a *actionNotifier) NewPullRequest(ctx context.Context, pull *issues_model.
return
}
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: pull.Issue.Poster.ID,
ActUser: pull.Issue.Poster,
OpType: activities_model.ActionCreatePullRequest,
@@ -160,7 +178,7 @@ func (a *actionNotifier) NewPullRequest(ctx context.Context, pull *issues_model.
}
func (a *actionNotifier) RenameRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldRepoName string) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionRenameRepo,
@@ -174,7 +192,7 @@ func (a *actionNotifier) RenameRepository(ctx context.Context, doer *user_model.
}
func (a *actionNotifier) TransferRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldOwnerName string) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionTransferRepo,
@@ -188,7 +206,7 @@ func (a *actionNotifier) TransferRepository(ctx context.Context, doer *user_mode
}
func (a *actionNotifier) CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionCreateRepo,
@@ -201,7 +219,7 @@ func (a *actionNotifier) CreateRepository(ctx context.Context, doer, u *user_mod
}
func (a *actionNotifier) ForkRepository(ctx context.Context, doer *user_model.User, oldRepo, repo *repo_model.Repository) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionCreateRepo,
@@ -266,13 +284,13 @@ func (a *actionNotifier) PullRequestReview(ctx context.Context, pr *issues_model
actions = append(actions, action)
}
- if err := activities_model.NotifyWatchersActions(ctx, actions); err != nil {
+ if err := notifyAllActions(ctx, actions); err != nil {
log.Error("notify watchers '%d/%d': %v", review.Reviewer.ID, review.Issue.RepoID, err)
}
}
func (*actionNotifier) MergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionMergePullRequest,
@@ -286,7 +304,7 @@ func (*actionNotifier) MergePullRequest(ctx context.Context, doer *user_model.Us
}
func (*actionNotifier) AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues_model.PullRequest) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionAutoMergePullRequest,
@@ -304,7 +322,7 @@ func (*actionNotifier) NotifyPullRevieweDismiss(ctx context.Context, doer *user_
if len(review.OriginalAuthor) > 0 {
reviewerName = review.OriginalAuthor
}
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: activities_model.ActionPullReviewDismissed,
@@ -342,7 +360,7 @@ func (a *actionNotifier) PushCommits(ctx context.Context, pusher *user_model.Use
opType = activities_model.ActionDeleteBranch
}
- if err = activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err = notifyAll(ctx, &activities_model.Action{
ActUserID: pusher.ID,
ActUser: pusher,
OpType: opType,
@@ -362,7 +380,7 @@ func (a *actionNotifier) CreateRef(ctx context.Context, doer *user_model.User, r
// has sent same action in `PushCommits`, so skip it.
return
}
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: opType,
@@ -381,7 +399,7 @@ func (a *actionNotifier) DeleteRef(ctx context.Context, doer *user_model.User, r
// has sent same action in `PushCommits`, so skip it.
return
}
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: opType,
@@ -405,7 +423,7 @@ func (a *actionNotifier) SyncPushCommits(ctx context.Context, pusher *user_model
return
}
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: repo.OwnerID,
ActUser: repo.MustOwner(ctx),
OpType: activities_model.ActionMirrorSyncPush,
@@ -420,7 +438,7 @@ func (a *actionNotifier) SyncPushCommits(ctx context.Context, pusher *user_model
}
func (a *actionNotifier) SyncCreateRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName, refID string) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: repo.OwnerID,
ActUser: repo.MustOwner(ctx),
OpType: activities_model.ActionMirrorSyncCreate,
@@ -434,7 +452,7 @@ func (a *actionNotifier) SyncCreateRef(ctx context.Context, doer *user_model.Use
}
func (a *actionNotifier) SyncDeleteRef(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, refFullName git.RefName) {
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: repo.OwnerID,
ActUser: repo.MustOwner(ctx),
OpType: activities_model.ActionMirrorSyncDelete,
@@ -452,7 +470,7 @@ func (a *actionNotifier) NewRelease(ctx context.Context, rel *repo_model.Release
log.Error("LoadAttributes: %v", err)
return
}
- if err := activities_model.NotifyWatchers(ctx, &activities_model.Action{
+ if err := notifyAll(ctx, &activities_model.Action{
ActUserID: rel.PublisherID,
ActUser: rel.Publisher,
OpType: activities_model.ActionPublishRelease,
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 989f69d4f4..6835dfbf36 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -440,11 +440,29 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int {
if err != nil {
return 0
}
- lineCount, err := blob.GetBlobLineCount()
+ reader, err := blob.DataAsync()
if err != nil {
return 0
}
- return lineCount
+ defer reader.Close()
+ buf := make([]byte, 32*1024)
+ count := 1
+ lineSep := []byte{'\n'}
+
+ c, err := reader.Read(buf)
+ if c == 0 && err == io.EOF {
+ return 0
+ }
+ for {
+ count += bytes.Count(buf[:c], lineSep)
+ switch {
+ case err == io.EOF:
+ return count
+ case err != nil:
+ return count
+ }
+ c, err = reader.Read(buf)
+ }
}
// Diff represents a difference between two git trees.
diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go
index 3d3c8432c4..695b177b8b 100644
--- a/services/gitdiff/gitdiff_test.go
+++ b/services/gitdiff/gitdiff_test.go
@@ -712,6 +712,8 @@ func TestGetDiffFull(t *testing.T) {
assert.Equal(t, ".gitattributes", diff.Files[0].Name)
assert.Equal(t, "24139dae656713ba861751fb2c2ac38839349a7a", diff.Files[0].NameHash)
+ assert.Len(t, diff.Files[0].Sections, 2)
+ assert.Equal(t, 4, diff.Files[0].Sections[1].Lines[0].SectionInfo.LeftIdx)
})
}
diff --git a/services/issue/pull.go b/services/issue/pull.go
index b0a0c47d88..2eef1fbfa8 100644
--- a/services/issue/pull.go
+++ b/services/issue/pull.go
@@ -43,8 +43,6 @@ type ReviewRequestNotifier struct {
}
func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue, pr *issues_model.PullRequest) ([]*ReviewRequestNotifier, error) {
- files := []string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"}
-
if pr.IsWorkInProgress(ctx) {
return nil, nil
}
@@ -72,18 +70,17 @@ func PullRequestCodeOwnersReview(ctx context.Context, issue *issues_model.Issue,
return nil, err
}
- var data string
- for _, file := range files {
+ var rules []*issues_model.CodeOwnerRule
+ for _, file := range []string{"CODEOWNERS", "docs/CODEOWNERS", ".gitea/CODEOWNERS"} {
if blob, err := commit.GetBlobByPath(file); err == nil {
- data, err = blob.GetBlobContent(setting.UI.MaxDisplayFileSize)
+ rc, size, err := blob.NewTruncatedReader(setting.UI.MaxDisplayFileSize)
if err == nil {
+ rules, _ = issues_model.GetCodeOwnersFromReader(ctx, rc, size > setting.UI.MaxDisplayFileSize)
break
}
}
}
- rules, _ := issues_model.GetCodeOwnersFromContent(ctx, data)
-
// get the mergebase
mergeBase, err := getMergeBase(repo, pr, git.BranchPrefix+pr.BaseBranch, pr.GetGitRefName())
if err != nil {
diff --git a/services/mailer/mail_actions.go b/services/mailer/mail_actions.go
index 7c63603a98..09763e164e 100644
--- a/services/mailer/mail_actions.go
+++ b/services/mailer/mail_actions.go
@@ -23,19 +23,24 @@ func MailActionRun(run *actions_model.ActionRun, priorStatus actions_model.Statu
return nil
}
- if run.TriggerUser.Email != "" && run.TriggerUser.EmailNotificationsPreference != user_model.EmailNotificationsDisabled {
- if err := sendMailActionRun(run.TriggerUser, run, priorStatus, lastRun); err != nil {
- return err
- }
+ if !run.NotifyEmail {
+ return nil
}
- if run.Repo.Owner.Email != "" && run.Repo.Owner.Email != run.TriggerUser.Email && run.Repo.Owner.EmailNotificationsPreference != user_model.EmailNotificationsDisabled {
- if err := sendMailActionRun(run.Repo.Owner, run, priorStatus, lastRun); err != nil {
- return err
- }
+ user := run.TriggerUser
+ // this happens e.g. when this is a scheduled run
+ if user.IsSystem() {
+ user = run.Repo.Owner
+ }
+ if user.IsSystem() || user.Email == "" {
+ return nil
}
- return nil
+ if user.EmailNotificationsPreference == user_model.EmailNotificationsDisabled {
+ return nil
+ }
+
+ return sendMailActionRun(user, run, priorStatus, lastRun)
}
func sendMailActionRun(to *user_model.User, run *actions_model.ActionRun, priorStatus actions_model.Status, lastRun *actions_model.ActionRun) error {
diff --git a/services/mailer/mail_actions_now_done_test.go b/services/mailer/mail_actions_now_done_test.go
index 0d832f2b36..6a01ea7631 100644
--- a/services/mailer/mail_actions_now_done_test.go
+++ b/services/mailer/mail_actions_now_done_test.go
@@ -4,42 +4,53 @@
package mailer
import (
+ "slices"
"testing"
actions_model "forgejo.org/models/actions"
"forgejo.org/models/db"
+ organization_model "forgejo.org/models/organization"
repo_model "forgejo.org/models/repo"
user_model "forgejo.org/models/user"
+ "forgejo.org/modules/optional"
"forgejo.org/modules/setting"
+ "forgejo.org/modules/test"
notify_service "forgejo.org/services/notify"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func getActionsNowDoneTestUsers(t *testing.T) []*user_model.User {
+func getActionsNowDoneTestUser(t *testing.T, name, email, notifications string) *user_model.User {
t.Helper()
- newTriggerUser := new(user_model.User)
- newTriggerUser.Name = "new_trigger_user"
- newTriggerUser.Language = "en_US"
- newTriggerUser.IsAdmin = false
- newTriggerUser.Email = "new_trigger_user@example.com"
- newTriggerUser.LastLoginUnix = 1693648327
- newTriggerUser.CreatedUnix = 1693648027
- newTriggerUser.EmailNotificationsPreference = user_model.EmailNotificationsEnabled
- require.NoError(t, user_model.CreateUser(db.DefaultContext, newTriggerUser))
+ user := new(user_model.User)
+ user.Name = name
+ user.Language = "en_US"
+ user.IsAdmin = false
+ user.Email = email
+ user.LastLoginUnix = 1693648327
+ user.CreatedUnix = 1693648027
+ opts := user_model.CreateUserOverwriteOptions{
+ AllowCreateOrganization: optional.Some(true),
+ EmailNotificationsPreference: ¬ifications,
+ }
+ require.NoError(t, user_model.AdminCreateUser(db.DefaultContext, user, &opts))
+ return user
+}
- newOwner := new(user_model.User)
- newOwner.Name = "new_owner"
- newOwner.Language = "en_US"
- newOwner.IsAdmin = false
- newOwner.Email = "new_owner@example.com"
- newOwner.LastLoginUnix = 1693648329
- newOwner.CreatedUnix = 1693648029
- newOwner.EmailNotificationsPreference = user_model.EmailNotificationsEnabled
- require.NoError(t, user_model.CreateUser(db.DefaultContext, newOwner))
-
- return []*user_model.User{newTriggerUser, newOwner}
+func getActionsNowDoneTestOrg(t *testing.T, name, email string, owner *user_model.User) *user_model.User {
+ t.Helper()
+ org := new(organization_model.Organization)
+ org.Name = name
+ org.Language = "en_US"
+ org.IsAdmin = false
+ // contact email for the organization, for display purposes but otherwise not used as of v12
+ org.Email = email
+ org.LastLoginUnix = 1693648327
+ org.CreatedUnix = 1693648027
+ org.Email = email
+ require.NoError(t, organization_model.CreateOrganization(db.DefaultContext, org, owner))
+ return (*user_model.User)(org)
}
func assertTranslatedLocaleMailActionsNowDone(t *testing.T, msgBody string) {
@@ -49,98 +60,181 @@ func assertTranslatedLocaleMailActionsNowDone(t *testing.T, msgBody string) {
func TestActionRunNowDoneNotificationMail(t *testing.T) {
ctx := t.Context()
- users := getActionsNowDoneTestUsers(t)
- defer CleanUpUsers(ctx, users)
- triggerUser := users[0]
- ownerUser := users[1]
+ defer test.MockVariableValue(&setting.Admin.DisableRegularOrgCreation, false)()
+
+ actionsUser := user_model.NewActionsUser()
+ require.NotEmpty(t, actionsUser.Email)
repo := repo_model.Repository{
Name: "some repo",
Description: "rockets are cool",
- Owner: ownerUser,
- OwnerID: ownerUser.ID,
}
// Do some funky stuff with the action run's ids:
// The run with the larger ID finished first.
// This is odd but something that must work.
- run1 := &actions_model.ActionRun{ID: 2, Repo: &repo, RepoID: repo.ID, Title: "some workflow", TriggerUser: triggerUser, TriggerUserID: triggerUser.ID, Status: actions_model.StatusFailure, Stopped: 1745821796, TriggerEvent: "workflow_dispatch"}
- run2 := &actions_model.ActionRun{ID: 1, Repo: &repo, RepoID: repo.ID, Title: "some workflow", TriggerUser: triggerUser, TriggerUserID: triggerUser.ID, Status: actions_model.StatusSuccess, Stopped: 1745822796, TriggerEvent: "push"}
+ run1 := &actions_model.ActionRun{ID: 2, Repo: &repo, RepoID: repo.ID, Title: "some workflow", Status: actions_model.StatusFailure, Stopped: 1745821796, TriggerEvent: "workflow_dispatch"}
+ run2 := &actions_model.ActionRun{ID: 1, Repo: &repo, RepoID: repo.ID, Title: "some workflow", Status: actions_model.StatusSuccess, Stopped: 1745822796, TriggerEvent: "push"}
+
+ assignUsers := func(triggerUser, owner *user_model.User) {
+ for _, run := range []*actions_model.ActionRun{run1, run2} {
+ run.TriggerUser = triggerUser
+ run.TriggerUserID = triggerUser.ID
+ run.NotifyEmail = true
+ }
+ repo.Owner = owner
+ repo.OwnerID = owner.ID
+ }
notify_service.RegisterNotifier(NewNotifier())
+ orgOwner := getActionsNowDoneTestUser(t, "org_owner", "org_owner@example.com", "disabled")
+ defer CleanUpUsers(ctx, []*user_model.User{orgOwner})
+
t.Run("DontSendNotificationEmailOnFirstActionSuccess", func(t *testing.T) {
+ user := getActionsNowDoneTestUser(t, "new_user", "new_user@example.com", "enabled")
+ defer CleanUpUsers(ctx, []*user_model.User{user})
+ assignUsers(user, user)
defer MockMailSettings(func(msgs ...*Message) {
assert.Fail(t, "no mail should be sent")
})()
notify_service.ActionRunNowDone(ctx, run2, actions_model.StatusRunning, nil)
})
- t.Run("SendNotificationEmailOnActionRunFailed", func(t *testing.T) {
- mailSentToOwner := false
- mailSentToTriggerUser := false
+ t.Run("WorkflowEnableEmailNotificationIsFalse", func(t *testing.T) {
+ user := getActionsNowDoneTestUser(t, "new_user1", "new_user1@example.com", "enabled")
+ defer CleanUpUsers(ctx, []*user_model.User{user})
+ assignUsers(user, user)
defer MockMailSettings(func(msgs ...*Message) {
- assert.LessOrEqual(t, len(msgs), 2)
- for _, msg := range msgs {
- switch msg.To {
- case triggerUser.EmailTo():
- assert.False(t, mailSentToTriggerUser, "sent mail twice")
- mailSentToTriggerUser = true
- case ownerUser.EmailTo():
- assert.False(t, mailSentToOwner, "sent mail twice")
- mailSentToOwner = true
- default:
- assert.Fail(t, "sent mail to unknown sender", msg.To)
- }
- assert.Contains(t, msg.Body, triggerUser.HTMLURL())
- assert.Contains(t, msg.Body, triggerUser.Name)
- // what happened
- assert.Contains(t, msg.Body, "failed")
- // new status of run
- assert.Contains(t, msg.Body, "failure")
- // prior status of this run
- assert.Contains(t, msg.Body, "waiting")
- assertTranslatedLocaleMailActionsNowDone(t, msg.Body)
- }
+ assert.Fail(t, "no mail should be sent")
})()
- notify_service.ActionRunNowDone(ctx, run1, actions_model.StatusWaiting, nil)
- assert.True(t, mailSentToOwner)
- assert.True(t, mailSentToTriggerUser)
+ run2.NotifyEmail = false
+ notify_service.ActionRunNowDone(ctx, run2, actions_model.StatusRunning, nil)
})
- t.Run("SendNotificationEmailOnActionRunRecovered", func(t *testing.T) {
- mailSentToOwner := false
- mailSentToTriggerUser := false
- defer MockMailSettings(func(msgs ...*Message) {
- assert.LessOrEqual(t, len(msgs), 2)
- for _, msg := range msgs {
- switch msg.To {
- case triggerUser.EmailTo():
- assert.False(t, mailSentToTriggerUser, "sent mail twice")
- mailSentToTriggerUser = true
- case ownerUser.EmailTo():
- assert.False(t, mailSentToOwner, "sent mail twice")
- mailSentToOwner = true
- default:
- assert.Fail(t, "sent mail to unknown sender", msg.To)
- }
- assert.Contains(t, msg.Body, triggerUser.HTMLURL())
- assert.Contains(t, msg.Body, triggerUser.Name)
- // what happened
- assert.Contains(t, msg.Body, "recovered")
- // old status of run
- assert.Contains(t, msg.Body, "failure")
- // new status of run
- assert.Contains(t, msg.Body, "success")
- // prior status of this run
- assert.Contains(t, msg.Body, "running")
- assertTranslatedLocaleMailActionsNowDone(t, msg.Body)
- }
- })()
- assert.NotNil(t, setting.MailService)
+ for _, testCase := range []struct {
+ name string
+ triggerUser *user_model.User
+ owner *user_model.User
+ expected string
+ expectMail bool
+ }{
+ {
+ // if the action is assigned a trigger user in a repository
+ // owned by a regular user, the mail is sent to the trigger user
+ name: "RegularTriggerUser",
+ triggerUser: getActionsNowDoneTestUser(t, "new_trigger_user0", "new_trigger_user0@example.com", user_model.EmailNotificationsEnabled),
+ owner: getActionsNowDoneTestUser(t, "new_owner0", "new_owner0@example.com", user_model.EmailNotificationsEnabled),
+ expected: "trigger",
+ expectMail: true,
+ },
+ {
+ // if the action is assigned to a system user (e.g. ActionsUser)
+ // in a repository owned by a regular user, the mail is sent to
+ // the user that owns the repository
+ name: "SystemTriggerUserAndRegularOwner",
+ triggerUser: actionsUser,
+ owner: getActionsNowDoneTestUser(t, "new_owner1", "new_owner1@example.com", user_model.EmailNotificationsEnabled),
+ expected: "owner",
+ expectMail: true,
+ },
+ {
+ // if the action is assigned a trigger user with disabled notifications in a repository
+ // owned by a regular user, no mail is sent
+ name: "RegularTriggerUserNotificationsDisabled",
+ triggerUser: getActionsNowDoneTestUser(t, "new_trigger_user2", "new_trigger_user2@example.com", user_model.EmailNotificationsDisabled),
+ owner: getActionsNowDoneTestUser(t, "new_owner2", "new_owner2@example.com", user_model.EmailNotificationsEnabled),
+ expectMail: false,
+ },
+ {
+ // if the action is assigned to a system user (e.g. ActionsUser)
+ // owned by a regular user with disabled notifications, no mail is sent
+ name: "SystemTriggerUserAndRegularOwnerNotificationsDisabled",
+ triggerUser: actionsUser,
+ owner: getActionsNowDoneTestUser(t, "new_owner3", "new_owner3@example.com", user_model.EmailNotificationsDisabled),
+ expectMail: false,
+ },
+ {
+ // if the action is assigned to a system user (e.g. ActionsUser)
+ // in a repository owned by an organization with an email contact, the mail is sent to
+ // this email contact
+ name: "SystemTriggerUserAndOrgOwner",
+ triggerUser: actionsUser,
+ owner: getActionsNowDoneTestOrg(t, "new_org1", "new_org_owner0@example.com", orgOwner),
+ expected: "owner",
+ expectMail: true,
+ },
+ {
+ // if the action is assigned to a system user (e.g. ActionsUser)
+ // in a repository owned by an organization without an email contact, no mail is sent
+ name: "SystemTriggerUserAndNoMailOrgOwner",
+ triggerUser: actionsUser,
+ owner: getActionsNowDoneTestOrg(t, "new_org2", "", orgOwner),
+ expectMail: false,
+ },
+ } {
+ t.Run(testCase.name, func(t *testing.T) {
+ assignUsers(testCase.triggerUser, testCase.owner)
+ defer CleanUpUsers(ctx, slices.DeleteFunc([]*user_model.User{testCase.triggerUser, testCase.owner}, func(user *user_model.User) bool {
+ return user.IsSystem()
+ }))
- notify_service.ActionRunNowDone(ctx, run2, actions_model.StatusRunning, run1)
- assert.True(t, mailSentToOwner)
- assert.True(t, mailSentToTriggerUser)
- })
+ t.Run("SendNotificationEmailOnActionRunFailed", func(t *testing.T) {
+ mailSent := false
+ defer MockMailSettings(func(msgs ...*Message) {
+ assert.Len(t, msgs, 1)
+ msg := msgs[0]
+ assert.False(t, mailSent, "sent mail twice")
+ expectedEmail := testCase.triggerUser.Email
+ if testCase.expected == "owner" { // otherwise "trigger"
+ expectedEmail = testCase.owner.Email
+ }
+ require.Contains(t, msg.To, expectedEmail, "sent mail to unknown sender")
+ mailSent = true
+ assert.Contains(t, msg.Body, testCase.triggerUser.HTMLURL())
+ assert.Contains(t, msg.Body, testCase.triggerUser.Name)
+ // what happened
+ assert.Contains(t, msg.Body, "failed")
+ // new status of run
+ assert.Contains(t, msg.Body, "failure")
+ // prior status of this run
+ assert.Contains(t, msg.Body, "waiting")
+ assertTranslatedLocaleMailActionsNowDone(t, msg.Body)
+ })()
+ require.NotNil(t, setting.MailService)
+
+ notify_service.ActionRunNowDone(ctx, run1, actions_model.StatusWaiting, nil)
+ assert.Equal(t, testCase.expectMail, mailSent)
+ })
+
+ t.Run("SendNotificationEmailOnActionRunRecovered", func(t *testing.T) {
+ mailSent := false
+ defer MockMailSettings(func(msgs ...*Message) {
+ assert.Len(t, msgs, 1)
+ msg := msgs[0]
+ assert.False(t, mailSent, "sent mail twice")
+ expectedEmail := testCase.triggerUser.Email
+ if testCase.expected == "owner" { // otherwise "trigger"
+ expectedEmail = testCase.owner.Email
+ }
+ require.Contains(t, msg.To, expectedEmail, "sent mail to unknown sender")
+ mailSent = true
+ assert.Contains(t, msg.Body, testCase.triggerUser.HTMLURL())
+ assert.Contains(t, msg.Body, testCase.triggerUser.Name)
+ // what happened
+ assert.Contains(t, msg.Body, "recovered")
+ // old status of run
+ assert.Contains(t, msg.Body, "failure")
+ // new status of run
+ assert.Contains(t, msg.Body, "success")
+ // prior status of this run
+ assert.Contains(t, msg.Body, "running")
+ })()
+ require.NotNil(t, setting.MailService)
+
+ notify_service.ActionRunNowDone(ctx, run2, actions_model.StatusRunning, run1)
+ assert.Equal(t, testCase.expectMail, mailSent)
+ })
+ })
+ }
}
diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go
index ca5c645e0c..d8646d9ddd 100644
--- a/services/mailer/mailer.go
+++ b/services/mailer/mailer.go
@@ -29,7 +29,7 @@ import (
notify_service "forgejo.org/services/notify"
ntlmssp "github.com/Azure/go-ntlmssp"
- "github.com/jaytaylor/html2text"
+ "github.com/inbucket/html2text"
"gopkg.in/gomail.v2"
)
diff --git a/services/mailer/main_test.go b/services/mailer/main_test.go
index 47e5d5d175..5e9cbe3e99 100644
--- a/services/mailer/main_test.go
+++ b/services/mailer/main_test.go
@@ -8,6 +8,7 @@ import (
"testing"
"forgejo.org/models/db"
+ organization_model "forgejo.org/models/organization"
"forgejo.org/models/unittest"
user_model "forgejo.org/models/user"
"forgejo.org/modules/setting"
@@ -51,6 +52,11 @@ func MockMailSettings(send func(msgs ...*Message)) func() {
func CleanUpUsers(ctx context.Context, users []*user_model.User) {
for _, u := range users {
- db.DeleteByID[user_model.User](ctx, u.ID)
+ if u.IsOrganization() {
+ organization_model.DeleteOrganization(ctx, (*organization_model.Organization)(u))
+ } else {
+ db.DeleteByID[user_model.User](ctx, u.ID)
+ db.DeleteByBean(ctx, &user_model.EmailAddress{UID: u.ID})
+ }
}
}
diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go
index 55adad9685..7887dacdb1 100644
--- a/services/migrations/gitea_uploader.go
+++ b/services/migrations/gitea_uploader.go
@@ -766,7 +766,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*issues_model
issue := issues_model.Issue{
RepoID: g.repo.ID,
Repo: g.repo,
- Title: prTitle,
+ Title: util.TruncateRunes(prTitle, 255),
Index: pr.Number,
Content: pr.Content,
MilestoneID: milestoneID,
diff --git a/services/pull/check.go b/services/pull/check.go
index afeb7e675e..6002e2ae26 100644
--- a/services/pull/check.go
+++ b/services/pull/check.go
@@ -28,6 +28,7 @@ import (
"forgejo.org/modules/timeutil"
asymkey_service "forgejo.org/services/asymkey"
notify_service "forgejo.org/services/notify"
+ shared_automerge "forgejo.org/services/shared/automerge"
)
// prPatchCheckerQueue represents a queue to handle update pull request tests
@@ -170,7 +171,7 @@ func isSignedIfRequired(ctx context.Context, pr *issues_model.PullRequest, doer
// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
// and set to be either conflict or mergeable.
-func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) {
+func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) bool {
// If status has not been changed to conflict by testPatch then we are mergeable
if pr.Status == issues_model.PullRequestStatusChecking {
pr.Status = issues_model.PullRequestStatusMergeable
@@ -184,12 +185,15 @@ func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) {
if has {
log.Trace("Not updating status for %-v as it is due to be rechecked", pr)
- return
+ return false
}
if err := pr.UpdateColsIfNotMerged(ctx, "merge_base", "status", "conflicted_files", "changed_protected_files"); err != nil {
log.Error("Update[%-v]: %v", pr, err)
+ return false
}
+
+ return true
}
// getMergeCommit checks if a pull request has been merged
@@ -339,15 +343,22 @@ func handler(items ...string) []string {
}
func testPR(id int64) {
- pullWorkingPool.CheckIn(fmt.Sprint(id))
- defer pullWorkingPool.CheckOut(fmt.Sprint(id))
ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("Test PR[%d] from patch checking queue", id))
defer finished()
+ if pr, updated := testPRProtected(ctx, id); pr != nil && updated {
+ shared_automerge.AddToQueueIfMergeable(ctx, pr)
+ }
+}
+
+func testPRProtected(ctx context.Context, id int64) (*issues_model.PullRequest, bool) {
+ pullWorkingPool.CheckIn(fmt.Sprint(id))
+ defer pullWorkingPool.CheckOut(fmt.Sprint(id))
+
pr, err := issues_model.GetPullRequestByID(ctx, id)
if err != nil {
log.Error("Unable to GetPullRequestByID[%d] for testPR: %v", id, err)
- return
+ return nil, false
}
log.Trace("Testing %-v", pr)
@@ -357,12 +368,12 @@ func testPR(id int64) {
if pr.HasMerged {
log.Trace("%-v is already merged (status: %s, merge commit: %s)", pr, pr.Status, pr.MergedCommitID)
- return
+ return nil, false
}
if manuallyMerged(ctx, pr) {
log.Trace("%-v is manually merged (status: %s, merge commit: %s)", pr, pr.Status, pr.MergedCommitID)
- return
+ return nil, false
}
if err := TestPatch(pr); err != nil {
@@ -371,9 +382,10 @@ func testPR(id int64) {
if err := pr.UpdateCols(ctx, "status"); err != nil {
log.Error("update pr [%-v] status to PullRequestStatusError failed: %v", pr, err)
}
- return
+ return nil, false
}
- checkAndUpdateStatus(ctx, pr)
+
+ return pr, checkAndUpdateStatus(ctx, pr)
}
// CheckPRsForBaseBranch check all pulls with baseBrannch
diff --git a/services/repository/files/content.go b/services/repository/files/content.go
index 5f7dd38303..3d2217df18 100644
--- a/services/repository/files/content.go
+++ b/services/repository/files/content.go
@@ -250,8 +250,25 @@ func GetContents(ctx context.Context, repo *repo_model.Repository, treePath, ref
return contentsResponse, nil
}
-// GetBlobBySHA get the GitBlobResponse of a repository using a sha hash.
-func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, sha string) (*api.GitBlobResponse, error) {
+// GetBlobsBySHA gets multiple GitBlobs of a repository by sha hash.
+func GetBlobsBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, shas []string) ([]*api.GitBlob, error) {
+ if len(shas) > setting.API.MaxResponseItems {
+ shas = shas[:setting.API.MaxResponseItems]
+ }
+
+ blobs := make([]*api.GitBlob, 0, len(shas))
+ for _, sha := range shas {
+ blob, err := GetBlobBySHA(ctx, repo, gitRepo, sha)
+ if err != nil {
+ return nil, err
+ }
+ blobs = append(blobs, blob)
+ }
+ return blobs, nil
+}
+
+// GetBlobBySHA get the GitBlob of a repository using a sha hash.
+func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, sha string) (*api.GitBlob, error) {
gitBlob, err := gitRepo.GetBlob(sha)
if err != nil {
return nil, err
@@ -263,7 +280,7 @@ func GetBlobBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git
return nil, err
}
}
- return &api.GitBlobResponse{
+ return &api.GitBlob{
SHA: gitBlob.ID.String(),
URL: repo.APIURL() + "/git/blobs/" + url.PathEscape(gitBlob.ID.String()),
Size: gitBlob.Size(),
diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go
index e55b840660..8fc8f56b4f 100644
--- a/services/repository/files/content_test.go
+++ b/services/repository/files/content_test.go
@@ -192,7 +192,7 @@ func TestGetBlobBySHA(t *testing.T) {
defer gitRepo.Close()
gbr, err := GetBlobBySHA(db.DefaultContext, repo, gitRepo, "65f1bf27bc3bf70f64657658635e66094edbcb4d")
- expectedGBR := &api.GitBlobResponse{
+ expectedGBR := &api.GitBlob{
Content: "dHJlZSAyYTJmMWQ0NjcwNzI4YTJlMTAwNDllMzQ1YmQ3YTI3NjQ2OGJlYWI2CmF1dGhvciB1c2VyMSA8YWRkcmVzczFAZXhhbXBsZS5jb20+IDE0ODk5NTY0NzkgLTA0MDAKY29tbWl0dGVyIEV0aGFuIEtvZW5pZyA8ZXRoYW50a29lbmlnQGdtYWlsLmNvbT4gMTQ4OTk1NjQ3OSAtMDQwMAoKSW5pdGlhbCBjb21taXQK",
Encoding: "base64",
URL: "https://try.gitea.io/api/v1/repos/user2/repo1/git/blobs/65f1bf27bc3bf70f64657658635e66094edbcb4d",
@@ -202,3 +202,43 @@ func TestGetBlobBySHA(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, expectedGBR, gbr)
}
+
+func TestGetBlobsBySHA(t *testing.T) {
+ unittest.PrepareTestEnv(t)
+ repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
+
+ gitRepo, err := gitrepo.OpenRepository(db.DefaultContext, repo)
+ require.NoError(t, err)
+ defer gitRepo.Close()
+
+ gbr, err := GetBlobsBySHA(db.DefaultContext, repo, gitRepo, []string{
+ "ea82fc8777a24b07c26b3a4bf4e2742c03733eab", // Home.md
+ "6395b68e1feebb1e4c657b4f9f6ba2676a283c0b", // line.svg
+ "26f842bcad37fa40a1bb34cbb5ee219ee35d863d", // test.xml
+ })
+ expectedGBR := []*api.GitBlob{
+ {
+ Content: "IyBIb21lIHBhZ2UKClRoaXMgaXMgdGhlIGhvbWUgcGFnZSEK",
+ Encoding: "base64",
+ URL: "https://try.gitea.io/api/v1/repos/user2/repo2/git/blobs/ea82fc8777a24b07c26b3a4bf4e2742c03733eab",
+ SHA: "ea82fc8777a24b07c26b3a4bf4e2742c03733eab",
+ Size: 36,
+ },
+ {
+ Content: "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZwogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHdpZHRoPSIxMjgiCiAgIGhlaWdodD0iMTI4IgogICB2aWV3Qm94PSIwIDAgMTI4IDEyOCI+CgogIDxsaW5lIHgxPSIwIiB5MT0iNyIgeDI9IjEwIiB5Mj0iNyIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KPC9zdmc+",
+ Encoding: "base64",
+ URL: "https://try.gitea.io/api/v1/repos/user2/repo2/git/blobs/6395b68e1feebb1e4c657b4f9f6ba2676a283c0b",
+ SHA: "6395b68e1feebb1e4c657b4f9f6ba2676a283c0b",
+ Size: 246,
+ },
+ {
+ Content: "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHRlc3Q+VGhpcyBpcyBYTUw8L3Rlc3Q+Cg==",
+ Encoding: "base64",
+ URL: "https://try.gitea.io/api/v1/repos/user2/repo2/git/blobs/26f842bcad37fa40a1bb34cbb5ee219ee35d863d",
+ SHA: "26f842bcad37fa40a1bb34cbb5ee219ee35d863d",
+ Size: 64,
+ },
+ }
+ require.NoError(t, err)
+ assert.Equal(t, expectedGBR, gbr)
+}
diff --git a/services/shared/automerge/automerge.go b/services/shared/automerge/automerge.go
index 1dc309f4b3..be7b2f6eb4 100644
--- a/services/shared/automerge/automerge.go
+++ b/services/shared/automerge/automerge.go
@@ -21,9 +21,9 @@ import (
var PRAutoMergeQueue *queue.WorkerPoolQueue[string]
func addToQueue(pr *issues_model.PullRequest, sha string) {
- log.Trace("Adding pullID: %d to the pull requests patch checking queue with sha %s", pr.ID, sha)
+ log.Trace("Adding pullID: %d to the automerge queue with sha %s", pr.ID, sha)
if err := PRAutoMergeQueue.Push(fmt.Sprintf("%d_%s", pr.ID, sha)); err != nil {
- log.Error("Error adding pullID: %d to the pull requests patch checking queue %v", pr.ID, err)
+ log.Error("Error adding pullID: %d to the automerge queue %v", pr.ID, err)
}
}
@@ -43,32 +43,29 @@ func StartPRCheckAndAutoMergeBySHA(ctx context.Context, sha string, repo *repo_m
return nil
}
-// StartPRCheckAndAutoMerge start an automerge check and auto merge task for a pull request
func StartPRCheckAndAutoMerge(ctx context.Context, pull *issues_model.PullRequest) {
if pull == nil || pull.HasMerged || !pull.CanAutoMerge() {
return
}
- if err := pull.LoadBaseRepo(ctx); err != nil {
- log.Error("LoadBaseRepo: %v", err)
- return
+ commitID := pull.HeadCommitID
+ if commitID == "" {
+ commitID = getCommitIDFromRefName(ctx, pull)
}
- gitRepo, err := gitrepo.OpenRepository(ctx, pull.BaseRepo)
- if err != nil {
- log.Error("OpenRepository: %v", err)
- return
- }
- defer gitRepo.Close()
- commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
- if err != nil {
- log.Error("GetRefCommitID: %v", err)
+ if commitID == "" {
return
}
addToQueue(pull, commitID)
}
+var AddToQueueIfMergeable = func(ctx context.Context, pull *issues_model.PullRequest) {
+ if pull.Status == issues_model.PullRequestStatusMergeable {
+ StartPRCheckAndAutoMerge(ctx, pull)
+ }
+}
+
func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.Repository, filter func(*issues_model.PullRequest) bool) (map[int64]*issues_model.PullRequest, error) {
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
if err != nil {
@@ -118,3 +115,24 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model.
return pulls, nil
}
+
+func getCommitIDFromRefName(ctx context.Context, pull *issues_model.PullRequest) string {
+ if err := pull.LoadBaseRepo(ctx); err != nil {
+ log.Error("LoadBaseRepo: %v", err)
+ return ""
+ }
+
+ gitRepo, err := gitrepo.OpenRepository(ctx, pull.BaseRepo)
+ if err != nil {
+ log.Error("OpenRepository: %v", err)
+ return ""
+ }
+ defer gitRepo.Close()
+ commitID, err := gitRepo.GetRefCommitID(pull.GetGitRefName())
+ if err != nil {
+ log.Error("GetRefCommitID: %v", err)
+ return ""
+ }
+
+ return commitID
+}
diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go
index b3201e5d10..009efc994f 100644
--- a/services/webhook/notifier.go
+++ b/services/webhook/notifier.go
@@ -894,9 +894,16 @@ func (m *webhookNotifier) ActionRunNowDone(ctx context.Context, run *actions_mod
Owner: run.TriggerUser,
}
+ // The doer is the one whose perspective is used to view this ActionRun.
+ // In the best case we use the user that created the webhook.
+ // Unfortunately we don't know who that was.
+ // So instead we use the repo owner, who is able to create webhooks and allow others to do so by making them repo admins.
+ // This is pretty close to perfect.
+ doer := run.Repo.Owner
+
payload := &api.ActionPayload{
- Run: convert.ToActionRun(ctx, run),
- LastRun: convert.ToActionRun(ctx, lastRun),
+ Run: convert.ToActionRun(ctx, run, doer),
+ LastRun: convert.ToActionRun(ctx, lastRun, doer),
PriorStatus: priorStatus.String(),
}
diff --git a/templates/admin/user/edit.tmpl b/templates/admin/user/edit.tmpl
index 7d004dd903..a1ff3d4117 100644
--- a/templates/admin/user/edit.tmpl
+++ b/templates/admin/user/edit.tmpl
@@ -208,6 +208,7 @@
{{RenderCommitBody $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}@@ -185,9 +194,16 @@ {{end}}