mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-15 12:33:45 +09:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4729e2418 | ||
|
|
f7330fd027 | ||
|
|
755d8e21ad | ||
|
|
7c0bf06d96 | ||
|
|
0d196e29e8 | ||
|
|
b86606fa38 | ||
|
|
74602bb487 | ||
|
|
1465e0cbb2 | ||
|
|
928b603d19 | ||
|
|
8ff542c1a2 | ||
|
|
39a0db6ecf | ||
|
|
9cc93c05cd | ||
|
|
b31418edd9 | ||
|
|
242f7f1a52 | ||
|
|
8d7f1e430a | ||
|
|
a6b32adc45 | ||
|
|
1f0dca4614 | ||
|
|
1d665da32f | ||
|
|
09adc26eb6 | ||
|
|
297346a762 | ||
|
|
acd648061d | ||
|
|
c5fe0a096d | ||
|
|
0c7bf6801f | ||
|
|
5863f7e048 | ||
|
|
a785c46ca8 | ||
|
|
6bddfd3086 | ||
|
|
dd8a726b25 | ||
|
|
08eecba32b | ||
|
|
9c2212df15 | ||
|
|
9b4746967c | ||
|
|
00da1facc4 | ||
|
|
b461993775 | ||
|
|
b885e57762 | ||
|
|
081449d7a5 | ||
|
|
ee3a21a537 | ||
|
|
61c7732e12 | ||
|
|
57c2ca7f26 | ||
|
|
0704009dd7 | ||
|
|
14a6aafb50 | ||
|
|
471a1e8111 | ||
|
|
123c254b84 | ||
|
|
db43f63c53 | ||
|
|
3ecd520f8e | ||
|
|
e9935d358c | ||
|
|
8d653b148b | ||
|
|
b702f2dac3 | ||
|
|
d59b8541f2 | ||
|
|
efd34d0d7d | ||
|
|
2ec2935f78 | ||
|
|
540541caa2 | ||
|
|
a13d64bf98 |
66
.drone.yml
66
.drone.yml
@@ -45,7 +45,7 @@ steps:
|
||||
commands:
|
||||
- make lint-backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend]
|
||||
@@ -58,7 +58,7 @@ steps:
|
||||
commands:
|
||||
- make golangci-lint-windows vet
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
GOOS: windows
|
||||
@@ -73,7 +73,7 @@ steps:
|
||||
commands:
|
||||
- make lint-backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend]
|
||||
@@ -109,11 +109,11 @@ steps:
|
||||
depends_on: [test-frontend]
|
||||
|
||||
- name: build-backend-no-gcc
|
||||
image: golang:1.17 # this step is kept as the lowest version of golang that we support
|
||||
image: golang:1.16 # this step is kept as the lowest version of golang that we support
|
||||
pull: always
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
commands:
|
||||
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||
depends_on: [deps-backend, checks-backend]
|
||||
@@ -125,7 +125,7 @@ steps:
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: linux
|
||||
GOARCH: arm64
|
||||
TAGS: bindata gogit
|
||||
@@ -141,7 +141,7 @@ steps:
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
TAGS: bindata gogit
|
||||
@@ -156,7 +156,7 @@ steps:
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
GOOS: linux
|
||||
GOARCH: 386
|
||||
commands:
|
||||
@@ -269,7 +269,7 @@ steps:
|
||||
- ./build/test-env-check.sh
|
||||
- make backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend, prepare-test-env]
|
||||
@@ -283,7 +283,7 @@ steps:
|
||||
commands:
|
||||
- make unit-test-coverage test-check
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN:
|
||||
@@ -299,7 +299,7 @@ steps:
|
||||
commands:
|
||||
- make unit-test-coverage test-check
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
GITHUB_READ_TOKEN:
|
||||
@@ -315,7 +315,7 @@ steps:
|
||||
commands:
|
||||
- make test-mysql-migration integration-test-coverage
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
TEST_LDAP: 1
|
||||
@@ -332,7 +332,7 @@ steps:
|
||||
commands:
|
||||
- timeout -s ABRT 40m make test-mysql8-migration test-mysql8
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
TEST_LDAP: 1
|
||||
@@ -348,7 +348,7 @@ steps:
|
||||
commands:
|
||||
- make test-mssql-migration test-mssql
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
RACE_ENABLED: true
|
||||
TEST_LDAP: 1
|
||||
@@ -363,7 +363,7 @@ steps:
|
||||
commands:
|
||||
- make coverage
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata
|
||||
depends_on: [unit-test, test-mysql]
|
||||
when:
|
||||
@@ -455,7 +455,7 @@ steps:
|
||||
- ./build/test-env-check.sh
|
||||
- make backend
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend, prepare-test-env]
|
||||
@@ -469,7 +469,7 @@ steps:
|
||||
commands:
|
||||
- timeout -s ABRT 40m make test-sqlite-migration test-sqlite
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
RACE_ENABLED: true
|
||||
TEST_TAGS: gogit sqlite sqlite_unlock_notify
|
||||
@@ -485,7 +485,7 @@ steps:
|
||||
commands:
|
||||
- timeout -s ABRT 40m make test-pgsql-migration test-pgsql
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn
|
||||
GOPROXY: https://goproxy.io
|
||||
TAGS: bindata gogit
|
||||
RACE_ENABLED: true
|
||||
TEST_TAGS: gogit
|
||||
@@ -653,7 +653,7 @@ steps:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
volumes:
|
||||
- name: deps
|
||||
@@ -771,7 +771,7 @@ steps:
|
||||
- export PATH=$PATH:$GOPATH/bin
|
||||
- make release
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [fetch-tags]
|
||||
volumes:
|
||||
@@ -901,7 +901,7 @@ steps:
|
||||
auto_tag_suffix: linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -919,7 +919,7 @@ steps:
|
||||
auto_tag_suffix: linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -964,7 +964,7 @@ steps:
|
||||
tags: dev-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -982,7 +982,7 @@ steps:
|
||||
tags: dev-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1026,7 +1026,7 @@ steps:
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1044,7 +1044,7 @@ steps:
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-amd64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1079,7 +1079,7 @@ steps:
|
||||
repo: gitea/gitea
|
||||
tags: linux-arm64
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
environment:
|
||||
PLUGIN_MIRROR:
|
||||
from_secret: plugin_mirror
|
||||
@@ -1122,7 +1122,7 @@ steps:
|
||||
auto_tag_suffix: linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1140,7 +1140,7 @@ steps:
|
||||
auto_tag_suffix: linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1185,7 +1185,7 @@ steps:
|
||||
tags: dev-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1203,7 +1203,7 @@ steps:
|
||||
tags: dev-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1247,7 +1247,7 @@ steps:
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
@@ -1265,7 +1265,7 @@ steps:
|
||||
tags: ${DRONE_BRANCH##release/v}-dev-linux-arm64-rootless
|
||||
repo: gitea/gitea
|
||||
build_args:
|
||||
- GOPROXY=https://goproxy.cn
|
||||
- GOPROXY=https://goproxy.io
|
||||
password:
|
||||
from_secret: docker_password
|
||||
username:
|
||||
|
||||
60
CHANGELOG.md
60
CHANGELOG.md
@@ -4,7 +4,65 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/1.16.5) - 2022-03-23
|
||||
## [1.16.7](https://github.com/go-gitea/gitea/releases/tag/v1.16.7) - 2022-05-02
|
||||
|
||||
* SECURITY
|
||||
* Escape git fetch remote (#19487) (#19490)
|
||||
* BUGFIXES
|
||||
* Don't overwrite err with nil (#19572) (#19574)
|
||||
* On Migrations, only write commit-graph if wiki clone was successful (#19563) (#19568)
|
||||
* Respect DefaultUserIsRestricted system default when creating new user (#19310) (#19560)
|
||||
* Don't error when branch's commit doesn't exist (#19547) (#19548)
|
||||
* Support `hostname:port` to pass host matcher's check (#19543) (#19544)
|
||||
* Prevent intermittent race in attribute reader close (#19537) (#19539)
|
||||
* Fix 64-bit atomic operations on 32-bit machines (#19531) (#19532)
|
||||
* Prevent dangling archiver goroutine (#19516) (#19526)
|
||||
* Fix migrate release from github (#19510) (#19523)
|
||||
* When view _Siderbar or _Footer, just display once (#19501) (#19522)
|
||||
* Fix blame page select range error and some typos (#19503)
|
||||
* Fix name of doctor fix "authorized-keys" in hints (#19464) (#19484)
|
||||
* User specific repoID or xorm builder conditions for issue search (#19475) (#19476)
|
||||
* Prevent dangling cat-file calls (goroutine alternative) (#19454) (#19466)
|
||||
* RepoAssignment ensure to close before overwrite (#19449) (#19460)
|
||||
* Set correct PR status on 3way on conflict checking (#19457) (#19458)
|
||||
* Mark TemplateLoading error as "UnprocessableEntity" (#19445) (#19446)
|
||||
|
||||
## [1.16.6](https://github.com/go-gitea/gitea/releases/tag/v1.16.6) - 2022-04-20
|
||||
|
||||
* ENHANCEMENTS
|
||||
* Only request write when necessary (#18657) (#19422)
|
||||
* Disable service worker by default (#18914) (#19342)
|
||||
* BUGFIXES
|
||||
* When dumping trim the standard suffices instead of a random suffix (#19440) (#19447)
|
||||
* Fix DELETE request for non-existent public key (#19443) (#19444)
|
||||
* Don't panic on ErrEmailInvalid (#19441) (#19442)
|
||||
* Add uploadpack.allowAnySHA1InWant to allow --filter=blob:none with older git clients (#19430) (#19438)
|
||||
* Warn on SSH connection for incorrect configuration (#19317) (#19437)
|
||||
* Search Issues via API, dont show 500 if filter result in empty list (#19244) (#19436)
|
||||
* When updating mirror repo intervals by API reschedule next update too (#19429) (#19433)
|
||||
* Fix nil error when some pages are rendered outside request context (#19427) (#19428)
|
||||
* Fix double blob-hunk on diff page (#19404) (#19405)
|
||||
* Don't allow merging PR's which are being conflict checked (#19357) (#19358)
|
||||
* Fix middleware function's placements (#19377) (#19378)
|
||||
* Fix invalid CSRF token bug, make sure CSRF tokens can be up-to-date (#19338)
|
||||
* Restore user autoregistration with email addresses (#19261) (#19312)
|
||||
* Move checks for pulls before merge into own function (#19271) (#19277)
|
||||
* Granular webhook events in editHook (#19251) (#19257)
|
||||
* Only send webhook events to active system webhooks and only deliver to active hooks (#19234) (#19248)
|
||||
* Use full output of git show-ref --tags to get tags for PushUpdateAddTag (#19235) (#19236)
|
||||
* Touch mirrors on even on fail to update (#19217) (#19233)
|
||||
* Hide sensitive content on admin panel progress monitor (#19218 & #19226) (#19231)
|
||||
* Fix clone url JS error for the empty repo page (#19209)
|
||||
* Bump goldmark to v1.4.11 (#19201) (#19203)
|
||||
* TESTING
|
||||
* Prevent intermittent failures in RepoIndexerTest (#19225 #19229) (#19228)
|
||||
* BUILD
|
||||
* Revert the minimal golang version requirement from 1.17 to 1.16 and add a warning in Makefile (#19319)
|
||||
* MISC
|
||||
* Performance improvement for add team user when org has more than 1000 repositories (#19227) (#19289)
|
||||
* Check go and nodejs version by go.mod and package.json (#19197) (#19254)
|
||||
|
||||
## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/v1.16.5) - 2022-03-23
|
||||
|
||||
* BREAKING
|
||||
* Bump to build with go1.18 (#19120 et al) (#19127)
|
||||
|
||||
16
Makefile
16
Makefile
@@ -25,8 +25,6 @@ HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||
COMMA := ,
|
||||
|
||||
XGO_VERSION := go-1.18.x
|
||||
MIN_GO_VERSION := 001017000
|
||||
MIN_NODE_VERSION := 012017000
|
||||
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
|
||||
@@ -203,10 +201,15 @@ help:
|
||||
|
||||
.PHONY: go-check
|
||||
go-check:
|
||||
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
|
||||
$(eval MIN_GO_VERSION_STR := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2))
|
||||
$(eval MIN_GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_GO_VERSION_STR)' | tr '.' ' ')))
|
||||
$(eval GO_VERSION_STR := $(shell $(GO) version | grep -Eo '[0-9]+\.[0-9.]+'))
|
||||
$(eval GO_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(GO_VERSION_STR)' | tr '.' ' ')))
|
||||
@if [ "$(GO_VERSION)" -lt "$(MIN_GO_VERSION)" ]; then \
|
||||
echo "Gitea requires Go 1.16 or greater to build. You can get it at https://golang.org/dl/"; \
|
||||
echo "Gitea requires Go $(MIN_GO_VERSION_STR) or greater to build, but $(GO_VERSION) was found. You can get an updated version at https://go.dev/dl/"; \
|
||||
exit 1; \
|
||||
else \
|
||||
echo "WARNING: Please ensure Go $(GO_VERSION_STR) is still maintained to avoid possible security problems. You can check it at https://go.dev/dl/"; \
|
||||
fi
|
||||
|
||||
.PHONY: git-check
|
||||
@@ -218,11 +221,12 @@ git-check:
|
||||
|
||||
.PHONY: node-check
|
||||
node-check:
|
||||
$(eval MIN_NODE_VERSION_STR := $(shell grep -Eo '"node":.*[0-9.]+"' package.json | sed -n 's/.*[^0-9.]\([0-9.]*\)"/\1/p'))
|
||||
$(eval MIN_NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell echo '$(MIN_NODE_VERSION_STR)' | tr '.' ' ')))
|
||||
$(eval NODE_VERSION := $(shell printf "%03d%03d%03d" $(shell node -v | cut -c2- | tr '.' ' ');))
|
||||
$(eval MIN_NODE_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_NODE_VERSION) | grep -o ...)))
|
||||
$(eval NPM_MISSING := $(shell hash npm > /dev/null 2>&1 || echo 1))
|
||||
@if [ "$(NODE_VERSION)" -lt "$(MIN_NODE_VERSION)" -o "$(NPM_MISSING)" = "1" ]; then \
|
||||
echo "Gitea requires Node.js $(MIN_NODE_VER_FMT) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
|
||||
echo "Gitea requires Node.js $(MIN_NODE_VERSION_STR) or greater and npm to build. You can get it at https://nodejs.org/en/download/"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
|
||||
20
cmd/admin.go
20
cmd/admin.go
@@ -25,6 +25,7 @@ import (
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
auth_service "code.gitea.io/gitea/services/auth"
|
||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||
"code.gitea.io/gitea/services/auth/source/smtp"
|
||||
@@ -113,6 +114,10 @@ var (
|
||||
Name: "access-token",
|
||||
Usage: "Generate access token for the user",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "restricted",
|
||||
Usage: "Make a restricted user account",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -537,17 +542,26 @@ func runCreateUser(c *cli.Context) error {
|
||||
changePassword = c.Bool("must-change-password")
|
||||
}
|
||||
|
||||
restricted := util.OptionalBoolNone
|
||||
|
||||
if c.IsSet("restricted") {
|
||||
restricted = util.OptionalBoolOf(c.Bool("restricted"))
|
||||
}
|
||||
|
||||
u := &user_model.User{
|
||||
Name: username,
|
||||
Email: c.String("email"),
|
||||
Passwd: password,
|
||||
IsActive: true,
|
||||
IsAdmin: c.Bool("admin"),
|
||||
MustChangePassword: changePassword,
|
||||
Theme: setting.UI.DefaultTheme,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u); err != nil {
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
IsRestricted: restricted,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
|
||||
return fmt.Errorf("CreateUser: %v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ func (o outputType) String() string {
|
||||
}
|
||||
|
||||
var outputTypeEnum = &outputType{
|
||||
Enum: []string{"zip", "rar", "tar", "sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
|
||||
Enum: []string{"zip", "tar", "tar.sz", "tar.gz", "tar.xz", "tar.bz2", "tar.br", "tar.lz4"},
|
||||
Default: "zip",
|
||||
}
|
||||
|
||||
@@ -160,7 +160,12 @@ func runDump(ctx *cli.Context) error {
|
||||
fatal("Deleting default logger failed. Can not write to stdout: %v", err)
|
||||
}
|
||||
} else {
|
||||
fileName = strings.TrimSuffix(fileName, path.Ext(fileName))
|
||||
for _, suffix := range outputTypeEnum.Enum {
|
||||
if strings.HasSuffix(fileName, "."+suffix) {
|
||||
fileName = strings.TrimSuffix(fileName, "."+suffix)
|
||||
break
|
||||
}
|
||||
}
|
||||
fileName += "." + outType
|
||||
}
|
||||
setting.LoadFromExisting()
|
||||
|
||||
@@ -297,6 +297,15 @@ func runServ(c *cli.Context) error {
|
||||
gitcmd = exec.CommandContext(ctx, verb, repoPath)
|
||||
}
|
||||
|
||||
// Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when
|
||||
// `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection.
|
||||
if _, err := os.Stat(setting.RepoRootPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return fail("Incorrect configuration.",
|
||||
"Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.")
|
||||
}
|
||||
}
|
||||
|
||||
gitcmd.Dir = setting.RepoRootPath
|
||||
gitcmd.Stdout = os.Stdout
|
||||
gitcmd.Stdin = os.Stdin
|
||||
|
||||
@@ -1075,7 +1075,7 @@ PATH =
|
||||
;SEARCH_REPO_DESCRIPTION = true
|
||||
;;
|
||||
;; Whether to enable a Service Worker to cache frontend assets
|
||||
;USE_SERVICE_WORKER = true
|
||||
;USE_SERVICE_WORKER = false
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -19,7 +19,7 @@ params:
|
||||
author: The Gitea Authors
|
||||
website: https://docs.gitea.io
|
||||
version: 1.16.4
|
||||
minGoVersion: 1.17
|
||||
minGoVersion: 1.16
|
||||
goVersion: 1.18
|
||||
minNodeVersion: 12.17
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
|
||||
add it to this config.
|
||||
- `DEFAULT_SHOW_FULL_NAME`: **false**: Whether the full name of the users should be shown where possible. If the full name isn't set, the username will be used.
|
||||
- `SEARCH_REPO_DESCRIPTION`: **true**: Whether to search within description at repository search on explore page.
|
||||
- `USE_SERVICE_WORKER`: **true**: Whether to enable a Service Worker to cache frontend assets.
|
||||
- `USE_SERVICE_WORKER`: **false**: Whether to enable a Service Worker to cache frontend assets.
|
||||
|
||||
### UI - Admin (`ui.admin`)
|
||||
|
||||
|
||||
@@ -185,8 +185,6 @@ Before committing, make sure the linters pass:
|
||||
make lint-frontend
|
||||
```
|
||||
|
||||
Note: When working on frontend code, set `USE_SERVICE_WORKER` to `false` in `app.ini` to prevent undesirable caching of frontend assets.
|
||||
|
||||
### Building and adding SVGs
|
||||
|
||||
SVG icons are built using the `make svg` target which compiles the icon sources defined in `build/generate-svg.js` into the output directory `public/img/svg`. Custom icons can be added in the `web_src/svg` directory.
|
||||
|
||||
@@ -43,7 +43,7 @@ Vous devriez avoir une instance fonctionnelle de Gitea. Pour accèder à l'inter
|
||||
|
||||
## Named Volumes
|
||||
|
||||
Ce guide aboutira à une installation avec les données Gita et PostgreSQL stockées dans des volumes nommés. Cela permet une sauvegarde, une restauration et des mises à niveau en toute simplicité.
|
||||
Ce guide aboutira à une installation avec les données Gitea et PostgreSQL stockées dans des volumes nommés. Cela permet une sauvegarde, une restauration et des mises à niveau en toute simplicité.
|
||||
|
||||
### The Database
|
||||
|
||||
|
||||
135
go.mod
135
go.mod
@@ -1,9 +1,8 @@
|
||||
module code.gitea.io/gitea
|
||||
|
||||
go 1.17
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
code.gitea.io/gitea-vet v0.2.1
|
||||
code.gitea.io/sdk/gitea v0.15.1
|
||||
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb
|
||||
@@ -38,7 +37,7 @@ require (
|
||||
github.com/go-swagger/go-swagger v0.27.0
|
||||
github.com/go-testfixtures/testfixtures/v3 v3.6.1
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f
|
||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
@@ -55,7 +54,6 @@ require (
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
|
||||
github.com/klauspost/compress v1.13.6
|
||||
github.com/klauspost/cpuid/v2 v2.0.9
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
|
||||
github.com/markbates/goth v1.69.0
|
||||
@@ -85,7 +83,7 @@ require (
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/xanzy/go-gitlab v0.58.0
|
||||
github.com/yohcop/openid-go v1.0.0
|
||||
github.com/yuin/goldmark v1.4.8
|
||||
github.com/yuin/goldmark v1.4.11
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
go.jolheiser.com/hcaptcha v0.0.4
|
||||
@@ -93,7 +91,7 @@ require (
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
|
||||
@@ -112,174 +110,49 @@ require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/RoaringBitmap/roaring v0.9.4 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.1 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.3 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.0 // indirect
|
||||
github.com/blevesearch/segment v0.9.0 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
|
||||
github.com/blevesearch/vellum v1.0.7 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.3 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cloudflare/cfssl v1.6.1 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
|
||||
github.com/couchbase/gomemcached v0.1.2 // indirect
|
||||
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.0 // indirect
|
||||
github.com/go-openapi/runtime v0.21.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.1 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/validate v0.20.3 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/goccy/go-json v0.9.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||
github.com/jhump/protoreflect v1.8.2 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/markbates/going v1.0.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mholt/acmez v1.0.2 // indirect
|
||||
github.com/miekg/dns v1.1.46 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/afero v1.8.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.3.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.10.1 // indirect
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/steveyen/gtreap v0.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.1 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/v3 v3.5.0-alpha.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.2 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.43.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
||||
|
||||
12
go.sum
12
go.sum
@@ -649,8 +649,8 @@ github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY=
|
||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
|
||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8=
|
||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JPCjlxoJd6K8ALZqSDDhk2ymieAZOVaDg0=
|
||||
@@ -1539,8 +1539,8 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark v1.4.8 h1:zHPiabbIRssZOI0MAzJDHsyvG4MXCGqVaMOwR+HeoQQ=
|
||||
github.com/yuin/goldmark v1.4.8/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark v1.4.11 h1:i45YIzqLnUc2tGaTlJCyUxSG8TvgyGqhqOZOUKIjJ6w=
|
||||
github.com/yuin/goldmark v1.4.11/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg=
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU=
|
||||
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
|
||||
@@ -1676,8 +1676,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
||||
@@ -69,6 +69,12 @@ func TestAPIAddEmail(t *testing.T) {
|
||||
Primary: false,
|
||||
},
|
||||
}, emails)
|
||||
|
||||
opts = api.CreateEmailOption{
|
||||
Emails: []string{"notAEmail"},
|
||||
}
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/user/emails?token="+token, &opts)
|
||||
session.MakeRequest(t, req, http.StatusUnprocessableEntity)
|
||||
}
|
||||
|
||||
func TestAPIDeleteEmail(t *testing.T) {
|
||||
|
||||
@@ -112,6 +112,13 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
}
|
||||
|
||||
os.Unsetenv("GIT_AUTHOR_NAME")
|
||||
os.Unsetenv("GIT_AUTHOR_EMAIL")
|
||||
os.Unsetenv("GIT_AUTHOR_DATE")
|
||||
os.Unsetenv("GIT_COMMITTER_NAME")
|
||||
os.Unsetenv("GIT_COMMITTER_EMAIL")
|
||||
os.Unsetenv("GIT_COMMITTER_DATE")
|
||||
|
||||
err := unittest.InitFixtures(
|
||||
unittest.FixturesOptions{
|
||||
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),
|
||||
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/services/pull"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/unknwon/i18n"
|
||||
@@ -65,7 +67,7 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
|
||||
|
||||
func TestPullMerge(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
|
||||
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
|
||||
assert.NoError(t, err)
|
||||
hookTasksLenBefore := len(hookTasks)
|
||||
|
||||
@@ -87,7 +89,7 @@ func TestPullMerge(t *testing.T) {
|
||||
|
||||
func TestPullRebase(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
|
||||
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
|
||||
assert.NoError(t, err)
|
||||
hookTasksLenBefore := len(hookTasks)
|
||||
|
||||
@@ -109,7 +111,7 @@ func TestPullRebase(t *testing.T) {
|
||||
|
||||
func TestPullRebaseMerge(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
|
||||
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
|
||||
assert.NoError(t, err)
|
||||
hookTasksLenBefore := len(hookTasks)
|
||||
|
||||
@@ -131,7 +133,7 @@ func TestPullRebaseMerge(t *testing.T) {
|
||||
|
||||
func TestPullSquash(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||
hookTasks, err := webhook.HookTasks(1, 1) //Retrieve previous hook number
|
||||
hookTasks, err := webhook.HookTasks(1, 1) // Retrieve previous hook number
|
||||
assert.NoError(t, err)
|
||||
hookTasksLenBefore := len(hookTasks)
|
||||
|
||||
@@ -335,3 +337,74 @@ func TestCantMergeUnrelated(t *testing.T) {
|
||||
gitRepo.Close()
|
||||
})
|
||||
}
|
||||
|
||||
func TestConflictChecking(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
|
||||
|
||||
// Create new clean repo to test conflict checking.
|
||||
baseRepo, err := repo_service.CreateRepository(user, user, models.CreateRepoOptions{
|
||||
Name: "conflict-checking",
|
||||
Description: "Tempo repo",
|
||||
AutoInit: true,
|
||||
Readme: "Default",
|
||||
DefaultBranch: "main",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, baseRepo)
|
||||
|
||||
// create a commit on new branch.
|
||||
_, err = files_service.CreateOrUpdateRepoFile(baseRepo, user, &files_service.UpdateRepoFileOptions{
|
||||
TreePath: "important_file",
|
||||
Message: "Add a important file",
|
||||
Content: "Just a non-important file",
|
||||
IsNewFile: true,
|
||||
OldBranch: "main",
|
||||
NewBranch: "important-secrets",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// create a commit on main branch.
|
||||
_, err = files_service.CreateOrUpdateRepoFile(baseRepo, user, &files_service.UpdateRepoFileOptions{
|
||||
TreePath: "important_file",
|
||||
Message: "Add a important file",
|
||||
Content: "Not the same content :P",
|
||||
IsNewFile: true,
|
||||
OldBranch: "main",
|
||||
NewBranch: "main",
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// create Pull to merge the important-secrets branch into main branch.
|
||||
pullIssue := &models.Issue{
|
||||
RepoID: baseRepo.ID,
|
||||
Title: "PR with conflict!",
|
||||
PosterID: user.ID,
|
||||
Poster: user,
|
||||
IsPull: true,
|
||||
}
|
||||
|
||||
pullRequest := &models.PullRequest{
|
||||
HeadRepoID: baseRepo.ID,
|
||||
BaseRepoID: baseRepo.ID,
|
||||
HeadBranch: "important-secrets",
|
||||
BaseBranch: "main",
|
||||
HeadRepo: baseRepo,
|
||||
BaseRepo: baseRepo,
|
||||
Type: models.PullRequestGitea,
|
||||
}
|
||||
err = pull.NewPullRequest(baseRepo, pullIssue, nil, nil, pullRequest, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "PR with conflict!"}).(*models.Issue)
|
||||
conflictingPR, err := models.GetPullRequestByIssueID(issue.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Ensure conflictedFiles is populated.
|
||||
assert.Equal(t, 1, len(conflictingPR.ConflictedFiles))
|
||||
// Check if status is correct.
|
||||
assert.Equal(t, models.PullRequestStatusConflict, conflictingPR.Status)
|
||||
// Ensure that mergeable returns false
|
||||
assert.False(t, conflictingPR.Mergeable())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1165,7 +1165,8 @@ func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) {
|
||||
// IssuesOptions represents options of an issue.
|
||||
type IssuesOptions struct {
|
||||
db.ListOptions
|
||||
RepoIDs []int64 // include all repos if empty
|
||||
RepoID int64 // overwrites RepoCond if not 0
|
||||
RepoCond builder.Cond
|
||||
AssigneeID int64
|
||||
PosterID int64
|
||||
MentionedID int64
|
||||
@@ -1238,7 +1239,7 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64
|
||||
}
|
||||
}
|
||||
|
||||
func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
|
||||
func (opts *IssuesOptions) setupSessionWithLimit(sess *xorm.Session) {
|
||||
if opts.Page >= 0 && opts.PageSize > 0 {
|
||||
var start int
|
||||
if opts.Page == 0 {
|
||||
@@ -1248,20 +1249,23 @@ func (opts *IssuesOptions) setupSession(sess *xorm.Session) {
|
||||
}
|
||||
sess.Limit(opts.PageSize, start)
|
||||
}
|
||||
opts.setupSessionNoLimit(sess)
|
||||
}
|
||||
|
||||
func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) {
|
||||
if len(opts.IssueIDs) > 0 {
|
||||
sess.In("issue.id", opts.IssueIDs)
|
||||
}
|
||||
|
||||
if len(opts.RepoIDs) > 0 {
|
||||
applyReposCondition(sess, opts.RepoIDs)
|
||||
if opts.RepoID != 0 {
|
||||
opts.RepoCond = builder.Eq{"issue.repo_id": opts.RepoID}
|
||||
}
|
||||
if opts.RepoCond != nil {
|
||||
sess.And(opts.RepoCond)
|
||||
}
|
||||
|
||||
switch opts.IsClosed {
|
||||
case util.OptionalBoolTrue:
|
||||
sess.And("issue.is_closed=?", true)
|
||||
case util.OptionalBoolFalse:
|
||||
sess.And("issue.is_closed=?", false)
|
||||
if !opts.IsClosed.IsNone() {
|
||||
sess.And("issue.is_closed=?", opts.IsClosed.IsTrue())
|
||||
}
|
||||
|
||||
if opts.AssigneeID > 0 {
|
||||
@@ -1380,10 +1384,6 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *Organizati
|
||||
return cond
|
||||
}
|
||||
|
||||
func applyReposCondition(sess *xorm.Session, repoIDs []int64) *xorm.Session {
|
||||
return sess.In("issue.repo_id", repoIDs)
|
||||
}
|
||||
|
||||
func applyAssigneeCondition(sess *xorm.Session, assigneeID int64) *xorm.Session {
|
||||
return sess.Join("INNER", "issue_assignees", "issue.id = issue_assignees.issue_id").
|
||||
And("issue_assignees.assignee_id = ?", assigneeID)
|
||||
@@ -1414,7 +1414,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
|
||||
|
||||
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
|
||||
opts.setupSession(sess)
|
||||
opts.setupSessionNoLimit(sess)
|
||||
|
||||
countsSlice := make([]*struct {
|
||||
RepoID int64
|
||||
@@ -1424,7 +1424,7 @@ func CountIssuesByRepo(opts *IssuesOptions) (map[int64]int64, error) {
|
||||
Select("issue.repo_id AS repo_id, COUNT(*) AS count").
|
||||
Table("issue").
|
||||
Find(&countsSlice); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("unable to CountIssuesByRepo: %w", err)
|
||||
}
|
||||
|
||||
countMap := make(map[int64]int64, len(countsSlice))
|
||||
@@ -1441,14 +1441,14 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
|
||||
|
||||
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
|
||||
opts.setupSession(sess)
|
||||
opts.setupSessionNoLimit(sess)
|
||||
|
||||
accessCond := accessibleRepositoryCondition(user)
|
||||
if err := sess.Where(accessCond).
|
||||
Distinct("issue.repo_id").
|
||||
Table("issue").
|
||||
Find(&repoIDs); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("unable to GetRepoIDsForIssuesOptions: %w", err)
|
||||
}
|
||||
|
||||
return repoIDs, nil
|
||||
@@ -1459,17 +1459,16 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
|
||||
sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
opts.setupSession(sess)
|
||||
opts.setupSessionWithLimit(sess)
|
||||
sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID)
|
||||
|
||||
issues := make([]*Issue, 0, opts.ListOptions.PageSize)
|
||||
if err := sess.Find(&issues); err != nil {
|
||||
return nil, fmt.Errorf("Find: %v", err)
|
||||
return nil, fmt.Errorf("unable to query Issues: %w", err)
|
||||
}
|
||||
sess.Close()
|
||||
|
||||
if err := IssueList(issues).LoadAttributes(); err != nil {
|
||||
return nil, fmt.Errorf("LoadAttributes: %v", err)
|
||||
return nil, fmt.Errorf("unable to LoadAttributes for Issues: %w", err)
|
||||
}
|
||||
|
||||
return issues, nil
|
||||
@@ -1480,18 +1479,17 @@ func CountIssues(opts *IssuesOptions) (int64, error) {
|
||||
e := db.GetEngine(db.DefaultContext)
|
||||
|
||||
countsSlice := make([]*struct {
|
||||
RepoID int64
|
||||
Count int64
|
||||
Count int64
|
||||
}, 0, 1)
|
||||
|
||||
sess := e.Select("COUNT(issue.id) AS count").Table("issue")
|
||||
sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id")
|
||||
opts.setupSession(sess)
|
||||
opts.setupSessionNoLimit(sess)
|
||||
if err := sess.Find(&countsSlice); err != nil {
|
||||
return 0, fmt.Errorf("Find: %v", err)
|
||||
return 0, fmt.Errorf("unable to CountIssues: %w", err)
|
||||
}
|
||||
if len(countsSlice) < 1 {
|
||||
return 0, fmt.Errorf("there is less than one result sql record")
|
||||
if len(countsSlice) != 1 {
|
||||
return 0, fmt.Errorf("unable to get one row result when CountIssues, row count=%d", len(countsSlice))
|
||||
}
|
||||
return countsSlice[0].Count, nil
|
||||
}
|
||||
|
||||
@@ -101,12 +101,9 @@ func (label *Label) CalOpenIssues() {
|
||||
|
||||
// CalOpenOrgIssues calculates the open issues of a label for a specific repo
|
||||
func (label *Label) CalOpenOrgIssues(repoID, labelID int64) {
|
||||
repoIDs := []int64{repoID}
|
||||
labelIDs := []int64{labelID}
|
||||
|
||||
counts, _ := CountIssuesByRepo(&IssuesOptions{
|
||||
RepoIDs: repoIDs,
|
||||
LabelIDs: labelIDs,
|
||||
RepoID: repoID,
|
||||
LabelIDs: []int64{labelID},
|
||||
})
|
||||
|
||||
for _, count := range counts {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func TestIssue_ReplaceLabels(t *testing.T) {
|
||||
@@ -153,7 +154,7 @@ func TestIssues(t *testing.T) {
|
||||
},
|
||||
{
|
||||
IssuesOptions{
|
||||
RepoIDs: []int64{1, 3},
|
||||
RepoCond: builder.In("repo_id", 1, 3),
|
||||
SortType: "oldest",
|
||||
ListOptions: db.ListOptions{
|
||||
Page: 1,
|
||||
@@ -340,7 +341,7 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) {
|
||||
},
|
||||
{
|
||||
IssuesOptions{
|
||||
RepoIDs: []int64{1, 2},
|
||||
RepoCond: builder.In("repo_id", 1, 2),
|
||||
},
|
||||
[]int64{1, 2},
|
||||
},
|
||||
|
||||
@@ -453,7 +453,7 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
|
||||
|
||||
// Downgrading Gitea's database version not supported
|
||||
if int(v-minDBVersion) > len(migrations) {
|
||||
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gita, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations))
|
||||
msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gitea, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations))
|
||||
msg += "\nGitea will exit to keep your database safe and unchanged. Please use the correct Gitea release, do not change the migration version manually (incorrect manual operation may lose data)."
|
||||
if !setting.IsProd {
|
||||
msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minDBVersion+len(migrations))
|
||||
|
||||
@@ -940,11 +940,6 @@ func AddTeamMember(team *Team, userID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get team and its repositories.
|
||||
if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -966,17 +961,51 @@ func AddTeamMember(team *Team, userID int64) error {
|
||||
team.NumMembers++
|
||||
|
||||
// Give access to team repositories.
|
||||
for _, repo := range team.Repos {
|
||||
if err := recalculateUserAccess(ctx, repo, userID); err != nil {
|
||||
return err
|
||||
}
|
||||
if setting.Service.AutoWatchNewRepos {
|
||||
if err = repo_model.WatchRepoCtx(ctx, userID, repo.ID, true); err != nil {
|
||||
return err
|
||||
// update exist access if mode become bigger
|
||||
subQuery := builder.Select("repo_id").From("team_repo").
|
||||
Where(builder.Eq{"team_id": team.ID})
|
||||
|
||||
if _, err := sess.Where("user_id=?", userID).
|
||||
In("repo_id", subQuery).
|
||||
And("mode < ?", team.AccessMode).
|
||||
SetExpr("mode", team.AccessMode).
|
||||
Update(new(Access)); err != nil {
|
||||
return fmt.Errorf("update user accesses: %v", err)
|
||||
}
|
||||
|
||||
// for not exist access
|
||||
var repoIDs []int64
|
||||
accessSubQuery := builder.Select("repo_id").From("access").Where(builder.Eq{"user_id": userID})
|
||||
if err := sess.SQL(subQuery.And(builder.NotIn("repo_id", accessSubQuery))).Find(&repoIDs); err != nil {
|
||||
return fmt.Errorf("select id accesses: %v", err)
|
||||
}
|
||||
|
||||
accesses := make([]*Access, 0, 100)
|
||||
for i, repoID := range repoIDs {
|
||||
accesses = append(accesses, &Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode})
|
||||
if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 {
|
||||
if err = db.Insert(ctx, accesses); err != nil {
|
||||
return fmt.Errorf("insert new user accesses: %v", err)
|
||||
}
|
||||
accesses = accesses[:0]
|
||||
}
|
||||
}
|
||||
|
||||
// watch could be failed, so run it in a goroutine
|
||||
if setting.Service.AutoWatchNewRepos {
|
||||
// Get team and its repositories.
|
||||
if err := team.GetRepositories(&SearchOrgTeamOptions{}); err != nil {
|
||||
log.Error("getRepositories failed: %v", err)
|
||||
}
|
||||
go func(repos []*repo_model.Repository) {
|
||||
for _, repo := range repos {
|
||||
if err = repo_model.WatchRepoCtx(db.DefaultContext, userID, repo.ID, true); err != nil {
|
||||
log.Error("watch repo failed: %v", err)
|
||||
}
|
||||
}
|
||||
}(team.Repos)
|
||||
}
|
||||
|
||||
return committer.Commit()
|
||||
}
|
||||
|
||||
|
||||
@@ -222,22 +222,19 @@ func (pr *PullRequest) loadProtectedBranch(ctx context.Context) (err error) {
|
||||
}
|
||||
|
||||
// GetDefaultMergeMessage returns default message used when merging pull request
|
||||
func (pr *PullRequest) GetDefaultMergeMessage() string {
|
||||
func (pr *PullRequest) GetDefaultMergeMessage() (string, error) {
|
||||
if pr.HeadRepo == nil {
|
||||
var err error
|
||||
pr.HeadRepo, err = repo_model.GetRepositoryByID(pr.HeadRepoID)
|
||||
if err != nil {
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
|
||||
return ""
|
||||
return "", fmt.Errorf("GetRepositoryById[%d]: %v", pr.HeadRepoID, err)
|
||||
}
|
||||
}
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
log.Error("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
|
||||
return ""
|
||||
return "", fmt.Errorf("Cannot load issue %d for PR id %d: Error: %v", pr.IssueID, pr.ID, err)
|
||||
}
|
||||
if err := pr.LoadBaseRepo(); err != nil {
|
||||
log.Error("LoadBaseRepo: %v", err)
|
||||
return ""
|
||||
return "", fmt.Errorf("LoadBaseRepo: %v", err)
|
||||
}
|
||||
|
||||
issueReference := "#"
|
||||
@@ -246,10 +243,10 @@ func (pr *PullRequest) GetDefaultMergeMessage() string {
|
||||
}
|
||||
|
||||
if pr.BaseRepoID == pr.HeadRepoID {
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch)
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch)
|
||||
return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), nil
|
||||
}
|
||||
|
||||
// ReviewCount represents a count of Reviews
|
||||
@@ -335,19 +332,17 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error {
|
||||
}
|
||||
|
||||
// GetDefaultSquashMessage returns default message used when squash and merging pull request
|
||||
func (pr *PullRequest) GetDefaultSquashMessage() string {
|
||||
func (pr *PullRequest) GetDefaultSquashMessage() (string, error) {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
log.Error("LoadIssue: %v", err)
|
||||
return ""
|
||||
return "", fmt.Errorf("LoadIssue: %v", err)
|
||||
}
|
||||
if err := pr.LoadBaseRepo(); err != nil {
|
||||
log.Error("LoadBaseRepo: %v", err)
|
||||
return ""
|
||||
return "", fmt.Errorf("LoadBaseRepo: %v", err)
|
||||
}
|
||||
if pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) {
|
||||
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index)
|
||||
return fmt.Sprintf("%s (!%d)", pr.Issue.Title, pr.Issue.Index), nil
|
||||
}
|
||||
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index)
|
||||
return fmt.Sprintf("%s (#%d)", pr.Issue.Title, pr.Issue.Index), nil
|
||||
}
|
||||
|
||||
// GetGitRefName returns git ref for hidden pull request branch
|
||||
@@ -702,3 +697,14 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
|
||||
}
|
||||
return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
|
||||
}
|
||||
|
||||
// Mergeable returns if the pullrequest is mergeable.
|
||||
func (pr *PullRequest) Mergeable() bool {
|
||||
// If a pull request isn't mergable if it's:
|
||||
// - Being conflict checked.
|
||||
// - Has a conflict.
|
||||
// - Received a error while being conflict checked.
|
||||
// - Is a work-in-progress pull request.
|
||||
return pr.Status != PullRequestStatusChecking && pr.Status != PullRequestStatusConflict &&
|
||||
pr.Status != PullRequestStatusError && !pr.IsWorkInProgress()
|
||||
}
|
||||
|
||||
@@ -261,11 +261,15 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2}).(*PullRequest)
|
||||
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", pr.GetDefaultMergeMessage())
|
||||
msg, err := pr.GetDefaultMergeMessage()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", msg)
|
||||
|
||||
pr.BaseRepoID = 1
|
||||
pr.HeadRepoID = 2
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage())
|
||||
msg, err = pr.GetDefaultMergeMessage()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", msg)
|
||||
}
|
||||
|
||||
func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
|
||||
@@ -283,9 +287,13 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) {
|
||||
|
||||
pr := unittest.AssertExistsAndLoadBean(t, &PullRequest{ID: 2, BaseRepo: baseRepo}).(*PullRequest)
|
||||
|
||||
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", pr.GetDefaultMergeMessage())
|
||||
msg, err := pr.GetDefaultMergeMessage()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", msg)
|
||||
|
||||
pr.BaseRepoID = 1
|
||||
pr.HeadRepoID = 2
|
||||
assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", pr.GetDefaultMergeMessage())
|
||||
msg, err = pr.GetDefaultMergeMessage()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Merge pull request 'issue3' (!3) from user2/repo1:branch2 into master", msg)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -115,6 +116,13 @@ func UpdateMirror(m *Mirror) error {
|
||||
return updateMirror(db.GetEngine(db.DefaultContext), m)
|
||||
}
|
||||
|
||||
// TouchMirror updates the mirror updatedUnix
|
||||
func TouchMirror(ctx context.Context, m *Mirror) error {
|
||||
m.UpdatedUnix = timeutil.TimeStampNow()
|
||||
_, err := db.GetEngine(ctx).ID(m.ID).Cols("updated_unix").Update(m)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteMirrorByRepoID deletes a mirror by repoID
|
||||
func DeleteMirrorByRepoID(repoID int64) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID})
|
||||
|
||||
@@ -622,7 +622,14 @@ func IsUsableUsername(name string) error {
|
||||
|
||||
// CreateUserOverwriteOptions are an optional options who overwrite system defaults on user creation
|
||||
type CreateUserOverwriteOptions struct {
|
||||
Visibility structs.VisibleType
|
||||
KeepEmailPrivate util.OptionalBool
|
||||
Visibility *structs.VisibleType
|
||||
AllowCreateOrganization util.OptionalBool
|
||||
EmailNotificationsPreference *string
|
||||
MaxRepoCreation *int
|
||||
Theme *string
|
||||
IsRestricted util.OptionalBool
|
||||
IsActive util.OptionalBool
|
||||
}
|
||||
|
||||
// CreateUser creates record of a new user.
|
||||
@@ -638,10 +645,36 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
|
||||
u.EmailNotificationsPreference = setting.Admin.DefaultEmailNotification
|
||||
u.MaxRepoCreation = -1
|
||||
u.Theme = setting.UI.DefaultTheme
|
||||
u.IsRestricted = setting.Service.DefaultUserIsRestricted
|
||||
u.IsActive = !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm)
|
||||
|
||||
// overwrite defaults if set
|
||||
if len(overwriteDefault) != 0 && overwriteDefault[0] != nil {
|
||||
u.Visibility = overwriteDefault[0].Visibility
|
||||
overwrite := overwriteDefault[0]
|
||||
if !overwrite.KeepEmailPrivate.IsNone() {
|
||||
u.KeepEmailPrivate = overwrite.KeepEmailPrivate.IsTrue()
|
||||
}
|
||||
if overwrite.Visibility != nil {
|
||||
u.Visibility = *overwrite.Visibility
|
||||
}
|
||||
if !overwrite.AllowCreateOrganization.IsNone() {
|
||||
u.AllowCreateOrganization = overwrite.AllowCreateOrganization.IsTrue()
|
||||
}
|
||||
if overwrite.EmailNotificationsPreference != nil {
|
||||
u.EmailNotificationsPreference = *overwrite.EmailNotificationsPreference
|
||||
}
|
||||
if overwrite.MaxRepoCreation != nil {
|
||||
u.MaxRepoCreation = *overwrite.MaxRepoCreation
|
||||
}
|
||||
if overwrite.Theme != nil {
|
||||
u.Theme = *overwrite.Theme
|
||||
}
|
||||
if !overwrite.IsRestricted.IsNone() {
|
||||
u.IsRestricted = overwrite.IsRestricted.IsTrue()
|
||||
}
|
||||
if !overwrite.IsActive.IsNone() {
|
||||
u.IsActive = overwrite.IsActive.IsTrue()
|
||||
}
|
||||
}
|
||||
|
||||
// validate data
|
||||
|
||||
@@ -497,14 +497,19 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) {
|
||||
}
|
||||
|
||||
// GetSystemWebhooks returns all admin system webhooks.
|
||||
func GetSystemWebhooks() ([]*Webhook, error) {
|
||||
return getSystemWebhooks(db.GetEngine(db.DefaultContext))
|
||||
func GetSystemWebhooks(isActive util.OptionalBool) ([]*Webhook, error) {
|
||||
return getSystemWebhooks(db.GetEngine(db.DefaultContext), isActive)
|
||||
}
|
||||
|
||||
func getSystemWebhooks(e db.Engine) ([]*Webhook, error) {
|
||||
func getSystemWebhooks(e db.Engine, isActive util.OptionalBool) ([]*Webhook, error) {
|
||||
webhooks := make([]*Webhook, 0, 5)
|
||||
if isActive.IsNone() {
|
||||
return webhooks, e.
|
||||
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
|
||||
Find(&webhooks)
|
||||
}
|
||||
return webhooks, e.
|
||||
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
|
||||
Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
|
||||
Find(&webhooks)
|
||||
}
|
||||
|
||||
|
||||
@@ -229,6 +229,7 @@ func Csrfer(opt CsrfOptions, ctx *Context) CSRF {
|
||||
}
|
||||
}
|
||||
|
||||
needsNew = needsNew || ctx.Req.Method == "GET" // If this request is a Get request, it will generate a new token, make sure the token is always up-to-date.
|
||||
if needsNew {
|
||||
// FIXME: actionId.
|
||||
x.Token = GenerateToken(x.Secret, x.ID, "POST")
|
||||
|
||||
@@ -410,6 +410,12 @@ func RepoIDAssignment() func(ctx *Context) {
|
||||
|
||||
// RepoAssignment returns a middleware to handle repository assignment
|
||||
func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
if _, repoAssignmentOnce := ctx.Data["repoAssignmentExecuted"]; repoAssignmentOnce {
|
||||
log.Trace("RepoAssignment was exec already, skipping second call ...")
|
||||
return
|
||||
}
|
||||
ctx.Data["repoAssignmentExecuted"] = true
|
||||
|
||||
var (
|
||||
owner *user_model.User
|
||||
err error
|
||||
@@ -592,6 +598,9 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
ctx.ServerError("RepoAssignment Invalid repo "+repo_model.RepoPath(userName, repoName), err)
|
||||
return
|
||||
}
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
ctx.Repo.GitRepo.Close()
|
||||
}
|
||||
ctx.Repo.GitRepo = gitRepo
|
||||
|
||||
// We opened it, we should close it
|
||||
|
||||
@@ -67,6 +67,7 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
|
||||
PatchURL: pr.Issue.PatchURL(),
|
||||
HasMerged: pr.HasMerged,
|
||||
MergeBase: pr.MergeBase,
|
||||
Mergeable: pr.Mergeable(),
|
||||
Deadline: apiIssue.Deadline,
|
||||
Created: pr.Issue.CreatedUnix.AsTimePtr(),
|
||||
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
|
||||
@@ -190,10 +191,6 @@ func ToAPIPullRequest(pr *models.PullRequest, doer *user_model.User) *api.PullRe
|
||||
}
|
||||
}
|
||||
|
||||
if pr.Status != models.PullRequestStatusChecking {
|
||||
mergeable := !(pr.Status == models.PullRequestStatusConflict || pr.Status == models.PullRequestStatusError) && !pr.IsWorkInProgress()
|
||||
apiPullRequest.Mergeable = mergeable
|
||||
}
|
||||
if pr.HasMerged {
|
||||
apiPullRequest.Merged = pr.MergedUnix.AsTimePtr()
|
||||
apiPullRequest.MergedCommitID = &pr.MergedCommitID
|
||||
|
||||
@@ -71,8 +71,8 @@ func checkAuthorizedKeys(logger log.Logger, autofix bool) error {
|
||||
"authorized_keys file %q is out of date.\nRegenerate it with:\n\t\"%s\"\nor\n\t\"%s\"",
|
||||
fPath,
|
||||
"gitea admin regenerate keys",
|
||||
"gitea doctor --run authorized_keys --fix")
|
||||
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized_keys --fix"`)
|
||||
"gitea doctor --run authorized-keys --fix")
|
||||
return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`)
|
||||
}
|
||||
logger.Warn("authorized_keys is out of date. Attempting rewrite...")
|
||||
err = asymkey_model.RewriteAllPublicKeys()
|
||||
|
||||
@@ -54,6 +54,12 @@ func CatFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
|
||||
<-closed
|
||||
}
|
||||
|
||||
// Ensure cancel is called as soon as the provided context is cancelled
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
cancel()
|
||||
}()
|
||||
|
||||
_, filename, line, _ := runtime.Caller(2)
|
||||
filename = strings.TrimPrefix(filename, callerPrefix)
|
||||
|
||||
@@ -93,6 +99,12 @@ func CatFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
|
||||
<-closed
|
||||
}
|
||||
|
||||
// Ensure cancel is called as soon as the provided context is cancelled
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
cancel()
|
||||
}()
|
||||
|
||||
_, filename, line, _ := runtime.Caller(2)
|
||||
filename = strings.TrimPrefix(filename, callerPrefix)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -32,10 +33,11 @@ const DefaultLocale = "C"
|
||||
|
||||
// Command represents a command with its subcommands or arguments.
|
||||
type Command struct {
|
||||
name string
|
||||
args []string
|
||||
parentContext context.Context
|
||||
desc string
|
||||
name string
|
||||
args []string
|
||||
parentContext context.Context
|
||||
desc string
|
||||
globalArgsLength int
|
||||
}
|
||||
|
||||
func (c *Command) String() string {
|
||||
@@ -56,9 +58,10 @@ func NewCommandContext(ctx context.Context, args ...string) *Command {
|
||||
cargs := make([]string, len(GlobalCommandArgs))
|
||||
copy(cargs, GlobalCommandArgs)
|
||||
return &Command{
|
||||
name: GitExecutable,
|
||||
args: append(cargs, args...),
|
||||
parentContext: ctx,
|
||||
name: GitExecutable,
|
||||
args: append(cargs, args...),
|
||||
parentContext: ctx,
|
||||
globalArgsLength: len(GlobalCommandArgs),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +148,21 @@ func (c *Command) RunWithContext(rc *RunContext) error {
|
||||
|
||||
desc := c.desc
|
||||
if desc == "" {
|
||||
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(c.args, " "), rc.Dir)
|
||||
args := c.args[c.globalArgsLength:]
|
||||
var argSensitiveURLIndexes []int
|
||||
for i, arg := range c.args {
|
||||
if strings.Contains(arg, "://") && strings.Contains(arg, "@") {
|
||||
argSensitiveURLIndexes = append(argSensitiveURLIndexes, i)
|
||||
}
|
||||
}
|
||||
if len(argSensitiveURLIndexes) > 0 {
|
||||
args = make([]string, len(c.args))
|
||||
copy(args, c.args)
|
||||
for _, urlArgIndex := range argSensitiveURLIndexes {
|
||||
args[urlArgIndex] = util.NewStringURLSanitizer(args[urlArgIndex], true).Replace(args[urlArgIndex])
|
||||
}
|
||||
}
|
||||
desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), rc.Dir)
|
||||
}
|
||||
|
||||
ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, rc.Timeout, desc)
|
||||
|
||||
@@ -112,8 +112,8 @@ func SetExecutablePath(path string) error {
|
||||
|
||||
// VersionInfo returns git version information
|
||||
func VersionInfo() string {
|
||||
var format = "Git Version: %s"
|
||||
var args = []interface{}{gitVersion.Original()}
|
||||
format := "Git Version: %s"
|
||||
args := []interface{}{gitVersion.Original()}
|
||||
// Since git wire protocol has been released from git v2.18
|
||||
if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil {
|
||||
format += ", Wire Protocol %s Enabled"
|
||||
@@ -148,7 +148,7 @@ func Init(ctx context.Context) error {
|
||||
|
||||
// By default partial clones are disabled, enable them from git v2.22
|
||||
if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil {
|
||||
GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true")
|
||||
GlobalCommandArgs = append(GlobalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true")
|
||||
}
|
||||
|
||||
// Save current git version on init to gitVersion otherwise it would require an RWMutex
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/proxy"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// GPGSettings represents the default GPG settings for this repository
|
||||
@@ -158,6 +159,12 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
|
||||
}
|
||||
cmd.AddArguments("--", from, to)
|
||||
|
||||
if strings.Contains(from, "://") && strings.Contains(from, "@") {
|
||||
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.NewStringURLSanitizer(from, true).Replace(from), to, opts.Shared, opts.Mirror, opts.Depth))
|
||||
} else {
|
||||
cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth))
|
||||
}
|
||||
|
||||
if opts.Timeout <= 0 {
|
||||
opts.Timeout = -1
|
||||
}
|
||||
@@ -234,6 +241,11 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
||||
if len(opts.Branch) > 0 {
|
||||
cmd.AddArguments(opts.Branch)
|
||||
}
|
||||
if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") {
|
||||
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.NewStringURLSanitizer(opts.Remote, true).Replace(opts.Remote), opts.Force, opts.Mirror))
|
||||
} else {
|
||||
cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror))
|
||||
}
|
||||
var outbuf, errbuf strings.Builder
|
||||
|
||||
if opts.Timeout == 0 {
|
||||
|
||||
@@ -119,12 +119,10 @@ type CheckAttributeReader struct {
|
||||
env []string
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
running chan struct{}
|
||||
}
|
||||
|
||||
// Init initializes the cmd
|
||||
func (c *CheckAttributeReader) Init(ctx context.Context) error {
|
||||
c.running = make(chan struct{})
|
||||
cmdArgs := []string{"check-attr", "--stdin", "-z"}
|
||||
|
||||
if len(c.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
|
||||
@@ -183,14 +181,7 @@ func (c *CheckAttributeReader) Run() error {
|
||||
_ = c.stdOut.Close()
|
||||
}()
|
||||
stdErr := new(bytes.Buffer)
|
||||
err := c.cmd.RunInDirTimeoutEnvFullPipelineFunc(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader, func(_ context.Context, _ context.CancelFunc) error {
|
||||
select {
|
||||
case <-c.running:
|
||||
default:
|
||||
close(c.running)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
err := c.cmd.RunInDirTimeoutEnvFullPipeline(c.env, -1, c.Repo.Path, c.stdOut, stdErr, c.stdinReader)
|
||||
if err != nil && // If there is an error we need to return but:
|
||||
c.ctx.Err() != err && // 1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded)
|
||||
err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed
|
||||
@@ -210,7 +201,7 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
return nil, c.ctx.Err()
|
||||
case <-c.running:
|
||||
default:
|
||||
}
|
||||
|
||||
if _, err = c.stdinWriter.Write([]byte(path + "\x00")); err != nil {
|
||||
@@ -237,11 +228,6 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
|
||||
func (c *CheckAttributeReader) Close() error {
|
||||
c.cancel()
|
||||
err := c.stdinWriter.Close()
|
||||
select {
|
||||
case <-c.running:
|
||||
default:
|
||||
close(c.running)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
"github.com/go-git/go-git/v5/plumbing/storer"
|
||||
)
|
||||
|
||||
// IsObjectExist returns true if given reference exists in the repository.
|
||||
@@ -82,7 +83,8 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
|
||||
}
|
||||
|
||||
// WalkReferences walks all the references from the repository
|
||||
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
|
||||
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
|
||||
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
|
||||
repo, err := OpenRepositoryCtx(ctx, repoPath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -97,9 +99,45 @@ func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) er
|
||||
defer iter.Close()
|
||||
|
||||
err = iter.ForEach(func(ref *plumbing.Reference) error {
|
||||
err := walkfn(string(ref.Name()))
|
||||
err := walkfn(ref.Hash().String(), string(ref.Name()))
|
||||
i++
|
||||
return err
|
||||
})
|
||||
return i, err
|
||||
}
|
||||
|
||||
// WalkReferences walks all the references from the repository
|
||||
func (repo *Repository) WalkReferences(arg ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
|
||||
i := 0
|
||||
var iter storer.ReferenceIter
|
||||
var err error
|
||||
switch arg {
|
||||
case ObjectTag:
|
||||
iter, err = repo.gogitRepo.Tags()
|
||||
case ObjectBranch:
|
||||
iter, err = repo.gogitRepo.Branches()
|
||||
default:
|
||||
iter, err = repo.gogitRepo.References()
|
||||
}
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
defer iter.Close()
|
||||
|
||||
err = iter.ForEach(func(ref *plumbing.Reference) error {
|
||||
if i < skip {
|
||||
i++
|
||||
return nil
|
||||
}
|
||||
err := walkfn(ref.Hash().String(), string(ref.Name()))
|
||||
i++
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if limit != 0 && i >= skip+limit {
|
||||
return storer.ErrStop
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -68,13 +68,29 @@ func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
|
||||
}
|
||||
|
||||
// WalkReferences walks all the references from the repository
|
||||
func WalkReferences(ctx context.Context, repoPath string, walkfn func(string) error) (int, error) {
|
||||
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
|
||||
return walkShowRef(ctx, repoPath, "", 0, 0, walkfn)
|
||||
}
|
||||
|
||||
// WalkReferences walks all the references from the repository
|
||||
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
|
||||
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
|
||||
var arg string
|
||||
switch refType {
|
||||
case ObjectTag:
|
||||
arg = "--tags"
|
||||
case ObjectBranch:
|
||||
arg = "--heads"
|
||||
default:
|
||||
arg = ""
|
||||
}
|
||||
|
||||
return walkShowRef(repo.Ctx, repo.Path, arg, skip, limit, walkfn)
|
||||
}
|
||||
|
||||
// callShowRef return refs, if limit = 0 it will not limit
|
||||
func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
|
||||
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(branchName string) error {
|
||||
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(_, branchName string) error {
|
||||
branchName = strings.TrimPrefix(branchName, prefix)
|
||||
branchNames = append(branchNames, branchName)
|
||||
|
||||
@@ -83,7 +99,7 @@ func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit
|
||||
return
|
||||
}
|
||||
|
||||
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(string) error) (countAll int, err error) {
|
||||
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
|
||||
stdoutReader, stdoutWriter := io.Pipe()
|
||||
defer func() {
|
||||
_ = stdoutReader.Close()
|
||||
@@ -125,11 +141,7 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
|
||||
for limit == 0 || i < skip+limit {
|
||||
// The output of show-ref is simply a list:
|
||||
// <sha> SP <ref> LF
|
||||
_, err := bufReader.ReadSlice(' ')
|
||||
for err == bufio.ErrBufferFull {
|
||||
// This shouldn't happen but we'll tolerate it for the sake of peace
|
||||
_, err = bufReader.ReadSlice(' ')
|
||||
}
|
||||
sha, err := bufReader.ReadString(' ')
|
||||
if err == io.EOF {
|
||||
return i, nil
|
||||
}
|
||||
@@ -149,7 +161,12 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
|
||||
if len(branchName) > 0 {
|
||||
branchName = branchName[:len(branchName)-1]
|
||||
}
|
||||
err = walkfn(branchName)
|
||||
|
||||
if len(sha) > 0 {
|
||||
sha = sha[:len(sha)-1]
|
||||
}
|
||||
|
||||
err = walkfn(sha, branchName)
|
||||
if err != nil {
|
||||
return i, err
|
||||
}
|
||||
|
||||
21
modules/git/repo_commitgraph.go
Normal file
21
modules/git/repo_commitgraph.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// WriteCommitGraph write commit graph to speed up repo access
|
||||
// this requires git v2.18 to be installed
|
||||
func WriteCommitGraph(ctx context.Context, repoPath string) error {
|
||||
if CheckGitVersionAtLeast("2.18") == nil {
|
||||
if _, err := NewCommandContext(ctx, "commit-graph", "write").RunInDir(repoPath); err != nil {
|
||||
return fmt.Errorf("unable to write commit-graph for '%s' : %w", repoPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
@@ -34,69 +33,6 @@ func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error
|
||||
return err
|
||||
}
|
||||
|
||||
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
|
||||
t, ok := repo.tagCache.Get(tagID.String())
|
||||
if ok {
|
||||
log.Debug("Hit cache: %s", tagID)
|
||||
tagClone := *t.(*Tag)
|
||||
tagClone.Name = name // This is necessary because lightweight tags may have same id
|
||||
return &tagClone, nil
|
||||
}
|
||||
|
||||
tp, err := repo.GetTagType(tagID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
|
||||
commitIDStr, err := repo.GetTagCommitID(name)
|
||||
if err != nil {
|
||||
// every tag should have a commit ID so return all errors
|
||||
return nil, err
|
||||
}
|
||||
commitID, err := NewIDFromString(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If type is "commit, the tag is a lightweight tag
|
||||
if ObjectType(tp) == ObjectCommit {
|
||||
commit, err := repo.GetCommit(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tag := &Tag{
|
||||
Name: name,
|
||||
ID: tagID,
|
||||
Object: commitID,
|
||||
Type: tp,
|
||||
Tagger: commit.Committer,
|
||||
Message: commit.Message(),
|
||||
}
|
||||
|
||||
repo.tagCache.Set(tagID.String(), tag)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
// The tag is an annotated tag with a message.
|
||||
data, err := NewCommandContext(repo.Ctx, "cat-file", "-p", tagID.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag, err := parseTagData(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag.Name = name
|
||||
tag.ID = tagID
|
||||
tag.Type = tp
|
||||
|
||||
repo.tagCache.Set(tagID.String(), tag)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
// GetTagNameBySHA returns the name of a tag from its tag object SHA or commit SHA
|
||||
func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
|
||||
if len(sha) < 5 {
|
||||
@@ -159,6 +95,20 @@ func (repo *Repository) GetTag(name string) (*Tag, error) {
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
// GetTagWithID returns a Git tag by given name and ID
|
||||
func (repo *Repository) GetTagWithID(idStr, name string) (*Tag, error) {
|
||||
id, err := NewIDFromString(idStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag, err := repo.getTag(id, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
// GetTagInfos returns all tag infos of the repository.
|
||||
func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
|
||||
// TODO this a slow implementation, makes one git command per tag
|
||||
@@ -192,19 +142,6 @@ func (repo *Repository) GetTagInfos(page, pageSize int) ([]*Tag, int, error) {
|
||||
return tags, tagsTotal, nil
|
||||
}
|
||||
|
||||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
|
||||
func (repo *Repository) GetTagType(id SHA1) (string, error) {
|
||||
// Get tag type
|
||||
stdout, err := NewCommandContext(repo.Ctx, "cat-file", "-t", id.String()).RunInDir(repo.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(stdout) == 0 {
|
||||
return "", ErrNotExist{ID: id.String()}
|
||||
}
|
||||
return strings.TrimSpace(stdout), nil
|
||||
}
|
||||
|
||||
// GetAnnotatedTag returns a Git tag by its SHA, must be an annotated tag
|
||||
func (repo *Repository) GetAnnotatedTag(sha string) (*Tag, error) {
|
||||
id, err := NewIDFromString(sha)
|
||||
|
||||
@@ -11,6 +11,8 @@ package git
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
|
||||
"github.com/go-git/go-git/v5/plumbing"
|
||||
)
|
||||
|
||||
@@ -53,3 +55,83 @@ func (repo *Repository) GetTags(skip, limit int) ([]string, error) {
|
||||
|
||||
return tagNames, nil
|
||||
}
|
||||
|
||||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
|
||||
func (repo *Repository) GetTagType(id SHA1) (string, error) {
|
||||
// Get tag type
|
||||
obj, err := repo.gogitRepo.Object(plumbing.AnyObject, id)
|
||||
if err != nil {
|
||||
if err == plumbing.ErrReferenceNotFound {
|
||||
return "", &ErrNotExist{ID: id.String()}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
return obj.Type().String(), nil
|
||||
}
|
||||
|
||||
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
|
||||
t, ok := repo.tagCache.Get(tagID.String())
|
||||
if ok {
|
||||
log.Debug("Hit cache: %s", tagID)
|
||||
tagClone := *t.(*Tag)
|
||||
tagClone.Name = name // This is necessary because lightweight tags may have same id
|
||||
return &tagClone, nil
|
||||
}
|
||||
|
||||
tp, err := repo.GetTagType(tagID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
|
||||
commitIDStr, err := repo.GetTagCommitID(name)
|
||||
if err != nil {
|
||||
// every tag should have a commit ID so return all errors
|
||||
return nil, err
|
||||
}
|
||||
commitID, err := NewIDFromString(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If type is "commit, the tag is a lightweight tag
|
||||
if ObjectType(tp) == ObjectCommit {
|
||||
commit, err := repo.GetCommit(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tag := &Tag{
|
||||
Name: name,
|
||||
ID: tagID,
|
||||
Object: commitID,
|
||||
Type: tp,
|
||||
Tagger: commit.Committer,
|
||||
Message: commit.Message(),
|
||||
}
|
||||
|
||||
repo.tagCache.Set(tagID.String(), tag)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
gogitTag, err := repo.gogitRepo.TagObject(tagID)
|
||||
if err != nil {
|
||||
if err == plumbing.ErrReferenceNotFound {
|
||||
return nil, &ErrNotExist{ID: tagID.String()}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag := &Tag{
|
||||
Name: name,
|
||||
ID: tagID,
|
||||
Object: gogitTag.Target,
|
||||
Type: tp,
|
||||
Tagger: &gogitTag.Tagger,
|
||||
Message: gogitTag.Message,
|
||||
}
|
||||
|
||||
repo.tagCache.Set(tagID.String(), tag)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,13 @@
|
||||
|
||||
package git
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// IsTagExist returns true if given tag exists in the repository.
|
||||
func (repo *Repository) IsTagExist(name string) bool {
|
||||
if name == "" {
|
||||
@@ -23,3 +30,104 @@ func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
|
||||
tags, _, err = callShowRef(repo.Ctx, repo.Path, TagPrefix, "--tags", skip, limit)
|
||||
return
|
||||
}
|
||||
|
||||
// GetTagType gets the type of the tag, either commit (simple) or tag (annotated)
|
||||
func (repo *Repository) GetTagType(id SHA1) (string, error) {
|
||||
wr, rd, cancel := repo.CatFileBatchCheck(repo.Ctx)
|
||||
defer cancel()
|
||||
_, err := wr.Write([]byte(id.String() + "\n"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
_, typ, _, err := ReadBatchLine(rd)
|
||||
if IsErrNotExist(err) {
|
||||
return "", ErrNotExist{ID: id.String()}
|
||||
}
|
||||
return typ, nil
|
||||
}
|
||||
|
||||
func (repo *Repository) getTag(tagID SHA1, name string) (*Tag, error) {
|
||||
t, ok := repo.tagCache.Get(tagID.String())
|
||||
if ok {
|
||||
log.Debug("Hit cache: %s", tagID)
|
||||
tagClone := *t.(*Tag)
|
||||
tagClone.Name = name // This is necessary because lightweight tags may have same id
|
||||
return &tagClone, nil
|
||||
}
|
||||
|
||||
tp, err := repo.GetTagType(tagID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the commit ID and tag ID (may be different for annotated tag) for the returned tag object
|
||||
commitIDStr, err := repo.GetTagCommitID(name)
|
||||
if err != nil {
|
||||
// every tag should have a commit ID so return all errors
|
||||
return nil, err
|
||||
}
|
||||
commitID, err := NewIDFromString(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If type is "commit, the tag is a lightweight tag
|
||||
if ObjectType(tp) == ObjectCommit {
|
||||
commit, err := repo.GetCommit(commitIDStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tag := &Tag{
|
||||
Name: name,
|
||||
ID: tagID,
|
||||
Object: commitID,
|
||||
Type: tp,
|
||||
Tagger: commit.Committer,
|
||||
Message: commit.Message(),
|
||||
}
|
||||
|
||||
repo.tagCache.Set(tagID.String(), tag)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
// The tag is an annotated tag with a message.
|
||||
wr, rd, cancel := repo.CatFileBatch(repo.Ctx)
|
||||
defer cancel()
|
||||
|
||||
if _, err := wr.Write([]byte(tagID.String() + "\n")); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, typ, size, err := ReadBatchLine(rd)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) || IsErrNotExist(err) {
|
||||
return nil, ErrNotExist{ID: tagID.String()}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if typ != "tag" {
|
||||
return nil, ErrNotExist{ID: tagID.String()}
|
||||
}
|
||||
|
||||
// then we need to parse the tag
|
||||
// and load the commit
|
||||
data, err := io.ReadAll(io.LimitReader(rd, size))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = rd.Discard(1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag, err := parseTagData(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag.Name = name
|
||||
tag.ID = tagID
|
||||
tag.Type = tp
|
||||
|
||||
repo.tagCache.Set(tagID.String(), tag)
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// HostMatchList is used to check if a host or IP is in a list.
|
||||
@@ -102,11 +104,11 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool {
|
||||
for _, builtin := range hl.builtins {
|
||||
switch builtin {
|
||||
case MatchBuiltinExternal:
|
||||
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
|
||||
if ip.IsGlobalUnicast() && !util.IsIPPrivate(ip) {
|
||||
return true
|
||||
}
|
||||
case MatchBuiltinPrivate:
|
||||
if ip.IsPrivate() {
|
||||
if util.IsIPPrivate(ip) {
|
||||
return true
|
||||
}
|
||||
case MatchBuiltinLoopback:
|
||||
@@ -125,13 +127,18 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool {
|
||||
|
||||
// MatchHostName checks if the host matches an allow/deny(block) list
|
||||
func (hl *HostMatchList) MatchHostName(host string) bool {
|
||||
hostname, _, err := net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
hostname = host
|
||||
}
|
||||
|
||||
if hl == nil {
|
||||
return false
|
||||
}
|
||||
if hl.checkPattern(host) {
|
||||
if hl.checkPattern(hostname) {
|
||||
return true
|
||||
}
|
||||
if ip := net.ParseIP(host); ip != nil {
|
||||
if ip := net.ParseIP(hostname); ip != nil {
|
||||
return hl.checkIP(ip)
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -38,6 +38,7 @@ func TestHostOrIPMatchesList(t *testing.T) {
|
||||
|
||||
{"", net.ParseIP("10.0.1.1"), true},
|
||||
{"10.0.1.1", nil, true},
|
||||
{"10.0.1.1:8080", nil, true},
|
||||
{"", net.ParseIP("192.168.1.1"), true},
|
||||
{"192.168.1.1", nil, true},
|
||||
{"", net.ParseIP("fd00::1"), true},
|
||||
@@ -48,6 +49,7 @@ func TestHostOrIPMatchesList(t *testing.T) {
|
||||
|
||||
{"mydomain.com", net.IPv4zero, false},
|
||||
{"sub.mydomain.com", net.IPv4zero, true},
|
||||
{"sub.mydomain.com:8080", net.IPv4zero, true},
|
||||
|
||||
{"", net.ParseIP("169.254.1.1"), true},
|
||||
{"169.254.1.1", nil, true},
|
||||
|
||||
@@ -130,7 +130,7 @@ func Init() {
|
||||
log.Info("PID: %d Repository Indexer closed", os.Getpid())
|
||||
})
|
||||
|
||||
waitChannel := make(chan time.Duration)
|
||||
waitChannel := make(chan time.Duration, 1)
|
||||
|
||||
// Create the Queue
|
||||
switch setting.Indexer.RepoType {
|
||||
|
||||
@@ -98,7 +98,7 @@ var (
|
||||
// InitIssueIndexer initialize issue indexer, syncReindex is true then reindex until
|
||||
// all issue index done.
|
||||
func InitIssueIndexer(syncReindex bool) {
|
||||
waitChannel := make(chan time.Duration)
|
||||
waitChannel := make(chan time.Duration, 1)
|
||||
|
||||
// Create the Queue
|
||||
switch setting.Indexer.IssueType {
|
||||
@@ -272,7 +272,7 @@ func populateIssueIndexer(ctx context.Context) {
|
||||
// UpdateRepoIndexer add/update all issues of the repositories
|
||||
func UpdateRepoIndexer(repo *repo_model.Repository) {
|
||||
is, err := models.Issues(&models.IssuesOptions{
|
||||
RepoIDs: []int64{repo.ID},
|
||||
RepoID: repo.ID,
|
||||
IsClosed: util.OptionalBoolNone,
|
||||
IsPull: util.OptionalBoolNone,
|
||||
})
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/queue"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
_ "code.gitea.io/gitea/models"
|
||||
@@ -24,6 +27,10 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func TestRepoStatsIndex(t *testing.T) {
|
||||
if err := git.Init(context.Background()); !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
setting.Cfg = ini.Empty()
|
||||
|
||||
@@ -32,10 +39,14 @@ func TestRepoStatsIndex(t *testing.T) {
|
||||
err := Init()
|
||||
assert.NoError(t, err)
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
repo, err := repo_model.GetRepositoryByID(1)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = UpdateRepoIndexer(repo)
|
||||
assert.NoError(t, err)
|
||||
|
||||
queue.GetManager().FlushAll(context.Background(), 5*time.Second)
|
||||
|
||||
status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeStats)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.CommitSha)
|
||||
|
||||
@@ -197,6 +197,11 @@ func testAnswers(baseURLContent, baseURLImages string) []string {
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
`, `<ul>
|
||||
<li class="task-list-item"><input type="checkbox" disabled="" data-source-position="3"/> If you want to rebase/retry this PR, click this checkbox.</li>
|
||||
</ul>
|
||||
<hr/>
|
||||
<p>This PR has been generated by <a href="https://github.com/renovatebot/renovate" rel="nofollow">Renovate Bot</a>.</p>
|
||||
`,
|
||||
}
|
||||
}
|
||||
@@ -269,6 +274,14 @@ Here is a simple footnote,[^1] and here is a longer one.[^bignote]
|
||||
|
||||
Add as many paragraphs as you like.
|
||||
`,
|
||||
`
|
||||
- [ ] <!-- rebase-check --> If you want to rebase/retry this PR, click this checkbox.
|
||||
|
||||
---
|
||||
|
||||
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
|
||||
|
||||
<!-- test-comment -->`,
|
||||
}
|
||||
|
||||
func TestTotal_RenderWiki(t *testing.T) {
|
||||
|
||||
@@ -19,6 +19,10 @@ import (
|
||||
// they use to detect if there is a block and will grow and shrink in
|
||||
// response to demand as per configuration.
|
||||
type WorkerPool struct {
|
||||
// This field requires to be the first one in the struct.
|
||||
// This is to allow 64 bit atomic operations on 32-bit machines.
|
||||
// See: https://pkg.go.dev/sync/atomic#pkg-note-BUG & Gitea issue 19518
|
||||
numInQueue int64
|
||||
lock sync.Mutex
|
||||
baseCtx context.Context
|
||||
baseCtxCancel context.CancelFunc
|
||||
@@ -32,7 +36,6 @@ type WorkerPool struct {
|
||||
blockTimeout time.Duration
|
||||
boostTimeout time.Duration
|
||||
boostWorkers int
|
||||
numInQueue int64
|
||||
}
|
||||
|
||||
// WorkerPoolConfiguration is the basic configuration for a WorkerPool
|
||||
|
||||
@@ -80,6 +80,10 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
||||
return repo, fmt.Errorf("Clone: %v", err)
|
||||
}
|
||||
|
||||
if err := git.WriteCommitGraph(ctx, repoPath); err != nil {
|
||||
return repo, err
|
||||
}
|
||||
|
||||
if opts.Wiki {
|
||||
wikiPath := repo_model.WikiPath(u.Name, opts.RepoName)
|
||||
wikiRemotePath := WikiRemoteURL(opts.CloneAddr)
|
||||
@@ -88,7 +92,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
|
||||
}
|
||||
|
||||
if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
||||
if err := git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
@@ -99,6 +103,10 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
||||
if err := util.RemoveAll(wikiPath); err != nil {
|
||||
return repo, fmt.Errorf("Failed to remove %s: %v", wikiPath, err)
|
||||
}
|
||||
} else {
|
||||
if err := git.WriteCommitGraph(ctx, wikiPath); err != nil {
|
||||
return repo, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,23 +286,25 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||
}
|
||||
}
|
||||
}
|
||||
tags, err := gitRepo.GetTags(0, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to GetTags in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
for _, tagName := range tags {
|
||||
if _, ok := existingRelTags[strings.ToLower(tagName)]; !ok {
|
||||
if err := PushUpdateAddTag(repo, gitRepo, tagName); err != nil {
|
||||
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
|
||||
_, err := gitRepo.WalkReferences(git.ObjectTag, 0, 0, func(sha1, refname string) error {
|
||||
tagName := strings.TrimPrefix(refname, git.TagPrefix)
|
||||
if _, ok := existingRelTags[strings.ToLower(tagName)]; ok {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
if err := PushUpdateAddTag(repo, gitRepo, tagName, sha1, refname); err != nil {
|
||||
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// PushUpdateAddTag must be called for any push actions to add tag
|
||||
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName string) error {
|
||||
tag, err := gitRepo.GetTag(tagName)
|
||||
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName, sha1, refname string) error {
|
||||
tag, err := gitRepo.GetTagWithID(sha1, tagName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to GetTag: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ package setting
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"net/url"
|
||||
@@ -1010,7 +1009,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||
UI.ShowUserEmail = Cfg.Section("ui").Key("SHOW_USER_EMAIL").MustBool(true)
|
||||
UI.DefaultShowFullName = Cfg.Section("ui").Key("DEFAULT_SHOW_FULL_NAME").MustBool(false)
|
||||
UI.SearchRepoDescription = Cfg.Section("ui").Key("SEARCH_REPO_DESCRIPTION").MustBool(true)
|
||||
UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(true)
|
||||
UI.UseServiceWorker = Cfg.Section("ui").Key("USE_SERVICE_WORKER").MustBool(false)
|
||||
|
||||
HasRobotsTxt, err = util.IsFile(path.Join(CustomPath, "robots.txt"))
|
||||
if err != nil {
|
||||
@@ -1080,28 +1079,22 @@ func loadInternalToken(sec *ini.Section) string {
|
||||
}
|
||||
switch tempURI.Scheme {
|
||||
case "file":
|
||||
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0o600)
|
||||
if err != nil {
|
||||
buf, err := os.ReadFile(tempURI.RequestURI())
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
buf, err := io.ReadAll(fp)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to read InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
// No token in the file, generate one and store it.
|
||||
if len(buf) == 0 {
|
||||
token, err := generate.NewInternalToken()
|
||||
if err != nil {
|
||||
log.Fatal("Error generate internal token: %v", err)
|
||||
}
|
||||
if _, err := io.WriteString(fp, token); err != nil {
|
||||
err = os.WriteFile(tempURI.RequestURI(), []byte(token), 0o600)
|
||||
if err != nil {
|
||||
log.Fatal("Error writing to InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
return strings.TrimSpace(string(buf))
|
||||
default:
|
||||
log.Fatal("Unsupported URI-Scheme %q (INTERNAL_TOKEN_URI = %q)", tempURI.Scheme, uri)
|
||||
|
||||
@@ -19,6 +19,7 @@ type CreateUserOption struct {
|
||||
Password string `json:"password" binding:"Required;MaxSize(255)"`
|
||||
MustChangePassword *bool `json:"must_change_password"`
|
||||
SendNotify bool `json:"send_notify"`
|
||||
Restricted *bool `json:"restricted"`
|
||||
Visibility string `json:"visibility" binding:"In(,public,limited,private)"`
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +183,8 @@ type EditRepoOption struct {
|
||||
Archived *bool `json:"archived,omitempty"`
|
||||
// set to a string like `8h30m0s` to set the mirror interval time
|
||||
MirrorInterval *string `json:"mirror_interval,omitempty"`
|
||||
// enable prune - remove obsolete remote-tracking references
|
||||
EnablePrune *bool `json:"enable_prune,omitempty"`
|
||||
}
|
||||
|
||||
// GenerateRepoOption options when creating repository using a template
|
||||
|
||||
19
modules/util/net.go
Normal file
19
modules/util/net.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// IsIPPrivate for net.IP.IsPrivate.
|
||||
func IsIPPrivate(ip net.IP) bool {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return ip4[0] == 10 ||
|
||||
(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
|
||||
(ip4[0] == 192 && ip4[1] == 168)
|
||||
}
|
||||
return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc
|
||||
}
|
||||
@@ -1435,7 +1435,7 @@ pulls.manually_merged=Слито вручную
|
||||
pulls.manually_merged_as=Запрос на слияние был объединён вручную, как <a rel="nofollow" class="ui sha" href="%[1]s"><code>%[2]s</code></a>.
|
||||
pulls.is_closed=Запрос на слияние был закрыт.
|
||||
pulls.has_merged=Слияние этого запроса успешно завершено.
|
||||
pulls.title_wip_desc=`<a href="#">Добавьте <strong>%s</strong> в начало заголовка</a> для защиты от случайного досрочного принятия запроса на слияние
|
||||
pulls.title_wip_desc=`<a href="#">Добавьте <strong>%s</strong> в начало заголовка</a> для защиты от случайного досрочного принятия запроса на слияние`
|
||||
pulls.cannot_merge_work_in_progress=Этот запрос на слияние помечен как в процессе работы.
|
||||
pulls.still_in_progress=Всё ещё в процессе?
|
||||
pulls.add_prefix=Добавить <strong>%s</strong> префикс
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/password"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
@@ -81,7 +82,6 @@ func CreateUser(ctx *context.APIContext) {
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
MustChangePassword: true,
|
||||
IsActive: true,
|
||||
LoginType: auth.Plain,
|
||||
}
|
||||
if form.MustChangePassword != nil {
|
||||
@@ -107,11 +107,17 @@ func CreateUser(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
var overwriteDefault *user_model.CreateUserOverwriteOptions
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
if form.Restricted != nil {
|
||||
overwriteDefault.IsRestricted = util.OptionalBoolOf(*form.Restricted)
|
||||
}
|
||||
|
||||
if form.Visibility != "" {
|
||||
overwriteDefault = &user_model.CreateUserOverwriteOptions{
|
||||
Visibility: api.VisibilityModes[form.Visibility],
|
||||
}
|
||||
visibility := api.VisibilityModes[form.Visibility]
|
||||
overwriteDefault.Visibility = &visibility
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
|
||||
|
||||
@@ -177,23 +177,18 @@ func CreateBranch(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
err := repo_service.CreateNewBranch(ctx.User, ctx.Repo.Repository, opt.OldBranchName, opt.BranchName)
|
||||
|
||||
if err != nil {
|
||||
if models.IsErrBranchDoesNotExist(err) {
|
||||
ctx.Error(http.StatusNotFound, "", "The old branch does not exist")
|
||||
}
|
||||
if models.IsErrTagAlreadyExists(err) {
|
||||
ctx.Error(http.StatusConflict, "", "The branch with the same tag already exists.")
|
||||
|
||||
} else if models.IsErrBranchAlreadyExists(err) || git.IsErrPushOutOfDate(err) {
|
||||
ctx.Error(http.StatusConflict, "", "The branch already exists.")
|
||||
|
||||
} else if models.IsErrBranchNameConflict(err) {
|
||||
ctx.Error(http.StatusConflict, "", "The branch with the same name already exists.")
|
||||
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "CreateRepoBranch", err)
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -263,10 +258,15 @@ func ListBranches(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
apiBranches := make([]*api.Branch, len(branches))
|
||||
apiBranches := make([]*api.Branch, 0, len(branches))
|
||||
for i := range branches {
|
||||
c, err := branches[i].GetCommit()
|
||||
if err != nil {
|
||||
// Skip if this branch doesn't exist anymore.
|
||||
if git.IsErrNotExist(err) {
|
||||
totalNumOfBranches--
|
||||
continue
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "GetCommit", err)
|
||||
return
|
||||
}
|
||||
@@ -275,11 +275,12 @@ func ListBranches(ctx *context.APIContext) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err)
|
||||
return
|
||||
}
|
||||
apiBranches[i], err = convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin())
|
||||
apiBranch, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.User, ctx.Repo.IsAdmin())
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err)
|
||||
return
|
||||
}
|
||||
apiBranches = append(apiBranches, apiBranch)
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(totalNumOfBranches, listOptions.PageSize)
|
||||
@@ -532,7 +533,6 @@ func CreateBranchProtection(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusCreated, convert.ToBranchProtection(bp))
|
||||
|
||||
}
|
||||
|
||||
// EditBranchProtection edits a branch protection for a repo
|
||||
|
||||
@@ -173,6 +173,7 @@ func SearchIssues(ctx *context.APIContext) {
|
||||
opts.TeamID = team.ID
|
||||
}
|
||||
|
||||
repoCond := models.SearchRepositoryCondition(opts)
|
||||
repoIDs, _, err := models.SearchRepositoryIDs(opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err)
|
||||
@@ -233,7 +234,7 @@ func SearchIssues(ctx *context.APIContext) {
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: limit,
|
||||
},
|
||||
RepoIDs: repoIDs,
|
||||
RepoCond: repoCond,
|
||||
IsClosed: isClosed,
|
||||
IssueIDs: issueIDs,
|
||||
IncludedLabelNames: includedLabelNames,
|
||||
@@ -460,7 +461,7 @@ func ListIssues(ctx *context.APIContext) {
|
||||
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
|
||||
issuesOpt := &models.IssuesOptions{
|
||||
ListOptions: listOptions,
|
||||
RepoIDs: []int64{ctx.Repo.Repository.ID},
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
IsClosed: isClosed,
|
||||
IssueIDs: issueIDs,
|
||||
LabelIDs: labelIDs,
|
||||
|
||||
@@ -95,7 +95,6 @@ func ListPullRequests(ctx *context.APIContext) {
|
||||
Labels: ctx.FormStrings("labels"),
|
||||
MilestoneID: ctx.FormInt64("milestone"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "PullRequests", err)
|
||||
return
|
||||
@@ -724,13 +723,12 @@ func MergePullRequest(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = pr.LoadHeadRepo(); err != nil {
|
||||
if err := pr.LoadHeadRepo(); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadHeadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = pr.LoadIssue()
|
||||
if err != nil {
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadIssue", err)
|
||||
return
|
||||
}
|
||||
@@ -744,29 +742,33 @@ func MergePullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
}
|
||||
|
||||
if pr.Issue.IsClosed {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged
|
||||
force := form.ForceMerge != nil && *form.ForceMerge
|
||||
|
||||
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "IsUSerAllowedToMerge", err)
|
||||
return
|
||||
}
|
||||
if !allowedMerge {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
|
||||
return
|
||||
}
|
||||
|
||||
if pr.HasMerged {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
|
||||
if err := pull_service.CheckPullMergable(ctx, ctx.User, &ctx.Repo.Permission, pr, manuallMerge, force); err != nil {
|
||||
if errors.Is(err, pull_service.ErrIsClosed) {
|
||||
ctx.NotFound()
|
||||
} else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
|
||||
} else if errors.Is(err, pull_service.ErrHasMerged) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR already merged", "")
|
||||
} else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
|
||||
} else if errors.Is(err, pull_service.ErrNotMergableState) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
|
||||
} else if models.IsErrNotAllowedToMerge(err) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
|
||||
} else if asymkey_service.IsErrWontSign(err) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
|
||||
} else {
|
||||
ctx.InternalServerError(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// handle manually-merged mark
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged {
|
||||
if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
|
||||
if manuallMerge {
|
||||
if err := pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
|
||||
if models.IsErrInvalidMergeStyle(err) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
|
||||
return
|
||||
@@ -782,63 +784,13 @@ func MergePullRequest(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if !pr.CanAutoMerge() {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR not in mergeable state", "Please try again later")
|
||||
// set defaults to propagate needed fields
|
||||
if err := form.SetDefaults(pr); err != nil {
|
||||
ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if pr.IsWorkInProgress() {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR is a work in progress", "Work in progress PRs cannot be merged")
|
||||
return
|
||||
}
|
||||
|
||||
if err := pull_service.CheckPRReadyToMerge(pr, false); err != nil {
|
||||
if !models.IsErrNotAllowedToMerge(err) {
|
||||
ctx.Error(http.StatusInternalServerError, "CheckPRReadyToMerge", err)
|
||||
return
|
||||
}
|
||||
if form.ForceMerge != nil && *form.ForceMerge {
|
||||
if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "IsUserRepoAdmin", err)
|
||||
return
|
||||
} else if !isRepoAdmin {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "Merge", "Only repository admin can merge if not all checks are ok (force merge)")
|
||||
}
|
||||
} else {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := pull_service.IsSignedIfRequired(pr, ctx.User); err != nil {
|
||||
if !asymkey_service.IsErrWontSign(err) {
|
||||
ctx.Error(http.StatusInternalServerError, "IsSignedIfRequired", err)
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusMethodNotAllowed, fmt.Sprintf("Protected branch %s requires signed commits but this merge would not be signed", pr.BaseBranch), err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Do) == 0 {
|
||||
form.Do = string(repo_model.MergeStyleMerge)
|
||||
}
|
||||
|
||||
message := strings.TrimSpace(form.MergeTitleField)
|
||||
if len(message) == 0 {
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge {
|
||||
message = pr.GetDefaultMergeMessage()
|
||||
}
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash {
|
||||
message = pr.GetDefaultSquashMessage()
|
||||
}
|
||||
}
|
||||
|
||||
form.MergeMessageField = strings.TrimSpace(form.MergeMessageField)
|
||||
if len(form.MergeMessageField) > 0 {
|
||||
message += "\n\n" + form.MergeMessageField
|
||||
}
|
||||
|
||||
if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
|
||||
if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil {
|
||||
if models.IsErrInvalidMergeStyle(err) {
|
||||
ctx.Error(http.StatusMethodNotAllowed, "Invalid merge style", fmt.Errorf("%s is not allowed an allowed merge style for this repository", repo_model.MergeStyle(form.Do)))
|
||||
return
|
||||
|
||||
@@ -160,7 +160,7 @@ func Search(ctx *context.APIContext) {
|
||||
opts.Collaborate = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
var mode = ctx.FormString("mode")
|
||||
mode := ctx.FormString("mode")
|
||||
switch mode {
|
||||
case "source":
|
||||
opts.Fork = util.OptionalBoolFalse
|
||||
@@ -186,9 +186,9 @@ func Search(ctx *context.APIContext) {
|
||||
opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private"))
|
||||
}
|
||||
|
||||
var sortMode = ctx.FormString("sort")
|
||||
sortMode := ctx.FormString("sort")
|
||||
if len(sortMode) > 0 {
|
||||
var sortOrder = ctx.FormString("order")
|
||||
sortOrder := ctx.FormString("order")
|
||||
if len(sortOrder) == 0 {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
@@ -264,7 +264,8 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
||||
if repo_model.IsErrRepoAlreadyExist(err) {
|
||||
ctx.Error(http.StatusConflict, "", "The repository with the same name already exists.")
|
||||
} else if db.IsErrNameReserved(err) ||
|
||||
db.IsErrNamePatternNotAllowed(err) {
|
||||
db.IsErrNamePatternNotAllowed(err) ||
|
||||
models.IsErrIssueLabelTemplateLoad(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "CreateRepository", err)
|
||||
@@ -624,7 +625,7 @@ func Edit(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if opts.MirrorInterval != nil {
|
||||
if err := updateMirrorInterval(ctx, opts); err != nil {
|
||||
if err := updateMirror(ctx, opts); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -949,37 +950,67 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateMirrorInterval updates the repo's mirror Interval
|
||||
func updateMirrorInterval(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
// updateMirror updates a repo's mirror Interval and EnablePrune
|
||||
func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
// only update mirror if interval or enable prune are provided
|
||||
if opts.MirrorInterval == nil && opts.EnablePrune == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// these values only make sense if the repo is a mirror
|
||||
if !repo.IsMirror {
|
||||
err := fmt.Errorf("repo is not a mirror, can not change mirror interval")
|
||||
ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
// get the mirror from the repo
|
||||
mirror, err := repo_model.GetMirrorByRepoID(repo.ID)
|
||||
if err != nil {
|
||||
log.Error("Failed to get mirror: %s", err)
|
||||
ctx.Error(http.StatusInternalServerError, "MirrorInterval", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// update MirrorInterval
|
||||
if opts.MirrorInterval != nil {
|
||||
if !repo.IsMirror {
|
||||
err := fmt.Errorf("repo is not a mirror, can not change mirror interval")
|
||||
ctx.Error(http.StatusUnprocessableEntity, err.Error(), err)
|
||||
return err
|
||||
}
|
||||
mirror, err := repo_model.GetMirrorByRepoID(repo.ID)
|
||||
|
||||
// MirrorInterval should be a duration
|
||||
interval, err := time.ParseDuration(*opts.MirrorInterval)
|
||||
if err != nil {
|
||||
log.Error("Failed to get mirror: %s", err)
|
||||
ctx.Error(http.StatusInternalServerError, "MirrorInterval", err)
|
||||
return err
|
||||
}
|
||||
if interval, err := time.ParseDuration(*opts.MirrorInterval); err == nil {
|
||||
mirror.Interval = interval
|
||||
mirror.Repo = repo
|
||||
if err := repo_model.UpdateMirror(mirror); err != nil {
|
||||
log.Error("Failed to Set Mirror Interval: %s", err)
|
||||
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
|
||||
return err
|
||||
}
|
||||
log.Trace("Repository %s/%s Mirror Interval was Updated to %s", ctx.Repo.Owner.Name, repo.Name, interval)
|
||||
} else {
|
||||
log.Error("Wrong format for MirrorInternal Sent: %s", err)
|
||||
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure the provided duration is not too short
|
||||
if interval != 0 && interval < setting.Mirror.MinInterval {
|
||||
err := fmt.Errorf("invalid mirror interval: %s is below minimum interval: %s", interval, setting.Mirror.MinInterval)
|
||||
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
|
||||
return err
|
||||
}
|
||||
|
||||
mirror.Interval = interval
|
||||
mirror.Repo = repo
|
||||
mirror.ScheduleNextUpdate()
|
||||
log.Trace("Repository %s Mirror[%d] Set Interval: %s NextUpdateUnix: %s", repo.FullName(), mirror.ID, interval, mirror.NextUpdateUnix)
|
||||
}
|
||||
|
||||
// update EnablePrune
|
||||
if opts.EnablePrune != nil {
|
||||
mirror.EnablePrune = *opts.EnablePrune
|
||||
log.Trace("Repository %s Mirror[%d] Set EnablePrune: %t", repo.FullName(), mirror.ID, mirror.EnablePrune)
|
||||
}
|
||||
|
||||
// finally update the mirror in the DB
|
||||
if err := repo_model.UpdateMirror(mirror); err != nil {
|
||||
log.Error("Failed to Set Mirror Interval: %s", err)
|
||||
ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -80,9 +80,16 @@ func AddEmail(ctx *context.APIContext) {
|
||||
if err := user_model.AddEmailAddresses(emails); err != nil {
|
||||
if user_model.IsErrEmailAlreadyUsed(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email)
|
||||
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) {
|
||||
errMsg := fmt.Sprintf("Email address %s invalid", err.(user_model.ErrEmailInvalid).Email)
|
||||
} else if user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) {
|
||||
email := ""
|
||||
if typedError, ok := err.(user_model.ErrEmailInvalid); ok {
|
||||
email = typedError.Email
|
||||
}
|
||||
if typedError, ok := err.(user_model.ErrEmailCharIsNotSupported); ok {
|
||||
email = typedError.Email
|
||||
}
|
||||
|
||||
errMsg := fmt.Sprintf("Email address %q invalid", email)
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", errMsg)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "AddEmailAddresses", err)
|
||||
|
||||
@@ -266,16 +266,21 @@ func DeletePublicKey(ctx *context.APIContext) {
|
||||
id := ctx.ParamsInt64(":id")
|
||||
externallyManaged, err := asymkey_model.PublicKeyIsExternallyManaged(id)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err)
|
||||
if asymkey_model.IsErrKeyNotExist(err) {
|
||||
ctx.NotFound()
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "PublicKeyIsExternallyManaged", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if externallyManaged {
|
||||
ctx.Error(http.StatusForbidden, "", "SSH Key is externally managed for this user")
|
||||
return
|
||||
}
|
||||
|
||||
if err := asymkey_service.DeletePublicKey(ctx.User, id); err != nil {
|
||||
if asymkey_model.IsErrKeyNotExist(err) {
|
||||
ctx.NotFound()
|
||||
} else if asymkey_model.IsErrKeyAccessDenied(err) {
|
||||
if asymkey_model.IsErrKeyAccessDenied(err) {
|
||||
ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "DeletePublicKey", err)
|
||||
|
||||
@@ -246,18 +246,29 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh
|
||||
w.ChooseEvents = true
|
||||
w.Create = util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true)
|
||||
w.Push = util.IsStringInSlice(string(webhook.HookEventPush), form.Events, true)
|
||||
w.PullRequest = util.IsStringInSlice(string(webhook.HookEventPullRequest), form.Events, true)
|
||||
w.Create = util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true)
|
||||
w.Delete = util.IsStringInSlice(string(webhook.HookEventDelete), form.Events, true)
|
||||
w.Fork = util.IsStringInSlice(string(webhook.HookEventFork), form.Events, true)
|
||||
w.Issues = util.IsStringInSlice(string(webhook.HookEventIssues), form.Events, true)
|
||||
w.IssueComment = util.IsStringInSlice(string(webhook.HookEventIssueComment), form.Events, true)
|
||||
w.Push = util.IsStringInSlice(string(webhook.HookEventPush), form.Events, true)
|
||||
w.PullRequest = util.IsStringInSlice(string(webhook.HookEventPullRequest), form.Events, true)
|
||||
w.Repository = util.IsStringInSlice(string(webhook.HookEventRepository), form.Events, true)
|
||||
w.Release = util.IsStringInSlice(string(webhook.HookEventRelease), form.Events, true)
|
||||
w.BranchFilter = form.BranchFilter
|
||||
|
||||
// Issues
|
||||
w.Issues = issuesHook(form.Events, "issues_only")
|
||||
w.IssueAssign = issuesHook(form.Events, string(webhook.HookEventIssueAssign))
|
||||
w.IssueLabel = issuesHook(form.Events, string(webhook.HookEventIssueLabel))
|
||||
w.IssueMilestone = issuesHook(form.Events, string(webhook.HookEventIssueMilestone))
|
||||
w.IssueComment = issuesHook(form.Events, string(webhook.HookEventIssueComment))
|
||||
|
||||
// Pull requests
|
||||
w.PullRequest = pullHook(form.Events, "pull_request_only")
|
||||
w.PullRequestAssign = pullHook(form.Events, string(webhook.HookEventPullRequestAssign))
|
||||
w.PullRequestLabel = pullHook(form.Events, string(webhook.HookEventPullRequestLabel))
|
||||
w.PullRequestMilestone = pullHook(form.Events, string(webhook.HookEventPullRequestMilestone))
|
||||
w.PullRequestComment = pullHook(form.Events, string(webhook.HookEventPullRequestComment))
|
||||
w.PullRequestReview = pullHook(form.Events, "pull_request_review")
|
||||
w.PullRequestSync = pullHook(form.Events, string(webhook.HookEventPullRequestSync))
|
||||
|
||||
if err := w.UpdateEvent(); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateEvent", err)
|
||||
return false
|
||||
|
||||
@@ -508,13 +508,17 @@ func SubmitInstall(ctx *context.Context) {
|
||||
// Create admin account
|
||||
if len(form.AdminName) > 0 {
|
||||
u := &user_model.User{
|
||||
Name: form.AdminName,
|
||||
Email: form.AdminEmail,
|
||||
Passwd: form.AdminPasswd,
|
||||
IsAdmin: true,
|
||||
IsActive: true,
|
||||
Name: form.AdminName,
|
||||
Email: form.AdminEmail,
|
||||
Passwd: form.AdminPasswd,
|
||||
IsAdmin: true,
|
||||
}
|
||||
if err = user_model.CreateUser(u); err != nil {
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsRestricted: util.OptionalBoolFalse,
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
if err = user_model.CreateUser(u, overwriteDefault); err != nil {
|
||||
if !user_model.IsErrUserAlreadyExist(err) {
|
||||
setting.InstallLock = false
|
||||
ctx.Data["Err_AdminName"] = true
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,7 +35,7 @@ func DefaultOrSystemWebhooks(ctx *context.Context) {
|
||||
|
||||
sys["Title"] = ctx.Tr("admin.systemhooks")
|
||||
sys["Description"] = ctx.Tr("admin.systemhooks.desc")
|
||||
sys["Webhooks"], err = webhook.GetSystemWebhooks()
|
||||
sys["Webhooks"], err = webhook.GetSystemWebhooks(util.OptionalBoolNone)
|
||||
sys["BaseLink"] = setting.AppSubURL + "/admin/hooks"
|
||||
sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks"
|
||||
if err != nil {
|
||||
|
||||
@@ -125,10 +125,14 @@ func NewUserPost(ctx *context.Context) {
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
IsActive: true,
|
||||
LoginType: auth.Plain,
|
||||
}
|
||||
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
Visibility: &form.Visibility,
|
||||
}
|
||||
|
||||
if len(form.LoginType) > 0 {
|
||||
fields := strings.Split(form.LoginType, "-")
|
||||
if len(fields) == 2 {
|
||||
@@ -163,7 +167,7 @@ func NewUserPost(ctx *context.Context) {
|
||||
u.MustChangePassword = form.MustChangePassword
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(u, &user_model.CreateUserOverwriteOptions{Visibility: form.Visibility}); err != nil {
|
||||
if err := user_model.CreateUser(u, overwriteDefault); err != nil {
|
||||
switch {
|
||||
case user_model.IsErrUserAlreadyExist(err):
|
||||
ctx.Data["Err_UserName"] = true
|
||||
|
||||
@@ -507,14 +507,12 @@ func SignUpPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
u := &user_model.User{
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
|
||||
IsRestricted: setting.Service.DefaultUserIsRestricted,
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
}
|
||||
|
||||
if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, false) {
|
||||
if !createAndHandleCreatedUser(ctx, tplSignUp, form, u, nil, nil, false) {
|
||||
// error already handled
|
||||
return
|
||||
}
|
||||
@@ -525,8 +523,8 @@ func SignUpPost(ctx *context.Context) {
|
||||
|
||||
// createAndHandleCreatedUser calls createUserInContext and
|
||||
// then handleUserCreated.
|
||||
func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) bool {
|
||||
if !createUserInContext(ctx, tpl, form, u, gothUser, allowLink) {
|
||||
func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) bool {
|
||||
if !createUserInContext(ctx, tpl, form, u, overwrites, gothUser, allowLink) {
|
||||
return false
|
||||
}
|
||||
return handleUserCreated(ctx, u, gothUser)
|
||||
@@ -534,8 +532,8 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form int
|
||||
|
||||
// createUserInContext creates a user and handles errors within a given context.
|
||||
// Optionally a template can be specified.
|
||||
func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, gothUser *goth.User, allowLink bool) (ok bool) {
|
||||
if err := user_model.CreateUser(u); err != nil {
|
||||
func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) {
|
||||
if err := user_model.CreateUser(u, overwrites); err != nil {
|
||||
if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
|
||||
if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
|
||||
var user *user_model.User
|
||||
|
||||
@@ -285,13 +285,12 @@ func LinkAccountPostRegister(ctx *context.Context) {
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: form.Password,
|
||||
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
|
||||
LoginType: auth.OAuth2,
|
||||
LoginSource: authSource.ID,
|
||||
LoginName: gothUser.UserID,
|
||||
}
|
||||
|
||||
if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, &gothUser, false) {
|
||||
if !createAndHandleCreatedUser(ctx, tplLinkAccount, form, u, nil, &gothUser, false) {
|
||||
// error already handled
|
||||
return
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/session"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
auth_service "code.gitea.io/gitea/services/auth"
|
||||
@@ -872,19 +873,21 @@ func SignInOAuthCallback(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
u = &user_model.User{
|
||||
Name: getUserName(&gothUser),
|
||||
FullName: gothUser.Name,
|
||||
Email: gothUser.Email,
|
||||
IsActive: !setting.OAuth2Client.RegisterEmailConfirm,
|
||||
LoginType: auth.OAuth2,
|
||||
LoginSource: authSource.ID,
|
||||
LoginName: gothUser.UserID,
|
||||
IsRestricted: setting.Service.DefaultUserIsRestricted,
|
||||
Name: getUserName(&gothUser),
|
||||
FullName: gothUser.Name,
|
||||
Email: gothUser.Email,
|
||||
LoginType: auth.OAuth2,
|
||||
LoginSource: authSource.ID,
|
||||
LoginName: gothUser.UserID,
|
||||
}
|
||||
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolOf(!setting.OAuth2Client.RegisterEmailConfirm),
|
||||
}
|
||||
|
||||
setUserGroupClaims(authSource, u, &gothUser)
|
||||
|
||||
if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
|
||||
if !createAndHandleCreatedUser(ctx, base.TplName(""), nil, u, overwriteDefault, &gothUser, setting.OAuth2Client.AccountLinking != setting.OAuth2AccountLinkingDisabled) {
|
||||
// error already handled
|
||||
return
|
||||
}
|
||||
|
||||
@@ -425,12 +425,11 @@ func RegisterOpenIDPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
u := &user_model.User{
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: password,
|
||||
IsActive: !(setting.Service.RegisterEmailConfirm || setting.Service.RegisterManualConfirm),
|
||||
Name: form.UserName,
|
||||
Email: form.Email,
|
||||
Passwd: password,
|
||||
}
|
||||
if !createUserInContext(ctx, tplSignUpOID, form, u, nil, false) {
|
||||
if !createUserInContext(ctx, tplSignUpOID, form, u, nil, nil, false) {
|
||||
// error already handled
|
||||
return
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti
|
||||
Page: pager.Paginater.Current(),
|
||||
PageSize: setting.UI.IssuePagingNum,
|
||||
},
|
||||
RepoIDs: []int64{repo.ID},
|
||||
RepoID: repo.ID,
|
||||
AssigneeID: assigneeID,
|
||||
PosterID: posterID,
|
||||
MentionedID: mentionedID,
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
@@ -48,16 +49,14 @@ const (
|
||||
pullRequestTemplateKey = "PullRequestTemplate"
|
||||
)
|
||||
|
||||
var (
|
||||
pullRequestTemplateCandidates = []string{
|
||||
"PULL_REQUEST_TEMPLATE.md",
|
||||
"pull_request_template.md",
|
||||
".gitea/PULL_REQUEST_TEMPLATE.md",
|
||||
".gitea/pull_request_template.md",
|
||||
".github/PULL_REQUEST_TEMPLATE.md",
|
||||
".github/pull_request_template.md",
|
||||
}
|
||||
)
|
||||
var pullRequestTemplateCandidates = []string{
|
||||
"PULL_REQUEST_TEMPLATE.md",
|
||||
"pull_request_template.md",
|
||||
".gitea/PULL_REQUEST_TEMPLATE.md",
|
||||
".gitea/pull_request_template.md",
|
||||
".github/PULL_REQUEST_TEMPLATE.md",
|
||||
".github/pull_request_template.md",
|
||||
}
|
||||
|
||||
func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository {
|
||||
repo, err := repo_model.GetRepositoryByID(repoID)
|
||||
@@ -125,7 +124,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository {
|
||||
}
|
||||
}
|
||||
|
||||
var traverseParentRepo = forkRepo
|
||||
traverseParentRepo := forkRepo
|
||||
for {
|
||||
if ctx.User.ID == traverseParentRepo.OwnerID {
|
||||
canForkToUser = false
|
||||
@@ -195,7 +194,7 @@ func ForkPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
var err error
|
||||
var traverseParentRepo = forkRepo
|
||||
traverseParentRepo := forkRepo
|
||||
for {
|
||||
if ctxUser.ID == traverseParentRepo.OwnerID {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form)
|
||||
@@ -853,39 +852,53 @@ func MergePullRequest(ctx *context.Context) {
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
if issue.IsClosed {
|
||||
if issue.IsPull {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
|
||||
pr := issue.PullRequest
|
||||
pr.Issue = issue
|
||||
pr.Issue.Repo = ctx.Repo.Repository
|
||||
manuallMerge := repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged
|
||||
forceMerge := form.ForceMerge != nil && *form.ForceMerge
|
||||
|
||||
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsUserAllowedToMerge", err)
|
||||
return
|
||||
}
|
||||
if !allowedMerge {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
if err := pull_service.CheckPullMergable(ctx, ctx.User, &ctx.Repo.Permission, pr, manuallMerge, forceMerge); err != nil {
|
||||
if errors.Is(err, pull_service.ErrIsClosed) {
|
||||
if issue.IsPull {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.is_closed"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.closed_title"))
|
||||
ctx.Redirect(issue.Link())
|
||||
}
|
||||
} else if errors.Is(err, pull_service.ErrUserNotAllowedToMerge) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.update_not_allowed"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else if errors.Is(err, pull_service.ErrHasMerged) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else if errors.Is(err, pull_service.ErrIsWorkInProgress) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else if errors.Is(err, pull_service.ErrNotMergableState) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else if models.IsErrNotAllowedToMerge(err) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else if asymkey_service.IsErrWontSign(err) {
|
||||
ctx.Flash.Error(err.Error()) // has not translation ...
|
||||
ctx.Redirect(issue.Link())
|
||||
} else if errors.Is(err, pull_service.ErrDependenciesLeft) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
|
||||
ctx.Redirect(issue.Link())
|
||||
} else {
|
||||
ctx.ServerError("WebCheck", err)
|
||||
}
|
||||
|
||||
if pr.HasMerged {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.has_merged"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
|
||||
// handle manually-merged mark
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleManuallyMerged {
|
||||
if err = pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
|
||||
if manuallMerge {
|
||||
if err := pull_service.MergedManually(pr, ctx.User, ctx.Repo.GitRepo, form.MergeCommitID); err != nil {
|
||||
if models.IsErrInvalidMergeStyle(err) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
|
||||
ctx.Redirect(issue.Link())
|
||||
@@ -904,72 +917,13 @@ func MergePullRequest(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !pr.CanAutoMerge() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
|
||||
ctx.Redirect(issue.Link())
|
||||
// set defaults to propagate needed fields
|
||||
if err := form.SetDefaults(pr); err != nil {
|
||||
ctx.ServerError("SetDefaults", fmt.Errorf("SetDefaults: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
if pr.IsWorkInProgress() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_wip"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
|
||||
if err := pull_service.CheckPRReadyToMerge(pr, false); err != nil {
|
||||
if !models.IsErrNotAllowedToMerge(err) {
|
||||
ctx.ServerError("Merge PR status", err)
|
||||
return
|
||||
}
|
||||
if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
|
||||
ctx.ServerError("IsUserRepoAdmin", err)
|
||||
return
|
||||
} else if !isRepoAdmin {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
|
||||
message := strings.TrimSpace(form.MergeTitleField)
|
||||
if len(message) == 0 {
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleMerge {
|
||||
message = pr.GetDefaultMergeMessage()
|
||||
}
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleRebaseMerge {
|
||||
message = pr.GetDefaultMergeMessage()
|
||||
}
|
||||
if repo_model.MergeStyle(form.Do) == repo_model.MergeStyleSquash {
|
||||
message = pr.GetDefaultSquashMessage()
|
||||
}
|
||||
}
|
||||
|
||||
form.MergeMessageField = strings.TrimSpace(form.MergeMessageField)
|
||||
if len(form.MergeMessageField) > 0 {
|
||||
message += "\n\n" + form.MergeMessageField
|
||||
}
|
||||
|
||||
pr.Issue = issue
|
||||
pr.Issue.Repo = ctx.Repo.Repository
|
||||
|
||||
noDeps, err := models.IssueNoDependenciesLeft(issue)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !noDeps {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.dependency.pr_close_blocked"))
|
||||
ctx.Redirect(issue.Link())
|
||||
return
|
||||
}
|
||||
|
||||
if err = pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, message); err != nil {
|
||||
if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, repo_model.MergeStyle(form.Do), form.HeadCommitID, form.MergeTitleField); err != nil {
|
||||
if models.IsErrInvalidMergeStyle(err) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
|
||||
ctx.Redirect(issue.Link())
|
||||
@@ -1079,7 +1033,6 @@ func MergePullRequest(ctx *context.Context) {
|
||||
}
|
||||
|
||||
func stopTimerIfAvailable(user *user_model.User, issue *models.Issue) error {
|
||||
|
||||
if models.StopwatchExists(user.ID, issue.ID) {
|
||||
if err := models.CreateOrStopIssueStopwatch(user, issue); err != nil {
|
||||
return err
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/typesniffer"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
@@ -194,11 +193,7 @@ func SettingsPost(ctx *context.Context) {
|
||||
} else {
|
||||
ctx.Repo.Mirror.EnablePrune = form.EnablePrune
|
||||
ctx.Repo.Mirror.Interval = interval
|
||||
if interval != 0 {
|
||||
ctx.Repo.Mirror.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(interval)
|
||||
} else {
|
||||
ctx.Repo.Mirror.NextUpdateUnix = 0
|
||||
}
|
||||
ctx.Repo.Mirror.ScheduleNextUpdate()
|
||||
if err := repo_model.UpdateMirror(ctx.Repo.Mirror); err != nil {
|
||||
ctx.Data["Err_Interval"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
|
||||
|
||||
@@ -191,7 +191,10 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
|
||||
ctx.Data["title"] = pageName
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
|
||||
//lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
isSideBar := pageName == "_Sidebar"
|
||||
isFooter := pageName == "_Footer"
|
||||
|
||||
// lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
|
||||
if noEntry {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
|
||||
@@ -203,23 +206,33 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sidebarContent, _, _, _ := wikiContentsByName(ctx, commit, "_Sidebar")
|
||||
if ctx.Written() {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
var sidebarContent []byte
|
||||
if !isSideBar {
|
||||
sidebarContent, _, _, _ = wikiContentsByName(ctx, commit, "_Sidebar")
|
||||
if ctx.Written() {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
return nil, nil
|
||||
} else {
|
||||
sidebarContent = data
|
||||
}
|
||||
|
||||
footerContent, _, _, _ := wikiContentsByName(ctx, commit, "_Footer")
|
||||
if ctx.Written() {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
var footerContent []byte
|
||||
if !isFooter {
|
||||
footerContent, _, _, _ = wikiContentsByName(ctx, commit, "_Footer")
|
||||
if ctx.Written() {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
return nil, nil
|
||||
} else {
|
||||
footerContent = data
|
||||
}
|
||||
|
||||
var rctx = &markup.RenderContext{
|
||||
rctx := &markup.RenderContext{
|
||||
URLPrefix: ctx.Repo.RepoLink,
|
||||
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
|
||||
IsWiki: true,
|
||||
@@ -236,27 +249,35 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
|
||||
|
||||
ctx.Data["EscapeStatus"], ctx.Data["content"] = charset.EscapeControlString(buf.String())
|
||||
|
||||
buf.Reset()
|
||||
if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
if !isSideBar {
|
||||
buf.Reset()
|
||||
if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
}
|
||||
ctx.ServerError("Render", err)
|
||||
return nil, nil
|
||||
}
|
||||
ctx.ServerError("Render", err)
|
||||
return nil, nil
|
||||
ctx.Data["sidebarPresent"] = sidebarContent != nil
|
||||
ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String())
|
||||
} else {
|
||||
ctx.Data["sidebarPresent"] = false
|
||||
}
|
||||
ctx.Data["sidebarPresent"] = sidebarContent != nil
|
||||
ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String())
|
||||
|
||||
buf.Reset()
|
||||
if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
if !isFooter {
|
||||
buf.Reset()
|
||||
if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil {
|
||||
if wikiRepo != nil {
|
||||
wikiRepo.Close()
|
||||
}
|
||||
ctx.ServerError("Render", err)
|
||||
return nil, nil
|
||||
}
|
||||
ctx.ServerError("Render", err)
|
||||
return nil, nil
|
||||
ctx.Data["footerPresent"] = footerContent != nil
|
||||
ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String())
|
||||
} else {
|
||||
ctx.Data["footerPresent"] = false
|
||||
}
|
||||
ctx.Data["footerPresent"] = footerContent != nil
|
||||
ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String())
|
||||
|
||||
// get commit count - wiki revisions
|
||||
commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename)
|
||||
@@ -290,7 +311,7 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
|
||||
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
||||
ctx.Data["Reponame"] = ctx.Repo.Repository.Name
|
||||
|
||||
//lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
// lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
data, entry, pageFilename, noEntry := wikiContentsByName(ctx, commit, pageName)
|
||||
if noEntry {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
|
||||
@@ -364,7 +385,7 @@ func renderEditPage(ctx *context.Context) {
|
||||
ctx.Data["title"] = pageName
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
|
||||
//lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
// lookup filename in wiki - get filecontent, gitTree entry , real filename
|
||||
data, entry, _, noEntry := wikiContentsByName(ctx, commit, pageName)
|
||||
if noEntry {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/?action=_pages")
|
||||
|
||||
@@ -462,13 +462,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
// to check if it's in the team(which possible isn't the case).
|
||||
opts.User = nil
|
||||
}
|
||||
userRepoIDs, _, err := models.SearchRepositoryIDs(repoOpts)
|
||||
if err != nil {
|
||||
ctx.ServerError("models.SearchRepositoryIDs: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
opts.RepoIDs = userRepoIDs
|
||||
opts.RepoCond = models.SearchRepositoryCondition(repoOpts)
|
||||
}
|
||||
|
||||
// keyword holds the search term entered into the search field.
|
||||
@@ -532,7 +526,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
// Gets set when clicking filters on the issues overview page.
|
||||
repoIDs := getRepoIDs(ctx.FormString("repos"))
|
||||
if len(repoIDs) > 0 {
|
||||
opts.RepoIDs = repoIDs
|
||||
opts.RepoCond = builder.In("issue.repo_id", repoIDs)
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
@@ -374,8 +374,8 @@ func RegisterRoutes(m *web.Route) {
|
||||
|
||||
m.Group("/user", func() {
|
||||
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
||||
m.Get("/activate", auth.Activate, reqSignIn)
|
||||
m.Post("/activate", auth.ActivatePost, reqSignIn)
|
||||
m.Get("/activate", auth.Activate)
|
||||
m.Post("/activate", auth.ActivatePost)
|
||||
m.Any("/activate_email", auth.ActivateEmail)
|
||||
m.Get("/avatar/{username}/{size}", user.AvatarByUserName)
|
||||
m.Get("/recover_account", auth.ResetPasswd)
|
||||
@@ -383,7 +383,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Get("/forgot_password", auth.ForgotPasswd)
|
||||
m.Post("/forgot_password", auth.ForgotPasswdPost)
|
||||
m.Post("/logout", auth.SignOut)
|
||||
m.Get("/task/{task}", user.TaskStatus)
|
||||
m.Get("/task/{task}", reqSignIn, user.TaskStatus)
|
||||
})
|
||||
// ***** END: User *****
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
@@ -106,11 +107,15 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User {
|
||||
}
|
||||
|
||||
user := &user_model.User{
|
||||
Name: username,
|
||||
Email: email,
|
||||
IsActive: true,
|
||||
Name: username,
|
||||
Email: email,
|
||||
}
|
||||
if err := user_model.CreateUser(user); err != nil {
|
||||
|
||||
overwriteDefault := user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(user, &overwriteDefault); err != nil {
|
||||
// FIXME: should I create a system notice?
|
||||
log.Error("CreateUser: %v", err)
|
||||
return nil
|
||||
|
||||
@@ -23,19 +23,23 @@ import (
|
||||
// UserSignIn validates user name and password.
|
||||
func UserSignIn(username, password string) (*user_model.User, *auth.Source, error) {
|
||||
var user *user_model.User
|
||||
isEmail := false
|
||||
if strings.Contains(username, "@") {
|
||||
isEmail = true
|
||||
emailAddress := user_model.EmailAddress{LowerEmail: strings.ToLower(strings.TrimSpace(username))}
|
||||
// check same email
|
||||
has, err := db.GetEngine(db.DefaultContext).Where("is_activated=?", true).Get(&emailAddress)
|
||||
has, err := db.GetEngine(db.DefaultContext).Get(&emailAddress)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !has {
|
||||
return nil, nil, user_model.ErrEmailAddressNotExist{
|
||||
Email: username,
|
||||
if has {
|
||||
if !emailAddress.IsActivated {
|
||||
return nil, nil, user_model.ErrEmailAddressNotExist{
|
||||
Email: username,
|
||||
}
|
||||
}
|
||||
user = &user_model.User{ID: emailAddress.UID}
|
||||
}
|
||||
user = &user_model.User{ID: emailAddress.UID}
|
||||
} else {
|
||||
trimmedUsername := strings.TrimSpace(username)
|
||||
if len(trimmedUsername) == 0 {
|
||||
@@ -45,38 +49,40 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro
|
||||
user = &user_model.User{LowerName: strings.ToLower(trimmedUsername)}
|
||||
}
|
||||
|
||||
hasUser, err := user_model.GetUser(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if hasUser {
|
||||
source, err := auth.GetSourceByID(user.LoginSource)
|
||||
if user != nil {
|
||||
hasUser, err := user_model.GetUser(user)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !source.IsActive {
|
||||
return nil, nil, oauth2.ErrAuthSourceNotActived
|
||||
}
|
||||
if hasUser {
|
||||
source, err := auth.GetSourceByID(user.LoginSource)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
authenticator, ok := source.Cfg.(PasswordAuthenticator)
|
||||
if !ok {
|
||||
return nil, nil, smtp.ErrUnsupportedLoginType
|
||||
}
|
||||
if !source.IsActive {
|
||||
return nil, nil, oauth2.ErrAuthSourceNotActived
|
||||
}
|
||||
|
||||
user, err := authenticator.Authenticate(user, user.LoginName, password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
authenticator, ok := source.Cfg.(PasswordAuthenticator)
|
||||
if !ok {
|
||||
return nil, nil, smtp.ErrUnsupportedLoginType
|
||||
}
|
||||
|
||||
// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
|
||||
// user could be hint to resend confirm email.
|
||||
if user.ProhibitLogin {
|
||||
return nil, nil, user_model.ErrUserProhibitLogin{UID: user.ID, Name: user.Name}
|
||||
}
|
||||
user, err := authenticator.Authenticate(user, user.LoginName, password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return user, source, nil
|
||||
// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
|
||||
// user could be hint to resend confirm email.
|
||||
if user.ProhibitLogin {
|
||||
return nil, nil, user_model.ErrUserProhibitLogin{UID: user.ID, Name: user.Name}
|
||||
}
|
||||
|
||||
return user, source, nil
|
||||
}
|
||||
}
|
||||
|
||||
sources, err := auth.AllActiveSources()
|
||||
@@ -111,5 +117,9 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro
|
||||
}
|
||||
}
|
||||
|
||||
if isEmail {
|
||||
return nil, nil, user_model.ErrEmailAddressNotExist{Email: username}
|
||||
}
|
||||
|
||||
return nil, nil, user_model.ErrUserNotExist{Name: username}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
user_service "code.gitea.io/gitea/services/user"
|
||||
)
|
||||
@@ -80,19 +81,21 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
|
||||
}
|
||||
|
||||
user = &user_model.User{
|
||||
LowerName: strings.ToLower(sr.Username),
|
||||
Name: sr.Username,
|
||||
FullName: composeFullName(sr.Name, sr.Surname, sr.Username),
|
||||
Email: sr.Mail,
|
||||
LoginType: source.authSource.Type,
|
||||
LoginSource: source.authSource.ID,
|
||||
LoginName: userName,
|
||||
IsActive: true,
|
||||
IsAdmin: sr.IsAdmin,
|
||||
IsRestricted: sr.IsRestricted,
|
||||
LowerName: strings.ToLower(sr.Username),
|
||||
Name: sr.Username,
|
||||
FullName: composeFullName(sr.Name, sr.Surname, sr.Username),
|
||||
Email: sr.Mail,
|
||||
LoginType: source.authSource.Type,
|
||||
LoginSource: source.authSource.ID,
|
||||
LoginName: userName,
|
||||
IsAdmin: sr.IsAdmin,
|
||||
}
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsRestricted: util.OptionalBoolOf(sr.IsRestricted),
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
err := user_model.CreateUser(user)
|
||||
err := user_model.CreateUser(user, overwriteDefault)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
user_service "code.gitea.io/gitea/services/user"
|
||||
)
|
||||
|
||||
@@ -99,19 +100,21 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error {
|
||||
log.Trace("SyncExternalUsers[%s]: Creating user %s", source.authSource.Name, su.Username)
|
||||
|
||||
usr = &user_model.User{
|
||||
LowerName: su.LowerName,
|
||||
Name: su.Username,
|
||||
FullName: fullName,
|
||||
LoginType: source.authSource.Type,
|
||||
LoginSource: source.authSource.ID,
|
||||
LoginName: su.Username,
|
||||
Email: su.Mail,
|
||||
IsAdmin: su.IsAdmin,
|
||||
IsRestricted: su.IsRestricted,
|
||||
IsActive: true,
|
||||
LowerName: su.LowerName,
|
||||
Name: su.Username,
|
||||
FullName: fullName,
|
||||
LoginType: source.authSource.Type,
|
||||
LoginSource: source.authSource.ID,
|
||||
LoginName: su.Username,
|
||||
Email: su.Mail,
|
||||
IsAdmin: su.IsAdmin,
|
||||
}
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsRestricted: util.OptionalBoolOf(su.IsRestricted),
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
err = user_model.CreateUser(usr)
|
||||
err = user_model.CreateUser(usr, overwriteDefault)
|
||||
|
||||
if err != nil {
|
||||
log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/auth/pam"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"github.com/google/uuid"
|
||||
@@ -58,10 +59,12 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
|
||||
LoginType: auth.PAM,
|
||||
LoginSource: source.authSource.ID,
|
||||
LoginName: userName, // This is what the user typed in
|
||||
IsActive: true,
|
||||
}
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(user); err != nil {
|
||||
if err := user_model.CreateUser(user, overwriteDefault); err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
|
||||
@@ -74,10 +74,12 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str
|
||||
LoginType: auth_model.SMTP,
|
||||
LoginSource: source.authSource.ID,
|
||||
LoginName: userName,
|
||||
IsActive: true,
|
||||
}
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolTrue,
|
||||
}
|
||||
|
||||
if err := user_model.CreateUser(user); err != nil {
|
||||
if err := user_model.CreateUser(user, overwriteDefault); err != nil {
|
||||
return user, err
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
"code.gitea.io/gitea/services/auth/source/sspi"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
@@ -187,17 +188,20 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) {
|
||||
func (s *SSPI) newUser(username string, cfg *sspi.Source) (*user_model.User, error) {
|
||||
email := gouuid.New().String() + "@localhost.localdomain"
|
||||
user := &user_model.User{
|
||||
Name: username,
|
||||
Email: email,
|
||||
KeepEmailPrivate: true,
|
||||
Passwd: gouuid.New().String(),
|
||||
IsActive: cfg.AutoActivateUsers,
|
||||
Language: cfg.DefaultLanguage,
|
||||
UseCustomAvatar: true,
|
||||
Avatar: avatars.DefaultAvatarLink(),
|
||||
EmailNotificationsPreference: user_model.EmailNotificationsDisabled,
|
||||
Name: username,
|
||||
Email: email,
|
||||
Passwd: gouuid.New().String(),
|
||||
Language: cfg.DefaultLanguage,
|
||||
UseCustomAvatar: true,
|
||||
Avatar: avatars.DefaultAvatarLink(),
|
||||
}
|
||||
if err := user_model.CreateUser(user); err != nil {
|
||||
emailNotificationPreference := user_model.EmailNotificationsDisabled
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
IsActive: util.OptionalBoolOf(cfg.AutoActivateUsers),
|
||||
KeepEmailPrivate: util.OptionalBoolTrue,
|
||||
EmailNotificationsPreference: &emailNotificationPreference,
|
||||
}
|
||||
if err := user_model.CreateUser(user, overwriteDefault); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -582,6 +582,31 @@ func (f *MergePullRequestForm) Validate(req *http.Request, errs binding.Errors)
|
||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
// SetDefaults if not provided for mergestyle and commit message
|
||||
func (f *MergePullRequestForm) SetDefaults(pr *models.PullRequest) (err error) {
|
||||
if f.Do == "" {
|
||||
f.Do = "merge"
|
||||
}
|
||||
|
||||
f.MergeTitleField = strings.TrimSpace(f.MergeTitleField)
|
||||
if len(f.MergeTitleField) == 0 {
|
||||
switch f.Do {
|
||||
case "merge", "rebase-merge":
|
||||
f.MergeTitleField, err = pr.GetDefaultMergeMessage()
|
||||
case "squash":
|
||||
f.MergeTitleField, err = pr.GetDefaultSquashMessage()
|
||||
}
|
||||
}
|
||||
|
||||
f.MergeMessageField = strings.TrimSpace(f.MergeMessageField)
|
||||
if len(f.MergeMessageField) > 0 {
|
||||
f.MergeTitleField += "\n\n" + f.MergeMessageField
|
||||
f.MergeMessageField = ""
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CodeCommentForm form for adding code comments for PRs
|
||||
type CodeCommentForm struct {
|
||||
Origin string `binding:"Required;In(timeline,diff)"`
|
||||
|
||||
@@ -7,6 +7,7 @@ package migrations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -33,9 +34,7 @@ import (
|
||||
gouuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
var (
|
||||
_ base.Uploader = &GiteaLocalUploader{}
|
||||
)
|
||||
var _ base.Uploader = &GiteaLocalUploader{}
|
||||
|
||||
// GiteaLocalUploader implements an Uploader to gitea sites
|
||||
type GiteaLocalUploader struct {
|
||||
@@ -159,7 +158,7 @@ func (g *GiteaLocalUploader) CreateTopics(topics ...string) error {
|
||||
|
||||
// CreateMilestones creates milestones
|
||||
func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) error {
|
||||
var mss = make([]*models.Milestone, 0, len(milestones))
|
||||
mss := make([]*models.Milestone, 0, len(milestones))
|
||||
for _, milestone := range milestones {
|
||||
var deadline timeutil.TimeStamp
|
||||
if milestone.Deadline != nil {
|
||||
@@ -182,7 +181,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
|
||||
milestone.Updated = &milestone.Created
|
||||
}
|
||||
|
||||
var ms = models.Milestone{
|
||||
ms := models.Milestone{
|
||||
RepoID: g.repo.ID,
|
||||
Name: milestone.Title,
|
||||
Content: milestone.Description,
|
||||
@@ -210,7 +209,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
|
||||
|
||||
// CreateLabels creates labels
|
||||
func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error {
|
||||
var lbs = make([]*models.Label, 0, len(labels))
|
||||
lbs := make([]*models.Label, 0, len(labels))
|
||||
for _, label := range labels {
|
||||
lbs = append(lbs, &models.Label{
|
||||
RepoID: g.repo.ID,
|
||||
@@ -232,7 +231,7 @@ func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error {
|
||||
|
||||
// CreateReleases creates releases
|
||||
func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
|
||||
var rels = make([]*models.Release, 0, len(releases))
|
||||
rels := make([]*models.Release, 0, len(releases))
|
||||
for _, release := range releases {
|
||||
if release.Created.IsZero() {
|
||||
if !release.Published.IsZero() {
|
||||
@@ -242,13 +241,12 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
|
||||
}
|
||||
}
|
||||
|
||||
var rel = models.Release{
|
||||
rel := models.Release{
|
||||
RepoID: g.repo.ID,
|
||||
TagName: release.TagName,
|
||||
LowerTagName: strings.ToLower(release.TagName),
|
||||
Target: release.TargetCommitish,
|
||||
Title: release.Name,
|
||||
Sha1: release.TargetCommitish,
|
||||
Note: release.Body,
|
||||
IsDraft: release.Draft,
|
||||
IsPrerelease: release.Prerelease,
|
||||
@@ -277,15 +275,18 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
|
||||
rel.OriginalAuthorID = release.PublisherID
|
||||
}
|
||||
|
||||
// calc NumCommits if no draft
|
||||
if !release.Draft {
|
||||
// calc NumCommits if possible
|
||||
if rel.TagName != "" {
|
||||
commit, err := g.gitRepo.GetTagCommit(rel.TagName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTagCommit[%v]: %v", rel.TagName, err)
|
||||
}
|
||||
rel.NumCommits, err = commit.CommitsCount()
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsCount: %v", err)
|
||||
if !errors.Is(err, git.ErrNotExist{}) {
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTagCommit[%v]: %v", rel.TagName, err)
|
||||
}
|
||||
rel.Sha1 = commit.ID.String()
|
||||
rel.NumCommits, err = commit.CommitsCount()
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsCount: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +298,7 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error {
|
||||
asset.Created = release.Created
|
||||
}
|
||||
}
|
||||
var attach = repo_model.Attachment{
|
||||
attach := repo_model.Attachment{
|
||||
UUID: gouuid.New().String(),
|
||||
Name: asset.Name,
|
||||
DownloadCount: int64(*asset.DownloadCount),
|
||||
@@ -348,7 +349,7 @@ func (g *GiteaLocalUploader) SyncTags() error {
|
||||
|
||||
// CreateIssues creates issues
|
||||
func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
|
||||
var iss = make([]*models.Issue, 0, len(issues))
|
||||
iss := make([]*models.Issue, 0, len(issues))
|
||||
for _, issue := range issues {
|
||||
var labels []*models.Label
|
||||
for _, label := range issue.Labels {
|
||||
@@ -381,7 +382,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
|
||||
}
|
||||
}
|
||||
|
||||
var is = models.Issue{
|
||||
is := models.Issue{
|
||||
RepoID: g.repo.ID,
|
||||
Repo: g.repo,
|
||||
Index: issue.Number,
|
||||
@@ -433,7 +434,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
|
||||
g.userMap[reaction.UserID] = userid
|
||||
}
|
||||
}
|
||||
var res = models.Reaction{
|
||||
res := models.Reaction{
|
||||
Type: reaction.Content,
|
||||
CreatedUnix: timeutil.TimeStampNow(),
|
||||
}
|
||||
@@ -464,7 +465,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
|
||||
|
||||
// CreateComments creates comments of issues
|
||||
func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error {
|
||||
var cms = make([]*models.Comment, 0, len(comments))
|
||||
cms := make([]*models.Comment, 0, len(comments))
|
||||
for _, comment := range comments {
|
||||
var issue *models.Issue
|
||||
issueInter, ok := g.issues.Load(comment.IssueIndex)
|
||||
@@ -528,7 +529,7 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error {
|
||||
g.userMap[reaction.UserID] = userid
|
||||
}
|
||||
}
|
||||
var res = models.Reaction{
|
||||
res := models.Reaction{
|
||||
Type: reaction.Content,
|
||||
CreatedUnix: timeutil.TimeStampNow(),
|
||||
}
|
||||
@@ -553,7 +554,7 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error {
|
||||
|
||||
// CreatePullRequests creates pull requests
|
||||
func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error {
|
||||
var gprs = make([]*models.PullRequest, 0, len(prs))
|
||||
gprs := make([]*models.PullRequest, 0, len(prs))
|
||||
for _, pr := range prs {
|
||||
gpr, err := g.newPullRequest(pr)
|
||||
if err != nil {
|
||||
@@ -652,7 +653,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var head = "unknown repository"
|
||||
head := "unknown repository"
|
||||
if pr.IsForkPullRequest() && pr.State != "closed" {
|
||||
if pr.Head.OwnerName != "" {
|
||||
remote := pr.Head.OwnerName
|
||||
@@ -669,7 +670,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||
}
|
||||
|
||||
if ok {
|
||||
_, err = git.NewCommand("fetch", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath())
|
||||
_, err = git.NewCommandContext(g.ctx, "fetch", "--no-tags", "--", remote, pr.Head.Ref).RunInDir(g.repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("Fetch branch from %s failed: %v", pr.Head.CloneURL, err)
|
||||
} else {
|
||||
@@ -723,7 +724,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||
pr.Updated = pr.Created
|
||||
}
|
||||
|
||||
var issue = models.Issue{
|
||||
issue := models.Issue{
|
||||
RepoID: g.repo.ID,
|
||||
Repo: g.repo,
|
||||
Title: pr.Title,
|
||||
@@ -773,7 +774,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||
g.userMap[reaction.UserID] = userid
|
||||
}
|
||||
}
|
||||
var res = models.Reaction{
|
||||
res := models.Reaction{
|
||||
Type: reaction.Content,
|
||||
CreatedUnix: timeutil.TimeStampNow(),
|
||||
}
|
||||
@@ -787,7 +788,7 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*models.PullR
|
||||
issue.Reactions = append(issue.Reactions, &res)
|
||||
}
|
||||
|
||||
var pullRequest = models.PullRequest{
|
||||
pullRequest := models.PullRequest{
|
||||
HeadRepoID: g.repo.ID,
|
||||
HeadBranch: head,
|
||||
BaseRepoID: g.repo.ID,
|
||||
@@ -830,7 +831,7 @@ func convertReviewState(state string) models.ReviewType {
|
||||
|
||||
// CreateReviews create pull request reviews
|
||||
func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
|
||||
var cms = make([]*models.Review, 0, len(reviews))
|
||||
cms := make([]*models.Review, 0, len(reviews))
|
||||
for _, review := range reviews {
|
||||
var issue *models.Issue
|
||||
issueInter, ok := g.issues.Load(review.IssueIndex)
|
||||
@@ -862,7 +863,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
|
||||
review.CreatedAt = time.Unix(int64(issue.CreatedUnix), 0)
|
||||
}
|
||||
|
||||
var cm = models.Review{
|
||||
cm := models.Review{
|
||||
Type: convertReviewState(review.State),
|
||||
IssueID: issue.ID,
|
||||
Content: review.Content,
|
||||
@@ -926,7 +927,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
|
||||
comment.UpdatedAt = comment.CreatedAt
|
||||
}
|
||||
|
||||
var c = models.Comment{
|
||||
c := models.Comment{
|
||||
Type: models.CommentTypeCode,
|
||||
PosterID: comment.PosterID,
|
||||
IssueID: issue.ID,
|
||||
|
||||
@@ -97,7 +97,7 @@ func TestGiteaUploadRepo(t *testing.T) {
|
||||
assert.Len(t, releases, 1)
|
||||
|
||||
issues, err := models.Issues(&models.IssuesOptions{
|
||||
RepoIDs: []int64{repo.ID},
|
||||
RepoID: repo.ID,
|
||||
IsPull: util.OptionalBoolFalse,
|
||||
SortType: "oldest",
|
||||
})
|
||||
|
||||
@@ -39,7 +39,13 @@ func UpdateAddress(m *repo_model.Mirror, addr string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = git.NewCommand("remote", "add", remoteName, "--mirror=fetch", addr).RunInDir(repoPath)
|
||||
cmd := git.NewCommand("remote", "add", remoteName, "--mirror=fetch", addr)
|
||||
if strings.Contains(addr, "://") && strings.Contains(addr, "@") {
|
||||
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, util.NewStringURLSanitizer(addr, true).Replace(addr), repoPath))
|
||||
} else {
|
||||
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, addr, repoPath))
|
||||
}
|
||||
_, err = cmd.RunInDir(repoPath)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return err
|
||||
}
|
||||
@@ -53,7 +59,13 @@ func UpdateAddress(m *repo_model.Mirror, addr string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = git.NewCommand("remote", "add", remoteName, "--mirror=fetch", wikiRemotePath).RunInDir(wikiPath)
|
||||
cmd = git.NewCommand("remote", "add", remoteName, "--mirror=fetch", wikiRemotePath)
|
||||
if strings.Contains(wikiRemotePath, "://") && strings.Contains(wikiRemotePath, "@") {
|
||||
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, util.NewStringURLSanitizer(wikiRemotePath, true).Replace(wikiRemotePath), wikiPath))
|
||||
} else {
|
||||
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=fetch %s [repo_path: %s]", remoteName, wikiRemotePath, wikiPath))
|
||||
}
|
||||
_, err = cmd.RunInDir(wikiPath)
|
||||
if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
|
||||
return err
|
||||
}
|
||||
@@ -150,8 +162,8 @@ func pruneBrokenReferences(ctx context.Context,
|
||||
timeout time.Duration,
|
||||
stdoutBuilder, stderrBuilder *strings.Builder,
|
||||
sanitizer *strings.Replacer,
|
||||
isWiki bool) error {
|
||||
|
||||
isWiki bool,
|
||||
) error {
|
||||
wiki := ""
|
||||
if isWiki {
|
||||
wiki = "Wiki "
|
||||
@@ -188,6 +200,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
timeout := time.Duration(setting.Git.Timeout.Mirror) * time.Second
|
||||
|
||||
log.Trace("SyncMirrors [repo: %-v]: running git remote update...", m.Repo)
|
||||
|
||||
gitArgs := []string{"remote", "update"}
|
||||
if m.EnablePrune {
|
||||
gitArgs = append(gitArgs, "--prune")
|
||||
@@ -250,7 +263,11 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
}
|
||||
output := stderrBuilder.String()
|
||||
|
||||
gitRepo, err := git.OpenRepository(repoPath)
|
||||
if err := git.WriteCommitGraph(ctx, repoPath); err != nil {
|
||||
log.Error("SyncMirrors [repo: %-v]: %v", m.Repo, err)
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepositoryCtx(ctx, repoPath)
|
||||
if err != nil {
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to OpenRepository: %v", m.Repo, err)
|
||||
return nil, false
|
||||
@@ -332,6 +349,10 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if err := git.WriteCommitGraph(ctx, wikiPath); err != nil {
|
||||
log.Error("SyncMirrors [repo: %-v]: %v", m.Repo, err)
|
||||
}
|
||||
}
|
||||
log.Trace("SyncMirrors [repo: %-v Wiki]: git remote update complete", m.Repo)
|
||||
}
|
||||
@@ -375,6 +396,9 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
log.Trace("SyncMirrors [repo: %-v]: Running Sync", m.Repo)
|
||||
results, ok := runSync(ctx, m)
|
||||
if !ok {
|
||||
if err = repo_model.TouchMirror(ctx, m); err != nil {
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to TouchMirror: %v", m.Repo, err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
@@ -28,7 +29,13 @@ var stripExitStatus = regexp.MustCompile(`exit status \d+ - `)
|
||||
// AddPushMirrorRemote registers the push mirror remote.
|
||||
func AddPushMirrorRemote(m *repo_model.PushMirror, addr string) error {
|
||||
addRemoteAndConfig := func(addr, path string) error {
|
||||
if _, err := git.NewCommand("remote", "add", "--mirror=push", m.RemoteName, addr).RunInDir(path); err != nil {
|
||||
cmd := git.NewCommand("remote", "add", "--mirror=push", m.RemoteName, addr)
|
||||
if strings.Contains(addr, "://") && strings.Contains(addr, "@") {
|
||||
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, util.NewStringURLSanitizer(addr, true).Replace(addr), path))
|
||||
} else {
|
||||
cmd.SetDescription(fmt.Sprintf("remote add %s --mirror=push %s [repo_path: %s]", m.RemoteName, addr, path))
|
||||
}
|
||||
if _, err := cmd.RunInDir(path); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := git.NewCommand("config", "--add", "remote."+m.RemoteName+".push", "+refs/heads/*:refs/heads/*").RunInDir(path); err != nil {
|
||||
|
||||
@@ -7,6 +7,7 @@ package pull
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
@@ -24,11 +25,22 @@ import (
|
||||
"code.gitea.io/gitea/modules/queue"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||
)
|
||||
|
||||
// prQueue represents a queue to handle update pull request tests
|
||||
var prQueue queue.UniqueQueue
|
||||
|
||||
var (
|
||||
ErrIsClosed = errors.New("pull is closed")
|
||||
ErrUserNotAllowedToMerge = models.ErrNotAllowedToMerge{}
|
||||
ErrHasMerged = errors.New("has already been merged")
|
||||
ErrIsWorkInProgress = errors.New("work in progress PRs cannot be merged")
|
||||
ErrIsChecking = errors.New("cannot merge while conflict checking is in progress")
|
||||
ErrNotMergableState = errors.New("not in mergeable state")
|
||||
ErrDependenciesLeft = errors.New("is blocked by an open dependency")
|
||||
)
|
||||
|
||||
// AddToTaskQueue adds itself to pull request test task queue.
|
||||
func AddToTaskQueue(pr *models.PullRequest) {
|
||||
err := prQueue.PushFunc(strconv.FormatInt(pr.ID, 10), func() error {
|
||||
@@ -46,6 +58,83 @@ func AddToTaskQueue(pr *models.PullRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...)
|
||||
func CheckPullMergable(ctx context.Context, doer *user_model.User, perm *models.Permission, pr *models.PullRequest, manuallMerge, force bool) error {
|
||||
if pr.HasMerged {
|
||||
return ErrHasMerged
|
||||
}
|
||||
|
||||
if err := pr.LoadIssue(); err != nil {
|
||||
return err
|
||||
} else if pr.Issue.IsClosed {
|
||||
return ErrIsClosed
|
||||
}
|
||||
|
||||
if allowedMerge, err := IsUserAllowedToMerge(pr, *perm, doer); err != nil {
|
||||
return err
|
||||
} else if !allowedMerge {
|
||||
return ErrUserNotAllowedToMerge
|
||||
}
|
||||
|
||||
if manuallMerge {
|
||||
// don't check rules to "auto merge", doer is going to mark this pull as merged manually
|
||||
return nil
|
||||
}
|
||||
|
||||
if pr.IsWorkInProgress() {
|
||||
return ErrIsWorkInProgress
|
||||
}
|
||||
|
||||
if !pr.CanAutoMerge() {
|
||||
return ErrNotMergableState
|
||||
}
|
||||
|
||||
if pr.IsChecking() {
|
||||
return ErrIsChecking
|
||||
}
|
||||
|
||||
if err := CheckPRReadyToMerge(pr, false); err != nil {
|
||||
if models.IsErrNotAllowedToMerge(err) {
|
||||
if force {
|
||||
if isRepoAdmin, err2 := models.IsUserRepoAdmin(pr.BaseRepo, doer); err2 != nil {
|
||||
return err2
|
||||
} else if !isRepoAdmin {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := isSignedIfRequired(ctx, pr, doer); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if noDeps, err := models.IssueNoDependenciesLeft(pr.Issue); err != nil {
|
||||
return err
|
||||
} else if !noDeps {
|
||||
return ErrDependenciesLeft
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// isSignedIfRequired check if merge will be signed if required
|
||||
func isSignedIfRequired(ctx context.Context, pr *models.PullRequest, doer *user_model.User) (bool, error) {
|
||||
if err := pr.LoadProtectedBranch(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if pr.ProtectedBranch == nil || !pr.ProtectedBranch.RequireSignedCommits {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
sign, _, _, err := asymkey_service.SignMerge(pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName())
|
||||
|
||||
return sign, err
|
||||
}
|
||||
|
||||
// checkAndUpdateStatus checks if pull request is possible to leaving checking status,
|
||||
// and set to be either conflict or mergeable.
|
||||
func checkAndUpdateStatus(pr *models.PullRequest) {
|
||||
|
||||
@@ -164,13 +164,13 @@ func rawMerge(pr *models.PullRequest, doer *user_model.User, mergeStyle repo_mod
|
||||
}
|
||||
|
||||
infoPath := filepath.Join(tmpBasePath, ".git", "info")
|
||||
if err := os.MkdirAll(infoPath, 0700); err != nil {
|
||||
if err := os.MkdirAll(infoPath, 0o700); err != nil {
|
||||
log.Error("Unable to create .git/info in %s: %v", tmpBasePath, err)
|
||||
return "", fmt.Errorf("Unable to create .git/info in tmpBasePath: %v", err)
|
||||
}
|
||||
|
||||
sparseCheckoutListPath := filepath.Join(infoPath, "sparse-checkout")
|
||||
if err := os.WriteFile(sparseCheckoutListPath, []byte(sparseCheckoutList), 0600); err != nil {
|
||||
if err := os.WriteFile(sparseCheckoutListPath, []byte(sparseCheckoutList), 0o600); err != nil {
|
||||
log.Error("Unable to write .git/info/sparse-checkout file in %s: %v", tmpBasePath, err)
|
||||
return "", fmt.Errorf("Unable to write .git/info/sparse-checkout file in tmpBasePath: %v", err)
|
||||
}
|
||||
@@ -561,21 +561,6 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
|
||||
return out.String(), nil
|
||||
}
|
||||
|
||||
// IsSignedIfRequired check if merge will be signed if required
|
||||
func IsSignedIfRequired(pr *models.PullRequest, doer *user_model.User) (bool, error) {
|
||||
if err := pr.LoadProtectedBranch(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if pr.ProtectedBranch == nil || !pr.ProtectedBranch.RequireSignedCommits {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
sign, _, _, err := asymkey_service.SignMerge(pr, doer, pr.BaseRepo.RepoPath(), pr.BaseBranch, pr.GetGitRefName())
|
||||
|
||||
return sign, err
|
||||
}
|
||||
|
||||
// IsUserAllowedToMerge check if user is allowed to merge PR with given permissions and branch protections
|
||||
func IsUserAllowedToMerge(pr *models.PullRequest, p models.Permission, user *user_model.User) (bool, error) {
|
||||
if user == nil {
|
||||
|
||||
@@ -431,14 +431,16 @@ func checkConflicts(pr *models.PullRequest, gitRepo *git.Repository, tmpBasePath
|
||||
return nil
|
||||
})
|
||||
|
||||
// 8. If there is a conflict the `git apply` command will return a non-zero error code - so there will be a positive error.
|
||||
if err != nil {
|
||||
// 9. Check if the found conflictedfiles is non-zero, "err" could be non-nil, so we should ignore it if we found conflicts.
|
||||
// Note: `"err" could be non-nil` is due that if enable 3-way merge, it doesn't return any error on found conflicts.
|
||||
if len(pr.ConflictedFiles) > 0 {
|
||||
if conflict {
|
||||
pr.Status = models.PullRequestStatusConflict
|
||||
log.Trace("Found %d files conflicted: %v", len(pr.ConflictedFiles), pr.ConflictedFiles)
|
||||
|
||||
return true, nil
|
||||
}
|
||||
} else if err != nil {
|
||||
return false, fmt.Errorf("git apply --check: %v", err)
|
||||
}
|
||||
return false, nil
|
||||
|
||||
@@ -169,7 +169,7 @@ func doArchive(r *ArchiveRequest) (*repo_model.RepoArchiver, error) {
|
||||
w.Close()
|
||||
rd.Close()
|
||||
}()
|
||||
var done = make(chan error)
|
||||
done := make(chan error, 1) // Ensure that there is some capacity which will ensure that the goroutine below can always finish
|
||||
repo, err := repo_model.GetRepositoryByID(archiver.RepoID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("archiver.LoadRepo failed: %v", err)
|
||||
|
||||
@@ -69,7 +69,7 @@ func GetBranches(repo *repo_model.Repository, skip, limit int) ([]*git.Branch, i
|
||||
|
||||
// checkBranchName validates branch name with existing repository branches
|
||||
func checkBranchName(ctx context.Context, repo *repo_model.Repository, name string) error {
|
||||
_, err := git.WalkReferences(ctx, repo.RepoPath(), func(refName string) error {
|
||||
_, err := git.WalkReferences(ctx, repo.RepoPath(), func(_, refName string) error {
|
||||
branchRefName := strings.TrimPrefix(refName, git.BranchPrefix)
|
||||
switch {
|
||||
case branchRefName == name:
|
||||
|
||||
@@ -148,6 +148,8 @@ func Deliver(t *webhook_model.HookTask) error {
|
||||
t.Delivered = time.Now().UnixNano()
|
||||
if t.IsSucceed {
|
||||
log.Trace("Hook delivered: %s", t.UUID)
|
||||
} else if !w.IsActive {
|
||||
log.Trace("Hook delivery skipped as webhook is inactive: %s", t.UUID)
|
||||
} else {
|
||||
log.Trace("Hook delivery failed: %s", t.UUID)
|
||||
}
|
||||
@@ -172,6 +174,10 @@ func Deliver(t *webhook_model.HookTask) error {
|
||||
return fmt.Errorf("webhook task skipped (webhooks disabled): [%d]", t.ID)
|
||||
}
|
||||
|
||||
if !w.IsActive {
|
||||
return nil
|
||||
}
|
||||
|
||||
resp, err := webhookHTTPClient.Do(req.WithContext(graceful.GetManager().ShutdownContext()))
|
||||
if err != nil {
|
||||
t.ResponseInfo.Body = fmt.Sprintf("Delivery: %v", err)
|
||||
|
||||
@@ -212,7 +212,7 @@ func prepareWebhooks(repo *repo_model.Repository, event webhook_model.HookEventT
|
||||
}
|
||||
|
||||
// Add any admin-defined system webhooks
|
||||
systemHooks, err := webhook_model.GetSystemWebhooks()
|
||||
systemHooks, err := webhook_model.GetSystemWebhooks(util.OptionalBoolTrue)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetSystemWebhooks: %v", err)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<footer>
|
||||
<div class="ui container">
|
||||
<div class="ui left">
|
||||
{{.i18n.Tr "powered_by" "Gitea"}} {{if (or .ShowFooterVersion .PageIsAdmin)}}{{.i18n.Tr "version"}}: {{AppVer}}{{end}} {{if ShowFooterTemplateLoadTime}}{{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> {{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong>{{end}}
|
||||
{{.i18n.Tr "powered_by" "Gitea"}} {{if (or .ShowFooterVersion .PageIsAdmin)}}{{.i18n.Tr "version"}}: {{AppVer}}{{end}} {{if and .TmplLoadTimes ShowFooterTemplateLoadTime}}{{.i18n.Tr "page"}}: <strong>{{LoadTimes .PageStartTime}}</strong> {{.i18n.Tr "template"}}: <strong>{{call .TmplLoadTimes}}</strong>{{end}}
|
||||
</div>
|
||||
<div class="ui right links">
|
||||
{{if .ShowFooterBranding}}
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
<td class="chroma lines-code blob-hunk">{{/*
|
||||
*/}}<code {{if $inlineDiff.EscapeStatus.Escaped}}class="code-inner has-escaped" title="{{$.root.i18n.Tr "repo.line_unicode"}}"{{else}}class="code-inner"{{end}}>{{$inlineDiff.Content}}</code>{{/*
|
||||
*/}}
|
||||
{{$line.Content}}
|
||||
</td>
|
||||
{{else}}
|
||||
<td class="chroma lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}">{{/*
|
||||
|
||||
@@ -50,14 +50,17 @@ git push -u origin {{.Repository.DefaultBranch}}</code></pre>
|
||||
git push -u origin {{.Repository.DefaultBranch}}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<script defer>
|
||||
/* eslint-disable no-undef */
|
||||
const cloneUrls = document.getElementsByClassName('clone-url');
|
||||
if (cloneUrls) {
|
||||
for (let i = 0; i < cloneUrls.length; i++) {
|
||||
cloneUrls[i].textContent = (isSSH ? sshButton : httpsButton).getAttribute('data-link');
|
||||
<script>
|
||||
(() => {
|
||||
const proto = localStorage.getItem('repo-clone-protocol') || 'https';
|
||||
const btn = document.getElementById(`repo-clone-${proto}`) || document.getElementById(`repo-clone-https`) || document.getElementById(`repo-clone-ssh`);
|
||||
if (btn) {
|
||||
const cloneUrls = document.getElementsByClassName('clone-url');
|
||||
for (let i = 0; i < cloneUrls.length; i++) {
|
||||
cloneUrls[i].textContent = btn.getAttribute('data-link');
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
{{end}}
|
||||
{{else}}
|
||||
|
||||
@@ -14091,6 +14091,10 @@
|
||||
"type": "string",
|
||||
"x-go-name": "Password"
|
||||
},
|
||||
"restricted": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "Restricted"
|
||||
},
|
||||
"send_notify": {
|
||||
"type": "boolean",
|
||||
"x-go-name": "SendNotify"
|
||||
@@ -14757,6 +14761,11 @@
|
||||
"type": "string",
|
||||
"x-go-name": "Description"
|
||||
},
|
||||
"enable_prune": {
|
||||
"description": "enable prune - remove obsolete remote-tracking references",
|
||||
"type": "boolean",
|
||||
"x-go-name": "EnablePrune"
|
||||
},
|
||||
"external_tracker": {
|
||||
"$ref": "#/definitions/ExternalTracker"
|
||||
},
|
||||
|
||||
@@ -15,10 +15,6 @@ function selectRange($list, $select, $from) {
|
||||
const $issue = $('a.ref-in-new-issue');
|
||||
const $copyPermalink = $('a.copy-line-permalink');
|
||||
|
||||
if ($copyPermalink.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updateIssueHref = function (anchor) {
|
||||
if ($issue.length === 0) {
|
||||
return;
|
||||
@@ -29,6 +25,9 @@ function selectRange($list, $select, $from) {
|
||||
};
|
||||
|
||||
const updateCopyPermalinkHref = function(anchor) {
|
||||
if ($copyPermalink.length === 0) {
|
||||
return;
|
||||
}
|
||||
let link = $copyPermalink.attr('data-clipboard-text');
|
||||
link = `${link.replace(/#L\d+$|#L\d+-L\d+$/, '')}#${anchor}`;
|
||||
$copyPermalink.attr('data-clipboard-text', link);
|
||||
|
||||
Reference in New Issue
Block a user