Compare commits

..

2 Commits

Author SHA1 Message Date
Lasse Brandt Thomsen
0fe32826ed Allow read/write to user root and only read to group git on documentation (#15041)
Co-authored-by: Lasse Brandt Thomsen <lasse@bitmand.dk>
2021-03-20 00:45:04 +01:00
Lunny Xiao
cf549500e0 Fix bug when upload on web (#15042)
* Fix bug when upload on web

* move into own function

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2021-03-19 23:49:29 +01:00
288 changed files with 4562 additions and 7316 deletions

View File

@@ -4,46 +4,14 @@ 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 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). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.14.1](https://github.com/go-gitea/gitea/releases/tag/v1.14.1) - 2021-04-15 ## [1.14.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-03-19
* BUGFIXES
* Fix bug clone wiki (#15499) (#15502)
* Github Migration ignore rate limit, if not enabled (#15490) (#15495)
* Use subdir for URL (#15446) (#15493)
* Query the DB for the hash before inserting in to email_hash (#15457) (#15491)
* Ensure review dismissal only dismisses the correct review (#15477) (#15489)
* Use index of the supported tags to choose user lang (#15452) (#15488)
* Fix wrong file link in code search page (#15466) (#15486)
* Quick template fix for built-in SSH server in admin config (#15464) (#15481)
* Prevent superfluous response.WriteHeader (#15456) (#15476)
* Fix ambiguous argument error on tags (#15432) (#15474)
* Add created_unix instead of expiry to migration (#15458) (#15463)
* Fix repository search (#15428) (#15442)
* Prevent NPE on avatar direct rendering if federated avatars disabled (#15434) (#15439)
* Fix wiki clone urls (#15430) (#15431)
* Fix dingtalk icon url at webhook (#15417) (#15426)
* Standardise icon on projects PR page (#15387) (#15408)
* ENHANCEMENTS
* Add option to skip LFS/attachment files for `dump` (#15407) (#15492)
* Clone panel fixes (#15436)
* Use semantic dropdown for code search query type (#15276) (#15364)
* BUILD
* Build go-git variants for windows (#15482) (#15487)
* Lock down build-images dependencies (Partial #15479) (#15480)
* MISC
* Performance improvement for list pull requests (#15447) (#15500)
* Fix potential copy lfs records failure when fork a repository (#15441) (#15485)
## [1.14.0](https://github.com/go-gitea/gitea/releases/tag/v1.14.0) - 2021-04-11
* SECURITY * SECURITY
* Respect approved email domain list for externally validated user registration (#15014) * Respect approved email domain list for externally validated user registration (#15014)
* Add reverse proxy configuration support for remote IP address detection (#14959) * Add reverse proxy configuration support for remote IP address detection (#14959)
* Ensure validation occurs on clone addresses too (#14994) * Ensure validation occurs on clone addresses too (#14994)
* Fix several render issues highlighted during fuzzing (#14986)
* BREAKING * BREAKING
* Fix double 'push tag' action feed (#15078) (#15083)
* Remove possible resource leak (#15067) (#15082)
* Handle unauthorized user events gracefully (#15071) (#15074)
* Restore Access.log following migration to Chi framework (Stops access logging of /api/internal routes) (#14475) * Restore Access.log following migration to Chi framework (Stops access logging of /api/internal routes) (#14475)
* Migrate from Macaron to Chi framework (#14293) * Migrate from Macaron to Chi framework (#14293)
* Deprecate building for mips (#14174) * Deprecate building for mips (#14174)
@@ -74,7 +42,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Dump github/gitlab/gitea repository data to a local directory and restore to gitea (#12244) * Dump github/gitlab/gitea repository data to a local directory and restore to gitea (#12244)
* Create Rootless Docker image (#10154) * Create Rootless Docker image (#10154)
* API * API
* Speedup issue search (#15179) (#15192)
* Get pull, return head branch sha, even if deleted (#14931) * Get pull, return head branch sha, even if deleted (#14931)
* Export LFS & TimeTracking function status (#14753) * Export LFS & TimeTracking function status (#14753)
* Show Gitea version in swagger (#14654) * Show Gitea version in swagger (#14654)
@@ -99,20 +66,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Add more filters to issues search (#13514) * Add more filters to issues search (#13514)
* Add review request api (#11355) * Add review request api (#11355)
* BUGFIXES * BUGFIXES
* Fix delete nonexist oauth application 500 and prevent deadlock (#15384) (#15396)
* Always set the merge base used to merge the commit (#15352) (#15385)
* Upgrade to bluemonday 1.0.7 (#15379) (#15380)
* Turn RepoRef and RepoAssignment back into func(*Context) (#15372) (#15377)
* Move FCGI req.URL.Path fix-up to the FCGI listener (#15292) (#15361)
* Show diff on rename with diff changes (#15338) (#15339)
* Fix handling of logout event (#15323) (#15337)
* Fix CanCreateRepo check (#15311) (#15321)
* Fix xorm log stack level (#15285) (#15316)
* Fix bug in Wrap (#15302) (#15309)
* Drop the event source if we are unauthorized (#15275) (#15280)
* Backport Fix graph pagination (#15225) (#15249)
* Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15200)
* should run RetrieveRepoMetas() for empty pr (#15187) (#15190)
* Move setting to enable closing issue via commit in non default branch to repo settings (#14965) * Move setting to enable closing issue via commit in non default branch to repo settings (#14965)
* Show correct issues for team dashboard (#14952) * Show correct issues for team dashboard (#14952)
* Ensure that new pull request button works on forked forks owned by owner of the root and reduce ambiguity (#14932) * Ensure that new pull request button works on forked forks owned by owner of the root and reduce ambiguity (#14932)
@@ -169,9 +122,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Use GO variable in go-check target (#13146) (#13147) * Use GO variable in go-check target (#13146) (#13147)
* ENHANCEMENTS * ENHANCEMENTS
* UI style improvements * UI style improvements
* Dropzone styling improvements (#15291) (#15374)
* Add size to Save function (#15264) (#15270)
* Monaco improvements (#15333) (#15345)
* Support .mailmap in code activity stats (#15009) * Support .mailmap in code activity stats (#15009)
* Sort release attachments by name (#15008) * Sort release attachments by name (#15008)
* Add ui.explore settings to control view of explore pages (#14094) * Add ui.explore settings to control view of explore pages (#14094)
@@ -317,52 +267,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Reduce make verbosity (#13803) * Reduce make verbosity (#13803)
* Add git command error directory on log (#13194) * Add git command error directory on log (#13194)
## [1.13.7](https://github.com/go-gitea/gitea/releases/tag/v1.13.7) - 2021-04-07
* SECURITY
* Update to bluemonday-1.0.6 (#15294) (#15298)
* Clusterfuzz found another way (#15160) (#15169)
* API
* Fix wrong user returned in API (#15139) (#15150)
* BUGFIXES
* Add 'fonts' into 'KnownPublicEntries' (#15188) (#15317)
* Speed up `enry.IsVendor` (#15213) (#15246)
* Response 404 for diff/patch of a commit that not exist (#15221) (#15238)
* Prevent NPE in CommentMustAsDiff if no hunk header (#15199) (#15201)
* MISC
* Add size to Save function (#15264) (#15271)
## [1.13.6](https://github.com/go-gitea/gitea/releases/tag/v1.13.6) - 2021-03-23
* SECURITY
* Fix bug on avatar middleware (#15124) (#15125)
* Fix another clusterfuzz identified issue (#15096) (#15114)
* API
* Fix nil pointer exception in get pull reviews API (#15106)
* BUGFIXES
* Fix markdown rendering in milestone content (#15056) (#15092)
## [1.13.5](https://github.com/go-gitea/gitea/releases/tag/v1.13.5) - 2021-03-21
* SECURITY
* Update to goldmark 1.3.3 (#15059) (#15061)
* Another clusterfuzz spotted issue (#15032) (#15034)
* API
* Fix set milestone on PR creation (#14981) (#15001)
* Prevent panic when editing forked repos by API (#14960) (#14963)
* BUGFIXES
* Fix bug when upload on web (#15042) (#15055)
* Delete Labels & IssueLabels on Repo Delete too (#15039) (#15051)
* Fix postgres ID sequences broken by recreate-table (#15015) (#15029)
* Fix several render issues (#14986) (#15013)
* Make sure sibling images get a link too (#14979) (#14995)
* Fix Anchor jumping with escaped query components (#14969) (#14977)
* Fix release mail html template (#14976)
* Fix excluding more than two labels on issues list (#14962) (#14973)
* Don't mark each comment poster as OP (#14971) (#14972)
* Add "captcha" to list of reserved usernames (#14930)
* Re-enable import local paths after reversion from #13610 (#14925) (#14927)
## [1.13.4](https://github.com/go-gitea/gitea/releases/tag/v1.13.4) - 2021-03-07 ## [1.13.4](https://github.com/go-gitea/gitea/releases/tag/v1.13.4) - 2021-03-07
* SECURITY * SECURITY

View File

@@ -577,9 +577,6 @@ release-windows: | $(DIST_DIRS)
$(GO) install src.techknowlogick.com/xgo@latest; \ $(GO) install src.techknowlogick.com/xgo@latest; \
fi fi
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) . CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
ifeq (,$(findstring gogit,$(TAGS)))
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
endif
ifeq ($(CI),drone) ifeq ($(CI),drone)
cp /build/* $(DIST)/binaries cp /build/* $(DIST)/binaries
endif endif
@@ -702,8 +699,8 @@ generate-gitignore:
GO111MODULE=on $(GO) run build/generate-gitignores.go GO111MODULE=on $(GO) run build/generate-gitignores.go
.PHONY: generate-images .PHONY: generate-images
generate-images: | node_modules generate-images:
npm install --no-save --no-package-lock fabric@4 imagemin-zopfli@7 npm install --no-save --no-package-lock fabric imagemin-zopfli
node build/generate-images.js $(TAGS) node build/generate-images.js $(TAGS)
.PHONY: generate-manpage .PHONY: generate-manpage

View File

@@ -129,14 +129,6 @@ It can be used for backup and capture Gitea server image to send to maintainer`,
Name: "skip-custom-dir", Name: "skip-custom-dir",
Usage: "Skip custom directory", Usage: "Skip custom directory",
}, },
cli.BoolFlag{
Name: "skip-lfs-data",
Usage: "Skip LFS data",
},
cli.BoolFlag{
Name: "skip-attachment-data",
Usage: "Skip attachment data",
},
cli.GenericFlag{ cli.GenericFlag{
Name: "type", Name: "type",
Value: outputTypeEnum, Value: outputTypeEnum,
@@ -222,9 +214,7 @@ func runDump(ctx *cli.Context) error {
fatal("Failed to include repositories: %v", err) fatal("Failed to include repositories: %v", err)
} }
if ctx.IsSet("skip-lfs-data") && ctx.Bool("skip-lfs-data") { if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
log.Info("Skip dumping LFS data")
} else if err := storage.LFS.IterateObjects(func(objPath string, object storage.Object) error {
info, err := object.Stat() info, err := object.Stat()
if err != nil { if err != nil {
return err return err
@@ -323,9 +313,7 @@ func runDump(ctx *cli.Context) error {
} }
} }
if ctx.IsSet("skip-attachment-data") && ctx.Bool("skip-attachment-data") { if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
log.Info("Skip dumping attachment data")
} else if err := storage.Attachments.IterateObjects(func(objPath string, object storage.Object) error {
info, err := object.Stat() info, err := object.Stat()
if err != nil { if err != nil {
return err return err

View File

@@ -9,11 +9,9 @@ import (
"net" "net"
"net/http" "net/http"
"net/http/fcgi" "net/http/fcgi"
"strings"
"code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
) )
func runHTTP(network, listenAddr, name string, m http.Handler) error { func runHTTP(network, listenAddr, name string, m http.Handler) error {
@@ -50,12 +48,7 @@ func runFCGI(network, listenAddr, name string, m http.Handler) error {
fcgiServer := graceful.NewServer(network, listenAddr, name) fcgiServer := graceful.NewServer(network, listenAddr, name)
err := fcgiServer.ListenAndServe(func(listener net.Listener) error { err := fcgiServer.ListenAndServe(func(listener net.Listener) error {
return fcgi.Serve(listener, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { return fcgi.Serve(listener, m)
if setting.AppSubURL != "" {
req.URL.Path = strings.TrimPrefix(req.URL.Path, setting.AppSubURL)
}
m.ServeHTTP(resp, req)
}))
}) })
if err != nil { if err != nil {
log.Fatal("Failed to start FCGI main server: %v", err) log.Fatal("Failed to start FCGI main server: %v", err)

View File

@@ -79,7 +79,7 @@ chmod 770 /etc/gitea
chmod 750 /etc/gitea chmod 750 /etc/gitea
chmod 640 /etc/gitea/app.ini chmod 640 /etc/gitea/app.ini
``` ```
If you don't want the web installer to be able to write the config file at all, it is also possible to make the config file read-only for the gitea user (owner/group `root:root`, mode `0660`), and set `INSTALL_LOCK = true`. In that case all database configuration details must be set beforehand in the config file, as well as the `SECRET_KEY` and `INTERNAL_TOKEN` values. See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret INTERNAL_TOKEN`. If you don't want the web installer to be able to write the config file at all, it is also possible to make the config file read-only for the gitea user (owner/group `root:git`, mode `0640`), and set `INSTALL_LOCK = true`. In that case all database configuration details must be set beforehand in the config file, as well as the `SECRET_KEY` and `INTERNAL_TOKEN` values. See the [command line documentation]({{< relref "doc/usage/command-line.en-us.md" >}}) for information on using `gitea generate secret INTERNAL_TOKEN`.
### Configure Gitea's working directory ### Configure Gitea's working directory

12
go.mod
View File

@@ -5,7 +5,7 @@ go 1.14
require ( require (
cloud.google.com/go v0.78.0 // indirect cloud.google.com/go v0.78.0 // indirect
code.gitea.io/gitea-vet v0.2.1 code.gitea.io/gitea-vet v0.2.1
code.gitea.io/sdk/gitea v0.14.0 code.gitea.io/sdk/gitea v0.13.2
gitea.com/go-chi/binding v0.0.0-20210301195521-1fe1c9a555e7 gitea.com/go-chi/binding v0.0.0-20210301195521-1fe1c9a555e7
gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e
gitea.com/go-chi/captcha v0.0.0-20210110083842-e7696c336a1e gitea.com/go-chi/captcha v0.0.0-20210110083842-e7696c336a1e
@@ -86,7 +86,7 @@ require (
github.com/mgechev/revive v1.0.3 github.com/mgechev/revive v1.0.3
github.com/mholt/acmez v0.1.3 // indirect github.com/mholt/acmez v0.1.3 // indirect
github.com/mholt/archiver/v3 v3.5.0 github.com/mholt/archiver/v3 v3.5.0
github.com/microcosm-cc/bluemonday v1.0.7 github.com/microcosm-cc/bluemonday v1.0.4
github.com/miekg/dns v1.1.40 // indirect github.com/miekg/dns v1.1.40 // indirect
github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.10 github.com/minio/minio-go/v7 v7.0.10
@@ -128,7 +128,7 @@ require (
github.com/xanzy/go-gitlab v0.44.0 github.com/xanzy/go-gitlab v0.44.0
github.com/xanzy/ssh-agent v0.3.0 // indirect github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/yohcop/openid-go v1.0.0 github.com/yohcop/openid-go v1.0.0
github.com/yuin/goldmark v1.3.3 github.com/yuin/goldmark v1.3.2
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691
github.com/yuin/goldmark-meta v1.0.0 github.com/yuin/goldmark-meta v1.0.0
go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/hcaptcha v0.0.4
@@ -136,9 +136,9 @@ require (
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.16.0 // indirect go.uber.org/zap v1.16.0 // indirect
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46
golang.org/x/text v0.3.5 golang.org/x/text v0.3.5
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
golang.org/x/tools v0.1.0 golang.org/x/tools v0.1.0
@@ -153,3 +153,5 @@ require (
) )
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4 replace github.com/hashicorp/go-version => github.com/6543/go-version v1.2.4
replace github.com/microcosm-cc/bluemonday => github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8

23
go.sum
View File

@@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s= code.gitea.io/gitea-vet v0.2.1 h1:b30by7+3SkmiftK0RjuXqFvZg2q4p68uoPGuxhzBN0s=
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
code.gitea.io/sdk/gitea v0.14.0 h1:m4J352I3p9+bmJUfS+g0odeQzBY/5OXP91Gv6D4fnJ0= code.gitea.io/sdk/gitea v0.13.2 h1:wAnT/J7Z62q3fJXbgnecoaOBh8CM1Qq0/DakWxiv4yA=
code.gitea.io/sdk/gitea v0.14.0/go.mod h1:89WiyOX1KEcvjP66sRHdu0RafojGo60bT9UqW17VbWs= code.gitea.io/sdk/gitea v0.13.2/go.mod h1:lee2y8LeV3kQb2iK+hHlMqoadL4bp27QOkOV/hawLKg=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
gitea.com/go-chi/binding v0.0.0-20210301195521-1fe1c9a555e7 h1:xCVJPY823C8RWpgMabTw2kOglDrg0iS3GcQU6wdwHkU= gitea.com/go-chi/binding v0.0.0-20210301195521-1fe1c9a555e7 h1:xCVJPY823C8RWpgMabTw2kOglDrg0iS3GcQU6wdwHkU=
gitea.com/go-chi/binding v0.0.0-20210301195521-1fe1c9a555e7/go.mod h1:AyfTrwtfYN54R/HmVvMYPnSTenH5bVoyh8x6tBluxEA= gitea.com/go-chi/binding v0.0.0-20210301195521-1fe1c9a555e7/go.mod h1:AyfTrwtfYN54R/HmVvMYPnSTenH5bVoyh8x6tBluxEA=
@@ -196,6 +196,8 @@ github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chi-middleware/proxy v1.1.1 h1:4HaXUp8o2+bhHr1OhVy+VjN0+L7/07JDcn6v7YrTjrQ= github.com/chi-middleware/proxy v1.1.1 h1:4HaXUp8o2+bhHr1OhVy+VjN0+L7/07JDcn6v7YrTjrQ=
github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdikvbVJVHv/M+0= github.com/chi-middleware/proxy v1.1.1/go.mod h1:jQwMEJct2tz9VmtCELxvnXoMfa+SOdikvbVJVHv/M+0=
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -774,6 +776,8 @@ github.com/libdns/libdns v0.2.0 h1:ewg3ByWrdUrxrje8ChPVMBNcotg7H9LQYg+u5De2RzI=
github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8 h1:1omo92DLtxQu6VwVPSZAmduHaK5zssed6cvkHyl1XOg=
github.com/lunny/bluemonday v1.0.5-0.20201227154428-ca34796141e8/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 h1:uNwtsDp7ci48vBTTxDuwcoTXz4lwtDTe7TjCQ0noaWY=
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ= github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96/go.mod h1:mmIfjCSQlGYXmJ95jFN84AkQFnVABtKuJL8IrzwvUKQ=
github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ= github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbatJuy3nvq/hRSvuBJrHHr+ybPPiNvHQ=
@@ -830,8 +834,6 @@ github.com/mholt/acmez v0.1.3 h1:J7MmNIk4Qf9b8mAGqAh4XkNeowv3f1zW816yf4zt7Qk=
github.com/mholt/acmez v0.1.3/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= github.com/mholt/acmez v0.1.3/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE= github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE=
github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc= github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc=
github.com/microcosm-cc/bluemonday v1.0.7 h1:6yAQfk4XT+PI/dk1ZeBp1gr3Q2Hd1DR0O3aEyPUJVTE=
github.com/microcosm-cc/bluemonday v1.0.7/go.mod h1:HOT/6NaBlR0f9XlxD3zolN6Z3N8Lp4pvhp+jLS5ihnI=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA= github.com/miekg/dns v1.1.40 h1:pyyPFfGMnciYUk/mXpKkVmeMQjfXqt3FAJ2hy7tPiLA=
@@ -1143,8 +1145,8 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.3 h1:37BdQwPx8VOSic8eDSWee6QL9mRpZRm9VJp/QugNrW0= github.com/yuin/goldmark v1.3.2 h1:YjHC5TgyMmHpicTgEqDN0Q96Xo8K6tLXPnmNOHXCgs0=
github.com/yuin/goldmark v1.3.3/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.2/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSxtAiQNh3zgHJpdpkpVYjTPqRE3P6UZCOPa1nRDio= github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691 h1:VWSxtAiQNh3zgHJpdpkpVYjTPqRE3P6UZCOPa1nRDio=
github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo= github.com/yuin/goldmark-highlighting v0.0.0-20200307114337-60d527fdb691/go.mod h1:YLF3kDffRfUH/bTxOxHhV6lxwIB3Vfj91rEwNMS9MXo=
github.com/yuin/goldmark-meta v1.0.0 h1:ScsatUIT2gFS6azqzLGUjgOnELsBOxMXerM3ogdJhAM= github.com/yuin/goldmark-meta v1.0.0 h1:ScsatUIT2gFS6azqzLGUjgOnELsBOxMXerM3ogdJhAM=
@@ -1319,9 +1321,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1417,8 +1418,8 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46 h1:V066+OYJ66oTjnhm4Yrn7SXIwSCiDQJxpBxmvqb1N1c=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=

View File

@@ -239,26 +239,6 @@ func doAPICreatePullRequest(ctx APITestContext, owner, repo, baseBranch, headBra
} }
} }
func doAPIGetPullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) (api.PullRequest, error) {
return func(t *testing.T) (api.PullRequest, error) {
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d?token=%s",
owner, repo, index, ctx.Token)
req := NewRequest(t, http.MethodGet, urlStr)
expected := 200
if ctx.ExpectedCode != 0 {
expected = ctx.ExpectedCode
}
resp := ctx.Session.MakeRequest(t, req, expected)
json := jsoniter.ConfigCompatibleWithStandardLibrary
decoder := json.NewDecoder(resp.Body)
pr := api.PullRequest{}
err := decoder.Decode(&pr)
return pr, err
}
}
func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) { func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64) func(*testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s",

View File

@@ -92,10 +92,6 @@ func testAPIDeleteOAuth2Application(t *testing.T) {
session.MakeRequest(t, req, http.StatusNoContent) session.MakeRequest(t, req, http.StatusNoContent)
models.AssertNotExistsBean(t, &models.OAuth2Application{UID: oldApp.UID, Name: oldApp.Name}) models.AssertNotExistsBean(t, &models.OAuth2Application{UID: oldApp.UID, Name: oldApp.Name})
// Delete again will return not found
req = NewRequest(t, "DELETE", urlStr)
session.MakeRequest(t, req, http.StatusNotFound)
} }
func testAPIGetOAuth2Application(t *testing.T) { func testAPIGetOAuth2Application(t *testing.T) {

View File

@@ -122,7 +122,7 @@ func TestGetAttachment(t *testing.T) {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
//Write empty file to be available for response //Write empty file to be available for response
if tc.createFile { if tc.createFile {
_, err := storage.Attachments.Save(models.AttachmentRelativePath(tc.uuid), strings.NewReader("hello world"), -1) _, err := storage.Attachments.Save(models.AttachmentRelativePath(tc.uuid), strings.NewReader("hello world"))
assert.NoError(t, err) assert.NoError(t, err)
} }
//Actual test //Actual test

View File

@@ -5,7 +5,6 @@
package integrations package integrations
import ( import (
"encoding/hex"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
@@ -209,13 +208,13 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s
// Request raw paths // Request raw paths
req := NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", little)) req := NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", little))
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp := session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, littleSize, resp.Length) assert.Equal(t, littleSize, resp.Body.Len())
setting.CheckLFSVersion() setting.CheckLFSVersion()
if setting.LFS.StartServer { if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS))
resp := session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.NotEqual(t, littleSize, resp.Body.Len()) assert.NotEqual(t, littleSize, resp.Body.Len())
assert.LessOrEqual(t, resp.Body.Len(), 1024) assert.LessOrEqual(t, resp.Body.Len(), 1024)
if resp.Body.Len() != littleSize && resp.Body.Len() <= 1024 { if resp.Body.Len() != littleSize && resp.Body.Len() <= 1024 {
@@ -225,12 +224,12 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s
if !testing.Short() { if !testing.Short() {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", big)) req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", big))
resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, bigSize, resp.Length) assert.Equal(t, bigSize, resp.Body.Len())
if setting.LFS.StartServer { if setting.LFS.StartServer {
req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS)) req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", bigLFS))
resp := session.MakeRequest(t, req, http.StatusOK) resp = session.MakeRequest(t, req, http.StatusOK)
assert.NotEqual(t, bigSize, resp.Body.Len()) assert.NotEqual(t, bigSize, resp.Body.Len())
if resp.Body.Len() != bigSize && resp.Body.Len() <= 1024 { if resp.Body.Len() != bigSize && resp.Body.Len() <= 1024 {
assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier) assert.Contains(t, resp.Body.String(), models.LFSMetaFileIdentifier)
@@ -451,35 +450,27 @@ func doMergeFork(ctx, baseCtx APITestContext, baseBranch, headBranch string) fun
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
// Then get the diff string // Then get the diff string
var diffHash string var diffStr string
var diffLength int
t.Run("GetDiff", func(t *testing.T) { t.Run("GetDiff", func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index)) req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(baseCtx.Username), url.PathEscape(baseCtx.Reponame), pr.Index))
resp := ctx.Session.MakeRequestNilResponseHashSumRecorder(t, req, http.StatusOK) resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
diffHash = string(resp.Hash.Sum(nil)) diffStr = resp.Body.String()
diffLength = resp.Length
}) })
// Now: Merge the PR & make sure that doesn't break the PR page or change its diff // Now: Merge the PR & make sure that doesn't break the PR page or change its diff
t.Run("MergePR", doAPIMergePullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)) t.Run("MergePR", doAPIMergePullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index))
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
t.Run("CheckPR", func(t *testing.T) { t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffStr))
oldMergeBase := pr.MergeBase
pr2, err := doAPIGetPullRequest(baseCtx, baseCtx.Username, baseCtx.Reponame, pr.Index)(t)
assert.NoError(t, err)
assert.Equal(t, oldMergeBase, pr2.MergeBase)
})
t.Run("EnsurDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength))
// Then: Delete the head branch & make sure that doesn't break the PR page or change its diff // Then: Delete the head branch & make sure that doesn't break the PR page or change its diff
t.Run("DeleteHeadBranch", doBranchDelete(baseCtx, baseCtx.Username, baseCtx.Reponame, headBranch)) t.Run("DeleteHeadBranch", doBranchDelete(baseCtx, baseCtx.Username, baseCtx.Reponame, headBranch))
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength)) t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffStr))
// Delete the head repository & make sure that doesn't break the PR page or change its diff // Delete the head repository & make sure that doesn't break the PR page or change its diff
t.Run("DeleteHeadRepository", doAPIDeleteRepository(ctx)) t.Run("DeleteHeadRepository", doAPIDeleteRepository(ctx))
t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr)) t.Run("EnsureCanSeePull", doEnsureCanSeePull(baseCtx, pr))
t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffHash, diffLength)) t.Run("EnsureDiffNoChange", doEnsureDiffNoChange(baseCtx, pr, diffStr))
} }
} }
@@ -523,15 +514,20 @@ func doEnsureCanSeePull(ctx APITestContext, pr api.PullRequest) func(t *testing.
} }
} }
func doEnsureDiffNoChange(ctx APITestContext, pr api.PullRequest, diffHash string, diffLength int) func(t *testing.T) { func doEnsureDiffNoChange(ctx APITestContext, pr api.PullRequest, diffStr string) func(t *testing.T) {
return func(t *testing.T) { return func(t *testing.T) {
req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index)) req := NewRequest(t, "GET", fmt.Sprintf("/%s/%s/pulls/%d.diff", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), pr.Index))
resp := ctx.Session.MakeRequestNilResponseHashSumRecorder(t, req, http.StatusOK) resp := ctx.Session.MakeRequest(t, req, http.StatusOK)
actual := string(resp.Hash.Sum(nil)) expectedMaxLen := len(diffStr)
actualLength := resp.Length if expectedMaxLen > 800 {
expectedMaxLen = 800
equal := diffHash == actual }
assert.True(t, equal, "Unexpected change in the diff string: expected hash: %s size: %d but was actually: %s size: %d", hex.EncodeToString([]byte(diffHash)), diffLength, hex.EncodeToString([]byte(actual)), actualLength) actual := resp.Body.String()
actualMaxLen := len(actual)
if actualMaxLen > 800 {
actualMaxLen = 800
}
assert.Equal(t, diffStr, actual, "Unexpected change in the diff string: expected: %s but was actually: %s", diffStr[:expectedMaxLen], actual[:actualMaxLen])
} }
} }

View File

@@ -9,8 +9,6 @@ import (
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
"hash"
"hash/fnv"
"io" "io"
"net/http" "net/http"
"net/http/cookiejar" "net/http/cookiejar"
@@ -60,26 +58,6 @@ func NewNilResponseRecorder() *NilResponseRecorder {
} }
} }
type NilResponseHashSumRecorder struct {
httptest.ResponseRecorder
Hash hash.Hash
Length int
}
func (n *NilResponseHashSumRecorder) Write(b []byte) (int, error) {
_, _ = n.Hash.Write(b)
n.Length += len(b)
return len(b), nil
}
// NewRecorder returns an initialized ResponseRecorder.
func NewNilResponseHashSumRecorder() *NilResponseHashSumRecorder {
return &NilResponseHashSumRecorder{
Hash: fnv.New32(),
ResponseRecorder: *httptest.NewRecorder(),
}
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
defer log.Close() defer log.Close()
@@ -306,23 +284,6 @@ func (s *TestSession) MakeRequestNilResponseRecorder(t testing.TB, req *http.Req
return resp return resp
} }
func (s *TestSession) MakeRequestNilResponseHashSumRecorder(t testing.TB, req *http.Request, expectedStatus int) *NilResponseHashSumRecorder {
t.Helper()
baseURL, err := url.Parse(setting.AppURL)
assert.NoError(t, err)
for _, c := range s.jar.Cookies(baseURL) {
req.AddCookie(c)
}
resp := MakeRequestNilResponseHashSumRecorder(t, req, expectedStatus)
ch := http.Header{}
ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
cr := http.Request{Header: ch}
s.jar.SetCookies(baseURL, cr.Cookies())
return resp
}
const userPassword = "password" const userPassword = "password"
var loginSessionCache = make(map[string]*TestSession, 10) var loginSessionCache = make(map[string]*TestSession, 10)
@@ -468,19 +429,6 @@ func MakeRequestNilResponseRecorder(t testing.TB, req *http.Request, expectedSta
return recorder return recorder
} }
func MakeRequestNilResponseHashSumRecorder(t testing.TB, req *http.Request, expectedStatus int) *NilResponseHashSumRecorder {
t.Helper()
recorder := NewNilResponseHashSumRecorder()
c.ServeHTTP(recorder, req)
if expectedStatus != NoExpectedStatus {
if !assert.EqualValues(t, expectedStatus, recorder.Code,
"Request: %s %s", req.Method, req.URL.String()) {
logUnexpectedResponse(t, &recorder.ResponseRecorder)
}
}
return recorder
}
// logUnexpectedResponse logs the contents of an unexpected response. // logUnexpectedResponse logs the contents of an unexpected response.
func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) { func logUnexpectedResponse(t testing.TB, recorder *httptest.ResponseRecorder) {
t.Helper() t.Helper()

View File

@@ -382,7 +382,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) {
} }
if opts.Date != "" { if opts.Date != "" {
dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation) dateLow, err := time.Parse("2006-01-02", opts.Date)
if err != nil { if err != nil {
log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err) log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
} else { } else {

View File

@@ -85,7 +85,7 @@ func (a *Attachment) LinkedRepository() (*Repository, UnitType, error) {
func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) { func NewAttachment(attach *Attachment, buf []byte, file io.Reader) (_ *Attachment, err error) {
attach.UUID = gouuid.New().String() attach.UUID = gouuid.New().String()
size, err := storage.Attachments.Save(attach.RelativePath(), io.MultiReader(bytes.NewReader(buf), file), -1) size, err := storage.Attachments.Save(attach.RelativePath(), io.MultiReader(bytes.NewReader(buf), file))
if err != nil { if err != nil {
return nil, fmt.Errorf("Create: %v", err) return nil, fmt.Errorf("Create: %v", err)
} }

View File

@@ -96,11 +96,6 @@ func HashedAvatarLink(email string) string {
// we don't care about any DB problem just return the lowerEmail // we don't care about any DB problem just return the lowerEmail
return lowerEmail, nil return lowerEmail, nil
} }
has, err := sess.Where("email = ? AND hash = ?", emailHash.Email, emailHash.Hash).Get(new(EmailHash))
if has || err != nil {
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
return lowerEmail, nil
}
_, _ = sess.Insert(emailHash) _, _ = sess.Insert(emailHash)
if err := sess.Commit(); err != nil { if err := sess.Commit(); err != nil {
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time // Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time

View File

@@ -338,7 +338,7 @@ func FixCommentTypeLabelWithEmptyLabel() (int64, error) {
// CountCommentTypeLabelWithOutsideLabels count label comments with outside label // CountCommentTypeLabelWithOutsideLabels count label comments with outside label
func CountCommentTypeLabelWithOutsideLabels() (int64, error) { func CountCommentTypeLabelWithOutsideLabels() (int64, error) {
return x.Where("comment.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id))", CommentTypeLabel). return x.Where("comment.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND repository.owner_id != label.org_id))", CommentTypeLabel).
Table("comment"). Table("comment").
Join("inner", "label", "label.id = comment.label_id"). Join("inner", "label", "label.id = comment.label_id").
Join("inner", "issue", "issue.id = comment.issue_id "). Join("inner", "issue", "issue.id = comment.issue_id ").
@@ -354,9 +354,8 @@ func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
FROM comment AS com FROM comment AS com
INNER JOIN label ON com.label_id = label.id INNER JOIN label ON com.label_id = label.id
INNER JOIN issue on issue.id = com.issue_id INNER JOIN issue on issue.id = com.issue_id
INNER JOIN repository ON issue.repo_id = repository.id
WHERE WHERE
com.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)) com.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repo.owner_id))
) AS il_too)`, CommentTypeLabel) ) AS il_too)`, CommentTypeLabel)
if err != nil { if err != nil {
return 0, err return 0, err
@@ -367,9 +366,9 @@ func FixCommentTypeLabelWithOutsideLabels() (int64, error) {
// CountIssueLabelWithOutsideLabels count label comments with outside label // CountIssueLabelWithOutsideLabels count label comments with outside label
func CountIssueLabelWithOutsideLabels() (int64, error) { func CountIssueLabelWithOutsideLabels() (int64, error) {
return x.Where(builder.Expr("(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)")). return x.Where(builder.Expr("issue.repo_id != label.repo_id OR (label.repo_id = 0 AND repository.owner_id != label.org_id)")).
Table("issue_label"). Table("issue_label").
Join("inner", "label", "issue_label.label_id = label.id "). Join("inner", "label", "issue_label.id = label.id ").
Join("inner", "issue", "issue.id = issue_label.issue_id "). Join("inner", "issue", "issue.id = issue_label.issue_id ").
Join("inner", "repository", "issue.repo_id = repository.id"). Join("inner", "repository", "issue.repo_id = repository.id").
Count(new(IssueLabel)) Count(new(IssueLabel))
@@ -381,11 +380,11 @@ func FixIssueLabelWithOutsideLabels() (int64, error) {
SELECT il_too.id FROM ( SELECT il_too.id FROM (
SELECT il_too_too.id SELECT il_too_too.id
FROM issue_label AS il_too_too FROM issue_label AS il_too_too
INNER JOIN label ON il_too_too.label_id = label.id INNER JOIN label ON il_too_too.id = label.id
INNER JOIN issue on issue.id = il_too_too.issue_id INNER JOIN issue on issue.id = il_too_too.issue_id
INNER JOIN repository on repository.id = issue.repo_id INNER JOIN repository on repository.id = issue.repo_id
WHERE WHERE
(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id) issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
) AS il_too )`) ) AS il_too )`)
if err != nil { if err != nil {

View File

@@ -53,9 +53,6 @@ func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) {
for _, issue := range issues { for _, issue := range issues {
issue.Repo = repoMaps[issue.RepoID] issue.Repo = repoMaps[issue.RepoID]
if issue.PullRequest != nil {
issue.PullRequest.BaseRepo = issue.Repo
}
} }
return valuesRepository(repoMaps), nil return valuesRepository(repoMaps), nil
} }
@@ -519,11 +516,6 @@ func (issues IssueList) LoadDiscussComments() error {
return issues.loadComments(x, builder.Eq{"comment.type": CommentTypeComment}) return issues.loadComments(x, builder.Eq{"comment.type": CommentTypeComment})
} }
// LoadPullRequests loads pull requests
func (issues IssueList) LoadPullRequests() error {
return issues.loadPullRequests(x)
}
// GetApprovalCounts returns a map of issue ID to slice of approval counts // GetApprovalCounts returns a map of issue ID to slice of approval counts
// FIXME: only returns official counts due to double counting of non-official approvals // FIXME: only returns official counts due to double counting of non-official approvals
func (issues IssueList) GetApprovalCounts() (map[int64][]*ReviewCount, error) { func (issues IssueList) GetApprovalCounts() (map[int64][]*ReviewCount, error) {

View File

@@ -26,8 +26,6 @@ func NewXORMLogger(showSQL bool) xormlog.Logger {
} }
} }
const stackLevel = 8
// Log a message with defined skip and at logging level // Log a message with defined skip and at logging level
func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...interface{}) error { func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...interface{}) error {
return l.logger.Log(skip+1, level, format, v...) return l.logger.Log(skip+1, level, format, v...)
@@ -35,42 +33,42 @@ func (l *XORMLogBridge) Log(skip int, level log.Level, format string, v ...inter
// Debug show debug log // Debug show debug log
func (l *XORMLogBridge) Debug(v ...interface{}) { func (l *XORMLogBridge) Debug(v ...interface{}) {
_ = l.Log(stackLevel, log.DEBUG, fmt.Sprint(v...)) _ = l.Log(2, log.DEBUG, fmt.Sprint(v...))
} }
// Debugf show debug log // Debugf show debug log
func (l *XORMLogBridge) Debugf(format string, v ...interface{}) { func (l *XORMLogBridge) Debugf(format string, v ...interface{}) {
_ = l.Log(stackLevel, log.DEBUG, format, v...) _ = l.Log(2, log.DEBUG, format, v...)
} }
// Error show error log // Error show error log
func (l *XORMLogBridge) Error(v ...interface{}) { func (l *XORMLogBridge) Error(v ...interface{}) {
_ = l.Log(stackLevel, log.ERROR, fmt.Sprint(v...)) _ = l.Log(2, log.ERROR, fmt.Sprint(v...))
} }
// Errorf show error log // Errorf show error log
func (l *XORMLogBridge) Errorf(format string, v ...interface{}) { func (l *XORMLogBridge) Errorf(format string, v ...interface{}) {
_ = l.Log(stackLevel, log.ERROR, format, v...) _ = l.Log(2, log.ERROR, format, v...)
} }
// Info show information level log // Info show information level log
func (l *XORMLogBridge) Info(v ...interface{}) { func (l *XORMLogBridge) Info(v ...interface{}) {
_ = l.Log(stackLevel, log.INFO, fmt.Sprint(v...)) _ = l.Log(2, log.INFO, fmt.Sprint(v...))
} }
// Infof show information level log // Infof show information level log
func (l *XORMLogBridge) Infof(format string, v ...interface{}) { func (l *XORMLogBridge) Infof(format string, v ...interface{}) {
_ = l.Log(stackLevel, log.INFO, format, v...) _ = l.Log(2, log.INFO, format, v...)
} }
// Warn show warning log // Warn show warning log
func (l *XORMLogBridge) Warn(v ...interface{}) { func (l *XORMLogBridge) Warn(v ...interface{}) {
_ = l.Log(stackLevel, log.WARN, fmt.Sprint(v...)) _ = l.Log(2, log.WARN, fmt.Sprint(v...))
} }
// Warnf show warnning log // Warnf show warnning log
func (l *XORMLogBridge) Warnf(format string, v ...interface{}) { func (l *XORMLogBridge) Warnf(format string, v ...interface{}) {
_ = l.Log(stackLevel, log.WARN, format, v...) _ = l.Log(2, log.WARN, format, v...)
} }
// Level get logger level // Level get logger level

View File

@@ -39,7 +39,6 @@ func InsertMilestones(ms ...*Milestone) (err error) {
// InsertIssues insert issues to database // InsertIssues insert issues to database
func InsertIssues(issues ...*Issue) error { func InsertIssues(issues ...*Issue) error {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return err return err
} }
@@ -195,7 +194,6 @@ func InsertPullRequests(prs ...*PullRequest) error {
// InsertReleases migrates release // InsertReleases migrates release
func InsertReleases(rels ...*Release) error { func InsertReleases(rels ...*Release) error {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return err return err
} }

View File

@@ -14,7 +14,7 @@ func addSessionTable(x *xorm.Engine) error {
type Session struct { type Session struct {
Key string `xorm:"pk CHAR(16)"` Key string `xorm:"pk CHAR(16)"`
Data []byte `xorm:"BLOB"` Data []byte `xorm:"BLOB"`
Expiry timeutil.TimeStamp CreatedUnix timeutil.TimeStamp
} }
return x.Sync2(new(Session)) return x.Sync2(new(Session))
} }

View File

@@ -48,11 +48,11 @@ func removeInvalidLabels(x *xorm.Engine) error {
SELECT il_too.id FROM ( SELECT il_too.id FROM (
SELECT il_too_too.id SELECT il_too_too.id
FROM issue_label AS il_too_too FROM issue_label AS il_too_too
INNER JOIN label ON il_too_too.label_id = label.id INNER JOIN label ON il_too_too.id = label.id
INNER JOIN issue on issue.id = il_too_too.issue_id INNER JOIN issue on issue.id = il_too_too.issue_id
INNER JOIN repository on repository.id = issue.repo_id INNER JOIN repository on repository.id = issue.repo_id
WHERE WHERE
(label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id) issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id)
) AS il_too )`); err != nil { ) AS il_too )`); err != nil {
return err return err
} }
@@ -65,7 +65,7 @@ func removeInvalidLabels(x *xorm.Engine) error {
INNER JOIN issue on issue.id = com.issue_id INNER JOIN issue on issue.id = com.issue_id
INNER JOIN repository on repository.id = issue.repo_id INNER JOIN repository on repository.id = issue.repo_id
WHERE WHERE
com.type = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != repository.owner_id)) com.type = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != repository.owner_id))
) AS il_too)`, 7); err != nil { ) AS il_too)`, 7); err != nil {
return err return err
} }

View File

@@ -235,7 +235,7 @@ func deleteOAuth2Application(sess *xorm.Session, id, userid int64) error {
if deleted, err := sess.Delete(&OAuth2Application{ID: id, UID: userid}); err != nil { if deleted, err := sess.Delete(&OAuth2Application{ID: id, UID: userid}); err != nil {
return err return err
} else if deleted == 0 { } else if deleted == 0 {
return ErrOAuthApplicationNotFound{ID: id} return fmt.Errorf("cannot find oauth2 application")
} }
codes := make([]*OAuth2AuthorizationCode, 0) codes := make([]*OAuth2AuthorizationCode, 0)
// delete correlating auth codes // delete correlating auth codes
@@ -261,7 +261,6 @@ func deleteOAuth2Application(sess *xorm.Session, id, userid int64) error {
// DeleteOAuth2Application deletes the application with the given id and the grants and auth codes related to it. It checks if the userid was the creator of the app. // DeleteOAuth2Application deletes the application with the given id and the grants and auth codes related to it. It checks if the userid was the creator of the app.
func DeleteOAuth2Application(id, userid int64) error { func DeleteOAuth2Application(id, userid int64) error {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil { if err := sess.Begin(); err != nil {
return err return err
} }

View File

@@ -406,8 +406,7 @@ func (pr *PullRequest) SetMerged() (bool, error) {
return false, fmt.Errorf("Issue.changeStatus: %v", err) return false, fmt.Errorf("Issue.changeStatus: %v", err)
} }
// We need to save all of the data used to compute this merge as it may have already been changed by TestPatch. FIXME: need to set some state to prevent TestPatch from running whilst we are merging. if _, err := sess.Where("id = ?", pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil {
if _, err := sess.Where("id = ?", pr.ID).Cols("has_merged, status, merge_base, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil {
return false, fmt.Errorf("Failed to update pr[%d]: %v", pr.ID, err) return false, fmt.Errorf("Failed to update pr[%d]: %v", pr.ID, err)
} }

View File

@@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
"xorm.io/builder" "xorm.io/builder"
"xorm.io/xorm"
) )
// RepositoryListDefaultPageSize is the default number of repositories // RepositoryListDefaultPageSize is the default number of repositories
@@ -364,35 +363,6 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
// SearchRepositoryByCondition search repositories by condition // SearchRepositoryByCondition search repositories by condition
func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) { func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) {
sess, count, err := searchRepositoryByCondition(opts, cond)
if err != nil {
return nil, 0, err
}
defer sess.Close()
defaultSize := 50
if opts.PageSize > 0 {
defaultSize = opts.PageSize
}
repos := make(RepositoryList, 0, defaultSize)
if err := sess.Find(&repos); err != nil {
return nil, 0, fmt.Errorf("Repo: %v", err)
}
if opts.PageSize <= 0 {
count = int64(len(repos))
}
if loadAttributes {
if err := repos.loadAttributes(sess); err != nil {
return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
}
}
return repos, count, nil
}
func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (*xorm.Session, int64, error) {
if opts.Page <= 0 { if opts.Page <= 0 {
opts.Page = 1 opts.Page = 1
} }
@@ -406,24 +376,31 @@ func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (*x
} }
sess := x.NewSession() sess := x.NewSession()
defer sess.Close()
var count int64 count, err := sess.
if opts.PageSize > 0 {
var err error
count, err = sess.
Where(cond). Where(cond).
Count(new(Repository)) Count(new(Repository))
if err != nil { if err != nil {
_ = sess.Close()
return nil, 0, fmt.Errorf("Count: %v", err) return nil, 0, fmt.Errorf("Count: %v", err)
} }
}
repos := make(RepositoryList, 0, opts.PageSize)
sess.Where(cond).OrderBy(opts.OrderBy.String()) sess.Where(cond).OrderBy(opts.OrderBy.String())
if opts.PageSize > 0 { if opts.PageSize > 0 {
sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
} }
return sess, count, nil if err = sess.Find(&repos); err != nil {
return nil, 0, fmt.Errorf("Repo: %v", err)
}
if loadAttributes {
if err = repos.loadAttributes(sess); err != nil {
return nil, 0, fmt.Errorf("LoadAttributes: %v", err)
}
}
return repos, count, nil
} }
// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible // accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
@@ -479,33 +456,6 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
return SearchRepository(opts) return SearchRepository(opts)
} }
// SearchRepositoryIDs takes keyword and part of repository name to search,
// it returns results in given range and number of total results.
func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) {
opts.IncludeDescription = false
cond := SearchRepositoryCondition(opts)
sess, count, err := searchRepositoryByCondition(opts, cond)
if err != nil {
return nil, 0, err
}
defer sess.Close()
defaultSize := 50
if opts.PageSize > 0 {
defaultSize = opts.PageSize
}
ids := make([]int64, 0, defaultSize)
err = sess.Select("id").Table("repository").Find(&ids)
if opts.PageSize <= 0 {
count = int64(len(ids))
}
return ids, count, err
}
// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered. // AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered.
func AccessibleRepoIDsQuery(user *User) *builder.Builder { func AccessibleRepoIDsQuery(user *User) *builder.Builder {
// NB: Please note this code needs to still work if user is nil // NB: Please note this code needs to still work if user is nil

View File

@@ -330,10 +330,10 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e
SELECT il_too.id FROM ( SELECT il_too.id FROM (
SELECT il_too_too.id SELECT il_too_too.id
FROM issue_label AS il_too_too FROM issue_label AS il_too_too
INNER JOIN label ON il_too_too.label_id = label.id INNER JOIN label ON il_too_too.id = label.id
INNER JOIN issue on issue.id = il_too_too.issue_id INNER JOIN issue on issue.id = il_too_too.issue_id
WHERE WHERE
issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?)) issue.repo_id = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != ?))
) AS il_too )`, repo.ID, newOwner.ID); err != nil { ) AS il_too )`, repo.ID, newOwner.ID); err != nil {
return fmt.Errorf("Unable to remove old org labels: %v", err) return fmt.Errorf("Unable to remove old org labels: %v", err)
} }
@@ -343,9 +343,9 @@ func TransferOwnership(doer *User, newOwnerName string, repo *Repository) (err e
SELECT com.id SELECT com.id
FROM comment AS com FROM comment AS com
INNER JOIN label ON com.label_id = label.id INNER JOIN label ON com.label_id = label.id
INNER JOIN issue ON issue.id = com.issue_id INNER JOIN issue on issue.id = com.issue_id
WHERE WHERE
com.type = ? AND issue.repo_id = ? AND ((label.org_id = 0 AND issue.repo_id != label.repo_id) OR (label.repo_id = 0 AND label.org_id != ?)) com.type = ? AND issue.repo_id = ? AND (issue.repo_id != label.repo_id OR (label.repo_id = 0 AND label.org_id != ?))
) AS il_too)`, CommentTypeLabel, repo.ID, newOwner.ID); err != nil { ) AS il_too)`, CommentTypeLabel, repo.ID, newOwner.ID); err != nil {
return fmt.Errorf("Unable to remove old org label comments: %v", err) return fmt.Errorf("Unable to remove old org label comments: %v", err)
} }

View File

@@ -566,11 +566,7 @@ func DismissReview(review *Review, isDismiss bool) (err error) {
review.Dismissed = isDismiss review.Dismissed = isDismiss
if review.ID == 0 { _, err = x.Cols("dismissed").Update(review)
return ErrReviewNotExist{}
}
_, err = x.ID(review.ID).Cols("dismissed").Update(review)
return return
} }

View File

@@ -143,57 +143,11 @@ func TestGetReviewersByIssueID(t *testing.T) {
} }
func TestDismissReview(t *testing.T) { func TestDismissReview(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) review1 := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
review2 := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
rejectReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review) assert.NoError(t, DismissReview(review1, true))
requestReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review) assert.NoError(t, DismissReview(review2, true))
approveReviewExample := AssertExistsAndLoadBean(t, &Review{ID: 8}).(*Review) assert.NoError(t, DismissReview(review2, true))
assert.False(t, rejectReviewExample.Dismissed) assert.NoError(t, DismissReview(review2, false))
assert.False(t, requestReviewExample.Dismissed) assert.NoError(t, DismissReview(review2, false))
assert.False(t, approveReviewExample.Dismissed)
assert.NoError(t, DismissReview(rejectReviewExample, true))
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
assert.True(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.NoError(t, DismissReview(requestReviewExample, true))
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
assert.True(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.False(t, approveReviewExample.Dismissed)
assert.NoError(t, DismissReview(requestReviewExample, true))
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
assert.True(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.False(t, approveReviewExample.Dismissed)
assert.NoError(t, DismissReview(requestReviewExample, false))
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
assert.True(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.False(t, approveReviewExample.Dismissed)
assert.NoError(t, DismissReview(requestReviewExample, false))
rejectReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 9}).(*Review)
requestReviewExample = AssertExistsAndLoadBean(t, &Review{ID: 11}).(*Review)
assert.True(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.False(t, approveReviewExample.Dismissed)
assert.NoError(t, DismissReview(rejectReviewExample, false))
assert.False(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.False(t, approveReviewExample.Dismissed)
assert.NoError(t, DismissReview(approveReviewExample, true))
assert.False(t, rejectReviewExample.Dismissed)
assert.False(t, requestReviewExample.Dismissed)
assert.True(t, approveReviewExample.Dismissed)
} }

View File

@@ -239,10 +239,10 @@ func (u *User) GetEmail() string {
return u.Email return u.Email
} }
// GetAllUsers returns a slice of all individual users found in DB. // GetAllUsers returns a slice of all users found in DB.
func GetAllUsers() ([]*User, error) { func GetAllUsers() ([]*User, error) {
users := make([]*User, 0) users := make([]*User, 0)
return users, x.OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users) return users, x.OrderBy("id").Find(&users)
} }
// IsLocal returns true if user login type is LoginPlain. // IsLocal returns true if user login type is LoginPlain.

View File

@@ -1,70 +0,0 @@
// Copyright 2021 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 analyze
import (
"regexp"
"sort"
"strings"
"github.com/go-enry/go-enry/v2/data"
)
var isVendorRegExp *regexp.Regexp
func init() {
matchers := data.VendorMatchers
caretStrings := make([]string, 0, 10)
caretShareStrings := make([]string, 0, 10)
matcherStrings := make([]string, 0, len(matchers))
for _, matcher := range matchers {
str := matcher.String()
if str[0] == '^' {
caretStrings = append(caretStrings, str[1:])
} else if str[0:5] == "(^|/)" {
caretShareStrings = append(caretShareStrings, str[5:])
} else {
matcherStrings = append(matcherStrings, str)
}
}
sort.Strings(caretShareStrings)
sort.Strings(caretStrings)
sort.Strings(matcherStrings)
sb := &strings.Builder{}
sb.WriteString("(?:^(?:")
sb.WriteString(caretStrings[0])
for _, matcher := range caretStrings[1:] {
sb.WriteString(")|(?:")
sb.WriteString(matcher)
}
sb.WriteString("))")
sb.WriteString("|")
sb.WriteString("(?:(?:^|/)(?:")
sb.WriteString(caretShareStrings[0])
for _, matcher := range caretShareStrings[1:] {
sb.WriteString(")|(?:")
sb.WriteString(matcher)
}
sb.WriteString("))")
sb.WriteString("|")
sb.WriteString("(?:")
sb.WriteString(matcherStrings[0])
for _, matcher := range matcherStrings[1:] {
sb.WriteString(")|(?:")
sb.WriteString(matcher)
}
sb.WriteString(")")
combined := sb.String()
isVendorRegExp = regexp.MustCompile(combined)
}
// IsVendor returns whether or not path is a vendor path.
func IsVendor(path string) bool {
return isVendorRegExp.MatchString(path)
}

View File

@@ -1,42 +0,0 @@
// Copyright 2021 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 analyze
import "testing"
func TestIsVendor(t *testing.T) {
tests := []struct {
path string
want bool
}{
{"cache/", true},
{"random/cache/", true},
{"cache", false},
{"dependencies/", true},
{"Dependencies/", true},
{"dependency/", false},
{"dist/", true},
{"dist", false},
{"random/dist/", true},
{"random/dist", false},
{"deps/", true},
{"configure", true},
{"a/configure", true},
{"config.guess", true},
{"config.guess/", false},
{".vscode/", true},
{"doc/_build/", true},
{"a/docs/_build/", true},
{"a/dasdocs/_build-vsdoc.js", true},
{"a/dasdocs/_build-vsdoc.j", false},
}
for _, tt := range tests {
t.Run(tt.path, func(t *testing.T) {
if got := IsVendor(tt.path); got != tt.want {
t.Errorf("IsVendor() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -8,6 +8,7 @@ package context
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http"
"net/url" "net/url"
"path" "path"
"strings" "strings"
@@ -393,10 +394,13 @@ func RepoIDAssignment() func(ctx *Context) {
} }
// RepoAssignment returns a middleware to handle repository assignment // RepoAssignment returns a middleware to handle repository assignment
func RepoAssignment(ctx *Context) { func RepoAssignment() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var ( var (
owner *models.User owner *models.User
err error err error
ctx = GetContext(req)
) )
userName := ctx.Params(":username") userName := ctx.Params(":username")
@@ -539,6 +543,7 @@ func RepoAssignment(ctx *Context) {
// Stop at this point when the repo is empty. // Stop at this point when the repo is empty.
if ctx.Repo.Repository.IsEmpty { if ctx.Repo.Repository.IsEmpty {
ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch ctx.Data["BranchName"] = ctx.Repo.Repository.DefaultBranch
next.ServeHTTP(w, req)
return return
} }
@@ -619,6 +624,9 @@ func RepoAssignment(ctx *Context) {
ctx.Data["GoDocDirectory"] = prefix + "{/dir}" ctx.Data["GoDocDirectory"] = prefix + "{/dir}"
ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}" ctx.Data["GoDocFile"] = prefix + "{/dir}/{file}#L{line}"
} }
next.ServeHTTP(w, req)
})
}
} }
// RepoRefType type of repo reference // RepoRefType type of repo reference
@@ -643,7 +651,7 @@ const (
// RepoRef handles repository reference names when the ref name is not // RepoRef handles repository reference names when the ref name is not
// explicitly given // explicitly given
func RepoRef() func(*Context) { func RepoRef() func(http.Handler) http.Handler {
// since no ref name is explicitly specified, ok to just use branch // since no ref name is explicitly specified, ok to just use branch
return RepoRefByType(RepoRefBranch) return RepoRefByType(RepoRefBranch)
} }
@@ -722,8 +730,10 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
// RepoRefByType handles repository reference name for a specific type // RepoRefByType handles repository reference name for a specific type
// of repository reference // of repository reference
func RepoRefByType(refType RepoRefType) func(*Context) { func RepoRefByType(refType RepoRefType) func(http.Handler) http.Handler {
return func(ctx *Context) { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := GetContext(req)
// Empty repository does not have reference information. // Empty repository does not have reference information.
if ctx.Repo.Repository.IsEmpty { if ctx.Repo.Repository.IsEmpty {
return return
@@ -841,6 +851,9 @@ func RepoRefByType(refType RepoRefType) func(*Context) {
return return
} }
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
next.ServeHTTP(w, req)
})
} }
} }

View File

@@ -4,9 +4,7 @@
package context package context
import ( import "net/http"
"net/http"
)
// ResponseWriter represents a response writer for HTTP // ResponseWriter represents a response writer for HTTP
type ResponseWriter interface { type ResponseWriter interface {
@@ -62,11 +60,9 @@ func (r *Response) WriteHeader(statusCode int) {
} }
r.beforeExecuted = true r.beforeExecuted = true
} }
if r.status == 0 {
r.status = statusCode r.status = statusCode
r.ResponseWriter.WriteHeader(statusCode) r.ResponseWriter.WriteHeader(statusCode)
} }
}
// Flush flush cached data // Flush flush cached data
func (r *Response) Flush() { func (r *Response) Flush() {

View File

@@ -85,17 +85,18 @@ func ToPullReviewCommentList(review *models.Review, doer *models.User) ([]*api.P
apiComments := make([]*api.PullReviewComment, 0, len(review.CodeComments)) apiComments := make([]*api.PullReviewComment, 0, len(review.CodeComments))
auth := false
if doer != nil {
auth = doer.IsAdmin || doer.ID == review.ReviewerID
}
for _, lines := range review.CodeComments { for _, lines := range review.CodeComments {
for _, comments := range lines { for _, comments := range lines {
for _, comment := range comments { for _, comment := range comments {
auth := false
if doer != nil {
auth = doer.IsAdmin || doer.ID == comment.Poster.ID
}
apiComment := &api.PullReviewComment{ apiComment := &api.PullReviewComment{
ID: comment.ID, ID: comment.ID,
Body: comment.Content, Body: comment.Content,
Reviewer: ToUser(comment.Poster, doer != nil, auth), Reviewer: ToUser(review.Reviewer, doer != nil, auth),
ReviewID: review.ID, ReviewID: review.ID,
Created: comment.CreatedUnix.AsTime(), Created: comment.CreatedUnix.AsTime(),
Updated: comment.UpdatedUnix.AsTime(), Updated: comment.UpdatedUnix.AsTime(),

View File

@@ -7,7 +7,6 @@ package git
import ( import (
"io/ioutil" "io/ioutil"
"path/filepath"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -15,15 +14,32 @@ import (
) )
func TestBlob_Data(t *testing.T) { func TestBlob_Data(t *testing.T) {
output := "file2\n" output := `Copyright (c) 2016 The Gitea Authors
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") Copyright (c) 2015 The Gogs Authors
repo, err := OpenRepository(bareRepo1Path)
if !assert.NoError(t, err) { Permission is hereby granted, free of charge, to any person obtaining a copy
t.Fatal() of this software and associated documentation files (the "Software"), to deal
} in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
`
repo, err := OpenRepository("../../.git")
assert.NoError(t, err)
defer repo.Close() defer repo.Close()
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375") testBlob, err := repo.GetBlob("a8d4b49dd073a4a38a7e58385eeff7cc52568697")
assert.NoError(t, err) assert.NoError(t, err)
r, err := testBlob.DataAsync() r, err := testBlob.DataAsync()
@@ -37,14 +53,13 @@ func TestBlob_Data(t *testing.T) {
} }
func Benchmark_Blob_Data(b *testing.B) { func Benchmark_Blob_Data(b *testing.B) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare") repo, err := OpenRepository("../../.git")
repo, err := OpenRepository(bareRepo1Path)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
defer repo.Close() defer repo.Close()
testBlob, err := repo.GetBlob("6c493ff740f9380390d5c9ddef4af18697ac9375") testBlob, err := repo.GetBlob("a8d4b49dd073a4a38a7e58385eeff7cc52568697")
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }

View File

@@ -47,7 +47,7 @@ func GetRawDiffForFile(repoPath, startCommit, endCommit string, diffType RawDiff
func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error { func GetRepoRawDiffForFile(repo *Repository, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error {
commit, err := repo.GetCommit(endCommit) commit, err := repo.GetCommit(endCommit)
if err != nil { if err != nil {
return err return fmt.Errorf("GetCommit: %v", err)
} }
fileArgs := make([]string, 0) fileArgs := make([]string, 0)
if len(file) > 0 { if len(file) > 0 {

View File

@@ -21,7 +21,14 @@ func (repo *Repository) GetBranchCommitID(name string) (string, error) {
// GetTagCommitID returns last commit ID string of given tag. // GetTagCommitID returns last commit ID string of given tag.
func (repo *Repository) GetTagCommitID(name string) (string, error) { func (repo *Repository) GetTagCommitID(name string) (string, error) {
return repo.GetRefCommitID(TagPrefix + name) stdout, err := NewCommand("rev-list", "-n", "1", TagPrefix+name).RunInDir(repo.Path)
if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") {
return "", ErrNotExist{name, ""}
}
return "", err
}
return strings.TrimSpace(stdout), nil
} }
// ConvertToSHA1 returns a Hash object from a potential ID string // ConvertToSHA1 returns a Hash object from a potential ID string

View File

@@ -43,7 +43,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
sizes := make(map[string]int64) sizes := make(map[string]int64)
err = tree.Files().ForEach(func(f *object.File) error { err = tree.Files().ForEach(func(f *object.File) error {
if f.Size == 0 || analyze.IsVendor(f.Name) || enry.IsDotFile(f.Name) || if f.Size == 0 || enry.IsVendor(f.Name) || enry.IsDotFile(f.Name) ||
enry.IsDocumentation(f.Name) || enry.IsConfiguration(f.Name) { enry.IsDocumentation(f.Name) || enry.IsConfiguration(f.Name) {
return nil return nil
} }

View File

@@ -67,7 +67,7 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
for _, f := range entries { for _, f := range entries {
contentBuf.Reset() contentBuf.Reset()
content = contentBuf.Bytes() content = contentBuf.Bytes()
if f.Size() == 0 || analyze.IsVendor(f.Name()) || enry.IsDotFile(f.Name()) || if f.Size() == 0 || enry.IsVendor(f.Name()) || enry.IsDotFile(f.Name()) ||
enry.IsDocumentation(f.Name()) || enry.IsConfiguration(f.Name()) { enry.IsDocumentation(f.Name()) || enry.IsConfiguration(f.Name()) {
continue continue
} }

View File

@@ -68,19 +68,17 @@ func (g *Manager) start() {
// Set the running state // Set the running state
g.setState(stateRunning) g.setState(stateRunning)
if skip, _ := strconv.ParseBool(os.Getenv("SKIP_MINWINSVC")); skip { if skip, _ := strconv.ParseBool(os.Getenv("SKIP_MINWINSVC")); skip {
log.Trace("Skipping SVC check as SKIP_MINWINSVC is set")
return return
} }
// Make SVC process // Make SVC process
run := svc.Run run := svc.Run
isWindowsService, err := svc.IsWindowsService() isInteractive, err := svc.IsWindowsService()
if err != nil { if err != nil {
log.Error("Unable to ascertain if running as an Windows Service: %v", err) log.Error("Unable to ascertain if running as an Interactive Session: %v", err)
return return
} }
if !isWindowsService { if isInteractive {
log.Trace("Not running a service ... using the debug SVC manager")
run = debug.Run run = debug.Run
} }
go func() { go func() {
@@ -96,49 +94,38 @@ func (g *Manager) Execute(args []string, changes <-chan svc.ChangeRequest, statu
status <- svc.Status{State: svc.StartPending, WaitHint: uint32(setting.StartupTimeout / time.Millisecond)} status <- svc.Status{State: svc.StartPending, WaitHint: uint32(setting.StartupTimeout / time.Millisecond)}
} }
log.Trace("Awaiting server start-up")
// Now need to wait for everything to start... // Now need to wait for everything to start...
if !g.awaitServer(setting.StartupTimeout) { if !g.awaitServer(setting.StartupTimeout) {
log.Trace("... start-up failed ... Stopped")
return false, 1 return false, 1
} }
log.Trace("Sending Running state to SVC")
// We need to implement some way of svc.AcceptParamChange/svc.ParamChange // We need to implement some way of svc.AcceptParamChange/svc.ParamChange
status <- svc.Status{ status <- svc.Status{
State: svc.Running, State: svc.Running,
Accepts: svc.AcceptStop | svc.AcceptShutdown | acceptHammerCode, Accepts: svc.AcceptStop | svc.AcceptShutdown | acceptHammerCode,
} }
log.Trace("Started")
waitTime := 30 * time.Second waitTime := 30 * time.Second
loop: loop:
for { for {
select { select {
case <-g.ctx.Done(): case <-g.ctx.Done():
log.Trace("Shutting down")
g.DoGracefulShutdown() g.DoGracefulShutdown()
waitTime += setting.GracefulHammerTime waitTime += setting.GracefulHammerTime
break loop break loop
case <-g.shutdownRequested: case <-g.shutdownRequested:
log.Trace("Shutting down")
waitTime += setting.GracefulHammerTime waitTime += setting.GracefulHammerTime
break loop break loop
case change := <-changes: case change := <-changes:
switch change.Cmd { switch change.Cmd {
case svc.Interrogate: case svc.Interrogate:
log.Trace("SVC sent interrogate")
status <- change.CurrentStatus status <- change.CurrentStatus
case svc.Stop, svc.Shutdown: case svc.Stop, svc.Shutdown:
log.Trace("SVC requested shutdown - shutting down")
g.DoGracefulShutdown() g.DoGracefulShutdown()
waitTime += setting.GracefulHammerTime waitTime += setting.GracefulHammerTime
break loop break loop
case hammerCode: case hammerCode:
log.Trace("SVC requested hammer - shutting down and hammering immediately")
g.DoGracefulShutdown() g.DoGracefulShutdown()
g.DoImmediateHammer() g.DoImmediateHammer()
break loop break loop
@@ -147,8 +134,6 @@ loop:
} }
} }
} }
log.Trace("Sending StopPending state to SVC")
status <- svc.Status{ status <- svc.Status{
State: svc.StopPending, State: svc.StopPending,
WaitHint: uint32(waitTime / time.Millisecond), WaitHint: uint32(waitTime / time.Millisecond),
@@ -160,10 +145,8 @@ hammerLoop:
case change := <-changes: case change := <-changes:
switch change.Cmd { switch change.Cmd {
case svc.Interrogate: case svc.Interrogate:
log.Trace("SVC sent interrogate")
status <- change.CurrentStatus status <- change.CurrentStatus
case svc.Stop, svc.Shutdown, hammerCmd: case svc.Stop, svc.Shutdown, hammerCmd:
log.Trace("SVC requested hammer - hammering immediately")
g.DoImmediateHammer() g.DoImmediateHammer()
break hammerLoop break hammerLoop
default: default:
@@ -173,8 +156,6 @@ hammerLoop:
break hammerLoop break hammerLoop
} }
} }
log.Trace("Stopped")
return false, 0 return false, 0
} }

View File

@@ -178,7 +178,7 @@ func NewBleveIndexer(indexDir string) (*BleveIndexer, bool, error) {
func (b *BleveIndexer) addUpdate(batchWriter *io.PipeWriter, batchReader *bufio.Reader, commitSha string, update fileUpdate, repo *models.Repository, batch rupture.FlushingBatch) error { func (b *BleveIndexer) addUpdate(batchWriter *io.PipeWriter, batchReader *bufio.Reader, commitSha string, update fileUpdate, repo *models.Repository, batch rupture.FlushingBatch) error {
// Ignore vendored files in code search // Ignore vendored files in code search
if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) { if setting.Indexer.ExcludeVendored && enry.IsVendor(update.Filename) {
return nil return nil
} }

View File

@@ -177,7 +177,7 @@ func (b *ElasticSearchIndexer) init() (bool, error) {
func (b *ElasticSearchIndexer) addUpdate(batchWriter *io.PipeWriter, batchReader *bufio.Reader, sha string, update fileUpdate, repo *models.Repository) ([]elastic.BulkableRequest, error) { func (b *ElasticSearchIndexer) addUpdate(batchWriter *io.PipeWriter, batchReader *bufio.Reader, sha string, update fileUpdate, repo *models.Repository) ([]elastic.BulkableRequest, error) {
// Ignore vendored files in code search // Ignore vendored files in code search
if setting.Indexer.ExcludeVendored && analyze.IsVendor(update.Filename) { if setting.Indexer.ExcludeVendored && enry.IsVendor(update.Filename) {
return nil, nil return nil, nil
} }

View File

@@ -44,13 +44,24 @@ type ContentStore struct {
} }
// Get takes a Meta object and retrieves the content from the store, returning // Get takes a Meta object and retrieves the content from the store, returning
// it as an io.ReadSeekCloser. // it as an io.Reader. If fromByte > 0, the reader starts from that byte
func (s *ContentStore) Get(meta *models.LFSMetaObject) (storage.Object, error) { func (s *ContentStore) Get(meta *models.LFSMetaObject, fromByte int64) (io.ReadCloser, error) {
f, err := s.Open(meta.RelativePath()) f, err := s.Open(meta.RelativePath())
if err != nil { if err != nil {
log.Error("Whilst trying to read LFS OID[%s]: Unable to open Error: %v", meta.Oid, err) log.Error("Whilst trying to read LFS OID[%s]: Unable to open Error: %v", meta.Oid, err)
return nil, err return nil, err
} }
if fromByte > 0 {
if fromByte >= meta.Size {
return nil, ErrRangeNotSatisfiable{
FromByte: fromByte,
}
}
_, err = f.Seek(fromByte, io.SeekStart)
if err != nil {
log.Error("Whilst trying to read LFS OID[%s]: Unable to seek to %d Error: %v", meta.Oid, fromByte, err)
}
}
return f, err return f, err
} }
@@ -63,7 +74,7 @@ func (s *ContentStore) Put(meta *models.LFSMetaObject, r io.Reader) error {
// now pass the wrapped reader to Save - if there is a size mismatch or hash mismatch then // now pass the wrapped reader to Save - if there is a size mismatch or hash mismatch then
// the errors returned by the newHashingReader should percolate up to here // the errors returned by the newHashingReader should percolate up to here
written, err := s.Save(p, wrappedRd, meta.Size) written, err := s.Save(p, wrappedRd)
if err != nil { if err != nil {
log.Error("Whilst putting LFS OID[%s]: Failed to copy to tmpPath: %s Error: %v", meta.Oid, p, err) log.Error("Whilst putting LFS OID[%s]: Failed to copy to tmpPath: %s Error: %v", meta.Oid, p, err)
return err return err

View File

@@ -67,5 +67,5 @@ func IsPointerFile(buf *[]byte) *models.LFSMetaObject {
// ReadMetaObject will read a models.LFSMetaObject and return a reader // ReadMetaObject will read a models.LFSMetaObject and return a reader
func ReadMetaObject(meta *models.LFSMetaObject) (io.ReadCloser, error) { func ReadMetaObject(meta *models.LFSMetaObject) (io.ReadCloser, error) {
contentStore := &ContentStore{ObjectStorage: storage.LFS} contentStore := &ContentStore{ObjectStorage: storage.LFS}
return contentStore.Get(meta) return contentStore.Get(meta, 0)
} }

View File

@@ -175,11 +175,6 @@ func getContentHandler(ctx *context.Context) {
statusCode = 206 statusCode = 206
fromByte, _ = strconv.ParseInt(match[1], 10, 32) fromByte, _ = strconv.ParseInt(match[1], 10, 32)
if fromByte >= meta.Size {
writeStatus(ctx, http.StatusRequestedRangeNotSatisfiable)
return
}
if match[2] != "" { if match[2] != "" {
_toByte, _ := strconv.ParseInt(match[2], 10, 32) _toByte, _ := strconv.ParseInt(match[2], 10, 32)
if _toByte >= fromByte && _toByte < toByte { if _toByte >= fromByte && _toByte < toByte {
@@ -193,24 +188,18 @@ func getContentHandler(ctx *context.Context) {
} }
contentStore := &ContentStore{ObjectStorage: storage.LFS} contentStore := &ContentStore{ObjectStorage: storage.LFS}
content, err := contentStore.Get(meta) content, err := contentStore.Get(meta, fromByte)
if err != nil { if err != nil {
if IsErrRangeNotSatisfiable(err) {
writeStatus(ctx, http.StatusRequestedRangeNotSatisfiable)
} else {
// Errors are logged in contentStore.Get // Errors are logged in contentStore.Get
writeStatus(ctx, http.StatusNotFound) writeStatus(ctx, 404)
}
return return
} }
defer content.Close() defer content.Close()
if fromByte > 0 {
_, err = content.Seek(fromByte, io.SeekStart)
if err != nil {
log.Error("Whilst trying to read LFS OID[%s]: Unable to seek to %d Error: %v", meta.Oid, fromByte, err)
writeStatus(ctx, http.StatusInternalServerError)
return
}
}
contentLength := toByte + 1 - fromByte contentLength := toByte + 1 - fromByte
ctx.Resp.Header().Set("Content-Length", strconv.FormatInt(contentLength, 10)) ctx.Resp.Header().Set("Content-Length", strconv.FormatInt(contentLength, 10))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream") ctx.Resp.Header().Set("Content-Type", "application/octet-stream")

View File

@@ -313,7 +313,7 @@ func RenderEmoji(
return ctx.postProcess(rawHTML) return ctx.postProcess(rawHTML)
} }
var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL]\b)|(/?[hH][eE][aA][dD]\b))`) var tagCleaner = regexp.MustCompile(`<((?:/?\w+/\w+)|(?:/[\w ]+/)|(/?[hH][tT][mM][lL][ />])|(/?[hH][eE][aA][dD][ />]))`)
var nulCleaner = strings.NewReplacer("\000", "") var nulCleaner = strings.NewReplacer("\000", "")
func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) { func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
@@ -327,7 +327,7 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
_, _ = res.WriteString("<html><body>") _, _ = res.WriteString("<html><body>")
// Strip out nuls - they're always invalid // Strip out nuls - they're always invalid
_, _ = res.Write(tagCleaner.ReplaceAll([]byte(nulCleaner.Replace(string(rawHTML))), []byte("&lt;$1"))) _, _ = nulCleaner.WriteString(res, string(tagCleaner.ReplaceAll(rawHTML, []byte("&lt;$1"))))
// close the tags // close the tags
_, _ = res.WriteString("</body></html>") _, _ = res.WriteString("</body></html>")

View File

@@ -124,7 +124,7 @@ func TestRender_links(t *testing.T) {
`<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`) `<p><a href="http://www.example.com/wpstyle/?p=364" rel="nofollow">http://www.example.com/wpstyle/?p=364</a></p>`)
test( test(
"https://www.example.com/foo/?bar=baz&inga=42&quux", "https://www.example.com/foo/?bar=baz&inga=42&quux",
`<p><a href="https://www.example.com/foo/?bar=baz&inga=42&quux" rel="nofollow">https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux</a></p>`) `<p><a href="https://www.example.com/foo/?bar=baz&inga=42&quux=" rel="nofollow">https://www.example.com/foo/?bar=baz&amp;inga=42&amp;quux</a></p>`)
test( test(
"http://142.42.1.1/", "http://142.42.1.1/",
`<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`) `<p><a href="http://142.42.1.1/" rel="nofollow">http://142.42.1.1/</a></p>`)

View File

@@ -46,9 +46,7 @@ func ReplaceSanitizer() {
sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input") sanitizer.policy.AllowAttrs("checked", "disabled").OnElements("input")
// Custom URL-Schemes // Custom URL-Schemes
if len(setting.Markdown.CustomURLSchemes) > 0 {
sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...) sanitizer.policy.AllowURLSchemes(setting.Markdown.CustomURLSchemes...)
}
// Allow keyword markup // Allow keyword markup
sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span") sanitizer.policy.AllowAttrs("class").Matching(regexp.MustCompile(`^` + keywordClass + `$`)).OnElements("span")

View File

@@ -6,8 +6,6 @@
package markup package markup
import ( import (
"html/template"
"strings"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -52,13 +50,3 @@ func Test_Sanitizer(t *testing.T) {
assert.Equal(t, testCases[i+1], string(SanitizeBytes([]byte(testCases[i])))) assert.Equal(t, testCases[i+1], string(SanitizeBytes([]byte(testCases[i]))))
} }
} }
func TestSanitizeNonEscape(t *testing.T) {
descStr := "<scrİpt>&lt;script&gt;alert(document.domain)&lt;/script&gt;</scrİpt>"
output := template.HTML(Sanitize(string(descStr)))
if strings.Contains(string(output), "<script>") {
t.Errorf("un-escaped <script> in output: %q", output)
}
}

View File

@@ -525,6 +525,9 @@ func (g *GiteaDownloader) GetPullRequests(page, perPage int) ([]*base.PullReques
headRepoName = pr.Head.Repository.Name headRepoName = pr.Head.Repository.Name
headCloneURL = pr.Head.Repository.CloneURL headCloneURL = pr.Head.Repository.CloneURL
} }
if err := fixPullHeadSha(g.client, pr); err != nil {
return nil, false, fmt.Errorf("error while resolving head git ref: %s for pull #%d. Error: %v", pr.Head.Ref, pr.Index, err)
}
headSHA = pr.Head.Sha headSHA = pr.Head.Sha
headRef = pr.Head.Ref headRef = pr.Head.Ref
} }
@@ -676,3 +679,22 @@ func (g *GiteaDownloader) GetReviews(index int64) ([]*base.Review, error) {
} }
return allReviews, nil return allReviews, nil
} }
// fixPullHeadSha is a workaround for https://github.com/go-gitea/gitea/issues/12675
// When no head sha is available, this is because the branch got deleted in the base repo.
// pr.Head.Ref points in this case not to the head repo branch name, but the base repo ref,
// which stays available to resolve the commit sha.
func fixPullHeadSha(client *gitea_sdk.Client, pr *gitea_sdk.PullRequest) error {
owner := pr.Base.Repository.Owner.UserName
repo := pr.Base.Repository.Name
if pr.Head != nil && pr.Head.Sha == "" {
refs, _, err := client.GetRepoRefs(owner, repo, pr.Head.Ref)
if err != nil {
return err
} else if len(refs) == 0 {
return fmt.Errorf("unable to resolve PR ref '%s'", pr.Head.Ref)
}
pr.Head.Sha = refs[0].Object.SHA
}
return nil
}

View File

@@ -283,7 +283,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
} }
} }
defer rc.Close() defer rc.Close()
_, err = storage.Attachments.Save(attach.RelativePath(), rc, int64(*asset.Size)) _, err = storage.Attachments.Save(attach.RelativePath(), rc)
return err return err
}() }()
if err != nil { if err != nil {

View File

@@ -132,11 +132,6 @@ func (g *GithubDownloaderV3) sleep() {
func (g *GithubDownloaderV3) RefreshRate() error { func (g *GithubDownloaderV3) RefreshRate() error {
rates, _, err := g.client.RateLimits(g.ctx) rates, _, err := g.client.RateLimits(g.ctx)
if err != nil { if err != nil {
// if rate limit is not enabled, ignore it
if strings.Contains(err.Error(), "404") {
g.rate = nil
return nil
}
return err return err
} }

View File

@@ -332,8 +332,7 @@ func (a *actionNotifier) NotifyPushCommits(pusher *models.User, repo *models.Rep
func (a *actionNotifier) NotifyCreateRef(doer *models.User, repo *models.Repository, refType, refFullName string) { func (a *actionNotifier) NotifyCreateRef(doer *models.User, repo *models.Repository, refType, refFullName string) {
opType := models.ActionCommitRepo opType := models.ActionCommitRepo
if refType == "tag" { if refType == "tag" {
// has sent same action in `NotifyPushCommits`, so skip it. opType = models.ActionPushTag
return
} }
if err := models.NotifyWatchers(&models.Action{ if err := models.NotifyWatchers(&models.Action{
ActUserID: doer.ID, ActUserID: doer.ID,
@@ -351,8 +350,7 @@ func (a *actionNotifier) NotifyCreateRef(doer *models.User, repo *models.Reposit
func (a *actionNotifier) NotifyDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) { func (a *actionNotifier) NotifyDeleteRef(doer *models.User, repo *models.Repository, refType, refFullName string) {
opType := models.ActionDeleteBranch opType := models.ActionDeleteBranch
if refType == "tag" { if refType == "tag" {
// has sent same action in `NotifyPushCommits`, so skip it. opType = models.ActionDeleteTag
return
} }
if err := models.NotifyWatchers(&models.Action{ if err := models.NotifyWatchers(&models.Action{
ActUserID: doer.ID, ActUserID: doer.ID,

View File

@@ -27,7 +27,6 @@ type Options struct {
// KnownPublicEntries list all direct children in the `public` directory // KnownPublicEntries list all direct children in the `public` directory
var KnownPublicEntries = []string{ var KnownPublicEntries = []string{
"css", "css",
"fonts",
"img", "img",
"js", "js",
"serviceworker.js", "serviceworker.js",

View File

@@ -174,7 +174,6 @@ func (m *Manager) FlushAll(baseCtx context.Context, timeout time.Duration) error
default: default:
} }
mqs := m.ManagedQueues() mqs := m.ManagedQueues()
log.Debug("Found %d Managed Queues", len(mqs))
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(len(mqs)) wg.Add(len(mqs))
allEmpty := true allEmpty := true
@@ -185,7 +184,6 @@ func (m *Manager) FlushAll(baseCtx context.Context, timeout time.Duration) error
} }
allEmpty = false allEmpty = false
if flushable, ok := mq.Managed.(Flushable); ok { if flushable, ok := mq.Managed.(Flushable); ok {
log.Debug("Flushing (flushable) queue: %s", mq.Name)
go func(q *ManagedQueue) { go func(q *ManagedQueue) {
localCtx, localCancel := context.WithCancel(ctx) localCtx, localCancel := context.WithCancel(ctx)
pid := q.RegisterWorkers(1, start, hasTimeout, end, localCancel, true) pid := q.RegisterWorkers(1, start, hasTimeout, end, localCancel, true)
@@ -198,11 +196,7 @@ func (m *Manager) FlushAll(baseCtx context.Context, timeout time.Duration) error
wg.Done() wg.Done()
}(mq) }(mq)
} else { } else {
log.Debug("Queue: %s is non-empty but is not flushable - adding 100 millisecond wait", mq.Name)
go func() {
<-time.After(100 * time.Millisecond)
wg.Done() wg.Done()
}()
} }
} }

View File

@@ -99,8 +99,38 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
} }
// Copy uploaded files into repository. // Copy uploaded files into repository.
for i := range infos { for i, uploadInfo := range infos {
if err := copyUploadedLFSFileIntoRepository(&infos[i], filename2attribute2info, t, opts.TreePath); err != nil { file, err := os.Open(uploadInfo.upload.LocalPath())
if err != nil {
return err
}
defer file.Close()
var objectHash string
if setting.LFS.StartServer && filename2attribute2info[uploadInfo.upload.Name] != nil && filename2attribute2info[uploadInfo.upload.Name]["filter"] == "lfs" {
// Handle LFS
// FIXME: Inefficient! this should probably happen in models.Upload
oid, err := models.GenerateLFSOid(file)
if err != nil {
return err
}
fileInfo, err := file.Stat()
if err != nil {
return err
}
uploadInfo.lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: fileInfo.Size(), RepositoryID: t.repo.ID}
if objectHash, err = t.HashObject(strings.NewReader(uploadInfo.lfsMetaObject.Pointer())); err != nil {
return err
}
infos[i] = uploadInfo
} else if objectHash, err = t.HashObject(file); err != nil {
return err
}
// Add the object to the index
if err := t.AddObjectToIndex("100644", objectHash, path.Join(opts.TreePath, uploadInfo.upload.Name)); err != nil {
return err return err
} }
} }
@@ -122,11 +152,11 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
} }
// Now deal with LFS objects // Now deal with LFS objects
for i := range infos { for _, uploadInfo := range infos {
if infos[i].lfsMetaObject == nil { if uploadInfo.lfsMetaObject == nil {
continue continue
} }
infos[i].lfsMetaObject, err = models.NewLFSMetaObject(infos[i].lfsMetaObject) uploadInfo.lfsMetaObject, err = models.NewLFSMetaObject(uploadInfo.lfsMetaObject)
if err != nil { if err != nil {
// OK Now we need to cleanup // OK Now we need to cleanup
return cleanUpAfterFailure(&infos, t, err) return cleanUpAfterFailure(&infos, t, err)
@@ -152,39 +182,6 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
return models.DeleteUploads(uploads...) return models.DeleteUploads(uploads...)
} }
func copyUploadedLFSFileIntoRepository(info *uploadInfo, filename2attribute2info map[string]map[string]string, t *TemporaryUploadRepository, treePath string) error {
file, err := os.Open(info.upload.LocalPath())
if err != nil {
return err
}
defer file.Close()
var objectHash string
if setting.LFS.StartServer && filename2attribute2info[info.upload.Name] != nil && filename2attribute2info[info.upload.Name]["filter"] == "lfs" {
// Handle LFS
// FIXME: Inefficient! this should probably happen in models.Upload
oid, err := models.GenerateLFSOid(file)
if err != nil {
return err
}
fileInfo, err := file.Stat()
if err != nil {
return err
}
info.lfsMetaObject = &models.LFSMetaObject{Oid: oid, Size: fileInfo.Size(), RepositoryID: t.repo.ID}
if objectHash, err = t.HashObject(strings.NewReader(info.lfsMetaObject.Pointer())); err != nil {
return err
}
} else if objectHash, err = t.HashObject(file); err != nil {
return err
}
// Add the object to the index
return t.AddObjectToIndex("100644", objectHash, path.Join(treePath, info.upload.Name))
}
func uploadToLFSContentStore(info uploadInfo, contentStore *lfs.ContentStore) error { func uploadToLFSContentStore(info uploadInfo, contentStore *lfs.ContentStore) error {
if info.lfsMetaObject == nil { if info.lfsMetaObject == nil {
return nil return nil

View File

@@ -64,12 +64,6 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
return err return err
} }
// copy lfs files failure should not be ignored
if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
rollbackRemoveFn()
return err
}
repoPath := models.RepoPath(owner.Name, repo.Name) repoPath := models.RepoPath(owner.Name, repo.Name)
if stdout, err := git.NewCommand( if stdout, err := git.NewCommand(
"clone", "--bare", oldRepoPath, repoPath). "clone", "--bare", oldRepoPath, repoPath).
@@ -98,7 +92,6 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
return nil, err return nil, err
} }
// even if below operations failed, it could be ignored. And they will be retried
ctx := models.DefaultDBContext() ctx := models.DefaultDBContext()
if err = repo.UpdateSize(ctx); err != nil { if err = repo.UpdateSize(ctx); err != nil {
log.Error("Failed to update size for repository: %v", err) log.Error("Failed to update size for repository: %v", err)
@@ -107,5 +100,11 @@ func ForkRepository(doer, owner *models.User, oldRepo *models.Repository, name,
log.Error("Copy language stat from oldRepo failed") log.Error("Copy language stat from oldRepo failed")
} }
if err := models.CopyLFS(ctx, repo, oldRepo); err != nil {
if errDelete := models.DeleteRepository(doer, owner.ID, repo.ID); errDelete != nil {
log.Error("Rollback deleteRepository: %v", errDelete)
}
return nil, err
}
return repo, nil return repo, nil
} }

View File

@@ -66,7 +66,7 @@ func (l *LocalStorage) Open(path string) (Object, error) {
} }
// Save a file // Save a file
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) { func (l *LocalStorage) Save(path string, r io.Reader) (int64, error) {
p := filepath.Join(l.dir, path) p := filepath.Join(l.dir, path)
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil { if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
return 0, err return 0, err

View File

@@ -131,13 +131,13 @@ func (m *MinioStorage) Open(path string) (Object, error) {
} }
// Save save a file to minio // Save save a file to minio
func (m *MinioStorage) Save(path string, r io.Reader, size int64) (int64, error) { func (m *MinioStorage) Save(path string, r io.Reader) (int64, error) {
uploadInfo, err := m.client.PutObject( uploadInfo, err := m.client.PutObject(
m.ctx, m.ctx,
m.bucket, m.bucket,
m.buildMinioPath(path), m.buildMinioPath(path),
r, r,
size, -1,
minio.PutObjectOptions{ContentType: "application/octet-stream"}, minio.PutObjectOptions{ContentType: "application/octet-stream"},
) )
if err != nil { if err != nil {

View File

@@ -65,8 +65,7 @@ type Object interface {
// ObjectStorage represents an object storage to handle a bucket and files // ObjectStorage represents an object storage to handle a bucket and files
type ObjectStorage interface { type ObjectStorage interface {
Open(path string) (Object, error) Open(path string) (Object, error)
// Save store a object, if size is unknown set -1 Save(path string, r io.Reader) (int64, error)
Save(path string, r io.Reader, size int64) (int64, error)
Stat(path string) (os.FileInfo, error) Stat(path string) (os.FileInfo, error)
Delete(path string) error Delete(path string) error
URL(path, name string) (*url.URL, error) URL(path, name string) (*url.URL, error)
@@ -81,13 +80,7 @@ func Copy(dstStorage ObjectStorage, dstPath string, srcStorage ObjectStorage, sr
} }
defer f.Close() defer f.Close()
size := int64(-1) return dstStorage.Save(dstPath, f)
fsinfo, err := f.Stat()
if err == nil {
size = fsinfo.Size()
}
return dstStorage.Save(dstPath, f, size)
} }
// SaveFrom saves data to the ObjectStorage with path p from the callback // SaveFrom saves data to the ObjectStorage with path p from the callback
@@ -101,7 +94,7 @@ func SaveFrom(objStorage ObjectStorage, p string, callback func(w io.Writer) err
} }
}() }()
_, err := objStorage.Save(p, pr, -1) _, err := objStorage.Save(p, pr)
return err return err
} }

View File

@@ -29,7 +29,6 @@ type LangType struct {
var ( var (
matcher language.Matcher matcher language.Matcher
allLangs []LangType allLangs []LangType
supportedTags []language.Tag
) )
// AllLangs returns all supported langauages // AllLangs returns all supported langauages
@@ -52,12 +51,12 @@ func InitLocales() {
} }
} }
supportedTags = make([]language.Tag, len(setting.Langs)) tags := make([]language.Tag, len(setting.Langs))
for i, lang := range setting.Langs { for i, lang := range setting.Langs {
supportedTags[i] = language.Raw.Make(lang) tags[i] = language.Raw.Make(lang)
} }
matcher = language.NewMatcher(supportedTags) matcher = language.NewMatcher(tags)
for i := range setting.Names { for i := range setting.Names {
key := "locale_" + setting.Langs[i] + ".ini" key := "locale_" + setting.Langs[i] + ".ini"
if err = i18n.SetMessageWithDesc(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil { if err = i18n.SetMessageWithDesc(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
@@ -80,9 +79,8 @@ func InitLocales() {
} }
// Match matches accept languages // Match matches accept languages
func Match(tags ...language.Tag) language.Tag { func Match(tags ...language.Tag) (tag language.Tag, index int, c language.Confidence) {
_, i, _ := matcher.Match(tags...) return matcher.Match(tags...)
return supportedTags[i]
} }
// locale represents the information of localization. // locale represents the information of localization.

View File

@@ -38,7 +38,7 @@ func Locale(resp http.ResponseWriter, req *http.Request) translation.Locale {
// The first element in the list is chosen to be the default language automatically. // The first element in the list is chosen to be the default language automatically.
if len(lang) == 0 { if len(lang) == 0 {
tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language")) tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language"))
tag := translation.Match(tags...) tag, _, _ := translation.Match(tags...)
lang = tag.String() lang = tag.String()
} }

View File

@@ -68,11 +68,10 @@ func Wrap(handlers ...interface{}) http.HandlerFunc {
} }
case func(http.Handler) http.Handler: case func(http.Handler) http.Handler:
var next = http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) var next = http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
if len(handlers) > i+1 {
next = Wrap(handlers[i+1:]...)
}
t(next).ServeHTTP(resp, req) t(next).ServeHTTP(resp, req)
if r, ok := resp.(context.ResponseWriter); ok && r.Status() > 0 {
return return
}
default: default:
panic(fmt.Sprintf("Unsupported handler type: %#v", t)) panic(fmt.Sprintf("Unsupported handler type: %#v", t))
} }

View File

@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
issue_indexer "code.gitea.io/gitea/modules/indexer/issues" issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
@@ -112,7 +113,11 @@ func SearchIssues(ctx *context.APIContext) {
} }
// find repos user can access (for issue search) // find repos user can access (for issue search)
repoIDs := make([]int64, 0)
opts := &models.SearchRepoOptions{ opts := &models.SearchRepoOptions{
ListOptions: models.ListOptions{
PageSize: 15,
},
Private: false, Private: false,
AllPublic: true, AllPublic: true,
TopicOnly: false, TopicOnly: false,
@@ -127,12 +132,23 @@ func SearchIssues(ctx *context.APIContext) {
opts.AllLimited = true opts.AllLimited = true
} }
repoIDs, _, err := models.SearchRepositoryIDs(opts) for page := 1; ; page++ {
opts.Page = page
repos, count, err := models.SearchRepositoryByName(opts)
if err != nil { if err != nil {
ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err) ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err)
return return
} }
if len(repos) == 0 {
break
}
log.Trace("Processing next %d repos of %d", len(repos), count)
for _, repo := range repos {
repoIDs = append(repoIDs, repo.ID)
}
}
var issues []*models.Issue var issues []*models.Issue
var filteredCount int64 var filteredCount int64
@@ -141,6 +157,7 @@ func SearchIssues(ctx *context.APIContext) {
keyword = "" keyword = ""
} }
var issueIDs []int64 var issueIDs []int64
var labelIDs []int64
if len(keyword) > 0 && len(repoIDs) > 0 { if len(keyword) > 0 && len(repoIDs) > 0 {
if issueIDs, err = issue_indexer.SearchIssuesByKeyword(repoIDs, keyword); err != nil { if issueIDs, err = issue_indexer.SearchIssuesByKeyword(repoIDs, keyword); err != nil {
ctx.Error(http.StatusInternalServerError, "SearchIssuesByKeyword", err) ctx.Error(http.StatusInternalServerError, "SearchIssuesByKeyword", err)
@@ -175,7 +192,7 @@ func SearchIssues(ctx *context.APIContext) {
// Only fetch the issues if we either don't have a keyword or the search returned issues // Only fetch the issues if we either don't have a keyword or the search returned issues
// This would otherwise return all issues if no issues were found by the search. // This would otherwise return all issues if no issues were found by the search.
if len(keyword) == 0 || len(issueIDs) > 0 || len(includedLabelNames) > 0 { if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
issuesOpt := &models.IssuesOptions{ issuesOpt := &models.IssuesOptions{
ListOptions: models.ListOptions{ ListOptions: models.ListOptions{
Page: ctx.QueryInt("page"), Page: ctx.QueryInt("page"),

View File

@@ -274,11 +274,7 @@ func DeleteOauth2Application(ctx *context.APIContext) {
// "$ref": "#/responses/empty" // "$ref": "#/responses/empty"
appID := ctx.ParamsInt64(":id") appID := ctx.ParamsInt64(":id")
if err := models.DeleteOAuth2Application(appID, ctx.User.ID); err != nil { if err := models.DeleteOAuth2Application(appID, ctx.User.ID); err != nil {
if models.IsErrOAuthApplicationNotFound(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "DeleteOauth2ApplicationByID", err) ctx.Error(http.StatusInternalServerError, "DeleteOauth2ApplicationByID", err)
}
return return
} }

View File

@@ -30,17 +30,6 @@ func Events(ctx *context.Context) {
ctx.Resp.Header().Set("X-Accel-Buffering", "no") ctx.Resp.Header().Set("X-Accel-Buffering", "no")
ctx.Resp.WriteHeader(http.StatusOK) ctx.Resp.WriteHeader(http.StatusOK)
if !ctx.IsSigned {
// Return unauthorized status event
event := (&eventsource.Event{
Name: "close",
Data: "unauthorized",
})
_, _ = event.WriteTo(ctx)
ctx.Resp.Flush()
return
}
// Listen to connection close and un-register messageChan // Listen to connection close and un-register messageChan
notify := ctx.Req.Context().Done() notify := ctx.Req.Context().Done()
ctx.Resp.Flush() ctx.Resp.Flush()

View File

@@ -6,7 +6,6 @@
package repo package repo
import ( import (
"errors"
"path" "path"
"strings" "strings"
@@ -390,11 +389,6 @@ func RawDiff(ctx *context.Context) {
git.RawDiffType(ctx.Params(":ext")), git.RawDiffType(ctx.Params(":ext")),
ctx.Resp, ctx.Resp,
); err != nil { ); err != nil {
if git.IsErrNotExist(err) {
ctx.NotFound("GetRawDiff",
errors.New("commit "+ctx.Params(":sha")+" does not exist."))
return
}
ctx.ServerError("GetRawDiff", err) ctx.ServerError("GetRawDiff", err)
return return
} }

View File

@@ -431,16 +431,12 @@ func PrepareCompareDiff(
ctx.Data["IsNothingToCompare"] = true ctx.Data["IsNothingToCompare"] = true
if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil { if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
config := unit.PullRequestsConfig() config := unit.PullRequestsConfig()
if !config.AutodetectManualMerge { if !config.AutodetectManualMerge {
allowEmptyPr := !(baseBranch == headBranch && ctx.Repo.Repository.Name == headRepo.Name) ctx.Data["AllowEmptyPr"] = !(baseBranch == headBranch && ctx.Repo.Repository.Name == headRepo.Name)
ctx.Data["AllowEmptyPr"] = allowEmptyPr } else {
return !allowEmptyPr
}
ctx.Data["AllowEmptyPr"] = false ctx.Data["AllowEmptyPr"] = false
} }
}
return true return true
} }

View File

@@ -103,11 +103,9 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
isWiki := false isWiki := false
var unitType = models.UnitTypeCode var unitType = models.UnitTypeCode
var wikiRepoName string
if strings.HasSuffix(reponame, ".wiki") { if strings.HasSuffix(reponame, ".wiki") {
isWiki = true isWiki = true
unitType = models.UnitTypeWiki unitType = models.UnitTypeWiki
wikiRepoName = reponame
reponame = reponame[:len(reponame)-5] reponame = reponame[:len(reponame)-5]
} }
@@ -316,11 +314,6 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
return return
} }
if isWiki { // you cannot send wiki operation before create the repository
ctx.HandleText(http.StatusNotFound, "Repository not found")
return
}
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg { if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.") ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
return return
@@ -370,9 +363,6 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name r.URL.Path = strings.ToLower(r.URL.Path) // blue: In case some repo name has upper case name
dir := models.RepoPath(username, reponame) dir := models.RepoPath(username, reponame)
if isWiki {
dir = models.RepoPath(username, wikiRepoName)
}
return &serviceHandler{cfg, w, r, dir, cfg.Env} return &serviceHandler{cfg, w, r, dir, cfg.Env}
} }

View File

@@ -241,13 +241,14 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
} }
} }
var issueList = models.IssueList(issues) approvalCounts, err := models.IssueList(issues).GetApprovalCounts()
approvalCounts, err := issueList.GetApprovalCounts()
if err != nil { if err != nil {
ctx.ServerError("ApprovalCounts", err) ctx.ServerError("ApprovalCounts", err)
return return
} }
var commitStatus = make(map[int64]*models.CommitStatus, len(issues))
// Get posters. // Get posters.
for i := range issues { for i := range issues {
// Check read status // Check read status
@@ -257,12 +258,16 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
ctx.ServerError("GetIsRead", err) ctx.ServerError("GetIsRead", err)
return return
} }
if issues[i].IsPull {
if err := issues[i].LoadPullRequest(); err != nil {
ctx.ServerError("LoadPullRequest", err)
return
} }
commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues) var statuses, _ = pull_service.GetLastCommitStatus(issues[i].PullRequest)
if err != nil { commitStatus[issues[i].PullRequest.ID] = models.CalcCommitStatus(statuses)
ctx.ServerError("GetIssuesLastCommitStatus", err) }
return
} }
ctx.Data["Issues"] = issues ctx.Data["Issues"] = issues

View File

@@ -192,9 +192,6 @@ func CreatePost(ctx *context.Context) {
ctx.Data["Licenses"] = models.Licenses ctx.Data["Licenses"] = models.Licenses
ctx.Data["Readmes"] = models.Readmes ctx.Data["Readmes"] = models.Readmes
ctx.Data["CanCreateRepo"] = ctx.User.CanCreateRepo()
ctx.Data["MaxCreationLimit"] = ctx.User.MaxCreationLimit()
ctxUser := checkContextUser(ctx, form.UID) ctxUser := checkContextUser(ctx, form.UID)
if ctx.Written() { if ctx.Written() {
return return

View File

@@ -5,6 +5,7 @@
package repo package repo
import ( import (
"path"
"strings" "strings"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
@@ -39,7 +40,7 @@ func Search(ctx *context.Context) {
ctx.Data["Keyword"] = keyword ctx.Data["Keyword"] = keyword
ctx.Data["Language"] = language ctx.Data["Language"] = language
ctx.Data["queryType"] = queryType ctx.Data["queryType"] = queryType
ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL() ctx.Data["SourcePath"] = path.Join(setting.AppSubURL, ctx.Repo.Repository.Owner.Name, ctx.Repo.Repository.Name)
ctx.Data["SearchResults"] = searchResults ctx.Data["SearchResults"] = searchResults
ctx.Data["SearchResultLanguages"] = searchResultLanguages ctx.Data["SearchResultLanguages"] = searchResultLanguages
ctx.Data["RequireHighlightJS"] = true ctx.Data["RequireHighlightJS"] = true

View File

@@ -11,7 +11,6 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"path/filepath"
"strings" "strings"
"time" "time"
@@ -88,21 +87,13 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
return return
} }
prefix := strings.Trim(prefix, "/") if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) {
if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") {
next.ServeHTTP(w, req) next.ServeHTTP(w, req)
return return
} }
rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/") rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix)
rPath = strings.TrimPrefix(rPath, "/") rPath = strings.TrimPrefix(rPath, "/")
if rPath == "" {
http.Error(w, "file not found", 404)
return
}
rPath = path.Clean("/" + filepath.ToSlash(rPath))
rPath = rPath[1:]
fi, err := objStore.Stat(rPath) fi, err := objStore.Stat(rPath)
if err == nil && httpcache.HandleTimeCache(req, w, fi) { if err == nil && httpcache.HandleTimeCache(req, w, fi) {

View File

@@ -168,6 +168,15 @@ func WebRoutes() *web.Route {
r.Use(h) r.Use(h)
} }
if (setting.Protocol == setting.FCGI || setting.Protocol == setting.FCGIUnix) && setting.AppSubURL != "" {
r.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
req.URL.Path = strings.TrimPrefix(req.URL.Path, setting.AppSubURL)
next.ServeHTTP(resp, req)
})
})
}
mailer.InitMailRender(templates.Mailer()) mailer.InitMailRender(templates.Mailer())
if setting.Service.EnableCaptcha { if setting.Service.EnableCaptcha {
@@ -391,7 +400,7 @@ func RegisterRoutes(m *web.Route) {
}) })
}, reqSignOut) }, reqSignOut)
m.Any("/user/events", events.Events) m.Any("/user/events", reqSignIn, events.Events)
m.Group("/login/oauth", func() { m.Group("/login/oauth", func() {
m.Get("/authorize", bindIgnErr(auth.AuthorizationForm{}), user.AuthorizeOAuth) m.Get("/authorize", bindIgnErr(auth.AuthorizationForm{}), user.AuthorizeOAuth)
@@ -691,7 +700,7 @@ func RegisterRoutes(m *web.Route) {
}, reqSignIn) }, reqSignIn)
// ***** Release Attachment Download without Signin // ***** Release Attachment Download without Signin
m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload) m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment(), repo.MustBeNotEmpty, repo.RedirectDownload)
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
m.Group("/settings", func() { m.Group("/settings", func() {
@@ -771,9 +780,9 @@ func RegisterRoutes(m *web.Route) {
ctx.Data["PageIsSettings"] = true ctx.Data["PageIsSettings"] = true
ctx.Data["LFSStartServer"] = setting.LFS.StartServer ctx.Data["LFSStartServer"] = setting.LFS.StartServer
}) })
}, reqSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoAdmin, context.RepoRef()) }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef())
m.Post("/{username}/{reponame}/action/{action}", reqSignIn, context.RepoAssignment, context.UnitTypes(), repo.Action) m.Post("/{username}/{reponame}/action/{action}", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)
// Grouping for those endpoints not requiring authentication // Grouping for those endpoints not requiring authentication
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
@@ -783,7 +792,7 @@ func RegisterRoutes(m *web.Route) {
m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists). m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
Get(ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff). Get(ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost) Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
}, context.RepoAssignment, context.UnitTypes()) }, context.RepoAssignment(), context.UnitTypes())
// Grouping for those endpoints that do require authentication // Grouping for those endpoints that do require authentication
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
@@ -890,7 +899,7 @@ func RegisterRoutes(m *web.Route) {
m.Post("/restore", repo.RestoreBranchPost) m.Post("/restore", repo.RestoreBranchPost)
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty) }, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
}, reqSignIn, context.RepoAssignment, context.UnitTypes()) }, reqSignIn, context.RepoAssignment(), context.UnitTypes())
// Releases // Releases
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
@@ -928,11 +937,11 @@ func RegisterRoutes(m *web.Route) {
} }
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
}) })
}, ignSignIn, context.RepoAssignment, context.UnitTypes(), reqRepoReleaseReader) }, ignSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoReleaseReader)
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
m.Post("/topics", repo.TopicsPost) m.Post("/topics", repo.TopicsPost)
}, context.RepoAssignment, context.RepoMustNotBeArchived(), reqRepoAdmin) }, context.RepoAssignment(), context.RepoMustNotBeArchived(), reqRepoAdmin)
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
m.Group("", func() { m.Group("", func() {
@@ -1080,17 +1089,17 @@ func RegisterRoutes(m *web.Route) {
}, context.RepoRef(), reqRepoCodeReader) }, context.RepoRef(), reqRepoCodeReader)
m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}", m.Get("/commit/{sha:([a-f0-9]{7,40})}.{ext:patch|diff}",
repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff) repo.MustBeNotEmpty, reqRepoCodeReader, repo.RawDiff)
}, ignSignIn, context.RepoAssignment, context.UnitTypes()) }, ignSignIn, context.RepoAssignment(), context.UnitTypes())
m.Group("/{username}/{reponame}", func() { m.Group("/{username}/{reponame}", func() {
m.Get("/stars", repo.Stars) m.Get("/stars", repo.Stars)
m.Get("/watchers", repo.Watchers) m.Get("/watchers", repo.Watchers)
m.Get("/search", reqRepoCodeReader, repo.Search) m.Get("/search", reqRepoCodeReader, repo.Search)
}, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes()) }, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
m.Group("/{username}", func() { m.Group("/{username}", func() {
m.Group("/{reponame}", func() { m.Group("/{reponame}", func() {
m.Get("", repo.SetEditorconfigIfExists, repo.Home) m.Get("", repo.SetEditorconfigIfExists, repo.Home)
}, goGet, ignSignIn, context.RepoAssignment, context.RepoRef(), context.UnitTypes()) }, goGet, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
m.Group("/{reponame}", func() { m.Group("/{reponame}", func() {
m.Group("/info/lfs", func() { m.Group("/info/lfs", func() {

View File

@@ -7,14 +7,12 @@ package user
import ( import (
"errors" "errors"
"net/url" "net/url"
"path"
"strconv" "strconv"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
) )
// Avatar redirect browser to user avatar of requested size // Avatar redirect browser to user avatar of requested size
@@ -72,8 +70,6 @@ func AvatarByEmailHash(ctx *context.Context) {
} }
var avatarURL *url.URL var avatarURL *url.URL
if setting.EnableFederatedAvatar && setting.LibravatarService != nil {
avatarURL, err = models.LibravatarURL(email) avatarURL, err = models.LibravatarURL(email)
if err != nil { if err != nil {
avatarURL, err = url.Parse(models.DefaultAvatarLink()) avatarURL, err = url.Parse(models.DefaultAvatarLink())
@@ -82,17 +78,6 @@ func AvatarByEmailHash(ctx *context.Context) {
return return
} }
} }
} else if !setting.DisableGravatar {
copyOfGravatarSourceURL := *setting.GravatarSourceURL
avatarURL = &copyOfGravatarSourceURL
avatarURL.Path = path.Join(avatarURL.Path, hash)
} else {
avatarURL, err = url.Parse(models.DefaultAvatarLink())
if err != nil {
ctx.ServerError("invalid default avatar url", err)
return
}
}
ctx.Redirect(models.MakeFinalAvatarURL(avatarURL, size)) ctx.Redirect(models.MakeFinalAvatarURL(avatarURL, size))
} }

View File

@@ -546,14 +546,14 @@ func buildIssueOverview(ctx *context.Context, unitType models.UnitType) {
} }
// maps pull request IDs to their CommitStatus. Will be posted to ctx.Data. // maps pull request IDs to their CommitStatus. Will be posted to ctx.Data.
var commitStatus = make(map[int64]*models.CommitStatus, len(issues))
for _, issue := range issues { for _, issue := range issues {
issue.Repo = showReposMap[issue.RepoID] issue.Repo = showReposMap[issue.RepoID]
}
commitStatus, err := pull_service.GetIssuesLastCommitStatus(issues) if isPullList {
if err != nil { var statuses, _ = pull_service.GetLastCommitStatus(issue.PullRequest)
ctx.ServerError("GetIssuesLastCommitStatus", err) commitStatus[issue.PullRequest.ID] = models.CalcCommitStatus(statuses)
return }
} }
// ------------------------------- // -------------------------------

View File

@@ -1014,11 +1014,6 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
} }
diffLine := &DiffLine{Type: DiffLineAdd, RightIdx: rightLine} diffLine := &DiffLine{Type: DiffLineAdd, RightIdx: rightLine}
rightLine++ rightLine++
if curSection == nil {
// Create a new section to represent this hunk
curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection)
}
curSection.Lines = append(curSection.Lines, diffLine) curSection.Lines = append(curSection.Lines, diffLine)
case '-': case '-':
curFileLinesCount++ curFileLinesCount++
@@ -1031,11 +1026,6 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
if leftLine > 0 { if leftLine > 0 {
leftLine++ leftLine++
} }
if curSection == nil {
// Create a new section to represent this hunk
curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection)
}
curSection.Lines = append(curSection.Lines, diffLine) curSection.Lines = append(curSection.Lines, diffLine)
case ' ': case ' ':
curFileLinesCount++ curFileLinesCount++
@@ -1046,11 +1036,6 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
diffLine := &DiffLine{Type: DiffLinePlain, LeftIdx: leftLine, RightIdx: rightLine} diffLine := &DiffLine{Type: DiffLinePlain, LeftIdx: leftLine, RightIdx: rightLine}
leftLine++ leftLine++
rightLine++ rightLine++
if curSection == nil {
// Create a new section to represent this hunk
curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection)
}
curSection.Lines = append(curSection.Lines, diffLine) curSection.Lines = append(curSection.Lines, diffLine)
default: default:
// This is unexpected // This is unexpected
@@ -1303,14 +1288,6 @@ func CommentAsDiff(c *models.Comment) (*Diff, error) {
// CommentMustAsDiff executes AsDiff and logs the error instead of returning // CommentMustAsDiff executes AsDiff and logs the error instead of returning
func CommentMustAsDiff(c *models.Comment) *Diff { func CommentMustAsDiff(c *models.Comment) *Diff {
if c == nil {
return nil
}
defer func() {
if err := recover(); err != nil {
log.Error("PANIC whilst retrieving diff for comment[%d] Error: %v\nStack: %s", c.ID, err, log.Stack(2))
}
}()
diff, err := CommentAsDiff(c) diff, err := CommentAsDiff(c)
if err != nil { if err != nil {
log.Warn("CommentMustAsDiff: %v", err) log.Warn("CommentMustAsDiff: %v", err)

View File

@@ -64,7 +64,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
pr.Merger = doer pr.Merger = doer
pr.MergerID = doer.ID pr.MergerID = doer.ID
if _, err := pr.SetMerged(); err != nil { if _, err = pr.SetMerged(); err != nil {
log.Error("setMerged [%d]: %v", pr.ID, err) log.Error("setMerged [%d]: %v", pr.ID, err)
} }

View File

@@ -8,6 +8,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@@ -642,74 +643,33 @@ func GetSquashMergeCommitMessages(pr *models.PullRequest) string {
return stringBuilder.String() return stringBuilder.String()
} }
// GetIssuesLastCommitStatus returns a map
func GetIssuesLastCommitStatus(issues models.IssueList) (map[int64]*models.CommitStatus, error) {
if err := issues.LoadPullRequests(); err != nil {
return nil, err
}
if _, err := issues.LoadRepositories(); err != nil {
return nil, err
}
var (
gitRepos = make(map[int64]*git.Repository)
res = make(map[int64]*models.CommitStatus)
err error
)
defer func() {
for _, gitRepo := range gitRepos {
gitRepo.Close()
}
}()
for _, issue := range issues {
if !issue.IsPull {
continue
}
gitRepo, ok := gitRepos[issue.RepoID]
if !ok {
gitRepo, err = git.OpenRepository(issue.Repo.RepoPath())
if err != nil {
return nil, err
}
gitRepos[issue.RepoID] = gitRepo
}
status, err := getLastCommitStatus(gitRepo, issue.PullRequest)
if err != nil {
return nil, err
}
res[issue.PullRequest.ID] = status
}
return res, nil
}
// GetLastCommitStatus returns list of commit statuses for latest commit on this pull request. // GetLastCommitStatus returns list of commit statuses for latest commit on this pull request.
func GetLastCommitStatus(pr *models.PullRequest) (status *models.CommitStatus, err error) { func GetLastCommitStatus(pr *models.PullRequest) (status []*models.CommitStatus, err error) {
if err = pr.LoadBaseRepo(); err != nil { if err = pr.LoadBaseRepo(); err != nil {
return nil, err return nil, err
} }
gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath()) gitRepo, err := git.OpenRepository(pr.BaseRepo.RepoPath())
if err != nil { if err != nil {
return nil, err return nil, err
} }
defer gitRepo.Close() defer gitRepo.Close()
return getLastCommitStatus(gitRepo, pr) compareInfo, err := gitRepo.GetCompareInfo(pr.BaseRepo.RepoPath(), pr.MergeBase, pr.GetGitRefName())
}
// getLastCommitStatus get pr's last commit status. PR's last commit status is the head commit id's last commit status
func getLastCommitStatus(gitRepo *git.Repository, pr *models.PullRequest) (status *models.CommitStatus, err error) {
sha, err := gitRepo.GetRefCommitID(pr.GetGitRefName())
if err != nil { if err != nil {
return nil, err return nil, err
} }
if compareInfo.Commits.Len() == 0 {
return nil, errors.New("pull request has no commits")
}
sha := compareInfo.Commits.Front().Value.(*git.Commit).ID.String()
statusList, err := models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, models.ListOptions{}) statusList, err := models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, models.ListOptions{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return models.CalcCommitStatus(statusList), nil return statusList, nil
} }
// IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head // IsHeadEqualWithBranch returns if the commits of branchName are available in pull request head

View File

@@ -70,7 +70,7 @@
<dd>{{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd> <dd>{{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
{{if not .SSH.Disabled}} {{if not .SSH.Disabled}}
<dt>{{.i18n.Tr "admin.config.ssh_start_builtin_server"}}</dt> <dt>{{.i18n.Tr "admin.config.ssh_start_builtin_server"}}</dt>
<dd>{{if .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd> <dd>{{if not .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
<dt>{{.i18n.Tr "admin.config.ssh_domain"}}</dt> <dt>{{.i18n.Tr "admin.config.ssh_domain"}}</dt>
<dd>{{.SSH.Domain}}</dd> <dd>{{.SSH.Domain}}</dd>
<dt>{{.i18n.Tr "admin.config.ssh_port"}}</dt> <dt>{{.i18n.Tr "admin.config.ssh_port"}}</dt>

View File

@@ -5,17 +5,19 @@
<form class="ui form ignore-dirty" style="max-width: 100%"> <form class="ui form ignore-dirty" style="max-width: 100%">
<input type="hidden" name="tab" value="{{$.TabName}}"> <input type="hidden" name="tab" value="{{$.TabName}}">
<div class="ui fluid action input"> <div class="ui fluid action input">
<div class="twelve wide field">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus> <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
<div class="ui dropdown selection">
<input name="t" type="hidden" value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="text">{{.i18n.Tr (printf "explore.search.%s" (or .queryType "fuzzy"))}}</div>
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
<div class="item" data-value="">{{.i18n.Tr "explore.search.fuzzy"}}</div>
<div class="item" data-value="match">{{.i18n.Tr "explore.search.match"}}</div>
</div> </div>
<div class="two wide field">
<select name="t">
<option value="">{{.i18n.Tr "explore.search.fuzzy"}}</option>
<option value="match" {{if eq .queryType "match"}}selected{{end}}>{{.i18n.Tr "explore.search.match"}}</option>
</select>
</div> </div>
<div class="three field">
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button> <button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
</div> </div>
</div>
</form> </form>
<div class="ui divider"></div> <div class="ui divider"></div>

View File

@@ -18,7 +18,7 @@
{{else if eq .HookType "discord"}} {{else if eq .HookType "discord"}}
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/discord.png"> <img width="26" height="26" src="{{StaticUrlPrefix}}/img/discord.png">
{{else if eq .HookType "dingtalk"}} {{else if eq .HookType "dingtalk"}}
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/dingtalk.ico"> <img width="26" height="26" src="{{StaticUrlPrefix}}/img/dingtalk.png">
{{else if eq .HookType "telegram"}} {{else if eq .HookType "telegram"}}
<img width="26" height="26" src="{{StaticUrlPrefix}}/img/telegram.png"> <img width="26" height="26" src="{{StaticUrlPrefix}}/img/telegram.png">
{{else if eq .HookType "msteams"}} {{else if eq .HookType "msteams"}}

View File

@@ -25,7 +25,7 @@
</td> </td>
<td class="right aligned overflow-visible"> <td class="right aligned overflow-visible">
<div class="ui basic jump dropdown icon button poping up" data-content="{{$.i18n.Tr "repo.branch.download" ($.DefaultBranch)}}" data-variation="tiny inverted" data-position="top right"> <div class="ui basic jump dropdown icon button poping up" data-content="{{$.i18n.Tr "repo.branch.download" ($.DefaultBranch)}}" data-variation="tiny inverted" data-position="top right">
{{svg "octicon-download"}} <i class="download icon"></i>
<div class="menu"> <div class="menu">
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a> <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a> <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.DefaultBranch}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a>
@@ -91,20 +91,20 @@
</a> </a>
{{end}} {{end}}
{{else}} {{else}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="vm">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a> <a href="{{.LatestPullRequest.Issue.HTMLURL}}">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
{{if .LatestPullRequest.HasMerged}} {{if .LatestPullRequest.HasMerged}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label purple large label vm">{{svg "octicon-git-merge" 16 "mr-2"}}{{$.i18n.Tr "repo.pulls.merged"}}</a> <a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label purple mini label">{{svg "octicon-git-merge"}} {{$.i18n.Tr "repo.pulls.merged"}}</a>
{{else if .LatestPullRequest.Issue.IsClosed}} {{else if .LatestPullRequest.Issue.IsClosed}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label red large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.i18n.Tr "repo.issues.closed_title"}}</a> <a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label red mini label">{{svg "octicon-git-pull-request"}} {{$.i18n.Tr "repo.issues.closed_title"}}</a>
{{else}} {{else}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label green large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.i18n.Tr "repo.issues.open_title"}}</a> <a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label green mini label">{{svg "octicon-git-pull-request"}} {{$.i18n.Tr "repo.issues.open_title"}}</a>
{{end}} {{end}}
{{end}} {{end}}
</td> </td>
<td class="two wide right aligned overflow-visible"> <td class="two wide right aligned overflow-visible">
{{if (not .IsDeleted)}} {{if (not .IsDeleted)}}
<div class="ui basic jump dropdown icon button poping up" data-content="{{$.i18n.Tr "repo.branch.download" (.Name)}}" data-variation="tiny inverted" data-position="top right"> <div class="ui basic jump dropdown icon button poping up" data-content="{{$.i18n.Tr "repo.branch.download" (.Name)}}" data-variation="tiny inverted" data-position="top right">
{{svg "octicon-download"}} <i class="download icon"></i>
<div class="menu"> <div class="menu">
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a> <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a> <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound .Name}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a>

View File

@@ -1,17 +1,17 @@
{{if not $.DisableHTTP}} {{if not $.DisableHTTP}}
<button class="ui basic clone button no-transition" id="repo-clone-https" data-link="{{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}"> <button class="ui basic clone button no-transition" id="repo-clone-https" data-link="{{.CloneLink.HTTPS}}">
{{if UseHTTPS}}HTTPS{{else}}HTTP{{end}} {{if UseHTTPS}}HTTPS{{else}}HTTP{{end}}
</button> </button>
{{end}} {{end}}
{{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} {{if and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
<button class="ui basic clone button no-transition" id="repo-clone-ssh" data-link="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}"> <button class="ui basic clone button no-transition" id="repo-clone-ssh" data-link="{{.CloneLink.SSH}}">
SSH SSH
</button> </button>
{{end}} {{end}}
{{if not $.DisableHTTP}} {{if not $.DisableHTTP}}
<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.HTTPS}}{{else}}{{$.CloneLink.HTTPS}}{{end}}" readonly> <input id="repo-clone-url" value="{{$.CloneLink.HTTPS}}" readonly>
{{else if and (not .DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}} {{else if and (not .DisableSSH) (or $.IsSigned $.ExposeAnonSSH)}}
<input id="repo-clone-url" value="{{if $.PageIsWiki}}{{$.WikiCloneLink.SSH}}{{else}}{{$.CloneLink.SSH}}{{end}}" readonly> <input id="repo-clone-url" value="{{$.CloneLink.SSH}}" readonly>
{{end}} {{end}}
{{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}} {{if or (not $.DisableHTTP) (and (not $.DisableSSH) (or $.IsSigned $.ExposeAnonSSH))}}
<button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url"> <button class="ui basic icon button poping up clipboard" id="clipboard-btn" data-original="{{.i18n.Tr "repo.copy_link"}}" data-success="{{.i18n.Tr "repo.copy_link_success"}}" data-error="{{.i18n.Tr "repo.copy_link_error"}}" data-content="{{.i18n.Tr "repo.copy_link"}}" data-variation="inverted tiny" data-clipboard-target="#repo-clone-url">

View File

@@ -10,7 +10,7 @@
<div class="ui attached segment"> <div class="ui attached segment">
{{template "base/alert" .}} {{template "base/alert" .}}
<p class="ui center">{{.i18n.Tr "repo.new_repo_helper" (printf "%s%s" AppSubUrl "/repo/migrate") | Safe}}</p> <p class="ui center">{{.i18n.Tr "repo.new_repo_helper" "/repo/migrate" | Safe}}</p>
{{if not .CanCreateRepo}} {{if not .CanCreateRepo}}
<div class="ui negative message"> <div class="ui negative message">

View File

@@ -43,13 +43,15 @@
</ol> </ol>
{{range $i, $file := .Diff.Files}} {{range $i, $file := .Diff.Files}}
{{if $file.IsIncomplete}} {{if $file.IsIncomplete}}
<div class="diff-file-box diff-box file-content mt-3"> <div class="diff-file-box diff-box file-content">
<h4 class="ui top attached normal header rounded"> <h4 class="ui top attached normal header rounded">
<a role="button" class="fold-file muted mr-2"> <a role="button" class="fold-file muted mr-2">
{{svg "octicon-chevron-down" 18}} {{svg "octicon-chevron-down" 18}}
</a> </a>
<div class="bold ui left df ac"> <div class="bold ui left df ac">
{{if not $file.IsRenamed}}
{{template "repo/diff/stats" dict "file" . "root" $}} {{template "repo/diff/stats" dict "file" . "root" $}}
{{end}}
</div> </div>
<span class="file mono">{{$file.Name}}</span> <span class="file mono">{{$file.Name}}</span>
<div class="diff-file-header-actions df ac"> <div class="diff-file-header-actions df ac">
@@ -68,7 +70,7 @@
</h4> </h4>
</div> </div>
{{else}} {{else}}
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{.Index}}"> <div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb"> <h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb">
<div class="df ac"> <div class="df ac">
{{$isImage := false}} {{$isImage := false}}
@@ -83,7 +85,7 @@
<div class="bold df ac"> <div class="bold df ac">
{{if $file.IsBin}} {{if $file.IsBin}}
{{$.i18n.Tr "repo.diff.bin"}} {{$.i18n.Tr "repo.diff.bin"}}
{{else}} {{else if not $file.IsRenamed}}
{{template "repo/diff/stats" dict "file" . "root" $}} {{template "repo/diff/stats" dict "file" . "root" $}}
{{end}} {{end}}
</div> </div>
@@ -103,6 +105,7 @@
</div> </div>
</h4> </h4>
<div class="diff-file-body ui attached unstackable table segment"> <div class="diff-file-body ui attached unstackable table segment">
{{if ne $file.Type 4}}
<div class="file-body file-code has-context-menu{{if not $isImage}} code-diff{{end}}{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $isImage}} py-4{{end}}"> <div class="file-body file-code has-context-menu{{if not $isImage}} code-diff{{end}}{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $isImage}} py-4{{end}}">
<table class="chroma{{if $isImage}} w-100{{end}}"> <table class="chroma{{if $isImage}} w-100{{end}}">
<tbody> <tbody>
@@ -118,13 +121,14 @@
</tbody> </tbody>
</table> </table>
</div> </div>
{{end}}
</div> </div>
</div> </div>
{{end}} {{end}}
{{end}} {{end}}
{{if .Diff.IsIncomplete}} {{if .Diff.IsIncomplete}}
<div class="diff-file-box diff-box file-content mt-3"> <div class="diff-file-box diff-box file-content">
<h4 class="ui top attached normal header"> <h4 class="ui top attached normal header">
{{$.i18n.Tr "repo.diff.too_many_files"}} {{$.i18n.Tr "repo.diff.too_many_files"}}
</h4> </h4>

View File

@@ -3,7 +3,7 @@
{{ $createdStr:= TimeSinceUnix .CreatedUnix $.root.Lang }} {{ $createdStr:= TimeSinceUnix .CreatedUnix $.root.Lang }}
<div class="comment" id="{{.HashTag}}"> <div class="comment" id="{{.HashTag}}">
{{if .OriginalAuthor }} {{if .OriginalAuthor }}
<span class="avatar"><img src="{{AppSubUrl}}/img/avatar_default.png"></span> <span class="avatar"><img src="/img/avatar_default.png"></span>
{{else}} {{else}}
<a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}> <a class="avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>
{{avatar .Poster}} {{avatar .Poster}}

View File

@@ -3,21 +3,17 @@
{{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}} {{$isNotPending := (not (eq (index .comments 0).Review.Type 0))}}
<div class="conversation-holder" data-path="{{(index .comments 0).TreePath}}" data-side="{{if lt (index .comments 0).Line 0}}left{{else}}right{{end}}" data-idx="{{(index .comments 0).UnsignedLine}}"> <div class="conversation-holder" data-path="{{(index .comments 0).TreePath}}" data-side="{{if lt (index .comments 0).Line 0}}left{{else}}right{{end}}" data-idx="{{(index .comments 0).UnsignedLine}}">
{{if $resolved}} {{if $resolved}}
<div class="ui attached header resolved-placeholder df ac sb"> <div class="ui attached header resolved-placeholder">
<div class="ui grey text"> <span class="ui grey text left"><b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}}</span>
<b>{{$resolveDoer.Name}}</b> {{$.i18n.Tr "repo.issues.review.resolved_by"}} <button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny right labeled button show-outdated">
</div> {{svg "octicon-unfold"}}
<div>
<button id="show-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="ui tiny right labeled button show-outdated df ac">
{{svg "octicon-unfold" 16 "mr-3"}}
{{$.i18n.Tr "repo.issues.review.show_resolved"}} {{$.i18n.Tr "repo.issues.review.show_resolved"}}
</button> </button>
<button id="hide-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="hide ui tiny right labeled button hide-outdated df ac"> <button id="hide-outdated-{{(index .comments 0).ID}}" data-comment="{{(index .comments 0).ID}}" class="hide ui tiny right labeled button hide-outdated">
{{svg "octicon-fold" 16 "mr-3"}} {{svg "octicon-fold"}}
{{$.i18n.Tr "repo.issues.review.hide_resolved"}} {{$.i18n.Tr "repo.issues.review.hide_resolved"}}
</button> </button>
</div> </div>
</div>
{{end}} {{end}}
<div id="code-comments-{{(index .comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}"> <div id="code-comments-{{(index .comments 0).ID}}" class="field comment-code-cloud {{if $resolved}}hide{{end}}">
<div class="comment-list"> <div class="comment-list">

View File

@@ -1,9 +1,9 @@
<div id="rev-container"> <div id="rev-container">
<ul id="rev-list"> <ul id="rev-list">
{{ range $commitI, $commit := .Graph.Commits }} {{ range $commitI, $commit := .Graph.Commits }}
<li {{if $commit.Rev}}id="commit-{{$commit.Rev}}"{{end}} data-flow="{{$commit.Flow}}"> <li id="commit-{{$commit.Rev}}" data-flow="{{$commit.Flow}}">
{{ if $commit.OnlyRelation }} {{ if $commit.OnlyRelation }}
<span></span> <span />
{{ else }} {{ else }}
<span class="sha" id="{{$commit.ShortRev}}"> <span class="sha" id="{{$commit.ShortRev}}">
{{$class := "ui sha label"}} {{$class := "ui sha label"}}

View File

@@ -110,13 +110,13 @@
{{if eq $n 0}} {{if eq $n 0}}
<div class="ui action tiny input" id="clone-panel"> <div class="ui action tiny input" id="clone-panel">
{{template "repo/clone_buttons" .}} {{template "repo/clone_buttons" .}}
<button id="download-btn" class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right"> <div class="ui basic jump dropdown icon button poping up" data-content="{{.i18n.Tr "repo.download_archive"}}" data-variation="tiny inverted" data-position="top right">
{{svg "octicon-download"}} {{svg "octicon-download"}}
<div class="menu"> <div class="menu">
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a> <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.zip">{{svg "octicon-file-zip"}}&nbsp;ZIP</a>
<a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a> <a class="item archive-link" data-url="{{$.RepoLink}}/archive/{{EscapePound $.BranchName}}.tar.gz">{{svg "octicon-file-zip"}}&nbsp;TAR.GZ</a>
</div> </div>
</button> </div>
</div> </div>
{{end}} {{end}}
</div> </div>

View File

@@ -40,7 +40,7 @@
</div> </div>
<div class="three wide column"> <div class="three wide column">
{{if $.PageIsOrgSettingsLabels}} {{if $.PageIsOrgSettingsLabels}}
<a class="ui right open-issues" href="{{AppSubUrl}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a> <a class="ui right open-issues" href="/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
{{else}} {{else}}
<a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a> <a class="ui right open-issues" href="{{$.RepoLink}}/issues?labels={{.ID}}">{{svg "octicon-issue-opened"}} {{$.i18n.Tr "repo.issues.label_open_issues" .NumOpenIssues}}</a>
{{end}} {{end}}

View File

@@ -4,8 +4,8 @@
<div class="ui container"> <div class="ui container">
<div class="ui three column stackable grid"> <div class="ui three column stackable grid">
<div class="column"> <div class="column">
<h1>{{.Milestone.Name}}</h1> <h3>{{.Milestone.Name}}</h3>
<div class="markdown content"> <div class="content">
{{.Milestone.RenderedContent|Str2html}} {{.Milestone.RenderedContent|Str2html}}
</div> </div>
</div> </div>

View File

@@ -43,7 +43,7 @@
<div class="milestone list"> <div class="milestone list">
{{range .Milestones}} {{range .Milestones}}
<li class="item"> <li class="item">
{{svg "octicon-milestone" 16 "mr-2"}} <a href="{{$.RepoLink}}/milestone/{{.ID}}">{{.Name}}</a> {{svg "octicon-milestone"}} <a href="{{$.RepoLink}}/milestone/{{.ID}}">{{.Name}}</a>
<div class="ui right green progress" data-percent="{{.Completeness}}"> <div class="ui right green progress" data-percent="{{.Completeness}}">
<div class="bar" {{if not .Completeness}}style="background-color: transparent"{{end}}> <div class="bar" {{if not .Completeness}}style="background-color: transparent"{{end}}>
<div class="progress"></div> <div class="progress"></div>
@@ -80,7 +80,7 @@
</div> </div>
{{end}} {{end}}
{{if .Content}} {{if .Content}}
<div class="markdown content"> <div class="content">
{{.RenderedContent|Str2html}} {{.RenderedContent|Str2html}}
</div> </div>
{{end}} {{end}}

View File

@@ -13,7 +13,7 @@
<ui class="ui timeline"> <ui class="ui timeline">
<div id="{{.Issue.HashTag}}" class="timeline-item comment first"> <div id="{{.Issue.HashTag}}" class="timeline-item comment first">
{{if .Issue.OriginalAuthor }} {{if .Issue.OriginalAuthor }}
<span class="timeline-avatar"><img src="{{AppSubUrl}}/img/avatar_default.png"></span> <span class="timeline-avatar"><img src="/img/avatar_default.png"></span>
{{else}} {{else}}
<a class="timeline-avatar" {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}> <a class="timeline-avatar" {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>
{{avatar .Issue.Poster}} {{avatar .Issue.Poster}}

View File

@@ -13,7 +13,7 @@
{{if eq .Type 0}} {{if eq .Type 0}}
<div class="timeline-item comment" id="{{.HashTag}}"> <div class="timeline-item comment" id="{{.HashTag}}">
{{if .OriginalAuthor }} {{if .OriginalAuthor }}
<span class="timeline-avatar"><img src="{{AppSubUrl}}/img/avatar_default.png"></span> <span class="timeline-avatar"><img src="/img/avatar_default.png"></span>
{{else}} {{else}}
<a class="timeline-avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}> <a class="timeline-avatar" {{if gt .Poster.ID 0}}href="{{.Poster.HomeLink}}"{{end}}>
{{avatar .Poster}} {{avatar .Poster}}
@@ -459,31 +459,22 @@
{{ range $filename, $lines := .Review.CodeComments}} {{ range $filename, $lines := .Review.CodeComments}}
{{range $line, $comms := $lines}} {{range $line, $comms := $lines}}
<div class="ui segments"> <div class="ui segments">
<div class="ui segment py-3 df ac sb"> <div class="ui segment py-3">
{{$invalid := (index $comms 0).Invalidated}} {{$invalid := (index $comms 0).Invalidated}}
{{$resolved := (index $comms 0).IsResolved}} {{$resolved := (index $comms 0).IsResolved}}
{{$resolveDoer := (index $comms 0).ResolveDoer}} {{$resolveDoer := (index $comms 0).ResolveDoer}}
{{$isNotPending := (not (eq (index $comms 0).Review.Type 0))}} {{$isNotPending := (not (eq (index $comms 0).Review.Type 0))}}
<div class="df ac">
<a href="{{(index $comms 0).CodeCommentURL}}" class="file-comment ml-3">{{$filename}}</a>
{{if $invalid }}
<span class="ui label basic small ml-3">
{{$.i18n.Tr "repo.issues.review.outdated"}}
</span>
{{end}}
</div>
<div>
{{if or $invalid $resolved}} {{if or $invalid $resolved}}
<button id="show-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if not $resolved}}hide {{end}}ui compact right labeled button show-outdated df ac"> <button id="show-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if not $resolved}}hide {{end}}ui compact right labeled button show-outdated">
{{svg "octicon-unfold" 16 "mr-3"}} {{svg "octicon-unfold"}}
{{if $resolved}} {{if $resolved}}
{{$.i18n.Tr "repo.issues.review.show_resolved"}} {{$.i18n.Tr "repo.issues.review.show_resolved"}}
{{else}} {{else}}
{{$.i18n.Tr "repo.issues.review.show_outdated"}} {{$.i18n.Tr "repo.issues.review.show_outdated"}}
{{end}} {{end}}
</button> </button>
<button id="hide-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if $resolved}}hide {{end}}ui compact right labeled button hide-outdated df ac"> <button id="hide-outdated-{{(index $comms 0).ID}}" data-comment="{{(index $comms 0).ID}}" class="{{if $resolved}}hide {{end}}ui compact right labeled button hide-outdated">
{{svg "octicon-fold" 16 "mr-3"}} {{svg "octicon-fold"}}
{{if $resolved}} {{if $resolved}}
{{$.i18n.Tr "repo.issues.review.hide_resolved"}} {{$.i18n.Tr "repo.issues.review.hide_resolved"}}
{{else}} {{else}}
@@ -491,7 +482,12 @@
{{end}} {{end}}
</button> </button>
{{end}} {{end}}
</div> <a href="{{(index $comms 0).CodeCommentURL}}" class="file-comment">{{$filename}}</a>
{{if $invalid }}
<span class="ui label basic small yellow">
{{$.i18n.Tr "repo.issues.review.outdated"}}
</span>
{{end}}
</div> </div>
{{$diff := (CommentMustAsDiff (index $comms 0))}} {{$diff := (CommentMustAsDiff (index $comms 0))}}
{{if $diff}} {{if $diff}}

View File

@@ -578,6 +578,8 @@
{{end}} {{end}}
</button> </button>
</div> </div>
<div class="ui tiny modal" id="lock"> <div class="ui tiny modal" id="lock">
<div class="header"> <div class="header">
{{ if .Issue.IsLocked }} {{ if .Issue.IsLocked }}
@@ -586,6 +588,7 @@
{{.i18n.Tr "repo.issues.lock.title"}} {{.i18n.Tr "repo.issues.lock.title"}}
{{end}} {{end}}
</div> </div>
</div>
<div class="content"> <div class="content">
<div class="ui warning message text left"> <div class="ui warning message text left">
{{ if .Issue.IsLocked }} {{ if .Issue.IsLocked }}

View File

@@ -158,23 +158,10 @@
<div class="card board-card" data-issue="{{.ID}}"> <div class="card board-card" data-issue="{{.ID}}">
<div class="content"> <div class="content">
<div class="header"> <div class="header">
<span> <span class="{{if .IsClosed}}red{{else}}green{{end}}">
{{if .IsPull}} {{if .IsPull}}{{svg "octicon-git-merge"}}
{{if .PullRequest.HasMerged}} {{else if .IsClosed}}{{svg "octicon-issue-closed"}}
{{svg "octicon-git-merge" 16 "text purple"}} {{else}}{{svg "octicon-issue-opened"}}
{{else}}
{{if .IsClosed}}
{{svg "octicon-git-pull-request" 16 "text red"}}
{{else}}
{{svg "octicon-git-pull-request" 16 "text green"}}
{{end}}
{{end}}
{{else}}
{{if .IsClosed}}
{{svg "octicon-issue-closed" 16 "text red"}}
{{else}}
{{svg "octicon-issue-opened" 16 "text green"}}
{{end}}
{{end}} {{end}}
</span> </span>
<a class="project-board-title" href="{{$.RepoLink}}/issues/{{.Index}}">#{{.Index}} {{.Title}}</a> <a class="project-board-title" href="{{$.RepoLink}}/issues/{{.Index}}">#{{.Index}} {{.Title}}</a>

View File

@@ -5,16 +5,20 @@
<div class="ui repo-search"> <div class="ui repo-search">
<form class="ui form ignore-dirty" method="get"> <form class="ui form ignore-dirty" method="get">
<div class="ui fluid action input"> <div class="ui fluid action input">
<div class="twelve wide field">
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}"> <input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "repo.search.search_repo"}}">
<div class="ui dropdown selection">
<input name="t" type="hidden" value="{{.queryType}}">{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="text">{{.i18n.Tr (printf "repo.search.%s" (or .queryType "fuzzy"))}}</div>
<div class="menu transition hidden" tabindex="-1" style="display: block !important;">
<div class="item" data-value="">{{.i18n.Tr "repo.search.fuzzy"}}</div>
<div class="item" data-value="match">{{.i18n.Tr "repo.search.match"}}</div>
</div> </div>
<div class="two wide field">
<select name="t">
<option value="">{{.i18n.Tr "repo.search.fuzzy"}}</option>
<option value="match" {{if eq .queryType "match"}}selected{{end}}>{{.i18n.Tr "repo.search.match"}}</option>
</select>
</div>
<div class="three field">
<button class="ui button" type="submit">
<i class="icon df ac jc">{{svg "octicon-search" 16}}</i>
</button>
</div> </div>
<button class="ui icon button" type="submit">{{svg "octicon-search" 16}}</button>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -62,12 +62,12 @@
{{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}} {{$.i18n.Tr .GetLastEventLabelFake $timeStr (.Poster.GetDisplayName | Escape) | Safe}}
{{end}} {{end}}
{{if and .Milestone (ne $.listType "milestone")}} {{if and .Milestone (ne $.listType "milestone")}}
<a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}> <a class="milestone" {{if $.RepoLink}}href="{{$.RepoLink}}/milestone/{{.Milestone.ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/milestone/{{.Milestone.ID}}"{{end}}>
{{svg "octicon-milestone" 14 "mr-2"}}{{.Milestone.Name}} {{svg "octicon-milestone" 14 "mr-2"}}{{.Milestone.Name}}
</a> </a>
{{end}} {{end}}
{{if .Ref}} {{if .Ref}}
<a class="ref" {{if $.RepoLink}}href="{{$.RepoLink}}{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.OwnerName}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}> <a class="ref" {{if $.RepoLink}}href="{{$.RepoLink}}{{index $.IssueRefURLs .ID}}"{{else}}href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}{{index $.IssueRefURLs .ID}}"{{end}}>
{{svg "octicon-git-branch" 14 "mr-2"}}{{index $.IssueRefEndNames .ID}} {{svg "octicon-git-branch" 14 "mr-2"}}{{index $.IssueRefEndNames .ID}}
</a> </a>
{{end}} {{end}}

View File

@@ -19,7 +19,7 @@
{{end}} {{end}}
{{else}} {{else}}
{{if .NeedsPassword}} {{if .NeedsPassword}}
<form class="ui form" action="{{AppSubUrl}}/user/activate" method="post"> <form class="ui form" action="/user/activate" method="post">
<div class="required inline field"> <div class="required inline field">
<label for="password">{{.i18n.Tr "password"}}</label> <label for="password">{{.i18n.Tr "password"}}</label>
<input id="password" name="password" type="password" autocomplete="off" required> <input id="password" name="password" type="password" autocomplete="off" required>

View File

@@ -71,8 +71,8 @@
</div> </div>
</div> </div>
</div> </div>
</div>
{{end}} {{end}}
</div>
{{if .ContextUser.IsOrganization}} {{if .ContextUser.IsOrganization}}
<div class="right stackable menu"> <div class="right stackable menu">
@@ -102,5 +102,4 @@
</div> </div>
{{end}} {{end}}
</div> </div>
</div>
<div class="ui divider"></div> <div class="ui divider"></div>

Some files were not shown because too many files have changed in this diff Show More