Compare commits

...

82 Commits

Author SHA1 Message Date
Matti R
2f71571305 target go1.12 2019-09-07 12:40:52 -04:00
guillep2k
a182a80f7c Changelog for v1.9.3 (#8117)
* Changelog for 1.9.3

* Fix ref to 8071

* Correct punctuation

Co-Authored-By: techknowlogick <matti@mdranta.net>
2019-09-06 12:25:24 -04:00
Rutger Broekhoff
89c57487cd Fix Go 1.13 private repository go get issue (#8100)
* Fix Go 1.13 invalid import path creation

Signed-off-by: Rutger Broekhoff <rutger@viasalix.nl>

* Apply suggested changes from #8100

Signed-off-by: Rutger Broekhoff <rutger@viasalix.nl>
2019-09-06 09:59:03 -04:00
guillep2k
bb609cacee Backport: Strict name matching for Repository.GetTagID() (#8082)
* Strict name matching for Repository.GetTagID()

* Add test for GetTagID()
2019-09-04 16:37:09 +02:00
Mura Li
e7f6da386f Avoid ambiguity of branch/directory names for the git-diff-tree command (#8066) (#8070) 2019-09-03 22:58:19 +03:00
Mario Lubenka
7727f84fe8 Bugfix/deformed emoji in commit message (backport 1.9) (#8071)
* Fixes deformed emoji in pull request comments or reviews

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>

* Generate css via command

Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
2019-09-03 18:05:47 +02:00
guillep2k
5d2676089e Add change title notification for issues (#8064) 2019-09-03 11:39:53 +08:00
Tamal Saha
9bea8d825b Run CORS handler first for /api routes (#7967) (#8053)
Signed-off-by: Tamal Saha <tamal@appscode.com>
2019-09-02 08:55:33 +03:00
Mario Lubenka
3cc728870a Evaluate emojis in commit messages in list view (#7906) (#8044)
Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
(cherry picked from commit 08c63190c6)
2019-08-31 21:12:08 +08:00
Lunny Xiao
0793b5e9c0 keep blame view buttons sequence consistent with normal view when view a file (#8007) (#8009) 2019-08-28 08:11:41 +02:00
Richard Mahn
bb423f9350 Backport for #7945 (#7994) 2019-08-27 07:01:16 +02:00
Gary Kim
4d6c8d9b13 backport: Fix adding default Telegram webhook (#7992)
Signed-off-by: Gary Kim <gary@garykim.dev>
2019-08-27 12:24:25 +08:00
David Svantesson
b6b1560701 Abort syncrhonization from LDAP source if there is some error. (#7965)
Signed-off-by: David Svantesson <davidsvantesson@gmail.com>
(cherry picked from commit b2d23a1389)
2019-08-25 02:59:21 +02:00
Lunny Xiao
30dbddcc4d Add release notes of 1.9.2 (#7934)
* Add release notes of 1.9.2

* add missing issue
2019-08-22 16:36:40 +03:00
Mura Li
c491c22279 Fix pull creation with empty changes (#7920) (#7926)
* Logs the stderr of git-apply
* Add an integration test
* Skip testPatch when patch is empty
2019-08-20 22:14:09 -04:00
Lunny Xiao
5649f0d2b3 fix wrong sender when send slack webhook (#7918) (#7924) 2019-08-20 13:42:14 -04:00
Lunny Xiao
7dd726faeb upload support text/plain; charset=utf8 (#7899) 2019-08-17 13:59:36 +01:00
Antoine GIRARD
14c979c1b2 drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884)
* drone/docker: prepare multi-arch release

* Add docker-linux-arm64 pipeline

* add arm 64 build to manifest

* tag dry-run + indent

* Fix notify dependency
2019-08-15 18:13:24 -04:00
Antoine GIRARD
6b84a1d72b lfs/lock: round locked_at timestamp to second (#7872) (#7875)
* lfs/lock: round locked_at timestamp to second

* test returned locked_at values

* tests: use time RFC3339
2019-08-15 18:53:20 +08:00
Lanre Adelowo
68424eddf0 fix non existent milestone with 500 error (#7867) (#7873) 2019-08-15 09:37:59 +08:00
Lunny Xiao
ab23e4b7f4 Add changelog of v1.9.1 (#7859)
* add changelog of v1.9.1

* Update CHANGELOG.md

Co-Authored-By: Lauris BH <lauris@nix.lv>

* mention releases build by go1.12.8

* Update CHANGELOG.md

Co-Authored-By: Lauris BH <lauris@nix.lv>
2019-08-14 16:26:58 +03:00
zeripath
1bb88dad20 Fix local runs of ssh-requiring integration tests (#7857) 2019-08-14 19:02:04 +08:00
zeripath
94f0151789 Attempt to fix hook problem (#7856) 2019-08-14 17:43:02 +08:00
Antoine GIRARD
1e2fe9f0b4 gpg/bugfix: Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7846) (#7850)
* Use .ExpiredUnix.IsZero for display green color of gpg key

* remove useless parentheses
2019-08-14 10:59:10 +08:00
Mura Li
f3496c88b2 Do not fetch all refs (#7837)
Which would unnecessarily slow down the pull compare operation.
2019-08-13 19:03:01 +08:00
Antoine GIRARD
89915ca8a0 Fix duplicate call of webhook (#7821) (#7824) 2019-08-12 09:53:26 +08:00
Mario Lubenka
24fa56830f Enable switching to a different source branch when PR already exists (#7823)
Signed-off-by: Mario Lubenka <mario.lubenka@googlemail.com>
2019-08-11 23:32:03 +03:00
David Svantesson
0fa9ea516a Rewrite existing repo units if setting is not included in api body (#7811)
Signed-off-by: David Svantesson <davidsvantesson@gmail.com>
2019-08-11 12:45:45 +03:00
Gary Kim
9b95b41aa8 Prevent Commit Status and Message From Overflowing On Branch Page (#7800) (#7808)
Signed-off-by: Gary Kim <gary@garykim.dev>
2019-08-09 21:40:16 +03:00
Antoine GIRARD
38e799779f api: fix multiple bugs with statuses endpoints (#7785) (#7807)
* fix commit statuses api url

* search refs before passing sha

* adjust tests

* directly search tags and branches names + remove un-needed check in NewCommitStatus

* fix comment

* de-duplicate code

* test: use relative setting.AppURL

* Update routers/api/v1/repo/status.go

Co-Authored-By: Lauris BH <lauris@nix.lv>

* remove return

* Update routers/api/v1/repo/status.go

Co-Authored-By: Lauris BH <lauris@nix.lv>
2019-08-09 16:18:46 +03:00
WGH
4f39e56795 Fix Slack webhook fork message (#7774) (#7783)
The order of forkee and fork was mixed up.
2019-08-07 11:57:08 -04:00
Lunny Xiao
7b92f91e88 Fix approvals counting (#7757) (#7777)
* fix approvals counting

* fix tests

* fmt
2019-08-07 15:24:01 +08:00
Lunny Xiao
aea49d0b92 fix rename failed when rewrite public keys (#7761) (#7769) 2019-08-06 15:41:26 +08:00
zeripath
1b5908fb6a Fix dropTableColumns sqlite implementation (#7710) (#7765)
* Fix dropTableColumns sqlite implementation

* use droptables and its index dropping support in v78 and v85

* golang-ci fixes

* Add migration from gitea 1.3.3 for sqlite which reveals the droptables bug - thus showing this works
2019-08-06 07:35:54 +03:00
zeripath
65a76b7cb0 Be more strict with git arguments (#7715) (#7762)
* Be more strict with git arguments
* fix-up commit test
* use bindings for branch name
2019-08-05 22:05:48 -04:00
Lunny Xiao
c6f1825fe9 add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752) 2019-08-05 00:08:57 -04:00
guillep2k
4f5dbc4d00 Backport: fix repo_index_status lingering when deleting a repository (#7738) 2019-08-04 10:00:03 +03:00
Lauris BH
4ee8982e91 Fix milestone completness calculation when migrating (#7725) (#7732) 2019-08-04 09:29:17 +08:00
guillep2k
0d10482168 Fixes indexed repos keeping outdated indexes when files grow too large (#7731)
* Fixes indexed repos keeping outdated indexes when files grow too large

Co-Authored-By: zeripath <art27@cantab.net>
2019-08-03 21:42:53 +03:00
guillep2k
6d441de2bd Backport: skip non-regular files (e.g. submodules) on repo indexing (#7717)
* Backport: skip non-regular files (e.g. submodules) on repo indexing

* Include "executable" files in the index, as they are not necessarily binary
2019-08-02 22:40:15 +08:00
Lunny Xiao
d15e49f7ff improve branches list performance and fix protected branch icon when no-login (#7695) (#7704) 2019-08-01 11:40:00 -04:00
zeripath
39da4ac6d4 Correct wrong datetime format for git (#7689) (#7690) 2019-07-31 22:13:15 +01:00
techknowlogick
8f29011723 1.9.0 Changelog (#7676) 2019-07-31 09:29:31 -04:00
Lunny Xiao
ee43d20d3b fix duplicated webhook when creating issue with assignees (#7681) (#7684) 2019-07-31 14:39:33 +03:00
Lunny Xiao
99ffd826e5 upgrade macaron/captcha to fix random error problem (#7407) (#7683) 2019-07-31 10:09:29 +01:00
David Svantesson
93bac4e10d Backport of #7675. (#7682)
Move add to hook queue for created repo to outside xorm session.

Signed-off-by: David Svantesson <davidsvantesson@gmail.com>
2019-07-31 11:19:14 +03:00
6543
9fbb898058 Show protection symbol if needed on default branch (#7660) (#7668)
* backport issue showing portection symbol if needet at default branch

* sugestion to use range .Branches
d57973a804
2019-07-30 22:48:53 +08:00
6543
0a9794a6bc hide delete/restore button on archived repos [backport] (#7660)
* hide delete/restore button on archived repos
close issue #7653
 * backport vor v1.9

* hide column also

* move protected icon to first colum
backport parts of https://github.com/go-gitea/gitea/pull/7461

* backport comit divergenze fix
https://github.com/go-gitea/gitea/issues/7625
2019-07-30 00:20:39 +03:00
Lunny Xiao
d4044b9c98 fix bug on migrating milestone from github (#7665) (#7666) 2019-07-29 12:08:24 -04:00
Antoine GIRARD
1e6d2e47e9 css: use flex to fix floating paginate (#7656) (#7662) 2019-07-29 09:05:53 -04:00
Lunny Xiao
d827b0bfb7 change length of some repository's columns (#7652) (#7655) 2019-07-29 00:15:13 -04:00
renothing
d789170e31 fix wrong email when use gitea as OAuth2 provider (#7640) (#7647)
when you use gitea as OAuth2 provider, the /api/v1/user should return
user primary email as identifier, which is unique in OAuth2 clients.

this patch use convert.ToUser replace all u.APIFormat in api requests,
return primary email when caller is yourself or admin.
2019-07-27 17:25:16 +03:00
Andreas Shimokawa
9bbe3eb0b4 reserve .well-known username (#7638) 2019-07-26 16:37:31 -04:00
silverwind
650fdceb5a Fix syntax highlight initialization (#7617) (#7626)
* Fix syntax highlight initialization

Previously hljs was initialized via a function that relies on the
DOMContentLoaded event, registerd after jQuery's 'ready' event. I assume
that with the recent jQuery update, DOMContentLoaded may not be
guaranteed to fire after 'ready'. Fixed this via vanilla JS initalization.

Fixes: https://github.com/go-gitea/gitea/issues/7559

* semicolon
2019-07-26 07:12:35 +01:00
Lunny Xiao
4c69e158e5 Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623)
* fix bug create/edit wiki pages when code master branch protected

* improve FullPushingEnvironment function
2019-07-26 04:22:20 +03:00
zeripath
b7e41f7b8f Fix panic on push at #7611 (#7615) (#7618)
* Fix panic in #7611

Use pr.IssueID instead of pr.Issue.ID as Issue may not be loaded and is unnecessary

* Only fetch the head branch from the remote
2019-07-25 22:23:52 +01:00
zeripath
5a3d9861ba Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590)
* Handle ErrUserProhibitLogin in http git (#7586)

* Use 403
2019-07-23 17:06:10 -04:00
zeripath
adb43358bc fix #7568 (#7587) (#7589) 2019-07-23 20:53:13 +01:00
silverwind
d6a980501b Fix file header overflow in file and blame views (#7562) (#7579) 2019-07-23 14:18:39 +08:00
Richard Mahn
103a66ae83 Fixes #7564 - Malformed URLs in API git/commits response (#7565) (#7567) 2019-07-22 22:38:38 +01:00
silverwind
426fd2a816 Fix empty commits now showing in repo overview (#7521) (#7563)
* Fix empty commits now showing in repo overview

* add test

* make fmt
2019-07-22 19:23:49 +03:00
Lunny Xiao
337f2625ac Fix markdown invoke sequence (#7513) (#7560) 2019-07-22 14:27:47 +03:00
Lunny Xiao
5ebf4990a5 Fix repository's pull request count error (#7518) (#7524)
* fix pr count error

* fix tests
2019-07-19 07:40:16 +01:00
Lunny Xiao
3fd07a0be6 remove duplicated webhook trigger (#7511) (#7516) 2019-07-18 21:20:35 +08:00
Antoine GIRARD
d372539f79 Backport drone fix from #7480 and #7496 (#7504)
* don't make release-version deps on transalations since translations is only triggered by push on master (#7496)

* drone/docker: Use a more standard format (#7480)

* drone/docker: Use a more standard format

Based on the plugin drone structure itself : ebce953fc4/.drone.yml (L9)
Use autotag : http://plugins.drone.io/drone-plugins/drone-docker/#autotag

* use latest plugins/docker:linux-amd64

* remove useless cache_from

* Don't depends on translations step
2019-07-18 00:32:29 -04:00
Richard Mahn
91e24a3a10 Fixes #7474 - Handles all redirects for Web UI File CRUD (#7478) (#7507)
* Fixes #7474 - Handles all redirects for Web UI File CRUD

* Fixes lint errors

* Typo fix

* Adds unit tests for a few helper functions

* Fixes per review

* Fix for new branch creation and to unit test

* Fixes the template used for errors on delete
2019-07-18 09:11:55 +08:00
Richard Mahn
a29e667eff Backport for #7475 - settings error (#7483) 2019-07-16 12:45:38 +08:00
Matti R
92b993c91f Fetch refs for successful testing for tag (#7388) 2019-07-15 10:16:10 -04:00
techknowlogick
33b1027c76 1.9.0-rc2 changelog (#7467)
* 1.9.0-rc2 changelog

* Update CHANGELOG.md
2019-07-15 17:32:34 +08:00
mrsdizzie
b45f9260bf Fix regex for issues in commit messages (#7444) (#7466)
* Fix regex for issues in commit messages

Use same regex as markup for matching in commits.

Fixes #7438

* make fmt
2019-07-14 21:05:59 +01:00
Allen Wild
ee1a8d7b41 cmd/serv: actually exit after fatal errors (#7460)
Regression in 356854fc5f, where
a log.Fatal call was removed. log.Fatal calls os.Exit(1) as intended,
but without it the fail() function returns normally and execution
continues past the fatal error, causing a panic.

This is visible as a go panic log and stack trace returned to the SSH
client, which is not only ugly, it leaks server and build system
information.

Fix by removing the stray return statement so that the fail() function
always calls os.Exit(1).

Backport: 2186a99c76
Fixes: https://github.com/go-gitea/gitea/issues/7457
Signed-off-by: Allen Wild <allenwild93@gmail.com>
2019-07-14 12:02:22 +08:00
Gary Kim
ba19a35b6b Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453)
Fix an issue introduced by cc8e7dd355

Signed-off-by: Gary Kim <gary@garykim.dev>
2019-07-13 22:51:44 +08:00
silverwind
cc8e7dd355 fix Dropzone.js integration (#7445) (#7448) 2019-07-12 22:27:36 +01:00
Cherrg
f52840623c backport of #7393 - create class for inline positioned lists (#7439)
see #7393
affects #6464

Signed-off-by: Michael Gnehr michael@gnehr.de
2019-07-12 20:11:05 +01:00
silverwind
97d4a38e01 Diff: Fix indentation on unhighlighted code (#7435) (#7443)
There was a missing space before the `nohighlight` class which made the
previous class concatenate wrongly as `wrapnohighlight` in the template.
2019-07-12 12:17:54 -04:00
techknowlogick
60ccd87d6e backport #7425 - jquery 3 (#7442) 2019-07-12 16:20:17 +01:00
Gary Kim
2477737fff Only show "New Pull Request" button if repo allows pulls (#7426) (#7432)
Signed-off-by: Gary Kim <gary@garykim.dev>
2019-07-12 12:35:07 +08:00
Lunny Xiao
a360daeff9 Fix vendor (#7394) (#7396) 2019-07-09 04:34:53 -04:00
quantonganh
82d4d725ae only return head: null if source branch was deleted (#6705) (#7376)
* only return head: null if source branch was deleted

* add URL into GetPullRequest

* TestPullRequest_APIFormat

* log error if it is not Err(Branch)NotExist

(cherry picked from commit ff85a6331e)
2019-07-09 10:35:13 +08:00
Cherrg
1e585d7991 backport of #7385 - add missing template variable on organisation settings (#7386)
affects #6755

Signed-off-by: Michael Gnehr <michael@gnehr.de>
2019-07-08 21:03:44 +03:00
Cherrg
f849766998 backport of #7380 (#7383)
fix post parameter - on issue list - unset assignee

Signed-off-by: Michael Gnehr <michael@gnehr.de>
2019-07-08 18:50:33 +03:00
Lunny Xiao
f4818671e4 Fix migration tests since #7 fixed (#7375) (#7381)
* fix migration tests since #7 fixed

* fix test time
2019-07-08 23:04:46 +08:00
128 changed files with 1523 additions and 701 deletions

View File

@@ -114,6 +114,17 @@ steps:
- push
- pull_request
- name: tag-pre-condition
pull: always
image: alpine/git
commands:
- git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
depends_on:
- build
when:
event:
- tag
- name: tag-test
pull: always
image: golang:1.12
@@ -122,7 +133,7 @@ steps:
environment:
TAGS: bindata
depends_on:
- build
- tag-pre-condition
when:
event:
- tag
@@ -351,7 +362,7 @@ steps:
- name: static
pull: always
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.12.x
commands:
- export PATH=$PATH:$GOPATH/bin
- make generate
@@ -442,7 +453,6 @@ trigger:
depends_on:
- testing
- translations
steps:
- name: fetch-tags
@@ -453,7 +463,7 @@ steps:
- name: static
pull: always
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.12.x
commands:
- export PATH=$PATH:$GOPATH/bin
- make generate
@@ -548,7 +558,7 @@ steps:
---
kind: pipeline
name: docker
name: docker-linux-amd64
platform:
os: linux
@@ -558,6 +568,15 @@ workspace:
base: /go
path: src/code.gitea.io/gitea
depends_on:
- testing
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
- "refs/pull/**"
steps:
- name: fetch-tags
pull: default
@@ -571,56 +590,121 @@ steps:
- name: dryrun
pull: always
image: plugins/docker:18.09
image: plugins/docker:linux-amd64
settings:
cache_from: gitea/gitea
dry_run: true
repo: gitea/gitea
tags: linux-amd64
when:
event:
- pull_request
- name: release
- name: publish
pull: always
image: plugins/docker:18.09
image: plugins/docker:linux-amd64
settings:
cache_from: gitea/gitea
auto_tag: true
auto_tag_suffix: linux-amd64
repo: gitea/gitea
tags:
- "${DRONE_BRANCH##release/v}"
environment:
DOCKER_PASSWORD:
password:
from_secret: docker_password
DOCKER_USERNAME:
username:
from_secret: docker_username
depends_on:
- dryrun
when:
branch:
- "release/*"
event:
- push
exclude:
- pull_request
- name: latest
pull: always
image: plugins/docker:18.09
settings:
cache_from: gitea/gitea
default_tags: true
repo: gitea/gitea
environment:
DOCKER_PASSWORD:
from_secret: docker_password
DOCKER_USERNAME:
from_secret: docker_username
depends_on:
- dryrun
---
kind: pipeline
name: docker-linux-arm64
platform:
os: linux
arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
depends_on:
- testing
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
- "refs/pull/**"
steps:
- name: fetch-tags
pull: default
image: docker:git
commands:
- git fetch --tags --force
when:
branch:
- master
event:
- push
- tag
exclude:
- pull_request
- name: dryrun
pull: always
image: plugins/docker:linux-arm64
settings:
dry_run: true
repo: gitea/gitea
tags: linux-arm64
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-arm64
settings:
auto_tag: true
auto_tag_suffix: linux-arm64
repo: gitea/gitea
password:
from_secret: docker_password
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
---
kind: pipeline
name: docker-manifest
platform:
os: linux
arch: amd64
steps:
- name: manifest
pull: always
image: plugins/manifest
settings:
auto_tag: true
ignore_missing: true
spec: docker/manifest.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
depends_on:
- docker-linux-amd64
- docker-linux-arm64
---
kind: pipeline
@@ -644,7 +728,9 @@ depends_on:
- translations
- release-version
- release-master
- docker
- docker-linux-amd64
- docker-linux-arm64
- docker-manifest
- docs
steps:

View File

@@ -4,9 +4,71 @@ 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.9.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc1) - 2019-07-06
## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06
* BUGFIXES
* Fix go get from a private repository with Go 1.13 (#8100)
* Strict name matching for Repository.GetTagID() (#8082)
* Avoid ambiguity of branch/directory names for the git-diff-tree command (#8070)
* Add change title notification for issues (#8064)
* Run CORS handler first for /api routes (#7967) (#8053)
* Evaluate emojis in commit messages in list view (#8044)
* Fix failed to synchronize tags to releases for repository (#7990) (#7994)
* Fix adding default Telegram webhook (#7972) (#7992)
* Abort synchronization from LDAP source if there is some error (#7965)
* Fix deformed emoji in commit message (#8071)
* ENHANCEMENT
* Keep blame view buttons sequence consistent with normal view when viewing a file (#8007) (#8009)
## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22
* BUGFIXES
* Fix wrong sender when send slack webhook (#7918) (#7924)
* Upload support text/plain; charset=utf8 (#7899)
* Lfs/lock: round locked_at timestamp to second (#7872) (#7875)
* Fix non existent milestone with 500 error (#7867) (#7873)
* SECURITY
* Fix No PGP signature on 1.9.1 tag (#7874)
* Release built with go 1.12.9 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ
* ENHANCEMENT
* Fix pull creation with empty changes (#7920) (#7926)
* BUILD
* Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884)
## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14
* BREAKING
* Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752)
* SECURITY
* Be more strict with git arguments (#7715) (#7762)
* Release built with go 1.12.8 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA
* BUGFIXES
* Fix local runs of ssh-requiring integration tests (#7855) (#7857)
* Fix hook problem (#7856) (#7754)
* Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7850) (#7846)
* Do not fetch all refs (#7797) (#7837)
* Fix duplicate call of webhook (#7824) (#7821)
* Enable switching to a different source branch when PR already exists (#7823)
* Rewrite existing repo units if setting is not included in api body (#7811)
* Prevent Commit Status and Message From Overflowing On Branch Page (#7800) (#7808)
* API: fix multiple bugs with statuses endpoints (Backport #7785) (#7807)
* Fix Slack webhook fork message (1.9 release backport) (#7783)
* Fix approvals counting (#7757) (#7777)
* Fix rename failed when rewrite public keys (#7761) (#7769)
* Fix dropTableColumns sqlite implementation (#7710) (#7765)
* Fix repo_index_status lingering when deleting a repository (#7738)
* Fix milestone completness calculation when migrating (#7725) (#7732)
* Fixes indexed repos keeping outdated indexes when files grow too large (#7731)
* Skip non-regular files (e.g. submodules) on repo indexing (#7717)
* Improve branches list performance and fix protected branch icon when no-login (#7695) (#7704)
* Correct wrong datetime format for git (#7689) (#7690)
## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
* BREAKING
* Better logging (#6038) (#6095)
* SECURITY
* Shadow the password on cache and session config on admin panel (#7300)
* Fix markdown invoke sequence (#7513) (#7560)
* Reserve .well-known username (#7638)
* Do not leak secrets via timing side channel (#7364)
* Ensure that decryption of cookie actually suceeds (#7363)
* FEATURE
* Content API for Creating, Updating, Deleting Files (#6314)
* Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
@@ -29,6 +91,39 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Implement Default Webhooks (#4299)
* Telegram webhook (#4227)
* BUGFIXES
* Send webhook after commit when creating issue with assignees (#7681) (#7684)
* Upgrade macaron/captcha to fix random error problem (#7407) (#7683)
* Move add to hook queue for created repo to outside xorm session. (#7682) (#7675)
* Show protection symbol if needed on default branch (#7660) (#7668)
* Hide delete/restore button on archived repos (#7660)
* Fix bug on migrating milestone from github (#7665) (#7666)
* Use flex to fix floating paginate (#7656) (#7662)
* Change length of some repository's columns (#7652) (#7655)
* Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647)
* Fix syntax highlight initialization (#7617) (#7626)
* Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623)
* Fix panic on push at #7611 (#7615) (#7618)
* Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590)
* Fix color of split-diff view in dark theme (#7587) (#7589)
* Fix file header overflow in file and blame views (#7562) (#7579)
* Malformed URLs in API git/commits response (#7565) (#7567)
* Fix empty commits now showing in repo overview (#7521) (#7563)
* Fix repository's pull request count error (#7518) (#7524)
* Remove duplicated webhook trigger (#7511) (#7516)
* Handles all redirects for Web UI File CRUD (#7478) (#7507)
* Fix regex for issues in commit messages (#7444) (#7466)
* cmd/serv: actually exit after fatal errors (#7458) (#7460)
* Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453)
* Fix Dropzone.js integration (#7445) (#7448)
* Create class for inline positioned lists (#7439) (#7393)
* Diff: Fix indentation on unhighlighted code (#7435) (#7443)
* jQuery 3 (#7442) (#7425)
* Only show "New Pull Request" button if repo allows pulls (#7426) (#7432)
* Fix vendor references (#7394) (#7396)
* Only return head: null if source branch was deleted (#6705) (#7376)
* Add missing template variable on organisation settings (#7386) (#7385)
* Fix post parameter on issue list which had unset assignee (#7380) (#7383)
* Fix migration tests due to issue 7 being resolved (#7375) (#7381)
* Correctly adjust mirror url (#6593)
* Handle early git version's lack of get-url (#7065)
* Fix icon position in issue view (#7354)
@@ -166,6 +261,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Disable benchmarking during tag events on DroneIO (#6365)
* Comments list performance optimization (#5305)
* ENHANCEMENT
* Update Drone docker generation to standard format (#7480) (#7496) (#7504)
* Add API Endpoint for Repo Edit (#7006)
* Add state param to milestone listing API (#7131)
* Make captcha and password optional for external accounts (#6606)
@@ -285,8 +381,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Refactor: append, build variable and type switch (#4940)
* Git statistics in Activity tab (#4724)
* Drop the bits argument when generating an ed25519 key (#6504)
* SECURITY
* Shadow the password on cache and session config on admin panel (#7300)
* TESTING
* Exclude pull_request from fetch-tags step, fixes #7108 (#7120)
* Refactor and improve git test (#7086)

View File

@@ -96,6 +96,7 @@ func runHookPreReceive(c *cli.Context) error {
UserID: userID,
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
ProtectedBranchID: prID,
})
switch statusCode {

View File

@@ -73,7 +73,6 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
}
return
}
os.Exit(1)

19
docker/manifest.tmpl vendored Normal file
View File

@@ -0,0 +1,19 @@
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}latest{{/if}}
{{#if build.tags}}
tags:
{{#each build.tags}}
- {{this}}
{{/each}}
{{/if}}
manifests:
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-amd64
platform:
architecture: amd64
os: linux
-
image: gitea/gitea:{{#if build.tag}}{{trimPrefix "v" build.tag}}-{{/if}}linux-arm64
platform:
architecture: arm64
os: linux
variant: v8

4
go.mod
View File

@@ -45,7 +45,7 @@ require (
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab
github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372
github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f
@@ -135,4 +135,4 @@ require (
xorm.io/core v0.6.3
)
replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44
replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44

8
go.sum
View File

@@ -66,8 +66,8 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M=
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 h1:DWxZh2sImfCFn/79OUBhzFkPTKnsdDzXH/JTxpw5n6w=
github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -113,8 +113,8 @@ github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76u
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM=
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw=
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok=
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI=
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78=
github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8=
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=

View File

@@ -104,8 +104,11 @@ func TestAPILFSLocksLogged(t *testing.T) {
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks", test.repo.FullName()), map[string]string{"path": test.path})
req.Header.Set("Accept", "application/vnd.git-lfs+json")
req.Header.Set("Content-Type", "application/vnd.git-lfs+json")
session.MakeRequest(t, req, test.httpResult)
resp := session.MakeRequest(t, req, test.httpResult)
if len(test.addTime) > 0 {
var lfsLock api.LFSLockResponse
DecodeJSON(t, resp, &lfsLock)
assert.EqualValues(t, lfsLock.Lock.LockedAt.Format(time.RFC3339), lfsLock.Lock.LockedAt.Format(time.RFC3339Nano)) //locked at should be rounded to second
for _, id := range test.addTime {
resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
}
@@ -124,6 +127,7 @@ func TestAPILFSLocksLogged(t *testing.T) {
for i, lock := range lfsLocks.Locks {
assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 3*time.Second)
assert.EqualValues(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) //locked at should be rounded to second
}
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})

View File

@@ -24,20 +24,24 @@ import (
)
func withKeyFile(t *testing.T, keyname string, callback func(string)) {
keyFile := filepath.Join(setting.AppDataPath, keyname)
err := ssh.GenKeyPair(keyFile)
tmpDir, err := ioutil.TempDir("", "key-file")
assert.NoError(t, err)
defer os.RemoveAll(tmpDir)
err = os.Chmod(tmpDir, 0700)
assert.NoError(t, err)
keyFile := filepath.Join(tmpDir, keyname)
err = ssh.GenKeyPair(keyFile)
assert.NoError(t, err)
//Setup ssh wrapper
os.Setenv("GIT_SSH_COMMAND",
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
filepath.Join(setting.AppWorkPath, keyFile))
"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\"")
os.Setenv("GIT_SSH_VARIANT", "ssh")
callback(keyFile)
defer os.RemoveAll(keyFile)
defer os.RemoveAll(keyFile + ".pub")
}
func createSSHUrl(gitPath string, u *url.URL) *url.URL {

View File

@@ -54,6 +54,10 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
func TestPullMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -63,11 +67,19 @@ func TestPullMerge(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
hookTasks, err = models.HookTasks(1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullRebase(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -77,12 +89,21 @@ func TestPullRebase(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
hookTasks, err = models.HookTasks(1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullRebaseMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
prepareTestEnv(t)
hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -92,12 +113,21 @@ func TestPullRebaseMerge(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
hookTasks, err = models.HookTasks(1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}
func TestPullSquash(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
prepareTestEnv(t)
hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -108,6 +138,10 @@ func TestPullSquash(t *testing.T) {
elem := strings.Split(test.RedirectURL(resp), "/")
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
hookTasks, err = models.HookTasks(1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
})
}

View File

@@ -8,6 +8,7 @@ import (
"net/http"
"net/url"
"path"
"strings"
"testing"
"code.gitea.io/gitea/models"
@@ -93,3 +94,28 @@ func TestPullCreate_CommitStatus(t *testing.T) {
}
})
}
func TestPullCreate_EmptyChangesWithCommits(t *testing.T) {
onGiteaRun(t, func(t *testing.T, u *url.URL) {
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testEditFileToNewBranch(t, session, "user1", "repo1", "master", "status1", "README.md", "status1")
testEditFileToNewBranch(t, session, "user1", "repo1", "status1", "status1", "README.md", "# repo1\n\nDescription for repo1")
url := path.Join("user1", "repo1", "compare", "master...status1")
req := NewRequestWithValues(t, "POST", url,
map[string]string{
"_csrf": GetCSRF(t, session, url),
"title": "pull request from status1",
},
)
session.MakeRequest(t, req, http.StatusFound)
req = NewRequest(t, "GET", "/user1/repo1/pulls/1")
resp := session.MakeRequest(t, req, http.StatusOK)
doc := NewHTMLParser(t, resp.Body)
text := strings.TrimSpace(doc.doc.Find(".item.text.green").Text())
assert.EqualValues(t, "This pull request can be merged automatically.", text)
})
}

View File

@@ -5,10 +5,13 @@
package integrations
import (
"encoding/json"
"net/http"
"net/http/httptest"
"path"
"testing"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
@@ -67,6 +70,29 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
for _, class := range classes {
assert.True(t, sel.HasClass(class))
}
//By SHA
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/"+path.Base(commitURL)+"/statuses")
testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), state)
//By Ref
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/master/statuses")
testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), state)
req = NewRequest(t, "GET", "/api/v1/repos/user2/repo1/commits/v1.1/statuses")
testRepoCommitsWithStatus(t, session.MakeRequest(t, req, http.StatusOK), state)
}
func testRepoCommitsWithStatus(t *testing.T, resp *httptest.ResponseRecorder, state string) {
decoder := json.NewDecoder(resp.Body)
statuses := []*api.Status{}
assert.NoError(t, decoder.Decode(&statuses))
assert.Len(t, statuses, 1)
for _, s := range statuses {
assert.Equal(t, api.StatusState(state), s.State)
assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/statuses/65f1bf27bc3bf70f64657658635e66094edbcb4d", s.URL)
assert.Equal(t, "http://test.ci/", s.TargetURL)
assert.Equal(t, "", s.Description)
assert.Equal(t, "testci", s.Context)
}
}
func TestRepoCommitsWithStatusPending(t *testing.T) {

View File

@@ -65,6 +65,7 @@ var (
)
const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+`
const issueRefRegexpStrNoKeyword = `(?:\s|^|\(|\[)(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`
func assembleKeywordsPattern(words []string) string {
return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
@@ -73,7 +74,7 @@ func assembleKeywordsPattern(words []string) string {
func init() {
issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStr)
issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword)
}
// Action represents user operation type and other information to

View File

@@ -155,6 +155,25 @@ func TestPushCommits_AvatarLink(t *testing.T) {
pushCommits.AvatarLink("nonexistent@example.com"))
}
func TestRegExp_issueReferenceKeywordsPat(t *testing.T) {
trueTestCases := []string{
"#2",
"[#2]",
"please see go-gitea/gitea#5",
}
falseTestCases := []string{
"kb#2",
"#2xy",
}
for _, testCase := range trueTestCases {
assert.True(t, issueReferenceKeywordsPat.MatchString(testCase))
}
for _, testCase := range falseTestCases {
assert.False(t, issueReferenceKeywordsPat.MatchString(testCase))
}
}
func Test_getIssueFromRef(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)

View File

@@ -101,7 +101,7 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
reviews, err := GetReviewersByPullID(pr.Issue.ID)
reviews, err := GetReviewersByPullID(pr.IssueID)
if err != nil {
log.Error("GetReviewersByPullID: %v", err)
return 0

View File

@@ -87,7 +87,7 @@ func (status *CommitStatus) loadRepo(e Engine) (err error) {
// APIURL returns the absolute APIURL to this commit-status.
func (status *CommitStatus) APIURL() string {
_ = status.loadRepo(x)
return fmt.Sprintf("%sapi/v1/%s/statuses/%s",
return fmt.Sprintf("%sapi/v1/repos/%s/statuses/%s",
setting.AppURL, status.Repo.FullName(), status.SHA)
}

View File

@@ -19,20 +19,25 @@ func TestGetCommitStatuses(t *testing.T) {
statuses, err := GetCommitStatuses(repo1, sha1, 0)
assert.NoError(t, err)
if assert.Len(t, statuses, 5) {
assert.Equal(t, statuses[0].Context, "ci/awesomeness")
assert.Equal(t, statuses[0].State, CommitStatusPending)
assert.Len(t, statuses, 5)
assert.Equal(t, statuses[1].Context, "cov/awesomeness")
assert.Equal(t, statuses[1].State, CommitStatusWarning)
assert.Equal(t, "ci/awesomeness", statuses[0].Context)
assert.Equal(t, CommitStatusPending, statuses[0].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[0].APIURL())
assert.Equal(t, statuses[2].Context, "cov/awesomeness")
assert.Equal(t, statuses[2].State, CommitStatusSuccess)
assert.Equal(t, "cov/awesomeness", statuses[1].Context)
assert.Equal(t, CommitStatusWarning, statuses[1].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[1].APIURL())
assert.Equal(t, statuses[3].Context, "ci/awesomeness")
assert.Equal(t, statuses[3].State, CommitStatusFailure)
assert.Equal(t, "cov/awesomeness", statuses[2].Context)
assert.Equal(t, CommitStatusSuccess, statuses[2].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[2].APIURL())
assert.Equal(t, statuses[4].Context, "deploy/awesomeness")
assert.Equal(t, statuses[4].State, CommitStatusError)
}
assert.Equal(t, "ci/awesomeness", statuses[3].Context)
assert.Equal(t, CommitStatusFailure, statuses[3].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[3].APIURL())
assert.Equal(t, "deploy/awesomeness", statuses[4].Context)
assert.Equal(t, CommitStatusError, statuses[4].State)
assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/statuses/1234123412341234123412341234123412341234", statuses[4].APIURL())
}

View File

@@ -12,13 +12,13 @@ import (
// PushingEnvironment returns an os environment to allow hooks to work on push
func PushingEnvironment(doer *User, repo *Repository) []string {
return FullPushingEnvironment(doer, doer, repo, 0)
return FullPushingEnvironment(doer, doer, repo, repo.Name, 0)
}
// FullPushingEnvironment returns an os environment to allow hooks to work on push
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string {
func FullPushingEnvironment(author, committer *User, repo *Repository, repoName string, prID int64) []string {
isWiki := "false"
if strings.HasSuffix(repo.Name, ".wiki") {
if strings.HasSuffix(repoName, ".wiki") {
isWiki = "true"
}
@@ -32,7 +32,7 @@ func FullPushingEnvironment(author, committer *User, repo *Repository, prID int6
"GIT_AUTHOR_EMAIL="+authorSig.Email,
"GIT_COMMITTER_NAME="+committerSig.Name,
"GIT_COMMITTER_EMAIL="+committerSig.Email,
EnvRepoName+"="+repo.Name,
EnvRepoName+"="+repoName,
EnvRepoUsername+"="+repo.MustOwnerName(),
EnvRepoIsWiki+"="+isWiki,
EnvPusherName+"="+committer.Name,

View File

@@ -1835,3 +1835,22 @@ func (issue *Issue) BlockedByDependencies() ([]*Issue, error) {
func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
return issue.getBlockingDependencies(x)
}
func (issue *Issue) updateClosedNum(e Engine) (err error) {
if issue.IsPull {
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
issue.RepoID,
true,
true,
issue.RepoID,
)
} else {
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
issue.RepoID,
false,
true,
issue.RepoID,
)
}
return
}

View File

@@ -142,11 +142,15 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
return err
}
return sess.Commit()
if err := sess.Commit(); err != nil {
return err
}
go HookQueue.Add(issue.RepoID)
return nil
}
func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) {
// Update the assignee
removed, err := updateIssueAssignee(sess, issue, assigneeID)
if err != nil {
@@ -209,7 +213,6 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
return nil
}
}
go HookQueue.Add(issue.RepoID)
return nil
}

View File

@@ -632,12 +632,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
act.OpType = ActionReopenPullRequest
}
if opts.Issue.IsPull {
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID)
} else {
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID)
}
if err != nil {
if err = opts.Issue.updateClosedNum(e); err != nil {
return err
}
@@ -647,12 +642,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
act.OpType = ActionClosePullRequest
}
if opts.Issue.IsPull {
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID)
} else {
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID)
}
if err != nil {
if err = opts.Issue.updateClosedNum(e); err != nil {
return err
}
}

View File

@@ -56,7 +56,7 @@ func (l *LFSLock) APIFormat() *api.LFSLock {
return &api.LFSLock{
ID: strconv.FormatInt(l.ID, 10),
Path: l.Path,
LockedAt: l.Created,
LockedAt: l.Created.Round(time.Second),
Owner: &api.LFSLockOwner{
Name: l.Owner.DisplayName(),
},

View File

@@ -62,38 +62,50 @@ func insertIssue(sess *xorm.Session, issue *Issue) error {
if _, err := sess.Insert(issueLabels); err != nil {
return err
}
cols := make([]string, 0)
if !issue.IsPull {
sess.ID(issue.RepoID).Incr("num_issues")
cols = append(cols, "num_issues")
if issue.IsClosed {
sess.Incr("num_closed_issues")
cols = append(cols, "num_closed_issues")
}
} else {
sess.ID(issue.RepoID).Incr("num_pulls")
cols = append(cols, "num_pulls")
if issue.IsClosed {
sess.Incr("num_closed_pulls")
cols = append(cols, "num_closed_pulls")
}
}
if _, err := sess.NoAutoTime().Update(issue.Repo); err != nil {
if _, err := sess.NoAutoTime().Cols(cols...).Update(issue.Repo); err != nil {
return err
}
cols = []string{"num_issues"}
sess.Incr("num_issues")
if issue.IsClosed {
sess.Incr("num_closed_issues")
cols = append(cols, "num_closed_issues")
}
if _, err := sess.In("id", labelIDs).NoAutoTime().Update(new(Label)); err != nil {
if _, err := sess.In("id", labelIDs).NoAutoTime().Cols(cols...).Update(new(Label)); err != nil {
return err
}
if issue.MilestoneID > 0 {
cols = []string{"num_issues"}
sess.Incr("num_issues")
cl := "num_closed_issues"
if issue.IsClosed {
sess.Incr("num_closed_issues")
cols = append(cols, "num_closed_issues")
cl = "(num_closed_issues + 1)"
}
if _, err := sess.ID(issue.MilestoneID).
SetExpr("completeness", "num_closed_issues * 100 / num_issues").
NoAutoTime().
SetExpr("completeness", cl+" * 100 / (num_issues + 1)").
NoAutoTime().Cols(cols...).
Update(new(Milestone)); err != nil {
return err
}

View File

@@ -321,11 +321,25 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
return err
}
tableSQL := string(res[0]["sql"])
// Separate out the column definitions
tableSQL = tableSQL[strings.Index(tableSQL, "("):]
// Remove the required columnNames
for _, name := range columnNames {
tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*[,)]").ReplaceAllString(tableSQL, "")
tableSQL = regexp.MustCompile(regexp.QuoteMeta("`"+name+"`")+"[^`,)]*?[,)]").ReplaceAllString(tableSQL, "")
}
// Ensure the query is ended properly
tableSQL = strings.TrimSpace(tableSQL)
if tableSQL[len(tableSQL)-1] != ')' {
if tableSQL[len(tableSQL)-1] == ',' {
tableSQL = tableSQL[:len(tableSQL)-1]
}
tableSQL += ")"
}
// Find all the columns in the table
columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1)
tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL

View File

@@ -5,13 +5,7 @@
package migrations
import (
"fmt"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"github.com/go-xorm/xorm"
"xorm.io/core"
)
func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
@@ -21,73 +15,28 @@ func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
IsEmpty bool `xorm:"INDEX"`
}
// First remove the index
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
var err error
if models.DbCfg.Type == core.POSTGRES || models.DbCfg.Type == core.SQLITE {
_, err = sess.Exec("DROP INDEX IF EXISTS IDX_repository_is_bare")
} else if models.DbCfg.Type == core.MSSQL {
_, err = sess.Exec(`DECLARE @ConstraintName VARCHAR(256)
DECLARE @SQL NVARCHAR(256)
SELECT @ConstraintName = obj.name FROM sys.columns col LEFT OUTER JOIN sys.objects obj ON obj.object_id = col.default_object_id AND obj.type = 'D' WHERE col.object_id = OBJECT_ID('repository') AND obj.name IS NOT NULL AND col.name = 'is_bare'
SET @SQL = N'ALTER TABLE [repository] DROP CONSTRAINT [' + @ConstraintName + N']'
EXEC sp_executesql @SQL`)
if err != nil {
return err
}
} else if models.DbCfg.Type == core.MYSQL {
indexes, err := sess.QueryString(`SHOW INDEX FROM repository WHERE KEY_NAME = 'IDX_repository_is_bare'`)
if err != nil {
return err
}
if len(indexes) >= 1 {
_, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository")
if err != nil {
return fmt.Errorf("Drop index failed: %v", err)
}
}
} else {
_, err = sess.Exec("DROP INDEX IDX_repository_is_bare ON repository")
}
if err != nil {
return fmt.Errorf("Drop index failed: %v", err)
}
if err = sess.Commit(); err != nil {
return err
}
if err := sess.Begin(); err != nil {
return err
}
if err := sess.Sync2(new(Repository)); err != nil {
return err
}
if _, err := sess.Exec("UPDATE repository SET is_empty = is_bare;"); err != nil {
return err
}
if models.DbCfg.Type != core.SQLITE {
_, err = sess.Exec("ALTER TABLE repository DROP COLUMN is_bare")
if err != nil {
return fmt.Errorf("Drop column failed: %v", err)
}
}
if err = sess.Commit(); err != nil {
if err := sess.Commit(); err != nil {
return err
}
if models.DbCfg.Type == core.SQLITE {
log.Warn("TABLE repository's COLUMN is_bare should be DROP but sqlite is not supported, you could manually do that.")
if err := sess.Begin(); err != nil {
return err
}
return nil
if err := dropTableColumns(sess, "repository", "is_bare"); err != nil {
return err
}
return sess.Commit()
}

View File

@@ -8,9 +8,7 @@ import (
"fmt"
"github.com/go-xorm/xorm"
"xorm.io/core"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
@@ -37,41 +35,6 @@ func hashAppToken(x *xorm.Engine) error {
// First remove the index
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
var err error
if models.DbCfg.Type == core.POSTGRES || models.DbCfg.Type == core.SQLITE {
_, err = sess.Exec("DROP INDEX IF EXISTS UQE_access_token_sha1")
} else if models.DbCfg.Type == core.MSSQL {
_, err = sess.Exec(`DECLARE @ConstraintName VARCHAR(256)
DECLARE @SQL NVARCHAR(256)
SELECT @ConstraintName = obj.name FROM sys.columns col LEFT OUTER JOIN sys.objects obj ON obj.object_id = col.default_object_id AND obj.type = 'D' WHERE col.object_id = OBJECT_ID('access_token') AND obj.name IS NOT NULL AND col.name = 'sha1'
SET @SQL = N'ALTER TABLE [access_token] DROP CONSTRAINT [' + @ConstraintName + N']'
EXEC sp_executesql @SQL`)
} else if models.DbCfg.Type == core.MYSQL {
indexes, err := sess.QueryString(`SHOW INDEX FROM access_token WHERE KEY_NAME = 'UQE_access_token_sha1'`)
if err != nil {
return err
}
if len(indexes) >= 1 {
_, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token")
if err != nil {
return err
}
}
} else {
_, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token")
}
if err != nil {
return fmt.Errorf("Drop index failed: %v", err)
}
if err = sess.Commit(); err != nil {
return err
}
if err := sess.Begin(); err != nil {
return err
@@ -81,7 +44,7 @@ func hashAppToken(x *xorm.Engine) error {
return fmt.Errorf("Sync2: %v", err)
}
if err = sess.Commit(); err != nil {
if err := sess.Commit(); err != nil {
return err
}

View File

@@ -755,11 +755,14 @@ func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
}
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (count int64, err error) {
if count, err = x.In("uid", userIDs).In("team_id", teamIDs).Count(new(TeamUser)); err != nil {
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (int64, error) {
var ids []int64
if err := x.In("uid", userIDs).In("team_id", teamIDs).
Table("team_user").
Cols("uid").GroupBy("uid").Find(&ids); err != nil {
return 0, err
}
return
return int64(len(ids)), nil
}
// ___________ __________

View File

@@ -370,7 +370,7 @@ func TestUsersInTeamsCount(t *testing.T) {
assert.Equal(t, expected, count)
}
test([]int64{2}, []int64{1, 2, 3, 4}, 2)
test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2)
test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3)
test([]int64{2}, []int64{1, 2, 3, 4}, 1) // only userid 2
test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 2) // userid 2,4
test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3) // userid 2,4,5
}

View File

@@ -189,36 +189,6 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
return nil
}
}
if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil {
log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err)
return nil
}
if baseCommit, err = baseBranch.GetCommit(); err != nil {
log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err)
return nil
}
if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil {
log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err)
return nil
}
if headCommit, err = headBranch.GetCommit(); err != nil {
log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err)
return nil
}
apiBaseBranchInfo := &api.PRBranchInfo{
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
Sha: baseCommit.ID.String(),
RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
}
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
Sha: headCommit.ID.String(),
RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
}
if err = pr.Issue.loadRepo(e); err != nil {
log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
@@ -227,6 +197,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
apiPullRequest := &api.PullRequest{
ID: pr.ID,
URL: pr.Issue.HTMLURL(),
Index: pr.Index,
Poster: apiIssue.Poster,
Title: apiIssue.Title,
@@ -241,13 +212,68 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
DiffURL: pr.Issue.DiffURL(),
PatchURL: pr.Issue.PatchURL(),
HasMerged: pr.HasMerged,
Base: apiBaseBranchInfo,
Head: apiHeadBranchInfo,
MergeBase: pr.MergeBase,
Deadline: apiIssue.Deadline,
Created: pr.Issue.CreatedUnix.AsTimePtr(),
Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
}
baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch)
if err != nil {
if git.IsErrBranchNotExist(err) {
apiPullRequest.Base = nil
} else {
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
return nil
}
} else {
apiBaseBranchInfo := &api.PRBranchInfo{
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
}
baseCommit, err = baseBranch.GetCommit()
if err != nil {
if git.IsErrNotExist(err) {
apiBaseBranchInfo.Sha = ""
} else {
log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
return nil
}
} else {
apiBaseBranchInfo.Sha = baseCommit.ID.String()
}
apiPullRequest.Base = apiBaseBranchInfo
}
headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
if err != nil {
if git.IsErrBranchNotExist(err) {
apiPullRequest.Head = nil
} else {
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
return nil
}
} else {
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
}
headCommit, err = headBranch.GetCommit()
if err != nil {
if git.IsErrNotExist(err) {
apiHeadBranchInfo.Sha = ""
} else {
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
return nil
}
} else {
apiHeadBranchInfo.Sha = headCommit.ID.String()
}
apiPullRequest.Head = apiHeadBranchInfo
}
if pr.Status != PullRequestStatusChecking {
mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress()
@@ -572,7 +598,7 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
if err != nil {
for i := range patchConflicts {
if strings.Contains(stderr, patchConflicts[i]) {
log.Trace("PullRequest[%d].testPatch (apply): has conflict", pr.ID)
log.Trace("PullRequest[%d].testPatch (apply): has conflict: %s", pr.ID, stderr)
const prefix = "error: patch failed:"
pr.Status = PullRequestStatusConflict
pr.ConflictedFiles = make([]string, 0, 5)
@@ -635,13 +661,16 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
}
pr.Index = pull.Index
if err = repo.savePatch(sess, pr.Index, patch); err != nil {
return fmt.Errorf("SavePatch: %v", err)
}
pr.BaseRepo = repo
if err = pr.testPatch(sess); err != nil {
return fmt.Errorf("testPatch: %v", err)
pr.Status = PullRequestStatusChecking
if len(patch) > 0 {
if err = repo.savePatch(sess, pr.Index, patch); err != nil {
return fmt.Errorf("SavePatch: %v", err)
}
if err = pr.testPatch(sess); err != nil {
return fmt.Errorf("testPatch: %v", err)
}
}
// No conflict appears after test means mergeable.
if pr.Status == PullRequestStatusChecking {

View File

@@ -31,7 +31,15 @@ func TestPullRequest_LoadIssue(t *testing.T) {
assert.Equal(t, int64(2), pr.Issue.ID)
}
// TODO TestPullRequest_APIFormat
func TestPullRequest_APIFormat(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
assert.NoError(t, pr.LoadAttributes())
assert.NoError(t, pr.LoadIssue())
apiPullRequest := pr.APIFormat()
assert.NotNil(t, apiPullRequest)
assert.Nil(t, apiPullRequest.Head)
}
func TestPullRequest_GetBaseRepo(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())

View File

@@ -409,7 +409,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
Action: api.HookReleaseUpdated,
Release: rel.APIFormat(),
Repository: rel.Repo.APIFormat(mode),
Sender: rel.Publisher.APIFormat(),
Sender: doer.APIFormat(),
}); err1 != nil {
log.Error("PrepareWebhooks: %v", err)
} else {
@@ -420,7 +420,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
}
// DeleteReleaseByID deletes a release and corresponding Git tag by given ID.
func DeleteReleaseByID(id int64, u *User, delTag bool) error {
func DeleteReleaseByID(id int64, doer *User, delTag bool) error {
rel, err := GetReleaseByID(id)
if err != nil {
return fmt.Errorf("GetReleaseByID: %v", err)
@@ -459,12 +459,12 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error {
return fmt.Errorf("LoadAttributes: %v", err)
}
mode, _ := AccessLevel(u, rel.Repo)
mode, _ := AccessLevel(doer, rel.Repo)
if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
Action: api.HookReleaseDeleted,
Release: rel.APIFormat(),
Repository: rel.Repo.APIFormat(mode),
Sender: rel.Publisher.APIFormat(),
Sender: doer.APIFormat(),
}); err != nil {
log.Error("PrepareWebhooks: %v", err)
} else {

View File

@@ -134,8 +134,8 @@ type Repository struct {
Owner *User `xorm:"-"`
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
Name string `xorm:"INDEX NOT NULL"`
Description string
Website string
Description string `xorm:"TEXT"`
Website string `xorm:"VARCHAR(2048)"`
DefaultBranch string
NumWatches int
@@ -1324,7 +1324,6 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
}); err != nil {
return fmt.Errorf("prepareWebhooks: %v", err)
}
go HookQueue.Add(repo.ID)
} else if err = repo.recalculateAccesses(e); err != nil {
// Organization automatically called this in addRepository method.
return fmt.Errorf("recalculateAccesses: %v", err)
@@ -1393,7 +1392,16 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
}
}
return repo, sess.Commit()
if err = sess.Commit(); err != nil {
return nil, err
}
// Add to hook queue for created repo after session commit.
if u.IsOrganization() {
go HookQueue.Add(repo.ID)
}
return repo, err
}
func countRepositories(userID int64, private bool) int64 {
@@ -1783,6 +1791,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
&HookTask{RepoID: repoID},
&Notification{RepoID: repoID},
&CommitStatus{RepoID: repoID},
&RepoIndexerStatus{RepoID: repoID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}
@@ -2327,6 +2336,23 @@ func CheckRepoStats() {
}
// ***** END: Repository.NumClosedIssues *****
// ***** START: Repository.NumClosedPulls *****
desc = "repository count 'num_closed_pulls'"
results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true)
if err != nil {
log.Error("Select %s: %v", desc, err)
} else {
for _, result := range results {
id := com.StrTo(result["id"]).MustInt64()
log.Trace("Updating %s: %d", desc, id)
_, err = x.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, true, id)
if err != nil {
log.Error("Update %s[%d]: %v", desc, id, err)
}
}
}
// ***** END: Repository.NumClosedPulls *****
// FIXME: use checker when stop supporting old fork repo format.
// ***** START: Repository.NumForks *****
results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
@@ -2461,6 +2487,11 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
go HookQueue.Add(oldRepo.ID)
}
// Add to hook queue for created repo after session commit.
if u.IsOrganization() {
go HookQueue.Add(repo.ID)
}
if err = repo.UpdateSize(); err != nil {
log.Error("Failed to update size for repository: %v", err)
}

View File

@@ -199,7 +199,7 @@ func addUpdate(update fileUpdate, repo *Repository, batch rupture.FlushingBatch)
if size, err := strconv.Atoi(strings.TrimSpace(stdout)); err != nil {
return fmt.Errorf("Misformatted git cat-file output: %v", err)
} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
return nil
return addDelete(update.Filename, repo, batch)
}
fileContents, err := git.NewCommand("cat-file", "blob", update.BlobSha).
@@ -231,20 +231,28 @@ func addDelete(filename string, repo *Repository, batch rupture.FlushingBatch) e
return indexerUpdate.AddToFlushingBatch(batch)
}
func isIndexable(entry *git.TreeEntry) bool {
return entry.IsRegular() || entry.IsExecutable()
}
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
entries, err := git.ParseTreeEntries(stdout)
if err != nil {
return nil, err
}
var idxCount = 0
updates := make([]fileUpdate, len(entries))
for i, entry := range entries {
updates[i] = fileUpdate{
Filename: entry.Name(),
BlobSha: entry.ID.String(),
for _, entry := range entries {
if isIndexable(entry) {
updates[idxCount] = fileUpdate{
Filename: entry.Name(),
BlobSha: entry.ID.String(),
}
idxCount++
}
}
return updates, nil
return updates[:idxCount], nil
}
// genesisChanges get changes to add repo to the indexer for the first time

View File

@@ -642,12 +642,14 @@ func rewriteAllPublicKeys(e Engine) error {
}
_, err = t.WriteString(line + "\n")
if err != nil {
f.Close()
return err
}
}
defer f.Close()
f.Close()
}
t.Close()
return os.Rename(tmpPath, fPath)
}

View File

@@ -195,9 +195,9 @@ func (u *User) UpdateTheme(themeName string) error {
return UpdateUserCols(u, "theme")
}
// getEmail returns an noreply email, if the user has set to keep his
// GetEmail returns an noreply email, if the user has set to keep his
// email address private, otherwise the primary email address.
func (u *User) getEmail() string {
func (u *User) GetEmail() string {
if u.KeepEmailPrivate {
return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
}
@@ -210,7 +210,7 @@ func (u *User) APIFormat() *api.User {
ID: u.ID,
UserName: u.Name,
FullName: u.FullName,
Email: u.getEmail(),
Email: u.GetEmail(),
AvatarURL: u.AvatarLink(),
Language: u.Language,
IsAdmin: u.IsAdmin,
@@ -425,7 +425,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
func (u *User) NewGitSig() *git.Signature {
return &git.Signature{
Name: u.GitName(),
Email: u.getEmail(),
Email: u.GetEmail(),
When: time.Now(),
}
}
@@ -751,6 +751,7 @@ var (
"robots.txt",
".",
"..",
".well-known",
}
reservedUserPatterns = []string{"*.keys", "*.gpg"}
)
@@ -1375,9 +1376,7 @@ type SearchUserOptions struct {
}
func (opts *SearchUserOptions) toConds() builder.Cond {
var cond = builder.NewCond()
cond = cond.And(builder.Eq{"type": opts.Type})
var cond builder.Cond = builder.Eq{"type": opts.Type}
if len(opts.Keyword) > 0 {
lowerKeyword := strings.ToLower(opts.Keyword)
@@ -1646,7 +1645,12 @@ func SyncExternalUsers() {
return
}
sr := s.LDAP().SearchEntries()
sr, err := s.LDAP().SearchEntries()
if err != nil {
log.Error("SyncExternalUsers LDAP source failure [%s], skipped", s.Name)
continue
}
for _, su := range sr {
if len(su.Username) == 0 {
continue

View File

@@ -890,7 +890,6 @@ func DeliverHooks() {
for _, t := range tasks {
if err = t.deliver(); err != nil {
log.Error("deliver: %v", err)
continue
}
}

View File

@@ -120,8 +120,8 @@ func getSlackDeletePayload(p *api.DeletePayload, slack *SlackMeta) (*SlackPayloa
// getSlackForkPayload composes Slack payload for forked by a repository.
func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
forkLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
baseLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
forkLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName)
text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
return &SlackPayload{
Channel: slack.Channel,

View File

@@ -217,7 +217,13 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
if err := git.Push(basePath, git.PushOptions{
Remote: "origin",
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
Env: PushingEnvironment(doer, repo),
Env: FullPushingEnvironment(
doer,
doer,
repo,
repo.Name+".wiki",
0,
),
}); err != nil {
log.Error("%v", err)
return fmt.Errorf("Push: %v", err)

View File

@@ -308,12 +308,12 @@ func (ls *Source) UsePagedSearch() bool {
}
// SearchEntries : search an LDAP source for all users matching userFilter
func (ls *Source) SearchEntries() []*SearchResult {
func (ls *Source) SearchEntries() ([]*SearchResult, error) {
l, err := dial(ls)
if err != nil {
log.Error("LDAP Connect error, %s:%v", ls.Host, err)
ls.Enabled = false
return nil
return nil, err
}
defer l.Close()
@@ -321,7 +321,7 @@ func (ls *Source) SearchEntries() []*SearchResult {
err := l.Bind(ls.BindDN, ls.BindPassword)
if err != nil {
log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err)
return nil
return nil, err
}
log.Trace("Bound as BindDN %s", ls.BindDN)
} else {
@@ -350,7 +350,7 @@ func (ls *Source) SearchEntries() []*SearchResult {
}
if err != nil {
log.Error("LDAP Search failed unexpectedly! (%v)", err)
return nil
return nil, err
}
result := make([]*SearchResult, len(sr.Entries))
@@ -368,5 +368,5 @@ func (ls *Source) SearchEntries() []*SearchResult {
}
}
return result
return result, nil
}

View File

@@ -249,6 +249,19 @@ func Contexter() macaron.Handler {
if ctx.Query("go-get") == "1" {
ownerName := c.Params(":username")
repoName := c.Params(":reponame")
trimmedRepoName := strings.TrimSuffix(repoName, ".git")
if ownerName == "" || trimmedRepoName == "" {
_, _ = c.Write([]byte(`<!doctype html>
<html>
<body>
invalid import path
</body>
</html>
`))
c.WriteHeader(400)
return
}
branchName := "master"
repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
@@ -276,7 +289,7 @@ func Contexter() macaron.Handler {
</body>
</html>
`, map[string]string{
"GoGetImport": ComposeGoGetImport(ownerName, strings.TrimSuffix(repoName, ".git")),
"GoGetImport": ComposeGoGetImport(ownerName, trimmedRepoName),
"CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName),
"GoDocDirectory": prefix + "{/dir}",
"GoDocFile": prefix + "{/dir}/{file}#L{line}",

View File

@@ -201,10 +201,14 @@ func ComposeGoGetImport(owner, repo string) string {
// .netrc file.
func EarlyResponseForGoGetMeta(ctx *Context) {
username := ctx.Params(":username")
reponame := ctx.Params(":reponame")
reponame := strings.TrimSuffix(ctx.Params(":reponame"), ".git")
if username == "" || reponame == "" {
ctx.PlainText(400, []byte("invalid repository path"))
return
}
ctx.PlainText(200, []byte(com.Expand(`<meta name="go-import" content="{GoGetImport} git {CloneLink}">`,
map[string]string{
"GoGetImport": ComposeGoGetImport(username, strings.TrimSuffix(reponame, ".git")),
"GoGetImport": ComposeGoGetImport(username, reponame),
"CloneLink": models.ComposeHTTPSCloneURL(username, reponame),
})))
}

View File

@@ -169,6 +169,7 @@ func AddChanges(repoPath string, all bool, files ...string) error {
if all {
cmd.AddArguments("--all")
}
cmd.AddArguments("--")
_, err := cmd.AddArguments(files...).RunInDir(repoPath)
return err
}
@@ -304,6 +305,7 @@ func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error)
}
// FileChangedSinceCommit Returns true if the file given has changed since the the past commit
// YOU MUST ENSURE THAT pastCommit is a valid commit ID.
func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) {
return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
}

View File

@@ -68,7 +68,9 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom
// get it for free during the tree traversal and it's used for listing
// pages to display information about newest commit for a given path.
var treeCommit *Commit
if rev, ok := revs[""]; ok {
if treePath == "" {
treeCommit = commit
} else if rev, ok := revs[""]; ok {
treeCommit = convertCommit(rev)
}
return commitsInfo, treeCommit, nil

View File

@@ -28,21 +28,27 @@ func cloneRepo(url, dir, name string) (string, error) {
func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
// these test case are specific to the repo1 test repo
testCases := []struct {
CommitID string
Path string
ExpectedIDs map[string]string
CommitID string
Path string
ExpectedIDs map[string]string
ExpectedTreeCommit string
}{
{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{
"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
}},
}, "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2"},
{"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{
"file1.txt": "2839944139e0de9737a044f78b0e4b40d989a9e3",
"branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185",
}},
}, "2839944139e0de9737a044f78b0e4b40d989a9e3"},
{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{
"branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658",
}},
}, "5c80b0245c1c6f8343fa418ec374b13b5d4ee658"},
{"feaf4ba6bc635fec442f46ddd4512416ec43c2c2", "", map[string]string{
"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
"foo": "37991dec2c8e592043f47155ce4808d4580f9123",
}, "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"},
}
for _, testCase := range testCases {
commit, err := repo1.GetCommit(testCase.CommitID)
@@ -51,7 +57,8 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
assert.NoError(t, err)
entries, err := tree.ListEntries()
assert.NoError(t, err)
commitsInfo, _, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
commitsInfo, treeCommit, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
assert.Equal(t, testCase.ExpectedTreeCommit, treeCommit.ID.String())
assert.NoError(t, err)
assert.Len(t, commitsInfo, len(testCase.ExpectedIDs))
for _, commitInfo := range commitsInfo {

View File

@@ -187,8 +187,7 @@ func Pull(repoPath string, opts PullRemoteOptions) error {
if opts.All {
cmd.AddArguments("--all")
} else {
cmd.AddArguments(opts.Remote)
cmd.AddArguments(opts.Branch)
cmd.AddArguments("--", opts.Remote, opts.Branch)
}
if opts.Timeout <= 0 {
@@ -213,7 +212,7 @@ func Push(repoPath string, opts PushOptions) error {
if opts.Force {
cmd.AddArguments("-f")
}
cmd.AddArguments(opts.Remote, opts.Branch)
cmd.AddArguments("--", opts.Remote, opts.Branch)
_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
return err
}

View File

@@ -135,7 +135,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
cmd.AddArguments("-d")
}
cmd.AddArguments(name)
cmd.AddArguments("--", name)
_, err := cmd.RunInDir(repo.Path)
return err

View File

@@ -117,20 +117,26 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
return commit, nil
}
// GetCommit returns commit object of by ID string.
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
// ConvertToSHA1 returns a Hash object from a potential ID string
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
if len(commitID) != 40 {
var err error
actualCommitID, err := NewCommand("rev-parse", commitID).RunInDir(repo.Path)
actualCommitID, err := NewCommand("rev-parse", "--verify", commitID).RunInDir(repo.Path)
if err != nil {
if strings.Contains(err.Error(), "unknown revision or path") {
return nil, ErrNotExist{commitID, ""}
if strings.Contains(err.Error(), "unknown revision or path") ||
strings.Contains(err.Error(), "fatal: Needed a single revision") {
return SHA1{}, ErrNotExist{commitID, ""}
}
return nil, err
return SHA1{}, err
}
commitID = actualCommitID
}
id, err := NewIDFromString(commitID)
return NewIDFromString(commitID)
}
// GetCommit returns commit object of by ID string.
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
id, err := repo.ConvertToSHA1(commitID)
if err != nil {
return nil, err
}
@@ -243,6 +249,7 @@ func (repo *Repository) getFilesChanged(id1, id2 string) ([]string, error) {
}
// FileChangedBetweenCommits Returns true if the file changed between commit IDs id1 and id2
// You must ensure that id1 and id2 are valid commit ids.
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
if err != nil {

View File

@@ -55,5 +55,5 @@ func TestGetCommitWithBadCommitID(t *testing.T) {
commit, err := bareRepo1.GetCommit("bad_branch")
assert.Nil(t, commit)
assert.Error(t, err)
assert.EqualError(t, err, "object does not exist [id: bad_branch, rel_path: ]")
assert.True(t, IsErrNotExist(err))
}

View File

@@ -39,7 +39,7 @@ func (repo *Repository) GetMergeBase(tmpRemote string, base, head string) (strin
}
}
stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path)
stdout, err := NewCommand("merge-base", "--", base, head).RunInDir(repo.Path)
return strings.TrimSpace(stdout), base, err
}
@@ -54,7 +54,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string)
if repo.Path != basePath {
// Add a temporary remote
tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
if err = repo.AddRemote(tmpRemote, basePath, true); err != nil {
if err = repo.AddRemote(tmpRemote, basePath, false); err != nil {
return nil, fmt.Errorf("AddRemote: %v", err)
}
defer func() {

View File

@@ -12,7 +12,7 @@ import (
// ReadTreeToIndex reads a treeish to the index
func (repo *Repository) ReadTreeToIndex(treeish string) error {
if len(treeish) != 40 {
res, err := NewCommand("rev-parse", treeish).RunInDir(repo.Path)
res, err := NewCommand("rev-parse", "--verify", treeish).RunInDir(repo.Path)
if err != nil {
return err
}

View File

@@ -23,12 +23,12 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, code)
assert.EqualValues(t, 8, code.CommitCount)
assert.EqualValues(t, 2, code.AuthorCount)
assert.EqualValues(t, 8, code.CommitCountInAllBranches)
assert.EqualValues(t, 9, code.CommitCount)
assert.EqualValues(t, 3, code.AuthorCount)
assert.EqualValues(t, 9, code.CommitCountInAllBranches)
assert.EqualValues(t, 10, code.Additions)
assert.EqualValues(t, 1, code.Deletions)
assert.Len(t, code.Authors, 2)
assert.Len(t, code.Authors, 3)
assert.Contains(t, code.Authors, "tris.git@shoddynet.org")
assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
assert.EqualValues(t, 5, code.Authors[""])

View File

@@ -29,13 +29,13 @@ func (repo *Repository) IsTagExist(name string) bool {
// CreateTag create one tag in the repository
func (repo *Repository) CreateTag(name, revision string) error {
_, err := NewCommand("tag", name, revision).RunInDir(repo.Path)
_, err := NewCommand("tag", "--", name, revision).RunInDir(repo.Path)
return err
}
// CreateAnnotatedTag create one annotated tag in the repository
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
_, err := NewCommand("tag", "-a", "-m", message, name, revision).RunInDir(repo.Path)
_, err := NewCommand("tag", "-a", "-m", message, "--", name, revision).RunInDir(repo.Path)
return err
}
@@ -153,15 +153,18 @@ func (repo *Repository) GetTagNameBySHA(sha string) (string, error) {
// GetTagID returns the object ID for a tag (annotated tags have both an object SHA AND a commit SHA)
func (repo *Repository) GetTagID(name string) (string, error) {
stdout, err := NewCommand("show-ref", name).RunInDir(repo.Path)
stdout, err := NewCommand("show-ref", "--tags", "--", name).RunInDir(repo.Path)
if err != nil {
return "", err
}
fields := strings.Fields(stdout)
if len(fields) != 2 {
return "", ErrNotExist{ID: name}
// Make sure exact match is used: "v1" != "release/v1"
for _, line := range strings.Split(stdout, "\n") {
fields := strings.Fields(line)
if len(fields) == 2 && fields[1] == "refs/tags/"+name {
return fields[0], nil
}
}
return fields[0], nil
return "", ErrNotExist{ID: name}
}
// GetTag returns a Git tag by given name.

View File

@@ -62,6 +62,16 @@ func TestRepository_GetTag(t *testing.T) {
assert.NotEqual(t, aTagID, aTag.Object.String())
assert.EqualValues(t, aTagCommitID, aTag.Object.String())
assert.EqualValues(t, "tag", aTag.Type)
rTagCommitID := "8006ff9adbf0cb94da7dad9e537e53817f9fa5c0"
rTagName := "release/" + lTagName
bareRepo1.CreateTag(rTagName, rTagCommitID)
rTagID, err := bareRepo1.GetTagID(rTagName)
assert.NoError(t, err)
assert.EqualValues(t, rTagCommitID, rTagID)
oTagID, err := bareRepo1.GetTagID(lTagName)
assert.NoError(t, err)
assert.EqualValues(t, lTagCommitID, oTagID)
}
func TestRepository_GetAnnotatedTag(t *testing.T) {

View File

@@ -28,7 +28,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != 40 {
res, err := NewCommand("rev-parse", idStr).RunInDir(repo.Path)
res, err := NewCommand("rev-parse", "--verify", idStr).RunInDir(repo.Path)
if err != nil {
return nil, err
}
@@ -63,7 +63,7 @@ type CommitTreeOpts struct {
// CommitTree creates a commit from a given tree id for the user with provided message
func (repo *Repository) CommitTree(sig *Signature, tree *Tree, opts CommitTreeOpts) (SHA1, error) {
commitTimeStr := time.Now().Format(time.UnixDate)
commitTimeStr := time.Now().Format(time.RFC3339)
// Because this may call hooks we should pass in the environment
env := append(os.Environ(),

View File

@@ -0,0 +1 @@
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200 push

View File

@@ -0,0 +1 @@
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200 push

View File

@@ -1 +1 @@
37991dec2c8e592043f47155ce4808d4580f9123
feaf4ba6bc635fec442f46ddd4512416ec43c2c2

View File

@@ -108,6 +108,11 @@ func (te *TreeEntry) IsRegular() bool {
return te.gogitTreeEntry.Mode == filemode.Regular
}
// IsExecutable if the entry is an executable file (not necessarily binary)
func (te *TreeEntry) IsExecutable() bool {
return te.gogitTreeEntry.Mode == filemode.Executable
}
// Blob returns the blob object the entry
func (te *TreeEntry) Blob() *Blob {
encodedObj, err := te.ptree.repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, te.gogitTreeEntry.Hash)

View File

@@ -153,7 +153,7 @@ func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
}
body = blackfriday.Markdown(body, renderer, exts)
return body
return markup.SanitizeBytes(body)
}
var (

View File

@@ -111,7 +111,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
RepoID: g.repo.ID,
Name: milestone.Title,
Content: milestone.Description,
IsClosed: milestone.State == "close",
IsClosed: milestone.State == "closed",
DeadlineUnix: deadline,
}
if ms.IsClosed && milestone.Closed != nil {

View File

@@ -173,6 +173,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
var (
closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC)
closed7 = time.Date(2019, 7, 8, 8, 20, 23, 0, time.UTC)
)
assert.EqualValues(t, []*base.Issue{
{
@@ -208,9 +209,9 @@ func TestGitHubDownloadRepo(t *testing.T) {
Number: 7,
Title: "display page revisions on wiki",
Content: "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991",
Milestone: "1.x.x",
Milestone: "1.10.0",
PosterName: "joubertredrat",
State: "open",
State: "closed",
Created: time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC),
Labels: []*base.Label{
{
@@ -232,6 +233,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
Heart: 0,
Hooray: 0,
},
Closed: &closed7,
},
{
Number: 8,

View File

@@ -29,12 +29,13 @@ type HookOptions struct {
UserName string
GitObjectDirectory string
GitAlternativeObjectDirectories string
GitQuarantinePath string
ProtectedBranchID int64
}
// HookPreReceive check whether the provided commits are allowed
func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) {
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&prID=%d",
reqURL := setting.LocalURL + fmt.Sprintf("api/internal/hook/pre-receive/%s/%s?old=%s&new=%s&ref=%s&userID=%d&gitObjectDirectory=%s&gitAlternativeObjectDirectories=%s&gitQuarantinePath=%s&prID=%d",
url.PathEscape(ownerName),
url.PathEscape(repoName),
url.QueryEscape(opts.OldCommitID),
@@ -43,6 +44,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string)
opts.UserID,
url.QueryEscape(opts.GitObjectDirectory),
url.QueryEscape(opts.GitAlternativeObjectDirectories),
url.QueryEscape(opts.GitQuarantinePath),
opts.ProtectedBranchID,
)

View File

@@ -49,7 +49,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
}
defer func() {
go models.HookQueue.Add(pr.BaseRepo.ID)
go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
}()
@@ -102,7 +101,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
}
// Fetch head branch
if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
if err := git.NewCommand("fetch", remoteRepoName, pr.HeadBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
}
@@ -241,7 +240,13 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
headUser = doer
}
env := models.FullPushingEnvironment(headUser, doer, pr.BaseRepo, pr.ID)
env := models.FullPushingEnvironment(
headUser,
doer,
pr.BaseRepo,
pr.BaseRepo.Name,
pr.ID,
)
// Push back to upstream.
if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
@@ -287,39 +292,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
go models.HookQueue.Add(pr.Issue.Repo.ID)
}
l, err := baseGitRepo.CommitsBetweenIDs(pr.MergedCommitID, pr.MergeBase)
if err != nil {
log.Error("CommitsBetweenIDs: %v", err)
return nil
}
// It is possible that head branch is not fully sync with base branch for merge commits,
// so we need to get latest head commit and append merge commit manually
// to avoid strange diff commits produced.
mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch)
if err != nil {
log.Error("GetBranchCommit: %v", err)
return nil
}
if mergeStyle == models.MergeStyleMerge {
l.PushFront(mergeCommit)
}
p := &api.PushPayload{
Ref: git.BranchPrefix + pr.BaseBranch,
Before: pr.MergeBase,
After: mergeCommit.ID.String(),
CompareURL: setting.AppURL + pr.BaseRepo.ComposeCompareURL(pr.MergeBase, pr.MergedCommitID),
Commits: models.ListToPushCommits(l).ToAPIPayloadCommits(pr.BaseRepo.HTMLURL()),
Repo: pr.BaseRepo.APIFormat(mode),
Pusher: pr.HeadRepo.MustOwner().APIFormat(),
Sender: doer.APIFormat(),
}
if err = models.PrepareWebhooks(pr.BaseRepo, models.HookEventPush, p); err != nil {
log.Error("PrepareWebhooks: %v", err)
} else {
go models.HookQueue.Add(pr.BaseRepo.ID)
}
return nil
}
@@ -327,8 +299,7 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) {
var outbuf, errbuf strings.Builder
// Compute the diff-tree for sparse-checkout
// The branch argument must be enclosed with double-quotes ("") in case it contains slashes (e.g "feature/test")
if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch).RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil {
if err := git.NewCommand("diff-tree", "--no-commit-id", "--name-only", "-r", "--root", baseBranch, headBranch, "--").RunInDirPipeline(repoPath, &outbuf, &errbuf); err != nil {
return "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String())
}
return outbuf.String(), nil

View File

@@ -92,6 +92,12 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
// Assigned LastCommitID in opts if it hasn't been set
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err)
}
opts.LastCommitID = lastCommitID.String()
}
// Get the files in the index
@@ -172,32 +178,6 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
return nil, err
}
// Simulate push event.
oldCommitID := opts.LastCommitID
if opts.NewBranch != opts.OldBranch {
oldCommitID = git.EmptySHA
}
if err = repo.GetOwner(); err != nil {
return nil, fmt.Errorf("GetOwner: %v", err)
}
err = PushUpdate(
repo,
opts.NewBranch,
models.PushUpdateOptions{
PusherID: doer.ID,
PusherName: doer.Name,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: oldCommitID,
NewCommitID: commitHash,
},
)
if err != nil {
return nil, fmt.Errorf("PushUpdate: %v", err)
}
commit, err = t.GetCommit(commitHash)
if err != nil {
return nil, err

View File

@@ -249,7 +249,7 @@ func (t *TemporaryUploadRepository) GetLastCommitByRef(ref string) (string, erro
// CommitTree creates a commit from a given tree for the user with provided message
func (t *TemporaryUploadRepository) CommitTree(author, committer *models.User, treeHash string, message string) (string, error) {
commitTimeStr := time.Now().Format(time.UnixDate)
commitTimeStr := time.Now().Format(time.RFC3339)
authorSig := author.NewGitSig()
committerSig := committer.NewGitSig()

View File

@@ -188,6 +188,13 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
// Assigned LastCommitID in opts if it hasn't been set
if opts.LastCommitID == "" {
opts.LastCommitID = commit.ID.String()
} else {
lastCommitID, err := t.gitRepo.ConvertToSHA1(opts.LastCommitID)
if err != nil {
return nil, fmt.Errorf("DeleteRepoFile: Invalid last commit ID: %v", err)
}
opts.LastCommitID = lastCommitID.String()
}
encoding := "UTF-8"
@@ -387,32 +394,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
return nil, err
}
// Simulate push event.
oldCommitID := opts.LastCommitID
if opts.NewBranch != opts.OldBranch || oldCommitID == "" {
oldCommitID = git.EmptySHA
}
if err = repo.GetOwner(); err != nil {
return nil, fmt.Errorf("GetOwner: %v", err)
}
err = PushUpdate(
repo,
opts.NewBranch,
models.PushUpdateOptions{
PusherID: doer.ID,
PusherName: doer.Name,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: oldCommitID,
NewCommitID: commitHash,
},
)
if err != nil {
return nil, fmt.Errorf("PushUpdate: %v", err)
}
commit, err = t.GetCommit(commitHash)
if err != nil {
return nil, err

View File

@@ -11,7 +11,6 @@ import (
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/setting"
)
@@ -177,31 +176,5 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
return err
}
// Simulate push event.
oldCommitID := opts.LastCommitID
if opts.NewBranch != opts.OldBranch {
oldCommitID = git.EmptySHA
}
if err = repo.GetOwner(); err != nil {
return fmt.Errorf("GetOwner: %v", err)
}
err = PushUpdate(
repo,
opts.NewBranch,
models.PushUpdateOptions{
PusherID: doer.ID,
PusherName: doer.Name,
RepoUserName: repo.Owner.Name,
RepoName: repo.Name,
RefFullName: git.BranchPrefix + opts.NewBranch,
OldCommitID: oldCommitID,
NewCommitID: commitHash,
},
)
if err != nil {
return fmt.Errorf("PushUpdate: %v", err)
}
return models.DeleteUploads(uploads...)
}

View File

@@ -10,9 +10,9 @@ type FileOptions struct {
// message (optional) for the commit of this file. if not supplied, a default message will be used
Message string `json:"message"`
// branch (optional) to base this file from. if not given, the default branch is used
BranchName string `json:"branch"`
BranchName string `json:"branch" binding:"GitRefName;MaxSize(100)"`
// new_branch (optional) will make a new branch from `branch` before creating the file
NewBranchName string `json:"new_branch"`
NewBranchName string `json:"new_branch" binding:"GitRefName;MaxSize(100)"`
// `author` and `committer` are optional (if only one is given, it will be used for the other, otherwise the authenticated user will be used)
Author Identity `json:"author"`
Committer Identity `json:"committer"`

View File

@@ -694,6 +694,7 @@ editor.delete = Delete '%s'
editor.commit_message_desc = Add an optional extended description…
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
editor.propose_file_change = Propose file change
editor.new_branch_name_desc = New branch name…
editor.cancel = Cancel
editor.filename_cannot_be_empty = The filename cannot be empty.

View File

@@ -208,6 +208,9 @@ footer .ui.left,footer .ui.right{line-height:40px}
.ui.tabular.menu .item{color:rgba(0,0,0,.5)}
.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}
.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}
.inline-grouped-list{display:inline-block;vertical-align:top}
.inline-grouped-list>.ui{display:block;margin-top:5px;margin-bottom:10px}
.inline-grouped-list>.ui:first-child{margin-top:1px}
.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}
.markdown:not(code).ui.segment{padding:3em}
.markdown:not(code).file-view{padding:2em 2em 2em!important}
@@ -620,6 +623,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository #commits-table thead .sha{width:140px}
.repository #commits-table thead .shatd{text-align:center}
.repository #commits-table td.sha .sha.label{margin:0}
.repository #commits-table td.message{text-overflow:unset}
.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}
.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #bbb}
.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#fafafa;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #bbb;border-top-left-radius:0;border-bottom-left-radius:0}
@@ -664,6 +668,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository .diff-file-box .code-diff-split tbody tr td:nth-child(4){border-left-width:1px;border-left-style:solid}
.repository .diff-file-box.file-content{clear:right}
.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}
.repository .diff-file-box.file-content img.emoji{padding:0}
.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}
.repository .repo-search-result{padding-top:10px;padding-bottom:10px}
.repository .repo-search-result .lines-num a{color:inherit}
@@ -744,7 +749,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository .segment.reactions .select-reaction{float:none}
.repository .segment.reactions .select-reaction:not(.active) a{display:none}
.repository .segment.reactions:hover .select-reaction a{display:block}
.user-cards .list{padding:0}
.user-cards .list{padding:0;display:flex;flex-wrap:wrap}
.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}
.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}
.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}
@@ -814,8 +819,8 @@ footer .ui.left,footer .ui.right{line-height:40px}
.stats-table .table-cell{display:table-cell}
.stats-table .table-cell.tiny{height:.5em}
tbody.commit-list{vertical-align:baseline}
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 24px);display:inline-block;vertical-align:middle}
.commit-list .message-wrapper .commit-status-link{display:inline-block;vertical-align:middle}
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 50px);display:inline-block;vertical-align:middle}
.commit-list .commit-status-link{display:inline-block;vertical-align:middle}
.commit-body{white-space:pre-wrap}
.git-notes.top{text-align:left}
.git-notes .commit-body{margin:0}

View File

@@ -209,7 +209,7 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb
.repository .label.list .item{border-bottom:1px dashed #4c505c}
.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}
.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important}
.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important}
.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}

View File

@@ -10,6 +10,11 @@ function htmlEncode(text) {
var csrf;
var suburl;
// Disable Dropzone auto-discover because it's manually initialized
if (typeof(Dropzone) !== "undefined") {
Dropzone.autoDiscover = false;
}
// Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
if (!Array.from) {
Array.from = (function () {
@@ -1270,6 +1275,7 @@ function initEditor() {
$('.quick-pull-branch-name').hide();
$('.quick-pull-branch-name input').prop('required',false);
}
$('#commit-button').text($(this).attr('button_text'));
});
var $editFilename = $("#file-name");
@@ -1968,17 +1974,18 @@ $(document).ready(function () {
// Highlight JS
if (typeof hljs != 'undefined') {
hljs.initHighlightingOnLoad();
const nodes = [].slice.call(document.querySelectorAll('pre code') || []);
for (let i = 0; i < nodes.length; i++) {
hljs.highlightBlock(nodes[i]);
}
}
// Dropzone
var $dropzone = $('#dropzone');
const $dropzone = $('#dropzone');
if ($dropzone.length > 0) {
// Disable auto discover for all elements:
Dropzone.autoDiscover = false;
const filenameDict = {};
var filenameDict = {};
$dropzone.dropzone({
new Dropzone("#dropzone", {
url: $dropzone.data('upload-url'),
headers: {"X-Csrf-Token": csrf},
maxFiles: $dropzone.data('max-file'),
@@ -2006,7 +2013,7 @@ $(document).ready(function () {
});
}
})
}
},
});
}
@@ -2104,12 +2111,16 @@ $(document).ready(function () {
});
$('.issue-action').click(function () {
var action = this.dataset.action
var elementId = this.dataset.elementId
var issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
let action = this.dataset.action;
let elementId = this.dataset.elementId;
let issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
return this.dataset.issueId;
}).get().join();
var url = this.dataset.url
let url = this.dataset.url;
if (elementId === '0' && url.substr(-9) === '/assignee'){
elementId = '';
action = 'clear';
}
updateIssuesMeta(url, action, issueIDs, elementId).then(reload);
});

View File

@@ -605,7 +605,6 @@ code,
.file-comment {
font: 12px @monospaced-fonts, monospace;
color: rgba(0, 0, 0, 0.87);
}
.ui.floating.dropdown {
@@ -877,3 +876,19 @@ footer {
.ui.tabular.menu .item.active {
color: rgba(0, 0, 0, 0.9);
}
/* multiple radio or checkboxes as inline element */
.inline-grouped-list {
display: inline-block;
vertical-align: top;
> .ui {
display: block;
margin-top: 5px;
margin-bottom: 10px;
&:first-child {
margin-top: 1px;
}
}
}

View File

@@ -1265,6 +1265,10 @@
margin: 0;
}
td.message {
text-overflow: unset;
}
&.ui.basic.striped.table tbody tr:nth-child(2n) {
background-color: rgba(0, 0, 0, 0.02) !important;
}
@@ -1540,6 +1544,9 @@
max-width: 100%;
padding: 5px 5px 0 5px;
}
img.emoji {
padding: 0;
}
clear: right;
}
@@ -1971,6 +1978,8 @@
&.user-cards {
.list {
padding: 0;
display: flex;
flex-wrap: wrap;
.item {
list-style: none;
@@ -2300,12 +2309,12 @@ tbody.commit-list {
.commit-list .message-wrapper {
overflow: hidden;
text-overflow: ellipsis;
max-width: calc(100% - 24px);
max-width: calc(100% - 50px);
display: inline-block;
vertical-align: middle;
}
.commit-list .message-wrapper .commit-status-link {
.commit-list .commit-status-link {
display: inline-block;
vertical-align: middle;
}

View File

@@ -1082,7 +1082,7 @@ a.ui.labels .label:hover {
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) {

View File

@@ -6,7 +6,10 @@ File(s): /vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
Version: 1.9.0
File(s): /vendor/plugins/jquery/jquery.min.js
Version: 1.12.4
Version: 3.4.1
File(s): /vendor/plugins/jquery-migrate/jquery-migrate.min.js
Version: 3.0.1
File(s): /vendor/plugins/semantic/semantic.min.js
Version: 2.3.1

View File

@@ -17,8 +17,13 @@
</tr>
<tr>
<td><a href="./plugins/jquery/jquery.min.js">jquery.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
<td><a href="https://code.jquery.com/jquery-1.12.4.min.js">jquery-1.12.4.min.js</a></td>
<td><a href="https://jquery.org/license/">MIT</a></td>
<td><a href="https://code.jquery.com/jquery-3.4.1.min.js">jquery-3.4.1.min.js</a></td>
</tr>
<tr>
<td><a href="./plugins/jquery-migrate/jquery-migrate.min.js">jquery-migrate.min.js</a></td>
<td><a href="https://jquery.org/license/">MIT</a></td>
<td><a href="https://code.jquery.com/jquery-migrate-3.0.1.min.js">jquery-migrate-3.0.1.min.js</a></td>
</tr>
<tr>
<td><a href="./plugins/semantic/semantic.min.js">semantic.min.js</a></td>

View File

@@ -0,0 +1,215 @@
/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */
void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) {
"function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window);
}(function(e, t) {
"use strict";
function r(r) {
var n = t.console;
o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r),
e.migrateTrace && n.trace && n.trace()));
}
function n(e, t, n, a) {
Object.defineProperty(e, t, {
configurable: !0,
enumerable: !0,
get: function() {
return r(a), n;
},
set: function(e) {
r(a), n = e;
}
});
}
function a(e, t, n, a) {
e[t] = function() {
return r(a), n.apply(this, arguments);
};
}
e.migrateVersion = "3.0.1", function() {
var r = /^[12]\./;
t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),
e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),
t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion));
}();
var o = {};
e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() {
o = {}, e.migrateWarnings.length = 0;
}, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode");
var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
e.fn.init = function(e) {
var t = Array.prototype.slice.call(arguments);
return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"),
t[0] = []), i.apply(this, t);
}, e.fn.init.prototype = e.fn, e.find = function(e) {
var n = Array.prototype.slice.call(arguments);
if ("string" == typeof e && c.test(e)) try {
t.document.querySelector(e);
} catch (a) {
e = e.replace(l, function(e, t, r, n) {
return "[" + t + r + '"' + n + '"]';
});
try {
t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]),
n[0] = e;
} catch (e) {
r("Attribute selector with '#' was not fixed: " + n[0]);
}
}
return u.apply(this, n);
};
var d;
for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]);
e.fn.size = function() {
return r("jQuery.fn.size() is deprecated and removed; use the .length property"),
this.length;
}, e.parseJSON = function() {
return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments);
}, e.isNumeric = function(t) {
var n = s(t), a = function(t) {
var r = t && t.toString();
return !e.isArray(t) && r - parseFloat(r) + 1 >= 0;
}(t);
return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"),
a;
}, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"),
n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),
n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos");
var p = e.ajax;
e.ajax = function() {
var e = p.apply(this, arguments);
return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"),
a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")),
e;
};
var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g;
e.fn.removeAttr = function(t) {
var n = this;
return e.each(t.match(m), function(t, a) {
e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a),
n.prop(a, !1));
}), f.apply(this, arguments);
}, e.fn.toggleClass = function(t) {
return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"),
this.each(function() {
var r = this.getAttribute && this.getAttribute("class") || "";
r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || "");
}));
};
var h = !1;
e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) {
var n = e.cssHooks[r] && e.cssHooks[r].get;
n && (e.cssHooks[r].get = function() {
var e;
return h = !0, e = n.apply(this, arguments), h = !1, e;
});
}), e.swap = function(e, t, n, a) {
var o, i, s = {};
h || r("jQuery.swap() is undocumented and deprecated");
for (i in t) s[i] = e.style[i], e.style[i] = t[i];
o = n.apply(e, a || []);
for (i in t) e.style[i] = s[i];
return o;
};
var g = e.data;
e.data = function(t, n, a) {
var o;
if (n && "object" == typeof n && 2 === arguments.length) {
o = e.hasData(t) && g.call(this, t);
var i = {};
for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s),
o[s] = n[s]) : i[s] = n[s];
return g.call(this, t, i), n;
}
return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n),
arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments);
};
var v = e.Tween.prototype.run, j = function(e) {
return e;
};
e.Tween.prototype.run = function() {
e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"),
e.easing[this.easing] = j), v.apply(this, arguments);
}, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated");
var Q = e.fn.load, b = e.event.add, w = e.event.fix;
e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"),
e.event.fix = function(t) {
var n, a = t.type, o = this.fixHooks[a], i = e.event.props;
if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop());
if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a),
(i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop());
return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n;
}, e.event.add = function(e, n) {
return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"),
b.apply(this, arguments);
}, e.each([ "load", "unload", "error" ], function(t, n) {
e.fn[n] = function() {
var e = Array.prototype.slice.call(arguments, 0);
return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"),
e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e),
this));
};
}), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) {
e.fn[n] = function(e, t) {
return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n);
};
}), e(function() {
e(t.document).triggerHandler("ready");
}), e.event.special.ready = {
setup: function() {
this === t.document && r("'ready' event is deprecated");
}
}, e.fn.extend({
bind: function(e, t, n) {
return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n);
},
unbind: function(e, t) {
return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t);
},
delegate: function(e, t, n, a) {
return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a);
},
undelegate: function(e, t, n) {
return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
},
hover: function(e, t) {
return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e);
}
});
var x = e.fn.offset;
e.fn.offset = function() {
var n, a = this[0], o = {
top: 0,
left: 0
};
return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"),
o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o);
};
var k = e.param;
e.param = function(t, n) {
var a = e.ajaxSettings && e.ajaxSettings.traditional;
return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),
n = a), k.call(this, t, n);
};
var A = e.fn.andSelf || e.fn.addBack;
e.fn.andSelf = function() {
return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),
A.apply(this, arguments);
};
var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ];
return e.Deferred = function(t) {
var n = S(), a = n.promise();
return n.pipe = a.pipe = function() {
var t = arguments;
return r("deferred.pipe() is deprecated"), e.Deferred(function(r) {
e.each(q, function(o, i) {
var s = e.isFunction(t[o]) && t[o];
n[i[1]](function() {
var t = s && s.apply(this, arguments);
t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments);
});
}), t = null;
}).promise();
}, t && t.call(n, n), n;
}, e.Deferred.exceptionHook = S.exceptionHook, e;
});

File diff suppressed because one or more lines are too long

View File

@@ -82,6 +82,15 @@ func GetAllOrgs(ctx *context.APIContext) {
// summary: List all organizations
// produces:
// - application/json
// parameters:
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results, maximum page size is 50
// type: integer
// responses:
// "200":
// "$ref": "#/responses/OrganizationList"
@@ -90,7 +99,9 @@ func GetAllOrgs(ctx *context.APIContext) {
users, _, err := models.SearchUsers(&models.SearchUserOptions{
Type: models.UserTypeOrganization,
OrderBy: models.SearchOrderByAlphabetically,
PageSize: -1,
Page: ctx.QueryInt("page"),
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
Private: true,
})
if err != nil {
ctx.Error(500, "SearchOrganizations", err)

View File

@@ -91,8 +91,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
if form.SendNotify && setting.MailService != nil {
models.SendRegisterNotifyMail(ctx.Context.Context, u)
}
ctx.JSON(201, u.APIFormat())
ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
// EditUser api for modifying a user's information
@@ -181,7 +180,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
}
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
ctx.JSON(200, u.APIFormat())
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
// DeleteUser api for deleting a user
@@ -326,7 +325,7 @@ func GetAllUsers(ctx *context.APIContext) {
results := make([]*api.User, len(users))
for i := range users {
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
}
ctx.JSON(200, &results)

View File

@@ -74,7 +74,6 @@ import (
"code.gitea.io/gitea/routers/api/v1/user"
"github.com/go-macaron/binding"
"github.com/go-macaron/cors"
macaron "gopkg.in/macaron.v1"
)
@@ -501,12 +500,6 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/swagger", misc.Swagger) //Render V1 by default
}
var handlers []macaron.Handler
if setting.EnableCORS {
handlers = append(handlers, cors.CORS(setting.CORSConfig))
}
handlers = append(handlers, securityHeaders(), context.APIContexter(), sudo())
m.Group("/v1", func() {
// Miscellaneous
if setting.API.EnableSwagger {
@@ -852,7 +845,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/topics", func() {
m.Get("/search", repo.TopicSearch)
})
}, handlers...)
}, securityHeaders(), context.APIContexter(), sudo())
}
func securityHeaders() macaron.Handler {

View File

@@ -229,7 +229,7 @@ func ToTeam(team *models.Team) *api.Team {
}
// ToUser convert models.User to api.User
func ToUser(user *models.User, signed, admin bool) *api.User {
func ToUser(user *models.User, signed, authed bool) *api.User {
result := &api.User{
ID: user.ID,
UserName: user.Name,
@@ -239,7 +239,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User {
LastLogin: user.LastLoginUnix.AsTime(),
Created: user.CreatedUnix.AsTime(),
}
if signed && (!user.KeepEmailPrivate || admin) {
// hide primary email if API caller isn't user itself or an admin
if !signed {
result.Email = ""
} else if user.KeepEmailPrivate && !authed {
result.Email = user.GetEmail()
} else {
result.Email = user.Email
}
return result

View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/convert"
"code.gitea.io/gitea/routers/api/v1/user"
)
@@ -46,7 +47,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
apiMembers := make([]*api.User, len(members))
for i, member := range members {
apiMembers[i] = member.APIFormat()
apiMembers[i] = convert.ToUser(member, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
}
ctx.JSON(200, apiMembers)
}

View File

@@ -257,7 +257,7 @@ func GetTeamMembers(ctx *context.APIContext) {
}
members := make([]*api.User, len(team.Members))
for i, member := range team.Members {
members[i] = member.APIFormat()
members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
}
ctx.JSON(200, members)
}
@@ -288,7 +288,7 @@ func GetTeamMember(ctx *context.APIContext) {
if ctx.Written() {
return
}
ctx.JSON(200, u.APIFormat())
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
// AddTeamMember api for add a member to a team

View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
)
// ListCollaborators list a repository's collaborators
@@ -42,7 +43,7 @@ func ListCollaborators(ctx *context.APIContext) {
}
users := make([]*api.User, len(collaborators))
for i, collaborator := range collaborators {
users[i] = collaborator.APIFormat()
users[i] = convert.ToUser(collaborator.User, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
}
ctx.JSON(200, users)
}

View File

@@ -92,7 +92,7 @@ func GetSingleCommit(ctx *context.APIContext) {
URL: setting.AppURL + ctx.Link[1:],
SHA: commit.ID.String(),
},
HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(),
HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
RepoCommit: &api.RepoCommit{
URL: setting.AppURL + ctx.Link[1:],
Author: &api.CommitUser{
@@ -111,7 +111,7 @@ func GetSingleCommit(ctx *context.APIContext) {
},
Message: commit.Message(),
Tree: &api.CommitMeta{
URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(),
URL: ctx.Repo.Repository.APIURL() + "/git/trees/" + commit.ID.String(),
SHA: commit.ID.String(),
},
},

View File

@@ -71,19 +71,22 @@ func GetGitRefs(ctx *context.APIContext) {
getGitRefsInternal(ctx, ctx.Params("*"))
}
func getGitRefsInternal(ctx *context.APIContext, filter string) {
func getGitRefs(ctx *context.APIContext, filter string) ([]*git.Reference, string, error) {
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
if err != nil {
ctx.Error(500, "OpenRepository", err)
return
return nil, "OpenRepository", err
}
if len(filter) > 0 {
filter = "refs/" + filter
}
refs, err := gitRepo.GetRefsFiltered(filter)
return refs, "GetRefsFiltered", err
}
func getGitRefsInternal(ctx *context.APIContext, filter string) {
refs, lastMethodName, err := getGitRefs(ctx, filter)
if err != nil {
ctx.Error(500, "GetRefsFiltered", err)
ctx.Error(500, lastMethodName, err)
return
}

View File

@@ -130,8 +130,8 @@ func TestHook(ctx *context.APIContext) {
convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
},
Repo: ctx.Repo.Repository.APIFormat(models.AccessModeNone),
Pusher: ctx.User.APIFormat(),
Sender: ctx.User.APIFormat(),
Pusher: convert.ToUser(ctx.User, ctx.IsSigned, false),
Sender: convert.ToUser(ctx.User, ctx.IsSigned, false),
}); err != nil {
ctx.Error(500, "PrepareWebhook: ", err)
return

View File

@@ -183,7 +183,8 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
allowed := false
for _, t := range allowedTypes {
t := strings.Trim(t, " ")
if t == "*/*" || t == fileType {
if t == "*/*" || t == fileType ||
strings.HasPrefix(fileType, t+";") {
allowed = true
break
}

View File

@@ -646,89 +646,102 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
})
}
if opts.HasIssues != nil {
if *opts.HasIssues {
// We don't currently allow setting individual issue settings through the API,
// only can enable/disable issues, so when enabling issues,
// we either get the existing config which means it was already enabled,
// or create a new config since it doesn't exist.
unit, err := repo.GetUnit(models.UnitTypeIssues)
var config *models.IssuesConfig
if err != nil {
// Unit type doesn't exist so we make a new config file with default values
config = &models.IssuesConfig{
EnableTimetracker: true,
AllowOnlyContributorsToTrackTime: true,
EnableDependencies: true,
}
} else {
config = unit.IssuesConfig()
}
units = append(units, models.RepoUnit{
RepoID: repo.ID,
Type: models.UnitTypeIssues,
Config: config,
})
if opts.HasIssues == nil {
// If HasIssues setting not touched, rewrite existing repo unit
if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
units = append(units, *unit)
} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
units = append(units, *unit)
}
} else if *opts.HasIssues {
// We don't currently allow setting individual issue settings through the API,
// only can enable/disable issues, so when enabling issues,
// we either get the existing config which means it was already enabled,
// or create a new config since it doesn't exist.
unit, err := repo.GetUnit(models.UnitTypeIssues)
var config *models.IssuesConfig
if err != nil {
// Unit type doesn't exist so we make a new config file with default values
config = &models.IssuesConfig{
EnableTimetracker: true,
AllowOnlyContributorsToTrackTime: true,
EnableDependencies: true,
}
} else {
config = unit.IssuesConfig()
}
units = append(units, models.RepoUnit{
RepoID: repo.ID,
Type: models.UnitTypeIssues,
Config: config,
})
}
if opts.HasWiki != nil {
if *opts.HasWiki {
// We don't currently allow setting individual wiki settings through the API,
// only can enable/disable the wiki, so when enabling the wiki,
// we either get the existing config which means it was already enabled,
// or create a new config since it doesn't exist.
config := &models.UnitConfig{}
units = append(units, models.RepoUnit{
RepoID: repo.ID,
Type: models.UnitTypeWiki,
Config: config,
})
if opts.HasWiki == nil {
// If HasWiki setting not touched, rewrite existing repo unit
if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
units = append(units, *unit)
} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
units = append(units, *unit)
}
} else if *opts.HasWiki {
// We don't currently allow setting individual wiki settings through the API,
// only can enable/disable the wiki, so when enabling the wiki,
// we either get the existing config which means it was already enabled,
// or create a new config since it doesn't exist.
config := &models.UnitConfig{}
units = append(units, models.RepoUnit{
RepoID: repo.ID,
Type: models.UnitTypeWiki,
Config: config,
})
}
if opts.HasPullRequests != nil {
if *opts.HasPullRequests {
// We do allow setting individual PR settings through the API, so
// we get the config settings and then set them
// if those settings were provided in the opts.
unit, err := repo.GetUnit(models.UnitTypePullRequests)
var config *models.PullRequestsConfig
if err != nil {
// Unit type doesn't exist so we make a new config file with default values
config = &models.PullRequestsConfig{
IgnoreWhitespaceConflicts: false,
AllowMerge: true,
AllowRebase: true,
AllowRebaseMerge: true,
AllowSquash: true,
}
} else {
config = unit.PullRequestsConfig()
}
if opts.IgnoreWhitespaceConflicts != nil {
config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
}
if opts.AllowMerge != nil {
config.AllowMerge = *opts.AllowMerge
}
if opts.AllowRebase != nil {
config.AllowRebase = *opts.AllowRebase
}
if opts.AllowRebaseMerge != nil {
config.AllowRebaseMerge = *opts.AllowRebaseMerge
}
if opts.AllowSquash != nil {
config.AllowSquash = *opts.AllowSquash
}
units = append(units, models.RepoUnit{
RepoID: repo.ID,
Type: models.UnitTypePullRequests,
Config: config,
})
if opts.HasPullRequests == nil {
// If HasPullRequest setting not touched, rewrite existing repo unit
if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
units = append(units, *unit)
}
} else if *opts.HasPullRequests {
// We do allow setting individual PR settings through the API, so
// we get the config settings and then set them
// if those settings were provided in the opts.
unit, err := repo.GetUnit(models.UnitTypePullRequests)
var config *models.PullRequestsConfig
if err != nil {
// Unit type doesn't exist so we make a new config file with default values
config = &models.PullRequestsConfig{
IgnoreWhitespaceConflicts: false,
AllowMerge: true,
AllowRebase: true,
AllowRebaseMerge: true,
AllowSquash: true,
}
} else {
config = unit.PullRequestsConfig()
}
if opts.IgnoreWhitespaceConflicts != nil {
config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
}
if opts.AllowMerge != nil {
config.AllowMerge = *opts.AllowMerge
}
if opts.AllowRebase != nil {
config.AllowRebase = *opts.AllowRebase
}
if opts.AllowRebaseMerge != nil {
config.AllowRebaseMerge = *opts.AllowRebaseMerge
}
if opts.AllowSquash != nil {
config.AllowSquash = *opts.AllowSquash
}
units = append(units, models.RepoUnit{
RepoID: repo.ID,
Type: models.UnitTypePullRequests,
Config: config,
})
}
if err := models.UpdateRepositoryUnits(repo, units); err != nil {

View File

@@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
)
// ListStargazers list a repository's stargazers
@@ -38,7 +39,7 @@ func ListStargazers(ctx *context.APIContext) {
}
users := make([]*api.User, len(stargazers))
for i, stargazer := range stargazers {
users[i] = stargazer.APIFormat()
users[i] = convert.ToUser(stargazer, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
}
ctx.JSON(200, users)
}

View File

@@ -46,10 +46,7 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) {
// "$ref": "#/responses/StatusList"
sha := ctx.Params("sha")
if len(sha) == 0 {
sha = ctx.Params("ref")
}
if len(sha) == 0 {
ctx.Error(400, "ref/sha not given", nil)
ctx.Error(400, "sha not given", nil)
return
}
status := &models.CommitStatus{
@@ -121,7 +118,38 @@ func GetCommitStatusesByRef(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/StatusList"
getCommitStatuses(ctx, ctx.Params("ref"))
filter := ctx.Params("ref")
if len(filter) == 0 {
ctx.Error(400, "ref not given", nil)
return
}
for _, reftype := range []string{"heads", "tags"} { //Search branches and tags
refSHA, lastMethodName, err := searchRefCommitByType(ctx, reftype, filter)
if err != nil {
ctx.Error(500, lastMethodName, err)
return
}
if refSHA != "" {
filter = refSHA
break
}
}
getCommitStatuses(ctx, filter) //By default filter is maybe the raw SHA
}
func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (string, string, error) {
refs, lastMethodName, err := getGitRefs(ctx, refType+"/"+filter) //Search by type
if err != nil {
return "", lastMethodName, err
}
if len(refs) > 0 {
return refs[0].Object.String(), "", nil //Return found SHA
}
return "", "", nil
}
func getCommitStatuses(ctx *context.APIContext, sha string) {

View File

@@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
)
// ListSubscribers list a repo's subscribers (i.e. watchers)
@@ -38,7 +39,7 @@ func ListSubscribers(ctx *context.APIContext) {
}
users := make([]*api.User, len(subscribers))
for i, subscriber := range subscribers {
users[i] = subscriber.APIFormat()
users[i] = convert.ToUser(subscriber, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
}
ctx.JSON(200, users)
}

View File

@@ -9,12 +9,13 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/routers/api/v1/convert"
)
func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
apiUsers := make([]*api.User, len(users))
for i := range users {
apiUsers[i] = users[i].APIFormat()
apiUsers[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
}
ctx.JSON(200, &apiUsers)
}

View File

@@ -22,13 +22,13 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
apiKey.KeyType = "user"
if defaultUser.ID == key.OwnerID {
apiKey.Owner = defaultUser.APIFormat()
apiKey.Owner = convert.ToUser(defaultUser, true, true)
} else {
user, err := models.GetUserByID(key.OwnerID)
if err != nil {
return apiKey, err
}
apiKey.Owner = user.APIFormat()
apiKey.Owner = convert.ToUser(user, true, true)
}
} else {
apiKey.KeyType = "unknown"

View File

@@ -104,11 +104,7 @@ func GetInfo(ctx *context.APIContext) {
return
}
// Hide user e-mail when API caller isn't signed in.
if !ctx.IsSigned {
u.Email = ""
}
ctx.JSON(200, u.APIFormat())
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.ID == u.ID || ctx.User.IsAdmin))
}
// GetAuthenticatedUser get current user's information
@@ -121,7 +117,7 @@ func GetAuthenticatedUser(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/User"
ctx.JSON(200, ctx.User.APIFormat())
ctx.JSON(200, convert.ToUser(ctx.User, ctx.IsSigned, ctx.User != nil))
}
// GetUserHeatmapData is the handler to get a users heatmap

View File

@@ -39,6 +39,7 @@ func Settings(ctx *context.Context) {
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
ctx.Data["Title"] = ctx.Tr("org.settings")
ctx.Data["PageIsSettingsOptions"] = true
ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
if ctx.HasError() {
ctx.HTML(200, tplSettingsOptions)

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