Compare commits
38 commits
b699c23a14
...
f649ef486c
Author | SHA1 | Date | |
---|---|---|---|
|
f649ef486c | ||
9ee18bd50f | |||
010d1e5627 | |||
5e13cadb4d | |||
24240aad00 | |||
1c3fff8db7 | |||
e7009d9fc6 | |||
|
f48fda8eef | ||
|
cd48a007bb | ||
|
6afbef5a8b | ||
|
d745780014 | ||
|
652abf0ae0 | ||
|
1f804d35ca | ||
|
c83a05f114 | ||
|
a3c75ac438 | ||
|
14bc4d79c1 | ||
|
672d54fafa | ||
|
0495544b8a | ||
|
1fbc56d732 | ||
|
1a9ba1c65d | ||
|
cbebcc1c26 | ||
|
0e677d7b41 | ||
|
790770aef3 | ||
|
43b4c38d4f | ||
|
e79a10793f | ||
|
be5411d6b5 | ||
|
bdf3be53b0 | ||
|
e50473e6bb | ||
|
20c135cd46 | ||
|
937ef6fa90 | ||
|
54d4e664c2 | ||
|
c571ac6fd3 | ||
|
f663773200 | ||
|
a28677273b | ||
|
c8d687997d | ||
|
5cb1037cb7 | ||
|
2dcea782c5 | ||
|
31842f12a4 |
83 changed files with 1312 additions and 863 deletions
39
.woodpecker.yml
Normal file
39
.woodpecker.yml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
clone:
|
||||||
|
git:
|
||||||
|
image: woodpeckerci/plugin-git
|
||||||
|
settings:
|
||||||
|
tags: true
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: docker.io/alpine:3.16
|
||||||
|
commands:
|
||||||
|
- echo "172.17.0.1 alpine.proxy.coso npm.proxy.coso" >> /etc/hosts
|
||||||
|
- echo "http://alpine.proxy.coso/alpine/v3.16/main" > /etc/apk/repositories
|
||||||
|
- echo "http://alpine.proxy.coso/alpine/v3.16/community" >> /etc/apk/repositories
|
||||||
|
- apk add git nodejs npm go make rsync openssh-client-default
|
||||||
|
- npm set registry http://npm.proxy.coso
|
||||||
|
|
||||||
|
- GOOS=linux GOARCH=amd64 LDFLAGS="-linkmode external -extldflags '-static' $LDFLAGS" TAGS="bindata sqlite sqlite_unlock_notify" make build
|
||||||
|
|
||||||
|
- eval $(ssh-agent -s)
|
||||||
|
- echo "$${SSH_KEY}" | tr -d '\r' | ssh-add -
|
||||||
|
- mkdir -p ~/.ssh
|
||||||
|
- echo "[nulo.in]:420,[186.136.121.7]:420 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGPkgRVWYcVcgjI0xAjDgZQsYuXU9edcya8zna01ibyUMlfKHIMD9yOoq0R+fQPTCqwiol/2tKMPJ2hlKshc+H8=" > ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
# #!/bin/sh
|
||||||
|
# # Editar en https://gitea.nulo.in/Nulo/gitea si se cambia
|
||||||
|
# bin=/usr/local/bin/gitea
|
||||||
|
# new=/usr/local/bin/gitea.new
|
||||||
|
#
|
||||||
|
# rm "$new"
|
||||||
|
# cat /dev/stdin > "$new" || exit $?
|
||||||
|
# chmod +x "$new" || exit $?
|
||||||
|
# mv "$new" "$bin" || exit $?
|
||||||
|
# sv restart gitea || exit $?
|
||||||
|
- ssh -p420 ci-gitea@nulo.in doas /usr/local/sbin/instalar-gitea < gitea
|
||||||
|
when:
|
||||||
|
branch: gitea.nulo.in
|
||||||
|
event: push
|
||||||
|
secrets:
|
||||||
|
- ssh_key
|
36
CHANGELOG.md
36
CHANGELOG.md
|
@ -4,6 +4,42 @@ 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.17.3](https://github.com/go-gitea/gitea/releases/tag/v1.17.3) - 2022-10-15
|
||||||
|
|
||||||
|
* SECURITY
|
||||||
|
* Sanitize and Escape refs in git backend (#21464) (#21463)
|
||||||
|
* Bump `golang.org/x/text` (#21412) (#21413)
|
||||||
|
* Update bluemonday (#21281) (#21287)
|
||||||
|
* ENHANCEMENTS
|
||||||
|
* Fix empty container layer history and UI (#21251) (#21278)
|
||||||
|
* Use en-US as fallback when using other default language (#21200) (#21256)
|
||||||
|
* Make the vscode clone link respect transport protocol (#20557) (#21128)
|
||||||
|
* BUGFIXES
|
||||||
|
* Do DB update after merge in hammer context (#21401) (#21416)
|
||||||
|
* Add Num{Issues,Pulls} stats checks (#21404) (#21414)
|
||||||
|
* Stop logging CheckPath returns error: context canceled (#21064) (#21405)
|
||||||
|
* Parse OAuth Authorization header when request omits client secret (#21351) (#21374)
|
||||||
|
* Ignore port for loopback redirect URIs (#21293) (#21373)
|
||||||
|
* Set SemverCompatible to false for Conan packages (#21275) (#21366)
|
||||||
|
* Tag list should include draft releases with existing tags (#21263) (#21365)
|
||||||
|
* Fix linked account translation (#21331) (#21334)
|
||||||
|
* Make NuGet service index publicly accessible (#21242) (#21277)
|
||||||
|
* Foreign ID conflicts if ID is 0 for each item (#21271) (#21272)
|
||||||
|
* Use absolute links in feeds (#21229) (#21265)
|
||||||
|
* Prevent invalid behavior for file reviewing when loading more files (#21230) (#21234)
|
||||||
|
* Respect `REQUIRE_SIGNIN_VIEW` for packages (#20873) (#21232)
|
||||||
|
* Treat git object mode 40755 as directory (#21195) (#21218)
|
||||||
|
* Allow uppercase ASCII alphabet in PyPI package names (#21095) (#21217)
|
||||||
|
* Fix limited user cannot view himself's profile (#21212)
|
||||||
|
* Fix template bug of admin monitor (#21209)
|
||||||
|
* Fix reaction of issues (#21185) (#21196)
|
||||||
|
* Fix CSV diff for added/deleted files (#21189) (#21193)
|
||||||
|
* Fix pagination limit parameter problem (#21111)
|
||||||
|
* TESTING
|
||||||
|
* Fix missing m.Run() in TestMain (#21341)
|
||||||
|
* BUILD
|
||||||
|
* Use Go 1.19 fmt for Gitea 1.17, sync emoji data (#21239)
|
||||||
|
|
||||||
## [1.17.2](https://github.com/go-gitea/gitea/releases/tag/v1.17.2) - 2022-09-06
|
## [1.17.2](https://github.com/go-gitea/gitea/releases/tag/v1.17.2) - 2022-09-06
|
||||||
|
|
||||||
* SECURITY
|
* SECURITY
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -33,7 +33,7 @@ GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1
|
||||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.0
|
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.0
|
||||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
|
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.0
|
||||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||||
|
|
||||||
DOCKER_IMAGE ?= gitea/gitea
|
DOCKER_IMAGE ?= gitea/gitea
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -214,8 +214,7 @@ const hdr = `
|
||||||
|
|
||||||
package emoji
|
package emoji
|
||||||
|
|
||||||
// Code generated by gen.go. DO NOT EDIT.
|
// Code generated by build/generate-emoji.go. DO NOT EDIT.
|
||||||
// Sourced from %s
|
// Sourced from %s
|
||||||
//
|
|
||||||
var GemojiData = %#v
|
var GemojiData = %#v
|
||||||
`
|
`
|
||||||
|
|
13
go.mod
13
go.mod
|
@ -64,7 +64,7 @@ require (
|
||||||
github.com/mattn/go-isatty v0.0.14
|
github.com/mattn/go-isatty v0.0.14
|
||||||
github.com/mattn/go-sqlite3 v1.14.12
|
github.com/mattn/go-sqlite3 v1.14.12
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
github.com/mholt/archiver/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19
|
github.com/microcosm-cc/bluemonday v1.0.20
|
||||||
github.com/minio/minio-go/v7 v7.0.26
|
github.com/minio/minio-go/v7 v7.0.26
|
||||||
github.com/msteinert/pam v1.0.0
|
github.com/msteinert/pam v1.0.0
|
||||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||||
|
@ -91,11 +91,11 @@ require (
|
||||||
go.jolheiser.com/hcaptcha v0.0.4
|
go.jolheiser.com/hcaptcha v0.0.4
|
||||||
go.jolheiser.com/pwn v0.0.3
|
go.jolheiser.com/pwn v0.0.3
|
||||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||||
golang.org/x/net v0.0.0-20220630215102-69896b714898
|
golang.org/x/net v0.0.0-20220927171203-f486391704dc
|
||||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
|
||||||
golang.org/x/text v0.3.7
|
golang.org/x/text v0.3.8
|
||||||
golang.org/x/tools v0.1.10
|
golang.org/x/tools v0.1.12
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||||
gopkg.in/ini.v1 v1.66.4
|
gopkg.in/ini.v1 v1.66.4
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
@ -271,9 +271,8 @@ require (
|
||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
go.uber.org/multierr v1.8.0 // indirect
|
go.uber.org/multierr v1.8.0 // indirect
|
||||||
go.uber.org/zap v1.21.0 // indirect
|
go.uber.org/zap v1.21.0 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||||
google.golang.org/grpc v1.43.0 // indirect
|
google.golang.org/grpc v1.43.0 // indirect
|
||||||
|
|
27
go.sum
27
go.sum
|
@ -1146,8 +1146,8 @@ github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo=
|
||||||
github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
||||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
|
github.com/microcosm-cc/bluemonday v1.0.20 h1:flpzsq4KU3QIYAYGV/szUat7H+GPOXR0B2JU5A1Wp8Y=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
|
github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50=
|
||||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||||
|
@ -1716,8 +1716,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -1788,8 +1788,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
|
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
|
||||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-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=
|
||||||
|
@ -1824,8 +1824,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -1936,8 +1936,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
@ -1950,8 +1950,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
|
||||||
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -2045,16 +2046,14 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
|
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
|
|
@ -266,7 +266,7 @@ func TestPackageConan(t *testing.T) {
|
||||||
|
|
||||||
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, pd.SemVer)
|
assert.Nil(t, pd.SemVer)
|
||||||
assert.Equal(t, name, pd.Package.Name)
|
assert.Equal(t, name, pd.Package.Name)
|
||||||
assert.Equal(t, version1, pd.Version.Version)
|
assert.Equal(t, version1, pd.Version.Version)
|
||||||
assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
|
assert.IsType(t, &conan_module.Metadata{}, pd.Metadata)
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/packages"
|
"code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -79,6 +80,18 @@ func TestPackageGeneric(t *testing.T) {
|
||||||
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
assert.Equal(t, int64(1), pvs[0].DownloadCount)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("RequireSignInView", func(t *testing.T) {
|
||||||
|
defer PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
setting.Service.RequireSignInView = true
|
||||||
|
defer func() {
|
||||||
|
setting.Service.RequireSignInView = false
|
||||||
|
}()
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", url)
|
||||||
|
MakeRequest(t, req, http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("Delete", func(t *testing.T) {
|
t.Run("Delete", func(t *testing.T) {
|
||||||
defer PrintCurrentTest(t)()
|
defer PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
nuget_module "code.gitea.io/gitea/modules/packages/nuget"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/routers/api/packages/nuget"
|
"code.gitea.io/gitea/routers/api/packages/nuget"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -65,39 +66,58 @@ func TestPackageNuGet(t *testing.T) {
|
||||||
t.Run("ServiceIndex", func(t *testing.T) {
|
t.Run("ServiceIndex", func(t *testing.T) {
|
||||||
defer PrintCurrentTest(t)()
|
defer PrintCurrentTest(t)()
|
||||||
|
|
||||||
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
privateUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Visibility: structs.VisibleTypePrivate}).(*user_model.User)
|
||||||
req = AddBasicAuthHeader(req, user.Name)
|
|
||||||
MakeRequest(t, req, http.StatusOK)
|
|
||||||
|
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
cases := []struct {
|
||||||
req = addNuGetAPIKeyHeader(req, token)
|
Owner string
|
||||||
resp := MakeRequest(t, req, http.StatusOK)
|
UseBasicAuth bool
|
||||||
|
UseTokenAuth bool
|
||||||
|
}{
|
||||||
|
{privateUser.Name, false, false},
|
||||||
|
{privateUser.Name, true, false},
|
||||||
|
{privateUser.Name, false, true},
|
||||||
|
{user.Name, false, false},
|
||||||
|
{user.Name, true, false},
|
||||||
|
{user.Name, false, true},
|
||||||
|
}
|
||||||
|
|
||||||
var result nuget.ServiceIndexResponse
|
for _, c := range cases {
|
||||||
DecodeJSON(t, resp, &result)
|
url := fmt.Sprintf("/api/packages/%s/nuget", c.Owner)
|
||||||
|
|
||||||
assert.Equal(t, "3.0.0", result.Version)
|
req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url))
|
||||||
assert.NotEmpty(t, result.Resources)
|
if c.UseBasicAuth {
|
||||||
|
req = AddBasicAuthHeader(req, user.Name)
|
||||||
|
} else if c.UseTokenAuth {
|
||||||
|
req = addNuGetAPIKeyHeader(req, token)
|
||||||
|
}
|
||||||
|
resp := MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
root := setting.AppURL + url[1:]
|
var result nuget.ServiceIndexResponse
|
||||||
for _, r := range result.Resources {
|
DecodeJSON(t, resp, &result)
|
||||||
switch r.Type {
|
|
||||||
case "SearchQueryService":
|
assert.Equal(t, "3.0.0", result.Version)
|
||||||
fallthrough
|
assert.NotEmpty(t, result.Resources)
|
||||||
case "SearchQueryService/3.0.0-beta":
|
|
||||||
fallthrough
|
root := setting.AppURL + url[1:]
|
||||||
case "SearchQueryService/3.0.0-rc":
|
for _, r := range result.Resources {
|
||||||
assert.Equal(t, root+"/query", r.ID)
|
switch r.Type {
|
||||||
case "RegistrationsBaseUrl":
|
case "SearchQueryService":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "RegistrationsBaseUrl/3.0.0-beta":
|
case "SearchQueryService/3.0.0-beta":
|
||||||
fallthrough
|
fallthrough
|
||||||
case "RegistrationsBaseUrl/3.0.0-rc":
|
case "SearchQueryService/3.0.0-rc":
|
||||||
assert.Equal(t, root+"/registration", r.ID)
|
assert.Equal(t, root+"/query", r.ID)
|
||||||
case "PackageBaseAddress/3.0.0":
|
case "RegistrationsBaseUrl":
|
||||||
assert.Equal(t, root+"/package", r.ID)
|
fallthrough
|
||||||
case "PackagePublish/2.0.0":
|
case "RegistrationsBaseUrl/3.0.0-beta":
|
||||||
assert.Equal(t, root, r.ID)
|
fallthrough
|
||||||
|
case "RegistrationsBaseUrl/3.0.0-rc":
|
||||||
|
assert.Equal(t, root+"/registration", r.ID)
|
||||||
|
case "PackageBaseAddress/3.0.0":
|
||||||
|
assert.Equal(t, root+"/package", r.ID)
|
||||||
|
case "PackagePublish/2.0.0":
|
||||||
|
assert.Equal(t, root, r.ID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -218,6 +218,11 @@ func (a *Action) GetRepoLink() string {
|
||||||
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
|
return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepoAbsoluteLink returns the absolute link to action repository.
|
||||||
|
func (a *Action) GetRepoAbsoluteLink() string {
|
||||||
|
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
|
||||||
|
}
|
||||||
|
|
||||||
// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings
|
// GetRepositoryFromMatch returns a *repo_model.Repository from a username and repo strings
|
||||||
func GetRepositoryFromMatch(ownerName, repoName string) (*repo_model.Repository, error) {
|
func GetRepositoryFromMatch(ownerName, repoName string) (*repo_model.Repository, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
|
issue_model "code.gitea.io/gitea/models/issues"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unittest"
|
"code.gitea.io/gitea/models/unittest"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
@ -19,7 +20,7 @@ import (
|
||||||
|
|
||||||
func TestAction_GetRepoPath(t *testing.T) {
|
func TestAction_GetRepoPath(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
action := &Action{RepoID: repo.ID}
|
action := &Action{RepoID: repo.ID}
|
||||||
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
|
assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath())
|
||||||
|
@ -27,12 +28,15 @@ func TestAction_GetRepoPath(t *testing.T) {
|
||||||
|
|
||||||
func TestAction_GetRepoLink(t *testing.T) {
|
func TestAction_GetRepoLink(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository)
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository)
|
||||||
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User)
|
||||||
action := &Action{RepoID: repo.ID}
|
comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 2}).(*issue_model.Comment)
|
||||||
|
action := &Action{RepoID: repo.ID, CommentID: comment.ID}
|
||||||
setting.AppSubURL = "/suburl"
|
setting.AppSubURL = "/suburl"
|
||||||
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
|
||||||
assert.Equal(t, expected, action.GetRepoLink())
|
assert.Equal(t, expected, action.GetRepoLink())
|
||||||
|
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
|
||||||
|
assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetFeeds(t *testing.T) {
|
func TestGetFeeds(t *testing.T) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -56,6 +57,18 @@ func (app *OAuth2Application) PrimaryRedirectURI() string {
|
||||||
|
|
||||||
// ContainsRedirectURI checks if redirectURI is allowed for app
|
// ContainsRedirectURI checks if redirectURI is allowed for app
|
||||||
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
|
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
|
||||||
|
uri, err := url.Parse(redirectURI)
|
||||||
|
// ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
||||||
|
if err == nil && uri.Scheme == "http" && uri.Port() != "" {
|
||||||
|
ip := net.ParseIP(uri.Hostname())
|
||||||
|
if ip != nil && ip.IsLoopback() {
|
||||||
|
// strip port
|
||||||
|
uri.Host = uri.Hostname()
|
||||||
|
if util.IsStringInSlice(uri.String(), app.RedirectURIs, true) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return util.IsStringInSlice(redirectURI, app.RedirectURIs, true)
|
return util.IsStringInSlice(redirectURI, app.RedirectURIs, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,26 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
|
||||||
assert.False(t, app.ContainsRedirectURI("d"))
|
assert.False(t, app.ContainsRedirectURI("d"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOAuth2Application_ContainsRedirectURI_WithPort(t *testing.T) {
|
||||||
|
app := &OAuth2Application{
|
||||||
|
RedirectURIs: []string{"http://127.0.0.1/", "http://::1/", "http://192.168.0.1/", "http://intranet/", "https://127.0.0.1/"},
|
||||||
|
}
|
||||||
|
|
||||||
|
// http loopback uris should ignore port
|
||||||
|
// https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
|
||||||
|
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1:3456/"))
|
||||||
|
assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
|
||||||
|
assert.True(t, app.ContainsRedirectURI("http://[::1]:3456/"))
|
||||||
|
|
||||||
|
// not http
|
||||||
|
assert.False(t, app.ContainsRedirectURI("https://127.0.0.1:3456/"))
|
||||||
|
// not loopback
|
||||||
|
assert.False(t, app.ContainsRedirectURI("http://192.168.0.1:9954/"))
|
||||||
|
assert.False(t, app.ContainsRedirectURI("http://intranet:3456/"))
|
||||||
|
// unparseable
|
||||||
|
assert.False(t, app.ContainsRedirectURI(":"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
|
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
|
||||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application)
|
app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application)
|
||||||
|
|
|
@ -181,6 +181,10 @@ func createReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, erro
|
||||||
Reaction: opts.Type,
|
Reaction: opts.Type,
|
||||||
UserID: opts.DoerID,
|
UserID: opts.DoerID,
|
||||||
}
|
}
|
||||||
|
if findOpts.CommentID == 0 {
|
||||||
|
// explicit search of Issue Reactions where CommentID = 0
|
||||||
|
findOpts.CommentID = -1
|
||||||
|
}
|
||||||
|
|
||||||
existingR, _, err := FindReactions(ctx, findOpts)
|
existingR, _, err := FindReactions(ctx, findOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -256,16 +260,23 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error {
|
||||||
CommentID: opts.CommentID,
|
CommentID: opts.CommentID,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := db.GetEngine(ctx).Where("original_author_id = 0").Delete(reaction)
|
sess := db.GetEngine(ctx).Where("original_author_id = 0")
|
||||||
|
if opts.CommentID == -1 {
|
||||||
|
reaction.CommentID = 0
|
||||||
|
sess.MustCols("comment_id")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := sess.Delete(reaction)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteIssueReaction deletes a reaction on issue.
|
// DeleteIssueReaction deletes a reaction on issue.
|
||||||
func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
func DeleteIssueReaction(doerID, issueID int64, content string) error {
|
||||||
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
return DeleteReaction(db.DefaultContext, &ReactionOptions{
|
||||||
Type: content,
|
Type: content,
|
||||||
DoerID: doerID,
|
DoerID: doerID,
|
||||||
IssueID: issueID,
|
IssueID: issueID,
|
||||||
|
CommentID: -1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,7 @@ type FindReleasesOptions struct {
|
||||||
IsPreRelease util.OptionalBool
|
IsPreRelease util.OptionalBool
|
||||||
IsDraft util.OptionalBool
|
IsDraft util.OptionalBool
|
||||||
TagNames []string
|
TagNames []string
|
||||||
|
HasSha1 util.OptionalBool // useful to find draft releases which are created with existing tags
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
||||||
|
@ -191,6 +192,13 @@ func (opts *FindReleasesOptions) toConds(repoID int64) builder.Cond {
|
||||||
if !opts.IsDraft.IsNone() {
|
if !opts.IsDraft.IsNone() {
|
||||||
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
|
cond = cond.And(builder.Eq{"is_draft": opts.IsDraft.IsTrue()})
|
||||||
}
|
}
|
||||||
|
if !opts.HasSha1.IsNone() {
|
||||||
|
if opts.HasSha1.IsTrue() {
|
||||||
|
cond = cond.And(builder.Neq{"sha1": ""})
|
||||||
|
} else {
|
||||||
|
cond = cond.And(builder.Eq{"sha1": ""})
|
||||||
|
}
|
||||||
|
}
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -605,15 +605,27 @@ func CheckRepoStats(ctx context.Context) error {
|
||||||
repoStatsCorrectNumStars,
|
repoStatsCorrectNumStars,
|
||||||
"repository count 'num_stars'",
|
"repository count 'num_stars'",
|
||||||
},
|
},
|
||||||
|
// Repository.NumIssues
|
||||||
|
{
|
||||||
|
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, false),
|
||||||
|
repoStatsCorrectNumIssues,
|
||||||
|
"repository count 'num_issues'",
|
||||||
|
},
|
||||||
// Repository.NumClosedIssues
|
// Repository.NumClosedIssues
|
||||||
{
|
{
|
||||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false),
|
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, false),
|
||||||
repoStatsCorrectNumClosedIssues,
|
repoStatsCorrectNumClosedIssues,
|
||||||
"repository count 'num_closed_issues'",
|
"repository count 'num_closed_issues'",
|
||||||
},
|
},
|
||||||
|
// Repository.NumPulls
|
||||||
|
{
|
||||||
|
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, true),
|
||||||
|
repoStatsCorrectNumPulls,
|
||||||
|
"repository count 'num_pulls'",
|
||||||
|
},
|
||||||
// Repository.NumClosedPulls
|
// Repository.NumClosedPulls
|
||||||
{
|
{
|
||||||
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true),
|
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true),
|
||||||
repoStatsCorrectNumClosedPulls,
|
repoStatsCorrectNumClosedPulls,
|
||||||
"repository count 'num_closed_pulls'",
|
"repository count 'num_closed_pulls'",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1265,7 +1265,7 @@ func isUserVisibleToViewerCond(viewer *User) builder.Cond {
|
||||||
|
|
||||||
// IsUserVisibleToViewer check if viewer is able to see user profile
|
// IsUserVisibleToViewer check if viewer is able to see user profile
|
||||||
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
||||||
if viewer != nil && viewer.IsAdmin {
|
if viewer != nil && (viewer.IsAdmin || viewer.ID == u.ID) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,7 +1304,7 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if count < 0 {
|
if count == 0 {
|
||||||
// No common organization
|
// No common organization
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,20 +36,20 @@ func drawBlock(img *image.Paletted, x, y, size, angle int, points []int) {
|
||||||
|
|
||||||
// blank
|
// blank
|
||||||
//
|
//
|
||||||
// --------
|
// --------
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// --------
|
// --------
|
||||||
func b0(img *image.Paletted, x, y, size, angle int) {}
|
func b0(img *image.Paletted, x, y, size, angle int) {}
|
||||||
|
|
||||||
// full-filled
|
// full-filled
|
||||||
//
|
//
|
||||||
// --------
|
// --------
|
||||||
// |######|
|
// |######|
|
||||||
// |######|
|
// |######|
|
||||||
// |######|
|
// |######|
|
||||||
// --------
|
// --------
|
||||||
func b1(img *image.Paletted, x, y, size, angle int) {
|
func b1(img *image.Paletted, x, y, size, angle int) {
|
||||||
for i := x; i < x+size; i++ {
|
for i := x; i < x+size; i++ {
|
||||||
for j := y; j < y+size; j++ {
|
for j := y; j < y+size; j++ {
|
||||||
|
@ -59,12 +59,13 @@ func b1(img *image.Paletted, x, y, size, angle int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// a small block
|
// a small block
|
||||||
// ----------
|
//
|
||||||
// | |
|
// ----------
|
||||||
// | #### |
|
// | |
|
||||||
// | #### |
|
// | #### |
|
||||||
// | |
|
// | #### |
|
||||||
// ----------
|
// | |
|
||||||
|
// ----------
|
||||||
func b2(img *image.Paletted, x, y, size, angle int) {
|
func b2(img *image.Paletted, x, y, size, angle int) {
|
||||||
l := size / 4
|
l := size / 4
|
||||||
x += l
|
x += l
|
||||||
|
@ -79,15 +80,15 @@ func b2(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// diamond
|
// diamond
|
||||||
//
|
//
|
||||||
// ---------
|
// ---------
|
||||||
// | # |
|
// | # |
|
||||||
// | ### |
|
// | ### |
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// |#######|
|
// |#######|
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// | ### |
|
// | ### |
|
||||||
// | # |
|
// | # |
|
||||||
// ---------
|
// ---------
|
||||||
func b3(img *image.Paletted, x, y, size, angle int) {
|
func b3(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, 0, []int{
|
drawBlock(img, x, y, size, 0, []int{
|
||||||
|
@ -101,13 +102,13 @@ func b3(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b4
|
// b4
|
||||||
//
|
//
|
||||||
// -------
|
// -------
|
||||||
// |#####|
|
// |#####|
|
||||||
// |#### |
|
// |#### |
|
||||||
// |### |
|
// |### |
|
||||||
// |## |
|
// |## |
|
||||||
// |# |
|
// |# |
|
||||||
// |------
|
// |------
|
||||||
func b4(img *image.Paletted, x, y, size, angle int) {
|
func b4(img *image.Paletted, x, y, size, angle int) {
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
0, 0,
|
0, 0,
|
||||||
|
@ -119,11 +120,11 @@ func b4(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b5
|
// b5
|
||||||
//
|
//
|
||||||
// ---------
|
// ---------
|
||||||
// | # |
|
// | # |
|
||||||
// | ### |
|
// | ### |
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// |#######|
|
// |#######|
|
||||||
func b5(img *image.Paletted, x, y, size, angle int) {
|
func b5(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -136,11 +137,11 @@ func b5(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b6
|
// b6
|
||||||
//
|
//
|
||||||
// --------
|
// --------
|
||||||
// |### |
|
// |### |
|
||||||
// |### |
|
// |### |
|
||||||
// |### |
|
// |### |
|
||||||
// --------
|
// --------
|
||||||
func b6(img *image.Paletted, x, y, size, angle int) {
|
func b6(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -154,12 +155,12 @@ func b6(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b7 italic cone
|
// b7 italic cone
|
||||||
//
|
//
|
||||||
// ---------
|
// ---------
|
||||||
// | # |
|
// | # |
|
||||||
// | ## |
|
// | ## |
|
||||||
// | #####|
|
// | #####|
|
||||||
// | ####|
|
// | ####|
|
||||||
// |--------
|
// |--------
|
||||||
func b7(img *image.Paletted, x, y, size, angle int) {
|
func b7(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -173,14 +174,14 @@ func b7(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b8 three small triangles
|
// b8 three small triangles
|
||||||
//
|
//
|
||||||
// -----------
|
// -----------
|
||||||
// | # |
|
// | # |
|
||||||
// | ### |
|
// | ### |
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// | # # |
|
// | # # |
|
||||||
// | ### ### |
|
// | ### ### |
|
||||||
// |#########|
|
// |#########|
|
||||||
// -----------
|
// -----------
|
||||||
func b8(img *image.Paletted, x, y, size, angle int) {
|
func b8(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
mm := m / 2
|
mm := m / 2
|
||||||
|
@ -212,13 +213,13 @@ func b8(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b9 italic triangle
|
// b9 italic triangle
|
||||||
//
|
//
|
||||||
// ---------
|
// ---------
|
||||||
// |# |
|
// |# |
|
||||||
// | #### |
|
// | #### |
|
||||||
// | #####|
|
// | #####|
|
||||||
// | #### |
|
// | #### |
|
||||||
// | # |
|
// | # |
|
||||||
// ---------
|
// ---------
|
||||||
func b9(img *image.Paletted, x, y, size, angle int) {
|
func b9(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -231,16 +232,16 @@ func b9(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b10
|
// b10
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// | ####|
|
// | ####|
|
||||||
// | ### |
|
// | ### |
|
||||||
// | ## |
|
// | ## |
|
||||||
// | # |
|
// | # |
|
||||||
// |#### |
|
// |#### |
|
||||||
// |### |
|
// |### |
|
||||||
// |## |
|
// |## |
|
||||||
// |# |
|
// |# |
|
||||||
// ----------
|
// ----------
|
||||||
func b10(img *image.Paletted, x, y, size, angle int) {
|
func b10(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -260,13 +261,13 @@ func b10(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b11
|
// b11
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |#### |
|
// |#### |
|
||||||
// |#### |
|
// |#### |
|
||||||
// |#### |
|
// |#### |
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// ----------
|
// ----------
|
||||||
func b11(img *image.Paletted, x, y, size, angle int) {
|
func b11(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -280,13 +281,13 @@ func b11(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b12
|
// b12
|
||||||
//
|
//
|
||||||
// -----------
|
// -----------
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// |#########|
|
// |#########|
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// | # |
|
// | # |
|
||||||
// -----------
|
// -----------
|
||||||
func b12(img *image.Paletted, x, y, size, angle int) {
|
func b12(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -299,13 +300,13 @@ func b12(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b13
|
// b13
|
||||||
//
|
//
|
||||||
// -----------
|
// -----------
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// | # |
|
// | # |
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// |#########|
|
// |#########|
|
||||||
// -----------
|
// -----------
|
||||||
func b13(img *image.Paletted, x, y, size, angle int) {
|
func b13(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -318,13 +319,13 @@ func b13(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b14
|
// b14
|
||||||
//
|
//
|
||||||
// ---------
|
// ---------
|
||||||
// | # |
|
// | # |
|
||||||
// | ### |
|
// | ### |
|
||||||
// |#### |
|
// |#### |
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// ---------
|
// ---------
|
||||||
func b14(img *image.Paletted, x, y, size, angle int) {
|
func b14(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -337,13 +338,13 @@ func b14(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b15
|
// b15
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |##### |
|
// |##### |
|
||||||
// |### |
|
// |### |
|
||||||
// |# |
|
// |# |
|
||||||
// | |
|
// | |
|
||||||
// | |
|
// | |
|
||||||
// ----------
|
// ----------
|
||||||
func b15(img *image.Paletted, x, y, size, angle int) {
|
func b15(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -356,14 +357,14 @@ func b15(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b16
|
// b16
|
||||||
//
|
//
|
||||||
// ---------
|
// ---------
|
||||||
// | # |
|
// | # |
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// |#######|
|
// |#######|
|
||||||
// | # |
|
// | # |
|
||||||
// | ##### |
|
// | ##### |
|
||||||
// |#######|
|
// |#######|
|
||||||
// ---------
|
// ---------
|
||||||
func b16(img *image.Paletted, x, y, size, angle int) {
|
func b16(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
drawBlock(img, x, y, size, angle, []int{
|
drawBlock(img, x, y, size, angle, []int{
|
||||||
|
@ -383,13 +384,13 @@ func b16(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b17
|
// b17
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |##### |
|
// |##### |
|
||||||
// |### |
|
// |### |
|
||||||
// |# |
|
// |# |
|
||||||
// | ##|
|
// | ##|
|
||||||
// | ##|
|
// | ##|
|
||||||
// ----------
|
// ----------
|
||||||
func b17(img *image.Paletted, x, y, size, angle int) {
|
func b17(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
|
|
||||||
|
@ -412,13 +413,13 @@ func b17(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b18
|
// b18
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |##### |
|
// |##### |
|
||||||
// |#### |
|
// |#### |
|
||||||
// |### |
|
// |### |
|
||||||
// |## |
|
// |## |
|
||||||
// |# |
|
// |# |
|
||||||
// ----------
|
// ----------
|
||||||
func b18(img *image.Paletted, x, y, size, angle int) {
|
func b18(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
|
|
||||||
|
@ -432,13 +433,13 @@ func b18(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b19
|
// b19
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |########|
|
// |########|
|
||||||
// |### ###|
|
// |### ###|
|
||||||
// |# #|
|
// |# #|
|
||||||
// |### ###|
|
// |### ###|
|
||||||
// |########|
|
// |########|
|
||||||
// ----------
|
// ----------
|
||||||
func b19(img *image.Paletted, x, y, size, angle int) {
|
func b19(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
|
|
||||||
|
@ -473,13 +474,13 @@ func b19(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b20
|
// b20
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// | ## |
|
// | ## |
|
||||||
// |### |
|
// |### |
|
||||||
// |## |
|
// |## |
|
||||||
// |## |
|
// |## |
|
||||||
// |# |
|
// |# |
|
||||||
// ----------
|
// ----------
|
||||||
func b20(img *image.Paletted, x, y, size, angle int) {
|
func b20(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -494,13 +495,13 @@ func b20(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b21
|
// b21
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// | #### |
|
// | #### |
|
||||||
// |## #####|
|
// |## #####|
|
||||||
// |## ##|
|
// |## ##|
|
||||||
// |## |
|
// |## |
|
||||||
// |# |
|
// |# |
|
||||||
// ----------
|
// ----------
|
||||||
func b21(img *image.Paletted, x, y, size, angle int) {
|
func b21(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -522,13 +523,13 @@ func b21(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b22
|
// b22
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// | #### |
|
// | #### |
|
||||||
// |## ### |
|
// |## ### |
|
||||||
// |## ##|
|
// |## ##|
|
||||||
// |## ##|
|
// |## ##|
|
||||||
// |# #|
|
// |# #|
|
||||||
// ----------
|
// ----------
|
||||||
func b22(img *image.Paletted, x, y, size, angle int) {
|
func b22(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -550,13 +551,13 @@ func b22(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b23
|
// b23
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// | #######|
|
// | #######|
|
||||||
// |### #|
|
// |### #|
|
||||||
// |## |
|
// |## |
|
||||||
// |## |
|
// |## |
|
||||||
// |# |
|
// |# |
|
||||||
// ----------
|
// ----------
|
||||||
func b23(img *image.Paletted, x, y, size, angle int) {
|
func b23(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -578,13 +579,13 @@ func b23(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b24
|
// b24
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// | ## ###|
|
// | ## ###|
|
||||||
// |### ###|
|
// |### ###|
|
||||||
// |## ## |
|
// |## ## |
|
||||||
// |## ## |
|
// |## ## |
|
||||||
// |# # |
|
// |# # |
|
||||||
// ----------
|
// ----------
|
||||||
func b24(img *image.Paletted, x, y, size, angle int) {
|
func b24(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -606,13 +607,13 @@ func b24(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b25
|
// b25
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |# #|
|
// |# #|
|
||||||
// |## ###|
|
// |## ###|
|
||||||
// |## ## |
|
// |## ## |
|
||||||
// |###### |
|
// |###### |
|
||||||
// |#### |
|
// |#### |
|
||||||
// ----------
|
// ----------
|
||||||
func b25(img *image.Paletted, x, y, size, angle int) {
|
func b25(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -634,13 +635,13 @@ func b25(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b26
|
// b26
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |# #|
|
// |# #|
|
||||||
// |### ###|
|
// |### ###|
|
||||||
// | #### |
|
// | #### |
|
||||||
// |### ###|
|
// |### ###|
|
||||||
// |# #|
|
// |# #|
|
||||||
// ----------
|
// ----------
|
||||||
func b26(img *image.Paletted, x, y, size, angle int) {
|
func b26(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
@ -676,13 +677,13 @@ func b26(img *image.Paletted, x, y, size, angle int) {
|
||||||
|
|
||||||
// b27
|
// b27
|
||||||
//
|
//
|
||||||
// ----------
|
// ----------
|
||||||
// |########|
|
// |########|
|
||||||
// |## ###|
|
// |## ###|
|
||||||
// |# #|
|
// |# #|
|
||||||
// |### ##|
|
// |### ##|
|
||||||
// |########|
|
// |########|
|
||||||
// ----------
|
// ----------
|
||||||
func b27(img *image.Paletted, x, y, size, angle int) {
|
func b27(img *image.Paletted, x, y, size, angle int) {
|
||||||
m := size / 2
|
m := size / 2
|
||||||
q := size / 4
|
q := size / 4
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,47 +53,11 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
|
||||||
Owner: ctx.ContextUser,
|
Owner: ctx.ContextUser,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Package.Owner.IsOrganization() {
|
var err error
|
||||||
org := organization.OrgFromUser(ctx.Package.Owner)
|
ctx.Package.AccessMode, err = determineAccessMode(ctx)
|
||||||
|
if err != nil {
|
||||||
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
errCb(http.StatusInternalServerError, "determineAccessMode", err)
|
||||||
if ctx.Doer != nil {
|
return
|
||||||
var err error
|
|
||||||
ctx.Package.AccessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
|
||||||
if err != nil {
|
|
||||||
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// If access mode is less than write check every team for more permissions
|
|
||||||
if ctx.Package.AccessMode < perm.AccessModeWrite {
|
|
||||||
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
|
||||||
if err != nil {
|
|
||||||
errCb(http.StatusInternalServerError, "GetUserOrgTeams", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, t := range teams {
|
|
||||||
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
|
|
||||||
if ctx.Package.AccessMode < perm {
|
|
||||||
ctx.Package.AccessMode = perm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 2. If authorize level is none, check if org is visible to user
|
|
||||||
if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
|
||||||
ctx.Package.AccessMode = perm.AccessModeRead
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
|
||||||
// 1. Check if user is package owner
|
|
||||||
if ctx.Doer.ID == ctx.Package.Owner.ID {
|
|
||||||
ctx.Package.AccessMode = perm.AccessModeOwner
|
|
||||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
|
||||||
ctx.Package.AccessMode = perm.AccessModeRead
|
|
||||||
}
|
|
||||||
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
|
||||||
ctx.Package.AccessMode = perm.AccessModeRead
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
packageType := ctx.Params("type")
|
packageType := ctx.Params("type")
|
||||||
|
@ -117,6 +82,57 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
|
||||||
|
accessMode := perm.AccessModeNone
|
||||||
|
|
||||||
|
if setting.Service.RequireSignInView && ctx.Doer == nil {
|
||||||
|
return accessMode, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.Package.Owner.IsOrganization() {
|
||||||
|
org := organization.OrgFromUser(ctx.Package.Owner)
|
||||||
|
|
||||||
|
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
|
||||||
|
if ctx.Doer != nil {
|
||||||
|
var err error
|
||||||
|
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
|
||||||
|
if err != nil {
|
||||||
|
return accessMode, err
|
||||||
|
}
|
||||||
|
// If access mode is less than write check every team for more permissions
|
||||||
|
if accessMode < perm.AccessModeWrite {
|
||||||
|
teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
|
||||||
|
if err != nil {
|
||||||
|
return accessMode, err
|
||||||
|
}
|
||||||
|
for _, t := range teams {
|
||||||
|
perm := t.UnitAccessModeCtx(ctx, unit.TypePackages)
|
||||||
|
if accessMode < perm {
|
||||||
|
accessMode = perm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 2. If authorize level is none, check if org is visible to user
|
||||||
|
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
|
||||||
|
accessMode = perm.AccessModeRead
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
|
||||||
|
// 1. Check if user is package owner
|
||||||
|
if ctx.Doer.ID == ctx.Package.Owner.ID {
|
||||||
|
accessMode = perm.AccessModeOwner
|
||||||
|
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
||||||
|
accessMode = perm.AccessModeRead
|
||||||
|
}
|
||||||
|
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
||||||
|
accessMode = perm.AccessModeRead
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return accessMode, nil
|
||||||
|
}
|
||||||
|
|
||||||
// PackageContexter initializes a package context for a request.
|
// PackageContexter initializes a package context for a request.
|
||||||
func PackageContexter() func(next http.Handler) http.Handler {
|
func PackageContexter() func(next http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
|
|
|
@ -118,7 +118,7 @@ type CanCommitToBranchResults struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanCommitToBranch returns true if repository is editable and user has proper access level
|
// CanCommitToBranch returns true if repository is editable and user has proper access level
|
||||||
// and branch is not protected for push
|
// and branch is not protected for push
|
||||||
func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
|
func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) {
|
||||||
protectedBranch, err := git_model.GetProtectedBranchBy(ctx, r.Repository.ID, r.BranchName)
|
protectedBranch, err := git_model.GetProtectedBranchBy(ctx, r.Repository.ID, r.BranchName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -524,7 +524,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["NumTags"], err = models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
|
ctx.Data["NumTags"], err = models.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, models.FindReleasesOptions{
|
||||||
IncludeTags: true,
|
IncludeDrafts: true,
|
||||||
|
IncludeTags: true,
|
||||||
|
HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetReleaseCountByRepoID", err)
|
ctx.ServerError("GetReleaseCountByRepoID", err)
|
||||||
|
|
|
@ -322,7 +322,7 @@ func TestGuessDelimiter(t *testing.T) {
|
||||||
},
|
},
|
||||||
// case 3 - tab delimited
|
// case 3 - tab delimited
|
||||||
{
|
{
|
||||||
csv: "1 2",
|
csv: "1\t2",
|
||||||
expectedDelimiter: '\t',
|
expectedDelimiter: '\t',
|
||||||
},
|
},
|
||||||
// case 4 - pipe delimited
|
// case 4 - pipe delimited
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -40,6 +40,7 @@ type Command struct {
|
||||||
parentContext context.Context
|
parentContext context.Context
|
||||||
desc string
|
desc string
|
||||||
globalArgsLength int
|
globalArgsLength int
|
||||||
|
brokenArgs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Command) String() string {
|
func (c *Command) String() string {
|
||||||
|
@ -50,6 +51,7 @@ func (c *Command) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommand creates and returns a new Git Command based on given command and arguments.
|
// NewCommand creates and returns a new Git Command based on given command and arguments.
|
||||||
|
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func NewCommand(ctx context.Context, args ...string) *Command {
|
func NewCommand(ctx context.Context, args ...string) *Command {
|
||||||
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
|
// Make an explicit copy of globalCommandArgs, otherwise append might overwrite it
|
||||||
cargs := make([]string, len(globalCommandArgs))
|
cargs := make([]string, len(globalCommandArgs))
|
||||||
|
@ -63,11 +65,13 @@ func NewCommand(ctx context.Context, args ...string) *Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
// NewCommandNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
||||||
|
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func NewCommandNoGlobals(args ...string) *Command {
|
func NewCommandNoGlobals(args ...string) *Command {
|
||||||
return NewCommandContextNoGlobals(DefaultContext, args...)
|
return NewCommandContextNoGlobals(DefaultContext, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
// NewCommandContextNoGlobals creates and returns a new Git Command based on given command and arguments only with the specify args and don't care global command args
|
||||||
|
// Each argument should be safe to be trusted. User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
|
func NewCommandContextNoGlobals(ctx context.Context, args ...string) *Command {
|
||||||
return &Command{
|
return &Command{
|
||||||
name: GitExecutable,
|
name: GitExecutable,
|
||||||
|
@ -89,12 +93,28 @@ func (c *Command) SetDescription(desc string) *Command {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddArguments adds new argument(s) to the command.
|
// AddArguments adds new argument(s) to the command. Each argument must be safe to be trusted.
|
||||||
|
// User-provided arguments should be passed to AddDynamicArguments instead.
|
||||||
func (c *Command) AddArguments(args ...string) *Command {
|
func (c *Command) AddArguments(args ...string) *Command {
|
||||||
c.args = append(c.args, args...)
|
c.args = append(c.args, args...)
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddDynamicArguments adds new dynamic argument(s) to the command.
|
||||||
|
// The arguments may come from user input and can not be trusted, so no leading '-' is allowed to avoid passing options
|
||||||
|
func (c *Command) AddDynamicArguments(args ...string) *Command {
|
||||||
|
for _, arg := range args {
|
||||||
|
if arg != "" && arg[0] == '-' {
|
||||||
|
c.brokenArgs = append(c.brokenArgs, arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(c.brokenArgs) != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
c.args = append(c.args, args...)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
|
// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored.
|
||||||
type RunOpts struct {
|
type RunOpts struct {
|
||||||
Env []string
|
Env []string
|
||||||
|
@ -138,8 +158,14 @@ func CommonCmdServEnvs() []string {
|
||||||
return commonBaseEnvs()
|
return commonBaseEnvs()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrBrokenCommand = errors.New("git command is broken")
|
||||||
|
|
||||||
// Run runs the command with the RunOpts
|
// Run runs the command with the RunOpts
|
||||||
func (c *Command) Run(opts *RunOpts) error {
|
func (c *Command) Run(opts *RunOpts) error {
|
||||||
|
if len(c.brokenArgs) != 0 {
|
||||||
|
log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
|
||||||
|
return ErrBrokenCommand
|
||||||
|
}
|
||||||
if opts == nil {
|
if opts == nil {
|
||||||
opts = &RunOpts{}
|
opts = &RunOpts{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,19 @@ func TestRunWithContextStd(t *testing.T) {
|
||||||
assert.Contains(t, err.Error(), "exit status 129 - unknown option:")
|
assert.Contains(t, err.Error(), "exit status 129 - unknown option:")
|
||||||
assert.Empty(t, stdout)
|
assert.Empty(t, stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd = NewCommand(context.Background())
|
||||||
|
cmd.AddDynamicArguments("-test")
|
||||||
|
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
|
||||||
|
|
||||||
|
cmd = NewCommand(context.Background())
|
||||||
|
cmd.AddDynamicArguments("--test")
|
||||||
|
assert.ErrorIs(t, cmd.Run(&RunOpts{}), ErrBrokenCommand)
|
||||||
|
|
||||||
|
subCmd := "version"
|
||||||
|
cmd = NewCommand(context.Background()).AddDynamicArguments(subCmd) // for test purpose only, the sub-command should never be dynamic for production
|
||||||
|
stdout, stderr, err = cmd.RunStdString(&RunOpts{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Empty(t, stderr)
|
||||||
|
assert.Contains(t, stdout, "git version")
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ func AllCommitsCount(ctx context.Context, repoPath string, hidePRRefs bool, file
|
||||||
// CommitsCountFiles returns number of total commits of until given revision.
|
// CommitsCountFiles returns number of total commits of until given revision.
|
||||||
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
|
func CommitsCountFiles(ctx context.Context, repoPath string, revision, relpath []string) (int64, error) {
|
||||||
cmd := NewCommand(ctx, "rev-list", "--count")
|
cmd := NewCommand(ctx, "rev-list", "--count")
|
||||||
cmd.AddArguments(revision...)
|
cmd.AddDynamicArguments(revision...)
|
||||||
if len(relpath) > 0 {
|
if len(relpath) > 0 {
|
||||||
cmd.AddArguments("--")
|
cmd.AddArguments("--")
|
||||||
cmd.AddArguments(relpath...)
|
cmd.AddArguments(relpath...)
|
||||||
|
|
|
@ -68,8 +68,7 @@ func NewParser(r io.Reader, format Format) *Parser {
|
||||||
//
|
//
|
||||||
// It could, for example return something like:
|
// It could, for example return something like:
|
||||||
//
|
//
|
||||||
// { "objecttype": "tag", "refname:short": "v1.16.4", "object": "f460b7543ed500e49c133c2cd85c8c55ee9dbe27" }
|
// { "objecttype": "tag", "refname:short": "v1.16.4", "object": "f460b7543ed500e49c133c2cd85c8c55ee9dbe27" }
|
||||||
//
|
|
||||||
func (p *Parser) Next() map[string]string {
|
func (p *Parser) Next() map[string]string {
|
||||||
if !p.scanner.Scan() {
|
if !p.scanner.Scan() {
|
||||||
return nil
|
return nil
|
||||||
|
@ -89,8 +88,7 @@ func (p *Parser) Err() error {
|
||||||
|
|
||||||
// parseRef parses out all key-value pairs from a single reference block, such as
|
// parseRef parses out all key-value pairs from a single reference block, such as
|
||||||
//
|
//
|
||||||
// "objecttype tag\0refname:short v1.16.4\0object f460b7543ed500e49c133c2cd85c8c55ee9dbe27"
|
// "objecttype tag\0refname:short v1.16.4\0object f460b7543ed500e49c133c2cd85c8c55ee9dbe27"
|
||||||
//
|
|
||||||
func (p *Parser) parseRef(refBlock string) (map[string]string, error) {
|
func (p *Parser) parseRef(refBlock string) (map[string]string, error) {
|
||||||
if refBlock == "" {
|
if refBlock == "" {
|
||||||
// must be at EOF
|
// must be at EOF
|
||||||
|
|
|
@ -44,7 +44,7 @@ func parseTreeEntries(data []byte, ptree *Tree) ([]*TreeEntry, error) {
|
||||||
case "160000":
|
case "160000":
|
||||||
entry.entryMode = EntryModeCommit
|
entry.entryMode = EntryModeCommit
|
||||||
pos += 14 // skip over "160000 object "
|
pos += 14 // skip over "160000 object "
|
||||||
case "040000":
|
case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
|
||||||
entry.entryMode = EntryModeTree
|
entry.entryMode = EntryModeTree
|
||||||
pos += 12 // skip over "040000 tree "
|
pos += 12 // skip over "040000 tree "
|
||||||
default:
|
default:
|
||||||
|
@ -119,7 +119,7 @@ loop:
|
||||||
entry.entryMode = EntryModeSymlink
|
entry.entryMode = EntryModeSymlink
|
||||||
case "160000":
|
case "160000":
|
||||||
entry.entryMode = EntryModeCommit
|
entry.entryMode = EntryModeCommit
|
||||||
case "40000":
|
case "40000", "40755": // git uses 40000 for tree object, but some users may get 40755 for unknown reasons
|
||||||
entry.entryMode = EntryModeTree
|
entry.entryMode = EntryModeTree
|
||||||
default:
|
default:
|
||||||
log.Debug("Unknown mode: %v", string(mode))
|
log.Debug("Unknown mode: %v", string(mode))
|
||||||
|
|
|
@ -191,8 +191,8 @@ func (c *CheckAttributeReader) Run() error {
|
||||||
// CheckPath check attr for given path
|
// CheckPath check attr for given path
|
||||||
func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
|
func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil && err != c.ctx.Err() {
|
||||||
log.Error("CheckPath returns error: %v", err)
|
log.Error("Unexpected error when checking path %s in %s. Error: %v", path, c.Repo.Path, err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ func (repo *Repository) searchCommits(id SHA1, opts SearchCommitsOptions) ([]*Co
|
||||||
// add previous arguments except for --grep and --all
|
// add previous arguments except for --grep and --all
|
||||||
hashCmd.AddArguments(args...)
|
hashCmd.AddArguments(args...)
|
||||||
// add keyword as <commit>
|
// add keyword as <commit>
|
||||||
hashCmd.AddArguments(v)
|
hashCmd.AddDynamicArguments(v)
|
||||||
|
|
||||||
// search with given constraints for commit matching sha hash of v
|
// search with given constraints for commit matching sha hash of v
|
||||||
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
|
hashMatching, _, err := hashCmd.RunStdBytes(&RunOpts{Dir: repo.Path})
|
||||||
|
@ -208,14 +208,15 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (
|
||||||
}()
|
}()
|
||||||
go func() {
|
go func() {
|
||||||
stderr := strings.Builder{}
|
stderr := strings.Builder{}
|
||||||
err := NewCommand(repo.Ctx, "log", revision, "--follow",
|
gitCmd := NewCommand(repo.Ctx, "log", prettyLogFormat, "--follow",
|
||||||
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page),
|
"--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page))
|
||||||
prettyLogFormat, "--", file).
|
gitCmd.AddDynamicArguments(revision)
|
||||||
Run(&RunOpts{
|
gitCmd.AddArguments("--", file)
|
||||||
Dir: repo.Path,
|
err := gitCmd.Run(&RunOpts{
|
||||||
Stdout: stdoutWriter,
|
Dir: repo.Path,
|
||||||
Stderr: &stderr,
|
Stdout: stdoutWriter,
|
||||||
})
|
Stderr: &stderr,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
_ = stdoutWriter.CloseWithError(ConcatenateError(err, (&stderr).String()))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -59,15 +59,15 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
|
||||||
_ = stdoutWriter.Close()
|
_ = stdoutWriter.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
args := []string{"log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since)}
|
gitCmd := NewCommand(repo.Ctx, "log", "--numstat", "--no-merges", "--pretty=format:---%n%h%n%aN%n%aE%n", "--date=iso", fmt.Sprintf("--since='%s'", since))
|
||||||
if len(branch) == 0 {
|
if len(branch) == 0 {
|
||||||
args = append(args, "--branches=*")
|
gitCmd.AddArguments("--branches=*")
|
||||||
} else {
|
} else {
|
||||||
args = append(args, "--first-parent", branch)
|
gitCmd.AddArguments("--first-parent").AddDynamicArguments(branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
stderr := new(strings.Builder)
|
stderr := new(strings.Builder)
|
||||||
err = NewCommand(repo.Ctx, args...).Run(&RunOpts{
|
err = gitCmd.Run(&RunOpts{
|
||||||
Env: []string{},
|
Env: []string{},
|
||||||
Dir: repo.Path,
|
Dir: repo.Path,
|
||||||
Stdout: stdoutWriter,
|
Stdout: stdoutWriter,
|
||||||
|
|
|
@ -19,8 +19,10 @@ import (
|
||||||
type Signature = object.Signature
|
type Signature = object.Signature
|
||||||
|
|
||||||
// Helper to get a signature from the commit line, which looks like these:
|
// Helper to get a signature from the commit line, which looks like these:
|
||||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
//
|
||||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||||
|
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||||
|
//
|
||||||
// but without the "author " at the beginning (this method should)
|
// but without the "author " at the beginning (this method should)
|
||||||
// be used for author and committer.
|
// be used for author and committer.
|
||||||
//
|
//
|
||||||
|
|
|
@ -37,8 +37,10 @@ func (s *Signature) Decode(b []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to get a signature from the commit line, which looks like these:
|
// Helper to get a signature from the commit line, which looks like these:
|
||||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
//
|
||||||
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||||
|
// author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
|
||||||
|
//
|
||||||
// but without the "author " at the beginning (this method should)
|
// but without the "author " at the beginning (this method should)
|
||||||
// be used for author and committer.
|
// be used for author and committer.
|
||||||
func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
|
||||||
|
|
|
@ -24,19 +24,17 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
|
||||||
page = 1
|
page = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
args := make([]string, 0, 12+len(branches)+len(files))
|
graphCmd := git.NewCommand(r.Ctx, "log", "--graph", "--date-order", "--decorate=full")
|
||||||
|
|
||||||
args = append(args, "--graph", "--date-order", "--decorate=full")
|
|
||||||
|
|
||||||
if hidePRRefs {
|
if hidePRRefs {
|
||||||
args = append(args, "--exclude="+git.PullPrefix+"*")
|
graphCmd.AddArguments("--exclude=" + git.PullPrefix + "*")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(branches) == 0 {
|
if len(branches) == 0 {
|
||||||
args = append(args, "--all")
|
graphCmd.AddArguments("--all")
|
||||||
}
|
}
|
||||||
|
|
||||||
args = append(args,
|
graphCmd.AddArguments(
|
||||||
"-C",
|
"-C",
|
||||||
"-M",
|
"-M",
|
||||||
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
|
fmt.Sprintf("-n %d", setting.UI.GraphMaxCommitNum*page),
|
||||||
|
@ -44,15 +42,12 @@ func GetCommitGraph(r *git.Repository, page, maxAllowedColors int, hidePRRefs bo
|
||||||
fmt.Sprintf("--pretty=format:%s", format))
|
fmt.Sprintf("--pretty=format:%s", format))
|
||||||
|
|
||||||
if len(branches) > 0 {
|
if len(branches) > 0 {
|
||||||
args = append(args, branches...)
|
graphCmd.AddDynamicArguments(branches...)
|
||||||
}
|
}
|
||||||
args = append(args, "--")
|
|
||||||
if len(files) > 0 {
|
if len(files) > 0 {
|
||||||
args = append(args, files...)
|
graphCmd.AddArguments("--")
|
||||||
|
graphCmd.AddArguments(files...)
|
||||||
}
|
}
|
||||||
|
|
||||||
graphCmd := git.NewCommand(r.Ctx, "log")
|
|
||||||
graphCmd.AddArguments(args...)
|
|
||||||
graph := NewGraph()
|
graph := NewGraph()
|
||||||
|
|
||||||
stderr := new(strings.Builder)
|
stderr := new(strings.Builder)
|
||||||
|
|
|
@ -93,6 +93,7 @@ func NewFileLogger() LoggerProvider {
|
||||||
|
|
||||||
// Init file logger with json config.
|
// Init file logger with json config.
|
||||||
// config like:
|
// config like:
|
||||||
|
//
|
||||||
// {
|
// {
|
||||||
// "filename":"log/gogs.log",
|
// "filename":"log/gogs.log",
|
||||||
// "maxsize":1<<30,
|
// "maxsize":1<<30,
|
||||||
|
|
|
@ -48,6 +48,7 @@ func NewSMTPLogger() LoggerProvider {
|
||||||
|
|
||||||
// Init smtp writer with json config.
|
// Init smtp writer with json config.
|
||||||
// config like:
|
// config like:
|
||||||
|
//
|
||||||
// {
|
// {
|
||||||
// "Username":"example@gmail.com",
|
// "Username":"example@gmail.com",
|
||||||
// "password:"password",
|
// "password:"password",
|
||||||
|
|
|
@ -7,6 +7,7 @@ package markup_test
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ func TestMain(m *testing.M) {
|
||||||
if err := git.InitSimple(context.Background()); err != nil {
|
if err := git.InitSimple(context.Background()); err != nil {
|
||||||
log.Fatal("git init failed, err: %v", err)
|
log.Fatal("git init failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRender_Commits(t *testing.T) {
|
func TestRender_Commits(t *testing.T) {
|
||||||
|
@ -336,7 +338,7 @@ func TestRender_emoji(t *testing.T) {
|
||||||
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
||||||
test(
|
test(
|
||||||
"😎🤪🔐🤑❓",
|
"😎🤪🔐🤑❓",
|
||||||
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="question mark">❓</span></p>`)
|
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="red question mark">❓</span></p>`)
|
||||||
|
|
||||||
// should match nothing
|
// should match nothing
|
||||||
test(
|
test(
|
||||||
|
|
|
@ -6,6 +6,7 @@ package markdown_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ func TestMain(m *testing.M) {
|
||||||
if err := git.InitSimple(context.Background()); err != nil {
|
if err := git.InitSimple(context.Background()); err != nil {
|
||||||
log.Fatal("git init failed, err: %v", err)
|
log.Fatal("git init failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRender_StandardLinks(t *testing.T) {
|
func TestRender_StandardLinks(t *testing.T) {
|
||||||
|
|
|
@ -141,7 +141,7 @@ func (r *stripRenderer) AddOptions(...renderer.Option) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// StripMarkdown parses markdown content by removing all markup and code blocks
|
// StripMarkdown parses markdown content by removing all markup and code blocks
|
||||||
// in order to extract links and other references
|
// in order to extract links and other references
|
||||||
func StripMarkdown(rawBytes []byte) (string, []string) {
|
func StripMarkdown(rawBytes []byte) (string, []string) {
|
||||||
buf, links := StripMarkdownBytes(rawBytes)
|
buf, links := StripMarkdownBytes(rawBytes)
|
||||||
return string(buf), links
|
return string(buf), links
|
||||||
|
@ -153,7 +153,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// StripMarkdownBytes parses markdown content by removing all markup and code blocks
|
// StripMarkdownBytes parses markdown content by removing all markup and code blocks
|
||||||
// in order to extract links and other references
|
// in order to extract links and other references
|
||||||
func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) {
|
func StripMarkdownBytes(rawBytes []byte) ([]byte, []string) {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
gdMarkdown := goldmark.New(
|
gdMarkdown := goldmark.New(
|
||||||
|
|
|
@ -315,13 +315,5 @@ func IsMarkupFile(name, markup string) bool {
|
||||||
// Note that the '.' should be provided in ext, e.g ".md"
|
// Note that the '.' should be provided in ext, e.g ".md"
|
||||||
func IsReadmeFile(name string, ext ...string) bool {
|
func IsReadmeFile(name string, ext ...string) bool {
|
||||||
name = strings.ToLower(name)
|
name = strings.ToLower(name)
|
||||||
if len(ext) > 0 {
|
return name == "readme" || strings.Index(name, "readme.") == 0 || strings.Index(name, ".readme.") == 0
|
||||||
return name == "readme"+ext[0]
|
|
||||||
}
|
|
||||||
if len(name) < 6 {
|
|
||||||
return false
|
|
||||||
} else if len(name) == 6 {
|
|
||||||
return name == "readme"
|
|
||||||
}
|
|
||||||
return name[:7] == "readme."
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,9 @@ func parseOCIImageConfig(r io.Reader) (*Metadata, error) {
|
||||||
if i := strings.Index(cmd, "#(nop) "); i != -1 {
|
if i := strings.Index(cmd, "#(nop) "); i != -1 {
|
||||||
cmd = strings.TrimSpace(cmd[i+7:])
|
cmd = strings.TrimSpace(cmd[i+7:])
|
||||||
}
|
}
|
||||||
imageLayers = append(imageLayers, cmd)
|
if cmd != "" {
|
||||||
|
imageLayers = append(imageLayers, cmd)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata := &Metadata{
|
metadata := &Metadata{
|
||||||
|
|
|
@ -25,7 +25,7 @@ func DumpMemProfileForUsername(pprofDataPath, username string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpCPUProfileForUsername dumps a CPU profile at pprofDataPath as cpuprofile_<username>_<temporary id>
|
// DumpCPUProfileForUsername dumps a CPU profile at pprofDataPath as cpuprofile_<username>_<temporary id>
|
||||||
// it returns the stop function which stops, writes and closes the CPU profile file
|
// the stop function it returns stops, writes and closes the CPU profile file
|
||||||
func DumpCPUProfileForUsername(pprofDataPath, username string) (func(), error) {
|
func DumpCPUProfileForUsername(pprofDataPath, username string) (func(), error) {
|
||||||
f, err := os.CreateTemp(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username))
|
f, err := os.CreateTemp(pprofDataPath, fmt.Sprintf("cpuprofile_%s_", username))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -31,8 +31,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GitHub, GitLab, Gogs: *.wiki.git
|
GitHub, GitLab, Gogs: *.wiki.git
|
||||||
BitBucket: *.git/wiki
|
BitBucket: *.git/wiki
|
||||||
*/
|
*/
|
||||||
var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"}
|
var commonWikiURLSuffixes = []string{".wiki.git", ".git/wiki"}
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,10 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)
|
||||||
if err := util.Rename(tmp.Name(), p); err != nil {
|
if err := util.Rename(tmp.Name(), p); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
// Golang's tmp file (os.CreateTemp) always have 0o600 mode, so we need to change the file to follow the umask (as what Create/MkDir does)
|
||||||
|
if err := util.ApplyUmask(p, os.ModePerm); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
tmpRemoved = true
|
tmpRemoved = true
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,7 @@ func NewFuncMap() []template.FuncMap {
|
||||||
"DiffTypeToStr": DiffTypeToStr,
|
"DiffTypeToStr": DiffTypeToStr,
|
||||||
"DiffLineTypeToStr": DiffLineTypeToStr,
|
"DiffLineTypeToStr": DiffLineTypeToStr,
|
||||||
"ShortSha": base.ShortSha,
|
"ShortSha": base.ShortSha,
|
||||||
|
"MD5": base.EncodeMD5,
|
||||||
"ActionContent2Commits": ActionContent2Commits,
|
"ActionContent2Commits": ActionContent2Commits,
|
||||||
"PathEscape": url.PathEscape,
|
"PathEscape": url.PathEscape,
|
||||||
"PathEscapeSegments": util.PathEscapeSegments,
|
"PathEscapeSegments": util.PathEscapeSegments,
|
||||||
|
|
|
@ -41,14 +41,14 @@ func NewLocaleStore() *LocaleStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddLocaleByIni adds locale by ini into the store
|
// AddLocaleByIni adds locale by ini into the store
|
||||||
func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
|
func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, source, moreSource []byte) error {
|
||||||
if _, ok := ls.localeMap[langName]; ok {
|
if _, ok := ls.localeMap[langName]; ok {
|
||||||
return ErrLocaleAlreadyExist
|
return ErrLocaleAlreadyExist
|
||||||
}
|
}
|
||||||
iniFile, err := ini.LoadSources(ini.LoadOptions{
|
iniFile, err := ini.LoadSources(ini.LoadOptions{
|
||||||
IgnoreInlineComment: true,
|
IgnoreInlineComment: true,
|
||||||
UnescapeValueCommentSymbols: true,
|
UnescapeValueCommentSymbols: true,
|
||||||
}, localeFile, otherLocaleFiles...)
|
}, source, moreSource)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
iniFile.BlockMode = false
|
iniFile.BlockMode = false
|
||||||
lc := &locale{store: ls, langName: langName, langDesc: langDesc, messages: iniFile}
|
lc := &locale{store: ls, langName: langName, langDesc: langDesc, messages: iniFile}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Tr(t *testing.T) {
|
func TestLocaleStore(t *testing.T) {
|
||||||
testData1 := []byte(`
|
testData1 := []byte(`
|
||||||
.dot.name = Dot Name
|
.dot.name = Dot Name
|
||||||
fmt = %[1]s %[2]s
|
fmt = %[1]s %[2]s
|
||||||
|
@ -28,8 +28,8 @@ sub = Changed Sub String
|
||||||
`)
|
`)
|
||||||
|
|
||||||
ls := NewLocaleStore()
|
ls := NewLocaleStore()
|
||||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1))
|
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, nil))
|
||||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2))
|
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2, nil))
|
||||||
ls.SetDefaultLang("lang1")
|
ls.SetDefaultLang("lang1")
|
||||||
|
|
||||||
result := ls.Tr("lang1", "fmt", "a", "b")
|
result := ls.Tr("lang1", "fmt", "a", "b")
|
||||||
|
@ -54,3 +54,21 @@ sub = Changed Sub String
|
||||||
assert.Equal(t, []string{"lang1", "lang2"}, langs)
|
assert.Equal(t, []string{"lang1", "lang2"}, langs)
|
||||||
assert.Equal(t, []string{"Lang1", "Lang2"}, descs)
|
assert.Equal(t, []string{"Lang1", "Lang2"}, descs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocaleStoreMoreSource(t *testing.T) {
|
||||||
|
testData1 := []byte(`
|
||||||
|
a=11
|
||||||
|
b=12
|
||||||
|
`)
|
||||||
|
|
||||||
|
testData2 := []byte(`
|
||||||
|
b=21
|
||||||
|
c=22
|
||||||
|
`)
|
||||||
|
|
||||||
|
ls := NewLocaleStore()
|
||||||
|
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1, testData2))
|
||||||
|
assert.Equal(t, "11", ls.Tr("lang1", "a"))
|
||||||
|
assert.Equal(t, "21", ls.Tr("lang1", "b"))
|
||||||
|
assert.Equal(t, "22", ls.Tr("lang1", "c"))
|
||||||
|
}
|
||||||
|
|
|
@ -60,9 +60,9 @@ func InitLocales() {
|
||||||
log.Fatal("Failed to list locale files: %v", err)
|
log.Fatal("Failed to list locale files: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
localFiles := make(map[string][]byte, len(localeNames))
|
localeData := make(map[string][]byte, len(localeNames))
|
||||||
for _, name := range localeNames {
|
for _, name := range localeNames {
|
||||||
localFiles[name], err = options.Locale(name)
|
localeData[name], err = options.Locale(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to load %s locale file. %v", name, err)
|
log.Fatal("Failed to load %s locale file. %v", name, err)
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,16 @@ func InitLocales() {
|
||||||
|
|
||||||
matcher = language.NewMatcher(supportedTags)
|
matcher = language.NewMatcher(supportedTags)
|
||||||
for i := range setting.Names {
|
for i := range setting.Names {
|
||||||
|
var localeDataBase []byte
|
||||||
|
if i == 0 && setting.Langs[0] != "en-US" {
|
||||||
|
// Only en-US has complete translations. When use other language as default, the en-US should still be used as fallback.
|
||||||
|
localeDataBase = localeData["locale_en-US.ini"]
|
||||||
|
if localeDataBase == nil {
|
||||||
|
log.Fatal("Failed to load locale_en-US.ini file.")
|
||||||
|
}
|
||||||
|
}
|
||||||
key := "locale_" + setting.Langs[i] + ".ini"
|
key := "locale_" + setting.Langs[i] + ".ini"
|
||||||
if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
|
if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localeDataBase, localeData[key]); err != nil {
|
||||||
log.Error("Failed to set messages to %s: %v", setting.Langs[i], err)
|
log.Error("Failed to set messages to %s: %v", setting.Langs[i], err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
28
modules/util/file_unix.go
Normal file
28
modules/util/file_unix.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultUmask int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// at the moment, the umask could only be gotten by calling unix.Umask(newUmask)
|
||||||
|
// use 0o077 as temp new umask to reduce the risks if this umask is used anywhere else before the correct umask is recovered
|
||||||
|
tempUmask := 0o077
|
||||||
|
defaultUmask = unix.Umask(tempUmask)
|
||||||
|
unix.Umask(defaultUmask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplyUmask(f string, newMode os.FileMode) error {
|
||||||
|
mod := newMode & ^os.FileMode(defaultUmask)
|
||||||
|
return os.Chmod(f, mod)
|
||||||
|
}
|
36
modules/util/file_unix_test.go
Normal file
36
modules/util/file_unix_test.go
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestApplyUmask(t *testing.T) {
|
||||||
|
f, err := os.CreateTemp(t.TempDir(), "test-filemode-")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.Chmod(f.Name(), 0o777)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
st, err := os.Stat(f.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0o777, st.Mode().Perm()&0o777)
|
||||||
|
|
||||||
|
oldDefaultUmask := defaultUmask
|
||||||
|
defaultUmask = 0o037
|
||||||
|
defer func() {
|
||||||
|
defaultUmask = oldDefaultUmask
|
||||||
|
}()
|
||||||
|
err = ApplyUmask(f.Name(), os.ModePerm)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
st, err = os.Stat(f.Name())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0o740, st.Mode().Perm()&0o777)
|
||||||
|
}
|
16
modules/util/file_windows.go
Normal file
16
modules/util/file_windows.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ApplyUmask(f string, newMode os.FileMode) error {
|
||||||
|
// do nothing for Windows, because Windows doesn't use umask
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -17,13 +17,13 @@ func isSnakeCaseLowerOrNumber(c byte) bool {
|
||||||
// ToSnakeCase convert the input string to snake_case format.
|
// ToSnakeCase convert the input string to snake_case format.
|
||||||
//
|
//
|
||||||
// Some samples.
|
// Some samples.
|
||||||
// "FirstName" => "first_name"
|
|
||||||
// "HTTPServer" => "http_server"
|
|
||||||
// "NoHTTPS" => "no_https"
|
|
||||||
// "GO_PATH" => "go_path"
|
|
||||||
// "GO PATH" => "go_path" // space is converted to underscore.
|
|
||||||
// "GO-PATH" => "go_path" // hyphen is converted to underscore.
|
|
||||||
//
|
//
|
||||||
|
// "FirstName" => "first_name"
|
||||||
|
// "HTTPServer" => "http_server"
|
||||||
|
// "NoHTTPS" => "no_https"
|
||||||
|
// "GO_PATH" => "go_path"
|
||||||
|
// "GO PATH" => "go_path" // space is converted to underscore.
|
||||||
|
// "GO-PATH" => "go_path" // hyphen is converted to underscore.
|
||||||
func ToSnakeCase(input string) string {
|
func ToSnakeCase(input string) string {
|
||||||
if len(input) == 0 {
|
if len(input) == 0 {
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -66,7 +66,7 @@ func Routes() *web.Route {
|
||||||
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
|
r.Get("/p2/{vendorname}/{projectname}.json", composer.PackageMetadata)
|
||||||
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
|
r.Get("/files/{package}/{version}/{filename}", composer.DownloadPackageFile)
|
||||||
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
|
r.Put("", reqPackageAccess(perm.AccessModeWrite), composer.UploadPackage)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/conan", func() {
|
r.Group("/conan", func() {
|
||||||
r.Group("/v1", func() {
|
r.Group("/v1", func() {
|
||||||
r.Get("/ping", conan.Ping)
|
r.Get("/ping", conan.Ping)
|
||||||
|
@ -154,7 +154,7 @@ func Routes() *web.Route {
|
||||||
}, conan.ExtractPathParameters)
|
}, conan.ExtractPathParameters)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/generic", func() {
|
r.Group("/generic", func() {
|
||||||
r.Group("/{packagename}/{packageversion}/{filename}", func() {
|
r.Group("/{packagename}/{packageversion}/{filename}", func() {
|
||||||
r.Get("", generic.DownloadPackageFile)
|
r.Get("", generic.DownloadPackageFile)
|
||||||
|
@ -163,33 +163,35 @@ func Routes() *web.Route {
|
||||||
r.Delete("", generic.DeletePackage)
|
r.Delete("", generic.DeletePackage)
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/helm", func() {
|
r.Group("/helm", func() {
|
||||||
r.Get("/index.yaml", helm.Index)
|
r.Get("/index.yaml", helm.Index)
|
||||||
r.Get("/{filename}", helm.DownloadPackageFile)
|
r.Get("/{filename}", helm.DownloadPackageFile)
|
||||||
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
|
r.Post("/api/charts", reqPackageAccess(perm.AccessModeWrite), helm.UploadPackage)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/maven", func() {
|
r.Group("/maven", func() {
|
||||||
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
|
||||||
r.Get("/*", maven.DownloadPackageFile)
|
r.Get("/*", maven.DownloadPackageFile)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/nuget", func() {
|
r.Group("/nuget", func() {
|
||||||
r.Get("/index.json", nuget.ServiceIndex)
|
r.Get("/index.json", nuget.ServiceIndex) // Needs to be unauthenticated for the NuGet client.
|
||||||
r.Get("/query", nuget.SearchService)
|
|
||||||
r.Group("/registration/{id}", func() {
|
|
||||||
r.Get("/index.json", nuget.RegistrationIndex)
|
|
||||||
r.Get("/{version}", nuget.RegistrationLeaf)
|
|
||||||
})
|
|
||||||
r.Group("/package/{id}", func() {
|
|
||||||
r.Get("/index.json", nuget.EnumeratePackageVersions)
|
|
||||||
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
|
||||||
})
|
|
||||||
r.Group("", func() {
|
r.Group("", func() {
|
||||||
r.Put("/", nuget.UploadPackage)
|
r.Get("/query", nuget.SearchService)
|
||||||
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
r.Group("/registration/{id}", func() {
|
||||||
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
r.Get("/index.json", nuget.RegistrationIndex)
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
r.Get("/{version}", nuget.RegistrationLeaf)
|
||||||
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
|
})
|
||||||
|
r.Group("/package/{id}", func() {
|
||||||
|
r.Get("/index.json", nuget.EnumeratePackageVersions)
|
||||||
|
r.Get("/{version}/{filename}", nuget.DownloadPackageFile)
|
||||||
|
})
|
||||||
|
r.Group("", func() {
|
||||||
|
r.Put("/", nuget.UploadPackage)
|
||||||
|
r.Put("/symbolpackage", nuget.UploadSymbolPackage)
|
||||||
|
r.Delete("/{id}/{version}", nuget.DeletePackage)
|
||||||
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
|
r.Get("/symbols/{filename}/{guid:[0-9a-f]{32}}FFFFFFFF/{filename2}", nuget.DownloadSymbolFile)
|
||||||
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
})
|
})
|
||||||
r.Group("/npm", func() {
|
r.Group("/npm", func() {
|
||||||
r.Group("/@{scope}/{id}", func() {
|
r.Group("/@{scope}/{id}", func() {
|
||||||
|
@ -216,12 +218,12 @@ func Routes() *web.Route {
|
||||||
r.Delete("", npm.DeletePackageTag)
|
r.Delete("", npm.DeletePackageTag)
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
})
|
})
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/pypi", func() {
|
r.Group("/pypi", func() {
|
||||||
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
|
r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile)
|
||||||
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
|
r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile)
|
||||||
r.Get("/simple/{id}", pypi.PackageMetadata)
|
r.Get("/simple/{id}", pypi.PackageMetadata)
|
||||||
})
|
}, reqPackageAccess(perm.AccessModeRead))
|
||||||
r.Group("/rubygems", func() {
|
r.Group("/rubygems", func() {
|
||||||
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
|
r.Get("/specs.4.8.gz", rubygems.EnumeratePackages)
|
||||||
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
|
r.Get("/latest_specs.4.8.gz", rubygems.EnumeratePackagesLatest)
|
||||||
|
@ -233,7 +235,7 @@ func Routes() *web.Route {
|
||||||
r.Delete("/yank", rubygems.DeletePackage)
|
r.Delete("/yank", rubygems.DeletePackage)
|
||||||
}, reqPackageAccess(perm.AccessModeWrite))
|
}, reqPackageAccess(perm.AccessModeWrite))
|
||||||
})
|
})
|
||||||
}, context_service.UserAssignmentWeb(), context.PackageAssignment(), reqPackageAccess(perm.AccessModeRead))
|
}, context_service.UserAssignmentWeb(), context.PackageAssignment())
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -342,8 +342,7 @@ func uploadFile(ctx *context.Context, fileFilter stringSet, fileKey string) {
|
||||||
Name: rref.Name,
|
Name: rref.Name,
|
||||||
Version: rref.Version,
|
Version: rref.Version,
|
||||||
},
|
},
|
||||||
SemverCompatible: true,
|
Creator: ctx.Doer,
|
||||||
Creator: ctx.Doer,
|
|
||||||
}
|
}
|
||||||
pfci := &packages_service.PackageFileCreationInfo{
|
pfci := &packages_service.PackageFileCreationInfo{
|
||||||
PackageFileInfo: packages_service.PackageFileInfo{
|
PackageFileInfo: packages_service.PackageFileInfo{
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
|
|
||||||
// https://www.python.org/dev/peps/pep-0503/#normalized-names
|
// https://www.python.org/dev/peps/pep-0503/#normalized-names
|
||||||
var normalizer = strings.NewReplacer(".", "-", "_", "-")
|
var normalizer = strings.NewReplacer(".", "-", "_", "-")
|
||||||
var nameMatcher = regexp.MustCompile(`\A[a-z0-9\.\-_]+\z`)
|
var nameMatcher = regexp.MustCompile(`\A[a-zA-Z0-9\.\-_]+\z`)
|
||||||
|
|
||||||
// https://www.python.org/dev/peps/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
|
// https://www.python.org/dev/peps/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
|
||||||
var versionMatcher = regexp.MustCompile(`^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$`)
|
var versionMatcher = regexp.MustCompile(`^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?$`)
|
||||||
|
|
|
@ -7,59 +7,59 @@
|
||||||
//
|
//
|
||||||
// This documentation describes the Gitea API.
|
// This documentation describes the Gitea API.
|
||||||
//
|
//
|
||||||
// Schemes: http, https
|
// Schemes: http, https
|
||||||
// BasePath: /api/v1
|
// BasePath: /api/v1
|
||||||
// Version: {{AppVer | JSEscape | Safe}}
|
// Version: {{AppVer | JSEscape | Safe}}
|
||||||
// License: MIT http://opensource.org/licenses/MIT
|
// License: MIT http://opensource.org/licenses/MIT
|
||||||
//
|
//
|
||||||
// Consumes:
|
// Consumes:
|
||||||
// - application/json
|
// - application/json
|
||||||
// - text/plain
|
// - text/plain
|
||||||
//
|
//
|
||||||
// Produces:
|
// Produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// - text/html
|
// - text/html
|
||||||
//
|
//
|
||||||
// Security:
|
// Security:
|
||||||
// - BasicAuth :
|
// - BasicAuth :
|
||||||
// - Token :
|
// - Token :
|
||||||
// - AccessToken :
|
// - AccessToken :
|
||||||
// - AuthorizationHeaderToken :
|
// - AuthorizationHeaderToken :
|
||||||
// - SudoParam :
|
// - SudoParam :
|
||||||
// - SudoHeader :
|
// - SudoHeader :
|
||||||
// - TOTPHeader :
|
// - TOTPHeader :
|
||||||
//
|
//
|
||||||
// SecurityDefinitions:
|
// SecurityDefinitions:
|
||||||
// BasicAuth:
|
// BasicAuth:
|
||||||
// type: basic
|
// type: basic
|
||||||
// Token:
|
// Token:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: token
|
// name: token
|
||||||
// in: query
|
// in: query
|
||||||
// AccessToken:
|
// AccessToken:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: access_token
|
// name: access_token
|
||||||
// in: query
|
// in: query
|
||||||
// AuthorizationHeaderToken:
|
// AuthorizationHeaderToken:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: Authorization
|
// name: Authorization
|
||||||
// in: header
|
// in: header
|
||||||
// description: API tokens must be prepended with "token" followed by a space.
|
// description: API tokens must be prepended with "token" followed by a space.
|
||||||
// SudoParam:
|
// SudoParam:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: sudo
|
// name: sudo
|
||||||
// in: query
|
// in: query
|
||||||
// description: Sudo API request as the user provided as the key. Admin privileges are required.
|
// description: Sudo API request as the user provided as the key. Admin privileges are required.
|
||||||
// SudoHeader:
|
// SudoHeader:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: Sudo
|
// name: Sudo
|
||||||
// in: header
|
// in: header
|
||||||
// description: Sudo API request as the user provided as the key. Admin privileges are required.
|
// description: Sudo API request as the user provided as the key. Admin privileges are required.
|
||||||
// TOTPHeader:
|
// TOTPHeader:
|
||||||
// type: apiKey
|
// type: apiKey
|
||||||
// name: X-GITEA-OTP
|
// name: X-GITEA-OTP
|
||||||
// in: header
|
// in: header
|
||||||
// description: Must be used in combination with BasicAuth if two-factor authentication is enabled.
|
// description: Must be used in combination with BasicAuth if two-factor authentication is enabled.
|
||||||
//
|
//
|
||||||
// swagger:meta
|
// swagger:meta
|
||||||
package v1
|
package v1
|
||||||
|
|
|
@ -34,7 +34,7 @@ func GetGitAllRefs(ctx *context.APIContext) {
|
||||||
// required: true
|
// required: true
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/Reference"
|
// # "$ref": "#/responses/Reference" TODO: swagger doesnt support different output formats by ref
|
||||||
// "$ref": "#/responses/ReferenceList"
|
// "$ref": "#/responses/ReferenceList"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
@ -67,7 +67,7 @@ func GetGitRefs(ctx *context.APIContext) {
|
||||||
// required: true
|
// required: true
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/Reference"
|
// # "$ref": "#/responses/Reference" TODO: swagger doesnt support different output formats by ref
|
||||||
// "$ref": "#/responses/ReferenceList"
|
// "$ref": "#/responses/ReferenceList"
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
|
@ -566,6 +566,8 @@ func ListMyTrackedTimes(ctx *context.APIContext) {
|
||||||
// swagger:operation GET /user/times user userCurrentTrackedTimes
|
// swagger:operation GET /user/times user userCurrentTrackedTimes
|
||||||
// ---
|
// ---
|
||||||
// summary: List the current user's tracked times
|
// summary: List the current user's tracked times
|
||||||
|
// produces:
|
||||||
|
// - application/json
|
||||||
// parameters:
|
// parameters:
|
||||||
// - name: page
|
// - name: page
|
||||||
// in: query
|
// in: query
|
||||||
|
@ -575,9 +577,6 @@ func ListMyTrackedTimes(ctx *context.APIContext) {
|
||||||
// in: query
|
// in: query
|
||||||
// description: page size of results
|
// description: page size of results
|
||||||
// type: integer
|
// type: integer
|
||||||
// produces:
|
|
||||||
// - application/json
|
|
||||||
// parameters:
|
|
||||||
// - name: since
|
// - name: since
|
||||||
// in: query
|
// in: query
|
||||||
// description: Only show times updated after the given time. This is a timestamp in RFC 3339 format
|
// description: Only show times updated after the given time. This is a timestamp in RFC 3339 format
|
||||||
|
|
|
@ -585,7 +585,6 @@ func Edit(ctx *context.APIContext) {
|
||||||
// description: name of the repo to edit
|
// description: name of the repo to edit
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
// required: true
|
|
||||||
// - name: body
|
// - name: body
|
||||||
// in: body
|
// in: body
|
||||||
// description: "Properties of a repo that you can edit"
|
// description: "Properties of a repo that you can edit"
|
||||||
|
|
|
@ -48,11 +48,6 @@ func AddEmail(ctx *context.APIContext) {
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// parameters:
|
// parameters:
|
||||||
// - name: options
|
|
||||||
// in: body
|
|
||||||
// schema:
|
|
||||||
// "$ref": "#/definitions/CreateEmailOption"
|
|
||||||
// parameters:
|
|
||||||
// - name: body
|
// - name: body
|
||||||
// in: body
|
// in: body
|
||||||
// schema:
|
// schema:
|
||||||
|
|
|
@ -588,7 +588,8 @@ func OIDCKeys(ctx *context.Context) {
|
||||||
// AccessTokenOAuth manages all access token requests by the client
|
// AccessTokenOAuth manages all access token requests by the client
|
||||||
func AccessTokenOAuth(ctx *context.Context) {
|
func AccessTokenOAuth(ctx *context.Context) {
|
||||||
form := *web.GetForm(ctx).(*forms.AccessTokenForm)
|
form := *web.GetForm(ctx).(*forms.AccessTokenForm)
|
||||||
if form.ClientID == "" {
|
// if there is no ClientID or ClientSecret in the request body, fill these fields by the Authorization header and ensure the provided field matches the Authorization header
|
||||||
|
if form.ClientID == "" || form.ClientSecret == "" {
|
||||||
authHeader := ctx.Req.Header.Get("Authorization")
|
authHeader := ctx.Req.Header.Get("Authorization")
|
||||||
authContent := strings.SplitN(authHeader, " ", 2)
|
authContent := strings.SplitN(authHeader, " ", 2)
|
||||||
if len(authContent) == 2 && authContent[0] == "Basic" {
|
if len(authContent) == 2 && authContent[0] == "Basic" {
|
||||||
|
@ -608,7 +609,21 @@ func AccessTokenOAuth(ctx *context.Context) {
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if form.ClientID != "" && form.ClientID != pair[0] {
|
||||||
|
handleAccessTokenError(ctx, AccessTokenError{
|
||||||
|
ErrorCode: AccessTokenErrorCodeInvalidRequest,
|
||||||
|
ErrorDescription: "client_id in request body inconsistent with Authorization header",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
form.ClientID = pair[0]
|
form.ClientID = pair[0]
|
||||||
|
if form.ClientSecret != "" && form.ClientSecret != pair[1] {
|
||||||
|
handleAccessTokenError(ctx, AccessTokenError{
|
||||||
|
ErrorCode: AccessTokenErrorCodeInvalidRequest,
|
||||||
|
ErrorDescription: "client_secret in request body inconsistent with Authorization header",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
form.ClientSecret = pair[1]
|
form.ClientSecret = pair[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -686,9 +701,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !app.ValidateClientSecret([]byte(form.ClientSecret)) {
|
if !app.ValidateClientSecret([]byte(form.ClientSecret)) {
|
||||||
|
errorDescription := "invalid client secret"
|
||||||
|
if form.ClientSecret == "" {
|
||||||
|
errorDescription = "invalid empty client secret"
|
||||||
|
}
|
||||||
handleAccessTokenError(ctx, AccessTokenError{
|
handleAccessTokenError(ctx, AccessTokenError{
|
||||||
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
|
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
|
||||||
ErrorDescription: "client is not authorized",
|
ErrorDescription: errorDescription,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,27 +24,27 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func toBranchLink(act *models.Action) string {
|
func toBranchLink(act *models.Action) string {
|
||||||
return act.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch())
|
return act.GetRepoAbsoluteLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch())
|
||||||
}
|
}
|
||||||
|
|
||||||
func toTagLink(act *models.Action) string {
|
func toTagLink(act *models.Action) string {
|
||||||
return act.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag())
|
return act.GetRepoAbsoluteLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag())
|
||||||
}
|
}
|
||||||
|
|
||||||
func toIssueLink(act *models.Action) string {
|
func toIssueLink(act *models.Action) string {
|
||||||
return act.GetRepoLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0])
|
return act.GetRepoAbsoluteLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func toPullLink(act *models.Action) string {
|
func toPullLink(act *models.Action) string {
|
||||||
return act.GetRepoLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0])
|
return act.GetRepoAbsoluteLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func toSrcLink(act *models.Action) string {
|
func toSrcLink(act *models.Action) string {
|
||||||
return act.GetRepoLink() + "/src/" + util.PathEscapeSegments(act.GetBranch())
|
return act.GetRepoAbsoluteLink() + "/src/" + util.PathEscapeSegments(act.GetBranch())
|
||||||
}
|
}
|
||||||
|
|
||||||
func toReleaseLink(act *models.Action) string {
|
func toReleaseLink(act *models.Action) string {
|
||||||
return act.GetRepoLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
|
return act.GetRepoAbsoluteLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderMarkdown creates a minimal markdown render context from an action.
|
// renderMarkdown creates a minimal markdown render context from an action.
|
||||||
|
@ -79,17 +79,17 @@ func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (it
|
||||||
title = act.ActUser.DisplayName() + " "
|
title = act.ActUser.DisplayName() + " "
|
||||||
switch act.OpType {
|
switch act.OpType {
|
||||||
case models.ActionCreateRepo:
|
case models.ActionCreateRepo:
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoLink(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoAbsoluteLink(), act.ShortRepoPath())
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
case models.ActionRenameRepo:
|
case models.ActionRenameRepo:
|
||||||
title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(), act.ShortRepoPath())
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
case models.ActionCommitRepo:
|
case models.ActionCommitRepo:
|
||||||
link.Href = toBranchLink(act)
|
link.Href = toBranchLink(act)
|
||||||
if len(act.Content) != 0 {
|
if len(act.Content) != 0 {
|
||||||
title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoAbsoluteLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
||||||
} else {
|
} else {
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoAbsoluteLink(), link.Href, act.GetBranch(), act.ShortRepoPath())
|
||||||
}
|
}
|
||||||
case models.ActionCreateIssue:
|
case models.ActionCreateIssue:
|
||||||
link.Href = toIssueLink(act)
|
link.Href = toIssueLink(act)
|
||||||
|
@ -98,11 +98,11 @@ func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (it
|
||||||
link.Href = toPullLink(act)
|
link.Href = toPullLink(act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath())
|
||||||
case models.ActionTransferRepo:
|
case models.ActionTransferRepo:
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoLink(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(), act.ShortRepoPath())
|
||||||
case models.ActionPushTag:
|
case models.ActionPushTag:
|
||||||
link.Href = toTagLink(act)
|
link.Href = toTagLink(act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoLink(), link.Href, act.GetTag(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoAbsoluteLink(), link.Href, act.GetTag(), act.ShortRepoPath())
|
||||||
case models.ActionCommentIssue:
|
case models.ActionCommentIssue:
|
||||||
issueLink := toIssueLink(act)
|
issueLink := toIssueLink(act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
|
@ -140,26 +140,26 @@ func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (it
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
|
||||||
case models.ActionDeleteTag:
|
case models.ActionDeleteTag:
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoLink(), act.GetTag(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoAbsoluteLink(), act.GetTag(), act.ShortRepoPath())
|
||||||
case models.ActionDeleteBranch:
|
case models.ActionDeleteBranch:
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoAbsoluteLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath())
|
||||||
case models.ActionMirrorSyncPush:
|
case models.ActionMirrorSyncPush:
|
||||||
srcLink := toSrcLink(act)
|
srcLink := toSrcLink(act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = srcLink
|
link.Href = srcLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoAbsoluteLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
||||||
case models.ActionMirrorSyncCreate:
|
case models.ActionMirrorSyncCreate:
|
||||||
srcLink := toSrcLink(act)
|
srcLink := toSrcLink(act)
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = srcLink
|
link.Href = srcLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoAbsoluteLink(), srcLink, act.GetBranch(), act.ShortRepoPath())
|
||||||
case models.ActionMirrorSyncDelete:
|
case models.ActionMirrorSyncDelete:
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoLink(), act.GetBranch(), act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoAbsoluteLink(), act.GetBranch(), act.ShortRepoPath())
|
||||||
case models.ActionApprovePullRequest:
|
case models.ActionApprovePullRequest:
|
||||||
pullLink := toPullLink(act)
|
pullLink := toPullLink(act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath())
|
||||||
|
@ -174,16 +174,16 @@ func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (it
|
||||||
if link.Href == "#" {
|
if link.Href == "#" {
|
||||||
link.Href = releaseLink
|
link.Href = releaseLink
|
||||||
}
|
}
|
||||||
title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoLink(), releaseLink, act.ShortRepoPath(), act.Content)
|
title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoAbsoluteLink(), releaseLink, act.ShortRepoPath(), act.Content)
|
||||||
case models.ActionPullReviewDismissed:
|
case models.ActionPullReviewDismissed:
|
||||||
pullLink := toPullLink(act)
|
pullLink := toPullLink(act)
|
||||||
title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1])
|
title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1])
|
||||||
case models.ActionStarRepo:
|
case models.ActionStarRepo:
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoLink(), act.GetRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoAbsoluteLink(), act.GetRepoPath())
|
||||||
case models.ActionWatchRepo:
|
case models.ActionWatchRepo:
|
||||||
link.Href = act.GetRepoLink()
|
link.Href = act.GetRepoAbsoluteLink()
|
||||||
title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoLink(), act.GetRepoPath())
|
title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoAbsoluteLink(), act.GetRepoPath())
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
|
return nil, fmt.Errorf("unknown action type: %v", act.OpType)
|
||||||
}
|
}
|
||||||
|
@ -193,14 +193,14 @@ func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (it
|
||||||
switch act.OpType {
|
switch act.OpType {
|
||||||
case models.ActionCommitRepo, models.ActionMirrorSyncPush:
|
case models.ActionCommitRepo, models.ActionMirrorSyncPush:
|
||||||
push := templates.ActionContent2Commits(act)
|
push := templates.ActionContent2Commits(act)
|
||||||
repoLink := act.GetRepoLink()
|
repoLink := act.GetRepoAbsoluteLink()
|
||||||
|
|
||||||
for _, commit := range push.Commits {
|
for _, commit := range push.Commits {
|
||||||
if len(desc) != 0 {
|
if len(desc) != 0 {
|
||||||
desc += "\n\n"
|
desc += "\n\n"
|
||||||
}
|
}
|
||||||
desc += fmt.Sprintf("<a href=\"%s\">%s</a>\n%s",
|
desc += fmt.Sprintf("<a href=\"%s\">%s</a>\n%s",
|
||||||
html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), commit.Sha1)),
|
html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(), commit.Sha1)),
|
||||||
commit.Sha1,
|
commit.Sha1,
|
||||||
templates.RenderCommitMessage(ctx, commit.Message, repoLink, nil),
|
templates.RenderCommitMessage(ctx, commit.Message, repoLink, nil),
|
||||||
)
|
)
|
||||||
|
@ -209,7 +209,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (it
|
||||||
if push.Len > 1 {
|
if push.Len > 1 {
|
||||||
link = &feeds.Link{Href: fmt.Sprintf("%s/%s", setting.AppSubURL, push.CompareURL)}
|
link = &feeds.Link{Href: fmt.Sprintf("%s/%s", setting.AppSubURL, push.CompareURL)}
|
||||||
} else if push.Len == 1 {
|
} else if push.Len == 1 {
|
||||||
link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoLink(), push.Commits[0].Sha1)}
|
link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(), push.Commits[0].Sha1)}
|
||||||
}
|
}
|
||||||
|
|
||||||
case models.ActionCreateIssue, models.ActionCreatePullRequest:
|
case models.ActionCreateIssue, models.ActionCreatePullRequest:
|
||||||
|
|
|
@ -83,7 +83,7 @@ func Commits(ctx *context.Context) {
|
||||||
ctx.Data["CommitCount"] = commitsCount
|
ctx.Data["CommitCount"] = commitsCount
|
||||||
ctx.Data["RefName"] = ctx.Repo.RefName
|
ctx.Data["RefName"] = ctx.Repo.RefName
|
||||||
|
|
||||||
pager := context.NewPagination(int(commitsCount), setting.Git.CommitsRangeSize, page, 5)
|
pager := context.NewPagination(int(commitsCount), pageSize, page, 5)
|
||||||
pager.SetDefaultParams(ctx)
|
pager.SetDefaultParams(ctx)
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
|
|
|
@ -113,17 +113,17 @@ func setCsvCompareContext(ctx *context.Context) {
|
||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["CreateCsvDiff"] = func(diffFile *gitdiff.DiffFile, baseCommit, headCommit *git.Commit) CsvDiffResult {
|
ctx.Data["CreateCsvDiff"] = func(diffFile *gitdiff.DiffFile, baseBlob, headBlob *git.Blob) CsvDiffResult {
|
||||||
if diffFile == nil || baseCommit == nil || headCommit == nil {
|
if diffFile == nil {
|
||||||
return CsvDiffResult{nil, ""}
|
return CsvDiffResult{nil, ""}
|
||||||
}
|
}
|
||||||
|
|
||||||
errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
|
errTooLarge := errors.New(ctx.Locale.Tr("repo.error.csv.too_large"))
|
||||||
|
|
||||||
csvReaderFromCommit := func(ctx *markup.RenderContext, c *git.Commit) (*csv.Reader, io.Closer, error) {
|
csvReaderFromCommit := func(ctx *markup.RenderContext, blob *git.Blob) (*csv.Reader, io.Closer, error) {
|
||||||
blob, err := c.GetBlobByPath(diffFile.Name)
|
if blob == nil {
|
||||||
if err != nil {
|
// It's ok for blob to be nil (file added or deleted)
|
||||||
return nil, nil, err
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if setting.UI.CSV.MaxFileSize != 0 && setting.UI.CSV.MaxFileSize < blob.Size() {
|
if setting.UI.CSV.MaxFileSize != 0 && setting.UI.CSV.MaxFileSize < blob.Size() {
|
||||||
|
@ -139,28 +139,28 @@ func setCsvCompareContext(ctx *context.Context) {
|
||||||
return csvReader, reader, err
|
return csvReader, reader, err
|
||||||
}
|
}
|
||||||
|
|
||||||
baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.OldName}, baseCommit)
|
baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.OldName}, baseBlob)
|
||||||
if baseBlobCloser != nil {
|
if baseBlobCloser != nil {
|
||||||
defer baseBlobCloser.Close()
|
defer baseBlobCloser.Close()
|
||||||
}
|
}
|
||||||
if err == errTooLarge {
|
|
||||||
return CsvDiffResult{nil, err.Error()}
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CreateCsvDiff error whilst creating baseReader from file %s in commit %s in %s: %v", diffFile.Name, baseCommit.ID.String(), ctx.Repo.Repository.Name, err)
|
if err == errTooLarge {
|
||||||
return CsvDiffResult{nil, "unable to load file from base commit"}
|
return CsvDiffResult{nil, err.Error()}
|
||||||
|
}
|
||||||
|
log.Error("error whilst creating csv.Reader from file %s in base commit %s in %s: %v", diffFile.Name, baseBlob.ID.String(), ctx.Repo.Repository.Name, err)
|
||||||
|
return CsvDiffResult{nil, "unable to load file"}
|
||||||
}
|
}
|
||||||
|
|
||||||
headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.Name}, headCommit)
|
headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.Name}, headBlob)
|
||||||
if headBlobCloser != nil {
|
if headBlobCloser != nil {
|
||||||
defer headBlobCloser.Close()
|
defer headBlobCloser.Close()
|
||||||
}
|
}
|
||||||
if err == errTooLarge {
|
|
||||||
return CsvDiffResult{nil, err.Error()}
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("CreateCsvDiff error whilst creating headReader from file %s in commit %s in %s: %v", diffFile.Name, headCommit.ID.String(), ctx.Repo.Repository.Name, err)
|
if err == errTooLarge {
|
||||||
return CsvDiffResult{nil, "unable to load file from head commit"}
|
return CsvDiffResult{nil, err.Error()}
|
||||||
|
}
|
||||||
|
log.Error("error whilst creating csv.Reader from file %s in head commit %s in %s: %v", diffFile.Name, headBlob.ID.String(), ctx.Repo.Repository.Name, err)
|
||||||
|
return CsvDiffResult{nil, "unable to load file"}
|
||||||
}
|
}
|
||||||
|
|
||||||
sections, err := gitdiff.CreateCsvDiff(diffFile, baseReader, headReader)
|
sections, err := gitdiff.CreateCsvDiff(diffFile, baseReader, headReader)
|
||||||
|
|
|
@ -116,9 +116,17 @@ func releasesOrTags(ctx *context.Context, isTagList bool) {
|
||||||
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
||||||
|
|
||||||
opts := models.FindReleasesOptions{
|
opts := models.FindReleasesOptions{
|
||||||
ListOptions: listOptions,
|
ListOptions: listOptions,
|
||||||
IncludeDrafts: writeAccess && !isTagList,
|
}
|
||||||
IncludeTags: isTagList,
|
if isTagList {
|
||||||
|
// for the tags list page, show all releases with real tags (having real commit-id),
|
||||||
|
// the drafts should also be included because a real tag might be used as a draft.
|
||||||
|
opts.IncludeDrafts = true
|
||||||
|
opts.IncludeTags = true
|
||||||
|
opts.HasSha1 = util.OptionalBoolTrue
|
||||||
|
} else {
|
||||||
|
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
||||||
|
opts.IncludeDrafts = writeAccess
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, opts)
|
releases, err := models.GetReleasesByRepoID(ctx.Repo.Repository.ID, opts)
|
||||||
|
|
|
@ -1448,8 +1448,6 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
|
||||||
} else if language, has := attrs["gitlab-language"]; has && language != "unspecified" && language != "" {
|
} else if language, has := attrs["gitlab-language"]; has && language != "unspecified" && language != "" {
|
||||||
diffFile.Language = language
|
diffFile.Language = language
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.Error("Unexpected error: %v", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/structs"
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -78,8 +78,9 @@ type GiteaDownloader struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGiteaDownloader creates a gitea Downloader via gitea API
|
// NewGiteaDownloader creates a gitea Downloader via gitea API
|
||||||
// Use either a username/password or personal token. token is preferred
|
//
|
||||||
// Note: Public access only allows very basic access
|
// Use either a username/password or personal token. token is preferred
|
||||||
|
// Note: Public access only allows very basic access
|
||||||
func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, password, token string) (*GiteaDownloader, error) {
|
func NewGiteaDownloader(ctx context.Context, baseURL, repoPath, username, password, token string) (*GiteaDownloader, error) {
|
||||||
giteaClient, err := gitea_sdk.NewClient(
|
giteaClient, err := gitea_sdk.NewClient(
|
||||||
baseURL,
|
baseURL,
|
||||||
|
|
|
@ -412,6 +412,10 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is.ForeignReference.ForeignIndex == "0" {
|
||||||
|
is.ForeignReference.ForeignIndex = strconv.FormatInt(is.Index, 10)
|
||||||
|
}
|
||||||
|
|
||||||
if err := g.remapUser(issue, &is); err != nil {
|
if err := g.remapUser(issue, &is); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,8 +71,9 @@ type GitlabDownloader struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
|
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
|
||||||
// Use either a username/password, personal token entered into the username field, or anonymous/public access
|
//
|
||||||
// Note: Public access only allows very basic access
|
// Use either a username/password, personal token entered into the username field, or anonymous/public access
|
||||||
|
// Note: Public access only allows very basic access
|
||||||
func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, password, token string) (*GitlabDownloader, error) {
|
func NewGitlabDownloader(ctx context.Context, baseURL, repoPath, username, password, token string) (*GitlabDownloader, error) {
|
||||||
gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL), gitlab.WithHTTPClient(NewMigrationHTTPClient()))
|
gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL), gitlab.WithHTTPClient(NewMigrationHTTPClient()))
|
||||||
// Only use basic auth if token is blank and password is NOT
|
// Only use basic auth if token is blank and password is NOT
|
||||||
|
@ -374,7 +375,8 @@ type gitlabIssueContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIssues returns issues according start and limit
|
// GetIssues returns issues according start and limit
|
||||||
// Note: issue label description and colors are not supported by the go-gitlab library at this time
|
//
|
||||||
|
// Note: issue label description and colors are not supported by the go-gitlab library at this time
|
||||||
func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) {
|
func (g *GitlabDownloader) GetIssues(page, perPage int) ([]*base.Issue, bool, error) {
|
||||||
state := "all"
|
state := "all"
|
||||||
sort := "asc"
|
sort := "asc"
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/cache"
|
"code.gitea.io/gitea/modules/cache"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
"code.gitea.io/gitea/modules/graceful"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
"code.gitea.io/gitea/modules/references"
|
"code.gitea.io/gitea/modules/references"
|
||||||
|
@ -165,9 +166,10 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
|
||||||
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "")
|
go AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false, "", "")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// TODO: make it able to do this in a database session
|
// Run the merge in the hammer context to prevent cancellation
|
||||||
mergeCtx := context.Background()
|
hammerCtx := graceful.GetManager().HammerContext()
|
||||||
pr.MergedCommitID, err = rawMerge(mergeCtx, pr, doer, mergeStyle, expectedHeadCommitID, message)
|
|
||||||
|
pr.MergedCommitID, err = rawMerge(hammerCtx, pr, doer, mergeStyle, expectedHeadCommitID, message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -176,18 +178,18 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
|
||||||
pr.Merger = doer
|
pr.Merger = doer
|
||||||
pr.MergerID = doer.ID
|
pr.MergerID = doer.ID
|
||||||
|
|
||||||
if _, err := pr.SetMerged(ctx); err != nil {
|
if _, err := pr.SetMerged(hammerCtx); err != nil {
|
||||||
log.Error("setMerged [%d]: %v", pr.ID, err)
|
log.Error("setMerged [%d]: %v", pr.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pr.LoadIssueCtx(ctx); err != nil {
|
if err := pr.LoadIssueCtx(hammerCtx); err != nil {
|
||||||
log.Error("loadIssue [%d]: %v", pr.ID, err)
|
log.Error("loadIssue [%d]: %v", pr.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pr.Issue.LoadRepo(ctx); err != nil {
|
if err := pr.Issue.LoadRepo(hammerCtx); err != nil {
|
||||||
log.Error("loadRepo for issue [%d]: %v", pr.ID, err)
|
log.Error("loadRepo for issue [%d]: %v", pr.ID, err)
|
||||||
}
|
}
|
||||||
if err := pr.Issue.Repo.GetOwner(ctx); err != nil {
|
if err := pr.Issue.Repo.GetOwner(hammerCtx); err != nil {
|
||||||
log.Error("GetOwner for issue repo [%d]: %v", pr.ID, err)
|
log.Error("GetOwner for issue repo [%d]: %v", pr.ID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,17 +199,17 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U
|
||||||
cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true))
|
cache.Remove(pr.Issue.Repo.GetCommitsCountCacheKey(pr.BaseBranch, true))
|
||||||
|
|
||||||
// Resolve cross references
|
// Resolve cross references
|
||||||
refs, err := pr.ResolveCrossReferences(ctx)
|
refs, err := pr.ResolveCrossReferences(hammerCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("ResolveCrossReferences: %v", err)
|
log.Error("ResolveCrossReferences: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ref := range refs {
|
for _, ref := range refs {
|
||||||
if err = ref.LoadIssueCtx(ctx); err != nil {
|
if err = ref.LoadIssueCtx(hammerCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = ref.Issue.LoadRepo(ctx); err != nil {
|
if err = ref.Issue.LoadRepo(hammerCtx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
close := ref.RefAction == references.XRefActionCloses
|
close := ref.RefAction == references.XRefActionCloses
|
||||||
|
|
|
@ -157,7 +157,7 @@
|
||||||
<tbody>
|
<tbody>
|
||||||
{{range .Queue.Workers}}
|
{{range .Queue.Workers}}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{.Workers}}{{if .IsFlusher}}<span title="{{.i18n.Tr "admin.monitor.queue.flush"}}">{{svg "octicon-sync"}}</span>{{end}}</td>
|
<td>{{.Workers}}{{if .IsFlusher}}<span title="{{$.i18n.Tr "admin.monitor.queue.flush"}}">{{svg "octicon-sync"}}</span>{{end}}</td>
|
||||||
<td>{{DateFmtLong .Start}}</td>
|
<td>{{DateFmtLong .Start}}</td>
|
||||||
<td>{{if .HasTimeout}}{{DateFmtLong .Timeout}}{{else}}-{{end}}</td>
|
<td>{{if .HasTimeout}}{{DateFmtLong .Timeout}}{{else}}-{{end}}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
{{if .PackageDescriptor.Metadata.ImageLayers}}
|
{{if .PackageDescriptor.Metadata.ImageLayers}}
|
||||||
<h4 class="ui top attached header">{{.i18n.Tr "packages.container.layers"}}</h4>
|
<h4 class="ui top attached header">{{.i18n.Tr "packages.container.layers"}}</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<table id="notice-table" class="ui very basic compact table">
|
<table class="ui very basic compact table">
|
||||||
<tbody>
|
<tbody>
|
||||||
{{range .PackageDescriptor.Metadata.ImageLayers}}
|
{{range .PackageDescriptor.Metadata.ImageLayers}}
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
{{if .PackageDescriptor.Metadata.Labels}}
|
{{if .PackageDescriptor.Metadata.Labels}}
|
||||||
<h4 class="ui top attached header">{{.i18n.Tr "packages.container.labels"}}</h4>
|
<h4 class="ui top attached header">{{.i18n.Tr "packages.container.labels"}}</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<table id="notice-table" class="ui very basic compact table">
|
<table class="ui very basic compact table container-labels">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{.i18n.Tr "packages.container.labels.key"}}</th>
|
<th>{{.i18n.Tr "packages.container.labels.key"}}</th>
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
|
{{/*Golang's template has a bug with string interpolation containing slashes,
|
||||||
|
the double slash will be treated as a comment there.
|
||||||
|
But there are also JS lint rules for template that require to use string interpolation in 1.17*/}}
|
||||||
<script>
|
<script>
|
||||||
// synchronously set clone button states and urls here to avoid flickering
|
// synchronously set clone button states and urls here to avoid flickering
|
||||||
// on page load. initRepoCloneLink calls this when proto changes.
|
// on page load. initRepoCloneLink calls this when proto changes.
|
||||||
|
// this applies the protocol-dependant clone url to all elements with the
|
||||||
|
// `js-clone-url` and `js-clone-url-vsc` classes.
|
||||||
// TODO: This localStorage setting should be moved to backend user config
|
// TODO: This localStorage setting should be moved to backend user config
|
||||||
// so it's available during rendering, then this inline script can be removed.
|
// so it's available during rendering, then this inline script can be removed.
|
||||||
(window.updateCloneStates = function() {
|
(window.updateCloneStates = function() {
|
||||||
|
@ -19,5 +24,9 @@
|
||||||
for (const el of document.getElementsByClassName('js-clone-url')) {
|
for (const el of document.getElementsByClassName('js-clone-url')) {
|
||||||
el[el.nodeName === 'INPUT' ? 'value' : 'textContent'] = link;
|
el[el.nodeName === 'INPUT' ? 'value' : 'textContent'] = link;
|
||||||
}
|
}
|
||||||
|
const sep = '//';
|
||||||
|
for (const el of document.getElementsByClassName('js-clone-url-vsc')) {
|
||||||
|
el.href = `vscode:${sep}vscode.git/clone?url=${encodeURIComponent(link)}`;
|
||||||
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -57,7 +57,8 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</ol>
|
</ol>
|
||||||
<div id="diff-file-boxes">
|
<div id="diff-file-boxes">
|
||||||
{{range $i, $file := .Diff.Files}}
|
{{range $file := .Diff.Files}}
|
||||||
|
{{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}}
|
||||||
{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}}
|
{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}}
|
||||||
{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}}
|
{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}}
|
||||||
{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}}
|
{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}}
|
||||||
|
@ -93,8 +94,8 @@
|
||||||
<div class="diff-file-header-actions df ac">
|
<div class="diff-file-header-actions df ac">
|
||||||
{{if $showFileViewToggle}}
|
{{if $showFileViewToggle}}
|
||||||
<div class="ui compact icon buttons">
|
<div class="ui compact icon buttons">
|
||||||
<span class="ui tiny basic button tooltip file-view-toggle" data-toggle-selector="#diff-source-{{$i}}" data-content="{{$.i18n.Tr "repo.file_view_source"}}" data-position="bottom center">{{svg "octicon-code"}}</span>
|
<span class="ui tiny basic button tooltip file-view-toggle" data-toggle-selector="#diff-source-{{$file.NameHash}}" data-content="{{$.i18n.Tr "repo.file_view_source"}}" data-position="bottom center">{{svg "octicon-code"}}</span>
|
||||||
<span class="ui tiny basic button tooltip file-view-toggle active" data-toggle-selector="#diff-rendered-{{$i}}" data-content="{{$.i18n.Tr "repo.file_view_rendered"}}" data-position="bottom center">{{svg "octicon-file"}}</span>
|
<span class="ui tiny basic button tooltip file-view-toggle active" data-toggle-selector="#diff-rendered-{{$file.NameHash}}" data-content="{{$.i18n.Tr "repo.file_view_rendered"}}" data-position="bottom center">{{svg "octicon-file"}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if $file.IsProtected}}
|
{{if $file.IsProtected}}
|
||||||
|
@ -115,15 +116,14 @@
|
||||||
{{if $file.HasChangedSinceLastReview}}
|
{{if $file.HasChangedSinceLastReview}}
|
||||||
<span class="changed-since-last-review unselectable">{{$.i18n.Tr "repo.pulls.has_changed_since_last_review"}}</span>
|
<span class="changed-since-last-review unselectable">{{$.i18n.Tr "repo.pulls.has_changed_since_last_review"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.PullHeadCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}">
|
<label data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.PullHeadCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}">
|
||||||
<input type="checkbox" name="{{$file.GetDiffFileName}}" id="viewed-file-checkbox-{{$i}}" autocomplete="off" {{if $file.IsViewed}}checked{{end}}></input>
|
<input type="checkbox" name="{{$file.GetDiffFileName}}" autocomplete="off"{{if $file.IsViewed}} checked{{end}}> {{$.i18n.Tr "repo.pulls.has_viewed_file"}}
|
||||||
<label for="viewed-file-checkbox-{{$i}}">{{$.i18n.Tr "repo.pulls.has_viewed_file"}}</label>
|
</label>
|
||||||
</div>
|
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="diff-file-body ui attached unstackable table segment" {{if $file.IsViewed}}data-folded="true"{{end}}>
|
<div class="diff-file-body ui attached unstackable table segment" {{if $file.IsViewed}}data-folded="true"{{end}}>
|
||||||
<div id="diff-source-{{$i}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}">
|
<div id="diff-source-{{$file.NameHash}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}">
|
||||||
{{if or $file.IsIncomplete $file.IsBin}}
|
{{if or $file.IsIncomplete $file.IsBin}}
|
||||||
<div class="diff-file-body binary" style="padding: 5px 10px;">
|
<div class="diff-file-body binary" style="padding: 5px 10px;">
|
||||||
{{if $file.IsIncomplete}}
|
{{if $file.IsIncomplete}}
|
||||||
|
@ -148,12 +148,12 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{if $showFileViewToggle}}
|
{{if $showFileViewToggle}}
|
||||||
<div id="diff-rendered-{{$i}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
|
<div id="diff-rendered-{{$file.NameHash}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}">
|
||||||
<table class="chroma w-100">
|
<table class="chroma w-100">
|
||||||
{{if $isImage}}
|
{{if $isImage}}
|
||||||
{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
|
{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{template "repo/diff/csv_diff" dict "file" . "root" $}}
|
{{template "repo/diff/csv_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{{$result := call .root.CreateCsvDiff .file .root.BaseCommit .root.HeadCommit}}
|
{{$result := call .root.CreateCsvDiff .file .blobBase .blobHead}}
|
||||||
{{if $result.Error}}
|
{{if $result.Error}}
|
||||||
<div class="ui center">{{$result.Error}}</div>
|
<div class="ui center">{{$result.Error}}</div>
|
||||||
{{else if $result.Sections}}
|
{{else if $result.Sections}}
|
||||||
|
|
|
@ -116,19 +116,19 @@
|
||||||
<!-- Only show clone panel in repository home page -->
|
<!-- Only show clone panel in repository home page -->
|
||||||
{{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" .}}
|
||||||
{{template "repo/clone_script" .}}
|
<button id="download-btn" class="ui basic small compact jump dropdown icon button tooltip" data-content="{{.i18n.Tr "repo.download_archive"}}" data-position="top right">
|
||||||
<button id="download-btn" class="ui basic small compact jump dropdown icon button tooltip" data-content="{{.i18n.Tr "repo.download_archive"}}" data-position="top right">
|
{{svg "octicon-download"}}
|
||||||
{{svg "octicon-download"}}
|
<div class="menu">
|
||||||
<div class="menu">
|
{{if not $.DisableDownloadSourceArchives}}
|
||||||
{{if not $.DisableDownloadSourceArchives}}
|
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_zip"}}</a>
|
||||||
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_zip"}}</a>
|
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_tar"}}</a>
|
||||||
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-3"}}{{.i18n.Tr "repo.download_tar"}}</a>
|
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.bundle" rel="nofollow">{{svg "octicon-package" 16 "mr-3"}}{{.i18n.Tr "repo.download_bundle"}}</a>
|
||||||
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.bundle" rel="nofollow">{{svg "octicon-package" 16 "mr-3"}}{{.i18n.Tr "repo.download_bundle"}}</a>
|
{{end}}
|
||||||
{{end}}
|
<a class="item js-clone-url-vsc" href="vscode://vscode.git/clone?url={{.CloneButtonOriginLink.HTTPS}}">{{svg "gitea-vscode" 16 "mr-3"}}{{.i18n.Tr "repo.clone_in_vsc"}}</a>
|
||||||
<a class="item" href="vscode://vscode.git/clone?url={{$.RepoCloneLink.HTTPS}}">{{svg "gitea-vscode" 16 "mr-3"}}{{.i18n.Tr "repo.clone_in_vsc"}}</a>
|
</div>
|
||||||
</div>
|
</button>
|
||||||
</button>
|
{{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if and (ne $n 0) (not .IsViewFile) (not .IsBlame) }}
|
{{if and (ne $n 0) (not .IsViewFile) (not .IsBlame) }}
|
||||||
|
|
|
@ -77,14 +77,12 @@
|
||||||
<span class="ui green label">{{$.i18n.Tr "repo.release.stable"}}</span>
|
<span class="ui green label">{{$.i18n.Tr "repo.release.stable"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<span class="tag text blue">
|
<span class="tag text blue">
|
||||||
<a class="df ac je" href="{{if .IsDraft}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "mr-2"}}{{.TagName}}</a>
|
<a class="df ac je" href="{{if not .Sha1}}#{{else}}{{$.RepoLink}}/src/tag/{{.TagName | PathEscapeSegments}}{{end}}" rel="nofollow">{{svg "octicon-tag" 16 "mr-2"}}{{.TagName}}</a>
|
||||||
</span>
|
</span>
|
||||||
{{if not .IsDraft}}
|
{{if .Sha1}}
|
||||||
<span class="commit">
|
<span class="commit">
|
||||||
<a class="mono" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}}</a>
|
<a class="mono" href="{{$.RepoLink}}/src/commit/{{.Sha1}}" rel="nofollow">{{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}}</a>
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
|
||||||
{{if .Sha1 }}
|
|
||||||
{{template "repo/branch_dropdown" dict "root" $ "release" .}}
|
{{template "repo/branch_dropdown" dict "root" $ "release" .}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -12420,6 +12420,18 @@
|
||||||
"summary": "List the current user's tracked times",
|
"summary": "List the current user's tracked times",
|
||||||
"operationId": "userCurrentTrackedTimes",
|
"operationId": "userCurrentTrackedTimes",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page number of results to return (1-based)",
|
||||||
|
"name": "page",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "page size of results",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
|
@ -15619,7 +15631,6 @@
|
||||||
"$ref": "#/definitions/FileCommitResponse"
|
"$ref": "#/definitions/FileCommitResponse"
|
||||||
},
|
},
|
||||||
"content": {
|
"content": {
|
||||||
"type": "object",
|
|
||||||
"x-go-name": "Content"
|
"x-go-name": "Content"
|
||||||
},
|
},
|
||||||
"verification": {
|
"verification": {
|
||||||
|
@ -18661,7 +18672,6 @@
|
||||||
"x-go-name": "Ignored"
|
"x-go-name": "Ignored"
|
||||||
},
|
},
|
||||||
"reason": {
|
"reason": {
|
||||||
"type": "object",
|
|
||||||
"x-go-name": "Reason"
|
"x-go-name": "Reason"
|
||||||
},
|
},
|
||||||
"repository_url": {
|
"repository_url": {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<strong>{{$provider}}</strong>
|
<strong>{{$provider}}</strong>
|
||||||
{{if $loginSource.IsActive}}<span class="text red">{{$.i18n.Tr "settings.active"}}</span>{{end}}
|
{{if $loginSource.IsActive}}<span class="text red">{{$.i18n.Tr "repo.settings.active"}}</span>{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
9
web_src/less/_package.less
Normal file
9
web_src/less/_package.less
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.container-labels {
|
||||||
|
td:nth-child(1) {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-child(2) {
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
}
|
|
@ -272,13 +272,22 @@ a.blob-excerpt:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewed-file-form {
|
.viewed-file-form {
|
||||||
margin: 0 3px;
|
display: flex;
|
||||||
padding: 0 3px;
|
align-items: center;
|
||||||
border-radius: 3px;
|
border: 1px none;
|
||||||
|
padding: 4px 8px;
|
||||||
|
margin: -8px 0; // just like other buttons in the diff box header
|
||||||
|
border-radius: .285rem; // just like .ui.tiny.button
|
||||||
|
font-size: .857rem; // just like .ui.tiny.button
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewed-file-form input {
|
||||||
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.viewed-file-checked-form {
|
.viewed-file-checked-form {
|
||||||
background-color: var(--color-primary-light-4);
|
background-color: var(--color-primary-light-6);
|
||||||
|
border: 1px solid var(--color-primary-light-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#viewed-files-summary {
|
#viewed-files-summary {
|
||||||
|
|
|
@ -34,5 +34,6 @@
|
||||||
@import "_admin";
|
@import "_admin";
|
||||||
@import "_explore";
|
@import "_explore";
|
||||||
@import "_review";
|
@import "_review";
|
||||||
|
@import "_package";
|
||||||
|
|
||||||
@import "./helpers.less";
|
@import "./helpers.less";
|
||||||
|
|
Reference in a new issue