Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f48fda8eef | |||
| cd48a007bb | |||
| 6afbef5a8b | |||
| d745780014 | |||
| 652abf0ae0 | |||
| 1f804d35ca | |||
| c83a05f114 | |||
| a3c75ac438 | |||
| 14bc4d79c1 | |||
| 672d54fafa | |||
| 0495544b8a | |||
| 1fbc56d732 | |||
| 1a9ba1c65d | |||
| cbebcc1c26 | |||
| 0e677d7b41 | |||
| 790770aef3 | |||
| 43b4c38d4f | |||
| e79a10793f | |||
| be5411d6b5 | |||
| bdf3be53b0 | |||
| e50473e6bb | |||
| 20c135cd46 | |||
| 937ef6fa90 | |||
| 54d4e664c2 | |||
| c571ac6fd3 | |||
| f663773200 | |||
| a28677273b | |||
| c8d687997d | |||
| 5cb1037cb7 | |||
| 2dcea782c5 | |||
| 31842f12a4 | |||
| 32eef4aa2e | |||
| 449b39ea0e | |||
| 06f968d662 | |||
| 084797b4dc | |||
| 7888a55e8c | |||
| ea416d7d0e | |||
| 0db6add5c0 | |||
| 0ecbb71bee | |||
| ea38455e1f | |||
| 8fc80b34a0 | |||
| 71aa64ae25 | |||
| 3aba72c613 | |||
| bd1412c3af | |||
| 3973ce36d9 | |||
| fbde31fb1e | |||
| 2f0a1eb0d5 | |||
| e3697efbb0 | |||
| 989dd5502c | |||
| 54c0fe62cc | |||
| 2e2133d33f | |||
| 0d869c574e | |||
| 04105dbb7c | |||
| 0a0cd75071 | |||
| 85f829fb3c | |||
| 5ebd26d306 | |||
| bc7a4375be | |||
| fbcb42488f | |||
| 0230f1e1aa | |||
| 6779c351b1 | |||
| c1889f5b01 | |||
| c0754e9d19 | |||
| bf41958c16 | |||
| 033178f2fc | |||
| ebc8801fb2 | |||
| 37458bffbf | |||
| ec9b43ba16 | |||
| e6ec411491 | |||
| 17d3a474e0 | |||
| 9e8b1c6630 | |||
| eee51d8366 | |||
| c61ed6fad4 | |||
| b88a4b4854 | |||
| 399917a2d4 |
@@ -4,6 +4,86 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.17.3](https://github.com/go-gitea/gitea/releases/tag/v1.17.3) - 2022-10-15
|
||||
|
||||
* SECURITY
|
||||
* Sanitize and Escape refs in git backend (#21464) (#21463)
|
||||
* Bump `golang.org/x/text` (#21412) (#21413)
|
||||
* Update bluemonday (#21281) (#21287)
|
||||
* ENHANCEMENTS
|
||||
* Fix empty container layer history and UI (#21251) (#21278)
|
||||
* Use en-US as fallback when using other default language (#21200) (#21256)
|
||||
* Make the vscode clone link respect transport protocol (#20557) (#21128)
|
||||
* BUGFIXES
|
||||
* Do DB update after merge in hammer context (#21401) (#21416)
|
||||
* Add Num{Issues,Pulls} stats checks (#21404) (#21414)
|
||||
* Stop logging CheckPath returns error: context canceled (#21064) (#21405)
|
||||
* Parse OAuth Authorization header when request omits client secret (#21351) (#21374)
|
||||
* Ignore port for loopback redirect URIs (#21293) (#21373)
|
||||
* Set SemverCompatible to false for Conan packages (#21275) (#21366)
|
||||
* Tag list should include draft releases with existing tags (#21263) (#21365)
|
||||
* Fix linked account translation (#21331) (#21334)
|
||||
* Make NuGet service index publicly accessible (#21242) (#21277)
|
||||
* Foreign ID conflicts if ID is 0 for each item (#21271) (#21272)
|
||||
* Use absolute links in feeds (#21229) (#21265)
|
||||
* Prevent invalid behavior for file reviewing when loading more files (#21230) (#21234)
|
||||
* Respect `REQUIRE_SIGNIN_VIEW` for packages (#20873) (#21232)
|
||||
* Treat git object mode 40755 as directory (#21195) (#21218)
|
||||
* Allow uppercase ASCII alphabet in PyPI package names (#21095) (#21217)
|
||||
* Fix limited user cannot view himself's profile (#21212)
|
||||
* Fix template bug of admin monitor (#21209)
|
||||
* Fix reaction of issues (#21185) (#21196)
|
||||
* Fix CSV diff for added/deleted files (#21189) (#21193)
|
||||
* Fix pagination limit parameter problem (#21111)
|
||||
* TESTING
|
||||
* Fix missing m.Run() in TestMain (#21341)
|
||||
* BUILD
|
||||
* Use Go 1.19 fmt for Gitea 1.17, sync emoji data (#21239)
|
||||
|
||||
## [1.17.2](https://github.com/go-gitea/gitea/releases/tag/v1.17.2) - 2022-09-06
|
||||
|
||||
* SECURITY
|
||||
* Double check CloneURL is acceptable (#20869) (#20892)
|
||||
* Add more checks in migration code (#21011) (#21050)
|
||||
* ENHANCEMENTS
|
||||
* Fix hard-coded timeout and error panic in API archive download endpoint (#20925) (#21051)
|
||||
* Improve arc-green code theme (#21039) (#21042)
|
||||
* Enable contenthash in filename for dynamic assets (#20813) (#20932)
|
||||
* Don't open new page for ext wiki on same repository (#20725) (#20910)
|
||||
* Disable doctor logging on panic (#20847) (#20898)
|
||||
* Remove calls to load Mirrors in user.Dashboard (#20855) (#20897)
|
||||
* Update codemirror to 5.65.8 (#20875)
|
||||
* Rework repo buttons (#20602, #20718) (#20719)
|
||||
* BUGFIXES
|
||||
* Ensure delete user deletes all comments (#21067) (#21068)
|
||||
* Delete unreferenced packages when deleting a package version (#20977) (#21060)
|
||||
* Redirect if user does not exist on admin pages (#20981) (#21059)
|
||||
* Set uploadpack.allowFilter etc on gitea serv to enable partial clones with ssh (#20902) (#21058)
|
||||
* Fix 500 on time in timeline API (#21052) (#21057)
|
||||
* Fill the specified ref in webhook test payload (#20961) (#21055)
|
||||
* Add another index for Action table on postgres (#21033) (#21054)
|
||||
* Fix broken insecureskipverify handling in redis connection uris (#20967) (#21053)
|
||||
* Add Dev, Peer and Optional dependencies to npm PackageMetadataVersion (#21017) (#21044)
|
||||
* Do not add links to Posters or Assignees with ID < 0 (#20577) (#21037)
|
||||
* Fix modified due date message (#20388) (#21032)
|
||||
* Fix missed sort bug (#21006)
|
||||
* Fix input.value attr for RequiredClaimName/Value (#20946) (#21001)
|
||||
* Change review buttons to icons to make space for text (#20934) (#20978)
|
||||
* Fix download archiver of a commit (#20962) (#20971)
|
||||
* Return 404 NotFound if requested attachment does not exist (#20886) (#20941)
|
||||
* Set no-tags in git fetch on compare (#20893) (#20936)
|
||||
* Allow multiple metadata files for Maven packages (#20674) (#20916)
|
||||
* Increase Content field size of gpg_key and public_key to MEDIUMTEXT (#20896) (#20911)
|
||||
* Fix mirror address setting not working (#20850) (#20904)
|
||||
* Fix push mirror address backend get error Address cause setting page display error (#20593) (#20901)
|
||||
* Fix panic when an invalid oauth2 name is passed (#20820) (#20900)
|
||||
* In PushMirrorsIterate and MirrorsIterate if limit is negative do not set it (#20837) (#20899)
|
||||
* Ensure that graceful start-up is informed of unused SSH listener (#20877) (#20888)
|
||||
* Pad GPG Key ID with preceding zeroes (#20878) (#20885)
|
||||
* Fix SQL Query for `SearchTeam` (#20844) (#20872)
|
||||
* Fix the mode of custom dir to 0700 in docker-rootless (#20861) (#20867)
|
||||
* Fix UI mis-align for PR commit history (#20845) (#20859)
|
||||
|
||||
## [1.17.1](https://github.com/go-gitea/gitea/releases/tag/1.17.1) - 2022-08-17
|
||||
|
||||
* SECURITY
|
||||
|
||||
@@ -33,7 +33,7 @@ GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.0
|
||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.0
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
|
||||
DOCKER_IMAGE ?= gitea/gitea
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -214,8 +214,7 @@ const hdr = `
|
||||
|
||||
package emoji
|
||||
|
||||
// Code generated by gen.go. DO NOT EDIT.
|
||||
// Code generated by build/generate-emoji.go. DO NOT EDIT.
|
||||
// Sourced from %s
|
||||
//
|
||||
var GemojiData = %#v
|
||||
`
|
||||
|
||||
+43
-12
@@ -5,6 +5,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
golog "log"
|
||||
"os"
|
||||
@@ -123,6 +124,47 @@ func runRecreateTable(ctx *cli.Context) error {
|
||||
})
|
||||
}
|
||||
|
||||
func setDoctorLogger(ctx *cli.Context) {
|
||||
logFile := ctx.String("log-file")
|
||||
if !ctx.IsSet("log-file") {
|
||||
logFile = "doctor.log"
|
||||
}
|
||||
colorize := log.CanColorStdout
|
||||
if ctx.IsSet("color") {
|
||||
colorize = ctx.Bool("color")
|
||||
}
|
||||
|
||||
if len(logFile) == 0 {
|
||||
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
recovered := recover()
|
||||
if recovered == nil {
|
||||
return
|
||||
}
|
||||
|
||||
err, ok := recovered.(error)
|
||||
if !ok {
|
||||
panic(recovered)
|
||||
}
|
||||
if errors.Is(err, os.ErrPermission) {
|
||||
fmt.Fprintf(os.Stderr, "ERROR: Unable to write logs to provided file due to permissions error: %s\n %v\n", logFile, err)
|
||||
} else {
|
||||
fmt.Fprintf(os.Stderr, "ERROR: Unable to write logs to provided file: %s\n %v\n", logFile, err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "WARN: Logging will be disabled\n Use `--log-file` to configure log file location\n")
|
||||
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||
}()
|
||||
|
||||
if logFile == "-" {
|
||||
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"trace","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||
} else {
|
||||
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
|
||||
}
|
||||
}
|
||||
|
||||
func runDoctor(ctx *cli.Context) error {
|
||||
// Silence the default loggers
|
||||
log.DelNamedLogger("console")
|
||||
@@ -132,24 +174,13 @@ func runDoctor(ctx *cli.Context) error {
|
||||
defer cancel()
|
||||
|
||||
// Now setup our own
|
||||
logFile := ctx.String("log-file")
|
||||
if !ctx.IsSet("log-file") {
|
||||
logFile = "doctor.log"
|
||||
}
|
||||
setDoctorLogger(ctx)
|
||||
|
||||
colorize := log.CanColorStdout
|
||||
if ctx.IsSet("color") {
|
||||
colorize = ctx.Bool("color")
|
||||
}
|
||||
|
||||
if len(logFile) == 0 {
|
||||
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"NONE","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||
} else if logFile == "-" {
|
||||
log.NewLogger(1000, "doctor", "console", fmt.Sprintf(`{"level":"trace","stacktracelevel":"NONE","colorize":%t}`, colorize))
|
||||
} else {
|
||||
log.NewLogger(1000, "doctor", "file", fmt.Sprintf(`{"filename":%q,"level":"trace","stacktracelevel":"NONE"}`, logFile))
|
||||
}
|
||||
|
||||
// Finally redirect the default golog to here
|
||||
golog.SetFlags(0)
|
||||
golog.SetPrefix("")
|
||||
|
||||
@@ -112,11 +112,8 @@ func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) e
|
||||
|
||||
func migrateRepoArchivers(ctx context.Context, dstStorage storage.ObjectStorage) error {
|
||||
return db.IterateObjects(ctx, func(archiver *repo_model.RepoArchiver) error {
|
||||
p, err := archiver.RelativePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = storage.Copy(dstStorage, p, storage.RepoArchives, p)
|
||||
p := archiver.RelativePath()
|
||||
_, err := storage.Copy(dstStorage, p, storage.RepoArchives, p)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ mkdir -p ${HOME} && chmod 0700 ${HOME}
|
||||
if [ ! -w ${HOME} ]; then echo "${HOME} is not writable"; exit 1; fi
|
||||
|
||||
# Prepare custom folder
|
||||
mkdir -p ${GITEA_CUSTOM} && chmod 0500 ${GITEA_CUSTOM}
|
||||
mkdir -p ${GITEA_CUSTOM} && chmod 0700 ${GITEA_CUSTOM}
|
||||
|
||||
# Prepare temp folder
|
||||
mkdir -p ${GITEA_TEMP} && chmod 0700 ${GITEA_TEMP}
|
||||
|
||||
@@ -64,7 +64,7 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/mattn/go-sqlite3 v1.14.12
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.19
|
||||
github.com/microcosm-cc/bluemonday v1.0.20
|
||||
github.com/minio/minio-go/v7 v7.0.26
|
||||
github.com/msteinert/pam v1.0.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
@@ -91,11 +91,11 @@ require (
|
||||
go.jolheiser.com/hcaptcha v0.0.4
|
||||
go.jolheiser.com/pwn v0.0.3
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/tools v0.1.10
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
|
||||
golang.org/x/text v0.3.8
|
||||
golang.org/x/tools v0.1.12
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ini.v1 v1.66.4
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
@@ -271,9 +271,8 @@ require (
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.43.0 // indirect
|
||||
|
||||
@@ -1146,8 +1146,8 @@ github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo=
|
||||
github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
|
||||
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
|
||||
github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y=
|
||||
github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
@@ -1716,8 +1716,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1788,8 +1788,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
|
||||
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1824,8 +1824,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1936,8 +1936,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
@@ -1950,8 +1950,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -2045,16 +2046,14 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
|
||||
@@ -266,7 +266,7 @@ func TestPackageConan(t *testing.T) {
|
||||
|
||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, pd.SemVer)
|
||||
assert.Nil(t, pd.SemVer)
|
||||
assert.Equal(t, name, pd.Package.Name)
|
||||
assert.Equal(t, version1, pd.Version.Version)
|
||||
assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -79,6 +80,18 @@ func TestPackageGeneric(t *testing.T) {
|
||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||
})
|
||||
|
||||
t.Run("RequireSignInView", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
setting.Service.RequireSignInView = true
|
||||
defer func() {
|
||||
setting.Service.RequireSignInView = false
|
||||
}()
|
||||
|
||||
req := NewRequest(t, "GET", url)
|
||||
MakeRequest(t, req, http.StatusUnauthorized)
|
||||
})
|
||||
|
||||
t.Run("Delete", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ func TestPackageMaven(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated)
|
||||
putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest)
|
||||
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
|
||||
|
||||
pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven)
|
||||
@@ -135,12 +136,14 @@ func TestPackageMaven(t *testing.T) {
|
||||
pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, pfs, 2)
|
||||
i := 0
|
||||
if strings.HasSuffix(pfs[1].Name, ".pom") {
|
||||
i = 1
|
||||
for _, pf := range pfs {
|
||||
if strings.HasSuffix(pf.Name, ".pom") {
|
||||
assert.Equal(t, filename+".pom", pf.Name)
|
||||
assert.True(t, pf.IsLead)
|
||||
} else {
|
||||
assert.False(t, pf.IsLead)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, filename+".pom", pfs[i].Name)
|
||||
assert.True(t, pfs[i].IsLead)
|
||||
})
|
||||
|
||||
t.Run("DownloadPOM", func(t *testing.T) {
|
||||
@@ -202,4 +205,13 @@ func TestPackageMaven(t *testing.T) {
|
||||
assert.Equal(t, checksum, resp.Body.String())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("UploadSnapshot", func(t *testing.T) {
|
||||
snapshotVersion := packageVersion + "-SNAPSHOT"
|
||||
|
||||
putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated)
|
||||
putFile(t, "/maven-metadata.xml", "test", http.StatusOK)
|
||||
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated)
|
||||
putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/packages/nuget"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -65,39 +66,58 @@ func TestPackageNuGet(t *testing.T) {
|
||||
t.Run("ServiceIndex", func(t *testing.T) {
|
||||
defer PrintCurrentTest(t)()
|
||||
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusOK)
|
||||
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate}).(*user_model.User)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||
req = addNuGetAPIKeyHeader(req, token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
cases := []struct {
|
||||
Owner string
|
||||
UseBasicAuth bool
|
||||
UseTokenAuth bool
|
||||
}{
|
||||
{privateUser.Name, false, false},
|
||||
{privateUser.Name, true, false},
|
||||
{privateUser.Name, false, true},
|
||||
{user.Name, false, false},
|
||||
{user.Name, true, false},
|
||||
{user.Name, false, true},
|
||||
}
|
||||
|
||||
var result nuget.ServiceIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
for _, c := range cases {
|
||||
url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
|
||||
|
||||
assert.Equal(t, "3.0.0", result.Version)
|
||||
assert.NotEmpty(t, result.Resources)
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||
if c.UseBasicAuth {
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
} else if c.UseTokenAuth {
|
||||
req = addNuGetAPIKeyHeader(req, token)
|
||||
}
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
root := setting.AppURL + url[1:]
|
||||
for _, r := range result.Resources {
|
||||
switch r.Type {
|
||||
case "SearchQueryService":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-beta":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-rc":
|
||||
assert.Equal(t, root+"/query", r.ID)
|
||||
case "RegistrationsBaseUrl":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-beta":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-rc":
|
||||
assert.Equal(t, root+"/registration", r.ID)
|
||||
case "PackageBaseAddress/3.0.0":
|
||||
assert.Equal(t, root+"/package", r.ID)
|
||||
case "PackagePublish/2.0.0":
|
||||
assert.Equal(t, root, r.ID)
|
||||
var result nuget.ServiceIndexResponse
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Equal(t, "3.0.0", result.Version)
|
||||
assert.NotEmpty(t, result.Resources)
|
||||
|
||||
root := setting.AppURL + url[1:]
|
||||
for _, r := range result.Resources {
|
||||
switch r.Type {
|
||||
case "SearchQueryService":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-beta":
|
||||
fallthrough
|
||||
case "SearchQueryService/3.0.0-rc":
|
||||
assert.Equal(t, root+"/query", r.ID)
|
||||
case "RegistrationsBaseUrl":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-beta":
|
||||
fallthrough
|
||||
case "RegistrationsBaseUrl/3.0.0-rc":
|
||||
assert.Equal(t, root+"/registration", r.ID)
|
||||
case "PackageBaseAddress/3.0.0":
|
||||
assert.Equal(t, root+"/package", r.ID)
|
||||
case "PackagePublish/2.0.0":
|
||||
assert.Equal(t, root, r.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -223,7 +223,7 @@ func TestAPITeamSearch(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}).(*user_model.User)
|
||||
|
||||
var results TeamSearchResults
|
||||
|
||||
|
||||
@@ -26,8 +26,19 @@ func TestUserOrgs(t *testing.T) {
|
||||
orgs := getUserOrgs(t, adminUsername, normalUsername)
|
||||
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}).(*user_model.User)
|
||||
user17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user17"}).(*user_model.User)
|
||||
|
||||
assert.Equal(t, []*api.Organization{
|
||||
{
|
||||
ID: 17,
|
||||
UserName: user17.Name,
|
||||
FullName: user17.FullName,
|
||||
AvatarURL: user17.AvatarLink(),
|
||||
Description: "",
|
||||
Website: "",
|
||||
Location: "",
|
||||
Visibility: "public",
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
UserName: user3.Name,
|
||||
@@ -82,8 +93,19 @@ func TestMyOrgs(t *testing.T) {
|
||||
var orgs []*api.Organization
|
||||
DecodeJSON(t, resp, &orgs)
|
||||
user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}).(*user_model.User)
|
||||
user17 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user17"}).(*user_model.User)
|
||||
|
||||
assert.Equal(t, []*api.Organization{
|
||||
{
|
||||
ID: 17,
|
||||
UserName: user17.Name,
|
||||
FullName: user17.FullName,
|
||||
AvatarURL: user17.AvatarLink(),
|
||||
Description: "",
|
||||
Website: "",
|
||||
Location: "",
|
||||
Visibility: "public",
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
UserName: user3.Name,
|
||||
|
||||
@@ -179,8 +179,8 @@ func TestOrgRestrictedUser(t *testing.T) {
|
||||
func TestTeamSearch(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User)
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}).(*user_model.User)
|
||||
|
||||
var results TeamSearchResults
|
||||
|
||||
@@ -190,9 +190,9 @@ func TestTeamSearch(t *testing.T) {
|
||||
req.Header.Add("X-Csrf-Token", csrf)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
assert.Len(t, results.Data, 1)
|
||||
assert.Equal(t, "test_team", results.Data[0].Name)
|
||||
assert.Len(t, results.Data, 2)
|
||||
assert.Equal(t, "review_team", results.Data[0].Name)
|
||||
assert.Equal(t, "test_team", results.Data[1].Name)
|
||||
|
||||
// no access if not organization member
|
||||
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
export default {
|
||||
rootDir: 'web_src',
|
||||
setupFilesAfterEnv: ['jest-extended/all'],
|
||||
testEnvironment: '@happy-dom/jest-environment',
|
||||
testEnvironment: 'jest-environment-jsdom',
|
||||
testMatch: ['<rootDir>/**/*.test.js'],
|
||||
testTimeout: 20000,
|
||||
transform: {
|
||||
|
||||
+14
-2
@@ -98,7 +98,14 @@ func (a *Action) TableIndices() []*schemas.Index {
|
||||
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
|
||||
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
|
||||
|
||||
return []*schemas.Index{actUserIndex, repoIndex}
|
||||
indices := []*schemas.Index{actUserIndex, repoIndex}
|
||||
if setting.Database.UsePostgreSQL {
|
||||
cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
|
||||
cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
|
||||
indices = append(indices, cudIndex)
|
||||
}
|
||||
|
||||
return indices
|
||||
}
|
||||
|
||||
// GetOpType gets the ActionType of this action.
|
||||
@@ -211,6 +218,11 @@ func (a *Action) GetRepoLink() string {
|
||||
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
|
||||
}
|
||||
|
||||
// GetRepoAbsoluteLink returns the absolute link to action repository.
|
||||
func (a *Action) GetRepoAbsoluteLink() string {
|
||||
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
|
||||
}
|
||||
|
||||
// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings
|
||||
func GetRepositoryFromMatch(ownerName, repoName string) (*repo_model.Repository, error) {
|
||||
var err error
|
||||
@@ -275,7 +287,7 @@ func (a *Action) GetRefLink() string {
|
||||
return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix))
|
||||
case strings.HasPrefix(a.RefName, git.TagPrefix):
|
||||
return a.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.TagPrefix))
|
||||
case len(a.RefName) == 40 && git.SHAPattern.MatchString(a.RefName):
|
||||
case len(a.RefName) == 40 && git.IsValidSHAPattern(a.RefName):
|
||||
return a.GetRepoLink() + "/src/commit/" + a.RefName
|
||||
default:
|
||||
// FIXME: we will just assume it's a branch - this was the old way - at some point we may want to enforce that there is always a ref here.
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issue_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@@ -19,7 +20,7 @@ import (
|
||||
|
||||
func TestAction_GetRepoPath(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||
action := &Action{RepoID: repo.ID}
|
||||
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
|
||||
@@ -27,12 +28,15 @@ func TestAction_GetRepoPath(t *testing.T) {
|
||||
|
||||
func TestAction_GetRepoLink(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||
action := &Action{RepoID: repo.ID}
|
||||
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 2}).(*issue_model.Comment)
|
||||
action := &Action{RepoID: repo.ID, CommentID: comment.ID}
|
||||
setting.AppSubURL = "/suburl"
|
||||
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
||||
assert.Equal(t, expected, action.GetRepoLink())
|
||||
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
|
||||
assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
|
||||
}
|
||||
|
||||
func TestGetFeeds(t *testing.T) {
|
||||
|
||||
@@ -33,7 +33,7 @@ type GPGKey struct {
|
||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||
KeyID string `xorm:"INDEX CHAR(16) NOT NULL"`
|
||||
PrimaryKeyID string `xorm:"CHAR(16)"`
|
||||
Content string `xorm:"TEXT NOT NULL"`
|
||||
Content string `xorm:"MEDIUMTEXT NOT NULL"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||||
ExpiredUnix timeutil.TimeStamp
|
||||
AddedUnix timeutil.TimeStamp
|
||||
@@ -63,6 +63,15 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) {
|
||||
}
|
||||
}
|
||||
|
||||
// PaddedKeyID show KeyID padded to 16 characters
|
||||
func (key *GPGKey) PaddedKeyID() string {
|
||||
if len(key.KeyID) > 15 {
|
||||
return key.KeyID
|
||||
}
|
||||
zeros := "0000000000000000"
|
||||
return zeros[0:16-len(key.KeyID)] + key.KeyID
|
||||
}
|
||||
|
||||
// ListGPGKeys returns a list of public keys belongs to given user.
|
||||
func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([]*GPGKey, error) {
|
||||
sess := db.GetEngine(ctx).Table(&GPGKey{}).Where("owner_id=? AND primary_key_id=''", uid)
|
||||
|
||||
@@ -41,7 +41,7 @@ type PublicKey struct {
|
||||
OwnerID int64 `xorm:"INDEX NOT NULL"`
|
||||
Name string `xorm:"NOT NULL"`
|
||||
Fingerprint string `xorm:"INDEX NOT NULL"`
|
||||
Content string `xorm:"TEXT NOT NULL"`
|
||||
Content string `xorm:"MEDIUMTEXT NOT NULL"`
|
||||
Mode perm.AccessMode `xorm:"NOT NULL DEFAULT 2"`
|
||||
Type KeyType `xorm:"NOT NULL DEFAULT 1"`
|
||||
LoginSourceID int64 `xorm:"NOT NULL DEFAULT 0"`
|
||||
|
||||
+18
-1
@@ -10,6 +10,7 @@ import (
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
@@ -56,6 +57,18 @@ func (app *OAuth2Application) PrimaryRedirectURI() string {
|
||||
|
||||
// ContainsRedirectURI checks if redirectURI is allowed for app
|
||||
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
|
||||
uri, err := url.Parse(redirectURI)
|
||||
// ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
||||
if err == nil && uri.Scheme == "http" && uri.Port() != "" {
|
||||
ip := net.ParseIP(uri.Hostname())
|
||||
if ip != nil && ip.IsLoopback() {
|
||||
// strip port
|
||||
uri.Host = uri.Hostname()
|
||||
if util.IsStringInSlice(uri.String(), app.RedirectURIs, true) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return util.IsStringInSlice(redirectURI, app.RedirectURIs, true)
|
||||
}
|
||||
|
||||
@@ -512,10 +525,14 @@ func GetActiveOAuth2ProviderSources() ([]*Source, error) {
|
||||
func GetActiveOAuth2SourceByName(name string) (*Source, error) {
|
||||
authSource := new(Source)
|
||||
has, err := db.GetEngine(db.DefaultContext).Where("name = ? and type = ? and is_active = ?", name, OAuth2, true).Get(authSource)
|
||||
if !has || err != nil {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !has {
|
||||
return nil, fmt.Errorf("oauth2 source not found, name: %q", name)
|
||||
}
|
||||
|
||||
return authSource, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,26 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
|
||||
assert.False(t, app.ContainsRedirectURI("d"))
|
||||
}
|
||||
|
||||
func TestOAuth2Application_ContainsRedirectURI_WithPort(t *testing.T) {
|
||||
app := &OAuth2Application{
|
||||
RedirectURIs: []string{"http://127.0.0.1/", "http://::1/", "http://192.168.0.1/", "http://intranet/", "https://127.0.0.1/"},
|
||||
}
|
||||
|
||||
// http loopback uris should ignore port
|
||||
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
||||
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1:3456/"))
|
||||
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
|
||||
assert.True(t, app.ContainsRedirectURI("http://[::1]:3456/"))
|
||||
|
||||
// not http
|
||||
assert.False(t, app.ContainsRedirectURI("https://127.0.0.1:3456/"))
|
||||
// not loopback
|
||||
assert.False(t, app.ContainsRedirectURI("http://192.168.0.1:9954/"))
|
||||
assert.False(t, app.ContainsRedirectURI("http://intranet:3456/"))
|
||||
// unparseable
|
||||
assert.False(t, app.ContainsRedirectURI(":"))
|
||||
}
|
||||
|
||||
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application)
|
||||
|
||||
@@ -63,3 +63,9 @@
|
||||
uid: 29
|
||||
org_id: 17
|
||||
is_public: true
|
||||
|
||||
-
|
||||
id: 12
|
||||
uid: 2
|
||||
org_id: 17
|
||||
is_public: true
|
||||
|
||||
@@ -309,7 +309,7 @@
|
||||
avatar_email: user17@example.com
|
||||
num_repos: 2
|
||||
is_active: true
|
||||
num_members: 3
|
||||
num_members: 4
|
||||
num_teams: 3
|
||||
|
||||
-
|
||||
|
||||
@@ -68,6 +68,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
|
||||
issues, err := Issues(&IssuesOptions{
|
||||
ProjectBoardID: b.ID,
|
||||
ProjectID: b.ProjectID,
|
||||
SortType: "project-column-sorting",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -79,6 +80,7 @@ func LoadIssuesFromBoard(b *project_model.Board) (IssueList, error) {
|
||||
issues, err := Issues(&IssuesOptions{
|
||||
ProjectBoardID: -1, // Issues without ProjectBoardID
|
||||
ProjectID: b.ProjectID,
|
||||
SortType: "project-column-sorting",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -181,6 +181,10 @@ func createReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, erro
|
||||
Reaction: opts.Type,
|
||||
UserID: opts.DoerID,
|
||||
}
|
||||
if findOpts.CommentID == 0 {
|
||||
// explicit search of Issue Reactions where CommentID = 0
|
||||
findOpts.CommentID = -1
|
||||
}
|
||||
|
||||
existingR, _, err := FindReactions(ctx, findOpts)
|
||||
if err != nil {
|
||||
@@ -256,16 +260,23 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error {
|
||||
CommentID: opts.CommentID,
|
||||
}
|
||||
|
||||
_, err := db.GetEngine(ctx).Where("original_author_id = 0").Delete(reaction)
|
||||
sess := db.GetEngine(ctx).Where("original_author_id = 0")
|
||||
if opts.CommentID == -1 {
|
||||
reaction.CommentID = 0
|
||||
sess.MustCols("comment_id")
|
||||
}
|
||||
|
||||
_, err := sess.Delete(reaction)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteIssueReaction deletes a reaction on issue.
|
||||
func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
Type: content,
|
||||
DoerID: doerID,
|
||||
IssueID: issueID,
|
||||
CommentID: -1,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm"
|
||||
@@ -37,8 +38,14 @@ func (*improveActionTableIndicesAction) TableIndices() []*schemas.Index {
|
||||
|
||||
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
|
||||
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
|
||||
indices := []*schemas.Index{actUserIndex, repoIndex}
|
||||
if setting.Database.UsePostgreSQL {
|
||||
cudIndex := schemas.NewIndex("c_u_d", schemas.IndexType)
|
||||
cudIndex.AddColumn("created_unix", "user_id", "is_deleted")
|
||||
indices = append(indices, cudIndex)
|
||||
}
|
||||
|
||||
return []*schemas.Index{actUserIndex, repoIndex}
|
||||
return indices
|
||||
}
|
||||
|
||||
func improveActionTableIndices(x *xorm.Engine) error {
|
||||
|
||||
+25
-11
@@ -96,16 +96,7 @@ type SearchTeamOptions struct {
|
||||
IncludeDesc bool
|
||||
}
|
||||
|
||||
// SearchTeam search for teams. Caller is responsible to check permissions.
|
||||
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
|
||||
if opts.Page <= 0 {
|
||||
opts.Page = 1
|
||||
}
|
||||
if opts.PageSize == 0 {
|
||||
// Default limit
|
||||
opts.PageSize = 10
|
||||
}
|
||||
|
||||
func (opts *SearchTeamOptions) toCond() builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
|
||||
if len(opts.Keyword) > 0 {
|
||||
@@ -117,10 +108,28 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
|
||||
cond = cond.And(keywordCond)
|
||||
}
|
||||
|
||||
cond = cond.And(builder.Eq{"org_id": opts.OrgID})
|
||||
if opts.OrgID > 0 {
|
||||
cond = cond.And(builder.Eq{"`team`.org_id": opts.OrgID})
|
||||
}
|
||||
|
||||
if opts.UserID > 0 {
|
||||
cond = cond.And(builder.Eq{"team_user.uid": opts.UserID})
|
||||
}
|
||||
|
||||
return cond
|
||||
}
|
||||
|
||||
// SearchTeam search for teams. Caller is responsible to check permissions.
|
||||
func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
|
||||
sess := db.GetEngine(db.DefaultContext)
|
||||
|
||||
opts.SetDefaultValues()
|
||||
cond := opts.toCond()
|
||||
|
||||
if opts.UserID > 0 {
|
||||
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
|
||||
}
|
||||
|
||||
count, err := sess.
|
||||
Where(cond).
|
||||
Count(new(Team))
|
||||
@@ -128,6 +137,10 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if opts.UserID > 0 {
|
||||
sess = sess.Join("INNER", "team_user", "team_user.team_id = team.id")
|
||||
}
|
||||
|
||||
sess = sess.Where(cond)
|
||||
if opts.PageSize == -1 {
|
||||
opts.PageSize = int(count)
|
||||
@@ -137,6 +150,7 @@ func SearchTeam(opts *SearchTeamOptions) ([]*Team, int64, error) {
|
||||
|
||||
teams := make([]*Team, 0, opts.PageSize)
|
||||
if err = sess.
|
||||
Where(cond).
|
||||
OrderBy("lower_name").
|
||||
Find(&teams); err != nil {
|
||||
return nil, 0, err
|
||||
|
||||
@@ -214,9 +214,16 @@ func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
|
||||
Find(&ps)
|
||||
}
|
||||
|
||||
// HasOwnerPackages tests if a user/org has packages
|
||||
// HasOwnerPackages tests if a user/org has accessible packages
|
||||
func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
|
||||
return db.GetEngine(ctx).Where("owner_id = ?", ownerID).Exist(&Package{})
|
||||
return db.GetEngine(ctx).
|
||||
Table("package_version").
|
||||
Join("INNER", "package", "package.id = package_version.package_id").
|
||||
Where(builder.Eq{
|
||||
"package_version.is_internal": false,
|
||||
"package.owner_id": ownerID,
|
||||
}).
|
||||
Exist(&PackageVersion{})
|
||||
}
|
||||
|
||||
// HasRepositoryPackages tests if a repository has packages
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package packages_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
||||
_ "code.gitea.io/gitea/models"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
unittest.MainTest(m, &unittest.TestOptions{
|
||||
GiteaRootPath: filepath.Join("..", ".."),
|
||||
})
|
||||
}
|
||||
|
||||
func TestHasOwnerPackages(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User)
|
||||
|
||||
p, err := packages_model.TryInsertPackage(db.DefaultContext, &packages_model.Package{
|
||||
OwnerID: owner.ID,
|
||||
LowerName: "package",
|
||||
})
|
||||
assert.NotNil(t, p)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// A package without package versions gets automatically cleaned up and should return false
|
||||
has, err := packages_model.HasOwnerPackages(db.DefaultContext, owner.ID)
|
||||
assert.False(t, has)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pv, err := packages_model.GetOrInsertVersion(db.DefaultContext, &packages_model.PackageVersion{
|
||||
PackageID: p.ID,
|
||||
LowerVersion: "internal",
|
||||
IsInternal: true,
|
||||
})
|
||||
assert.NotNil(t, pv)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// A package with an internal package version gets automaticaly cleaned up and should return false
|
||||
has, err = packages_model.HasOwnerPackages(db.DefaultContext, owner.ID)
|
||||
assert.False(t, has)
|
||||
assert.NoError(t, err)
|
||||
|
||||
pv, err = packages_model.GetOrInsertVersion(db.DefaultContext, &packages_model.PackageVersion{
|
||||
PackageID: p.ID,
|
||||
LowerVersion: "normal",
|
||||
IsInternal: false,
|
||||
})
|
||||
assert.NotNil(t, pv)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// A package with a normal package version should return true
|
||||
has, err = packages_model.HasOwnerPackages(db.DefaultContext, owner.ID)
|
||||
assert.True(t, has)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -170,6 +170,7 @@ type FindReleasesOptions struct {
|
||||
IsPreRelease util.OptionalBool
|
||||
IsDraft util.OptionalBool
|
||||
TagNames []string
|
||||
HasSha1 util.OptionalBool // useful to find draft releases which are created with existing tags
|
||||
}
|
||||
|
||||
func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
||||
@@ -191,6 +192,13 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
||||
if !opts.IsDraft.IsNone() {
|
||||
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
|
||||
}
|
||||
if !opts.HasSha1.IsNone() {
|
||||
if opts.HasSha1.IsTrue() {
|
||||
cond = cond.And(builder.Neq{"sha1": ""})
|
||||
} else {
|
||||
cond = cond.And(builder.Eq{"sha1": ""})
|
||||
}
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
||||
|
||||
+14
-3
@@ -385,8 +385,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
|
||||
|
||||
archivePaths := make([]string, 0, len(archives))
|
||||
for _, v := range archives {
|
||||
p, _ := v.RelativePath()
|
||||
archivePaths = append(archivePaths, p)
|
||||
archivePaths = append(archivePaths, v.RelativePath())
|
||||
}
|
||||
|
||||
if _, err := db.DeleteByBean(ctx, &repo_model.RepoArchiver{RepoID: repoID}); err != nil {
|
||||
@@ -606,15 +605,27 @@ func CheckRepoStats(ctx context.Context) error {
|
||||
repoStatsCorrectNumStars,
|
||||
"repository count 'num_stars'",
|
||||
},
|
||||
// Repository.NumIssues
|
||||
{
|
||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, false),
|
||||
repoStatsCorrectNumIssues,
|
||||
"repository count 'num_issues'",
|
||||
},
|
||||
// Repository.NumClosedIssues
|
||||
{
|
||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false),
|
||||
repoStatsCorrectNumClosedIssues,
|
||||
"repository count 'num_closed_issues'",
|
||||
},
|
||||
// Repository.NumPulls
|
||||
{
|
||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, true),
|
||||
repoStatsCorrectNumPulls,
|
||||
"repository count 'num_pulls'",
|
||||
},
|
||||
// Repository.NumClosedPulls
|
||||
{
|
||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true),
|
||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true),
|
||||
repoStatsCorrectNumClosedPulls,
|
||||
"repository count 'num_closed_pulls'",
|
||||
},
|
||||
|
||||
@@ -39,9 +39,9 @@ func init() {
|
||||
db.RegisterModel(new(RepoArchiver))
|
||||
}
|
||||
|
||||
// RelativePath returns relative path
|
||||
func (archiver *RepoArchiver) RelativePath() (string, error) {
|
||||
return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String()), nil
|
||||
// RelativePath returns the archive path relative to the archive storage root.
|
||||
func (archiver *RepoArchiver) RelativePath() string {
|
||||
return fmt.Sprintf("%d/%s/%s.%s", archiver.RepoID, archiver.CommitID[:2], archiver.CommitID, archiver.Type.String())
|
||||
}
|
||||
|
||||
var delRepoArchiver = new(RepoArchiver)
|
||||
|
||||
+6
-57
@@ -8,7 +8,6 @@ package repo
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@@ -108,12 +107,14 @@ func DeleteMirrorByRepoID(repoID int64) error {
|
||||
|
||||
// MirrorsIterate iterates all mirror repositories.
|
||||
func MirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
|
||||
return db.GetEngine(db.DefaultContext).
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
Where("next_update_unix<=?", time.Now().Unix()).
|
||||
And("next_update_unix!=0").
|
||||
OrderBy("updated_unix ASC").
|
||||
Limit(limit).
|
||||
Iterate(new(Mirror), f)
|
||||
OrderBy("updated_unix ASC")
|
||||
if limit > 0 {
|
||||
sess = sess.Limit(limit)
|
||||
}
|
||||
return sess.Iterate(new(Mirror), f)
|
||||
}
|
||||
|
||||
// InsertMirror inserts a mirror to database
|
||||
@@ -121,55 +122,3 @@ func InsertMirror(ctx context.Context, mirror *Mirror) error {
|
||||
_, err := db.GetEngine(ctx).Insert(mirror)
|
||||
return err
|
||||
}
|
||||
|
||||
// MirrorRepositoryList contains the mirror repositories
|
||||
type MirrorRepositoryList []*Repository
|
||||
|
||||
func (repos MirrorRepositoryList) loadAttributes(ctx context.Context) error {
|
||||
if len(repos) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load mirrors.
|
||||
repoIDs := make([]int64, 0, len(repos))
|
||||
for i := range repos {
|
||||
if !repos[i].IsMirror {
|
||||
continue
|
||||
}
|
||||
|
||||
repoIDs = append(repoIDs, repos[i].ID)
|
||||
}
|
||||
mirrors := make([]*Mirror, 0, len(repoIDs))
|
||||
if err := db.GetEngine(ctx).
|
||||
Where("id > 0").
|
||||
In("repo_id", repoIDs).
|
||||
Find(&mirrors); err != nil {
|
||||
return fmt.Errorf("find mirrors: %v", err)
|
||||
}
|
||||
|
||||
set := make(map[int64]*Mirror)
|
||||
for i := range mirrors {
|
||||
set[mirrors[i].RepoID] = mirrors[i]
|
||||
}
|
||||
for i := range repos {
|
||||
repos[i].Mirror = set[repos[i].ID]
|
||||
if repos[i].Mirror != nil {
|
||||
repos[i].Mirror.Repo = repos[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAttributes loads the attributes for the given MirrorRepositoryList
|
||||
func (repos MirrorRepositoryList) LoadAttributes() error {
|
||||
return repos.loadAttributes(db.DefaultContext)
|
||||
}
|
||||
|
||||
// GetUserMirrorRepositories returns a list of mirror repositories of given user.
|
||||
func GetUserMirrorRepositories(userID int64) ([]*Repository, error) {
|
||||
repos := make([]*Repository, 0, 10)
|
||||
return repos, db.GetEngine(db.DefaultContext).
|
||||
Where("owner_id = ?", userID).
|
||||
And("is_mirror = ?", true).
|
||||
Find(&repos)
|
||||
}
|
||||
|
||||
@@ -95,10 +95,12 @@ func GetPushMirrorsByRepoID(repoID int64) ([]*PushMirror, error) {
|
||||
|
||||
// PushMirrorsIterate iterates all push-mirror repositories.
|
||||
func PushMirrorsIterate(limit int, f func(idx int, bean interface{}) error) error {
|
||||
return db.GetEngine(db.DefaultContext).
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
Where("last_update + (`interval` / ?) <= ?", time.Second, time.Now().Unix()).
|
||||
And("`interval` != 0").
|
||||
OrderBy("last_update ASC").
|
||||
Limit(limit).
|
||||
Iterate(new(PushMirror), f)
|
||||
OrderBy("last_update ASC")
|
||||
if limit > 0 {
|
||||
sess = sess.Limit(limit)
|
||||
}
|
||||
return sess.Iterate(new(PushMirror), f)
|
||||
}
|
||||
|
||||
+3
-3
@@ -100,9 +100,9 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||
|
||||
// Delete Comments
|
||||
const batchSize = 50
|
||||
for start := 0; ; start += batchSize {
|
||||
for {
|
||||
comments := make([]*issues_model.Comment, 0, batchSize)
|
||||
if err = e.Where("type=? AND poster_id=?", issues_model.CommentTypeComment, u.ID).Limit(batchSize, start).Find(&comments); err != nil {
|
||||
if err = e.Where("type=? AND poster_id=?", issues_model.CommentTypeComment, u.ID).Limit(batchSize, 0).Find(&comments); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(comments) == 0 {
|
||||
@@ -200,7 +200,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||
// ***** END: ExternalLoginUser *****
|
||||
|
||||
if _, err = e.ID(u.ID).Delete(new(user_model.User)); err != nil {
|
||||
return fmt.Errorf("Delete: %v", err)
|
||||
return fmt.Errorf("delete: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
+2
-2
@@ -1265,7 +1265,7 @@ func isUserVisibleToViewerCond(viewer *User) builder.Cond {
|
||||
|
||||
// IsUserVisibleToViewer check if viewer is able to see user profile
|
||||
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
||||
if viewer != nil && viewer.IsAdmin {
|
||||
if viewer != nil && (viewer.IsAdmin || viewer.ID == u.ID) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1304,7 +1304,7 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if count < 0 {
|
||||
if count == 0 {
|
||||
// No common organization
|
||||
return false
|
||||
}
|
||||
|
||||
+194
-193
@@ -36,20 +36,20 @@ func drawBlock(img *image.Paletted, x, y, size, angle int, points []int) {
|
||||
|
||||
// blank
|
||||
//
|
||||
// --------
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// --------
|
||||
// --------
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// --------
|
||||
func b0(img *image.Paletted, x, y, size, angle int) {}
|
||||
|
||||
// full-filled
|
||||
//
|
||||
// --------
|
||||
// |######|
|
||||
// |######|
|
||||
// |######|
|
||||
// --------
|
||||
// --------
|
||||
// |######|
|
||||
// |######|
|
||||
// |######|
|
||||
// --------
|
||||
func b1(img *image.Paletted, x, y, size, angle int) {
|
||||
for i := x; i < x+size; i++ {
|
||||
for j := y; j < y+size; j++ {
|
||||
@@ -59,12 +59,13 @@ func b1(img *image.Paletted, x, y, size, angle int) {
|
||||
}
|
||||
|
||||
// a small block
|
||||
// ----------
|
||||
// | |
|
||||
// | #### |
|
||||
// | #### |
|
||||
// | |
|
||||
// ----------
|
||||
//
|
||||
// ----------
|
||||
// | |
|
||||
// | #### |
|
||||
// | #### |
|
||||
// | |
|
||||
// ----------
|
||||
func b2(img *image.Paletted, x, y, size, angle int) {
|
||||
l := size / 4
|
||||
x += l
|
||||
@@ -79,15 +80,15 @@ func b2(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// diamond
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// | ##### |
|
||||
// | ### |
|
||||
// | # |
|
||||
// ---------
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// | ##### |
|
||||
// | ### |
|
||||
// | # |
|
||||
// ---------
|
||||
func b3(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, 0, []int{
|
||||
@@ -101,13 +102,13 @@ func b3(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b4
|
||||
//
|
||||
// -------
|
||||
// |#####|
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// |------
|
||||
// -------
|
||||
// |#####|
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// |------
|
||||
func b4(img *image.Paletted, x, y, size, angle int) {
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
0, 0,
|
||||
@@ -119,11 +120,11 @@ func b4(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b5
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
func b5(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -136,11 +137,11 @@ func b5(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b6
|
||||
//
|
||||
// --------
|
||||
// |### |
|
||||
// |### |
|
||||
// |### |
|
||||
// --------
|
||||
// --------
|
||||
// |### |
|
||||
// |### |
|
||||
// |### |
|
||||
// --------
|
||||
func b6(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -154,12 +155,12 @@ func b6(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b7 italic cone
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ## |
|
||||
// | #####|
|
||||
// | ####|
|
||||
// |--------
|
||||
// ---------
|
||||
// | # |
|
||||
// | ## |
|
||||
// | #####|
|
||||
// | ####|
|
||||
// |--------
|
||||
func b7(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -173,14 +174,14 @@ func b7(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b8 three small triangles
|
||||
//
|
||||
// -----------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// | # # |
|
||||
// | ### ### |
|
||||
// |#########|
|
||||
// -----------
|
||||
// -----------
|
||||
// | # |
|
||||
// | ### |
|
||||
// | ##### |
|
||||
// | # # |
|
||||
// | ### ### |
|
||||
// |#########|
|
||||
// -----------
|
||||
func b8(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
mm := m / 2
|
||||
@@ -212,13 +213,13 @@ func b8(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b9 italic triangle
|
||||
//
|
||||
// ---------
|
||||
// |# |
|
||||
// | #### |
|
||||
// | #####|
|
||||
// | #### |
|
||||
// | # |
|
||||
// ---------
|
||||
// ---------
|
||||
// |# |
|
||||
// | #### |
|
||||
// | #####|
|
||||
// | #### |
|
||||
// | # |
|
||||
// ---------
|
||||
func b9(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -231,16 +232,16 @@ func b9(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b10
|
||||
//
|
||||
// ----------
|
||||
// | ####|
|
||||
// | ### |
|
||||
// | ## |
|
||||
// | # |
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
// ----------
|
||||
// | ####|
|
||||
// | ### |
|
||||
// | ## |
|
||||
// | # |
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
func b10(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -260,13 +261,13 @@ func b10(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b11
|
||||
//
|
||||
// ----------
|
||||
// |#### |
|
||||
// |#### |
|
||||
// |#### |
|
||||
// | |
|
||||
// | |
|
||||
// ----------
|
||||
// ----------
|
||||
// |#### |
|
||||
// |#### |
|
||||
// |#### |
|
||||
// | |
|
||||
// | |
|
||||
// ----------
|
||||
func b11(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -280,13 +281,13 @@ func b11(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b12
|
||||
//
|
||||
// -----------
|
||||
// | |
|
||||
// | |
|
||||
// |#########|
|
||||
// | ##### |
|
||||
// | # |
|
||||
// -----------
|
||||
// -----------
|
||||
// | |
|
||||
// | |
|
||||
// |#########|
|
||||
// | ##### |
|
||||
// | # |
|
||||
// -----------
|
||||
func b12(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -299,13 +300,13 @@ func b12(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b13
|
||||
//
|
||||
// -----------
|
||||
// | |
|
||||
// | |
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#########|
|
||||
// -----------
|
||||
// -----------
|
||||
// | |
|
||||
// | |
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#########|
|
||||
// -----------
|
||||
func b13(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -318,13 +319,13 @@ func b13(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b14
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// |#### |
|
||||
// | |
|
||||
// | |
|
||||
// ---------
|
||||
// ---------
|
||||
// | # |
|
||||
// | ### |
|
||||
// |#### |
|
||||
// | |
|
||||
// | |
|
||||
// ---------
|
||||
func b14(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -337,13 +338,13 @@ func b14(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b15
|
||||
//
|
||||
// ----------
|
||||
// |##### |
|
||||
// |### |
|
||||
// |# |
|
||||
// | |
|
||||
// | |
|
||||
// ----------
|
||||
// ----------
|
||||
// |##### |
|
||||
// |### |
|
||||
// |# |
|
||||
// | |
|
||||
// | |
|
||||
// ----------
|
||||
func b15(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -356,14 +357,14 @@ func b15(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b16
|
||||
//
|
||||
// ---------
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// ---------
|
||||
// ---------
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// | # |
|
||||
// | ##### |
|
||||
// |#######|
|
||||
// ---------
|
||||
func b16(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
drawBlock(img, x, y, size, angle, []int{
|
||||
@@ -383,13 +384,13 @@ func b16(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b17
|
||||
//
|
||||
// ----------
|
||||
// |##### |
|
||||
// |### |
|
||||
// |# |
|
||||
// | ##|
|
||||
// | ##|
|
||||
// ----------
|
||||
// ----------
|
||||
// |##### |
|
||||
// |### |
|
||||
// |# |
|
||||
// | ##|
|
||||
// | ##|
|
||||
// ----------
|
||||
func b17(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
|
||||
@@ -412,13 +413,13 @@ func b17(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b18
|
||||
//
|
||||
// ----------
|
||||
// |##### |
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
// ----------
|
||||
// |##### |
|
||||
// |#### |
|
||||
// |### |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
func b18(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
|
||||
@@ -432,13 +433,13 @@ func b18(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b19
|
||||
//
|
||||
// ----------
|
||||
// |########|
|
||||
// |### ###|
|
||||
// |# #|
|
||||
// |### ###|
|
||||
// |########|
|
||||
// ----------
|
||||
// ----------
|
||||
// |########|
|
||||
// |### ###|
|
||||
// |# #|
|
||||
// |### ###|
|
||||
// |########|
|
||||
// ----------
|
||||
func b19(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
|
||||
@@ -473,13 +474,13 @@ func b19(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b20
|
||||
//
|
||||
// ----------
|
||||
// | ## |
|
||||
// |### |
|
||||
// |## |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
// ----------
|
||||
// | ## |
|
||||
// |### |
|
||||
// |## |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
func b20(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -494,13 +495,13 @@ func b20(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b21
|
||||
//
|
||||
// ----------
|
||||
// | #### |
|
||||
// |## #####|
|
||||
// |## ##|
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
// ----------
|
||||
// | #### |
|
||||
// |## #####|
|
||||
// |## ##|
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
func b21(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -522,13 +523,13 @@ func b21(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b22
|
||||
//
|
||||
// ----------
|
||||
// | #### |
|
||||
// |## ### |
|
||||
// |## ##|
|
||||
// |## ##|
|
||||
// |# #|
|
||||
// ----------
|
||||
// ----------
|
||||
// | #### |
|
||||
// |## ### |
|
||||
// |## ##|
|
||||
// |## ##|
|
||||
// |# #|
|
||||
// ----------
|
||||
func b22(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -550,13 +551,13 @@ func b22(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b23
|
||||
//
|
||||
// ----------
|
||||
// | #######|
|
||||
// |### #|
|
||||
// |## |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
// ----------
|
||||
// | #######|
|
||||
// |### #|
|
||||
// |## |
|
||||
// |## |
|
||||
// |# |
|
||||
// ----------
|
||||
func b23(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -578,13 +579,13 @@ func b23(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b24
|
||||
//
|
||||
// ----------
|
||||
// | ## ###|
|
||||
// |### ###|
|
||||
// |## ## |
|
||||
// |## ## |
|
||||
// |# # |
|
||||
// ----------
|
||||
// ----------
|
||||
// | ## ###|
|
||||
// |### ###|
|
||||
// |## ## |
|
||||
// |## ## |
|
||||
// |# # |
|
||||
// ----------
|
||||
func b24(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -606,13 +607,13 @@ func b24(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b25
|
||||
//
|
||||
// ----------
|
||||
// |# #|
|
||||
// |## ###|
|
||||
// |## ## |
|
||||
// |###### |
|
||||
// |#### |
|
||||
// ----------
|
||||
// ----------
|
||||
// |# #|
|
||||
// |## ###|
|
||||
// |## ## |
|
||||
// |###### |
|
||||
// |#### |
|
||||
// ----------
|
||||
func b25(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -634,13 +635,13 @@ func b25(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b26
|
||||
//
|
||||
// ----------
|
||||
// |# #|
|
||||
// |### ###|
|
||||
// | #### |
|
||||
// |### ###|
|
||||
// |# #|
|
||||
// ----------
|
||||
// ----------
|
||||
// |# #|
|
||||
// |### ###|
|
||||
// | #### |
|
||||
// |### ###|
|
||||
// |# #|
|
||||
// ----------
|
||||
func b26(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
@@ -676,13 +677,13 @@ func b26(img *image.Paletted, x, y, size, angle int) {
|
||||
|
||||
// b27
|
||||
//
|
||||
// ----------
|
||||
// |########|
|
||||
// |## ###|
|
||||
// |# #|
|
||||
// |### ##|
|
||||
// |########|
|
||||
// ----------
|
||||
// ----------
|
||||
// |########|
|
||||
// |## ###|
|
||||
// |# #|
|
||||
// |### ##|
|
||||
// |########|
|
||||
// ----------
|
||||
func b27(img *image.Paletted, x, y, size, angle int) {
|
||||
m := size / 2
|
||||
q := size / 4
|
||||
|
||||
+57
-41
@@ -13,6 +13,7 @@ import (
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
@@ -52,47 +53,11 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
|
||||
Owner: ctx.ContextUser,
|
||||
}
|
||||
|
||||
if ctx.Package.Owner.IsOrganization() {
|
||||
org := organization.OrgFromUser(ctx.Package.Owner)
|
||||
|
||||
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
||||
if ctx.Doer != nil {
|
||||
var err error
|
||||
ctx.Package.AccessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
|
||||
return
|
||||
}
|
||||
// If access mode is less than write check every team for more permissions
|
||||
if ctx.Package.AccessMode < perm.AccessModeWrite {
|
||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
||||
if err != nil {
|
||||
errCb(http.StatusInternalServerError, "GetUserOrgTeams", err)
|
||||
return
|
||||
}
|
||||
for _, t := range teams {
|
||||
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
|
||||
if ctx.Package.AccessMode < perm {
|
||||
ctx.Package.AccessMode = perm
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. If authorize level is none, check if org is visible to user
|
||||
if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
||||
ctx.Package.AccessMode = perm.AccessModeRead
|
||||
}
|
||||
} else {
|
||||
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
||||
// 1. Check if user is package owner
|
||||
if ctx.Doer.ID == ctx.Package.Owner.ID {
|
||||
ctx.Package.AccessMode = perm.AccessModeOwner
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
||||
ctx.Package.AccessMode = perm.AccessModeRead
|
||||
}
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
||||
ctx.Package.AccessMode = perm.AccessModeRead
|
||||
}
|
||||
var err error
|
||||
ctx.Package.AccessMode, err = determineAccessMode(ctx)
|
||||
if err != nil {
|
||||
errCb(http.StatusInternalServerError, "determineAccessMode", err)
|
||||
return
|
||||
}
|
||||
|
||||
packageType := ctx.Params("type")
|
||||
@@ -117,6 +82,57 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
|
||||
}
|
||||
}
|
||||
|
||||
func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
|
||||
accessMode := perm.AccessModeNone
|
||||
|
||||
if setting.Service.RequireSignInView && ctx.Doer == nil {
|
||||
return accessMode, nil
|
||||
}
|
||||
|
||||
if ctx.Package.Owner.IsOrganization() {
|
||||
org := organization.OrgFromUser(ctx.Package.Owner)
|
||||
|
||||
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
||||
if ctx.Doer != nil {
|
||||
var err error
|
||||
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
return accessMode, err
|
||||
}
|
||||
// If access mode is less than write check every team for more permissions
|
||||
if accessMode < perm.AccessModeWrite {
|
||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
||||
if err != nil {
|
||||
return accessMode, err
|
||||
}
|
||||
for _, t := range teams {
|
||||
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
|
||||
if accessMode < perm {
|
||||
accessMode = perm
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. If authorize level is none, check if org is visible to user
|
||||
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
} else {
|
||||
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
||||
// 1. Check if user is package owner
|
||||
if ctx.Doer.ID == ctx.Package.Owner.ID {
|
||||
accessMode = perm.AccessModeOwner
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
||||
accessMode = perm.AccessModeRead
|
||||
}
|
||||
}
|
||||
|
||||
return accessMode, nil
|
||||
}
|
||||
|
||||
// PackageContexter initializes a package context for a request.
|
||||
func PackageContexter() func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
|
||||
@@ -118,7 +118,7 @@ type CanCommitToBranchResults struct {
|
||||
}
|
||||
|
||||
// CanCommitToBranch returns true if repository is editable and user has proper access level
|
||||
// and branch is not protected for push
|
||||
// and branch is not protected for push
|
||||
func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
|
||||
protectedBranch, err := git_model.GetProtectedBranchBy(ctx, r.Repository.ID, r.BranchName)
|
||||
if err != nil {
|
||||
@@ -524,7 +524,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
}
|
||||
|
||||
ctx.Data["NumTags"], err = models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
|
||||
IncludeTags: true,
|
||||
IncludeDrafts: true,
|
||||
IncludeTags: true,
|
||||
HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("GetReleaseCountByRepoID", err)
|
||||
@@ -986,6 +988,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
|
||||
}
|
||||
|
||||
ctx.Data["BranchName"] = ctx.Repo.BranchName
|
||||
ctx.Data["RefName"] = ctx.Repo.RefName
|
||||
ctx.Data["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
|
||||
ctx.Data["TagName"] = ctx.Repo.TagName
|
||||
ctx.Data["CommitID"] = ctx.Repo.CommitID
|
||||
|
||||
@@ -101,6 +101,12 @@ func ToTimelineComment(c *issues_model.Comment, doer *user_model.User) *api.Time
|
||||
}
|
||||
|
||||
if c.Time != nil {
|
||||
err = c.Time.LoadAttributes()
|
||||
if err != nil {
|
||||
log.Error("Time.LoadAttributes: %v", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
comment.TrackedTime = ToTrackedTime(c.Time)
|
||||
}
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ func TestGuessDelimiter(t *testing.T) {
|
||||
},
|
||||
// case 3 - tab delimited
|
||||
{
|
||||
csv: "1 2",
|
||||
csv: "1\t2",
|
||||
expectedDelimiter: '\t',
|
||||
},
|
||||
// case 4 - pipe delimited
|
||||
|
||||
+334
-295
File diff suppressed because it is too large
Load Diff
+27
-1
@@ -40,6 +40,7 @@ type Command struct {
|
||||
parentContext context.Context
|
||||
desc string
|
||||
globalArgsLength int
|
||||
brokenArgs []string
|
||||
}
|
||||
|
||||
func (c *Command) String() string {
|
||||
@@ -50,6 +51,7 @@ func (c *Command) String() string {
|
||||
}
|
||||
|
||||
// NewCommand creates and returns a new Git Command based on given command and arguments.
|
||||
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||
func NewCommand(ctx context.Context, args ...string) *Command {
|
||||
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
|
||||
cargs := make([]string, len(globalCommandArgs))
|
||||
@@ -63,11 +65,13 @@ func NewCommand(ctx context.Context, args ...string) *Command {
|
||||
}
|
||||
|
||||
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
||||
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||
func NewCommandNoGlobals(args ...string) *Command {
|
||||
return NewCommandContextNoGlobals(DefaultContext, args...)
|
||||
}
|
||||
|
||||
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
||||
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
|
||||
return &Command{
|
||||
name: GitExecutable,
|
||||
@@ -89,12 +93,28 @@ func (c *Command) SetDescription(desc string) *Command {
|
||||
return c
|
||||
}
|
||||
|
||||
// AddArguments adds new argument(s) to the command.
|
||||
// AddArguments adds new argument(s) to the command. Each argument must be safe to be trusted.
|
||||
// User-provided arguments should be passed to AddDynamicArguments instead.
|
||||
func (c *Command) AddArguments(args ...string) *Command {
|
||||
c.args = append(c.args, args...)
|
||||
return c
|
||||
}
|
||||
|
||||
// AddDynamicArguments adds new dynamic argument(s) to the command.
|
||||
// The arguments may come from user input and can not be trusted, so no leading '-' is allowed to avoid passing options
|
||||
func (c *Command) AddDynamicArguments(args ...string) *Command {
|
||||
for _, arg := range args {
|
||||
if arg != "" && arg[0] == '-' {
|
||||
c.brokenArgs = append(c.brokenArgs, arg)
|
||||
}
|
||||
}
|
||||
if len(c.brokenArgs) != 0 {
|
||||
return c
|
||||
}
|
||||
c.args = append(c.args, args...)
|
||||
return c
|
||||
}
|
||||
|
||||
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
|
||||
type RunOpts struct {
|
||||
Env []string
|
||||
@@ -138,8 +158,14 @@ func CommonCmdServEnvs() []string {
|
||||
return commonBaseEnvs()
|
||||
}
|
||||
|
||||
var ErrBrokenCommand = errors.New("git command is broken")
|
||||
|
||||
// Run runs the command with the RunOpts
|
||||
func (c *Command) Run(opts *RunOpts) error {
|
||||
if len(c.brokenArgs) != 0 {
|
||||
log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
|
||||
return ErrBrokenCommand
|
||||
}
|
||||
if opts == nil {
|
||||
opts = &RunOpts{}
|
||||
}
|
||||
|
||||
@@ -26,4 +26,19 @@ func TestRunWithContextStd(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "exit status 129 - unknown option:")
|
||||
assert.Empty(t, stdout)
|
||||
}
|
||||
|
||||
cmd = NewCommand(context.Background())
|
||||
cmd.AddDynamicArguments("-test")
|
||||
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
|
||||
|
||||
cmd = NewCommand(context.Background())
|
||||
cmd.AddDynamicArguments("--test")
|
||||
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
|
||||
|
||||
subCmd := "version"
|
||||
cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production
|
||||
stdout, stderr, err = cmd.RunStdString(&RunOpts{})
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, stderr)
|
||||
assert.Contains(t, stdout, "git version")
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
|
||||
// CommitsCountFiles returns number of total commits of until given revision.
|
||||
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
|
||||
cmd := NewCommand(ctx, "rev-list", "--count")
|
||||
cmd.AddArguments(revision...)
|
||||
cmd.AddDynamicArguments(revision...)
|
||||
if len(relpath) > 0 {
|
||||
cmd.AddArguments("--")
|
||||
cmd.AddArguments(relpath...)
|
||||
|
||||
@@ -68,8 +68,7 @@ func NewParser(r io.Reader, format Format) *Parser {
|
||||
//
|
||||
// It could, for example return something like:
|
||||
//
|
||||
// { "objecttype": "tag", "refname:short": "v1.16.4", "object": "f460b7543ed500e49c133c2cd85c8c55ee9dbe27" }
|
||||
//
|
||||
// { "objecttype": "tag", "refname:short": "v1.16.4", "object": "f460b7543ed500e49c133c2cd85c8c55ee9dbe27" }
|
||||
func (p *Parser) Next() map[string]string {
|
||||
if !p.scanner.Scan() {
|
||||
return nil
|
||||
@@ -89,8 +88,7 @@ func (p *Parser) Err() error {
|
||||
|
||||
// parseRef parses out all key-value pairs from a single reference block, such as
|
||||
//
|
||||
// "objecttype tag\0refname:short v1.16.4\0object f460b7543ed500e49c133c2cd85c8c55ee9dbe27"
|
||||
//
|
||||
// "objecttype tag\0refname:short v1.16.4\0object f460b7543ed500e49c133c2cd85c8c55ee9dbe27"
|
||||
func (p *Parser) parseRef(refBlock string) (map[string]string, error) {
|
||||
if refBlock == "" {
|
||||
// must be at EOF
|
||||
|
||||
+14
-1
@@ -287,7 +287,20 @@ func syncGitConfig() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
// By default partial clones are disabled, enable them from git v2.22
|
||||
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
|
||||
if err = configSet("uploadpack.allowfilter", "true"); err != nil {
|
||||
return err
|
||||
}
|
||||
err = configSet("uploadpack.allowAnySHA1InWant", "true")
|
||||
} else {
|
||||
if err = configUnsetAll("uploadpack.allowfilter", "true"); err != nil {
|
||||
return err
|
||||
}
|
||||
err = configUnsetAll("uploadpack.allowAnySHA1InWant", "true")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// CheckGitVersionAtLeast check git version is at least the constraint version
|
||||
|
||||
@@ -44,7 +44,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
||||
case "160000":
|
||||
entry.entryMode = EntryModeCommit
|
||||
pos += 14 // skip over "160000 object "
|
||||
case "040000":
|
||||
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
|
||||
entry.entryMode = EntryModeTree
|
||||
pos += 12 // skip over "040000 tree "
|
||||
default:
|
||||
@@ -119,7 +119,7 @@ loop:
|
||||
entry.entryMode = EntryModeSymlink
|
||||
case "160000":
|
||||
entry.entryMode = EntryModeCommit
|
||||
case "40000":
|
||||
case "40000", "40755": // git uses 40000 for tree object, but some users may get 40755 for unknown reasons
|
||||
entry.entryMode = EntryModeTree
|
||||
default:
|
||||
log.Debug("Unknown mode: %v", string(mode))
|
||||
|
||||
+27
-1
@@ -4,7 +4,10 @@
|
||||
|
||||
package git
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// RemotePrefix is the base directory of the remotes information of git.
|
||||
@@ -15,6 +18,29 @@ const (
|
||||
pullLen = len(PullPrefix)
|
||||
)
|
||||
|
||||
// refNamePatternInvalid is regular expression with unallowed characters in git reference name
|
||||
// They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere.
|
||||
// They cannot have question-mark ?, asterisk *, or open bracket [ anywhere
|
||||
var refNamePatternInvalid = regexp.MustCompile(
|
||||
`[\000-\037\177 \\~^:?*[]|` + // No absolutely invalid characters
|
||||
`(?:^[/.])|` + // Not HasPrefix("/") or "."
|
||||
`(?:/\.)|` + // no "/."
|
||||
`(?:\.lock$)|(?:\.lock/)|` + // No ".lock/"" or ".lock" at the end
|
||||
`(?:\.\.)|` + // no ".." anywhere
|
||||
`(?://)|` + // no "//" anywhere
|
||||
`(?:@{)|` + // no "@{"
|
||||
`(?:[/.]$)|` + // no terminal '/' or '.'
|
||||
`(?:^@$)`) // Not "@"
|
||||
|
||||
// IsValidRefPattern ensures that the provided string could be a valid reference
|
||||
func IsValidRefPattern(name string) bool {
|
||||
return !refNamePatternInvalid.MatchString(name)
|
||||
}
|
||||
|
||||
func SanitizeRefPattern(name string) string {
|
||||
return refNamePatternInvalid.ReplaceAllString(name, "_")
|
||||
}
|
||||
|
||||
// Reference represents a Git ref.
|
||||
type Reference struct {
|
||||
Name string
|
||||
|
||||
@@ -191,8 +191,8 @@ func (c *CheckAttributeReader) Run() error {
|
||||
// CheckPath check attr for given path
|
||||
func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
log.Error("CheckPath returns error: %v", err)
|
||||
if err != nil && err != c.ctx.Err() {
|
||||
log.Error("Unexpected error when checking path %s in %s. Error: %v", path, c.Repo.Path, err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
|
||||
// add previous arguments except for --grep and --all
|
||||
hashCmd.AddArguments(args...)
|
||||
// add keyword as <commit>
|
||||
hashCmd.AddArguments(v)
|
||||
hashCmd.AddDynamicArguments(v)
|
||||
|
||||
// search with given constraints for commit matching sha hash of v
|
||||
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
|
||||
@@ -208,14 +208,15 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
|
||||
}()
|
||||
go func() {
|
||||
stderr := strings.Builder{}
|
||||
err := NewCommand(repo.Ctx, "log", revision, "--follow",
|
||||
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
|
||||
prettyLogFormat, "--", file).
|
||||
Run(&RunOpts{
|
||||
Dir: repo.Path,
|
||||
Stdout: stdoutWriter,
|
||||
Stderr: &stderr,
|
||||
})
|
||||
gitCmd := NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow",
|
||||
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page))
|
||||
gitCmd.AddDynamicArguments(revision)
|
||||
gitCmd.AddArguments("--", file)
|
||||
err := gitCmd.Run(&RunOpts{
|
||||
Dir: repo.Path,
|
||||
Stdout: stdoutWriter,
|
||||
Stderr: &stderr,
|
||||
})
|
||||
if err != nil {
|
||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
||||
} else {
|
||||
|
||||
@@ -138,7 +138,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
|
||||
|
||||
// ConvertToSHA1 returns a Hash object from a potential ID string
|
||||
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
|
||||
if len(commitID) == 40 && SHAPattern.MatchString(commitID) {
|
||||
if len(commitID) == 40 && IsValidSHAPattern(commitID) {
|
||||
sha1, err := NewIDFromString(commitID)
|
||||
if err == nil {
|
||||
return sha1, nil
|
||||
|
||||
@@ -40,7 +40,7 @@ func (repo *Repository) GetMergeBase(tmpRemote, base, head string) (string, stri
|
||||
if tmpRemote != "origin" {
|
||||
tmpBaseName := RemotePrefix + tmpRemote + "/tmp_" + base
|
||||
// Fetch commit into a temporary branch in order to be able to handle commits and tags
|
||||
_, _, err := NewCommand(repo.Ctx, "fetch", tmpRemote, base+":"+tmpBaseName).RunStdString(&RunOpts{Dir: repo.Path})
|
||||
_, _, err := NewCommand(repo.Ctx, "fetch", "--no-tags", tmpRemote, "--", base+":"+tmpBaseName).RunStdString(&RunOpts{Dir: repo.Path})
|
||||
if err == nil {
|
||||
base = tmpBaseName
|
||||
}
|
||||
|
||||
@@ -59,15 +59,15 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
||||
_ = stdoutWriter.Close()
|
||||
}()
|
||||
|
||||
args := []string{"log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since)}
|
||||
gitCmd := NewCommand(repo.Ctx, "log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since))
|
||||
if len(branch) == 0 {
|
||||
args = append(args, "--branches=*")
|
||||
gitCmd.AddArguments("--branches=*")
|
||||
} else {
|
||||
args = append(args, "--first-parent", branch)
|
||||
gitCmd.AddArguments("--first-parent").AddDynamicArguments(branch)
|
||||
}
|
||||
|
||||
stderr := new(strings.Builder)
|
||||
err = NewCommand(repo.Ctx, args...).Run(&RunOpts{
|
||||
err = gitCmd.Run(&RunOpts{
|
||||
Env: []string{},
|
||||
Dir: repo.Path,
|
||||
Stdout: stdoutWriter,
|
||||
|
||||
+6
-1
@@ -19,7 +19,12 @@ const EmptySHA = "0000000000000000000000000000000000000000"
|
||||
const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
|
||||
|
||||
// SHAPattern can be used to determine if a string is an valid sha
|
||||
var SHAPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
||||
var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
|
||||
|
||||
// IsValidSHAPattern will check if the provided string matches the SHA Pattern
|
||||
func IsValidSHAPattern(sha string) bool {
|
||||
return shaPattern.MatchString(sha)
|
||||
}
|
||||
|
||||
// MustID always creates a new SHA1 from a [20]byte array with no validation of input.
|
||||
func MustID(b []byte) SHA1 {
|
||||
|
||||
@@ -19,8 +19,10 @@ import (
|
||||
type Signature = object.Signature
|
||||
|
||||
// Helper to get a signature from the commit line, which looks like these:
|
||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||
//
|
||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||
//
|
||||
// but without the "author " at the beginning (this method should)
|
||||
// be used for author and committer.
|
||||
//
|
||||
|
||||
@@ -37,8 +37,10 @@ func (s *Signature) Decode(b []byte) {
|
||||
}
|
||||
|
||||
// Helper to get a signature from the commit line, which looks like these:
|
||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||
//
|
||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||
//
|
||||
// but without the "author " at the beginning (this method should)
|
||||
// be used for author and committer.
|
||||
func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||
|
||||
@@ -24,19 +24,17 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
|
||||
page = 1
|
||||
}
|
||||
|
||||
args := make([]string, 0, 12+len(branches)+len(files))
|
||||
|
||||
args = append(args, "--graph", "--date-order", "--decorate=full")
|
||||
graphCmd := git.NewCommand(r.Ctx, "log", "--graph", "--date-order", "--decorate=full")
|
||||
|
||||
if hidePRRefs {
|
||||
args = append(args, "--exclude="+git.PullPrefix+"*")
|
||||
graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*")
|
||||
}
|
||||
|
||||
if len(branches) == 0 {
|
||||
args = append(args, "--all")
|
||||
graphCmd.AddArguments("--all")
|
||||
}
|
||||
|
||||
args = append(args,
|
||||
graphCmd.AddArguments(
|
||||
"-C",
|
||||
"-M",
|
||||
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
|
||||
@@ -44,15 +42,12 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
|
||||
fmt.Sprintf("--pretty=format:%s", format))
|
||||
|
||||
if len(branches) > 0 {
|
||||
args = append(args, branches...)
|
||||
graphCmd.AddDynamicArguments(branches...)
|
||||
}
|
||||
args = append(args, "--")
|
||||
if len(files) > 0 {
|
||||
args = append(args, files...)
|
||||
graphCmd.AddArguments("--")
|
||||
graphCmd.AddArguments(files...)
|
||||
}
|
||||
|
||||
graphCmd := git.NewCommand(r.Ctx, "log")
|
||||
graphCmd.AddArguments(args...)
|
||||
graph := NewGraph()
|
||||
|
||||
stderr := new(strings.Builder)
|
||||
|
||||
@@ -114,9 +114,9 @@ func (g *Manager) start() {
|
||||
// Execute makes Manager implement svc.Handler
|
||||
func (g *Manager) Execute(args []string, changes <-chan svc.ChangeRequest, status chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
|
||||
if setting.StartupTimeout > 0 {
|
||||
status <- svc.Status{State: svc.StartPending}
|
||||
} else {
|
||||
status <- svc.Status{State: svc.StartPending, WaitHint: uint32(setting.StartupTimeout / time.Millisecond)}
|
||||
} else {
|
||||
status <- svc.Status{State: svc.StartPending}
|
||||
}
|
||||
|
||||
log.Trace("Awaiting server start-up")
|
||||
|
||||
@@ -93,6 +93,7 @@ func NewFileLogger() LoggerProvider {
|
||||
|
||||
// Init file logger with json config.
|
||||
// config like:
|
||||
//
|
||||
// {
|
||||
// "filename":"log/gogs.log",
|
||||
// "maxsize":1<<30,
|
||||
|
||||
@@ -33,7 +33,7 @@ func newLogger(name string, buffer int64) *MultiChannelledLogger {
|
||||
func (l *MultiChannelledLogger) SetLogger(name, provider, config string) error {
|
||||
eventLogger, err := NewChannelledLog(l.ctx, name, provider, config, l.bufferLength)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create sublogger (%s): %v", name, err)
|
||||
return fmt.Errorf("failed to create sublogger (%s): %w", name, err)
|
||||
}
|
||||
|
||||
l.MultiChannelledLog.DelLogger(name)
|
||||
@@ -41,9 +41,9 @@ func (l *MultiChannelledLogger) SetLogger(name, provider, config string) error {
|
||||
err = l.MultiChannelledLog.AddLogger(eventLogger)
|
||||
if err != nil {
|
||||
if IsErrDuplicateName(err) {
|
||||
return fmt.Errorf("Duplicate named sublogger %s %v", name, l.MultiChannelledLog.GetEventLoggerNames())
|
||||
return fmt.Errorf("%w other names: %v", err, l.MultiChannelledLog.GetEventLoggerNames())
|
||||
}
|
||||
return fmt.Errorf("Failed to add sublogger (%s): %v", name, err)
|
||||
return fmt.Errorf("failed to add sublogger (%s): %w", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -48,6 +48,7 @@ func NewSMTPLogger() LoggerProvider {
|
||||
|
||||
// Init smtp writer with json config.
|
||||
// config like:
|
||||
//
|
||||
// {
|
||||
// "Username":"example@gmail.com",
|
||||
// "password:"password",
|
||||
|
||||
@@ -7,6 +7,7 @@ package markup_test
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -32,6 +33,7 @@ func TestMain(m *testing.M) {
|
||||
if err := git.InitSimple(context.Background()); err != nil {
|
||||
log.Fatal("git init failed, err: %v", err)
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestRender_Commits(t *testing.T) {
|
||||
@@ -336,7 +338,7 @@ func TestRender_emoji(t *testing.T) {
|
||||
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
||||
test(
|
||||
"😎🤪🔐🤑❓",
|
||||
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="question mark">❓</span></p>`)
|
||||
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="red question mark">❓</span></p>`)
|
||||
|
||||
// should match nothing
|
||||
test(
|
||||
|
||||
@@ -6,6 +6,7 @@ package markdown_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -37,6 +38,7 @@ func TestMain(m *testing.M) {
|
||||
if err := git.InitSimple(context.Background()); err != nil {
|
||||
log.Fatal("git init failed, err: %v", err)
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func TestRender_StandardLinks(t *testing.T) {
|
||||
|
||||
@@ -141,7 +141,7 @@ func (r *stripRenderer) AddOptions(...renderer.Option) {
|
||||
}
|
||||
|
||||
// StripMarkdown parses markdown content by removing all markup and code blocks
|
||||
// in order to extract links and other references
|
||||
// in order to extract links and other references
|
||||
func StripMarkdown(rawBytes []byte) (string, []string) {
|
||||
buf, links := StripMarkdownBytes(rawBytes)
|
||||
return string(buf), links
|
||||
@@ -153,7 +153,7 @@ var (
|
||||
)
|
||||
|
||||
// StripMarkdownBytes parses markdown content by removing all markup and code blocks
|
||||
// in order to extract links and other references
|
||||
// in order to extract links and other references
|
||||
func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) {
|
||||
once.Do(func() {
|
||||
gdMarkdown := goldmark.New(
|
||||
|
||||
@@ -26,7 +26,7 @@ type PullRequest struct {
|
||||
Updated time.Time
|
||||
Closed *time.Time
|
||||
Labels []*Label
|
||||
PatchURL string `yaml:"patch_url"`
|
||||
PatchURL string `yaml:"patch_url"` // SECURITY: This must be safe to download directly from
|
||||
Merged bool
|
||||
MergedTime *time.Time `yaml:"merged_time"`
|
||||
MergeCommitSHA string `yaml:"merge_commit_sha"`
|
||||
@@ -37,6 +37,7 @@ type PullRequest struct {
|
||||
Reactions []*Reaction
|
||||
ForeignIndex int64
|
||||
Context DownloaderContext `yaml:"-"`
|
||||
EnsuredSafe bool `yaml:"ensured_safe"`
|
||||
}
|
||||
|
||||
func (p *PullRequest) GetLocalIndex() int64 { return p.Number }
|
||||
@@ -55,9 +56,9 @@ func (p PullRequest) GetGitRefName() string {
|
||||
|
||||
// PullRequestBranch represents a pull request branch
|
||||
type PullRequestBranch struct {
|
||||
CloneURL string `yaml:"clone_url"`
|
||||
Ref string
|
||||
SHA string
|
||||
CloneURL string `yaml:"clone_url"` // SECURITY: This must be safe to download from
|
||||
Ref string // SECURITY: this must be a git.IsValidRefPattern
|
||||
SHA string // SECURITY: this must be a git.IsValidSHAPattern
|
||||
RepoName string `yaml:"repo_name"`
|
||||
OwnerName string `yaml:"owner_name"`
|
||||
}
|
||||
|
||||
@@ -18,15 +18,16 @@ type ReleaseAsset struct {
|
||||
DownloadCount *int `yaml:"download_count"`
|
||||
Created time.Time
|
||||
Updated time.Time
|
||||
DownloadURL *string `yaml:"download_url"`
|
||||
|
||||
DownloadURL *string `yaml:"download_url"` // SECURITY: It is the responsibility of downloader to make sure this is safe
|
||||
// if DownloadURL is nil, the function should be invoked
|
||||
DownloadFunc func() (io.ReadCloser, error) `yaml:"-"`
|
||||
DownloadFunc func() (io.ReadCloser, error) `yaml:"-"` // SECURITY: It is the responsibility of downloader to make sure this is safe
|
||||
}
|
||||
|
||||
// Release represents a release
|
||||
type Release struct {
|
||||
TagName string `yaml:"tag_name"`
|
||||
TargetCommitish string `yaml:"target_commitish"`
|
||||
TagName string `yaml:"tag_name"` // SECURITY: This must pass git.IsValidRefPattern
|
||||
TargetCommitish string `yaml:"target_commitish"` // SECURITY: This must pass git.IsValidRefPattern
|
||||
Name string
|
||||
Body string
|
||||
Draft bool
|
||||
|
||||
@@ -12,7 +12,7 @@ type Repository struct {
|
||||
IsPrivate bool `yaml:"is_private"`
|
||||
IsMirror bool `yaml:"is_mirror"`
|
||||
Description string
|
||||
CloneURL string `yaml:"clone_url"`
|
||||
CloneURL string `yaml:"clone_url"` // SECURITY: This must be checked to ensure that is safe to be used
|
||||
OriginalURL string `yaml:"original_url"`
|
||||
DefaultBranch string
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ func getRedisTLSOptions(uri *url.URL) *tls.Config {
|
||||
|
||||
if len(skipverify) > 0 {
|
||||
skipverify, err := strconv.ParseBool(skipverify)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
tlsConfig.InsecureSkipVerify = skipverify
|
||||
}
|
||||
}
|
||||
@@ -254,7 +254,7 @@ func getRedisTLSOptions(uri *url.URL) *tls.Config {
|
||||
|
||||
if len(insecureskipverify) > 0 {
|
||||
insecureskipverify, err := strconv.ParseBool(insecureskipverify)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
tlsConfig.InsecureSkipVerify = insecureskipverify
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,24 @@ func TestRedisPasswordOpt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSkipVerifyOpt(t *testing.T) {
|
||||
uri, _ := url.Parse("rediss://myredis/0?skipverify=true")
|
||||
tlsConfig := getRedisTLSOptions(uri)
|
||||
|
||||
if !tlsConfig.InsecureSkipVerify {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestInsecureSkipVerifyOpt(t *testing.T) {
|
||||
uri, _ := url.Parse("rediss://myredis/0?insecureskipverify=true")
|
||||
tlsConfig := getRedisTLSOptions(uri)
|
||||
|
||||
if !tlsConfig.InsecureSkipVerify {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRedisSentinelUsernameOpt(t *testing.T) {
|
||||
uri, _ := url.Parse("redis+sentinel://redis:password@myredis/0?sentinelusername=suser&sentinelpassword=spass")
|
||||
opts := getRedisOptions(uri).Failover()
|
||||
|
||||
@@ -95,7 +95,9 @@ func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
|
||||
if i := strings.Index(cmd, "#(nop) "); i != -1 {
|
||||
cmd = strings.TrimSpace(cmd[i+7:])
|
||||
}
|
||||
imageLayers = append(imageLayers, cmd)
|
||||
if cmd != "" {
|
||||
imageLayers = append(imageLayers, cmd)
|
||||
}
|
||||
}
|
||||
|
||||
metadata := &Metadata{
|
||||
|
||||
@@ -25,7 +25,7 @@ func DumpMemProfileForUsername(pprofDataPath, username string) error {
|
||||
}
|
||||
|
||||
// DumpCPUProfileForUsername dumps a CPU profile at pprofDataPath as cpuprofile_<username>_<temporary id>
|
||||
// it returns the stop function which stops, writes and closes the CPU profile file
|
||||
// the stop function it returns stops, writes and closes the CPU profile file
|
||||
func DumpCPUProfileForUsername(pprofDataPath, username string) (func(), error) {
|
||||
f, err := os.CreateTemp(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username))
|
||||
if err != nil {
|
||||
|
||||
@@ -31,8 +31,8 @@ import (
|
||||
)
|
||||
|
||||
/*
|
||||
GitHub, GitLab, Gogs: *.wiki.git
|
||||
BitBucket: *.git/wiki
|
||||
GitHub, GitLab, Gogs: *.wiki.git
|
||||
BitBucket: *.git/wiki
|
||||
*/
|
||||
var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"}
|
||||
|
||||
|
||||
@@ -91,6 +91,8 @@ var (
|
||||
// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
|
||||
// It maps to ini:"LOCAL_ROOT_URL"
|
||||
LocalURL string
|
||||
// AssetVersion holds a opaque value that is used for cache-busting assets
|
||||
AssetVersion string
|
||||
|
||||
// Server settings
|
||||
Protocol Scheme
|
||||
@@ -749,6 +751,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||
}
|
||||
|
||||
AbsoluteAssetURL = MakeAbsoluteAssetURL(AppURL, StaticURLPrefix)
|
||||
AssetVersion = strings.ReplaceAll(AppVer, "+", "~") // make sure the version string is clear (no real escaping is needed)
|
||||
|
||||
manifestBytes := MakeManifestData(AppName, AppURL, AbsoluteAssetURL)
|
||||
ManifestData = `application/json;base64,` + base64.StdEncoding.EncodeToString(manifestBytes)
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
func Init() error {
|
||||
if setting.SSH.Disabled {
|
||||
builtinUnused()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,9 @@ func NewFuncMap() []template.FuncMap {
|
||||
"AppDomain": func() string {
|
||||
return setting.Domain
|
||||
},
|
||||
"AssetVersion": func() string {
|
||||
return setting.AssetVersion
|
||||
},
|
||||
"DisableGravatar": func() bool {
|
||||
return setting.DisableGravatar
|
||||
},
|
||||
@@ -454,6 +457,7 @@ func NewFuncMap() []template.FuncMap {
|
||||
}
|
||||
return items
|
||||
},
|
||||
"HasPrefix": strings.HasPrefix,
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -974,11 +978,11 @@ type remoteAddress struct {
|
||||
Password string
|
||||
}
|
||||
|
||||
func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress {
|
||||
func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress {
|
||||
a := remoteAddress{}
|
||||
|
||||
remoteURL := m.OriginalURL
|
||||
if remoteURL == "" {
|
||||
if ignoreOriginalURL || remoteURL == "" {
|
||||
var err error
|
||||
remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName)
|
||||
if err != nil {
|
||||
|
||||
@@ -54,6 +54,11 @@ func (ts TimeStamp) AsTime() (tm time.Time) {
|
||||
return ts.AsTimeInLocation(setting.DefaultUILocation)
|
||||
}
|
||||
|
||||
// AsLocalTime convert timestamp as time.Time in local location
|
||||
func (ts TimeStamp) AsLocalTime() time.Time {
|
||||
return time.Unix(int64(ts), 0)
|
||||
}
|
||||
|
||||
// AsTimeInLocation convert timestamp as time.Time in Local locale
|
||||
func (ts TimeStamp) AsTimeInLocation(loc *time.Location) (tm time.Time) {
|
||||
tm = time.Unix(int64(ts), 0).In(loc)
|
||||
|
||||
@@ -41,14 +41,14 @@ func NewLocaleStore() *LocaleStore {
|
||||
}
|
||||
|
||||
// AddLocaleByIni adds locale by ini into the store
|
||||
func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
|
||||
func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error {
|
||||
if _, ok := ls.localeMap[langName]; ok {
|
||||
return ErrLocaleAlreadyExist
|
||||
}
|
||||
iniFile, err := ini.LoadSources(ini.LoadOptions{
|
||||
IgnoreInlineComment: true,
|
||||
UnescapeValueCommentSymbols: true,
|
||||
}, localeFile, otherLocaleFiles...)
|
||||
}, source, moreSource)
|
||||
if err == nil {
|
||||
iniFile.BlockMode = false
|
||||
lc := &locale{store: ls, langName: langName, langDesc: langDesc, messages: iniFile}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Tr(t *testing.T) {
|
||||
func TestLocaleStore(t *testing.T) {
|
||||
testData1 := []byte(`
|
||||
.dot.name = Dot Name
|
||||
fmt = %[1]s %[2]s
|
||||
@@ -28,8 +28,8 @@ sub = Changed Sub String
|
||||
`)
|
||||
|
||||
ls := NewLocaleStore()
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1))
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2))
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, nil))
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil))
|
||||
ls.SetDefaultLang("lang1")
|
||||
|
||||
result := ls.Tr("lang1", "fmt", "a", "b")
|
||||
@@ -54,3 +54,21 @@ sub = Changed Sub String
|
||||
assert.Equal(t, []string{"lang1", "lang2"}, langs)
|
||||
assert.Equal(t, []string{"Lang1", "Lang2"}, descs)
|
||||
}
|
||||
|
||||
func TestLocaleStoreMoreSource(t *testing.T) {
|
||||
testData1 := []byte(`
|
||||
a=11
|
||||
b=12
|
||||
`)
|
||||
|
||||
testData2 := []byte(`
|
||||
b=21
|
||||
c=22
|
||||
`)
|
||||
|
||||
ls := NewLocaleStore()
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2))
|
||||
assert.Equal(t, "11", ls.Tr("lang1", "a"))
|
||||
assert.Equal(t, "21", ls.Tr("lang1", "b"))
|
||||
assert.Equal(t, "22", ls.Tr("lang1", "c"))
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ func InitLocales() {
|
||||
log.Fatal("Failed to list locale files: %v", err)
|
||||
}
|
||||
|
||||
localFiles := make(map[string][]byte, len(localeNames))
|
||||
localeData := make(map[string][]byte, len(localeNames))
|
||||
for _, name := range localeNames {
|
||||
localFiles[name], err = options.Locale(name)
|
||||
localeData[name], err = options.Locale(name)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load %s locale file. %v", name, err)
|
||||
}
|
||||
@@ -75,8 +75,16 @@ func InitLocales() {
|
||||
|
||||
matcher = language.NewMatcher(supportedTags)
|
||||
for i := range setting.Names {
|
||||
var localeDataBase []byte
|
||||
if i == 0 && setting.Langs[0] != "en-US" {
|
||||
// Only en-US has complete translations. When use other language as default, the en-US should still be used as fallback.
|
||||
localeDataBase = localeData["locale_en-US.ini"]
|
||||
if localeDataBase == nil {
|
||||
log.Fatal("Failed to load locale_en-US.ini file.")
|
||||
}
|
||||
}
|
||||
key := "locale_" + setting.Langs[i] + ".ini"
|
||||
if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
|
||||
if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localeDataBase, localeData[key]); err != nil {
|
||||
log.Error("Failed to set messages to %s: %v", setting.Langs[i], err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ func isSnakeCaseLowerOrNumber(c byte) bool {
|
||||
// ToSnakeCase convert the input string to snake_case format.
|
||||
//
|
||||
// Some samples.
|
||||
// "FirstName" => "first_name"
|
||||
// "HTTPServer" => "http_server"
|
||||
// "NoHTTPS" => "no_https"
|
||||
// "GO_PATH" => "go_path"
|
||||
// "GO PATH" => "go_path" // space is converted to underscore.
|
||||
// "GO-PATH" => "go_path" // hyphen is converted to underscore.
|
||||
//
|
||||
// "FirstName" => "first_name"
|
||||
// "HTTPServer" => "http_server"
|
||||
// "NoHTTPS" => "no_https"
|
||||
// "GO_PATH" => "go_path"
|
||||
// "GO PATH" => "go_path" // space is converted to underscore.
|
||||
// "GO-PATH" => "go_path" // hyphen is converted to underscore.
|
||||
func ToSnakeCase(input string) string {
|
||||
if len(input) == 0 {
|
||||
return ""
|
||||
|
||||
@@ -9,6 +9,8 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
|
||||
"gitea.com/go-chi/binding"
|
||||
"github.com/gobwas/glob"
|
||||
)
|
||||
@@ -24,30 +26,6 @@ const (
|
||||
ErrRegexPattern = "RegexPattern"
|
||||
)
|
||||
|
||||
// GitRefNamePatternInvalid is regular expression with unallowed characters in git reference name
|
||||
// They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere.
|
||||
// They cannot have question-mark ?, asterisk *, or open bracket [ anywhere
|
||||
var GitRefNamePatternInvalid = regexp.MustCompile(`[\000-\037\177 \\~^:?*[]+`)
|
||||
|
||||
// CheckGitRefAdditionalRulesValid check name is valid on additional rules
|
||||
func CheckGitRefAdditionalRulesValid(name string) bool {
|
||||
// Additional rules as described at https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
|
||||
if strings.HasPrefix(name, "/") || strings.HasSuffix(name, "/") ||
|
||||
strings.HasSuffix(name, ".") || strings.Contains(name, "..") ||
|
||||
strings.Contains(name, "//") || strings.Contains(name, "@{") ||
|
||||
name == "@" {
|
||||
return false
|
||||
}
|
||||
parts := strings.Split(name, "/")
|
||||
for _, part := range parts {
|
||||
if strings.HasSuffix(part, ".lock") || strings.HasPrefix(part, ".") {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// AddBindingRules adds additional binding rules
|
||||
func AddBindingRules() {
|
||||
addGitRefNameBindingRule()
|
||||
@@ -67,16 +45,10 @@ func addGitRefNameBindingRule() {
|
||||
IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
|
||||
str := fmt.Sprintf("%v", val)
|
||||
|
||||
if GitRefNamePatternInvalid.MatchString(str) {
|
||||
if !git.IsValidRefPattern(str) {
|
||||
errs.Add([]string{name}, ErrGitRefName, "GitRefName")
|
||||
return false, errs
|
||||
}
|
||||
|
||||
if !CheckGitRefAdditionalRulesValid(str) {
|
||||
errs.Add([]string{name}, ErrGitRefName, "GitRefName")
|
||||
return false, errs
|
||||
}
|
||||
|
||||
return true, errs
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1061,6 +1061,7 @@ normal_view=Normale Ansicht
|
||||
line=zeile
|
||||
lines=Zeilen
|
||||
|
||||
editor.add_file=Datei hinzufügen
|
||||
editor.new_file=Neue Datei
|
||||
editor.upload_file=Datei hochladen
|
||||
editor.edit_file=Datei bearbeiten
|
||||
|
||||
@@ -1061,6 +1061,7 @@ normal_view = Normal View
|
||||
line = line
|
||||
lines = lines
|
||||
|
||||
editor.add_file = Add File
|
||||
editor.new_file = New File
|
||||
editor.upload_file = Upload File
|
||||
editor.edit_file = Edit File
|
||||
@@ -1419,7 +1420,7 @@ issues.due_date_form_remove = "Remove"
|
||||
issues.due_date_not_writer = "You need repository write access to update an issue's due date."
|
||||
issues.due_date_not_set = "No due date set."
|
||||
issues.due_date_added = "added the due date %s %s"
|
||||
issues.due_date_modified = "modified the due date to %s from %s %s"
|
||||
issues.due_date_modified = "modified the due date from %[2]s to %[1]s %[3]s"
|
||||
issues.due_date_remove = "removed the due date %s %s"
|
||||
issues.due_date_overdue = "Overdue"
|
||||
issues.due_date_invalid = "The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'."
|
||||
|
||||
@@ -1061,6 +1061,7 @@ normal_view=Vista normal
|
||||
line=línea
|
||||
lines=líneas
|
||||
|
||||
editor.add_file=Añadir archivo
|
||||
editor.new_file=Nuevo Archivo
|
||||
editor.upload_file=Subir archivo
|
||||
editor.edit_file=Editar Archivo
|
||||
|
||||
@@ -820,6 +820,7 @@ normal_view=Vista normale
|
||||
line=riga
|
||||
lines=righe
|
||||
|
||||
editor.add_file=Aggiungi file
|
||||
editor.new_file=Nuovo file
|
||||
editor.upload_file=Carica File
|
||||
editor.edit_file=Modifica File
|
||||
|
||||
@@ -1061,6 +1061,7 @@ normal_view=Parastais skats
|
||||
line=rinda
|
||||
lines=rindas
|
||||
|
||||
editor.add_file=Pievienot
|
||||
editor.new_file=Jauna datne
|
||||
editor.upload_file=Augšupielādēt failu
|
||||
editor.edit_file=Labot failu
|
||||
|
||||
@@ -838,6 +838,7 @@ normal_view=Normale weergave
|
||||
line=regel
|
||||
lines=regels
|
||||
|
||||
editor.add_file=Bestand toevoegen
|
||||
editor.new_file=Nieuw bestand
|
||||
editor.upload_file=Upload bestand
|
||||
editor.edit_file=Bewerk bestand
|
||||
|
||||
@@ -1061,6 +1061,7 @@ normal_view=Vista normal
|
||||
line=linha
|
||||
lines=linhas
|
||||
|
||||
editor.add_file=Adicionar ficheiro
|
||||
editor.new_file=Novo ficheiro
|
||||
editor.upload_file=Carregar ficheiro
|
||||
editor.edit_file=Editar ficheiro
|
||||
|
||||
@@ -948,6 +948,7 @@ normal_view=Normal Görünüm
|
||||
line=satır
|
||||
lines=satır
|
||||
|
||||
editor.add_file=Dosya Ekle
|
||||
editor.new_file=Yeni dosya
|
||||
editor.upload_file=Dosya Yükle
|
||||
editor.edit_file=Dosyayı Düzenle
|
||||
@@ -1554,8 +1555,8 @@ activity.no_git_activity=Bu dönemde herhangi bir işleme yapılmamıştır.
|
||||
activity.git_stats_exclude_merges=Birleştirmeler hariç,
|
||||
activity.git_stats_author_1=%d yazar
|
||||
activity.git_stats_author_n=%d yazar
|
||||
activity.git_stats_pushed_1=
|
||||
activity.git_stats_pushed_n=
|
||||
activity.git_stats_pushed_1=
|
||||
activity.git_stats_pushed_n=
|
||||
activity.git_stats_commit_1=%d işlemeyi
|
||||
activity.git_stats_commit_n=%d işlemeyi
|
||||
activity.git_stats_push_to_branch=%s dalına ve
|
||||
@@ -2033,7 +2034,7 @@ branch.create_success='%s' dalı oluşturuldu.
|
||||
branch.branch_already_exists='%s' dalı zaten bu depoda var.
|
||||
branch.branch_name_conflict='%s' dal adı zaten mevcut olan '%s' dalıyla çakışıyor.
|
||||
branch.tag_collision='%s' dalı, depoda aynı ada sahip bir etiket olduğundan oluşturulamıyor.
|
||||
branch.deleted_by=%s tarafından silindi
|
||||
branch.deleted_by=%s tarafından silindi
|
||||
branch.restore_success='%s' dalı geri yüklendi.
|
||||
branch.restore_failed='%s' dalı geri yüklenemedi.
|
||||
branch.protected_deletion_failed='%s' dalı korunuyor. Silinemez.
|
||||
|
||||
@@ -695,8 +695,8 @@ last_used=上次使用在
|
||||
no_activity=没有最近活动
|
||||
can_read_info=读取
|
||||
can_write_info=写入
|
||||
key_state_desc=7 天内使用过该密钥
|
||||
token_state_desc=7 天内使用过该密钥
|
||||
key_state_desc=7 天内使用过该密钥
|
||||
token_state_desc=7 天内使用过该密钥
|
||||
principal_state_desc=7 天内使用过该规则
|
||||
show_openid=在个人信息上显示
|
||||
hide_openid=在个人信息上隐藏
|
||||
@@ -880,7 +880,7 @@ watchers=关注者
|
||||
stargazers=称赞者
|
||||
forks=派生仓库
|
||||
pick_reaction=选择你的表情
|
||||
reactions_more=再加载 %d
|
||||
reactions_more=再加载 %d
|
||||
unit_disabled=站点管理员已禁用此仓库单元。
|
||||
language_other=其它
|
||||
adopt_search=输入用户名以搜索未被收录的仓库... (留空以查找全部)
|
||||
@@ -1061,6 +1061,7 @@ normal_view=普通视图
|
||||
line=行
|
||||
lines=行
|
||||
|
||||
editor.add_file=添加文件
|
||||
editor.new_file=新建文件
|
||||
editor.upload_file=上传文件
|
||||
editor.edit_file=编辑文件
|
||||
@@ -1419,7 +1420,7 @@ issues.due_date_form_remove=删除
|
||||
issues.due_date_not_writer=你需要仓库写入权限来修改工单到期时间。
|
||||
issues.due_date_not_set=未设置到期时间。
|
||||
issues.due_date_added=于 %[2]s 设置到期时间为 %[1]s
|
||||
issues.due_date_modified=于 %[3]s 将到期时间从 %[2]s 修改为 %[1]s
|
||||
issues.due_date_modified=于 %[3]s 将到期时间从 %[2]s 修改为 %[1]s
|
||||
issues.due_date_remove=于 %[2]s 删除了到期时间 %[1]s
|
||||
issues.due_date_overdue=过期
|
||||
issues.due_date_invalid=到期日期无效或超出范围。请使用 'yyyy-mm-dd' 格式。
|
||||
@@ -3042,7 +3043,7 @@ filter.type.all=所有
|
||||
filter.no_result=您的过滤器没有产生任何结果。
|
||||
filter.container.tagged=已加标签
|
||||
filter.container.untagged=未加标签
|
||||
published_by=于 %[1]s 发布了 <a href="%[2]s">%[3]s</a>
|
||||
published_by=于 %[1]s 发布了 <a href="%[2]s">%[3]s</a>
|
||||
published_by_in=<a href="%[2]s">%[3]s</a> 于 %[1]s 发布了 <a href="%[4]s"><strong>%[5]s</strong></a>
|
||||
installation=安装
|
||||
about=关于这个软件包
|
||||
|
||||
@@ -1061,6 +1061,7 @@ normal_view=標準檢視
|
||||
line=行
|
||||
lines=行
|
||||
|
||||
editor.add_file=加入檔案
|
||||
editor.new_file=新增文件
|
||||
editor.upload_file=上傳文件
|
||||
editor.edit_file=編輯文件
|
||||
|
||||
Generated
+970
-3018
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -44,7 +44,6 @@
|
||||
"wrap-ansi": "8.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@happy-dom/jest-environment": "4.0.1",
|
||||
"eslint": "8.15.0",
|
||||
"eslint-plugin-html": "6.2.0",
|
||||
"eslint-plugin-import": "2.26.0",
|
||||
@@ -52,6 +51,7 @@
|
||||
"eslint-plugin-unicorn": "42.0.0",
|
||||
"eslint-plugin-vue": "9.0.1",
|
||||
"jest": "28.1.0",
|
||||
"jest-environment-jsdom": "28.1.3",
|
||||
"jest-extended": "2.0.0",
|
||||
"postcss-less": "6.0.0",
|
||||
"stylelint": "14.8.2",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 16 16" class="svg gitea-join" width="16" height="16" aria-hidden="true"><path d="M14 10.9V8.75h1.25a.75.75 0 0 0 0-1.5H14V5.1a.25.25 0 0 0-.43-.17l-2.9 2.9a.25.25 0 0 0 0 .35l2.9 2.9a.25.25 0 0 0 .43-.18ZM.75 8.75a.75.75 0 0 1 0-1.5H2V5.1a.25.25 0 0 1 .43-.17l2.9 2.9a.25.25 0 0 1 0 .35l-2.9 2.9A.25.25 0 0 1 2 10.9V8.75Zm6.5-6.5a.75.75 0 0 0 1.5 0v-.5a.75.75 0 0 0-1.5 0zM8 6a.75.75 0 0 1-.75-.75v-.5a.75.75 0 0 1 1.5 0v.5A.75.75 0 0 1 8 6Zm-.75 2.25a.75.75 0 0 0 1.5 0v-.5a.75.75 0 0 0-1.5 0zM8 12a.75.75 0 0 1-.75-.75v-.5a.75.75 0 0 1 1.5 0v.5A.75.75 0 0 1 8 12Zm-.75 2.25a.75.75 0 0 0 1.5 0v-.5a.75.75 0 0 0-1.5 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 645 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 16 16" class="svg gitea-split" width="16" height="16" aria-hidden="true"><path d="M7.25 14.25a.75.75 0 0 0 1.5 0v-.5a.75.75 0 0 0-1.5 0zM8 12a.75.75 0 0 1-.75-.75v-.5a.75.75 0 0 1 1.5 0v.5A.75.75 0 0 1 8 12Zm-.75-3.75a.75.75 0 0 0 1.5 0v-.5a.75.75 0 0 0-1.5 0zM8 6a.75.75 0 0 1-.75-.75v-.5a.75.75 0 0 1 1.5 0v.5A.75.75 0 0 1 8 6Zm-.75-3.75a.75.75 0 0 0 1.5 0v-.5a.75.75 0 0 0-1.5 0zm4.1 6.5a.75.75 0 0 1 0-1.5h1.25V5.1a.25.25 0 0 1 .43-.17l2.9 2.9a.25.25 0 0 1 0 .35l-2.9 2.9a.25.25 0 0 1-.43-.18V8.75ZM3.4 10.9V8.75h1.25a.75.75 0 0 0 0-1.5H3.4V5.1a.25.25 0 0 0-.43-.17l-2.9 2.9a.25.25 0 0 0 0 .35l2.9 2.9a.25.25 0 0 0 .43-.18z"/></svg>
|
||||
|
After Width: | Height: | Size: 654 B |
@@ -0,0 +1 @@
|
||||
<svg viewBox="0 0 15 15" class="svg gitea-whitespace" width="16" height="16" aria-hidden="true"><path d="m2.5 7.5.35.35a.5.5 0 0 0 0-.7l-.35.35ZM3 4h12V3H3v1Zm4 4h8V7H7v1Zm-4 4h12v-1H3v1ZM.85 9.85l2-2-.7-.7-2 2 .7.7Zm2-2.7-2-2-.7.7 2 2 .7-.7Z"/></svg>
|
||||
|
After Width: | Height: | Size: 251 B |
+25
-23
@@ -66,7 +66,7 @@ func Routes() *web.Route {
|
||||
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
|
||||
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
|
||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/conan", func() {
|
||||
r.Group("/v1", func() {
|
||||
r.Get("/ping", conan.Ping)
|
||||
@@ -154,7 +154,7 @@ func Routes() *web.Route {
|
||||
}, conan.ExtractPathParameters)
|
||||
})
|
||||
})
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/generic", func() {
|
||||
r.Group("/{packagename}/{packageversion}/{filename}", func() {
|
||||
r.Get("", generic.DownloadPackageFile)
|
||||
@@ -163,33 +163,35 @@ func Routes() *web.Route {
|
||||
r.Delete("", generic.DeletePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
})
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/helm", func() {
|
||||
r.Get("/index.yaml", helm.Index)
|
||||
r.Get("/{filename}", helm.DownloadPackageFile)
|
||||
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/maven", func() {
|
||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
||||
r.Get("/*", maven.DownloadPackageFile)
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/nuget", func() {
|
||||
r.Get("/index.json", nuget.ServiceIndex)
|
||||
r.Get("/query", nuget.SearchService)
|
||||
r.Group("/registration/{id}", func() {
|
||||
r.Get("/index.json", nuget.RegistrationIndex)
|
||||
r.Get("/{version}", nuget.RegistrationLeaf)
|
||||
})
|
||||
r.Group("/package/{id}", func() {
|
||||
r.Get("/index.json", nuget.EnumeratePackageVersions)
|
||||
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
||||
})
|
||||
r.Get("/index.json", nuget.ServiceIndex) // Needs to be unauthenticated for the NuGet client.
|
||||
r.Group("", func() {
|
||||
r.Put("/", nuget.UploadPackage)
|
||||
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
||||
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
|
||||
r.Get("/query", nuget.SearchService)
|
||||
r.Group("/registration/{id}", func() {
|
||||
r.Get("/index.json", nuget.RegistrationIndex)
|
||||
r.Get("/{version}", nuget.RegistrationLeaf)
|
||||
})
|
||||
r.Group("/package/{id}", func() {
|
||||
r.Get("/index.json", nuget.EnumeratePackageVersions)
|
||||
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
||||
})
|
||||
r.Group("", func() {
|
||||
r.Put("/", nuget.UploadPackage)
|
||||
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
||||
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
})
|
||||
r.Group("/npm", func() {
|
||||
r.Group("/@{scope}/{id}", func() {
|
||||
@@ -216,12 +218,12 @@ func Routes() *web.Route {
|
||||
r.Delete("", npm.DeletePackageTag)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
})
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/pypi", func() {
|
||||
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
|
||||
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
|
||||
r.Get("/simple/{id}", pypi.PackageMetadata)
|
||||
})
|
||||
}, reqPackageAccess(perm.AccessModeRead))
|
||||
r.Group("/rubygems", func() {
|
||||
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
|
||||
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
|
||||
@@ -233,7 +235,7 @@ func Routes() *web.Route {
|
||||
r.Delete("/yank", rubygems.DeletePackage)
|
||||
}, reqPackageAccess(perm.AccessModeWrite))
|
||||
})
|
||||
}, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
||||
}, context_service.UserAssignmentWeb(), context.PackageAssignment())
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user