Compare commits
241 Commits
gitroast
...
ux-registe
Author | SHA1 | Date |
---|---|---|
AJ ONeal | 2bdc146bcf | |
SagePtr | 378af8ea88 | |
SagePtr | c6daee6da6 | |
Jonas Franz | 94cd7bb25b | |
Chih-Hsuan Yen | d7ca839c67 | |
Dane | 513db27377 | |
AJ ONeal | 2b8dc17db7 | |
GiteaBot | 2e2eacf62a | |
Mura Li | dba955be7c | |
GiteaBot | b8d048fa0d | |
Lauris BH | ab5b245182 | |
SagePtr | fc0001caa1 | |
Lauris BH | 81702e6ec9 | |
Iwasa Kazmi | 6780661192 | |
Lanre Adelowo | e6d54d511d | |
silverwind | 31d5488059 | |
GiteaBot | 39735723f5 | |
flufmonster | b3393b5ca7 | |
GiteaBot | 79b4d4729c | |
Lauris BH | 4092b32bad | |
zeripath | 36e7cb9755 | |
Wyall | dab02b80fd | |
OvermindDL1 | 07af31d004 | |
GiteaBot | 364c029246 | |
SagePtr | 043ab2cd59 | |
GiteaBot | 8b113cd8b6 | |
bugreport0 | 91b164c778 | |
GiteaBot | 552d8d3a4e | |
crito | d6b97c8557 | |
Lauris BH | 4befec242a | |
nubenum | 756eafaaf6 | |
Lanre Adelowo | acb6f8a518 | |
Bo-Yi Wu | f6eb669b51 | |
GiteaBot | 3e76e7826e | |
Girish Ramakrishnan | 661fd901bd | |
Lanre Adelowo | 2a6d3ba058 | |
linweijie2012 | f98040ad50 | |
Lanre Adelowo | 126ba796dc | |
SagePtr | 10a2a904d7 | |
Bo-Yi Wu | ea20adaa84 | |
GiteaBot | 7dd93b2441 | |
techknowlogick | e91a2cf2ea | |
Drew Bowering | 8e3e59fdb8 | |
GiteaBot | b5b39a56ad | |
Fluf | 08ed515b62 | |
GiteaBot | c64c595acc | |
techknowlogick | f1ad4bb3d5 | |
Lanre Adelowo | 8ee9922fe6 | |
B-OnTheGo | e47df0b301 | |
Bobonium | 387a4b09c1 | |
GiteaBot | 15ebe4b853 | |
Lanre Adelowo | be48397945 | |
GiteaBot | 6e03390aa8 | |
Toni Villena | eea76a5241 | |
vz | e9dbfc70b7 | |
GiteaBot | 1dee960b45 | |
Lewis Cowles | c43399cad8 | |
zeripath | d293a2b9d6 | |
Lukas Bestle | e6a03813d4 | |
Lauris BH | fab7937c62 | |
Lauris BH | fa4663e61e | |
SagePtr | bf55276189 | |
techknowlogick | 13e8a0fe56 | |
SagePtr | 303d7f7e9c | |
Max Wittig | 3c6cc56143 | |
Matthias Kappeller | bd1bf2a072 | |
maiki | a5cc3a9baf | |
Lunny Xiao | 061b1aa2d4 | |
Nicolas Lenz | 668a477c69 | |
Lunny Xiao | e48df3ee47 | |
techknowlogick | a4ee5627ed | |
GiteaBot | 01fd05a5cb | |
Bernhard Fröhlich | 83d1173634 | |
GiteaBot | aad5cccec8 | |
SagePtr | 9500d394ec | |
Najib Idrissi | b9ae16d15e | |
techknowlogick | fcea86877f | |
GiteaBot | a938ddf704 | |
techknowlogick | 080428b2bf | |
GiteaBot | 179123de35 | |
SagePtr | 74d65b5b5b | |
Joel da Rosa | 34831afaa7 | |
Piotr Orzechowski | 51c3b4b4bf | |
Piotr Orzechowski | 56d931aeac | |
SagePtr | 4ae5a54c1f | |
Deoren Moor | b63e2e0ded | |
EnricoFerro | 0a24f5cac8 | |
techknowlogick | 194a11eb11 | |
EnricoFerro | 912953e82a | |
Russell Aunger | 127f477056 | |
GiteaBot | 0dac1ff677 | |
Lanre Adelowo | f766e9713b | |
GiteaBot | 3c39b6351c | |
Lanre Adelowo | 33bc2ebdfa | |
Lanre Adelowo | 6ca8fbd2f9 | |
GiteaBot | 05dcfcfc33 | |
Fluf | b82c14b3d2 | |
Lanre Adelowo | 6c1a31ffaa | |
Julien Tant | fa93857117 | |
Lanre Adelowo | a6cdda115d | |
Tosone | b1ad5734c6 | |
GiteaBot | 1b2aff02a2 | |
SagePtr | 50ce19eff7 | |
GiteaBot | 8273479b41 | |
Andrew Phillips | b30f6b4099 | |
GiteaBot | f24ba27d79 | |
SagePtr | 8f86c43b90 | |
GiteaBot | bc06ab4a31 | |
Lauris BH | 92466129ec | |
SagePtr | 0449330dbc | |
nemoinho | ca112f0a04 | |
GiteaBot | 03e558c29b | |
Julien Tant | e6777f7b9d | |
GiteaBot | df0eb7372c | |
Julien Tant | 7781e8cef2 | |
Lunny Xiao | 52c2cb15db | |
SagePtr | a4fa6bbc89 | |
Lauris BH | 6e68b61479 | |
techknowlogick | ce7c64c7e1 | |
Lanre Adelowo | 3422077a89 | |
Lauris BH | 7fbdd4f2ac | |
SagePtr | 3ad5399a31 | |
Lanre Adelowo | 69a855f3d4 | |
SagePtr | 4a7de87071 | |
techknowlogick | 5dfe8b4340 | |
Lunny Xiao | 8da45ae2b3 | |
nemoinho | 0e04a2091a | |
Lunny Xiao | 578cf52ce5 | |
techknowlogick | 0e464995ce | |
Piotr Orzechowski | 152c6af97e | |
GiteaBot | 00bd6277a8 | |
Lanre Adelowo | 3b51c4f3fb | |
SagePtr | 32145b6de8 | |
GiteaBot | 67a8688538 | |
Jerry Jacobs | b1bc08e268 | |
GiteaBot | ed3589f429 | |
Lauris BH | 5ae8408725 | |
GiteaBot | a42900c17f | |
Lanre Adelowo | 0df7cab4fb | |
Lanre Adelowo | 59b10e66f7 | |
Lanre Adelowo | c7a6ee5c0b | |
GiteaBot | 7cb1c1cf20 | |
Dennis Menschel | 9c0a374f3f | |
GiteaBot | 9ea327f1f7 | |
Lauris BH | 6e64f9db8e | |
Lunny Xiao | 9c354a539a | |
Allen Wild | c40f5d2d4c | |
Dingjun | 819f50ccd5 | |
Julien Tant | ced08d18a4 | |
Benedikt Kroll | d57233680b | |
Lanre Adelowo | b11ddd8d4c | |
GiteaBot | e277b3e0e4 | |
techknowlogick | 895e538836 | |
Piotr Orzechowski | a74426d631 | |
GiteaBot | 412583a3f2 | |
SagePtr | c1224124ea | |
GiteaBot | 5927599e43 | |
techknowlogick | adf3f004b6 | |
SagePtr | ac968c3c6f | |
Lukas Treyer | be4ec0cbba | |
GiteaBot | a847d16f5b | |
kolaente | 8d1ad55598 | |
William Le Pommelet | f847884d16 | |
Lauris BH | 1b9b894731 | |
GiteaBot | 7a30208e05 | |
Lanre Adelowo | 630f234223 | |
GiteaBot | 32f25598b3 | |
Lanre Adelowo | 4bf0cae1f5 | |
GiteaBot | d0fef4395f | |
Michael Kuhn | 344dc07239 | |
Kjell Kvinge | ba358ecbf5 | |
Lauris BH | ae9dd239fb | |
GiteaBot | ec43e5619b | |
Kjell Kvinge | bed623600d | |
GiteaBot | 5fa403c874 | |
Lunny Xiao | 0bb1c84208 | |
bugreport0 | b174817b6a | |
GiteaBot | cc9fa062e6 | |
Lauris BH | 0c59edaafa | |
GiteaBot | 1e2da5d396 | |
techknowlogick | 492ec97a46 | |
Lunny Xiao | d1337299e2 | |
GiteaBot | 9ca8aaecb4 | |
Joel da Rosa | 91373901f6 | |
techknowlogick | fe78154895 | |
kolaente | 1bff02de55 | |
Mahmoud Al-Qudsi | 7be5935c55 | |
kolaente | ef6813abc9 | |
GiteaBot | 55d9ddf24a | |
Alexey Terentyev | ca474af3c6 | |
GiteaBot | 8e103d3e76 | |
techknowlogick | a7c5e58635 | |
GiteaBot | ca8c7bb2b5 | |
Joel da Rosa | aa27cbf229 | |
GiteaBot | 6813640d2f | |
Lauris BH | e95417ea2c | |
Lauris BH | 659bc727bd | |
Thomas Boerger | e6b51200ab | |
Lauris BH | a7f90905df | |
Thomas Boerger | 8afd500c48 | |
Thomas Boerger | 8b21cdba78 | |
Thomas Boerger | 3e950ef112 | |
silverwind | c55caeaf0c | |
Thomas Boerger | d84490a0df | |
Lauris BH | c2ec38f9b7 | |
GiteaBot | 61f4ad2fc5 | |
Niclas Kroon | c9687c036d | |
GiteaBot | 3e445cce06 | |
BNolet | 80169460ec | |
GiteaBot | efd202f40f | |
techknowlogick | ab55ca7ebd | |
Lunny Xiao | 1675fc4301 | |
techknowlogick | 61b40520ba | |
techknowlogick | f1d6a1fffc | |
GiteaBot | 28c1c90230 | |
Jonas Franz | 2a60e72fcd | |
GiteaBot | cfb76cd99e | |
Guido Diepen | 7c943b1cad | |
Lanre Adelowo | 5bc8782d33 | |
Nicolas Da Mutten | e07d3ad0fc | |
Fluf | f035dcd4f2 | |
Lauris BH | 54fedd4070 | |
GiteaBot | 07063e3e11 | |
Lauris BH | 69e2ab1611 | |
GiteaBot | 4eae810d63 | |
Lauris BH | 4a8ee0b5cc | |
Lunny Xiao | b46066f17c | |
GiteaBot | 95f0f62ea4 | |
Antoine GIRARD | 74f9f98f78 | |
Matthew Richardson | 2e3475f02c | |
GiteaBot | df77ad31d5 | |
techknowlogick | c3bbf43970 | |
GiteaBot | fc53f95f23 | |
Tao Wang | 823318bfbe | |
tarelda | 5676f60cba | |
GiteaBot | 3fed13b0ee | |
cezar97 | 51ba3df5ff | |
ucodi | 4b654ad17f | |
Pofilo | 5d1a6382b6 | |
Clar Charr | c71ee33057 | |
techknowlogick | 9d4c1ddfa1 |
46
.drone.yml
46
.drone.yml
|
@ -22,7 +22,7 @@ pipeline:
|
|||
branch: [ master ]
|
||||
|
||||
update-translations:
|
||||
image: alpine:3.6
|
||||
image: alpine:3.7
|
||||
commands:
|
||||
- mv ./options/locale/locale_en-US.ini ./options/
|
||||
- sed -i -e 's/="/=/g' -e 's/"$$//g' ./options/locale/*.ini
|
||||
|
@ -56,7 +56,7 @@ pipeline:
|
|||
event: [ push, tag, pull_request ]
|
||||
|
||||
build-without-gcc:
|
||||
image: golang:1.8
|
||||
image: golang:1.9
|
||||
pull: true
|
||||
commands:
|
||||
- go build -o gitea_no_gcc # test if build succeeds without the sqlite tag
|
||||
|
@ -64,7 +64,7 @@ pipeline:
|
|||
event: [ push, tag, pull_request ]
|
||||
|
||||
build:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
environment:
|
||||
TAGS: bindata sqlite
|
||||
|
@ -83,7 +83,7 @@ pipeline:
|
|||
event: [ push, tag, pull_request ]
|
||||
|
||||
test:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
environment:
|
||||
|
@ -95,7 +95,7 @@ pipeline:
|
|||
branch: [ master ]
|
||||
|
||||
test:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
environment:
|
||||
|
@ -107,7 +107,7 @@ pipeline:
|
|||
branch: [ release/* ]
|
||||
|
||||
test:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
environment:
|
||||
|
@ -130,7 +130,7 @@ pipeline:
|
|||
# event: [ push, tag, pull_request ]
|
||||
|
||||
test-mysql:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
environment:
|
||||
|
@ -145,7 +145,7 @@ pipeline:
|
|||
branch: [ master ]
|
||||
|
||||
test-mysql:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
environment:
|
||||
|
@ -159,7 +159,7 @@ pipeline:
|
|||
event: [ tag ]
|
||||
|
||||
test-pgsql:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
group: test
|
||||
environment:
|
||||
|
@ -173,7 +173,7 @@ pipeline:
|
|||
event: [ push, tag, pull_request ]
|
||||
|
||||
generate-coverage:
|
||||
image: golang:1.10
|
||||
image: golang:1.11
|
||||
pull: true
|
||||
environment:
|
||||
TAGS: bindata
|
||||
|
@ -203,7 +203,7 @@ pipeline:
|
|||
when:
|
||||
event: [ push, tag ]
|
||||
|
||||
build_docs:
|
||||
build-docs:
|
||||
image: webhippie/hugo:latest
|
||||
pull: true
|
||||
commands:
|
||||
|
@ -212,26 +212,12 @@ pipeline:
|
|||
- make clean
|
||||
- make build
|
||||
|
||||
docker_docs:
|
||||
image: plugins/docker:17.05
|
||||
publish-docs:
|
||||
image: lucap/drone-netlify:latest
|
||||
pull: true
|
||||
secrets: [ docker_username, docker_password ]
|
||||
repo: gitea/docs
|
||||
context: docs
|
||||
dockerfile: docs/Dockerfile
|
||||
tags: [ '${DRONE_BRANCH##release/v}' ]
|
||||
when:
|
||||
event: [ push ]
|
||||
branch: [ release/* ]
|
||||
|
||||
docker_docs:
|
||||
image: plugins/docker:17.05
|
||||
pull: true
|
||||
secrets: [ docker_username, docker_password ]
|
||||
repo: gitea/docs
|
||||
context: docs
|
||||
dockerfile: docs/Dockerfile
|
||||
tags: [ 'latest' ]
|
||||
secrets: [ netlify_token ]
|
||||
site_id: d2260bae-7861-4c02-8646-8f6440b12672
|
||||
path: docs/public/
|
||||
when:
|
||||
event: [ push ]
|
||||
branch: [ master ]
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
# GNU makefile proxy script for BSD make
|
||||
# Written and maintained by Mahmoud Al-Qudsi <mqudsi@neosmart.net>
|
||||
# Copyright NeoSmart Technologies <https://neosmart.net/> 2014-2018
|
||||
# Obtain updates from <https://github.com/neosmart/gmake-proxy>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
JARG =
|
||||
GMAKE = "gmake"
|
||||
#When gmake is called from another make instance, -w is automatically added
|
||||
#which causes extraneous messages about directory changes to be emitted.
|
||||
#--no-print-directory silences these messages.
|
||||
GARGS = "--no-print-directory"
|
||||
|
||||
.if "$(.MAKE.JOBS)" != ""
|
||||
JARG = -j$(.MAKE.JOBS)
|
||||
.endif
|
||||
|
||||
#by default bmake will cd into ./obj first
|
||||
.OBJDIR: ./
|
||||
|
||||
.PHONY: FRC
|
||||
$(.TARGETS): FRC
|
||||
$(GMAKE) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
||||
|
||||
.DONE .DEFAULT: .SILENT
|
||||
$(GMAKE) $(GARGS) $(.TARGETS:S,.DONE,,) $(JARG)
|
||||
|
||||
.ERROR: .SILENT
|
||||
if ! which $(GMAKE) > /dev/null; then \
|
||||
echo "GNU Make is required!"; \
|
||||
fi
|
31
CHANGELOG.md
31
CHANGELOG.md
|
@ -4,10 +4,39 @@ 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.5.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.5.0-rc1) - 2018-07-04
|
||||
## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03
|
||||
* SECURITY
|
||||
* Don't disclose emails of all users when sending out emails (#4784)
|
||||
* Improve URL validation for external wiki and external issues (#4710) (#4740)
|
||||
* Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) (#4707)
|
||||
* BUGFIXES
|
||||
* Fix missing release title in webhook (#4783) (#4800)
|
||||
* Make sure to reset commit count in the cache on mirror syncing (#4770)
|
||||
* Fixed bug where team with admin privelege type doesn't get any unit (#4759)
|
||||
* Fix failure on creating pull request with assignees (#4583) (#4727)
|
||||
* Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686)
|
||||
* TRANSLATION
|
||||
* Fix incorrect caption of webhook setting (#4701) (#4718)
|
||||
|
||||
## [1.5.0](https://github.com/go-gitea/gitea/releases/tag/v1.5.0) - 2018-08-10
|
||||
* SECURITY
|
||||
* Check that repositories can only be migrated to own user or organizations (#4366) (#4370)
|
||||
* Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
|
||||
* Do not allow to reuse TOTP passcode (#3878)
|
||||
* BUGFIXES
|
||||
* Fix column droping for MSSQL that need new transaction for that (#4440) (#4484)
|
||||
* Redirect to correct page after using scratch token (#4458) (#4472)
|
||||
* Replace src with raw to fix image paths (#4377) (#4386)
|
||||
* Fixes repo membership check in API (#4341) (#4379)
|
||||
* Add default merge options when adding new repository (#4369) (#4373)
|
||||
* Fix repository last updated time update when delete a user who watched the repo (#4363) (#4371)
|
||||
* Fix html entity escaping in branch deletion message (#4471) (#4485)
|
||||
* Fix out-of-transaction query in removeOrgUser (#4521) (#4524)
|
||||
* Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519)
|
||||
* Fix panic issue on update avatar email (#4580) (#4590)
|
||||
* Fix bugs when too many IN variables (#4594) (#4597)
|
||||
* Push whitelist now doesn't apply to branch deletion (#4601) (#4640)
|
||||
* Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645) (#4650)
|
||||
* FEATURE
|
||||
* Add cli commands to regen hooks & keys (#3979)
|
||||
* Add support for FIDO U2F (#3971)
|
||||
|
|
|
@ -58,3 +58,4 @@ CMD ["/bin/s6-svscan", "/etc/s6"]
|
|||
|
||||
COPY docker /
|
||||
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea
|
||||
RUN ln -s /app/gitea/gitea /usr/local/bin/gitea
|
||||
|
|
File diff suppressed because it is too large
Load Diff
13
Gopkg.toml
13
Gopkg.toml
|
@ -15,7 +15,7 @@ ignored = ["google.golang.org/appengine*"]
|
|||
name = "code.gitea.io/sdk"
|
||||
|
||||
[[constraint]]
|
||||
revision = "9f005a07e0d31d45e6656d241bb5c0f2efd4bc94"
|
||||
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
|
@ -30,15 +30,14 @@ ignored = ["google.golang.org/appengine*"]
|
|||
revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
|
||||
name = "golang.org/x/net"
|
||||
|
||||
[[constraint]]
|
||||
#version = "v1.0.0"
|
||||
revision = "33197485abe227dcb254644cf5081c9a3c281669"
|
||||
name = "github.com/pingcap/tidb"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-xorm/xorm"
|
||||
#version = "0.6.5"
|
||||
revision = "d4149d1eee0c2c488a74a5863fd9caf13d60fd03"
|
||||
revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/go-sql-driver/mysql"
|
||||
revision = "d523deb1b23d913de5bdada721a6071e71283618"
|
||||
|
||||
[[override]]
|
||||
name = "github.com/gorilla/mux"
|
||||
|
|
|
@ -22,5 +22,5 @@ Peter Žeby <morlinest@gmail.com> (@morlinest)
|
|||
Matti Ranta <matti@mdranta.net> (@techknowlogick)
|
||||
Michael Lustfield <mtecknology@debian.org> (@MTecknology)
|
||||
Jonas Franz <info@jonasfranz.software> (@JonasFranzDEV)
|
||||
Flynn Lufmons <fluf@warpmail.net> (@flufmonster)
|
||||
Alexey Terentyev <axifnx@gmail.com> (@axifive)
|
||||
Lanre Adelowo <yo@lanre.wtf> (@adelowo)
|
||||
|
|
41
Makefile
41
Makefile
|
@ -21,7 +21,19 @@ GOFMT ?= gofmt -s
|
|||
GOFLAGS := -i -v
|
||||
EXTRA_GOFLAGS ?=
|
||||
|
||||
LDFLAGS := -X "main.Version=$(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')" -X "main.Tags=$(TAGS)"
|
||||
ifneq ($(DRONE_TAG),)
|
||||
VERSION ?= $(subst v,,$(DRONE_TAG))
|
||||
GITEA_VERSION := $(VERSION)
|
||||
else
|
||||
ifneq ($(DRONE_BRANCH),)
|
||||
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
|
||||
else
|
||||
VERSION ?= master
|
||||
endif
|
||||
GITEA_VERSION := $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
|
||||
endif
|
||||
|
||||
LDFLAGS := -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
|
||||
|
||||
PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list ./... | grep -v /vendor/))
|
||||
SOURCES ?= $(shell find . -name "*.go" -type f)
|
||||
|
@ -30,6 +42,10 @@ TAGS ?=
|
|||
|
||||
TMPDIR := $(shell mktemp -d 2>/dev/null || mktemp -d -t 'gitea-temp')
|
||||
|
||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||
SWAGGER_SPEC_S_TMPL := s|"basePath":\s*"/api/v1"|"basePath": "{{AppSubUrl}}/api/v1"|g
|
||||
SWAGGER_SPEC_S_JSON := s|"basePath":\s*"{{AppSubUrl}}/api/v1"|"basePath": "/api/v1"|g
|
||||
|
||||
TEST_MYSQL_HOST ?= mysql:3306
|
||||
TEST_MYSQL_DBNAME ?= testgitea
|
||||
TEST_MYSQL_USERNAME ?= root
|
||||
|
@ -45,15 +61,8 @@ else
|
|||
EXECUTABLE := gitea
|
||||
endif
|
||||
|
||||
ifneq ($(DRONE_TAG),)
|
||||
VERSION ?= $(subst v,,$(DRONE_TAG))
|
||||
else
|
||||
ifneq ($(DRONE_BRANCH),)
|
||||
VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
|
||||
else
|
||||
VERSION ?= master
|
||||
endif
|
||||
endif
|
||||
# $(call strip-suffix,filename)
|
||||
strip-suffix = $(firstword $(subst ., ,$(1)))
|
||||
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
@ -89,11 +98,12 @@ generate-swagger:
|
|||
@hash swagger > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/go-swagger/go-swagger/cmd/swagger; \
|
||||
fi
|
||||
swagger generate spec -o ./public/swagger.v1.json
|
||||
swagger generate spec -o './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
|
||||
.PHONY: swagger-check
|
||||
swagger-check: generate-swagger
|
||||
@diff=$$(git diff public/swagger.v1.json); \
|
||||
@diff=$$(git diff '$(SWAGGER_SPEC)'); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make generate-swagger' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
|
@ -105,7 +115,9 @@ swagger-validate:
|
|||
@hash swagger > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/go-swagger/go-swagger/cmd/swagger; \
|
||||
fi
|
||||
swagger validate ./public/swagger.v1.json
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
|
||||
swagger validate './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
|
||||
.PHONY: errcheck
|
||||
errcheck:
|
||||
|
@ -301,7 +313,7 @@ public/js/index.js: $(JAVASCRIPTS)
|
|||
|
||||
.PHONY: stylesheets-check
|
||||
stylesheets-check: generate-stylesheets
|
||||
@diff=$$(git diff public/css/index.css); \
|
||||
@diff=$$(git diff public/css/*); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make generate-stylesheets' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
|
@ -311,6 +323,7 @@ stylesheets-check: generate-stylesheets
|
|||
.PHONY: generate-stylesheets
|
||||
generate-stylesheets:
|
||||
node_modules/.bin/lessc --clean-css public/less/index.less public/css/index.css
|
||||
$(foreach file, $(filter-out public/less/themes/_base.less, $(wildcard public/less/themes/*)),node_modules/.bin/lessc --clean-css public/less/themes/$(notdir $(file)) > public/css/theme-$(notdir $(call strip-suffix,$(file))).css;)
|
||||
|
||||
.PHONY: swagger-ui
|
||||
swagger-ui:
|
||||
|
|
|
@ -29,7 +29,7 @@ This project has been
|
|||
|
||||
From the root of the source tree, run:
|
||||
|
||||
make generate all
|
||||
TAGS="bindata" make generate all
|
||||
|
||||
More info: https://docs.gitea.io/en-us/install-from-source/
|
||||
|
||||
|
@ -90,6 +90,10 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
|
|||
|
||||
Gitea is pronounced [/ɡɪ’ti:/](https://youtu.be/EM71-2uDAoY) as in "gi-tea" with a hard g.
|
||||
|
||||
**Why is this not hosted on a Gitea instance?**
|
||||
|
||||
We're [working on it](https://github.com/go-gitea/gitea/issues/1029).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License.
|
||||
|
|
18
README_ZH.md
18
README_ZH.md
|
@ -11,16 +11,9 @@
|
|||
[![GitHub release](https://img.shields.io/github/release/go-gitea/gitea.svg)](https://github.com/go-gitea/gitea/releases/latest)
|
||||
[![Become a backer/sponsor of gitea](https://opencollective.com/gitea/tiers/backer/badge.svg?label=backer&color=brightgreen)](https://opencollective.com/gitea)
|
||||
|
||||
| | | |
|
||||
|:---:|:---:|:---:|
|
||||
|![Dashboard](https://image.ibb.co/dms6DG/1.png)|![Repository](https://image.ibb.co/m6MSLw/2.png)|![Commits History](https://image.ibb.co/cjrSLw/3.png)|
|
||||
|![Branches](https://image.ibb.co/e6vbDG/4.png)|![Issues](https://image.ibb.co/bJTJSb/5.png)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|
||||
|![Releases](https://image.ibb.co/cUzgfw/7.png)|![Activity](https://image.ibb.co/eZgGDG/8.png)|![Wiki](https://image.ibb.co/dYV9YG/9.png)|
|
||||
|![Diff](https://image.ibb.co/ewA9YG/10.png)|![Organization](https://image.ibb.co/ceOwDG/11.png)|![Profile](https://image.ibb.co/c44Q7b/12.png)|
|
||||
|
||||
## 目标
|
||||
|
||||
Gitea的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用Go作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了x86,amd64,还包括 ARM 和 PowerPC。
|
||||
Gitea 的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。我们采用 Go 作为后端语言,这使我们只要生成一个可执行程序即可。并且他还支持跨平台,支持 Linux, macOS 和 Windows 以及各种架构,除了 x86,amd64,还包括 ARM 和 PowerPC。
|
||||
|
||||
如果您想试用一下,请访问 [在线Demo](https://try.gitea.io/)!
|
||||
|
||||
|
@ -47,3 +40,12 @@ Fork -> Patch -> Push -> Pull Request
|
|||
## 授权许可
|
||||
|
||||
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](https://github.com/go-gitea/gitea/blob/master/LICENSE) 文件中。
|
||||
|
||||
## 截图
|
||||
|
||||
| | | |
|
||||
|:---:|:---:|:---:|
|
||||
|![Dashboard](https://image.ibb.co/dms6DG/1.png)|![Repository](https://image.ibb.co/m6MSLw/2.png)|![Commits History](https://image.ibb.co/cjrSLw/3.png)|
|
||||
|![Branches](https://image.ibb.co/e6vbDG/4.png)|![Issues](https://image.ibb.co/bJTJSb/5.png)|![Pull Request View](https://image.ibb.co/e02dSb/6.png)|
|
||||
|![Releases](https://image.ibb.co/cUzgfw/7.png)|![Activity](https://image.ibb.co/eZgGDG/8.png)|![Wiki](https://image.ibb.co/dYV9YG/9.png)|
|
||||
|![Diff](https://image.ibb.co/ewA9YG/10.png)|![Organization](https://image.ibb.co/ceOwDG/11.png)|![Profile](https://image.ibb.co/c44Q7b/12.png)|
|
||||
|
|
286
cmd/admin.go
286
cmd/admin.go
|
@ -7,9 +7,12 @@ package cmd
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"code.gitea.io/git"
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth/oauth2"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
|
@ -26,6 +29,7 @@ var (
|
|||
subcmdChangePassword,
|
||||
subcmdRepoSyncReleases,
|
||||
subcmdRegenerate,
|
||||
subcmdAuth,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -121,6 +125,121 @@ var (
|
|||
},
|
||||
},
|
||||
}
|
||||
|
||||
subcmdAuth = cli.Command{
|
||||
Name: "auth",
|
||||
Usage: "Modify external auth providers",
|
||||
Subcommands: []cli.Command{
|
||||
microcmdAuthAddOauth,
|
||||
microcmdAuthUpdateOauth,
|
||||
microcmdAuthList,
|
||||
microcmdAuthDelete,
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthList = cli.Command{
|
||||
Name: "list",
|
||||
Usage: "List auth sources",
|
||||
Action: runListAuth,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config, c",
|
||||
Value: "custom/conf/app.ini",
|
||||
Usage: "Custom configuration file path",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
idFlag = cli.Int64Flag{
|
||||
Name: "id",
|
||||
Usage: "ID of OAuth authentication source",
|
||||
}
|
||||
|
||||
microcmdAuthDelete = cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete specific auth source",
|
||||
Action: runDeleteAuth,
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config, c",
|
||||
Value: "custom/conf/app.ini",
|
||||
Usage: "Custom configuration file path",
|
||||
},
|
||||
idFlag,
|
||||
},
|
||||
}
|
||||
|
||||
oauthCLIFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "config, c",
|
||||
Value: "custom/conf/app.ini",
|
||||
Usage: "Custom configuration file path",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "name",
|
||||
Value: "",
|
||||
Usage: "Application Name",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "provider",
|
||||
Value: "",
|
||||
Usage: "OAuth2 Provider",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "key",
|
||||
Value: "",
|
||||
Usage: "Client ID (Key)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "secret",
|
||||
Value: "",
|
||||
Usage: "Client Secret",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "auto-discover-url",
|
||||
Value: "",
|
||||
Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "use-custom-urls",
|
||||
Value: "false",
|
||||
Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "custom-auth-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Authorization URL (option for GitLab/GitHub)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "custom-token-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Token URL (option for GitLab/GitHub)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "custom-profile-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Profile URL (option for GitLab/GitHub)",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "custom-email-url",
|
||||
Value: "",
|
||||
Usage: "Use a custom Email URL (option for GitHub)",
|
||||
},
|
||||
}
|
||||
|
||||
microcmdAuthUpdateOauth = cli.Command{
|
||||
Name: "update-oauth",
|
||||
Usage: "Update existing Oauth authentication source",
|
||||
Action: runUpdateOauth,
|
||||
Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...),
|
||||
}
|
||||
|
||||
microcmdAuthAddOauth = cli.Command{
|
||||
Name: "add-oauth",
|
||||
Usage: "Add new Oauth authentication source",
|
||||
Action: runAddOauth,
|
||||
Flags: oauthCLIFlags,
|
||||
}
|
||||
)
|
||||
|
||||
func runChangePassword(c *cli.Context) error {
|
||||
|
@ -262,3 +381,170 @@ func runRegenerateKeys(c *cli.Context) error {
|
|||
}
|
||||
return models.RewriteAllPublicKeys()
|
||||
}
|
||||
|
||||
func parseOAuth2Config(c *cli.Context) *models.OAuth2Config {
|
||||
var customURLMapping *oauth2.CustomURLMapping
|
||||
if c.IsSet("use-custom-urls") {
|
||||
customURLMapping = &oauth2.CustomURLMapping{
|
||||
TokenURL: c.String("custom-token-url"),
|
||||
AuthURL: c.String("custom-auth-url"),
|
||||
ProfileURL: c.String("custom-profile-url"),
|
||||
EmailURL: c.String("custom-email-url"),
|
||||
}
|
||||
} else {
|
||||
customURLMapping = nil
|
||||
}
|
||||
return &models.OAuth2Config{
|
||||
Provider: c.String("provider"),
|
||||
ClientID: c.String("key"),
|
||||
ClientSecret: c.String("secret"),
|
||||
OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"),
|
||||
CustomURLMapping: customURLMapping,
|
||||
}
|
||||
}
|
||||
|
||||
func runAddOauth(c *cli.Context) error {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
if err := initDB(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := models.CreateLoginSource(&models.LoginSource{
|
||||
Type: models.LoginOAuth2,
|
||||
Name: c.String("name"),
|
||||
IsActived: true,
|
||||
Cfg: parseOAuth2Config(c),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runUpdateOauth(c *cli.Context) error {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
if err := initDB(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := models.GetLoginSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oAuth2Config := source.OAuth2()
|
||||
|
||||
if c.IsSet("name") {
|
||||
source.Name = c.String("name")
|
||||
}
|
||||
|
||||
if c.IsSet("provider") {
|
||||
oAuth2Config.Provider = c.String("provider")
|
||||
}
|
||||
|
||||
if c.IsSet("key") {
|
||||
oAuth2Config.ClientID = c.String("key")
|
||||
}
|
||||
|
||||
if c.IsSet("secret") {
|
||||
oAuth2Config.ClientSecret = c.String("secret")
|
||||
}
|
||||
|
||||
if c.IsSet("auto-discover-url") {
|
||||
oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url")
|
||||
}
|
||||
|
||||
// update custom URL mapping
|
||||
var customURLMapping *oauth2.CustomURLMapping
|
||||
|
||||
if oAuth2Config.CustomURLMapping != nil {
|
||||
customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL
|
||||
customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL
|
||||
customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL
|
||||
customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL
|
||||
}
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") {
|
||||
customURLMapping.TokenURL = c.String("custom-token-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") {
|
||||
customURLMapping.AuthURL = c.String("custom-auth-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") {
|
||||
customURLMapping.ProfileURL = c.String("custom-profile-url")
|
||||
}
|
||||
|
||||
if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") {
|
||||
customURLMapping.EmailURL = c.String("custom-email-url")
|
||||
}
|
||||
|
||||
oAuth2Config.CustomURLMapping = customURLMapping
|
||||
source.Cfg = oAuth2Config
|
||||
|
||||
if err := models.UpdateSource(source); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runListAuth(c *cli.Context) error {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
if err := initDB(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
loginSources, err := models.LoginSources()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// loop through each source and print
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight)
|
||||
fmt.Fprintf(w, "ID\tName\tType\tEnabled")
|
||||
for _, source := range loginSources {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t", source.ID, source.Name, models.LoginNames[source.Type], source.IsActived)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runDeleteAuth(c *cli.Context) error {
|
||||
if c.IsSet("config") {
|
||||
setting.CustomConf = c.String("config")
|
||||
}
|
||||
|
||||
if !c.IsSet("id") {
|
||||
return fmt.Errorf("--id flag is missing")
|
||||
}
|
||||
|
||||
if err := initDB(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := models.GetLoginSourceByID(c.Int64("id"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = models.DeleteSource(source); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
16
cmd/serv.go
16
cmd/serv.go
|
@ -16,6 +16,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/pprof"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
@ -42,6 +43,9 @@ var CmdServ = cli.Command{
|
|||
Value: "custom/conf/app.ini",
|
||||
Usage: "Custom configuration file path",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "enable-pprof",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -143,6 +147,18 @@ func runServ(c *cli.Context) error {
|
|||
username := strings.ToLower(rr[0])
|
||||
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
||||
|
||||
if setting.EnablePprof || c.Bool("enable-pprof") {
|
||||
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
|
||||
fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
|
||||
}
|
||||
|
||||
stopCPUProfiler := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
|
||||
defer func() {
|
||||
stopCPUProfiler()
|
||||
pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
|
||||
}()
|
||||
}
|
||||
|
||||
isWiki := false
|
||||
unitType := models.UnitTypeCode
|
||||
if strings.HasSuffix(reponame, ".wiki") {
|
||||
|
|
33
cmd/web.go
33
cmd/web.go
|
@ -5,6 +5,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -22,6 +23,7 @@ import (
|
|||
"github.com/Unknwon/com"
|
||||
context2 "github.com/gorilla/context"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
|
@ -71,6 +73,33 @@ func runHTTPRedirector() {
|
|||
}
|
||||
}
|
||||
|
||||
func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler) error {
|
||||
certManager := autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
HostPolicy: autocert.HostWhitelist(domain),
|
||||
Cache: autocert.DirCache(directory),
|
||||
Email: email,
|
||||
}
|
||||
go http.ListenAndServe(listenAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validatio happens here)
|
||||
server := &http.Server{
|
||||
Addr: listenAddr,
|
||||
Handler: m,
|
||||
TLSConfig: &tls.Config{
|
||||
GetCertificate: certManager.GetCertificate,
|
||||
},
|
||||
}
|
||||
return server.ListenAndServeTLS("", "")
|
||||
}
|
||||
|
||||
func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" && r.Method != "HEAD" {
|
||||
http.Error(w, "Use HTTPS", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
target := setting.AppURL + r.URL.RequestURI()
|
||||
http.Redirect(w, r, target, http.StatusFound)
|
||||
}
|
||||
|
||||
func runWeb(ctx *cli.Context) error {
|
||||
if ctx.IsSet("config") {
|
||||
setting.CustomConf = ctx.String("config")
|
||||
|
@ -143,6 +172,10 @@ func runWeb(ctx *cli.Context) error {
|
|||
case setting.HTTP:
|
||||
err = runHTTP(listenAddr, context2.ClearHandler(m))
|
||||
case setting.HTTPS:
|
||||
if setting.EnableLetsEncrypt {
|
||||
err = runLetsEncrypt(listenAddr, setting.Domain, setting.LetsEncryptDirectory, setting.LetsEncryptEmail, context2.ClearHandler(m))
|
||||
break
|
||||
}
|
||||
if setting.RedirectOtherPort {
|
||||
go runHTTPRedirector()
|
||||
}
|
||||
|
|
|
@ -60,6 +60,10 @@ FILE_MAX_SIZE = 3
|
|||
; Max number of files per upload. Defaults to 5
|
||||
MAX_FILES = 5
|
||||
|
||||
[repository.pull-request]
|
||||
; List of prefixes used in Pull Request title to mark them as Work In Progress
|
||||
WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP]
|
||||
|
||||
[ui]
|
||||
; Number of repositories that are displayed on one explore page
|
||||
EXPLORE_PAGING_NUM = 20
|
||||
|
@ -67,6 +71,10 @@ EXPLORE_PAGING_NUM = 20
|
|||
ISSUE_PAGING_NUM = 10
|
||||
; Number of maximum commits displayed in one activity feed
|
||||
FEED_MAX_COMMIT_NUM = 5
|
||||
; Number of maximum commits displayed in commit graph.
|
||||
GRAPH_MAX_COMMIT_NUM = 100
|
||||
; Number of line of codes shown for a code comment
|
||||
CODE_COMMENT_LINES = 4
|
||||
; Value of `theme-color` meta tag, used by Android >= 5.0
|
||||
; An invalid color like "none" or "disable" will have the default style
|
||||
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
|
||||
|
@ -75,13 +83,15 @@ THEME_COLOR_META_TAG = `#6cc644`
|
|||
MAX_DISPLAY_FILE_SIZE = 8388608
|
||||
; Whether the email of the user should be shown in the Explore Users page
|
||||
SHOW_USER_EMAIL = true
|
||||
; Set the default theme for the Gitea install
|
||||
DEFAULT_THEME = gitea
|
||||
|
||||
[ui.admin]
|
||||
; Number of users that are displayed on one page
|
||||
USER_PAGING_NUM = 50
|
||||
; Number of repos that are displayed on one page
|
||||
REPO_PAGING_NUM = 50
|
||||
; Number of notices that are displayed on in one page
|
||||
; Number of notices that are displayed on one page
|
||||
NOTICE_PAGING_NUM = 25
|
||||
; Number of organizations that are displayed on one page
|
||||
ORG_PAGING_NUM = 50
|
||||
|
@ -181,6 +191,12 @@ STATIC_ROOT_PATH =
|
|||
APP_DATA_PATH = data
|
||||
; Application level GZIP support
|
||||
ENABLE_GZIP = false
|
||||
; Application profiling (memory and cpu)
|
||||
; For "web" command it listens on localhost:6060
|
||||
; For "serve" command it dumps to disk at PPROF_DATA_PATH as (cpuprofile|memprofile)_<username>_<temporary id>
|
||||
ENABLE_PPROF = false
|
||||
; PPROF_DATA_PATH, use an absolute path when you start gitea as service
|
||||
PPROF_DATA_PATH = data/tmp/pprof
|
||||
; Landing page, can be "home", "explore", or "organizations"
|
||||
LANDING_PAGE = home
|
||||
; Enables git-lfs support. true or false, default is false.
|
||||
|
@ -207,9 +223,10 @@ NAME = gitea
|
|||
USER = root
|
||||
; Use PASSWD = `your password` for quoting if you use special characters in the password.
|
||||
PASSWD =
|
||||
; For "postgres" only, either "disable", "require" or "verify-full"
|
||||
; For Postgres, either "disable" (default), "require", or "verify-full"
|
||||
; For MySQL, either "false" (default), "true", or "skip-verify"
|
||||
SSL_MODE = disable
|
||||
; For "sqlite3" and "tidb", use absolute path when you start gitea as service
|
||||
; For "sqlite3" and "tidb", use an absolute path when you start gitea as service
|
||||
PATH = data/gitea.db
|
||||
; For "sqlite3" only. Query timeout
|
||||
SQLITE_TIMEOUT = 500
|
||||
|
@ -301,13 +318,22 @@ ENABLE_NOTIFY_MAIL = false
|
|||
ENABLE_REVERSE_PROXY_AUTHENTICATION = false
|
||||
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
|
||||
; Enable captcha validation for registration
|
||||
ENABLE_CAPTCHA = true
|
||||
ENABLE_CAPTCHA = false
|
||||
; Type of captcha you want to use. Options: image, recaptcha
|
||||
CAPTCHA_TYPE = image
|
||||
; Enable recaptcha to use Google's recaptcha service
|
||||
; Go to https://www.google.com/recaptcha/admin to sign up for a key
|
||||
RECAPTCHA_SECRET =
|
||||
RECAPTCHA_SITEKEY =
|
||||
; Default value for KeepEmailPrivate
|
||||
; Each new user will get the value of this setting copied into their profile
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
; Default value for AllowCreateOrganization
|
||||
; Every new user will have rights set to create organizations depending on this setting
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
; Default value for EnableDependencies
|
||||
; Repositories will use depencies by default depending on this setting
|
||||
DEFAULT_ENABLE_DEPENDENCIES = true
|
||||
; Enable Timetracking
|
||||
ENABLE_TIMETRACKING = true
|
||||
; Default value for EnableTimetracking
|
||||
|
@ -568,8 +594,8 @@ DEFAULT_INTERVAL = 8h
|
|||
MIN_INTERVAL = 10m
|
||||
|
||||
[api]
|
||||
; Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
|
||||
ENABLE_SWAGGER_ENDPOINT = true
|
||||
; Enables Swagger. True or false; default is true.
|
||||
ENABLE_SWAGGER = true
|
||||
; Max number of items in a page
|
||||
MAX_RESPONSE_ITEMS = 50
|
||||
|
||||
|
|
|
@ -29,4 +29,3 @@ AllowUsers git
|
|||
|
||||
Banner none
|
||||
Subsystem sftp /usr/lib/ssh/sftp-server
|
||||
UsePrivilegeSeparation no
|
||||
|
|
|
@ -4,6 +4,9 @@ RUN_MODE = $RUN_MODE
|
|||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
|
||||
|
@ -14,6 +17,7 @@ HTTP_PORT = $HTTP_PORT
|
|||
ROOT_URL = $ROOT_URL
|
||||
DISABLE_SSH = $DISABLE_SSH
|
||||
SSH_PORT = $SSH_PORT
|
||||
LFS_CONTENT_PATH = /data/git/lfs
|
||||
|
||||
[database]
|
||||
PATH = /data/gitea/gitea.db
|
||||
|
@ -23,6 +27,9 @@ NAME = $DB_NAME
|
|||
USER = $DB_USER
|
||||
PASSWD = $DB_PASSWD
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
public/
|
||||
templates/swagger/v1_json.tmpl
|
||||
themes/
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# build stage
|
||||
FROM golang:alpine AS build-env
|
||||
|
||||
RUN apk add --no-cache git
|
||||
RUN go get -d -v github.com/mholt/caddy/caddy github.com/pedronasser/caddy-search github.com/simia-tech/caddy-locale
|
||||
WORKDIR /go/src/github.com/mholt/caddy/caddy
|
||||
|
||||
RUN sed -i '/This is where other plugins get plugged in (imported)/a _ "github.com/pedronasser/caddy-search"' caddymain/run.go \
|
||||
&& sed -i '/This is where other plugins get plugged in (imported)/a _ "github.com/simia-tech/caddy-locale"' caddymain/run.go \
|
||||
&& go install -v . \
|
||||
&& /go/bin/caddy -version
|
||||
|
||||
FROM alpine:edge
|
||||
EXPOSE 80
|
||||
|
||||
RUN apk add --no-cache wget mailcap ca-certificates
|
||||
COPY --from=build-env /go/bin/caddy /usr/sbin/caddy
|
||||
|
||||
COPY docker/caddy.conf /etc/caddy.conf
|
||||
COPY public /srv/www
|
||||
|
||||
CMD ["/usr/sbin/caddy", "-conf", "/etc/caddy.conf"]
|
|
@ -31,7 +31,7 @@ menu:
|
|||
post: active
|
||||
- name: API
|
||||
url: https://try.gitea.io/api/swagger
|
||||
weight: 25
|
||||
weight: 45
|
||||
pre: plug
|
||||
- name: Blog
|
||||
url: https://blog.gitea.io/
|
||||
|
@ -79,7 +79,7 @@ languages:
|
|||
post: active
|
||||
- name: API
|
||||
url: https://try.gitea.io/api/swagger
|
||||
weight: 25
|
||||
weight: 45
|
||||
pre: plug
|
||||
- name: 博客
|
||||
url: https://blog.gitea.io/
|
||||
|
@ -122,7 +122,7 @@ languages:
|
|||
post: active
|
||||
- name: API
|
||||
url: https://try.gitea.io/api/swagger
|
||||
weight: 25
|
||||
weight: 45
|
||||
pre: plug
|
||||
- name: 部落格
|
||||
url: https://blog.gitea.io/
|
||||
|
@ -165,7 +165,7 @@ languages:
|
|||
post: active
|
||||
- name: API
|
||||
url: https://try.gitea.io/api/swagger
|
||||
weight: 25
|
||||
weight: 45
|
||||
pre: plug
|
||||
- name: Blog
|
||||
url: https://blog.gitea.io/
|
||||
|
@ -208,7 +208,7 @@ languages:
|
|||
post: active
|
||||
- name: API
|
||||
url: https://try.gitea.io/api/swagger
|
||||
weight: 25
|
||||
weight: 45
|
||||
pre: plug
|
||||
- name: Blog
|
||||
url: https://blog.gitea.io/
|
||||
|
@ -241,17 +241,17 @@ languages:
|
|||
menu:
|
||||
page:
|
||||
- name: Site
|
||||
url: /fr-fr/
|
||||
url: https://gitea.io/en-us/
|
||||
weight: 10
|
||||
pre: home
|
||||
post: active
|
||||
- name: Documentation
|
||||
url: https://docs.gitea.io/fr-fr/
|
||||
url: /fr-fr/
|
||||
weight: 20
|
||||
pre: question
|
||||
- name: API
|
||||
url: https://try.gitea.io/api/swagger
|
||||
weight: 25
|
||||
weight: 45
|
||||
pre: plug
|
||||
- name: Blog
|
||||
url: https://blog.gitea.io/
|
||||
|
|
|
@ -73,3 +73,7 @@ using BasicAuth, as follows:
|
|||
$ curl --request GET --url https://yourusername:yourpassword@gitea.your.host/api/v1/users/yourusername/tokens
|
||||
[{"name":"test","sha1":"..."},{"name":"dev","sha1":"..."}]
|
||||
```
|
||||
|
||||
## Sudo
|
||||
|
||||
The API allows admin users to sudo API requests as another user. Simply add either a `sudo=` parameter or `Sudo:` request header with the username of the user to sudo.
|
||||
|
|
|
@ -62,12 +62,18 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
HTTP protocol.
|
||||
- `USE_COMPAT_SSH_URI`: **false**: Force ssh:// clone url instead of scp-style uri when
|
||||
default SSH port is used.
|
||||
|
||||
### Repository - Pull Request (`repository.pull-request`)
|
||||
- `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request
|
||||
title to mark them as Work In Progress
|
||||
|
||||
## UI (`ui`)
|
||||
|
||||
- `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page.
|
||||
- `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues).
|
||||
- `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed.
|
||||
- `GRAPH_MAX_COMMIT_NUM`: **100**: Number of maximum commits shown in the commit graph.
|
||||
- `DEFAULT_THEME`: **gitea**: \[gitea, arc-green\]: Set the default theme for the Gitea install.
|
||||
|
||||
### UI - Admin (`ui.admin`)
|
||||
|
||||
|
@ -119,6 +125,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
- `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, redirects http requests
|
||||
on another (https) port.
|
||||
- `PORT_TO_REDIRECT`: **80**: Port used when `REDIRECT_OTHER_PORT` is true.
|
||||
- `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server).
|
||||
By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf).
|
||||
- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt.
|
||||
- `LETSENCRYPT_DIRECTORY`: **https**: Directory that Letsencrypt will use to cache information such as certs and private keys.
|
||||
- `LETSENCRYPT_EMAIL`: **email@example.com**: Email used by Letsencrypt to notify about problems with issued certificates. (No default)
|
||||
|
||||
## Database (`database`)
|
||||
|
||||
|
@ -127,7 +138,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
- `NAME`: **gitea**: Database name.
|
||||
- `USER`: **root**: Database username.
|
||||
- `PASSWD`: **\<empty\>**: Database user password. Use \`your password\` for quoting if you use special characters in the password.
|
||||
- `SSL_MODE`: **disable**: For PostgreSQL only.
|
||||
- `SSL_MODE`: **disable**: For PostgreSQL and MySQL only.
|
||||
- `PATH`: **data/gitea.db**: For SQLite3 only, the database file path.
|
||||
- `LOG_SQL`: **true**: Log the executed SQL.
|
||||
|
||||
|
@ -177,7 +188,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
- `ENABLE_REVERSE_PROXY_AUTHENTICATION`: **false**: Enable this to allow reverse proxy authentication.
|
||||
- `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: **false**: Enable this to allow auto-registration
|
||||
for reverse authentication.
|
||||
- `ENABLE_CAPTCHA`: **true**: Enable this to use captcha validation for registration.
|
||||
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
|
||||
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\]
|
||||
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
|
||||
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
|
||||
- `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default.
|
||||
|
||||
## Webhook (`webhook`)
|
||||
|
||||
|
@ -202,8 +217,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
This is common on linux systems.
|
||||
- Note that enabling sendmail will ignore all other `mailer` settings except `ENABLED`,
|
||||
`FROM` and `SENDMAIL_PATH`.
|
||||
- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system. (can be
|
||||
command or full path)
|
||||
- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be
|
||||
command or full path).
|
||||
|
||||
## Cache (`cache`)
|
||||
|
||||
|
@ -227,7 +242,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
`http://cn.gravatar.com/avatar/`.
|
||||
- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only.
|
||||
- `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see
|
||||
http://www.libravatar.org)
|
||||
[http://www.libravatar.org](http://www.libravatar.org)).
|
||||
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store local and cached files.
|
||||
|
||||
## Attachment (`attachment`)
|
||||
|
@ -279,10 +294,17 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
|||
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
|
||||
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`.
|
||||
|
||||
## Git - Timeout settings (`git.timeout`)
|
||||
- `MIGRATE`: **600**: Migrate external repositories timeout seconds.
|
||||
- `MIRROR`: **300**: Mirror external repositories timeout seconds.
|
||||
- `CLONE`: **300**: Git clone from internal repositories timeout seconds.
|
||||
- `PULL`: **300**: Git pull from internal repositories timeout seconds.
|
||||
- `GC`: **60**: Git repository GC timeout seconds.
|
||||
|
||||
## API (`api`)
|
||||
|
||||
- `ENABLE_SWAGGER_ENDPOINT`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
|
||||
- `MAX_RESPONSE_ITEMS`: **50**: Max number of items in a page
|
||||
- `MAX_RESPONSE_ITEMS`: **50**: Max number of items in a page.
|
||||
|
||||
## i18n (`i18n`)
|
||||
|
||||
|
|
|
@ -187,6 +187,13 @@ menu:
|
|||
- `MAX_GIT_DIFF_FILES`: 比较视图中的最大现实文件数目。
|
||||
- `GC_ARGS`: 执行 `git gc` 命令的参数, 比如: `--aggressive --auto`。
|
||||
|
||||
## Git - 超时设置 (`git.timeout`)
|
||||
- `MIGRATE`: **600**: 迁移外部仓库时的超时时间,单位秒
|
||||
- `MIRROR`: **300**: 镜像外部仓库的超时时间,单位秒
|
||||
- `CLONE`: **300**: 内部仓库间克隆的超时时间,单位秒
|
||||
- `PULL`: **300**: 内部仓库间拉取的超时时间,单位秒
|
||||
- `GC`: **60**: git仓库GC的超时时间,单位秒
|
||||
|
||||
## markup (`markup`)
|
||||
|
||||
外部渲染工具支持,你可以用你熟悉的文档渲染工具. 比如一下将新增一个名字为 `asciidoc` 的渲染工具which is followed `markup.` ini section. And there are some config items below.
|
||||
|
|
|
@ -59,7 +59,7 @@ to override can be found in the `templates` directory of Gitea source. Override
|
|||
making a copy of the file under `custom/templates` using a full path structure
|
||||
matching source.
|
||||
|
||||
Any statement contained inside `{{` and `}}` are Gitea's templete syntax and
|
||||
Any statement contained inside `{{` and `}}` are Gitea's template syntax and
|
||||
shouldn't be touched without fully understanding these components.
|
||||
|
||||
### Adding links and tabs
|
||||
|
@ -91,3 +91,7 @@ Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful temp
|
|||
## Customizing gitignores, labels, licenses, locales, and readmes.
|
||||
|
||||
Place custom files in corresponding sub-folder under `custom/options`.
|
||||
|
||||
## Customizing the look of Gitea
|
||||
|
||||
Gitea has two built-in themes, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options.
|
||||
|
|
|
@ -66,4 +66,3 @@ For documentation about each of the variables available, refer to the
|
|||
## Miscellaneous
|
||||
|
||||
* `SKIP_MINWINSVC`: If set to 1, do not run as a service on Windows.
|
||||
* `ZOOKEEPER_PATH`: [Zookeeper](http://zookeeper.apache.org/) jar file path
|
||||
|
|
|
@ -37,6 +37,9 @@ _Symbols used in table:_
|
|||
| Multiple OS support | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ |
|
||||
| Easy upgrade process | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ |
|
||||
| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Orgmode support | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | ? |
|
||||
| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ? |
|
||||
| Third-party render tool support | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ? |
|
||||
| Static Git-powered pages | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Integrated Git-powered wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
|
@ -53,7 +56,7 @@ _Symbols used in table:_
|
|||
|---------|-------|------|-----------|-----------|-----------|-----------|--------------|
|
||||
| Repository topics | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Repository code search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Global code search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Global code search | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ |
|
||||
| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ⁄ | ✓ |
|
||||
| Group Milestones | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Granular user roles (Code, Issues, Wiki etc) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
|
@ -74,7 +77,7 @@ _Symbols used in table:_
|
|||
| Issue templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Labels | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Time tracking | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Multiple assignees for issues | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Multiple assignees for issues | ✓ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ |
|
||||
| Related issues | ✘ | ✘ | ⁄ | ✘ | ✓ | ✘ | ✘ |
|
||||
| Confidential issues | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Comment reactions | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
|
@ -84,6 +87,7 @@ _Symbols used in table:_
|
|||
| Create new branches from issues | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| Issue search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Global issue search | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Issue dependency | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ |
|
||||
|
||||
#### Pull/Merge requests
|
||||
|
||||
|
@ -92,8 +96,8 @@ _Symbols used in table:_
|
|||
| Pull/Merge requests | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Squash merging | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ |
|
||||
| Rebase merging | ✓ | ✓ | ✓ | ✘ | ⁄ | ✘ | ✓ |
|
||||
| Pull/Merge request inline comments | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request approval | ✘ | ✘ | ⁄ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request inline comments | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Pull/Merge request approval | ✓ | ✘ | ⁄ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Merge conflict resolution | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| Restrict push and merge access to certain users | ✓ | ✘ | ✓ | ⁄ | ✓ | ✓ | ✓ |
|
||||
| Revert specific commits or a merge request | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
|
|
|
@ -21,10 +21,18 @@ the destination platform from the [downloads page](https://dl.gitea.io/gitea), c
|
|||
the URL and replace the URL within the commands below:
|
||||
|
||||
```sh
|
||||
wget -O gitea https://dl.gitea.io/gitea/1.4.2/gitea-1.4.2-linux-amd64
|
||||
wget -O gitea https://dl.gitea.io/gitea/1.5.0/gitea-1.5.0-linux-amd64
|
||||
chmod +x gitea
|
||||
```
|
||||
|
||||
## Verify GPG signature
|
||||
Gitea signs all binaries with a [GPG key](https://pgp.mit.edu/pks/lookup?op=vindex&fingerprint=on&search=0x2D9AE806EC1592E2) to prevent against unwanted modification of binaries. To validate the binary download the signature file which ends in `.asc` for the binary you downloaded and use the gpg command line tool.
|
||||
|
||||
```sh
|
||||
gpg --keyserver pgp.mit.edu --recv 0x2D9AE806EC1592E2
|
||||
gpg --verify gitea-1.5.0-linux-amd64.asc gitea-1.5.0-linux-amd64
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
After getting a binary, it can be tested with `./gitea web` or moved to a permanent
|
||||
|
@ -82,6 +90,20 @@ cp gitea /usr/local/bin/gitea
|
|||
|
||||
See how to create [Linux service]({{< relref "run-as-service-in-ubuntu.en-us.md" >}})
|
||||
|
||||
## Updating to a new version
|
||||
|
||||
You can update to a new version of gitea by stopping gitea, replacing the binary at `/usr/local/bin/gitea` and restarting the instance.
|
||||
The binary file name should not be changed during the update to avoid problems
|
||||
in existing repositories.
|
||||
|
||||
It is recommended you do a [backup]({{< relref "doc/usage/backup-and-restore.en-us.md" >}}) before updating your installation.
|
||||
|
||||
If you have carried out the installation steps as described above, the binary should
|
||||
have the generic name `gitea`. Do not change this, i.e. to include the version number.
|
||||
|
||||
See below for troubleshooting instructions to repair broken repositories after
|
||||
an update of your gitea version.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Old glibc versions
|
||||
|
@ -99,3 +121,25 @@ For errors like `702 runWeb()] [E] Failed to start server: listen tcp 0.0.0.0:30
|
|||
bind: address already in use` gitea needs to be started on another free port. This
|
||||
is possible using `./gitea web -p $PORT`. It's possible another instance of gitea
|
||||
is already running.
|
||||
|
||||
### Git error after updating to a new version of gitea
|
||||
|
||||
If the binary file name has been changed during the update to a new version of gitea,
|
||||
git hooks in existing repositories will not work any more. In that case, a git
|
||||
error will be displayed when pushing to the repository.
|
||||
|
||||
```
|
||||
remote: ./hooks/pre-receive.d/gitea: line 2: [...]: No such file or directory
|
||||
```
|
||||
|
||||
The `[...]` part of the error message will contain the path to your previous gitea
|
||||
binary.
|
||||
|
||||
To solve this, go to the admin options and run the task `Resynchronize pre-receive,
|
||||
update and post-receive hooks of all repositories` to update all hooks to contain
|
||||
the new binary path. Please note that this overwrite all git hooks including ones
|
||||
with customizations made.
|
||||
|
||||
If you aren't using the built-in to Gitea ssh server you will also need to re-write
|
||||
the authorized key file by running the `Update the '.ssh/authorized_keys' file with
|
||||
Gitea SSH keys.` task in the admin options.
|
||||
|
|
|
@ -64,3 +64,16 @@ bundled templates, options, plugins and themes are in `/usr/local/share/gitea`,
|
|||
is in `/usr/local/etc/rc.d/gitea`.
|
||||
|
||||
To enable Gitea to run as a service, run `sysrc gitea_enable=YES` and start it with `service gitea start`.
|
||||
|
||||
## Cloudron
|
||||
|
||||
Gitea is available as a 1-click install on [Cloudron](https://cloudron.io). For those unaware,
|
||||
Cloudron makes it easy to run apps like Gitea on your server and keep them up-to-date and secure.
|
||||
|
||||
[![Install](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=io.gitea.cloudronapp)
|
||||
|
||||
The Gitea package is maintained [here](https://git.cloudron.io/cloudron/gitea-app).
|
||||
|
||||
There is a [demo instance](https://my-demo.cloudron.me) (username: cloudron password: cloudron) where
|
||||
you can experiment with running Gitea.
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ image as a service. Since there is no database available one can be initialized
|
|||
Create a directory like `gitea` and paste the following content into a file named `docker-compose.yml`.
|
||||
Note that the volume should be owned by the user/group with the UID/GID specified in the config file.
|
||||
If you don't give the volume correct permissions, the container may not start.
|
||||
Also be aware that the tag `:latest` will install the current development version.
|
||||
For a stable release you can use `:1` or specify a certain release like `:1.5.1`.
|
||||
|
||||
```yaml
|
||||
version: "2"
|
||||
|
@ -103,6 +105,11 @@ services:
|
|||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
+ - DB_TYPE=mysql
|
||||
+ - DB_HOST=db:3306
|
||||
+ - DB_NAME=gitea
|
||||
+ - DB_USER=gitea
|
||||
+ - DB_PASSWD=gitea
|
||||
restart: always
|
||||
networks:
|
||||
- gitea
|
||||
|
@ -146,6 +153,11 @@ services:
|
|||
environment:
|
||||
- USER_UID=1000
|
||||
- USER_GID=1000
|
||||
+ - DB_TYPE=postgres
|
||||
+ - DB_HOST=db:5432
|
||||
+ - DB_NAME=gitea
|
||||
+ - DB_USER=gitea
|
||||
+ - DB_PASSWD=gitea
|
||||
restart: always
|
||||
networks:
|
||||
- gitea
|
||||
|
|
|
@ -33,50 +33,53 @@ There are some basic steps to follow. On a Linux system run as the Gogs user:
|
|||
* Enter Gitea admin panel on the UI, run `Rewrite '.ssh/authorized_keys' file`.
|
||||
* If custom or config path was changed, run `Rewrite all update hook of repositories`.
|
||||
|
||||
### Change gogs specific information:
|
||||
## Change gogs specific information
|
||||
|
||||
* Rename `gogs-repositories/` to `gitea-repositories/`
|
||||
* Rename `gogs-data/` to `gitea-data/`
|
||||
* In `gitea/custom/conf/app.ini` change:
|
||||
|
||||
### Upgrading to most recent `gitea` version:
|
||||
FROM:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
TO:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
* Verify by starting Gitea with `gitea web`
|
||||
|
||||
## Upgrading to most recent `gitea` version
|
||||
|
||||
After successful migration from `gogs` to `gitea 1.0.x` it is possible to upgrade to the recent `gitea` version.
|
||||
Simply download the file matching the destination platform from the [downloads page](https://dl.gitea.io/gitea)
|
||||
and replace the binary.
|
||||
|
||||
FROM:
|
||||
```
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
TO:
|
||||
```
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
* Verify by starting Gitea with `gitea web`
|
||||
|
||||
### Troubleshooting
|
||||
## Troubleshooting
|
||||
|
||||
* If errors are encountered relating to custom templates in the `gitea/custom/templates`
|
||||
folder, try moving the templates causing the errors away one by one. They may not be
|
||||
compatible with Gitea or an update.
|
||||
|
||||
### Add Gitea to startup on Unix
|
||||
## Add Gitea to startup on Unix
|
||||
|
||||
Update the appropriate file from [gitea/contrib](https://github.com/go-gitea/gitea/tree/master/contrib)
|
||||
with the right environment variables.
|
||||
|
|
|
@ -19,7 +19,7 @@ menu:
|
|||
|
||||
Veuillez suivre les étapes ci-dessous. Sur Unix, toute les commandes s'exécutent en tant que l'utilisateur utilisé pour votre installation de Gogs :
|
||||
|
||||
* Crééer une sauvegarde de Gogs avec la commande `gogs dump`. Le fichier nouvellement créé `gogs-dump-[timestamp].zip` contient toutes les données de votre instance de Gogs.
|
||||
* Crééer une sauvegarde de Gogs avec la commande `gogs dump`. Le fichier nouvellement créé `gogs-dump-[timestamp].zip` contient toutes les données de votre instance de Gogs.
|
||||
* Téléchargez le fichier correspondant à votre plateforme à partir de la [page de téléchargements](https://dl.gitea.io/gitea).
|
||||
* Mettez la binaire dans le répertoire d'installation souhaité.
|
||||
* Copiez le fichier `gogs/custom/conf/app.ini` vers `gitea/custom/conf/app.ini`.
|
||||
|
@ -29,43 +29,45 @@ Veuillez suivre les étapes ci-dessous. Sur Unix, toute les commandes s'exécute
|
|||
* Vérifiez votre installation en exécutant Gitea avec la commande `gitea web`.
|
||||
* Connectez vous au panel d'administration de Gitea et exécutez l'action `Rewrite '.ssh/authorized_keys' file`, puis l'action `Rewrite all update hook of repositories` (obligatoire si le chemin menant à votre configuration personnalisée à changé).
|
||||
|
||||
### Modifier les informations spécifiques de gogs
|
||||
## Modifier les informations spécifiques de gogs
|
||||
|
||||
* Renommez `gogs-repositories/` vers `gitea-repositories/`
|
||||
* Renommez `gogs-data/` to `gitea-data/`
|
||||
* Dans votre fichier `gitea/custom/conf/app.ini`, modifiez les éléments suivants:
|
||||
|
||||
DE :
|
||||
```
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
DE :
|
||||
|
||||
VERS :
|
||||
```
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gogs/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gogs-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gogs/log
|
||||
```
|
||||
|
||||
VERS :
|
||||
|
||||
```ini
|
||||
[database]
|
||||
PATH = /home/:USER/gitea/data/:DATABASE.db
|
||||
[attachment]
|
||||
PATH = /home/:USER/gitea-data/attachments
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars
|
||||
[log]
|
||||
ROOT_PATH = /home/:USER/gitea/log
|
||||
```
|
||||
|
||||
* Vérifiez votre installation en exécutant Gitea avec la commande `gitea web`.
|
||||
|
||||
### Dépannage
|
||||
## Dépannage
|
||||
|
||||
* Si vous rencontrez des erreurs relatives à des modèles personnalisés dans le dossier `gitea/custom/templates`, essayez de déplacer un par un les modèles provoquant les erreurs. Il est possible qu'ils ne soient pas compatibles avec Gitea.
|
||||
|
||||
### Démarrer automatiquement Gitea (Unix)
|
||||
## Démarrer automatiquement Gitea (Unix)
|
||||
|
||||
Distributions utilisant systemd:
|
||||
|
||||
|
|
|
@ -72,6 +72,50 @@ Admin operations:
|
|||
- Examples:
|
||||
- `gitea admin regenerate hooks`
|
||||
- `gitea admin regenerate keys`
|
||||
- `auth`:
|
||||
- `list`:
|
||||
- Description: lists all external authentication sources that exist
|
||||
- Options:
|
||||
- `--config path`: Gitea configuration file path. Optional. (default: custom/conf/app.ini).
|
||||
- Examples:
|
||||
- `gitea auth list`
|
||||
- `delete`:
|
||||
- Options:
|
||||
- `--id`: ID of source to be deleted. Required.
|
||||
- `--config path`: Gitea configuration file path. Optional. (default: custom/conf/app.ini).
|
||||
- Examples:
|
||||
- `gitea auth delete --id 1`
|
||||
- `add-oauth`:
|
||||
- Options:
|
||||
- `--config path`: Gitea configuration file path. Optional. (default: custom/conf/app.ini).
|
||||
- `--name`: Application Name.
|
||||
- `--provider`: OAuth2 Provider.
|
||||
- `--key`: Client ID (Key).
|
||||
- `--secret`: Client Secret.
|
||||
- `--auto-discover-url`: OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider).
|
||||
- `--use-custom-urls`: Use custom URLs for GitLab/GitHub OAuth endpoints.
|
||||
- `--custom-auth-url`: Use a custom Authorization URL (option for GitLab/GitHub).
|
||||
- `--custom-token-url`: Use a custom Token URL (option for GitLab/GitHub).
|
||||
- `--custom-profile-url`: Use a custom Profile URL (option for GitLab/GitHub).
|
||||
- `--custom-email-url`: Use a custom Email URL (option for GitHub).
|
||||
- Examples:
|
||||
- `gitea auth add-oauth --name external-github --provider github --key OBTAIN_FROM_SOURCE --secret OBTAIN_FROM_SOURCE`
|
||||
- `update-oauth`:
|
||||
- Options:
|
||||
- `--id`: ID of source to be updated. Required.
|
||||
- `--config path`: Gitea configuration file path. Optional. (default: custom/conf/app.ini).
|
||||
- `--name`: Application Name.
|
||||
- `--provider`: OAuth2 Provider.
|
||||
- `--key`: Client ID (Key).
|
||||
- `--secret`: Client Secret.
|
||||
- `--auto-discover-url`: OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider).
|
||||
- `--use-custom-urls`: Use custom URLs for GitLab/GitHub OAuth endpoints.
|
||||
- `--custom-auth-url`: Use a custom Authorization URL (option for GitLab/GitHub).
|
||||
- `--custom-token-url`: Use a custom Token URL (option for GitLab/GitHub).
|
||||
- `--custom-profile-url`: Use a custom Profile URL (option for GitLab/GitHub).
|
||||
- `--custom-email-url`: Use a custom Email URL (option for GitHub).
|
||||
- Examples:
|
||||
- `gitea auth update-oauth --id 1 --name external-github-updated`
|
||||
|
||||
#### cert
|
||||
|
||||
|
|
|
@ -32,6 +32,24 @@ KEY_FILE = key.pem
|
|||
```
|
||||
To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server).
|
||||
|
||||
## Using Let's Encrypt
|
||||
|
||||
[Let's Encrypt](https://letsencrypt.org/) is a Certificate Authority that allows you to automatically request and renew SSL/TLS certificates. In addition to starting Gitea on your configured port, to request HTTPS certificates Gitea will also need to listed on port 80, and will set up an autoredirect to HTTPS for you. Let's Encrypt will need to be able to access Gitea via the Internet to verify your ownership of the domain.
|
||||
|
||||
By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf)
|
||||
|
||||
```ini
|
||||
[server]
|
||||
PROTOCOL=https
|
||||
DOMAIN=git.example.com
|
||||
ENABLE_LETSENCRYPT=true
|
||||
LETSENCRYPT_ACCEPTTOS=true
|
||||
LETSENCRYPT_DIRECTORY=https
|
||||
LETSENCRYPT_EMAIL=email@example.com
|
||||
```
|
||||
|
||||
To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server).
|
||||
|
||||
## Using reverse proxy
|
||||
|
||||
Setup up your reverse proxy like shown in the [reverse proxy guide](../reverse-proxies).
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
date: "2018-06-01T19:00:00+02:00"
|
||||
title: "Usage: Pull Request"
|
||||
slug: "pull-request"
|
||||
weight: 13
|
||||
toc: true
|
||||
draft: false
|
||||
menu:
|
||||
sidebar:
|
||||
parent: "usage"
|
||||
name: "Pull Request"
|
||||
weight: 13
|
||||
identifier: "pull-request"
|
||||
---
|
||||
|
||||
# Pull Request
|
||||
|
||||
## "Work In Progress" pull requests
|
||||
|
||||
Marking a pull request as being a work in progress will prevent that pull request from being accidentally merged. To mark a pull request as being a work in progress, you must prefix its title by `WIP:` or `[WIP]` (case insensitive). Those values are configurable in your `app.ini` file :
|
||||
|
||||
```
|
||||
[repository.pull-request]
|
||||
WORK_IN_PROGRESS_PREFIXES=WIP:,[WIP]
|
||||
```
|
||||
|
||||
The first value of the list will be used in helpers.
|
||||
|
||||
## Pull Request Templates
|
||||
|
||||
You can find more information about pull request templates in the dedicated page : [Issue and Pull Request templates](../issue-pull-request-templates)
|
|
@ -1,44 +0,0 @@
|
|||
:80 {
|
||||
root /srv/www
|
||||
|
||||
locale en-US zh-CN zh-TW pt-BR nl-NL fr-FR {
|
||||
detect header
|
||||
}
|
||||
|
||||
redir 301 {
|
||||
if {path} match ^/$
|
||||
/ /{>Detected-Locale}/
|
||||
}
|
||||
|
||||
rewrite /en-US/ {
|
||||
regexp (.*)
|
||||
to /en-us/{1}
|
||||
}
|
||||
|
||||
rewrite /zh-CN/ {
|
||||
regexp (.*)
|
||||
to /zh-cn/{1}
|
||||
}
|
||||
|
||||
rewrite /zh-TW/ {
|
||||
regexp (.*)
|
||||
to /zh-tw/{1}
|
||||
}
|
||||
|
||||
rewrite /pt-BR/ {
|
||||
regexp (.*)
|
||||
to /pt-br/{1}
|
||||
}
|
||||
|
||||
rewrite /nl-NL/ {
|
||||
regexp (.*)
|
||||
to /nl-nl/{1}
|
||||
}
|
||||
|
||||
rewrite /fr-FR/ {
|
||||
regexp (.*)
|
||||
to /fr-fr/{1}
|
||||
}
|
||||
|
||||
header / Vary "Accept-Language"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/*
|
||||
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://cdnjs.cloudflare.com https://fonts.gstatic.com
|
||||
X-Frame-Options: DENY
|
||||
X-Xss-Protection: 1; mode=block
|
||||
X-Content-Type-Options: nosniff
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
|
@ -0,0 +1,8 @@
|
|||
https://gitea-docs.netlify.com/* https://docs.gitea.io/:splat 302!
|
||||
|
||||
/ /fr-fr/ 302! Language=fr
|
||||
/ /nl-nl/ 302! Language=nl
|
||||
/ /pt-br/ 302! Language=pt-br
|
||||
/ /zh-cn/ 302! Language=zh-cn
|
||||
/ /zh-tw/ 302! Language=zh-tw
|
||||
/ /en-us/ 302!
|
|
@ -11,6 +11,8 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
||||
|
@ -19,7 +21,8 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
|||
session := loginUser(t, "user1")
|
||||
keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
|
||||
"title": "test-key",
|
||||
|
@ -36,7 +39,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
|||
OwnerID: keyOwner.ID,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
|
||||
keyOwner.Name, newPublicKey.ID)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
|
||||
|
@ -47,7 +50,8 @@ func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {
|
|||
// user1 is an admin user
|
||||
session := loginUser(t, "user1")
|
||||
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d", models.NonexistentID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token="+token, models.NonexistentID)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
|
@ -57,7 +61,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
|||
normalUsername := "user2"
|
||||
session := loginUser(t, adminUsername)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", adminUsername, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
|
||||
"title": "test-key",
|
||||
|
@ -67,7 +72,37 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
|||
DecodeJSON(t, resp, &newPublicKey)
|
||||
|
||||
session = loginUser(t, normalUsername)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
|
||||
adminUsername, newPublicKey.ID)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
||||
func TestAPISudoUser(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
session := loginUser(t, adminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user?sudo=%s&token=%s", normalUsername, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var user api.User
|
||||
DecodeJSON(t, resp, &user)
|
||||
|
||||
assert.Equal(t, normalUsername, user.UserName)
|
||||
}
|
||||
|
||||
func TestAPISudoUserForbidden(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
adminUsername := "user1"
|
||||
normalUsername := "user2"
|
||||
|
||||
session := loginUser(t, normalUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/user?sudo=%s&token=%s", adminUsername, token)
|
||||
req := NewRequest(t, "GET", urlStr)
|
||||
session.MakeRequest(t, req, http.StatusForbidden)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,8 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
|
|||
prepareTestEnv(t)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s", branchName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
|
||||
resp := session.MakeRequest(t, req, NoExpectedStatus)
|
||||
if !exists {
|
||||
assert.EqualValues(t, http.StatusNotFound, resp.Code)
|
||||
|
|
|
@ -69,8 +69,9 @@ func TestAPICreateComment(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments",
|
||||
repoOwner.Name, repo.Name, issue.Index)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
|
||||
repoOwner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
|
||||
"body": commentBody,
|
||||
})
|
||||
|
@ -93,8 +94,9 @@ func TestAPIEditComment(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d",
|
||||
repoOwner.Name, repo.Name, comment.ID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||
repoOwner.Name, repo.Name, comment.ID, token)
|
||||
req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
|
||||
"body": newCommentBody,
|
||||
})
|
||||
|
@ -117,8 +119,9 @@ func TestAPIDeleteComment(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d",
|
||||
repoOwner.Name, repo.Name, comment.ID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
|
||||
repoOwner.Name, repo.Name, comment.ID, token)
|
||||
session.MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
models.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
|
||||
|
|
|
@ -20,16 +20,18 @@ type makeRequestFunc func(testing.TB, *http.Request, int) *httptest.ResponseReco
|
|||
func TestGPGKeys(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
makeRequest makeRequestFunc
|
||||
token string
|
||||
results []int
|
||||
}{
|
||||
{name: "NoLogin", makeRequest: MakeRequest,
|
||||
{name: "NoLogin", makeRequest: MakeRequest, token: "",
|
||||
results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
|
||||
},
|
||||
{name: "LoggedAsUser2", makeRequest: session.MakeRequest,
|
||||
{name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
|
||||
results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusInternalServerError, http.StatusInternalServerError, http.StatusCreated, http.StatusCreated}},
|
||||
}
|
||||
|
||||
|
@ -38,29 +40,29 @@ func TestGPGKeys(t *testing.T) {
|
|||
//Basic test on result code
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Run("ViewOwnGPGKeys", func(t *testing.T) {
|
||||
testViewOwnGPGKeys(t, tc.makeRequest, tc.results[0])
|
||||
testViewOwnGPGKeys(t, tc.makeRequest, tc.token, tc.results[0])
|
||||
})
|
||||
t.Run("ViewGPGKeys", func(t *testing.T) {
|
||||
testViewGPGKeys(t, tc.makeRequest, tc.results[1])
|
||||
testViewGPGKeys(t, tc.makeRequest, tc.token, tc.results[1])
|
||||
})
|
||||
t.Run("GetGPGKey", func(t *testing.T) {
|
||||
testGetGPGKey(t, tc.makeRequest, tc.results[2])
|
||||
testGetGPGKey(t, tc.makeRequest, tc.token, tc.results[2])
|
||||
})
|
||||
t.Run("DeleteGPGKey", func(t *testing.T) {
|
||||
testDeleteGPGKey(t, tc.makeRequest, tc.results[3])
|
||||
testDeleteGPGKey(t, tc.makeRequest, tc.token, tc.results[3])
|
||||
})
|
||||
|
||||
t.Run("CreateInvalidGPGKey", func(t *testing.T) {
|
||||
testCreateInvalidGPGKey(t, tc.makeRequest, tc.results[4])
|
||||
testCreateInvalidGPGKey(t, tc.makeRequest, tc.token, tc.results[4])
|
||||
})
|
||||
t.Run("CreateNoneRegistredEmailGPGKey", func(t *testing.T) {
|
||||
testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.results[5])
|
||||
testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[5])
|
||||
})
|
||||
t.Run("CreateValidGPGKey", func(t *testing.T) {
|
||||
testCreateValidGPGKey(t, tc.makeRequest, tc.results[6])
|
||||
testCreateValidGPGKey(t, tc.makeRequest, tc.token, tc.results[6])
|
||||
})
|
||||
t.Run("CreateValidSecondaryEmailGPGKey", func(t *testing.T) {
|
||||
testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.results[7])
|
||||
testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[7])
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -70,7 +72,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
|
||||
var keys []*api.GPGKey
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys") //GET all keys
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token) //GET all keys
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &keys)
|
||||
|
||||
|
@ -91,7 +93,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
assert.EqualValues(t, false, primaryKey2.Emails[0].Verified)
|
||||
|
||||
var key api.GPGKey
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)) //Primary key 1
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)+"?token="+token) //Primary key 1
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
|
||||
|
@ -99,13 +101,13 @@ func TestGPGKeys(t *testing.T) {
|
|||
assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
|
||||
assert.EqualValues(t, true, key.Emails[0].Verified)
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)) //Subkey of 38EA3BCED732982C
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)+"?token="+token) //Subkey of 38EA3BCED732982C
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
|
||||
assert.EqualValues(t, 0, len(key.Emails))
|
||||
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)) //Primary key 2
|
||||
req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)+"?token="+token) //Primary key 2
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &key)
|
||||
assert.EqualValues(t, "FABF39739FE1E927", key.KeyID)
|
||||
|
@ -119,7 +121,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
t.Run("CheckCommits", func(t *testing.T) {
|
||||
t.Run("NotSigned", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed")
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, false, branch.Commit.Verification.Verified)
|
||||
|
@ -127,7 +129,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
|
||||
t.Run("SignedWithNotValidatedEmail", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated")
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, false, branch.Commit.Verification.Verified)
|
||||
|
@ -135,7 +137,7 @@ func TestGPGKeys(t *testing.T) {
|
|||
|
||||
t.Run("SignedWithValidEmail", func(t *testing.T) {
|
||||
var branch api.Branch
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign")
|
||||
req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign?token="+token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &branch)
|
||||
assert.EqualValues(t, true, branch.Commit.Verification.Verified)
|
||||
|
@ -143,39 +145,39 @@ func TestGPGKeys(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys")
|
||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys")
|
||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1")
|
||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1")
|
||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1?token="+token)
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int, publicKey string) {
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys", api.CreateGPGKeyOption{
|
||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int, publicKey string) {
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys?token="+token, api.CreateGPGKeyOption{
|
||||
ArmoredKey: publicKey,
|
||||
})
|
||||
makeRequest(t, req, expected)
|
||||
}
|
||||
|
||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, expected, "invalid_key")
|
||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, token, expected, "invalid_key")
|
||||
}
|
||||
|
||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
|
||||
dCMCG2T1UwzUB/yWUFWJ2BtCwSjuaRv+cGohqEy6bhEBV90peGA33lHfjx7wP25O
|
||||
|
@ -194,9 +196,9 @@ INx/MmBfmtCq05FqNclvU+sj2R3N1JJOtBOjZrJHQbJhzoILou8AkxeX1A+q9OAz
|
|||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
||||
|
||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
//User2 <user2@example.com> //primary & activated
|
||||
testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx/6/I4Slm94+wXf8YNRvAyqj30dW
|
||||
VJhyBcnfNRDLKSQp5o/hhfDkCgdqBjLa1PnHlGS3PXJc0hP/FyYPD2BFvNMPpCYS
|
||||
|
@ -228,9 +230,9 @@ uy6MA3VSB99SK9ducGmE1Jv8mcziREroz2TEGr0zPs6h
|
|||
-----END PGP PUBLIC KEY BLOCK-----`)
|
||||
}
|
||||
|
||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
|
||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
|
||||
//User2 <user21@example.com> //secondary and not activated
|
||||
testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFmGWN4BCAC18V4tVGO65VLCV7p14FuXJlUtZ5CuYMvgEkcOqrvRaBSW9ao4
|
||||
PGESOhJpfWpnW3QgJniYndLzPpsmdHEclEER6aZjiNgReWPOjHD5tykWocZAJqXD
|
||||
|
|
|
@ -23,12 +23,13 @@ func TestAPIAddIssueLabels(t *testing.T) {
|
|||
label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
|
||||
owner.Name, repo.Name, issue.Index)
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
|
||||
owner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
|
||||
Labels: []int64{label.ID},
|
||||
})
|
||||
session := loginUser(t, owner.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
|
@ -45,12 +46,13 @@ func TestAPIReplaceIssueLabels(t *testing.T) {
|
|||
label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
|
||||
owner.Name, repo.Name, issue.Index)
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
|
||||
owner.Name, repo.Name, issue.Index, token)
|
||||
req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{
|
||||
Labels: []int64{label.ID},
|
||||
})
|
||||
session := loginUser(t, owner.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiLabels []*api.Label
|
||||
DecodeJSON(t, resp, &apiLabels)
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -22,8 +22,9 @@ func TestAPIListIssues(t *testing.T) {
|
|||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all",
|
||||
owner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all&token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiIssues []*api.Issue
|
||||
DecodeJSON(t, resp, &apiIssues)
|
||||
|
@ -41,8 +42,8 @@ func TestAPICreateIssue(t *testing.T) {
|
|||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
|
||||
Body: body,
|
||||
Title: title,
|
||||
|
|
|
@ -46,8 +46,8 @@ func TestCreateReadOnlyDeployKey(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "read-only",
|
||||
Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
|
||||
|
@ -72,8 +72,8 @@ func TestCreateReadWriteDeployKey(t *testing.T) {
|
|||
repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, repoOwner.Name)
|
||||
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
|
||||
rawKeyBody := api.CreateKeyOption{
|
||||
Title: "read-write",
|
||||
Key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsufOCrDDlT8DLkodnnJtbq7uGflcPae7euTfM+Laq4So+v4WeSV362Rg0O/+Sje1UthrhN6lQkfRkdWIlCRQEXg+LMqr6RhvDfZquE2Xwqv/itlz7LjbdAUdYoO1iH7rMSmYvQh4WEnC/DAacKGbhdGIM/ZBz0z6tHm7bPgbI9ykEKekTmPwQFP1Qebvf5NYOFMWqQ2sCEAI9dBMVLoojsIpV+KADf+BotiIi8yNfTG2rzmzpxBpW9fYjd1Sy1yd4NSUpoPbEJJYJ1TrjiSWlYOVq9Ar8xW1O87i6gBjL/3zN7ANeoYhaAXupdOS6YL22YOK/yC0tJtXwwdh/eSrh",
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -20,7 +23,8 @@ func TestAPIViewPulls(t *testing.T) {
|
|||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all", owner.Name, repo.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+token, owner.Name, repo.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var pulls []*api.PullRequest
|
||||
|
@ -28,3 +32,27 @@ func TestAPIViewPulls(t *testing.T) {
|
|||
expectedLen := models.GetCount(t, &models.Issue{RepoID: repo.ID}, models.Cond("is_pull = ?", true))
|
||||
assert.Len(t, pulls, expectedLen)
|
||||
}
|
||||
|
||||
// TestAPIMergePullWIP ensures that we can't merge a WIP pull request
|
||||
func TestAPIMergePullWIP(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
pr := models.AssertExistsAndLoadBean(t, &models.PullRequest{Status: models.PullRequestStatusMergeable}, models.Cond("has_merged = ?", false)).(*models.PullRequest)
|
||||
pr.LoadIssue()
|
||||
pr.Issue.ChangeTitle(owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title)
|
||||
|
||||
// force reload
|
||||
pr.LoadAttributes()
|
||||
|
||||
assert.Contains(t, pr.Issue.Title, setting.Repository.PullRequest.WorkInProgressPrefixes[0])
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/merge?token=%s", owner.Name, repo.Name, pr.Index, token), &auth.MergePullRequestForm{
|
||||
MergeMessageField: pr.Issue.Title,
|
||||
Do: string(models.MergeStyleMerge),
|
||||
})
|
||||
|
||||
session.MakeRequest(t, req, http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestAPICreateRelease(t *testing.T) {
|
|||
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
session := loginUser(t, owner.LowerName)
|
||||
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
@ -32,8 +32,8 @@ func TestAPICreateRelease(t *testing.T) {
|
|||
commitID, err := gitRepo.GetTagCommitID("v0.0.1")
|
||||
assert.NoError(t, err)
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases",
|
||||
owner.Name, repo.Name)
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
|
||||
owner.Name, repo.Name, token)
|
||||
req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
|
||||
TagName: "v0.0.1",
|
||||
Title: "v0.0.1",
|
||||
|
@ -53,8 +53,8 @@ func TestAPICreateRelease(t *testing.T) {
|
|||
Note: newRelease.Note,
|
||||
})
|
||||
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d",
|
||||
owner.Name, repo.Name, newRelease.ID)
|
||||
urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d?token=%s",
|
||||
owner.Name, repo.Name, newRelease.ID, token)
|
||||
req = NewRequest(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
|
|
|
@ -16,16 +16,17 @@ func TestAPIReposRaw(t *testing.T) {
|
|||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
for _, ref := range [...]string{
|
||||
"master", // Branch
|
||||
"v1.1", // Tag
|
||||
"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
|
||||
} {
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md", user.Name, ref)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
// Test default branch
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md", user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
|
|
@ -67,16 +67,16 @@ func TestAPISearchRepo(t *testing.T) {
|
|||
expectedResults
|
||||
}{
|
||||
{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{
|
||||
nil: {count: 16},
|
||||
user: {count: 16},
|
||||
user2: {count: 16}},
|
||||
nil: {count: 19},
|
||||
user: {count: 19},
|
||||
user2: {count: 19}},
|
||||
},
|
||||
{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10}},
|
||||
},
|
||||
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search", expectedResults: expectedResults{
|
||||
{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{
|
||||
nil: {count: 10},
|
||||
user: {count: 10},
|
||||
user2: {count: 10}},
|
||||
|
@ -143,9 +143,11 @@ func TestAPISearchRepo(t *testing.T) {
|
|||
var session *TestSession
|
||||
var testName string
|
||||
var userID int64
|
||||
var token string
|
||||
if userToLogin != nil && userToLogin.ID > 0 {
|
||||
testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
|
||||
session = loginUser(t, userToLogin.Name)
|
||||
token = getTokenForLoggedInUser(t, session)
|
||||
userID = userToLogin.ID
|
||||
} else {
|
||||
testName = "AnonymousUser"
|
||||
|
@ -153,7 +155,7 @@ func TestAPISearchRepo(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
request := NewRequest(t, "GET", testCase.requestURL)
|
||||
request := NewRequest(t, "GET", testCase.requestURL+"&token="+token)
|
||||
response := session.MakeRequest(t, request, http.StatusOK)
|
||||
|
||||
var body api.SearchResults
|
||||
|
@ -214,8 +216,8 @@ func TestAPIOrgRepos(t *testing.T) {
|
|||
sourceOrg := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)
|
||||
// Login as User2.
|
||||
session := loginUser(t, user.Name)
|
||||
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", sourceOrg.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiRepos []*api.Repository
|
||||
|
@ -231,7 +233,58 @@ func TestAPIOrgRepos(t *testing.T) {
|
|||
func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)
|
||||
sess := loginUser(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repositories/2")
|
||||
sess.MakeRequest(t, req, http.StatusNotFound)
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token)
|
||||
session.MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func TestAPIRepoMigrate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ctxUserID, userID int64
|
||||
cloneURL, repoName string
|
||||
expectedStatus int
|
||||
}{
|
||||
{ctxUserID: 1, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-admin", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-own", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad", expectedStatus: http.StatusForbidden},
|
||||
{ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-org", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden},
|
||||
}
|
||||
|
||||
prepareTestEnv(t)
|
||||
for _, testCase := range testCases {
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOption{
|
||||
CloneAddr: testCase.cloneURL,
|
||||
UID: int(testCase.userID),
|
||||
RepoName: testCase.repoName,
|
||||
})
|
||||
session.MakeRequest(t, req, testCase.expectedStatus)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAPIOrgRepoCreate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
ctxUserID int64
|
||||
orgName, repoName string
|
||||
expectedStatus int
|
||||
}{
|
||||
{ctxUserID: 1, orgName: "user3", repoName: "repo-admin", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, orgName: "user3", repoName: "repo-own", expectedStatus: http.StatusCreated},
|
||||
{ctxUserID: 2, orgName: "user6", repoName: "repo-bad-org", expectedStatus: http.StatusForbidden},
|
||||
}
|
||||
|
||||
prepareTestEnv(t)
|
||||
for _, testCase := range testCases {
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
|
||||
session := loginUser(t, user.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos?token="+token, testCase.orgName), &api.CreateRepoOption{
|
||||
Name: testCase.repoName,
|
||||
})
|
||||
session.MakeRequest(t, req, testCase.expectedStatus)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ func TestAPITeam(t *testing.T) {
|
|||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: teamUser.UID}).(*models.User)
|
||||
|
||||
session := loginUser(t, user.Name)
|
||||
req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
var apiTeam api.Team
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2018 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 integrations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
api "code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
// TestAPICreateAndDeleteToken tests that token that was just created can be deleted
|
||||
func TestAPICreateAndDeleteToken(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)
|
||||
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/users/user1/tokens", map[string]string{
|
||||
"name": "test-key-1",
|
||||
})
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
resp := MakeRequest(t, req, http.StatusCreated)
|
||||
|
||||
var newAccessToken api.AccessToken
|
||||
DecodeJSON(t, resp, &newAccessToken)
|
||||
models.AssertExistsAndLoadBean(t, &models.AccessToken{
|
||||
ID: newAccessToken.ID,
|
||||
Name: newAccessToken.Name,
|
||||
Sha1: newAccessToken.Sha1,
|
||||
UID: user.ID,
|
||||
})
|
||||
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", newAccessToken.ID)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNoContent)
|
||||
|
||||
models.AssertNotExistsBean(t, &models.AccessToken{ID: newAccessToken.ID})
|
||||
}
|
||||
|
||||
// TestAPIDeleteMissingToken ensures that error is thrown when token not found
|
||||
func TestAPIDeleteMissingToken(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)
|
||||
|
||||
req := NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", models.NonexistentID)
|
||||
req = AddBasicAuthHeader(req, user.Name)
|
||||
MakeRequest(t, req, http.StatusNotFound)
|
||||
}
|
|
@ -75,7 +75,8 @@ func TestGit(t *testing.T) {
|
|||
|
||||
t.Run("CreateRepo", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
|
||||
AutoInit: true,
|
||||
Description: "Temporary repo",
|
||||
Name: "repo-tmp-17",
|
||||
|
@ -166,7 +167,8 @@ func TestGit(t *testing.T) {
|
|||
t.Run("Standard", func(t *testing.T) {
|
||||
t.Run("CreateRepo", func(t *testing.T) {
|
||||
session := loginUser(t, "user2")
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
|
||||
AutoInit: true,
|
||||
Description: "Temporary repo",
|
||||
Name: "repo-tmp-18",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
ref: refs/heads/master
|
|
@ -0,0 +1,4 @@
|
|||
[core]
|
||||
repositoryformatversion = 0
|
||||
filemode = true
|
||||
bare = true
|
|
@ -0,0 +1 @@
|
|||
Unnamed repository; edit this file 'description' to name the repository.
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message taken by
|
||||
# applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit. The hook is
|
||||
# allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "applypatch-msg".
|
||||
|
||||
. git-sh-setup
|
||||
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||
:
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to check the commit log message.
|
||||
# Called by "git commit" with one argument, the name of the file
|
||||
# that has the commit message. The hook should exit with non-zero
|
||||
# status after issuing an appropriate message if it wants to stop the
|
||||
# commit. The hook is allowed to edit the commit message file.
|
||||
#
|
||||
# To enable this hook, rename this file to "commit-msg".
|
||||
|
||||
# Uncomment the below to add a Signed-off-by line to the message.
|
||||
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||
# hook is more suited to it.
|
||||
#
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||
|
||||
# This example catches duplicate Signed-off-by lines.
|
||||
|
||||
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||
echo >&2 Duplicate Signed-off-by lines.
|
||||
exit 1
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
ORI_DIR=`pwd`
|
||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
cd "$ORI_DIR"
|
||||
for i in `ls "$SHELL_FOLDER/post-receive.d"`; do
|
||||
sh "$SHELL_FOLDER/post-receive.d/$i"
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare a packed repository for use over
|
||||
# dumb transports.
|
||||
#
|
||||
# To enable this hook, rename this file to "post-update".
|
||||
|
||||
exec git update-server-info
|
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed
|
||||
# by applypatch from an e-mail message.
|
||||
#
|
||||
# The hook should exit with non-zero status after issuing an
|
||||
# appropriate message if it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-applypatch".
|
||||
|
||||
. git-sh-setup
|
||||
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||
:
|
|
@ -0,0 +1,49 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to verify what is about to be committed.
|
||||
# Called by "git commit" with no arguments. The hook should
|
||||
# exit with non-zero status after issuing an appropriate message if
|
||||
# it wants to stop the commit.
|
||||
#
|
||||
# To enable this hook, rename this file to "pre-commit".
|
||||
|
||||
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||
then
|
||||
against=HEAD
|
||||
else
|
||||
# Initial commit: diff against an empty tree object
|
||||
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||
fi
|
||||
|
||||
# If you want to allow non-ASCII filenames set this variable to true.
|
||||
allownonascii=$(git config --bool hooks.allownonascii)
|
||||
|
||||
# Redirect output to stderr.
|
||||
exec 1>&2
|
||||
|
||||
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||
# them from being added to the repository. We exploit the fact that the
|
||||
# printable range starts at the space character and ends with tilde.
|
||||
if [ "$allownonascii" != "true" ] &&
|
||||
# Note that the use of brackets around a tr range is ok here, (it's
|
||||
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||
# the square bracket bytes happen to fall in the designated range.
|
||||
test $(git diff --cached --name-only --diff-filter=A -z $against |
|
||||
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||
then
|
||||
cat <<\EOF
|
||||
Error: Attempt to add a non-ASCII file name.
|
||||
|
||||
This can cause problems if you want to work with people on other platforms.
|
||||
|
||||
To be portable it is advisable to rename the file.
|
||||
|
||||
If you know what you are doing you can disable this check using:
|
||||
|
||||
git config hooks.allownonascii true
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If there are whitespace errors, print the offending file names and fail.
|
||||
exec git diff-index --check --cached $against --
|
|
@ -0,0 +1,53 @@
|
|||
#!/bin/sh
|
||||
|
||||
# An example hook script to verify what is about to be pushed. Called by "git
|
||||
# push" after it has checked the remote status, but before anything has been
|
||||
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||
#
|
||||
# This hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- Name of the remote to which the push is being done
|
||||
# $2 -- URL to which the push is being done
|
||||
#
|
||||
# If pushing without using a named remote those arguments will be equal.
|
||||
#
|
||||
# Information about the commits which are being pushed is supplied as lines to
|
||||
# the standard input in the form:
|
||||
#
|
||||
# <local ref> <local sha1> <remote ref> <remote sha1>
|
||||
#
|
||||
# This sample shows how to prevent push of commits where the log message starts
|
||||
# with "WIP" (work in progress).
|
||||
|
||||
remote="$1"
|
||||
url="$2"
|
||||
|
||||
z40=0000000000000000000000000000000000000000
|
||||
|
||||
while read local_ref local_sha remote_ref remote_sha
|
||||
do
|
||||
if [ "$local_sha" = $z40 ]
|
||||
then
|
||||
# Handle delete
|
||||
:
|
||||
else
|
||||
if [ "$remote_sha" = $z40 ]
|
||||
then
|
||||
# New branch, examine all commits
|
||||
range="$local_sha"
|
||||
else
|
||||
# Update to existing branch, examine new commits
|
||||
range="$remote_sha..$local_sha"
|
||||
fi
|
||||
|
||||
# Check for WIP commit
|
||||
commit=`git rev-list -n 1 --grep '^WIP' "$range"`
|
||||
if [ -n "$commit" ]
|
||||
then
|
||||
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit 0
|
|
@ -0,0 +1,169 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||
#
|
||||
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||
# its job, and can prevent the command from running by exiting with
|
||||
# non-zero status.
|
||||
#
|
||||
# The hook is called with the following parameters:
|
||||
#
|
||||
# $1 -- the upstream the series was forked from.
|
||||
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||
#
|
||||
# This sample shows how to prevent topic branches that are already
|
||||
# merged to 'next' branch from getting rebased, because allowing it
|
||||
# would result in rebasing already published history.
|
||||
|
||||
publish=next
|
||||
basebranch="$1"
|
||||
if test "$#" = 2
|
||||
then
|
||||
topic="refs/heads/$2"
|
||||
else
|
||||
topic=`git symbolic-ref HEAD` ||
|
||||
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||
fi
|
||||
|
||||
case "$topic" in
|
||||
refs/heads/??/*)
|
||||
;;
|
||||
*)
|
||||
exit 0 ;# we do not interrupt others.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Now we are dealing with a topic branch being rebased
|
||||
# on top of master. Is it OK to rebase it?
|
||||
|
||||
# Does the topic really exist?
|
||||
git show-ref -q "$topic" || {
|
||||
echo >&2 "No such branch $topic"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Is topic fully merged to master?
|
||||
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||
if test -z "$not_in_master"
|
||||
then
|
||||
echo >&2 "$topic is fully merged to master; better remove it."
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
fi
|
||||
|
||||
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||
if test "$only_next_1" = "$only_next_2"
|
||||
then
|
||||
not_in_topic=`git rev-list "^$topic" master`
|
||||
if test -z "$not_in_topic"
|
||||
then
|
||||
echo >&2 "$topic is already up-to-date with master"
|
||||
exit 1 ;# we could allow it, but there is no point.
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
else
|
||||
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||
/usr/bin/perl -e '
|
||||
my $topic = $ARGV[0];
|
||||
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||
my (%not_in_next) = map {
|
||||
/^([0-9a-f]+) /;
|
||||
($1 => 1);
|
||||
} split(/\n/, $ARGV[1]);
|
||||
for my $elem (map {
|
||||
/^([0-9a-f]+) (.*)$/;
|
||||
[$1 => $2];
|
||||
} split(/\n/, $ARGV[2])) {
|
||||
if (!exists $not_in_next{$elem->[0]}) {
|
||||
if ($msg) {
|
||||
print STDERR $msg;
|
||||
undef $msg;
|
||||
}
|
||||
print STDERR " $elem->[1]\n";
|
||||
}
|
||||
}
|
||||
' "$topic" "$not_in_next" "$not_in_master"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
<<\DOC_END
|
||||
|
||||
This sample hook safeguards topic branches that have been
|
||||
published from being rewound.
|
||||
|
||||
The workflow assumed here is:
|
||||
|
||||
* Once a topic branch forks from "master", "master" is never
|
||||
merged into it again (either directly or indirectly).
|
||||
|
||||
* Once a topic branch is fully cooked and merged into "master",
|
||||
it is deleted. If you need to build on top of it to correct
|
||||
earlier mistakes, a new topic branch is created by forking at
|
||||
the tip of the "master". This is not strictly necessary, but
|
||||
it makes it easier to keep your history simple.
|
||||
|
||||
* Whenever you need to test or publish your changes to topic
|
||||
branches, merge them into "next" branch.
|
||||
|
||||
The script, being an example, hardcodes the publish branch name
|
||||
to be "next", but it is trivial to make it configurable via
|
||||
$GIT_DIR/config mechanism.
|
||||
|
||||
With this workflow, you would want to know:
|
||||
|
||||
(1) ... if a topic branch has ever been merged to "next". Young
|
||||
topic branches can have stupid mistakes you would rather
|
||||
clean up before publishing, and things that have not been
|
||||
merged into other branches can be easily rebased without
|
||||
affecting other people. But once it is published, you would
|
||||
not want to rewind it.
|
||||
|
||||
(2) ... if a topic branch has been fully merged to "master".
|
||||
Then you can delete it. More importantly, you should not
|
||||
build on top of it -- other people may already want to
|
||||
change things related to the topic as patches against your
|
||||
"master", so if you need further changes, it is better to
|
||||
fork the topic (perhaps with the same name) afresh from the
|
||||
tip of "master".
|
||||
|
||||
Let's look at this example:
|
||||
|
||||
o---o---o---o---o---o---o---o---o---o "next"
|
||||
/ / / /
|
||||
/ a---a---b A / /
|
||||
/ / / /
|
||||
/ / c---c---c---c B /
|
||||
/ / / \ /
|
||||
/ / / b---b C \ /
|
||||
/ / / / \ /
|
||||
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||
|
||||
|
||||
A, B and C are topic branches.
|
||||
|
||||
* A has one fix since it was merged up to "next".
|
||||
|
||||
* B has finished. It has been fully merged up to "master" and "next",
|
||||
and is ready to be deleted.
|
||||
|
||||
* C has not merged to "next" at all.
|
||||
|
||||
We would want to allow C to be rebased, refuse A, and encourage
|
||||
B to be deleted.
|
||||
|
||||
To compute (1):
|
||||
|
||||
git rev-list ^master ^topic next
|
||||
git rev-list ^master next
|
||||
|
||||
if these match, topic has not merged in next at all.
|
||||
|
||||
To compute (2):
|
||||
|
||||
git rev-list master..topic
|
||||
|
||||
if this is empty, it is fully merged to "master".
|
||||
|
||||
DOC_END
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
ORI_DIR=`pwd`
|
||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
cd "$ORI_DIR"
|
||||
for i in `ls "$SHELL_FOLDER/pre-receive.d"`; do
|
||||
sh "$SHELL_FOLDER/pre-receive.d/$i"
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
|
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to prepare the commit log message.
|
||||
# Called by "git commit" with the name of the file that has the
|
||||
# commit message, followed by the description of the commit
|
||||
# message's source. The hook's purpose is to edit the commit
|
||||
# message file. If the hook fails with a non-zero status,
|
||||
# the commit is aborted.
|
||||
#
|
||||
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||
|
||||
# This hook includes three examples. The first comments out the
|
||||
# "Conflicts:" part of a merge commit.
|
||||
#
|
||||
# The second includes the output of "git diff --name-status -r"
|
||||
# into the message, just before the "git status" output. It is
|
||||
# commented because it doesn't cope with --amend or with squashed
|
||||
# commits.
|
||||
#
|
||||
# The third example adds a Signed-off-by line to the message, that can
|
||||
# still be edited. This is rarely a good idea.
|
||||
|
||||
case "$2,$3" in
|
||||
merge,)
|
||||
/usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
|
||||
|
||||
# ,|template,)
|
||||
# /usr/bin/perl -i.bak -pe '
|
||||
# print "\n" . `git diff --cached --name-status -r`
|
||||
# if /^#/ && $first++ == 0' "$1" ;;
|
||||
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
ORI_DIR=`pwd`
|
||||
SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
|
||||
cd "$ORI_DIR"
|
||||
for i in `ls "$SHELL_FOLDER/update.d"`; do
|
||||
sh "$SHELL_FOLDER/update.d/$i" $1 $2 $3
|
||||
done
|
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
|
|
@ -0,0 +1,128 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# An example hook script to block unannotated tags from entering.
|
||||
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||
#
|
||||
# To enable this hook, rename this file to "update".
|
||||
#
|
||||
# Config
|
||||
# ------
|
||||
# hooks.allowunannotated
|
||||
# This boolean sets whether unannotated tags will be allowed into the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowdeletetag
|
||||
# This boolean sets whether deleting tags will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.allowmodifytag
|
||||
# This boolean sets whether a tag may be modified after creation. By default
|
||||
# it won't be.
|
||||
# hooks.allowdeletebranch
|
||||
# This boolean sets whether deleting branches will be allowed in the
|
||||
# repository. By default they won't be.
|
||||
# hooks.denycreatebranch
|
||||
# This boolean sets whether remotely creating branches will be denied
|
||||
# in the repository. By default this is allowed.
|
||||
#
|
||||
|
||||
# --- Command line
|
||||
refname="$1"
|
||||
oldrev="$2"
|
||||
newrev="$3"
|
||||
|
||||
# --- Safety check
|
||||
if [ -z "$GIT_DIR" ]; then
|
||||
echo "Don't run this script from the command line." >&2
|
||||
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Config
|
||||
allowunannotated=$(git config --bool hooks.allowunannotated)
|
||||
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
|
||||
denycreatebranch=$(git config --bool hooks.denycreatebranch)
|
||||
allowdeletetag=$(git config --bool hooks.allowdeletetag)
|
||||
allowmodifytag=$(git config --bool hooks.allowmodifytag)
|
||||
|
||||
# check for no description
|
||||
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||
case "$projectdesc" in
|
||||
"Unnamed repository"* | "")
|
||||
echo "*** Project description file hasn't been set" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Check types
|
||||
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||
zero="0000000000000000000000000000000000000000"
|
||||
if [ "$newrev" = "$zero" ]; then
|
||||
newrev_type=delete
|
||||
else
|
||||
newrev_type=$(git cat-file -t $newrev)
|
||||
fi
|
||||
|
||||
case "$refname","$newrev_type" in
|
||||
refs/tags/*,commit)
|
||||
# un-annotated tag
|
||||
short_refname=${refname##refs/tags/}
|
||||
if [ "$allowunannotated" != "true" ]; then
|
||||
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,delete)
|
||||
# delete tag
|
||||
if [ "$allowdeletetag" != "true" ]; then
|
||||
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/tags/*,tag)
|
||||
# annotated tag
|
||||
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||
then
|
||||
echo "*** Tag '$refname' already exists." >&2
|
||||
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,commit)
|
||||
# branch
|
||||
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/heads/*,delete)
|
||||
# delete branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
refs/remotes/*,commit)
|
||||
# tracking branch
|
||||
;;
|
||||
refs/remotes/*,delete)
|
||||
# delete tracking branch
|
||||
if [ "$allowdeletebranch" != "true" ]; then
|
||||
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# Anything else (is there anything else?)
|
||||
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- Finished
|
||||
exit 0
|
|
@ -0,0 +1,6 @@
|
|||
# git ls-files --others --exclude-from=.git/info/exclude
|
||||
# Lines that start with '#' are comments.
|
||||
# For a project mostly in C, the following would be a good set of
|
||||
# exclude patterns (uncomment them if you want to use them):
|
||||
# *.[oa]
|
||||
# *~
|
|
@ -0,0 +1,9 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/heads/Grüßen
|
||||
3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b refs/heads/Plus+Is+Not+Space
|
||||
3aa73c3499bff049a352b4e265575373e964b89a refs/heads/master
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/heads/ГлавнаяВетка
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/heads/а/б/в
|
||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a refs/heads/ブランチ
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/tags/Ё/人
|
||||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5 refs/tags/Тэг
|
||||
28d579e4920fbf4f66e71dab3e779d9fbf41422a refs/tags/タグ
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
x•ŽAjÄ0E»ö)´œR(²ci<PJ{Å–˜)ILo_ÓM×]}xü/×u½uDO½©‚/¤ˆ6!É9K’KT¦Hœ
|
||||
—À(EæäviºuÐÙ|dK8YÎsöñìÕЗd‚¦>¢ì…œÜûµ6¸Ú¼ý·>dÝ}Íu}OñÄ)xÁ€èi]ÿ%¹ÏRàKvÙôP°Û¢Ð똛lù
|
||||
u[¾ád£§ëÑÇ£>»²´QÑ
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
x<01><>]jC!<10>ћь*цНPtFЧ+<2B>в.e4#ЎЙС<18>ьОЖ;шг<D188>УљљЪб{<7B><><EFBFBD>_цPеФ<1B>ЋOXйгцrБbк2<D0BA>+ХygЎ2є2<D194>D"ђ)<>ѕI(`і<>BiЭљМ%1r<31>чcР§Іс§O>ѕ!§Кы[9њИ@<40><>-!МZДж,wЁM§WЩ|<7C>NPлЎ№нцЪsД}o.вцёћr<>ЁUQѓ<03>M<EFBFBD>
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b
|
|
@ -0,0 +1 @@
|
|||
3aa73c3499bff049a352b4e265575373e964b89a
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
28d579e4920fbf4f66e71dab3e779d9fbf41422a
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
|
|
@ -0,0 +1 @@
|
|||
28d579e4920fbf4f66e71dab3e779d9fbf41422a
|
|
@ -223,6 +223,22 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession
|
|||
return session
|
||||
}
|
||||
|
||||
func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
|
||||
req := NewRequest(t, "GET", "/user/settings/applications")
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
doc := NewHTMLParser(t, resp.Body)
|
||||
req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
|
||||
"_csrf": doc.GetCSRF(),
|
||||
"name": "api-testing-token",
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusFound)
|
||||
req = NewRequest(t, "GET", "/user/settings/applications")
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
token := htmlDoc.doc.Find(".ui.info p").Text()
|
||||
return token
|
||||
}
|
||||
|
||||
func NewRequest(t testing.TB, method, urlStr string) *http.Request {
|
||||
return NewRequestWithBody(t, method, urlStr, nil)
|
||||
}
|
||||
|
@ -256,6 +272,11 @@ func NewRequestWithBody(t testing.TB, method, urlStr string, body io.Reader) *ht
|
|||
return request
|
||||
}
|
||||
|
||||
func AddBasicAuthHeader(request *http.Request, username string) *http.Request {
|
||||
request.SetBasicAuth(username, userPassword)
|
||||
return request
|
||||
}
|
||||
|
||||
const NoExpectedStatus = -1
|
||||
|
||||
func MakeRequest(t testing.TB, req *http.Request, expectedStatus int) *httptest.ResponseRecorder {
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
// Copyright 2018 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 integrations
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testSrcRouteRedirect(t *testing.T, session *TestSession, user, repo, route, expectedLocation string, expectedStatus int) {
|
||||
prefix := path.Join("/", user, repo, "src")
|
||||
|
||||
// Make request
|
||||
req := NewRequest(t, "GET", path.Join(prefix, route))
|
||||
resp := session.MakeRequest(t, req, http.StatusFound)
|
||||
|
||||
// Check Location header
|
||||
location := resp.HeaderMap.Get("Location")
|
||||
assert.Equal(t, path.Join(prefix, expectedLocation), location)
|
||||
|
||||
// Perform redirect
|
||||
req = NewRequest(t, "GET", location)
|
||||
resp = session.MakeRequest(t, req, expectedStatus)
|
||||
}
|
||||
|
||||
func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) {
|
||||
location := path.Join("/", user, repo, "settings/branches")
|
||||
csrf := GetCSRF(t, session, location)
|
||||
req := NewRequestWithValues(t, "POST", location, map[string]string{
|
||||
"_csrf": csrf,
|
||||
"action": "default_branch",
|
||||
"branch": branch,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusFound)
|
||||
}
|
||||
|
||||
func TestNonasciiBranches(t *testing.T) {
|
||||
testRedirects := []struct {
|
||||
from string
|
||||
to string
|
||||
status int
|
||||
}{
|
||||
// Branches
|
||||
{
|
||||
from: "master",
|
||||
to: "branch/master",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "master/README.md",
|
||||
to: "branch/master/README.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "master/badfile",
|
||||
to: "branch/master/badfile",
|
||||
status: http.StatusNotFound, // it does not exists
|
||||
},
|
||||
{
|
||||
from: "ГлавнаяВетка",
|
||||
to: "branch/%d0%93%d0%bb%d0%b0%d0%b2%d0%bd%d0%b0%d1%8f%d0%92%d0%b5%d1%82%d0%ba%d0%b0",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "а/б/в",
|
||||
to: "branch/%d0%b0/%d0%b1/%d0%b2",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Grüßen/README.md",
|
||||
to: "branch/Gr%c3%bc%c3%9fen/README.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Plus+Is+Not+Space",
|
||||
to: "branch/Plus+Is+Not+Space",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Plus+Is+Not+Space/Файл.md",
|
||||
to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Plus+Is+Not+Space/and+it+is+valid.md",
|
||||
to: "branch/Plus+Is+Not+Space/and+it+is+valid.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "ブランチ",
|
||||
to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
// Tags
|
||||
{
|
||||
from: "Тэг",
|
||||
to: "tag/%d0%a2%d1%8d%d0%b3",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Ё/人",
|
||||
to: "tag/%d0%81/%e4%ba%ba",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "タグ",
|
||||
to: "tag/%e3%82%bf%e3%82%b0",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "タグ/ファイル.md",
|
||||
to: "tag/%e3%82%bf%e3%82%b0/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
// Files
|
||||
{
|
||||
from: "README.md",
|
||||
to: "branch/Plus+Is+Not+Space/README.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Файл.md",
|
||||
to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "ファイル.md",
|
||||
to: "branch/Plus+Is+Not+Space/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
|
||||
status: http.StatusNotFound, // it's not on default branch
|
||||
},
|
||||
// Same but url-encoded (few tests)
|
||||
{
|
||||
from: "%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
|
||||
to: "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "%E3%82%BF%E3%82%b0",
|
||||
to: "tag/%e3%82%bf%e3%82%b0",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "%D0%A4%D0%B0%D0%B9%D0%BB.md",
|
||||
to: "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "%D0%81%2F%E4%BA%BA",
|
||||
to: "tag/%d0%81/%e4%ba%ba",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
{
|
||||
from: "Ё%2F%E4%BA%BA",
|
||||
to: "tag/%d0%81/%e4%ba%ba",
|
||||
status: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
prepareTestEnv(t)
|
||||
|
||||
user := "user2"
|
||||
repo := "utf8"
|
||||
session := loginUser(t, user)
|
||||
|
||||
setDefaultBranch(t, session, user, repo, "Plus+Is+Not+Space")
|
||||
|
||||
for _, test := range testRedirects {
|
||||
testSrcRouteRedirect(t, session, user, repo, test.from, test.to, test.status)
|
||||
}
|
||||
|
||||
setDefaultBranch(t, session, user, repo, "master")
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@ import (
|
|||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/Unknwon/i18n"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -123,3 +124,23 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
|
|||
|
||||
assert.EqualValues(t, "Branch 'user1/feature/test' has been deleted.", resultMsg)
|
||||
}
|
||||
|
||||
func TestCantMergeWorkInProgress(t *testing.T) {
|
||||
prepareTestEnv(t)
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
||||
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master", "[wip] This is a pull title")
|
||||
|
||||
req := NewRequest(t, "GET", resp.Header().Get("Location"))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
text := strings.TrimSpace(htmlDoc.doc.Find(".merge.segment > .text.grey").Text())
|
||||
assert.NotEmpty(t, text, "Can't find WIP text")
|
||||
|
||||
// remove <strong /> from lang
|
||||
expected := i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress", "[wip]")
|
||||
replacer := strings.NewReplacer("<strong>", "", "</strong>", "")
|
||||
assert.Equal(t, replacer.Replace(expected), text, "Unable to find WIP text")
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
|||
prepareTestEnv(t)
|
||||
|
||||
session := loginUser(t, "user2")
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Request repository commits page
|
||||
req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
|
||||
|
@ -45,7 +46,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
|||
assert.NotEmpty(t, commitURL)
|
||||
|
||||
// Call API to add status for commit
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL),
|
||||
req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL)+"?token="+token,
|
||||
api.CreateStatusOption{
|
||||
State: api.StatusState(state),
|
||||
TargetURL: "http://test.ci/",
|
||||
|
|
1
main.go
1
main.go
|
@ -14,6 +14,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
// register supported doc types
|
||||
_ "code.gitea.io/gitea/modules/markup/csv"
|
||||
_ "code.gitea.io/gitea/modules/markup/markdown"
|
||||
_ "code.gitea.io/gitea/modules/markup/orgmode"
|
||||
|
||||
|
|
|
@ -47,6 +47,9 @@ const (
|
|||
ActionReopenPullRequest // 15
|
||||
ActionDeleteTag // 16
|
||||
ActionDeleteBranch // 17
|
||||
ActionMirrorSyncPush // 18
|
||||
ActionMirrorSyncCreate // 19
|
||||
ActionMirrorSyncDelete // 20
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -122,6 +125,12 @@ func (a *Action) loadRepo() {
|
|||
}
|
||||
}
|
||||
|
||||
// GetActFullName gets the action's user full name.
|
||||
func (a *Action) GetActFullName() string {
|
||||
a.loadActUser()
|
||||
return a.ActUser.FullName
|
||||
}
|
||||
|
||||
// GetActUserName gets the action's user name.
|
||||
func (a *Action) GetActUserName() string {
|
||||
a.loadActUser()
|
||||
|
@ -471,6 +480,10 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
|||
}
|
||||
|
||||
if err = issue.ChangeStatus(doer, repo, true); err != nil {
|
||||
// Don't return an error when dependencies are open as this would let the push fail
|
||||
if IsErrDependenciesLeft(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -524,12 +537,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
|
|||
}
|
||||
|
||||
refName := git.RefEndName(opts.RefFullName)
|
||||
if repo.IsBare && refName != repo.DefaultBranch {
|
||||
|
||||
// Change default branch and bare status only if pushed ref is non-empty branch.
|
||||
if repo.IsBare && opts.NewCommitID != git.EmptySHA && strings.HasPrefix(opts.RefFullName, git.BranchPrefix) {
|
||||
repo.DefaultBranch = refName
|
||||
repo.IsBare = false
|
||||
}
|
||||
|
||||
// Change repository bare status and update last updated time.
|
||||
repo.IsBare = repo.IsBare && opts.Commits.Len <= 0
|
||||
if err = UpdateRepository(repo, false); err != nil {
|
||||
return fmt.Errorf("UpdateRepository: %v", err)
|
||||
}
|
||||
|
@ -726,6 +741,71 @@ func MergePullRequestAction(actUser *User, repo *Repository, pull *Issue) error
|
|||
return mergePullRequestAction(x, actUser, repo, pull)
|
||||
}
|
||||
|
||||
func mirrorSyncAction(e Engine, opType ActionType, repo *Repository, refName string, data []byte) error {
|
||||
if err := notifyWatchers(e, &Action{
|
||||
ActUserID: repo.OwnerID,
|
||||
ActUser: repo.MustOwner(),
|
||||
OpType: opType,
|
||||
RepoID: repo.ID,
|
||||
Repo: repo,
|
||||
IsPrivate: repo.IsPrivate,
|
||||
RefName: refName,
|
||||
Content: string(data),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("notifyWatchers: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MirrorSyncPushActionOptions mirror synchronization action options.
|
||||
type MirrorSyncPushActionOptions struct {
|
||||
RefName string
|
||||
OldCommitID string
|
||||
NewCommitID string
|
||||
Commits *PushCommits
|
||||
}
|
||||
|
||||
// MirrorSyncPushAction adds new action for mirror synchronization of pushed commits.
|
||||
func MirrorSyncPushAction(repo *Repository, opts MirrorSyncPushActionOptions) error {
|
||||
if len(opts.Commits.Commits) > setting.UI.FeedMaxCommitNum {
|
||||
opts.Commits.Commits = opts.Commits.Commits[:setting.UI.FeedMaxCommitNum]
|
||||
}
|
||||
|
||||
apiCommits := opts.Commits.ToAPIPayloadCommits(repo.HTMLURL())
|
||||
|
||||
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||
apiPusher := repo.MustOwner().APIFormat()
|
||||
if err := PrepareWebhooks(repo, HookEventPush, &api.PushPayload{
|
||||
Ref: opts.RefName,
|
||||
Before: opts.OldCommitID,
|
||||
After: opts.NewCommitID,
|
||||
CompareURL: setting.AppURL + opts.Commits.CompareURL,
|
||||
Commits: apiCommits,
|
||||
Repo: repo.APIFormat(AccessModeOwner),
|
||||
Pusher: apiPusher,
|
||||
Sender: apiPusher,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("PrepareWebhooks: %v", err)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(opts.Commits)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return mirrorSyncAction(x, ActionMirrorSyncPush, repo, opts.RefName, data)
|
||||
}
|
||||
|
||||
// MirrorSyncCreateAction adds new action for mirror synchronization of new reference.
|
||||
func MirrorSyncCreateAction(repo *Repository, refName string) error {
|
||||
return mirrorSyncAction(x, ActionMirrorSyncCreate, repo, refName, nil)
|
||||
}
|
||||
|
||||
// MirrorSyncDeleteAction adds new action for mirror synchronization of delete reference.
|
||||
func MirrorSyncDeleteAction(repo *Repository, refName string) error {
|
||||
return mirrorSyncAction(x, ActionMirrorSyncDelete, repo, refName, nil)
|
||||
}
|
||||
|
||||
// GetFeedsOptions options for retrieving feeds
|
||||
type GetFeedsOptions struct {
|
||||
RequestedUser *User
|
||||
|
|
|
@ -74,7 +74,7 @@ func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
if len(protectBranch.WhitelistTeamIDs) == 0 {
|
||||
if len(protectBranch.MergeWhitelistTeamIDs) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -184,6 +184,24 @@ func (repo *Repository) IsProtectedBranch(branchName string, doer *User) (bool,
|
|||
BranchName: branchName,
|
||||
}
|
||||
|
||||
has, err := x.Exist(protectedBranch)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return has, nil
|
||||
}
|
||||
|
||||
// IsProtectedBranchForPush checks if branch is protected for push
|
||||
func (repo *Repository) IsProtectedBranchForPush(branchName string, doer *User) (bool, error) {
|
||||
if doer == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
protectedBranch := &ProtectedBranch{
|
||||
RepoID: repo.ID,
|
||||
BranchName: branchName,
|
||||
}
|
||||
|
||||
has, err := x.Get(protectedBranch)
|
||||
if err != nil {
|
||||
return true, err
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue