Compare commits

..

53 Commits

Author SHA1 Message Date
techknowlogick
eb0ee6bf58 Add 1.6.4 changelog (#5739) 2019-01-15 20:43:07 -05:00
Julian Tölle
937857e3af fix: use correct value for "MSpan Structures Obtained" #4742 (#5706) (#5715)
Signed-off-by: Julian Tölle <julian.toelle97@gmail.com>
2019-01-13 16:32:05 +02:00
zeripath
f5b43a615c When redirecting clean the path to avoid redirecting to //www.othersite.com (#5669) (#5703)
Fix #5627

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-12 14:57:50 -05:00
Lunny Xiao
1c4293b37f fix public will not be reused as public key after deleting as deploy key (#5671) (#5685) 2019-01-10 09:23:04 -05:00
Jonas Franz
30560b0f9b Add changelog for 1.6.3 (#5637)
* Add changelog for 1.6.3 and 1.7.0-rc2

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Remove 1.7.0 entries

Signed-off-by: Jonas Franz <info@jonasfranz.software>
2019-01-04 19:14:28 +01:00
zeripath
6076674d3a SECURITY: protect DeleteFilePost et al with cleanUploadFileName (#5631) (#5634)
This commit wraps more of the TreePaths with cleanUploadFileName

Signed-off-by: Andrew Thornton <art27@cantab.net>
2019-01-04 17:29:36 +01:00
Harshit Bansal
28cc3bd662 Fix wrong text getting saved on editing second comment on an issue. (#5608) (#5615)
* comments: Fix an incorrent DOM element selection.

This commit fixes a bug that was causing text from previously edited
comment to get saved when two comments were edited one after other.
Text area with id of `#content` isn't unique on the page but it was
being treated as unique by the event handling code.

Fixes: #5581.

* templates: Remove `id` from textarea in commit edit form.

An element is assigned an `id` only if it is unique for the whole page
but in this case there can be multiple textarea so it should have one.
2018-12-31 11:52:06 -05:00
techknowlogick
2631f7f64d Changelog for 1.6.2 (#5567) 2018-12-21 10:08:46 -05:00
techknowlogick
af4626a270 Immediate fix to htmlEncode user added text (#5575)
There are likely problems remaining with the way that initCommentForm
is creating its elements. I suspect that a malformed avatar url could
be used maliciously.
2018-12-21 09:05:47 -05:00
techknowlogick
21c70e1ed2 backport 5571 (#5573) 2018-12-21 16:22:56 +08:00
Lunny Xiao
b45d58805a fix indexer reindex bug when gitea restart (#5563) (#5564)
* fix issue indexer bug reindex when restart gitea

* also fix code indexer reindex when gitea restart
2018-12-19 09:51:53 -05:00
Greg Karékinian
200b974e19 Backport #5537 Remove a double slash in the HTTPS redirect with Let's Encrypt (#5539)
Before:

$ curl 0.0.0.0:3001
<a href="https://gitea.example.com:3000//">Found</a>.

After:

$ curl 0.0.0.0:3001
<a href="https://gitea.example.com:3000/">Found</a>.

Fixes #5536
2018-12-13 10:42:38 -05:00
Lunny Xiao
800271ee1f fix bug when a read perm user to edit his issue (#5516) (#5534) 2018-12-12 12:37:22 -05:00
Lunny Xiao
e6362f3d23 fix detect force push failure on deletion of protected branches (#5522) (#5531) 2018-12-12 09:49:47 -05:00
Greg Karékinian
716c2918be Backported #5525 Fix the Let's Encrypt handler (#5527)
* Fix the Let's Encrypt handler by listening on a valid address

Also handle errors in the HTTP server go routine, return a fatal error
when something goes wrong.

Thanks to @gbl08ma for finding the actual bug

Here is an example of the error handling:

    2018/12/11 14:23:07 [....io/gitea/cmd/web.go:87 func1()] [E] Failed to
    start the Let's Encrypt handler on port 30: listen tcp 0.0.0.0:30: bind:
    permission denied

Closes #5280

* Fix a typo
2018-12-11 13:34:35 -05:00
Lunny Xiao
60d7b614fe fix forgot deletion of notification when delete repository (#5506) (#5514) 2018-12-11 19:09:53 +08:00
Lunny Xiao
9cf9a54dca fix undeleted content when deleting user (#5509) 2018-12-11 10:33:20 +08:00
Lunny Xiao
2b4f87da46 Fix empty wiki (#5504) (#5508)
* fix wiki page when wiki path is exist but empty

* improve the error check
2018-12-10 22:37:56 +02:00
techknowlogick
ad9f9cdc30 Add 1.6.1 changelog (#5500) 2018-12-09 21:06:16 +08:00
Lunny Xiao
8237fd4a2d fix topic name length on database (#5493) (#5495) 2018-12-09 02:57:49 +02:00
romankl
8e4a0a978a ensure that the closed_at is set for closed (#5450)
right now the `closed_at` field for json responses is not filled during
the `APIIssue` creation for api responses.

For a closed issue you get a result like:
```json
"state":"open","comments":0,"created_at":"2018-11-29T16:39:24+01:00",
"updated_at":"2018-11-30T10:49:19+01:00","closed_at":null,
"due_date":null,"pull_request":null}
```
which has no information about the closing date. (which exists in the
db and ui)
with this PR the result changes to this:

```json
:null,"assignee":null,"assignees":null,
"state":"closed",
"comments":0,"created_at":"2018-11-29T16:43:05+01:00",
"updated_at":"2018-12-02T19:17:05+01:00",
"closed_at":"2018-12-02T19:17:05+01:00",
"due_date":null,"pull_request":null}
```

fixes: https://github.com/go-gitea/gitea/issues/5446
Signed-off-by: Roman <romaaan.git@gmail.com>
2018-12-02 17:50:47 -05:00
Lanre Adelowo
c1275e2ba6 Admin should be able to delete repos even if he is not a member of the organization (#5443) (#5447) 2018-12-02 20:07:20 +02:00
romankl
7bc1faabdb word-break the WebHook url to prevent a ui-break (#5445)
right now, the url is displayed with an anchor tag with no classes. If
the url is really really long, the url will break out of the containing
div and (depending on the url length) the browser shows the horizontal
scrollbar.
This pr makes use of the already existing css class `dont-break-out`
which gives all the anchor the necessary properties to prevent the
break.
Another solution could be to introduce some classes like
`text text-break-word`, but that would duplicate the `dont-break-out`
class just for text elements that use the `text` class.

fixes: https://github.com/go-gitea/gitea/issues/5416
Signed-off-by: Roman <romaaan.git@gmail.com>
2018-12-02 10:47:45 -05:00
Lunny Xiao
e406dc058d Fix repository deletion when there is large number of issues in it (#5426) (#5434) 2018-11-30 09:38:35 -05:00
Lauris BH
328e38ebc7 Fix dependent issue searching when gitea is run in subpath (#5392) (#5400) 2018-11-25 19:27:17 -05:00
Daniel Balko
773addf727 Backported #5383 on v1.6: API: '/orgs/:org/repos': return private repos with read access (#5310) (#3829) (#5393)
Signed-off-by: Daniel Balko <inxonic+github@gmail.com>
2018-11-24 13:14:27 +02:00
Lunny Xiao
0da8bc9ec0 add changelog of v1.6.0 (#5379)
* add changelog of v1.6.0

* improve changelog
2018-11-22 22:53:58 -05:00
Lunny Xiao
5d69703d3c dont' send assign webhooks when creating issue (#5365) (#5369) 2018-11-21 23:12:17 +08:00
Florian Eitel
ffc0c7f611 Migration fixes 5318 1.6 backport (#5355)
* Remove field from migration to support upgrades from older version

That will ensure the field does not get queried in the Select if it does
not exist yet:

```
[I] [SQL] SELECT "id", "repo_id", "index", "poster_id", "name", "content", "milestone_id", "priority", "assignee_id", "is_closed", "is_pull", "num_comments", "ref", "deadline_unix", "created_unix", "updated_unix
[...itea/routers/init.go:60 GlobalInit()] [E] Failed to initialize ORM engine: migrate: do migrate: pq: column "ref" does not exist
```

see #5318

* Skip remove stale watcher migration if not required

Otherwise the migration will fail if executed from a older database
version without multiple IssueWatch feature.

```
2018/11/11 23:51:14 [I] [SQL] SELECT DISTINCT "issue_watch"."user_id", "issue"."repo_id" FROM "issue_watch" INNER JOIN issue ON issue_watch.issue_id = issue.id WHERE (issue_watch.is_watching = $1) LIMIT 50 []int
[...itea/routers/init.go:60 GlobalInit()] [E] Failed to initialize ORM engine: migrate: do migrate: pq: relation "issue_watch" does not exist
```

see #5318
2018-11-18 22:34:14 +02:00
Lunny Xiao
8670decafb Fix create team, update team missing units (#5188) (#5313) 2018-11-11 12:43:56 -05:00
Lauris BH
297e619074 Fix file edit change preview functionality (#5300) (#5311) 2018-11-10 16:12:58 +02:00
Lunny Xiao
e9b984e162 fix bug when users have serval teams with different units on different repositories (#5307) (#5308) 2018-11-09 17:46:38 +08:00
Lauris BH
5995b65175 Fix U2F if gitea is configured in subpath (#5302) (#5306) 2018-11-09 13:45:50 +08:00
Lauris BH
996ce8cc03 Fix markdown image with link (#4675) (#5299)
* Fix markdown image with link

* Add gitea copyright notice

* add a test for markdown image with link

* remove svg related variables
2018-11-08 17:47:24 -05:00
Lauris BH
fe7cef0e1f Add changelog for 1.5.3 release (#5227) (#5298) 2018-11-08 17:20:10 -05:00
Lauris BH
464dcd1b66 Remove maxlines option for file logger (#5282) (#5287) 2018-11-07 09:14:44 +02:00
Lauris BH
68938d5dc4 Backport fix broken translation (#5284) 2018-11-07 06:50:52 +02:00
techknowlogick
9c11fafdb0 1.6.0-RC2 Changelog (#5275) 2018-11-04 17:07:08 -05:00
zeripath
c0bbbdd30b Backport #5250 on v1.6: Fix Issue 5249 and protect /api/v1/admin routes with CSRF token (#5272)
* Add CSRF checking to reqToken and place CSRF in the post for deadline creation

Fixes #5226, #5249

* /api/v1/admin/users routes should have reqToken middleware
2018-11-04 10:42:15 -05:00
kolaente
f95c966770 Backported wrong api request url for instances running in subfolders (#5247) (#5261) 2018-11-03 17:43:11 -04:00
Peter Hoffmann
14a074f979 fix: Accept web-command cli flags if web-command is commited (#5245)
* Added flags of default cmd CmdWeb to app-wide flags
* If command *is* specified app-wide flags are ignored

Backport of #5200
Signed-off-by: Berengar W. Lehr <Berengar.Lehr@kompetenztest.de>
2018-11-01 11:24:23 -04:00
Lunny Xiao
3786369356 This commit will reduce join star, repo_topic, topic tables on repo search, so that fix extra columns problem on mssql (#5136) (#5229)
* This commit will reduce join star, repo_topic, topic tables on repo search, so that fix extra columns problem on mssql

* fix tests
2018-10-31 20:21:31 -04:00
Lunny Xiao
79464216d9 fix data race on migrate repository (#5224) (#5230) 2018-10-31 20:23:13 +08:00
Peter Hoffmann
e28801ff1a fix: Add secret to all webhook's payload where it has been missing (#5208)
* Updated dependency manager via `dep ensure -update code.gitea.io/sdk`
* Gopkg.toml was not changed as sdk version is set to "master"
* affects webhooks for: Delete, Fork, IssueComment, Release
* also contains changes from go-gitea/go-sdk#125 and hence a swagger update

Signed-off-by: Berengar W. Lehr <Berengar.Lehr@kompetenztest.de>
Resolves: #4732, #5173
2018-10-30 17:14:12 +02:00
Lunny Xiao
478ba7f318 fix sqlite lock (#5210) (#5223) 2018-10-30 14:21:55 +08:00
Kim "BKC" Carlbäcker
582213a858 Update go-macaron/session to latest mast to fix RCE-bug (#5195) 2018-10-30 13:36:50 +08:00
Lunny Xiao
4d66de684f Fix race on updatesize (#5190) (#5215)
* fix race on updatesize

* fix more repoPath
2018-10-30 09:20:18 +08:00
Rodrigo Villablanca Vásquez
d220a3d772 fix to 3819 - Backport (#5219) 2018-10-29 15:56:21 -04:00
Lunny Xiao
7022957b15 fix sqlite and mssql lock (#5214) (#5218) 2018-10-29 14:10:50 -04:00
Lunny Xiao
e7128e8c41 Fix sqlite lock (#5176) (#5179)
* fix sqlite lock

* fix sqlite lock on getUnitType
2018-10-25 17:30:25 +03:00
Jonas Franz
274ff0d011 Add comment replies (#5147)
*         Add comment replies

Signed-off-by: Jonas Franz <info@jonasfranz.software>

* Use review.ID instead

Signed-off-by: Jonas Franz <info@jonasfranz.software>
2018-10-23 10:38:06 -04:00
Filip Navara
7238bb329a Fix SQL quoting (#5137)
`show` is keyword in MySQL and has to be quoted to reference a column name. Use grave accents (ASCII code 96) for quoting to match rest of the source code. It's non-standard SQL, but it's supported by SQLite and MySQL.

Signed-off-by: Filip Navara <navara@emclient.com>
2018-10-22 14:46:47 -04:00
kolaente
49d666f99a Fix regex to support optional end line of old section in diff hunk (#5097)
+ Named groups in reges for easier group parsing
2018-10-18 09:57:35 +08:00
1454 changed files with 60600 additions and 280468 deletions

View File

@@ -67,7 +67,7 @@ pipeline:
image: golang:1.11 image: golang:1.11
pull: true pull: true
environment: environment:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite
commands: commands:
- make clean - make clean
- make generate - make generate
@@ -87,7 +87,7 @@ pipeline:
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite
commands: commands:
- make unit-test-coverage - make unit-test-coverage
when: when:
@@ -99,7 +99,7 @@ pipeline:
pull: true pull: true
group: test group: test
environment: environment:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite
commands: commands:
- make test - make test
when: when:
@@ -117,19 +117,17 @@ pipeline:
when: when:
event: [ tag ] event: [ tag ]
test-sqlite: # Commented until db locking have been resolved!
image: golang:1.11 # test-sqlite:
pull: true # image: golang:1.10
group: test # pull: true
environment: # group: test
TAGS: bindata # environment:
commands: # TAGS: bindata
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash # commands:
- apt-get install -y git-lfs # - make test-sqlite
- (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.sqlite.test)' | sh)) & # when:
- make test-sqlite # event: [ push, tag, pull_request ]
when:
event: [ push, tag, pull_request ]
test-mysql: test-mysql:
image: golang:1.11 image: golang:1.11
@@ -156,7 +154,6 @@ pipeline:
commands: commands:
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
- apt-get install -y git-lfs - apt-get install -y git-lfs
- (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.test)' | sh)) &
- make test-mysql - make test-mysql
when: when:
event: [ tag ] event: [ tag ]
@@ -171,25 +168,10 @@ pipeline:
commands: commands:
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash - curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
- apt-get install -y git-lfs - apt-get install -y git-lfs
- (sleep 1200 && (echo 'kill -ABRT $(pidof gitea) $(pidof integrations.test)' | sh)) &
- make test-pgsql - make test-pgsql
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
test-mssql:
image: golang:1.11
pull: true
group: test
environment:
TAGS: bindata
TEST_LDAP: "1"
commands:
- curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
- apt-get install -y git-lfs
- make test-mssql
when:
event: [ push, tag, pull_request ]
generate-coverage: generate-coverage:
image: golang:1.11 image: golang:1.11
pull: true pull: true
@@ -214,7 +196,7 @@ pipeline:
image: karalabe/xgo-latest:latest image: karalabe/xgo-latest:latest
pull: true pull: true
environment: environment:
TAGS: bindata sqlite sqlite_unlock_notify TAGS: bindata sqlite
commands: commands:
- export PATH=$PATH:$GOPATH/bin - export PATH=$PATH:$GOPATH/bin
- make release - make release
@@ -276,7 +258,6 @@ pipeline:
pull: true pull: true
secrets: [ aws_access_key_id, aws_secret_access_key ] secrets: [ aws_access_key_id, aws_secret_access_key ]
bucket: releases bucket: releases
acl: public-read
endpoint: https://storage.gitea.io endpoint: https://storage.gitea.io
path_style: true path_style: true
strip_prefix: dist/release/ strip_prefix: dist/release/
@@ -290,7 +271,6 @@ pipeline:
pull: true pull: true
secrets: [ aws_access_key_id, aws_secret_access_key ] secrets: [ aws_access_key_id, aws_secret_access_key ]
bucket: releases bucket: releases
acl: public-read
endpoint: https://storage.gitea.io endpoint: https://storage.gitea.io
path_style: true path_style: true
strip_prefix: dist/release/ strip_prefix: dist/release/
@@ -305,7 +285,6 @@ pipeline:
pull: true pull: true
secrets: [ aws_access_key_id, aws_secret_access_key ] secrets: [ aws_access_key_id, aws_secret_access_key ]
bucket: releases bucket: releases
acl: public-read
endpoint: https://storage.gitea.io endpoint: https://storage.gitea.io
path_style: true path_style: true
strip_prefix: dist/release/ strip_prefix: dist/release/
@@ -361,15 +340,6 @@ services:
when: when:
event: [ push, tag, pull_request ] event: [ push, tag, pull_request ]
mssql:
image: microsoft/mssql-server-linux:latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=MwantsaSecurePassword1
- MSSQL_PID=Standard
when:
event: [ push, tag, pull_request ]
ldap: ldap:
image: gitea/test-openldap:latest image: gitea/test-openldap:latest
when: when:

52
.github/stale.yml vendored
View File

@@ -1,52 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 14
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- status/blocked
- kind/security
- lgtm/done
- reviewed/confirmed
- priority/critical
- kind/proposal
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs during the next 2 weeks. Thank you
for your contributions.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue has been automatically closed because of inactivity.
You can re-open it if needed.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 1
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
pulls:
daysUntilStale: 60
markComment: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs during the next 2 months. Thank you
for your contributions.
closeComment: >
This pull request has been automatically closed because of inactivity.
You can re-open it if needed.

3
.gitignore vendored
View File

@@ -53,14 +53,11 @@ coverage.all
/integrations/gitea-integration-mysql /integrations/gitea-integration-mysql
/integrations/gitea-integration-pgsql /integrations/gitea-integration-pgsql
/integrations/gitea-integration-sqlite /integrations/gitea-integration-sqlite
/integrations/gitea-integration-mssql
/integrations/indexers-mysql /integrations/indexers-mysql
/integrations/indexers-pgsql /integrations/indexers-pgsql
/integrations/indexers-sqlite /integrations/indexers-sqlite
/integrations/indexers-mssql
/integrations/mysql.ini /integrations/mysql.ini
/integrations/pgsql.ini /integrations/pgsql.ini
/integrations/mssql.ini
/node_modules /node_modules

View File

@@ -1,25 +0,0 @@
ignoreGeneratedHeader = false
severity = "warning"
confidence = 0.8
errorCode = 1
warningCode = 1
[rule.blank-imports]
[rule.context-as-argument]
[rule.context-keys-type]
[rule.dot-imports]
[rule.error-return]
[rule.error-strings]
[rule.error-naming]
[rule.exported]
[rule.if-return]
[rule.increment-decrement]
[rule.var-naming]
[rule.var-declaration]
[rule.package-comments]
[rule.range]
[rule.receiver-naming]
[rule.time-naming]
[rule.unexported-return]
[rule.indent-error-flow]
[rule.errorf]

View File

@@ -4,150 +4,17 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.7.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-02 ## [1.6.4](https://github.com/go-gitea/gitea/releases/tag/v1.6.4) - 2019-01-15
* BREAKING * BUGFIX
* Restrict permission check on repositories and fix some problems (#5314) * Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685)
* Show only opened milestones on issues page milestone filter (#5051) * When redirecting clean the path to avoid redirecting to external site (#5669) (#5703)
* FEATURE * Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715)
* Implement git refs API for listing references (branches, tags and other) (#5354)
* Approvals at Branch Protection (#5350) ## [1.6.3](https://github.com/go-gitea/gitea/releases/tag/v1.6.3) - 2019-01-04
* Add raw blob endpoint to get objects by SHA ID (#5334) * SECURITY
* Add api for user to create org (#5268) * Prevent DeleteFilePost doing arbitrary deletion (#5631)
* Create AuthorizedKeysCommand (#5236) * BUGFIX
* User action heatmap (#5131) * Fix wrong text getting saved on editing second comment on an issue (#5608)
* Refactor heatmap to vue component (#5401)
* Webhook for Pull Request approval/rejection (#5027)
* Add command for migrating database (#4954)
* Search keyword by splitting provided values by , (#4939)
* Create Progressive Web App (#4730)
* Give user a link to create PR after push (#4716)
* Add rebase with merge commit merge style (#3844) (#4052)
* BUGFIXES
* Fix bug on modifying sshd username (#5624)
* Delete tags in mirror which are removed for original repo. (#5609)
* Fix wrong text getting saved on editing second comment on an issue. (#5608)
* Fix nil pointer when adding a due date (#5587)
* Fix type mismatch of format string (#5574)
* Fix bug on upload file name (#5571)
* Issue is not overdue when it is on the same date #5566 (#5568)
* Fix indexer reindex bug when gitea restart (#5563)
* Fix table name typo on SQL (#5562)
* Synchronize SSH keys on login with LDAP + Fix SQLite deadlock on ldap ssh key deletion (#5557)
* Fix makefile generate buildstep (#5556)
* Fix nil pointer base branch bug (#5555)
* Fix permission check on api create org (#5523)
* Fix detect force push failure on deletion of protected branches (#5522)
* Fix approvals limitation (#5521)
* Fix bug when a read perm user to edit his issue (#5516)
* Fix adding reaction fail for read permission user (#5515)
* Fixing MSSQL timestamp type (#5511)
* Fix forgot deletion of notification when delete repository (#5506)
* Fix empty wiki (#5504)
* Fix clone wiki failed via ssh (#5503)
* Fix code review on mssql (#5502)
* Fix lfs version check warning log when using ssh protocol (#5501)
* Fix topic name length on database (#5493)
* Ensure that the `closed_at` is set for closed issues (#5449)
* Admin should be able to delete repos via the API even if he is not a member of the organization (#5443)
* Word-Break the WebHook url to prevent a ui-break (#5432)
* Fix forgot removed records when deleting user (#5429)
* Fix repository deletion when there is large number of issues in it (#5426)
* Fix heatmap colors for Chrome/Safari (#5421)
* Fix password variable shadowing (#5405)
* Fix dependent issue searching when gitea is run in subpath (#5392)
* Don't force a password change for the admin user when creating an account via cli (#5391)
* API: '/orgs/:org/repos': return private repos with read access (#5383)
* Don't send assign webhooks when creating issue (#5365)
* Removing Labels via EditPullRequest API (#5348)
* Migration fixes for gogs (0.11.66) to gitea (1.6.0) #5318 (#5341)
* Fix bug when users have serval teams with different units on different repositories (#5307)
* Fix U2F if gitea is configured in subpath (#5302)
* Fix file edit change preview functionality (#5300)
* Update gitignore list (#5258)
* Fixed heatmap not working in mssql (#5248)
* Fixed wrong api request url for instances running in subfolders (#5247)
* Fix compatibility heatmap with mysql 8 (#5232)
* Fix data race on migrate repository (#5224)
* Fix sqlite and mssql lock (#5214)
* Fix sqlite lock (#5210)
* Fix: Accept web-command cli flags if web-command is commited (#5200)
* Fix: Add secret to all webhook's payload where it has been missing (#5199)
* Fix race on updatesize (#5190)
* Fix create team, update team missing units (#5188)
* Fix sqlite lock (#5184 & #5176)
* Fix showing pull request link when delete a branch (#5166)
* Fix JSON result of empty array in heatmap data array (#5154)
* Update build tags for sqlite_unlock notify (#5144)
* This commit will reduce join star, repo_topic, topic tables on repo search, so that fix extra columns problem on mssql (#5136)
* Fix deadlock when sqlite (#5118)
* Add comment replies (#5104)
* Fix home page template regression (#5102)
* Fix regex to support optional end line of old section in diff hunk (#5096)
* LDAP via simple auth separate bind user and search base (#5055)
* Fix markdown image with link (#4675)
* Fix to 3819 - Filtering issues by tags on main screen issues (#3824)
* ENHANCEMENT
* Delete organization endpoint added (#5601)
* Update Licenses (#5558)
* Support reverse proxy providing email (#5554)
* Add git protocol v2 support via SSH on Docker image (#5520)
* Add tests for api user orgs (#5494)
* Allow link verification for services like Mastodon (#5481)
* Improve team members and repositories settings UI (#5457)
* Remove the required class from optional ssh port in installation page (#5428)
* Explicitly disable Git credential helper (#5367)
* Setting Labels via EditPullRequest API (#5347)
* Implement pasting image from clipboard for browsers that supports that (#5317)
* Milestone issues and pull requests (#5293)
* Support envs on external render commands (#5278)
* Add option to disable automatic mirror syncing. (#5242)
* Remove unused db init on commands serv, update, hooks (#5225)
* Serve audio files using HTML5 audio tag (#5221)
* Pass link prefixes to external markup parsers (#5201)
* Add AutoHead functionality. (#5186)
* Fix emojis not showing in commit messages (#5168)
* Block registration based on email domain (#5157)
* Update vendor/go-sqlite3 (#5133 & #5162)
* Update x/net lib (#5169)
* Show review summary in pull requests (#5132)
* Use type switch (#5122)
* Remove duplicated if bodies (#5121)
* Remove check for negative length (#5120)
* Make switch more clear (#5119)
* Use named const instead of a raw string (#5115)
* Fix issue where ecdsa and other key types are not synced from LDAP (#5092) (#5094)
* Refactor: err != nil check, just return error instead (#5093)
* Add notification interface and refactor UI notifications (#5085)
* Use APP_NAME on home page (#5048)
* Explicitly decide whether to use TLS in mailer's configuration (#5024)
* Generate random password (#5023)
* UX of link account (Step 1) (#5006)
* Make sure argsSet verifies string isn't empty too (#4980)
* Improve performance of dashboard (#4977)
* Keys API changes (#4960)
* Add must-change-password flag to cli for creating a user (#4955)
* Use native go method to get current user rather than environment variable (#4930)
* Make gitea serv use api/internal (#4886)
* Add support for search by uid (#4876)
* Allow to add organization members as collaborators on organization owned repositories (#4748)
* TESTING
* Kill testing processes if the test takes too long (#5174)
* Update outdated Go toolchain version for .drone.yml (#5146)
* Increase the retry limit to 20 times and the interval to 200ms (#5134)
* Retry test-fixtures loading in case of transaction rollback (#5125)
* Added test environment for mssql (#4282)
* BUILD
* Replace lint to revive (#5422)
* Update golang version in Dockerfile (#5246)
* DOCS
* Typo in routers/api/v1/org/org.go fixed. (#5598)
* Update the docs for sqlite_unlock_notify (#5145)
* CN translation of docs part (#5049)
* Kubernetes deployment file (#5046)
* MISC
* Upgrade alpine to 3.8 (#5423)
* Git-Trees API (#5403)
* Only chown directories during docker setup if necessary. Fix #4425 (#5064)
## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21 ## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21
* SECURITY * SECURITY

View File

@@ -244,11 +244,6 @@ they served:
* [Lauris Bukšis-Haberkorns](https://github.com/lafriks) <lauris@nix.lv> * [Lauris Bukšis-Haberkorns](https://github.com/lafriks) <lauris@nix.lv>
* [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com> * [Kim Carlbäcker](https://github.com/bkcsoft) <kim.carlbacker@gmail.com>
* 2019-01-01 ~ 2019-12-31
* [Lunny Xiao](https://github.com/lunny) <xiaolunwen@gmail.com>
* [Lauris Bukšis-Haberkorns](https://github.com/lafriks) <lauris@nix.lv>
* [Matti Ranta](https://github.com/techknowlogick) <matti@mdranta.net>
## Versions ## Versions
Gitea has the `master` branch as a tip branch and has version branches Gitea has the `master` branch as a tip branch and has version branches
@@ -280,7 +275,7 @@ be reviewed by two maintainers and must pass the automatic tests.
Code that you contribute should use the standard copyright header: Code that you contribute should use the standard copyright header:
``` ```
// Copyright 2019 The Gitea Authors. All rights reserved. // Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style // Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
``` ```

View File

@@ -1,10 +1,10 @@
################################### ###################################
#Build stage #Build stage
FROM golang:1.11-alpine3.8 AS build-env FROM golang:1.10-alpine3.7 AS build-env
ARG GITEA_VERSION ARG GITEA_VERSION
ARG TAGS="sqlite sqlite_unlock_notify" ARG TAGS="sqlite"
ENV TAGS "bindata $TAGS" ENV TAGS "bindata $TAGS"
#Build deps #Build deps
@@ -18,7 +18,7 @@ WORKDIR ${GOPATH}/src/code.gitea.io/gitea
RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \
&& make clean generate build && make clean generate build
FROM alpine:3.8 FROM alpine:3.7
LABEL maintainer="maintainers@gitea.io" LABEL maintainer="maintainers@gitea.io"
EXPOSE 22 3000 EXPOSE 22 3000

266
Gopkg.lock generated
View File

@@ -3,19 +3,19 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:ab875622908a804a327a95a1701002b150806a3c5406df51ec231eac16d3a1ca" digest = "1:835585f8450b4ec12252d032b0f13e6571ecf846e49076f69067f2503a7c1e07"
name = "code.gitea.io/git" name = "code.gitea.io/git"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "389d3c803e12a30dffcbb54a15c2242521bc4333" revision = "6ef79e80b3b06ca13a1f3a7b940903ebc73b44cb"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:aed2bc1c4026233af8ad43cab9d9464a0e3b906d3d058d2d6e814f3e1ddfa528" digest = "1:b194da40b41ae99546dfeec5a85f1fec2a6c51350d438e511ef90f4293c6dcd7"
name = "code.gitea.io/sdk" name = "code.gitea.io/sdk"
packages = ["gitea"] packages = ["gitea"]
pruneopts = "NUT" pruneopts = "NUT"
revision = "d95a6e0392218961d1bdd18020290a20bd61b063" revision = "4f96d9ac89886e78c50de8c835ebe87461578a5e"
[[projects]] [[projects]]
digest = "1:3fcef06a1a6561955c94af6c7757a6fa37605eb653f0d06ab960e5bb80092195" digest = "1:3fcef06a1a6561955c94af6c7757a6fa37605eb653f0d06ab960e5bb80092195"
@@ -82,15 +82,7 @@
revision = "349dd0209470eabd9514242c688c403c0926d266" revision = "349dd0209470eabd9514242c688c403c0926d266"
[[projects]] [[projects]]
branch = "master" digest = "1:67351095005f164e748a5a21899d1403b03878cb2d40a7b0f742376e6eeda974"
digest = "1:707ebe952a8b3d00b343c01536c79c73771d100f63ec6babeaed5c79e2b8a8dd"
name = "github.com/beorn7/perks"
packages = ["quantile"]
pruneopts = "NUT"
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
[[projects]]
digest = "1:c10f35be6200b09e26da267ca80f837315093ecaba27e7a223071380efb9dd32"
name = "github.com/blevesearch/bleve" name = "github.com/blevesearch/bleve"
packages = [ packages = [
".", ".",
@@ -135,7 +127,7 @@
"search/searcher", "search/searcher",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "c74e08f039e56cef576e4336382b2a2d12d9e026" revision = "ff210fbc6d348ad67aa5754eaea11a463fcddafd"
[[projects]] [[projects]]
branch = "master" branch = "master"
@@ -234,21 +226,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "57eb5e1fc594ad4b0b1dbea7b286d299e0cb43c2" revision = "57eb5e1fc594ad4b0b1dbea7b286d299e0cb43c2"
[[projects]]
digest = "1:b498b36dbb2b306d1c5205ee5236c9e60352be8f9eea9bf08186723a9f75b4f3"
name = "github.com/emirpasic/gods"
packages = [
"containers",
"lists",
"lists/arraylist",
"trees",
"trees/binaryheap",
"utils",
]
pruneopts = "NUT"
revision = "1615341f118ae12f353cc8a983f35b584342c9b3"
version = "v1.12.0"
[[projects]] [[projects]]
digest = "1:8603f74d35c93b37c615a02ba297be2cf2efc9ff6f1ff2b458a903990b568e48" digest = "1:8603f74d35c93b37c615a02ba297be2cf2efc9ff6f1ff2b458a903990b568e48"
name = "github.com/ethantkoenig/rupture" name = "github.com/ethantkoenig/rupture"
@@ -390,12 +367,12 @@
revision = "d523deb1b23d913de5bdada721a6071e71283618" revision = "d523deb1b23d913de5bdada721a6071e71283618"
[[projects]] [[projects]]
digest = "1:06d21295033f211588d0ad7ff391cc1b27e72b60cb6d4b7db0d70cffae4cf228" digest = "1:1397763fd29d5667bcfbacde8a37542ee145416b3acb7e1b149c98fef2567930"
name = "github.com/go-xorm/builder" name = "github.com/go-xorm/builder"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "03eb88feccce3e477c318ce7f6f1b386544ab20b" revision = "dc8bf48f58fab2b4da338ffd25191905fd741b8f"
version = "v0.3.3" version = "v0.3.0"
[[projects]] [[projects]]
digest = "1:c910feae32bcc3cbf068c7263424d9f198da931c0cad909179621835e6f87cb8" digest = "1:c910feae32bcc3cbf068c7263424d9f198da931c0cad909179621835e6f87cb8"
@@ -406,11 +383,11 @@
version = "v0.6.0" version = "v0.6.0"
[[projects]] [[projects]]
digest = "1:931a62a1aacc37a5e4c309a111642ec4da47b4dc453cd4ba5481b12eedb04a5d" digest = "1:22a1ac7f654095f6817076eb975368bab5481e42554d0121ea37e28a86a3f83d"
name = "github.com/go-xorm/xorm" name = "github.com/go-xorm/xorm"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "401f4ee8ff8cbc40a4754cb12192fbe4f02f3979" revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
[[projects]] [[projects]]
branch = "master" branch = "master"
@@ -428,12 +405,11 @@
revision = "7f3990acf1833faa5ebd0e86f0a4c72a4b5eba3c" revision = "7f3990acf1833faa5ebd0e86f0a4c72a4b5eba3c"
[[projects]] [[projects]]
digest = "1:97df918963298c287643883209a2c3f642e6593379f97ab400c2a2e219ab647d" digest = "1:b64f9be717fdab5f75122dc3868e8ca9d003779b6bc55f64f39a0cddc698bf88"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = ["proto"] packages = ["proto"]
pruneopts = "NUT" pruneopts = "NUT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" revision = "99511271042a09d1e01baea8781caa5210fec66e"
version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:60e25fc5f5cfd7783f985ca99b4383e848981dddf0be584db7d809be20848e25" digest = "1:60e25fc5f5cfd7783f985ca99b4383e848981dddf0be584db7d809be20848e25"
@@ -487,14 +463,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "8fb95d837f7d6db1913fecfd7bcc5333e6499596" revision = "8fb95d837f7d6db1913fecfd7bcc5333e6499596"
[[projects]]
branch = "master"
digest = "1:62fe3a7ea2050ecbd753a71889026f83d73329337ada66325cbafd5dea5f713d"
name = "github.com/jbenet/go-context"
packages = ["io"]
pruneopts = "NUT"
revision = "d14ea06fba99483203c19d92cfcd13ebe73135f4"
[[projects]] [[projects]]
digest = "1:6342cf70eaae592f7b8e2552037f2a9d4d16fa321c6e36f09c3bc450add2de19" digest = "1:6342cf70eaae592f7b8e2552037f2a9d4d16fa321c6e36f09c3bc450add2de19"
name = "github.com/kballard/go-shellquote" name = "github.com/kballard/go-shellquote"
@@ -502,14 +470,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "cd60e84ee657ff3dc51de0b4f55dd299a3e136f2" revision = "cd60e84ee657ff3dc51de0b4f55dd299a3e136f2"
[[projects]]
digest = "1:29e44e9481a689be0093a0033299b95741d394a97b28e0273c21afe697873a22"
name = "github.com/kevinburke/ssh_config"
packages = ["."]
pruneopts = "NUT"
revision = "81db2a75821ed34e682567d48be488a1c3121088"
version = "0.5"
[[projects]] [[projects]]
digest = "1:b32126992771fddadf6a778fe7ab29150665ed78f31ce4eb550a9db3bc0e650c" digest = "1:b32126992771fddadf6a778fe7ab29150665ed78f31ce4eb550a9db3bc0e650c"
name = "github.com/keybase/go-crypto" name = "github.com/keybase/go-crypto"
@@ -588,7 +548,7 @@
revision = "e3534c89ef969912856dfa39e56b09e58c5f5daf" revision = "e3534c89ef969912856dfa39e56b09e58c5f5daf"
[[projects]] [[projects]]
digest = "1:4b992ec853d0ea9bac3dcf09a64af61de1a392e6cb0eef2204c0c92f4ae6b911" digest = "1:23f75ae90fcc38dac6fad6881006ea7d0f2c78db5f9f81f3df558dc91460e61f"
name = "github.com/markbates/goth" name = "github.com/markbates/goth"
packages = [ packages = [
".", ".",
@@ -603,23 +563,15 @@
"providers/twitter", "providers/twitter",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "bc6d8ddf751a745f37ca5567dbbfc4157bbf5da9" revision = "f9c6649ab984d6ea71ef1e13b7b1cdffcf4592d3"
version = "v1.47.2" version = "v1.46.1"
[[projects]] [[projects]]
digest = "1:c9724c929d27a14475a45b17a267dbc60671c0bc2c5c05ed21f011f7b5bc9fb5" digest = "1:3ef954101983406a71171c4dc816a73e01bb3de608b3dd063627aa67a459f3e3"
name = "github.com/mattn/go-sqlite3" name = "github.com/mattn/go-sqlite3"
packages = ["."] packages = ["."]
pruneopts = "NUT" pruneopts = "NUT"
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75" revision = "acfa60124032040b9f5a9406f5a772ee16fe845e"
[[projects]]
digest = "1:5985ef4caf91ece5d54817c11ea25f182697534f8ae6521eadcd628c142ac4b6"
name = "github.com/matttproud/golang_protobuf_extensions"
packages = ["pbutil"]
pruneopts = "NUT"
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
@@ -636,14 +588,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "f77f16ffc87a6a58814e64ae72d55f9c41374e6d" revision = "f77f16ffc87a6a58814e64ae72d55f9c41374e6d"
[[projects]]
digest = "1:a4df73029d2c42fabcb6b41e327d2f87e685284ec03edf76921c267d9cfc9c23"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
pruneopts = "NUT"
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:c7dc71a7e144df03332152d730f9c5ae22cf1cfd55454cb001ba8ffcb78aa7f0" digest = "1:c7dc71a7e144df03332152d730f9c5ae22cf1cfd55454cb001ba8ffcb78aa7f0"
name = "github.com/mrjones/oauth" name = "github.com/mrjones/oauth"
@@ -673,14 +617,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "891127d8d1b52734debe1b3c3d7e747502b6c366" revision = "891127d8d1b52734debe1b3c3d7e747502b6c366"
[[projects]]
digest = "1:cf254277d898b713195cc6b4a3fac8bf738b9f1121625df27843b52b267eec6c"
name = "github.com/pelletier/go-buffruneio"
packages = ["."]
pruneopts = "NUT"
revision = "c37440a7cf42ac63b919c752ca73a85067e05992"
version = "v0.2.0"
[[projects]] [[projects]]
digest = "1:44c66ad69563dbe3f8e76d7d6cad21a03626e53f1875b5ab163ded419e01ca7a" digest = "1:44c66ad69563dbe3f8e76d7d6cad21a03626e53f1875b5ab163ded419e01ca7a"
name = "github.com/philhofer/fwd" name = "github.com/philhofer/fwd"
@@ -708,51 +644,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "54653902c20e47f3417541d35435cb6d6162e28a" revision = "54653902c20e47f3417541d35435cb6d6162e28a"
[[projects]]
digest = "1:aa2da1df3327c3a338bb42f978407c07de74cd0a5bef35e9411881dffd444214"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
"prometheus/internal",
"prometheus/promhttp",
]
pruneopts = "NUT"
revision = "1cafe34db7fdec6022e17e00e1c1ea501022f3e4"
version = "v0.9.0"
[[projects]]
branch = "master"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "NUT"
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
[[projects]]
branch = "master"
digest = "1:06375f3b602de9c99fa99b8484f0e949fd5273e6e9c6592b5a0dd4cd9085f3ea"
name = "github.com/prometheus/common"
packages = [
"expfmt",
"internal/bitbucket.org/ww/goautoneg",
"model",
]
pruneopts = "NUT"
revision = "7e9e6cabbd393fc208072eedef99188d0ce788b6"
[[projects]]
branch = "master"
digest = "1:102dea0c03a915acfc634b7c67f2662012b5483b56d9025e33f5188e112759b6"
name = "github.com/prometheus/procfs"
packages = [
".",
"internal/util",
"nfs",
"xfs",
]
pruneopts = "NUT"
revision = "185b4288413d2a0dd0806f78c90dde719829e5ae"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:5be01c22bc1040e2f6ce4755d51a0ac9cef823a9f2004fb1f9896a414ef519e6" digest = "1:5be01c22bc1040e2f6ce4755d51a0ac9cef823a9f2004fb1f9896a414ef519e6"
@@ -782,19 +673,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "1dba4b3954bc059efc3991ec364f9f9a35f597d2" revision = "1dba4b3954bc059efc3991ec364f9f9a35f597d2"
[[projects]]
digest = "1:89fd77d603a74a6540d60067debad9397865bf040955d907362c95d364baeba6"
name = "github.com/src-d/gcfg"
packages = [
".",
"scanner",
"token",
"types",
]
pruneopts = "NUT"
revision = "1ac3a1ac202429a54835fe8408a92880156b489d"
version = "v1.4.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:69177343ca227319b4580441a67d9d889e9ac7fcbfb89fbaa36d3283e6ab0139" digest = "1:69177343ca227319b4580441a67d9d889e9ac7fcbfb89fbaa36d3283e6ab0139"
@@ -842,14 +720,6 @@
pruneopts = "NUT" pruneopts = "NUT"
revision = "8ce1146b8621c95164efd9c8b1124cfa9b8afb4e" revision = "8ce1146b8621c95164efd9c8b1124cfa9b8afb4e"
[[projects]]
digest = "1:3148cb3478c26a92b4c1a18abb9428234b281e278af6267840721a24b6cbc6a3"
name = "github.com/xanzy/ssh-agent"
packages = ["."]
pruneopts = "NUT"
revision = "640f0ab560aeb89d523bb6ac322b1244d5c3796c"
version = "v0.2.0"
[[projects]] [[projects]]
digest = "1:27d050258a4b19ca3b7a1bf26f4a04c5c66bbf0670b346ee509ebb0ad82257a6" digest = "1:27d050258a4b19ca3b7a1bf26f4a04c5c66bbf0670b346ee509ebb0ad82257a6"
name = "github.com/yohcop/openid-go" name = "github.com/yohcop/openid-go"
@@ -858,56 +728,44 @@
revision = "2c050d2dae5345c417db301f11fda6fbf5ad0f0a" revision = "2c050d2dae5345c417db301f11fda6fbf5ad0f0a"
[[projects]] [[projects]]
digest = "1:c3d6b9e2cf3936ba9927da2e8858651aad69890b9dd3349f1316b4003b25d7a3" digest = "1:e4ea859df4986eb46feebbb84a2d163a4a314e87668177ca13b3b0adecaf50e8"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = [ packages = [
"acme", "acme",
"acme/autocert", "acme/autocert",
"cast5",
"curve25519", "curve25519",
"ed25519", "ed25519",
"ed25519/internal/edwards25519", "ed25519/internal/edwards25519",
"internal/chacha20", "internal/chacha20",
"md4", "md4",
"openpgp",
"openpgp/armor",
"openpgp/elgamal",
"openpgp/errors",
"openpgp/packet",
"openpgp/s2k",
"pbkdf2", "pbkdf2",
"poly1305", "poly1305",
"ssh", "ssh",
"ssh/agent",
"ssh/knownhosts",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e" revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
[[projects]] [[projects]]
branch = "master" digest = "1:47ea747d07fae720d749d06ac5dc5ded0df70c57e328b6549cf2d9c64698757e"
digest = "1:d0a0bdd2b64d981aa4e6a1ade90431d042cd7fa31b584e33d45e62cbfec43380"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
"context/ctxhttp",
"html", "html",
"html/atom", "html/atom",
"html/charset", "html/charset",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "9b4f9f5ad5197c79fd623a3638e70d8b26cef344" revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
[[projects]] [[projects]]
branch = "master" digest = "1:8159a9cda4b8810aaaeb0d60e2fa68e2fd86d8af4ec8f5059830839e3c8d93d5"
digest = "1:274a6321a5a9f185eeb3fab5d7d8397e0e9f57737490d749f562c7e205ffbc2e"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
packages = [ packages = [
".", ".",
"internal", "internal",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "c453e0c757598fd055e170a3a359263c91e13153" revision = "c10ba270aa0bf8b8c1c986e103859c67a9103061"
[[projects]] [[projects]]
digest = "1:9f303486d623f840492bfeb48eb906a94e9d3fe638a761639b72ce64bf7bfcc3" digest = "1:9f303486d623f840492bfeb48eb906a94e9d3fe638a761639b72ce64bf7bfcc3"
@@ -917,8 +775,7 @@
revision = "5a06fca2c336a4b2b2fcb45702e8c47621b2aa2c" revision = "5a06fca2c336a4b2b2fcb45702e8c47621b2aa2c"
[[projects]] [[projects]]
branch = "master" digest = "1:47495898c42062ace16d8046915b088e7c3846e77b997ec5a8a00ec552e179d5"
digest = "1:030ca7763285f6cdec5684d7417faa2810d10a508b0220b1487cc876b5c00c35"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = [ packages = [
"unix", "unix",
@@ -926,7 +783,7 @@
"windows/svc", "windows/svc",
] ]
pruneopts = "NUT" pruneopts = "NUT"
revision = "2772b66316d2c587efeb188dcd5ebc6987656e84" revision = "a646d33e2ee3172a661fc09bca23bb4889a41bc8"
[[projects]] [[projects]]
digest = "1:d2463fd72ee2636c3d9bbdb98fa4996a118f210ae3e5eaf62d281855bc0b4a83" digest = "1:d2463fd72ee2636c3d9bbdb98fa4996a118f210ae3e5eaf62d281855bc0b4a83"
@@ -1028,69 +885,6 @@
revision = "e6179049628164864e6e84e973cfb56335748dea" revision = "e6179049628164864e6e84e973cfb56335748dea"
version = "v2.3.2" version = "v2.3.2"
[[projects]]
digest = "1:1cf1388ec8c73b7ecc711d9f279ab631ea0a6964d1ccc32809a6be90c33fa2a0"
name = "gopkg.in/src-d/go-billy.v4"
packages = [
".",
"helper/chroot",
"helper/polyfill",
"osfs",
"util",
]
pruneopts = "NUT"
revision = "982626487c60a5252e7d0b695ca23fb0fa2fd670"
version = "v4.3.0"
[[projects]]
digest = "1:8a0efb153cc5b7e0e129d716834217be483e2b326e72f3dcca8b03cd3207e9e4"
name = "gopkg.in/src-d/go-git.v4"
packages = [
".",
"config",
"internal/revision",
"plumbing",
"plumbing/cache",
"plumbing/filemode",
"plumbing/format/config",
"plumbing/format/diff",
"plumbing/format/gitignore",
"plumbing/format/idxfile",
"plumbing/format/index",
"plumbing/format/objfile",
"plumbing/format/packfile",
"plumbing/format/pktline",
"plumbing/object",
"plumbing/protocol/packp",
"plumbing/protocol/packp/capability",
"plumbing/protocol/packp/sideband",
"plumbing/revlist",
"plumbing/storer",
"plumbing/transport",
"plumbing/transport/client",
"plumbing/transport/file",
"plumbing/transport/git",
"plumbing/transport/http",
"plumbing/transport/internal/common",
"plumbing/transport/server",
"plumbing/transport/ssh",
"storage",
"storage/filesystem",
"storage/filesystem/dotgit",
"storage/memory",
"utils/binary",
"utils/diff",
"utils/ioutil",
"utils/merkletrie",
"utils/merkletrie/filesystem",
"utils/merkletrie/index",
"utils/merkletrie/internal/frame",
"utils/merkletrie/noder",
]
pruneopts = "NUT"
revision = "f62cd8e3495579a8323455fa0c4e6c44bb0d5e09"
version = "v4.8.0"
[[projects]] [[projects]]
digest = "1:9c541fc507676a69ea8aaed1af53278a5241d26ce0f192c993fec2ac5b78f795" digest = "1:9c541fc507676a69ea8aaed1af53278a5241d26ce0f192c993fec2ac5b78f795"
name = "gopkg.in/testfixtures.v2" name = "gopkg.in/testfixtures.v2"
@@ -1099,14 +893,6 @@
revision = "fa3fb89109b0b31957a5430cef3e93e535de362b" revision = "fa3fb89109b0b31957a5430cef3e93e535de362b"
version = "v2.5.0" version = "v2.5.0"
[[projects]]
digest = "1:b233ad4ec87ac916e7bf5e678e98a2cb9e8b52f6de6ad3e11834fc7a71b8e3bf"
name = "gopkg.in/warnings.v0"
packages = ["."]
pruneopts = "NUT"
revision = "ec4a0fea49c7b46c2aeb0b51aac55779c607e52b"
version = "v0.1.2"
[[projects]] [[projects]]
digest = "1:ad6f94355d292690137613735965bd3688844880fdab90eccf66321910344942" digest = "1:ad6f94355d292690137613735965bd3688844880fdab90eccf66321910344942"
name = "gopkg.in/yaml.v2" name = "gopkg.in/yaml.v2"
@@ -1193,8 +979,6 @@
"github.com/nfnt/resize", "github.com/nfnt/resize",
"github.com/pquerna/otp", "github.com/pquerna/otp",
"github.com/pquerna/otp/totp", "github.com/pquerna/otp/totp",
"github.com/prometheus/client_golang/prometheus",
"github.com/prometheus/client_golang/prometheus/promhttp",
"github.com/russross/blackfriday", "github.com/russross/blackfriday",
"github.com/satori/go.uuid", "github.com/satori/go.uuid",
"github.com/sergi/go-diff/diffmatchpatch", "github.com/sergi/go-diff/diffmatchpatch",

View File

@@ -14,18 +14,12 @@ ignored = ["google.golang.org/appengine*"]
branch = "master" branch = "master"
name = "code.gitea.io/sdk" name = "code.gitea.io/sdk"
[[constraint]]
# branch = "master"
revision = "c74e08f039e56cef576e4336382b2a2d12d9e026"
name = "github.com/blevesearch/bleve"
#Not targetting v0.7.0 since standard where use only just after this tag
[[constraint]] [[constraint]]
revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e" revision = "12dd70caea0268ac0d6c2707d0611ef601e7c64e"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
[[constraint]] [[constraint]]
branch = "master" revision = "a646d33e2ee3172a661fc09bca23bb4889a41bc8"
name = "golang.org/x/sys" name = "golang.org/x/sys"
[[constraint]] [[constraint]]
@@ -33,25 +27,18 @@ ignored = ["google.golang.org/appengine*"]
name = "golang.org/x/text" name = "golang.org/x/text"
[[constraint]] [[constraint]]
branch = "master" revision = "f2499483f923065a842d38eb4c7f1927e6fc6e6d"
name = "golang.org/x/net" name = "golang.org/x/net"
[[override]] [[override]]
name = "github.com/go-xorm/xorm" name = "github.com/go-xorm/xorm"
revision = "401f4ee8ff8cbc40a4754cb12192fbe4f02f3979" #version = "0.6.5"
revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
[[override]]
name = "github.com/go-xorm/builder"
version = "0.3.3"
[[override]] [[override]]
name = "github.com/go-sql-driver/mysql" name = "github.com/go-sql-driver/mysql"
revision = "d523deb1b23d913de5bdada721a6071e71283618" revision = "d523deb1b23d913de5bdada721a6071e71283618"
[[override]]
name = "github.com/mattn/go-sqlite3"
revision = "c7c4067b79cc51e6dfdcef5c702e74b1e0fa7c75"
[[override]] [[override]]
name = "github.com/gorilla/mux" name = "github.com/gorilla/mux"
revision = "757bef944d0f21880861c2dd9c871ca543023cba" revision = "757bef944d0f21880861c2dd9c871ca543023cba"
@@ -70,7 +57,7 @@ ignored = ["google.golang.org/appengine*"]
[[constraint]] [[constraint]]
name = "github.com/markbates/goth" name = "github.com/markbates/goth"
version = "1.47.2" version = "1.46.1"
[[constraint]] [[constraint]]
branch = "master" branch = "master"
@@ -114,9 +101,5 @@ ignored = ["google.golang.org/appengine*"]
source = "github.com/go-gitea/bolt" source = "github.com/go-gitea/bolt"
[[override]] [[override]]
branch = "master" revision = "c10ba270aa0bf8b8c1c986e103859c67a9103061"
name = "golang.org/x/oauth2" name = "golang.org/x/oauth2"
[[constraint]]
name = "github.com/prometheus/client_golang"
version = "0.9.0"

View File

@@ -20,9 +20,7 @@ Jonas Östanbäck <jonas.ostanback@gmail.com> (@cez81)
David Schneiderbauer <dschneiderbauer@gmail.com> (@daviian) David Schneiderbauer <dschneiderbauer@gmail.com> (@daviian)
Peter Žeby <morlinest@gmail.com> (@morlinest) Peter Žeby <morlinest@gmail.com> (@morlinest)
Matti Ranta <matti@mdranta.net> (@techknowlogick) Matti Ranta <matti@mdranta.net> (@techknowlogick)
Jonas Franz <info@jonasfranz.software> (@jonasfranz) Michael Lustfield <mtecknology@debian.org> (@MTecknology)
Jonas Franz <info@jonasfranz.software> (@JonasFranzDEV)
Alexey Terentyev <axifnx@gmail.com> (@axifive) Alexey Terentyev <axifnx@gmail.com> (@axifive)
Lanre Adelowo <yo@lanre.wtf> (@adelowo) Lanre Adelowo <yo@lanre.wtf> (@adelowo)
Konrad Langenberg <k@knt.li> (@kolaente)
He-Long Zhang <outman99@hotmail.com> (@BetaCat0)
Andrew Thornton <art27@cantab.net> (@zeripath)

View File

@@ -54,10 +54,6 @@ TEST_PGSQL_HOST ?= pgsql:5432
TEST_PGSQL_DBNAME ?= testgitea TEST_PGSQL_DBNAME ?= testgitea
TEST_PGSQL_USERNAME ?= postgres TEST_PGSQL_USERNAME ?= postgres
TEST_PGSQL_PASSWORD ?= postgres TEST_PGSQL_PASSWORD ?= postgres
TEST_MSSQL_HOST ?= mssql:1433
TEST_MSSQL_DBNAME ?= gitea
TEST_MSSQL_USERNAME ?= sa
TEST_MSSQL_PASSWORD ?= MwantsaSecurePassword1
ifeq ($(OS), Windows_NT) ifeq ($(OS), Windows_NT)
EXECUTABLE := gitea.exe EXECUTABLE := gitea.exe
@@ -78,9 +74,9 @@ clean:
$(GO) clean -i ./... $(GO) clean -i ./...
rm -rf $(EXECUTABLE) $(DIST) $(BINDATA) \ rm -rf $(EXECUTABLE) $(DIST) $(BINDATA) \
integrations*.test \ integrations*.test \
integrations/gitea-integration-pgsql/ integrations/gitea-integration-mysql/ integrations/gitea-integration-sqlite/ integrations/gitea-integration-mssql/ \ integrations/gitea-integration-pgsql/ integrations/gitea-integration-mysql/ integrations/gitea-integration-sqlite/ \
integrations/indexers-mysql/ integrations/indexers-pgsql integrations/indexers-sqlite integrations/indexers-mssql \ integrations/indexers-mysql/ integrations/indexers-pgsql integrations/indexers-sqlite \
integrations/mysql.ini integrations/pgsql.ini integrations/mssql.ini integrations/mysql.ini integrations/pgsql.ini
.PHONY: fmt .PHONY: fmt
fmt: fmt:
@@ -93,7 +89,7 @@ vet:
.PHONY: generate .PHONY: generate
generate: generate:
@hash go-bindata > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash go-bindata > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/jteeuwen/go-bindata/go-bindata; \ $(GO) get -u github.com/jteeuwen/go-bindata/...; \
fi fi
$(GO) generate $(PACKAGES) $(GO) generate $(PACKAGES)
@@ -132,10 +128,10 @@ errcheck:
.PHONY: lint .PHONY: lint
lint: lint:
@hash revive > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
$(GO) get -u github.com/mgechev/revive; \ $(GO) get -u golang.org/x/lint/golint; \
fi fi
revive -config .revive.toml -exclude=./vendor/... ./... || exit 1 for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done;
.PHONY: misspell-check .PHONY: misspell-check
misspell-check: misspell-check:
@@ -163,7 +159,7 @@ fmt-check:
.PHONY: test .PHONY: test
test: test:
$(GO) test -tags='sqlite sqlite_unlock_notify' $(PACKAGES) $(GO) test -tags=sqlite $(PACKAGES)
.PHONY: coverage .PHONY: coverage
coverage: coverage:
@@ -174,7 +170,7 @@ coverage:
.PHONY: unit-test-coverage .PHONY: unit-test-coverage
unit-test-coverage: unit-test-coverage:
for PKG in $(PACKAGES); do $(GO) test -tags='sqlite sqlite_unlock_notify' -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done; for PKG in $(PACKAGES); do $(GO) test -tags=sqlite -cover -coverprofile $$GOPATH/src/$$PKG/coverage.out $$PKG || exit 1; done;
.PHONY: vendor .PHONY: vendor
vendor: vendor:
@@ -208,11 +204,6 @@ generate-ini:
-e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \ -e 's|{{TEST_PGSQL_USERNAME}}|${TEST_PGSQL_USERNAME}|g' \
-e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \ -e 's|{{TEST_PGSQL_PASSWORD}}|${TEST_PGSQL_PASSWORD}|g' \
integrations/pgsql.ini.tmpl > integrations/pgsql.ini integrations/pgsql.ini.tmpl > integrations/pgsql.ini
sed -e 's|{{TEST_MSSQL_HOST}}|${TEST_MSSQL_HOST}|g' \
-e 's|{{TEST_MSSQL_DBNAME}}|${TEST_MSSQL_DBNAME}|g' \
-e 's|{{TEST_MSSQL_USERNAME}}|${TEST_MSSQL_USERNAME}|g' \
-e 's|{{TEST_MSSQL_PASSWORD}}|${TEST_MSSQL_PASSWORD}|g' \
integrations/mssql.ini.tmpl > integrations/mssql.ini
.PHONY: test-mysql .PHONY: test-mysql
test-mysql: integrations.test generate-ini test-mysql: integrations.test generate-ini
@@ -222,10 +213,6 @@ test-mysql: integrations.test generate-ini
test-pgsql: integrations.test generate-ini test-pgsql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.test GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/pgsql.ini ./integrations.test
.PHONY: test-mssql
test-mssql: integrations.test generate-ini
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/mssql.ini ./integrations.test
.PHONY: bench-sqlite .PHONY: bench-sqlite
bench-sqlite: integrations.sqlite.test bench-sqlite: integrations.sqlite.test
GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench . GITEA_ROOT=${CURDIR} GITEA_CONF=integrations/sqlite.ini ./integrations.sqlite.test -test.cpuprofile=cpu.out -test.run DontRunTests -test.bench .
@@ -247,7 +234,7 @@ integrations.test: $(SOURCES)
$(GO) test -c code.gitea.io/gitea/integrations -o integrations.test $(GO) test -c code.gitea.io/gitea/integrations -o integrations.test
integrations.sqlite.test: $(SOURCES) integrations.sqlite.test: $(SOURCES)
$(GO) test -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite sqlite_unlock_notify' $(GO) test -c code.gitea.io/gitea/integrations -o integrations.sqlite.test -tags 'sqlite'
integrations.cover.test: $(SOURCES) integrations.cover.test: $(SOURCES)
$(GO) test -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(PACKAGES) | tr ' ' ',') -o integrations.cover.test $(GO) test -c code.gitea.io/gitea/integrations -coverpkg $(shell echo $(PACKAGES) | tr ' ' ',') -o integrations.cover.test
@@ -360,8 +347,6 @@ update-translations:
generate-images: generate-images:
mkdir -p $(TMPDIR)/images mkdir -p $(TMPDIR)/images
inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png inkscape -f $(PWD)/assets/logo.svg -w 880 -h 880 -e $(PWD)/public/img/gitea-lg.png
inkscape -f $(PWD)/assets/logo.svg -w 512 -h 512 -e $(PWD)/public/img/gitea-512.png
inkscape -f $(PWD)/assets/logo.svg -w 192 -h 192 -e $(PWD)/public/img/gitea-192.png
inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer1 -e $(TMPDIR)/images/sm-1.png inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer1 -e $(TMPDIR)/images/sm-1.png
inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer2 -e $(TMPDIR)/images/sm-2.png inkscape -f $(PWD)/assets/logo.svg -w 120 -h 120 -jC -i layer2 -e $(TMPDIR)/images/sm-2.png
composite -compose atop $(TMPDIR)/images/sm-2.png $(TMPDIR)/images/sm-1.png $(PWD)/public/img/gitea-sm.png composite -compose atop $(TMPDIR)/images/sm-2.png $(TMPDIR)/images/sm-1.png $(PWD)/public/img/gitea-sm.png

View File

@@ -38,7 +38,7 @@ More info: https://docs.gitea.io/en-us/install-from-source/
./gitea web ./gitea web
NOTE: If you're interested in using our APIs, we have experimental NOTE: If you're interested in using our APIs, we have experimental
support with [documentation](https://try.gitea.io/api/swagger). support with [documentation](https://godoc.org/code.gitea.io/sdk/gitea).
## Contributing ## Contributing

View File

@@ -6,7 +6,6 @@
package cmd package cmd
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"text/tabwriter" "text/tabwriter"
@@ -14,7 +13,6 @@ import (
"code.gitea.io/git" "code.gitea.io/git"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth/oauth2" "code.gitea.io/gitea/modules/auth/oauth2"
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@@ -61,19 +59,6 @@ var (
Value: "custom/conf/app.ini", Value: "custom/conf/app.ini",
Usage: "Custom configuration file path", Usage: "Custom configuration file path",
}, },
cli.BoolFlag{
Name: "random-password",
Usage: "Generate a random password for the user",
},
cli.BoolFlag{
Name: "must-change-password",
Usage: "Force the user to change his/her password after initial login",
},
cli.IntFlag{
Name: "random-password-length",
Usage: "Length of the random password to be generated",
Value: 12,
},
}, },
} }
@@ -288,30 +273,10 @@ func runChangePassword(c *cli.Context) error {
} }
func runCreateUser(c *cli.Context) error { func runCreateUser(c *cli.Context) error {
if err := argsSet(c, "name", "email"); err != nil { if err := argsSet(c, "name", "password", "email"); err != nil {
return err return err
} }
if c.IsSet("password") && c.IsSet("random-password") {
return errors.New("cannot set both -random-password and -password flags")
}
var password string
if c.IsSet("password") {
password = c.String("password")
} else if c.IsSet("random-password") {
var err error
password, err = generate.GetRandomString(c.Int("random-password-length"))
if err != nil {
return err
}
fmt.Printf("generated random password is '%s'\n", password)
} else {
return errors.New("must set either password or random-password flag")
}
if c.IsSet("config") { if c.IsSet("config") {
setting.CustomConf = c.String("config") setting.CustomConf = c.String("config")
} }
@@ -320,26 +285,12 @@ func runCreateUser(c *cli.Context) error {
return err return err
} }
// always default to true
var changePassword = true
// If this is the first user being created.
// Take it as the admin and don't force a password update.
if n := models.CountUsers(); n == 0 {
changePassword = false
}
if c.IsSet("must-change-password") {
changePassword = c.Bool("must-change-password")
}
if err := models.CreateUser(&models.User{ if err := models.CreateUser(&models.User{
Name: c.String("name"), Name: c.String("name"),
Email: c.String("email"), Email: c.String("email"),
Passwd: password, Passwd: c.String("password"),
IsActive: true, IsActive: true,
IsAdmin: c.Bool("admin"), IsAdmin: c.Bool("admin"),
MustChangePassword: changePassword,
}); err != nil { }); err != nil {
return fmt.Errorf("CreateUser: %v", err) return fmt.Errorf("CreateUser: %v", err)
} }
@@ -461,12 +412,16 @@ func runAddOauth(c *cli.Context) error {
return err return err
} }
return models.CreateLoginSource(&models.LoginSource{ if err := models.CreateLoginSource(&models.LoginSource{
Type: models.LoginOAuth2, Type: models.LoginOAuth2,
Name: c.String("name"), Name: c.String("name"),
IsActived: true, IsActived: true,
Cfg: parseOAuth2Config(c), Cfg: parseOAuth2Config(c),
}) }); err != nil {
return err
}
return nil
} }
func runUpdateOauth(c *cli.Context) error { func runUpdateOauth(c *cli.Context) error {
@@ -537,7 +492,11 @@ func runUpdateOauth(c *cli.Context) error {
oAuth2Config.CustomURLMapping = customURLMapping oAuth2Config.CustomURLMapping = customURLMapping
source.Cfg = oAuth2Config source.Cfg = oAuth2Config
return models.UpdateSource(source) if err := models.UpdateSource(source); err != nil {
return err
}
return nil
} }
func runListAuth(c *cli.Context) error { func runListAuth(c *cli.Context) error {
@@ -584,5 +543,8 @@ func runDeleteAuth(c *cli.Context) error {
return err return err
} }
return models.DeleteSource(source) if err = models.DeleteSource(source); err != nil {
return err
}
return nil
} }

View File

@@ -9,7 +9,6 @@ package cmd
import ( import (
"errors" "errors"
"fmt" "fmt"
"strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@@ -23,23 +22,15 @@ func argsSet(c *cli.Context, args ...string) error {
if !c.IsSet(a) { if !c.IsSet(a) {
return errors.New(a + " is not set") return errors.New(a + " is not set")
} }
if len(strings.TrimSpace(c.String(a))) == 0 {
return errors.New(a + " is required")
}
} }
return nil return nil
} }
func initDB() error { func initDB() error {
return initDBDisableConsole(false)
}
func initDBDisableConsole(disableConsole bool) error {
setting.NewContext() setting.NewContext()
models.LoadConfigs() models.LoadConfigs()
setting.NewXORMLogService(disableConsole) setting.NewXORMLogService(false)
if err := models.SetEngine(); err != nil { if err := models.SetEngine(); err != nil {
return fmt.Errorf("models.SetEngine: %v", err) return fmt.Errorf("models.SetEngine: %v", err)
} }

View File

@@ -8,8 +8,8 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"net/url"
"os" "os"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
@@ -62,6 +62,12 @@ var (
} }
) )
func hookSetup(logPath string) {
setting.NewContext()
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
models.LoadConfigs()
}
func runHookPreReceive(c *cli.Context) error { func runHookPreReceive(c *cli.Context) error {
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 { if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
return nil return nil
@@ -73,7 +79,7 @@ func runHookPreReceive(c *cli.Context) error {
setting.CustomConf = c.GlobalString("config") setting.CustomConf = c.GlobalString("config")
} }
setup("hooks/pre-receive.log") hookSetup("hooks/pre-receive.log")
// the environment setted on serv command // the environment setted on serv command
repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64) repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
@@ -149,7 +155,7 @@ func runHookUpdate(c *cli.Context) error {
setting.CustomConf = c.GlobalString("config") setting.CustomConf = c.GlobalString("config")
} }
setup("hooks/update.log") hookSetup("hooks/update.log")
return nil return nil
} }
@@ -165,10 +171,9 @@ func runHookPostReceive(c *cli.Context) error {
setting.CustomConf = c.GlobalString("config") setting.CustomConf = c.GlobalString("config")
} }
setup("hooks/post-receive.log") hookSetup("hooks/post-receive.log")
// the environment setted on serv command // the environment setted on serv command
repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
repoUser := os.Getenv(models.EnvRepoUsername) repoUser := os.Getenv(models.EnvRepoUsername)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true") isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
repoName := os.Getenv(models.EnvRepoName) repoName := os.Getenv(models.EnvRepoName)
@@ -206,47 +211,6 @@ func runHookPostReceive(c *cli.Context) error {
}); err != nil { }); err != nil {
log.GitLogger.Error(2, "Update: %v", err) log.GitLogger.Error(2, "Update: %v", err)
} }
if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) {
branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
repo, pullRequestAllowed, err := private.GetRepository(repoID)
if err != nil {
log.GitLogger.Error(2, "get repo: %v", err)
break
}
if !pullRequestAllowed {
break
}
baseRepo := repo
if repo.IsFork {
baseRepo = repo.BaseRepo
}
if !repo.IsFork && branch == baseRepo.DefaultBranch {
break
}
pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
if err != nil {
log.GitLogger.Error(2, "get active pr: %v", err)
break
}
fmt.Fprintln(os.Stderr, "")
if pr == nil {
if repo.IsFork {
branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
}
fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
fmt.Fprintf(os.Stderr, " %s/compare/%s...%s\n", baseRepo.HTMLURL(), url.QueryEscape(baseRepo.DefaultBranch), url.QueryEscape(branch))
} else {
fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
fmt.Fprintf(os.Stderr, " %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index)
}
fmt.Fprintln(os.Stderr, "")
}
} }
return nil return nil

View File

@@ -1,85 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"errors"
"fmt"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
// CmdKeys represents the available keys sub-command
var CmdKeys = cli.Command{
Name: "keys",
Usage: "This command queries the Gitea database to get the authorized command for a given ssh key fingerprint",
Action: runKeys,
Flags: []cli.Flag{
cli.StringFlag{
Name: "expected, e",
Value: "git",
Usage: "Expected user for whom provide key commands",
},
cli.StringFlag{
Name: "username, u",
Value: "",
Usage: "Username trying to log in by SSH",
},
cli.StringFlag{
Name: "type, t",
Value: "",
Usage: "Type of the SSH key provided to the SSH Server (requires content to be provided too)",
},
cli.StringFlag{
Name: "content, k",
Value: "",
Usage: "Base64 encoded content of the SSH key provided to the SSH Server (requires type to be provided too)",
},
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
func runKeys(c *cli.Context) error {
if c.IsSet("config") {
setting.CustomConf = c.String("config")
}
if !c.IsSet("username") {
return errors.New("No username provided")
}
// Check username matches the expected username
if strings.TrimSpace(c.String("username")) != strings.TrimSpace(c.String("expected")) {
return nil
}
content := ""
if c.IsSet("type") && c.IsSet("content") {
content = fmt.Sprintf("%s %s", strings.TrimSpace(c.String("type")), strings.TrimSpace(c.String("content")))
}
if content == "" {
return errors.New("No key type and content provided")
}
if err := initDBDisableConsole(true); err != nil {
return err
}
publicKey, err := models.SearchPublicKeyByContent(content)
if err != nil {
return err
}
fmt.Println(publicKey.AuthorizedString())
return nil
}

View File

@@ -1,52 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package cmd
import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/migrations"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
// CmdMigrate represents the available migrate sub-command.
var CmdMigrate = cli.Command{
Name: "migrate",
Usage: "Migrate the database",
Description: "This is a command for migrating the database, so that you can run gitea admin create-user before starting the server.",
Action: runMigrate,
Flags: []cli.Flag{
cli.StringFlag{
Name: "config, c",
Value: "custom/conf/app.ini",
Usage: "Custom configuration file path",
},
},
}
func runMigrate(ctx *cli.Context) error {
if ctx.IsSet("config") {
setting.CustomConf = ctx.String("config")
}
if err := initDB(); err != nil {
return err
}
log.Trace("AppPath: %s", setting.AppPath)
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
log.Trace("Custom path: %s", setting.CustomPath)
log.Trace("Log path: %s", setting.LogRootPath)
models.LoadConfigs()
if err := models.NewEngine(migrations.Migrate); err != nil {
log.Fatal(4, "Failed to initialize ORM engine: %v", err)
return err
}
return nil
}

View File

@@ -14,16 +14,15 @@ import (
"strings" "strings"
"time" "time"
"code.gitea.io/git"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/pprof" "code.gitea.io/gitea/modules/pprof"
"code.gitea.io/gitea/modules/private" "code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"github.com/Unknwon/com" "github.com/Unknwon/com"
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
version "github.com/mcuadros/go-version"
"github.com/urfave/cli" "github.com/urfave/cli"
) )
@@ -50,29 +49,20 @@ var CmdServ = cli.Command{
}, },
} }
func checkLFSVersion() { func setup(logPath string) error {
if setting.LFS.StartServer {
//Disable LFS client hooks if installed for the current OS user
//Needs at least git v2.1.2
binVersion, err := git.BinVersion()
if err != nil {
fail(fmt.Sprintf("Error retrieving git version: %v", err), fmt.Sprintf("Error retrieving git version: %v", err))
}
if !version.Compare(binVersion, "2.1.2", ">=") {
setting.LFS.StartServer = false
println("LFS server support needs at least Git v2.1.2, disabled")
} else {
git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "filter.lfs.required=",
"-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=")
}
}
}
func setup(logPath string) {
setting.NewContext() setting.NewContext()
checkLFSVersion()
log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath)) log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
models.LoadConfigs()
if setting.UseSQLite3 || setting.UseTiDB {
workPath := setting.AppWorkPath
if err := os.Chdir(workPath); err != nil {
log.GitLogger.Fatal(4, "Failed to change directory %s: %v", workPath, err)
}
}
setting.NewXORMLogService(true)
return models.SetEngine()
} }
func parseCmd(cmd string) (string, string) { func parseCmd(cmd string) (string, string) {
@@ -111,7 +101,10 @@ func runServ(c *cli.Context) error {
if c.IsSet("config") { if c.IsSet("config") {
setting.CustomConf = c.String("config") setting.CustomConf = c.String("config")
} }
setup("serv.log")
if err := setup("serv.log"); err != nil {
fail("System init failed", fmt.Sprintf("setup: %v", err))
}
if setting.SSH.Disabled { if setting.SSH.Disabled {
println("Gitea: SSH has been disabled") println("Gitea: SSH has been disabled")
@@ -166,15 +159,11 @@ func runServ(c *cli.Context) error {
}() }()
} }
var ( isWiki := false
isWiki bool unitType := models.UnitTypeCode
unitType = models.UnitTypeCode
unitName = "code"
)
if strings.HasSuffix(reponame, ".wiki") { if strings.HasSuffix(reponame, ".wiki") {
isWiki = true isWiki = true
unitType = models.UnitTypeWiki unitType = models.UnitTypeWiki
unitName = "wiki"
reponame = reponame[:len(reponame)-5] reponame = reponame[:len(reponame)-5]
} }
@@ -186,9 +175,9 @@ func runServ(c *cli.Context) error {
} }
os.Setenv(models.EnvRepoName, reponame) os.Setenv(models.EnvRepoName, reponame)
repo, err := private.GetRepositoryByOwnerAndName(username, reponame) repo, err := models.GetRepositoryByOwnerAndName(username, reponame)
if err != nil { if err != nil {
if strings.Contains(err.Error(), "Failed to get repository: repository does not exist") { if models.IsErrRepoNotExist(err) {
fail(accessDenied, "Repository does not exist: %s/%s", username, reponame) fail(accessDenied, "Repository does not exist: %s/%s", username, reponame)
} }
fail("Internal error", "Failed to get repository: %v", err) fail("Internal error", "Failed to get repository: %v", err)
@@ -219,13 +208,13 @@ func runServ(c *cli.Context) error {
keyID int64 keyID int64
user *models.User user *models.User
) )
if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView { if requestedMode == models.AccessModeWrite || repo.IsPrivate {
keys := strings.Split(c.Args()[0], "-") keys := strings.Split(c.Args()[0], "-")
if len(keys) != 2 { if len(keys) != 2 {
fail("Key ID format error", "Invalid key argument: %s", c.Args()[0]) fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
} }
key, err := private.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64()) key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
if err != nil { if err != nil {
fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err) fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
} }
@@ -236,22 +225,23 @@ func runServ(c *cli.Context) error {
if key.Mode < requestedMode { if key.Mode < requestedMode {
fail("Key permission denied", "Cannot push with deployment key: %d", key.ID) fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
} }
// Check if this deploy key belongs to current repository. // Check if this deploy key belongs to current repository.
has, err := private.HasDeployKey(key.ID, repo.ID) if !models.HasDeployKey(key.ID, repo.ID) {
if err != nil {
fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
}
if !has {
fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID) fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
} }
// Update deploy key activity. // Update deploy key activity.
if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil { deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
if err != nil {
fail("Internal error", "GetDeployKey: %v", err)
}
deployKey.UpdatedUnix = util.TimeStampNow()
if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil {
fail("Internal error", "UpdateDeployKey: %v", err) fail("Internal error", "UpdateDeployKey: %v", err)
} }
} else { } else {
user, err = private.GetUserByKeyID(key.ID) user, err = models.GetUserByKeyID(key.ID)
if err != nil { if err != nil {
fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err) fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
} }
@@ -262,19 +252,25 @@ func runServ(c *cli.Context) error {
user.Name, repoPath) user.Name, repoPath)
} }
mode, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType) mode, err := models.AccessLevel(user.ID, repo)
if err != nil { if err != nil {
fail("Internal error", "Failed to check access: %v", err) fail("Internal error", "Failed to check access: %v", err)
} else if *mode < requestedMode { } else if mode < requestedMode {
clientMessage := accessDenied clientMessage := accessDenied
if *mode >= models.AccessModeRead { if mode >= models.AccessModeRead {
clientMessage = "You do not have sufficient authorization for this action" clientMessage = "You do not have sufficient authorization for this action"
} }
fail(clientMessage, fail(clientMessage,
"User %s does not have level %v access to repository %s's "+unitName, "User %s does not have level %v access to repository %s",
user.Name, requestedMode, repoPath) user.Name, requestedMode, repoPath)
} }
if !repo.CheckUnitUser(user.ID, user.IsAdmin, unitType) {
fail("You do not have allowed for this action",
"User %s does not have allowed access to repository %s 's code",
user.Name, repoPath)
}
os.Setenv(models.EnvPusherName, user.Name) os.Setenv(models.EnvPusherName, user.Name)
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID)) os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
} }
@@ -329,8 +325,9 @@ func runServ(c *cli.Context) error {
} else { } else {
gitcmd = exec.Command(verb, repoPath) gitcmd = exec.Command(verb, repoPath)
} }
if isWiki { if isWiki {
if err = private.InitWiki(repo.ID); err != nil { if err = repo.InitWiki(); err != nil {
fail("Internal error", "Failed to init wiki repo: %v", err) fail("Internal error", "Failed to init wiki repo: %v", err)
} }
} }

View File

@@ -19,7 +19,7 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "debug", "mode": "debug",
"buildFlags": "-tags=\"sqlite sqlite_unlock_notify\"", "buildFlags": "-tags=\"sqlite\"",
"port": 2345, "port": 2345,
"host": "127.0.0.1", "host": "127.0.0.1",
"program": "${workspaceRoot}/main.go", "program": "${workspaceRoot}/main.go",

View File

@@ -35,7 +35,7 @@
"focus": false, "focus": false,
"panel": "shared" "panel": "shared"
}, },
"args": ["build", "-tags=\"sqlite sqlite_unlock_notify\""], "args": ["build", "-tags=\"sqlite\""],
"linux": { "linux": {
"args": ["-o", "gitea", "${workspaceRoot}/main.go"] "args": ["-o", "gitea", "${workspaceRoot}/main.go"]
}, },

View File

@@ -1,107 +0,0 @@
apiVersion: v1
kind: Namespace
metadata:
name: gitea
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: gitea
namespace: gitea
labels:
app: gitea
spec:
replicas: 1
template:
metadata:
name: gitea
labels:
app: gitea
spec:
containers:
- name: gitea
image: gitea/gitea:latest
imagePullPolicy: Always
volumeMounts:
- mountPath: "/var/lib/gitea"
name: "root"
- mountPath: "/data"
name: "data"
ports:
- containerPort: 22
name: ssh
protocol: TCP
- containerPort: 3000
name: http
protocol: TCP
restartPolicy: Always
volumes:
# Set up a data directory for gitea
# For production usage, you should consider using PV/PVC instead(or simply using storage like NAS)
# For more details, please see https://kubernetes.io/docs/concepts/storage/volumes/
- name: "root"
hostPath:
# directory location on host
path: "/var/lib/gitea"
# this field is optional
type: Directory
- name: "data"
hostPath:
path: "/data/gitea"
type: Directory
selector:
matchLabels:
app: gitea
---
# Using cluster mode
apiVersion: v1
kind: Service
metadata:
name: gitea-web
namespace: gitea
labels:
app: gitea-web
spec:
ports:
- port: 80
targetPort: 3000
name: http
selector:
app: gitea
---
# Using node-port mode
# This mainly open a specific TCP port for SSH usage on each host,
# so you can use a proxy layer to handle it(e.g. slb, nginx)
apiVersion: v1
kind: Service
metadata:
name: gitea-ssh
namespace: gitea
labels:
app: gitea-ssh
spec:
ports:
- port: 22
targetPort: 22
nodePort: 30022
name: ssh
selector:
app: gitea
type: NodePort
---
# Ingress is always suitable for HTTP usage,
# we suggest using an proxy layer such as slb to send traffic to different ports.
# Usually 80/443 for web and 22 directly for SSH.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: gitea
namespace: gitea
spec:
rules:
- host: your-gitea-host.com
http:
paths:
- backend:
serviceName: gitea-web
servicePort: 80

View File

@@ -144,7 +144,7 @@ START_SSH_SERVER = false
BUILTIN_SSH_SERVER_USER = BUILTIN_SSH_SERVER_USER =
; Domain name to be exposed in clone URL ; Domain name to be exposed in clone URL
SSH_DOMAIN = %(DOMAIN)s SSH_DOMAIN = %(DOMAIN)s
; The network interface the builtin SSH server should listen on ; THe network interface the builtin SSH server should listen on
SSH_LISTEN_HOST = SSH_LISTEN_HOST =
; Port number to be exposed in clone URL ; Port number to be exposed in clone URL
SSH_PORT = 22 SSH_PORT = 22
@@ -152,9 +152,6 @@ SSH_PORT = 22
SSH_LISTEN_PORT = %(SSH_PORT)s SSH_LISTEN_PORT = %(SSH_PORT)s
; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'. ; Root path of SSH directory, default is '~/.ssh', but you have to use '/home/git/.ssh'.
SSH_ROOT_PATH = SSH_ROOT_PATH =
; Gitea will create a authorized_keys file by default when it is not using the internal ssh server
; If you intend to use the AuthorizedKeysCommand functionality then you should turn this off.
SSH_CREATE_AUTHORIZED_KEYS_FILE = true
; For the built-in SSH server, choose the ciphers to support for SSH connections, ; For the built-in SSH server, choose the ciphers to support for SSH connections,
; for system SSH this setting has no effect ; for system SSH this setting has no effect
SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128 SSH_SERVER_CIPHERS = aes128-ctr, aes192-ctr, aes256-ctr, aes128-gcm@openssh.com, arcfour256, arcfour128
@@ -261,12 +258,11 @@ COOKIE_USERNAME = gitea_awesome
COOKIE_REMEMBER_NAME = gitea_incredible COOKIE_REMEMBER_NAME = gitea_incredible
; Reverse proxy authentication header name of user name ; Reverse proxy authentication header name of user name
REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL
; The minimum password length for new Users ; The minimum password length for new Users
MIN_PASSWORD_LENGTH = 6 MIN_PASSWORD_LENGTH = 6
; Set to true to allow users to import local server paths ; True when users are allowed to import local server paths
IMPORT_LOCAL_PATHS = false IMPORT_LOCAL_PATHS = false
; Set to true to prevent all users (including admin) from creating custom git hooks ; Prevent all users (including admin) from creating custom git hooks
DISABLE_GIT_HOOKS = false DISABLE_GIT_HOOKS = false
[openid] [openid]
@@ -310,12 +306,9 @@ ACTIVE_CODE_LIVE_MINUTES = 180
RESET_PASSWD_CODE_LIVE_MINUTES = 180 RESET_PASSWD_CODE_LIVE_MINUTES = 180
; Whether a new user needs to confirm their email when registering. ; Whether a new user needs to confirm their email when registering.
REGISTER_EMAIL_CONFIRM = false REGISTER_EMAIL_CONFIRM = false
; List of domain names that are allowed to be used to register on a Gitea instance
; gitea.io,example.com
EMAIL_DOMAIN_WHITELIST=
; Disallow registration, only allow admins to create accounts. ; Disallow registration, only allow admins to create accounts.
DISABLE_REGISTRATION = false DISABLE_REGISTRATION = false
; Allow registration only using third-party services, it works only when DISABLE_REGISTRATION is false ; Allow registration only using third part services, it works only when DISABLE_REGISTRATION is false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false ALLOW_ONLY_EXTERNAL_REGISTRATION = false
; User must sign in to view anything. ; User must sign in to view anything.
REQUIRE_SIGNIN_VIEW = false REQUIRE_SIGNIN_VIEW = false
@@ -324,7 +317,6 @@ ENABLE_NOTIFY_MAIL = false
; More detail: https://github.com/gogits/gogs/issues/165 ; More detail: https://github.com/gogits/gogs/issues/165
ENABLE_REVERSE_PROXY_AUTHENTICATION = false ENABLE_REVERSE_PROXY_AUTHENTICATION = false
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false
ENABLE_REVERSE_PROXY_EMAIL = false
; Enable captcha validation for registration ; Enable captcha validation for registration
ENABLE_CAPTCHA = false ENABLE_CAPTCHA = false
; Type of captcha you want to use. Options: image, recaptcha ; Type of captcha you want to use. Options: image, recaptcha
@@ -340,10 +332,8 @@ DEFAULT_KEEP_EMAIL_PRIVATE = false
; Every new user will have rights set to create organizations depending on this setting ; Every new user will have rights set to create organizations depending on this setting
DEFAULT_ALLOW_CREATE_ORGANIZATION = true DEFAULT_ALLOW_CREATE_ORGANIZATION = true
; Default value for EnableDependencies ; Default value for EnableDependencies
; Repositories will use dependencies by default depending on this setting ; Repositories will use depencies by default depending on this setting
DEFAULT_ENABLE_DEPENDENCIES = true DEFAULT_ENABLE_DEPENDENCIES = true
; Enable heatmap on users profiles.
ENABLE_USER_HEATMAP = true
; Enable Timetracking ; Enable Timetracking
ENABLE_TIMETRACKING = true ENABLE_TIMETRACKING = true
; Default value for EnableTimetracking ; Default value for EnableTimetracking
@@ -388,8 +378,6 @@ SKIP_VERIFY =
USE_CERTIFICATE = false USE_CERTIFICATE = false
CERT_FILE = custom/mailer/cert.pem CERT_FILE = custom/mailer/cert.pem
KEY_FILE = custom/mailer/key.pem KEY_FILE = custom/mailer/key.pem
; Should SMTP connection use TLS
IS_TLS_ENABLED = false
; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format ; Mail from address, RFC 5322. This can be just an email address, or the `"Name" <email@example.com>` format
FROM = FROM =
; Mailer user name and password ; Mailer user name and password
@@ -549,7 +537,7 @@ SCHEDULE = @every 10m
SCHEDULE = @every 24h SCHEDULE = @every 24h
TIMEOUT = 60s TIMEOUT = 60s
; Arguments for command 'git fsck', e.g. "--unreachable --tags" ; Arguments for command 'git fsck', e.g. "--unreachable --tags"
; see more on http://git-scm.com/docs/git-fsck ; see more on http://git-scm.com/docs/git-fsck/1.7.5
ARGS = ARGS =
; Check repository statistics ; Check repository statistics
@@ -588,7 +576,7 @@ MAX_GIT_DIFF_LINE_CHARACTERS = 5000
; Max number of files shown in diff view ; Max number of files shown in diff view
MAX_GIT_DIFF_FILES = 100 MAX_GIT_DIFF_FILES = 100
; Arguments for command 'git gc', e.g. "--aggressive --auto" ; Arguments for command 'git gc', e.g. "--aggressive --auto"
; see more on http://git-scm.com/docs/git-gc/ ; see more on http://git-scm.com/docs/git-gc/1.7.5
GC_ARGS = GC_ARGS =
; Operation timeout in seconds ; Operation timeout in seconds
@@ -666,9 +654,3 @@ FILE_EXTENSIONS = .adoc,.asciidoc
RENDER_COMMAND = "asciidoc --out-file=- -" RENDER_COMMAND = "asciidoc --out-file=- -"
; Don't pass the file on STDIN, pass the filename as argument instead. ; Don't pass the file on STDIN, pass the filename as argument instead.
IS_INPUT_FILE = false IS_INPUT_FILE = false
[metrics]
; Enables metrics endpoint. True or false; default is false.
ENABLED = false
; If you want to add authorization, specify a token here
TOKEN =

2
docker/Makefile vendored
View File

@@ -8,7 +8,7 @@ DOCKER_REF := $(DOCKER_IMAGE):$(DOCKER_TAG)
.PHONY: docker .PHONY: docker
docker: docker:
docker build --disable-content-trust=false -t $(DOCKER_REF) . docker build --disable-content-trust=false -t $(DOCKER_REF) .
# support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite sqlite_unlock_notify" . # support also build args docker build --build-arg GITEA_VERSION=v1.2.3 --build-arg TAGS="bindata sqlite" .
.PHONY: docker-build .PHONY: docker-build
docker-build: docker-build:

View File

@@ -39,8 +39,5 @@ if [ ! -f /data/gitea/conf/app.ini ]; then
envsubst < /etc/templates/app.ini > /data/gitea/conf/app.ini envsubst < /etc/templates/app.ini > /data/gitea/conf/app.ini
fi fi
# only chown if current owner is not already the gitea ${USER}. No recursive check to save time chown -R ${USER}:git /data/gitea /app/gitea /data/git
if ! [[ $(ls -ld /data/gitea | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /data/gitea; fi
if ! [[ $(ls -ld /app/gitea | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /app/gitea; fi
if ! [[ $(ls -ld /data/git | awk '{print $3}') = ${USER} ]]; then chown -R ${USER}:git /data/git; fi
chmod 0755 /data/gitea /app/gitea /data/git chmod 0755 /data/gitea /app/gitea /data/git

View File

@@ -29,5 +29,3 @@ AllowUsers git
Banner none Banner none
Subsystem sftp /usr/lib/ssh/sftp-server Subsystem sftp /usr/lib/ssh/sftp-server
AcceptEnv GIT_PROTOCOL

View File

@@ -4,7 +4,7 @@ if [ "${USER}" != "git" ]; then
# rename user # rename user
sed -i -e "s/^git\:/${USER}\:/g" /etc/passwd sed -i -e "s/^git\:/${USER}\:/g" /etc/passwd
# switch sshd config to different user # switch sshd config to different user
sed -i -e "s/AllowUsers git$/AllowUsers ${USER}/g" /etc/ssh/sshd_config sed -i -e "s/AllowUsers git/AllowUsers ${USER}/g" /etc/ssh/sshd_config
fi fi
## Change GID for USER? ## Change GID for USER?

View File

@@ -1,42 +0,0 @@
# Gitea: 文档
[![Build Status](http://drone.gitea.io/api/badges/go-gitea/docs/status.svg)](http://drone.gitea.io/go-gitea/docs)
[![Join the chat at https://img.shields.io/discord/322538954119184384.svg](https://img.shields.io/discord/322538954119184384.svg)](https://discord.gg/NsatcWJ)
[![](https://images.microbadger.com/badges/image/gitea/docs.svg)](http://microbadger.com/images/gitea/docs "Get your own image badge on microbadger.com")
## 关于托管方式
本页面托管在我们 Docker 容器内的基础设施上, 它会在每次推送到 `master` 分支的时候自动更新,如果你想自己管理这个页面,你可以从我们的 Docker 镜像 [gitea/docs](https://hub.docker.com/r/gitea/docs/) 中获取它。
## 安装 Hugo
本页面使用了 [Hugo](https://github.com/spf13/hugo) 静态页面生成工具,如果您有维护它的意愿,则需要在本地计算机上下载并安装 Hugo。Hugo 的安装教程不在本文档的讲述范围之内,详情请参见 [官方文档](https://gohugo.io/overview/installing/)。
## 如何部署
在 [localhost:1313](http://localhost:1313) 处构建和运行网站的命令如下,如果需要停止可以使用组合键 `Ctrl+C`:
```
make server
```
完成更改后,只需创建一个 Pull Request (PR),该 PR 一经合并网站将自动更新。
## 如何贡献您的代码
Fork -> Patch -> Push -> Pull Request
## 关于我们
* [维护者信息](https://github.com/orgs/go-gitea/people)
* [代码贡献者信息](https://github.com/go-gitea/docs/graphs/contributors)
## 许可证
此项目采用 Apache-2.0 许可协议,请参见 [协议文件](LICENSE) 获取更多信息。
## 版权声明
```
Copyright (c) 2016 The Gitea Authors <https://gitea.io>
```

View File

@@ -122,8 +122,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `LFS_CONTENT_PATH`: **./data/lfs**: Where to store LFS files. - `LFS_CONTENT_PATH`: **./data/lfs**: Where to store LFS files.
- `LFS_JWT_SECRET`: **\<empty\>**: LFS authentication secret, change this a unique string. - `LFS_JWT_SECRET`: **\<empty\>**: LFS authentication secret, change this a unique string.
- `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail. - `LFS_HTTP_AUTH_EXPIRY`: **20m**: LFS authentication validity period in time.Duration, pushes taking longer than this may fail.
- `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, allows redirecting http requests on `PORT_TO_REDIRECT` to the https port Gitea listens on. - `REDIRECT_OTHER_PORT`: **false**: If true and `PROTOCOL` is https, redirects http requests
- `PORT_TO_REDIRECT`: **80**: Port for the http redirection service to listen on. Used when `REDIRECT_OTHER_PORT` is true. on another (https) port.
- `PORT_TO_REDIRECT`: **80**: Port used when `REDIRECT_OTHER_PORT` is true.
- `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server). - `ENABLE_LETSENCRYPT`: **false**: If enabled you must set `DOMAIN` to valid internet facing domain (ensure DNS is set and port 80 is accessible by letsencrypt validation server).
By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf). By using Lets Encrypt **you must consent** to their [terms of service](https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf).
- `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt. - `LETSENCRYPT_ACCEPTTOS`: **false**: This is an explicit check that you accept the terms of service for Let's Encrypt.
@@ -159,11 +160,9 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
information. information.
- `REVERSE_PROXY_AUTHENTICATION_USER`: **X-WEBAUTH-USER**: Header name for reverse proxy - `REVERSE_PROXY_AUTHENTICATION_USER`: **X-WEBAUTH-USER**: Header name for reverse proxy
authentication. authentication.
- `REVERSE_PROXY_AUTHENTICATION_EMAIL`: **X-WEBAUTH-EMAIL**: Header name for reverse proxy - `DISABLE_GIT_HOOKS`: **false**: Prevent all users (including admin) from creating custom
authentication provided email.
- `DISABLE_GIT_HOOKS`: **false**: Set to `true` to prevent all users (including admin) from creating custom
git hooks. git hooks.
- `IMPORT_LOCAL_PATHS`: **false**: Set to `false` to prevent all users (including admin) from importing local path on server. - `IMPORT_LOCAL_PATHS`: **false**: Prevent all users (including admin) from importing local path on server.
## OpenID (`openid`) ## OpenID (`openid`)
@@ -189,16 +188,11 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `ENABLE_REVERSE_PROXY_AUTHENTICATION`: **false**: Enable this to allow reverse proxy authentication. - `ENABLE_REVERSE_PROXY_AUTHENTICATION`: **false**: Enable this to allow reverse proxy authentication.
- `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: **false**: Enable this to allow auto-registration - `ENABLE_REVERSE_PROXY_AUTO_REGISTRATION`: **false**: Enable this to allow auto-registration
for reverse authentication. for reverse authentication.
- `ENABLE_REVERSE_PROXY_EMAIL`: **false**: Enable this to allow to auto-registration with a
provided email rather than a generated email.
- `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration.
- `CAPTCHA_TYPE`: **image**: \[image, recaptcha\] - `CAPTCHA_TYPE`: **image**: \[image, recaptcha\]
- `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha.
- `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha.
- `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default. - `DEFAULT_ENABLE_DEPENDENCIES`: **true** Enable this to have dependencies enabled by default.
- `ENABLE_USER_HEATMAP`: **true** Enable this to display the heatmap on users profiles.
- `EMAIL_DOMAIN_WHITELIST`: **\<empty\>**: If non-empty, list of domain names that can only be used to register
on this instance.
## Webhook (`webhook`) ## Webhook (`webhook`)
@@ -225,7 +219,6 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
`FROM` and `SENDMAIL_PATH`. `FROM` and `SENDMAIL_PATH`.
- `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be - `SENDMAIL_PATH`: **sendmail**: The location of sendmail on the operating system (can be
command or full path). command or full path).
- ``IS_TLS_ENABLED`` : **false** : Decide if SMTP connections should use TLS.
## Cache (`cache`) ## Cache (`cache`)
@@ -287,7 +280,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `SCHEDULE`: **every 24h**: Cron syntax for scheduling repository health check. - `SCHEDULE`: **every 24h**: Cron syntax for scheduling repository health check.
- `TIMEOUT`: **60s**: Time duration syntax for health check execution timeout. - `TIMEOUT`: **60s**: Time duration syntax for health check execution timeout.
- `ARGS`: **\<empty\>**: Arguments for command `git fsck`, e.g. `--unreachable --tags`. See more on http://git-scm.com/docs/git-fsck - `ARGS`: **\<empty\>**: Arguments for command `git fsck`, e.g. `--unreachable --tags`.
### Cron - Repository Statistics Check (`cron.check_repo_stats`) ### Cron - Repository Statistics Check (`cron.check_repo_stats`)
@@ -299,7 +292,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `MAX_GIT_DIFF_LINES`: **100**: Max number of lines allowed of a single file in diff view. - `MAX_GIT_DIFF_LINES`: **100**: Max number of lines allowed of a single file in diff view.
- `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view. - `MAX_GIT_DIFF_LINE_CHARACTERS`: **5000**: Max character count per line highlighted in diff view.
- `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view. - `MAX_GIT_DIFF_FILES`: **100**: Max number of files shown in diff view.
- `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/ - `GC_ARGS`: **\<empty\>**: Arguments for command `git gc`, e.g. `--aggressive --auto`.
## Git - Timeout settings (`git.timeout`) ## Git - Timeout settings (`git.timeout`)
- `MIGRATE`: **600**: Migrate external repositories timeout seconds. - `MIGRATE`: **600**: Migrate external repositories timeout seconds.
@@ -308,11 +301,6 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `PULL`: **300**: Git pull from internal repositories timeout seconds. - `PULL`: **300**: Git pull from internal repositories timeout seconds.
- `GC`: **60**: Git repository GC timeout seconds. - `GC`: **60**: Git repository GC timeout seconds.
## Metrics (`metrics`)
- `ENABLED`: **false**: Enables /metrics endpoint for prometheus.
- `TOKEN`: **\<empty\>**: You need to specify the token, if you want to include in the authorization the metrics . The same token need to be used in prometheus parameters `bearer_token` or `bearer_token_file`.
## API (`api`) ## API (`api`)
- `ENABLE_SWAGGER_ENDPOINT`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true. - `ENABLE_SWAGGER_ENDPOINT`: **true**: Enables /api/swagger, /api/v1/swagger etc. endpoints. True or false; default is true.
@@ -370,10 +358,6 @@ IS_INPUT_FILE = false
- RENDER\_COMMAND: External command to render all matching extensions. - RENDER\_COMMAND: External command to render all matching extensions.
- IS\_INPUT\_FILE: **false** Input is not a standard input but a file param followed `RENDER_COMMAND`. - IS\_INPUT\_FILE: **false** Input is not a standard input but a file param followed `RENDER_COMMAND`.
Two special environment variables are passed to the render command:
- `GITEA_PREFIX_SRC`, which contains the current URL prefix in the `src` path tree. To be used as prefix for links.
- `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths.
## Other (`other`) ## Other (`other`)
- `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer. - `SHOW_FOOTER_BRANDING`: **false**: Show Gitea branding in the footer.

View File

@@ -88,14 +88,10 @@ Apart from `extra_links.tmpl` and `extra_tabs.tmpl`, there are other useful temp
- `body_outer_post.tmpl`, before the bottom `<footer>` element. - `body_outer_post.tmpl`, before the bottom `<footer>` element.
- `footer.tmpl`, right before the end of the `<body>` tag, a good place for additional Javascript. - `footer.tmpl`, right before the end of the `<body>` tag, a good place for additional Javascript.
## Adding Analytics to Gitea
Google Analytics, Matomo (previously Piwik), and other analytics services can be added to Gitea. To add the tracking code, refer to the `Other additions to the page` section of this document, and add the JavaScript to the `custom/templates/custom/header.tmpl` file.
## Customizing gitignores, labels, licenses, locales, and readmes. ## Customizing gitignores, labels, licenses, locales, and readmes.
Place custom files in corresponding sub-folder under `custom/options`. Place custom files in corresponding sub-folder under `custom/options`.
## Customizing the look of Gitea ## Customizing the look of Gitea
As of version 1.6.0 Gitea has built-in themes. The two built-in themes are, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options. Gitea has two built-in themes, the default theme `gitea`, and a dark theme `arc-green`. To change the look of your Gitea install change the value of `DEFAULT_THEME` in the [ui](https://docs.gitea.io/en-us/config-cheat-sheet/#ui-ui) section of `app.ini` to another one of the available options.

View File

@@ -57,7 +57,7 @@ Gitea 引用 `custom` 目录中的自定义配置文件来覆盖配置、模板
如果您只是想添加额外的链接到顶部导航栏或额外的选项卡到存储库视图,您可以将它们放在您 `custom/templates/custom/` 目录下的 `extra_links.tmpl``extra_tabs.tmpl` 文件中。 如果您只是想添加额外的链接到顶部导航栏或额外的选项卡到存储库视图,您可以将它们放在您 `custom/templates/custom/` 目录下的 `extra_links.tmpl``extra_tabs.tmpl` 文件中。
举例说明:假设您需要在网站放置一个静态的“关于”页面,您只需将该页面放在您的 举例说明:假设您在德国必须添加着名的法律要求的“Impressum”用以罗列谁负责网站的内容页面,您只需将该页面放在您的
"custom/public/"目录下(比如 `custom/public/impressum.html`)并且将它与 `custom/templates/custom/extra_links.tmpl` 链接起来即可。 "custom/public/"目录下(比如 `custom/public/impressum.html`)并且将它与 `custom/templates/custom/extra_links.tmpl` 链接起来即可。
这个链接应当使用一个名为“item”的 class 来匹配当前样式,您可以使用 `{{AppSubUrl}}` 来获取 base URL: 这个链接应当使用一个名为“item”的 class 来匹配当前样式,您可以使用 `{{AppSubUrl}}` 来获取 base URL:

View File

@@ -1,70 +0,0 @@
---
date: "2018-11-23:00:00+02:00"
title: "External renderers"
slug: "external-renderers"
weight: 40
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "External renderers"
weight: 40
identifier: "external-renderers"
---
# Custom files rendering configuration
Gitea supports custom file renderings (i.e., Jupyter notebooks, asciidoc, etc.) through external binaries,
it is just matter of:
* installing external binaries
* add some configuration to your `app.ini` file
* restart your gitea instance
## Installing external binaries
In order to get file rendering through external binaries, their associated packages must be installed.
If you're using a Docker image, your `Dockerfile` should contain something along this lines:
```
FROM gitea/gitea:1.6.0
[...]
COPY custom/app.ini /data/gitea/conf/app.ini
[...]
RUN apk --no-cache add asciidoctor freetype freetype-dev gcc g++ libpng python-dev py-pip python3-dev py3-pip
# install any other package you need for your external renderers
RUN pip3 install --upgrade pip
RUN pip3 install -U setuptools
RUN pip3 install jupyter matplotlib docutils
# add above any other python package you may need to install
```
## `app.ini` file configuration
add one `[markup.XXXXX]` section per external renderer on your custom `app.ini`:
```
[markup.asciidoc]
ENABLED = true
FILE_EXTENSIONS = .adoc,.asciidoc
RENDER_COMMAND = "asciidoctor --out-file=- -"
; Input is not a standard input but a file
IS_INPUT_FILE = false
[markup.jupyter]
ENABLED = true
FILE_EXTENSIONS = .ipynb
RENDER_COMMAND = "jupyter nbconvert --stdout --to html --template basic "
IS_INPUT_FILE = true
[markup.restructuredtext]
ENABLED = true
FILE_EXTENSIONS = .rst
RENDER_COMMAND = rst2html.py
IS_INPUT_FILE = false
```
Once your configuration changes have been made, restart Gitea to have changes take effect.

View File

@@ -119,5 +119,5 @@ _Symbols used in table:_
| Act as OAuth 2.0 provider | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | | Act as OAuth 2.0 provider | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| Two factor authentication (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | | Two factor authentication (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ |
| Mattermost/Slack integration | ✓ | ✓ | | ✓ | ✓ | | ✓ | | Mattermost/Slack integration | ✓ | ✓ | | ✓ | ✓ | | ✓ |
| Discord integration | ✓ | ✓ | ✓ | | | ✘ | ✘ | | Discord integration | ✓ | ✓ | ✓ | | | ✘ | ✘ |
| External CI/CD status display | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | | External CI/CD status display | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |

View File

@@ -80,17 +80,3 @@ To migrate an repository *with* all tags you need to do two things
``` ```
gitea admin repo-sync-releases gitea admin repo-sync-releases
``` ```
## LFS Issues
For issues concerning LFS data upload
```
batch response: Authentication required: Authorization error: <GITEA_LFS_URL>/info/lfs/objects/batch
Check that you have proper access to the repository
error: failed to push some refs to '<GIT_REPO_URL>'
```
Have you checked the value of `LFS_HTTP_AUTH_EXPIRY` in your `app.ini` file? By default your LFS token will expire after 20 minutes. If you have a slow connection or a large file (or both) it may not finish uploading within the time limit.
You may want to set this value to `60m` or `120m`.

View File

@@ -29,7 +29,7 @@ chmod +x gitea
Gitea signs all binaries with a [GPG key](https://pgp.mit.edu/pks/lookup?op=vindex&fingerprint=on&search=0x2D9AE806EC1592E2) to prevent against unwanted modification of binaries. To validate the binary download the signature file which ends in `.asc` for the binary you downloaded and use the gpg command line tool. Gitea signs all binaries with a [GPG key](https://pgp.mit.edu/pks/lookup?op=vindex&fingerprint=on&search=0x2D9AE806EC1592E2) to prevent against unwanted modification of binaries. To validate the binary download the signature file which ends in `.asc` for the binary you downloaded and use the gpg command line tool.
```sh ```sh
gpg --keyserver pgp.mit.edu --recv 7C9E68152594688862D62AF62D9AE806EC1592E2 gpg --keyserver pgp.mit.edu --recv 0x2D9AE806EC1592E2
gpg --verify gitea-1.5.0-linux-amd64.asc gitea-1.5.0-linux-amd64 gpg --verify gitea-1.5.0-linux-amd64.asc gitea-1.5.0-linux-amd64
``` ```

View File

@@ -66,7 +66,7 @@ provided to keep the build process as simple as possible.
Depending on requirements, the following build tags can be included. Depending on requirements, the following build tags can be included.
* `bindata`: Build a single monolithic binary, with all assets included. * `bindata`: Build a single monolithic binary, with all assets included.
* `sqlite sqlite_unlock_notify`: Enable support for a [SQLite3](https://sqlite.org/) database. Suggested only * `sqlite`: Enable support for a [SQLite3](https://sqlite.org/) database. Suggested only
for tiny installations. for tiny installations.
* `tidb`: Enable support for a [TiDB](https://github.com/pingcap/tidb) database. * `tidb`: Enable support for a [TiDB](https://github.com/pingcap/tidb) database.
* `pam`: Enable support for PAM (Linux Pluggable Authentication Modules). Can be used to * `pam`: Enable support for PAM (Linux Pluggable Authentication Modules). Can be used to

View File

@@ -57,7 +57,7 @@ git checkout pr-xyz
Comme nous regroupons déjà toutes les bibliothèques requises pour compiler Gitea, vous pouvez continuer avec le processus de compilation lui-même. Nous fournissons diverses [tâches Make](https://github.com/go-gitea/gitea/blob/master/Makefile) pour rendre le processus de construction aussi simple que possible. <a href='{{< relref "doc/advanced/make.fr-fr.md" >}}'>Voyez ici comment obtenir Make</a>. Selon vos besoins, vous pourrez éventuellement ajouter diverses options de compilation, vous pouvez choisir entre ces options : Comme nous regroupons déjà toutes les bibliothèques requises pour compiler Gitea, vous pouvez continuer avec le processus de compilation lui-même. Nous fournissons diverses [tâches Make](https://github.com/go-gitea/gitea/blob/master/Makefile) pour rendre le processus de construction aussi simple que possible. <a href='{{< relref "doc/advanced/make.fr-fr.md" >}}'>Voyez ici comment obtenir Make</a>. Selon vos besoins, vous pourrez éventuellement ajouter diverses options de compilation, vous pouvez choisir entre ces options :
* `bindata`: Intègre toutes les ressources nécessaires à l'exécution d'une instance de Gitea, ce qui rend un déploiement facile car il n'est pas nécessaire de se préoccuper des fichiers supplémentaires. * `bindata`: Intègre toutes les ressources nécessaires à l'exécution d'une instance de Gitea, ce qui rend un déploiement facile car il n'est pas nécessaire de se préoccuper des fichiers supplémentaires.
* `sqlite sqlite_unlock_notify`: Active la prise en charge d'une base de données [SQLite3](https://sqlite.org/), ceci n'est recommandé que pour les petites installations de Gitea. * `sqlite`: Active la prise en charge d'une base de données [SQLite3](https://sqlite.org/), ceci n'est recommandé que pour les petites installations de Gitea.
* `tidb`: Active la prise en charge d'une base de données [TiDB](https://github.com/pingcap/tidb), c'est une base de données simplet et basée sur des fichiers. Elle est comparable à SQLite. * `tidb`: Active la prise en charge d'une base de données [TiDB](https://github.com/pingcap/tidb), c'est une base de données simplet et basée sur des fichiers. Elle est comparable à SQLite.
* `pam`: Active la prise en charge de PAM (mLinux Pluggable Authentication Modules), très utile si vos utilisateurs doivent être authentifiés avec les comptes du système. * `pam`: Active la prise en charge de PAM (mLinux Pluggable Authentication Modules), très utile si vos utilisateurs doivent être authentifiés avec les comptes du système.

View File

@@ -47,7 +47,7 @@ git checkout v1.0.0
我们已经将所有的依赖项拷贝到本工程,我们提供了一些 [编译选项](https://github.com/go-gitea/gitea/blob/master/Makefile) 来让编译更简单。你可以按照你的需求来设置编译开关,可用编译选项如下: 我们已经将所有的依赖项拷贝到本工程,我们提供了一些 [编译选项](https://github.com/go-gitea/gitea/blob/master/Makefile) 来让编译更简单。你可以按照你的需求来设置编译开关,可用编译选项如下:
* `bindata`: 这个编译选项将会把运行Gitea所需的所有外部资源都打包到可执行文件中这样部署将非常简单因为除了可执行程序将不再需要任何其他文件。 * `bindata`: 这个编译选项将会把运行Gitea所需的所有外部资源都打包到可执行文件中这样部署将非常简单因为除了可执行程序将不再需要任何其他文件。
* `sqlite sqlite_unlock_notify`: 这个编译选项将启用SQLite3数据库的支持建议只在少数人使用时使用这个模式。 * `sqlite`: 这个编译选项将启用SQLite3数据库的支持建议只在少数人使用时使用这个模式。
* `tidb`: 这个编译选项启用tidb嵌入式数据库的支持他跟SQLite类似但是是用纯Go编写的。 * `tidb`: 这个编译选项启用tidb嵌入式数据库的支持他跟SQLite类似但是是用纯Go编写的。
* `pam`: 这个编译选项将会启用 PAM (Linux Pluggable Authentication Modules) 认证,如果你使用这一认证模式的话需要开启这个选项。 * `pam`: 这个编译选项将会启用 PAM (Linux Pluggable Authentication Modules) 认证,如果你使用这一认证模式的话需要开启这个选项。

View File

@@ -47,7 +47,7 @@ git checkout v1.0.0
完成設定相依性套件環境等工作後,您就可以開始編譯工作了。我們提供了不同的[編譯選項](https://github.com/go-gitea/gitea/blob/master/Makefile) ,讓編譯過程更加簡單。您可以根據需求來調整編譯選項,底下是可用的編譯選項說明: 完成設定相依性套件環境等工作後,您就可以開始編譯工作了。我們提供了不同的[編譯選項](https://github.com/go-gitea/gitea/blob/master/Makefile) ,讓編譯過程更加簡單。您可以根據需求來調整編譯選項,底下是可用的編譯選項說明:
* `bindata`: 使用此標籤來嵌入所有 Gitea 相關資源,您不用擔心其他額外檔案,對於部署來說非常方便。 * `bindata`: 使用此標籤來嵌入所有 Gitea 相關資源,您不用擔心其他額外檔案,對於部署來說非常方便。
* `sqlite sqlite_unlock_notify`: 使用此標籤來啟用 [SQLite3](https://sqlite.org/) 資料庫,建議只有少數人時才使用此模式。 * `sqlite`: 使用此標籤來啟用 [SQLite3](https://sqlite.org/) 資料庫,建議只有少數人時才使用此模式。
* `tidb`: 使用此標籤來啟用 [TiDB](https://github.com/pingcap/tidb) 資料庫,它是檔案形式的資料庫,跟 SQLite 類似。 * `tidb`: 使用此標籤來啟用 [TiDB](https://github.com/pingcap/tidb) 資料庫,它是檔案形式的資料庫,跟 SQLite 類似。
* `pam`: 使用此標籤來啟用 PAM (Linux Pluggable Authentication Modules) 認證,對於系統使用者來說,此方式最方便了。 * `pam`: 使用此標籤來啟用 PAM (Linux Pluggable Authentication Modules) 認證,對於系統使用者來說,此方式最方便了。

View File

@@ -1,63 +0,0 @@
---
date: "2017-07-21T12:00:00+02:00"
title: "在 Linux 中以 service 方式运行"
slug: "linux-service"
weight: 10
toc: true
draft: false
menu:
sidebar:
parent: "installation"
name: "在Linux中以service方式运行"
weight: 20
identifier: "linux-service"
---
### 在 Ubuntu 16.04 LTS 中以 service 方式运行
#### systemd 方式
在 terminal 中执行以下命令:
```
sudo vim /etc/systemd/system/gitea.service
```
接着拷贝示例代码 [gitea.service](https://github.com/go-gitea/gitea/blob/master/contrib/systemd/gitea.service) 并取消对任何需要运行在主机上的服务部分的注释,譬如 MySQL。
修改 userhome 目录以及其他必须的初始化参数,如果使用自定义端口,则需修改 PORT 参数,反之如果使用默认端口则需删除 -p 标记。
激活 gitea 并将它作为系统自启动服务:
```
sudo systemctl enable gitea
sudo systemctl start gitea
```
#### 使用 supervisor
在 terminal 中执行以下命令安装 supervisor
```
sudo apt install supervisor
```
为 supervisor 配置日志路径:
```
# assuming gitea is installed in /home/git/gitea/
mkdir /home/git/gitea/log/supervisor
```
在文件编辑器中打开 supervisor 的配置文件:
```
sudo vim /etc/supervisor/supervisord.conf
```
增加如下示例配置
[supervisord config](https://github.com/go-gitea/gitea/blob/master/contrib/supervisor/gitea)。
将 user(git) 和 home(/home/git) 设置为与上文部署中匹配的值。如果使用自定义端口,则需修改 PORT 参数,反之如果使用默认端口则需删除 -p 标记。
最后激活 supervisor 并将它作为系统自启动服务:
```
sudo systemctl enable supervisor
sudo systemctl start supervisor
```

View File

@@ -19,8 +19,8 @@ Gitea provides automatically updated Docker images within its Docker Hub organiz
possible to always use the latest stable tag or to use another service that handles updating possible to always use the latest stable tag or to use another service that handles updating
Docker images. Docker images.
This reference setup guides users through the setup based on `docker-compose`, but the installation This reference setup guides users through the setup based on `docker-compose`, the installation
of `docker-compose` is out of scope of this documentation. To install `docker-compose` itself follow of `docker-compose` is out of scope of this documentation. To install `docker-compose` follow
the official [install instructions](https://docs.docker.com/compose/install/). the official [install instructions](https://docs.docker.com/compose/install/).
## Basics ## Basics
@@ -267,16 +267,3 @@ be placed in `/data/gitea` directory. If using host volumes it's quite easy to a
files; for named volumes this is done through another container or by direct access at files; for named volumes this is done through another container or by direct access at
`/var/lib/docker/volumes/gitea_gitea/_data`. The configuration file will be saved at `/var/lib/docker/volumes/gitea_gitea/_data`. The configuration file will be saved at
`/data/gitea/conf/app.ini` after the installation. `/data/gitea/conf/app.ini` after the installation.
# Upgrading
:exclamation::exclamation: **Make sure you have volumed data to somewhere outside Docker container** :exclamation::exclamation:**
To upgrade your installation to the latest release:
```
# Edit `docker-compose.yml` to update the version, if you have one specified
# Pull new images
docker-compose pull
# Start a new container, automatically removes old one
docker-compose up -d
```

View File

@@ -163,24 +163,3 @@ for automatic deployments.
- `gitea generate secret INTERNAL_TOKEN` - `gitea generate secret INTERNAL_TOKEN`
- `gitea generate secret LFS_JWT_SECRET` - `gitea generate secret LFS_JWT_SECRET`
- `gitea generate secret SECRET_KEY` - `gitea generate secret SECRET_KEY`
#### keys
Provides an SSHD AuthorizedKeysCommand. Needs to be configured in the sshd config file:
```ini
...
# The value of -e and the AuthorizedKeysCommandUser should match the
# username running gitea
AuthorizedKeysCommandUser git
AuthorizedKeysCommand /path/to/gitea keys -e git -u %u -t %t -k %k
```
The command will return the appropriate authorized_keys line for the
provided key. You should also set the value
`SSH_CREATE_AUTHORIZED_KEYS_FILE=false` in the `[server]` section of
`app.ini`.
NB: opensshd requires the gitea program to be owned by root and not
writable by group or others. The program must be specified by an absolute
path.

View File

@@ -30,22 +30,8 @@ HTTP_PORT = 3000
CERT_FILE = cert.pem CERT_FILE = cert.pem
KEY_FILE = key.pem KEY_FILE = key.pem
``` ```
To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server). To learn more about the config values, please checkout the [Config Cheat Sheet](../config-cheat-sheet#server).
### Setting-up HTTP redirection
The Gitea server is only able to listen to one port; to redirect HTTP requests to the HTTPS port, you will need to enable the HTTP redirection service:
```ini
[server]
REDIRECT_OTHER_PORT = true
; Port the redirection service should listen on
PORT_TO_REDIRECT = 3080
```
If you are using Docker, make sure that this port is configured in your `docker-compose.yml` file.
## Using Let's Encrypt ## Using Let's Encrypt
[Let's Encrypt](https://letsencrypt.org/) is a Certificate Authority that allows you to automatically request and renew SSL/TLS certificates. In addition to starting Gitea on your configured port, to request HTTPS certificates Gitea will also need to listed on port 80, and will set up an autoredirect to HTTPS for you. Let's Encrypt will need to be able to access Gitea via the Internet to verify your ownership of the domain. [Let's Encrypt](https://letsencrypt.org/) is a Certificate Authority that allows you to automatically request and renew SSL/TLS certificates. In addition to starting Gitea on your configured port, to request HTTPS certificates Gitea will also need to listed on port 80, and will set up an autoredirect to HTTPS for you. Let's Encrypt will need to be able to access Gitea via the Internet to verify your ownership of the domain.

View File

@@ -7,11 +7,8 @@ package integrations
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"testing" "testing"
"github.com/stretchr/testify/assert"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
api "code.gitea.io/sdk/gitea" api "code.gitea.io/sdk/gitea"
) )
@@ -93,102 +90,3 @@ func TestCreateReadWriteDeployKey(t *testing.T) {
Mode: models.AccessModeWrite, Mode: models.AccessModeWrite,
}) })
} }
func TestCreateUserKey(t *testing.T) {
prepareTestEnv(t)
user := models.AssertExistsAndLoadBean(t, &models.User{Name: "user1"}).(*models.User)
session := loginUser(t, "user1")
token := url.QueryEscape(getTokenForLoggedInUser(t, session))
keysURL := fmt.Sprintf("/api/v1/user/keys?token=%s", token)
keyType := "ssh-rsa"
keyContent := "AAAAB3NzaC1yc2EAAAADAQABAAABAQCyTiPTeHJl6Gs5D1FyHT0qTWpVkAy9+LIKjctQXklrePTvUNVrSpt4r2exFYXNMPeA8V0zCrc3Kzs1SZw3jWkG3i53te9onCp85DqyatxOD2pyZ30/gPn1ZUg40WowlFM8gsUFMZqaH7ax6d8nsBKW7N/cRyqesiOQEV9up3tnKjIB8XMTVvC5X4rBWgywz7AFxSv8mmaTHnUgVW4LgMPwnTWo0pxtiIWbeMLyrEE4hIM74gSwp6CRQYo6xnG3fn4yWkcK2X2mT9adQ241IDdwpENJHcry/T6AJ8dNXduEZ67egnk+rVlQ2HM4LpymAv9DAAFFeaQK0hT+3aMDoumV"
rawKeyBody := api.CreateKeyOption{
Title: "test-key",
Key: keyType + " " + keyContent,
}
req := NewRequestWithJSON(t, "POST", keysURL, rawKeyBody)
resp := session.MakeRequest(t, req, http.StatusCreated)
var newPublicKey api.PublicKey
DecodeJSON(t, resp, &newPublicKey)
models.AssertExistsAndLoadBean(t, &models.PublicKey{
ID: newPublicKey.ID,
OwnerID: user.ID,
Name: rawKeyBody.Title,
Content: rawKeyBody.Key,
Mode: models.AccessModeWrite,
})
// Search by fingerprint
fingerprintURL := fmt.Sprintf("/api/v1/user/keys?token=%s&fingerprint=%s", token, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
var fingerprintPublicKeys []api.PublicKey
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
assert.Equal(t, user.ID, fingerprintPublicKeys[0].Owner.ID)
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", user.Name, token, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
assert.Equal(t, user.ID, fingerprintPublicKeys[0].Owner.ID)
// Fail search by fingerprint
fingerprintURL = fmt.Sprintf("/api/v1/user/keys?token=%s&fingerprint=%sA", token, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Len(t, fingerprintPublicKeys, 0)
// Fail searching for wrong users key
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", "user2", token, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Len(t, fingerprintPublicKeys, 0)
// Now login as user 2
session2 := loginUser(t, "user2")
token2 := url.QueryEscape(getTokenForLoggedInUser(t, session2))
// Should find key even though not ours, but we shouldn't know whose it is
fingerprintURL = fmt.Sprintf("/api/v1/user/keys?token=%s&fingerprint=%s", token2, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
assert.Nil(t, fingerprintPublicKeys[0].Owner)
// Should find key even though not ours, but we shouldn't know whose it is
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", user.Name, token2, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Equal(t, newPublicKey.Fingerprint, fingerprintPublicKeys[0].Fingerprint)
assert.Equal(t, newPublicKey.ID, fingerprintPublicKeys[0].ID)
assert.Nil(t, fingerprintPublicKeys[0].Owner)
// Fail when searching for key if it is not ours
fingerprintURL = fmt.Sprintf("/api/v1/users/%s/keys?token=%s&fingerprint=%s", "user2", token2, newPublicKey.Fingerprint)
req = NewRequest(t, "GET", fingerprintURL)
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &fingerprintPublicKeys)
assert.Len(t, fingerprintPublicKeys, 0)
}

View File

@@ -1,48 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"net/http"
"strings"
"testing"
"code.gitea.io/gitea/models"
api "code.gitea.io/sdk/gitea"
"github.com/stretchr/testify/assert"
)
func TestAPIOrg(t *testing.T) {
prepareTestEnv(t)
session := loginUser(t, "user1")
token := getTokenForLoggedInUser(t, session)
var org = api.CreateOrgOption{
UserName: "user1_org",
FullName: "User1's organization",
Description: "This organization created by user1",
Website: "https://try.gitea.io",
Location: "Shanghai",
}
req := NewRequestWithJSON(t, "POST", "/api/v1/orgs?token="+token, &org)
resp := session.MakeRequest(t, req, http.StatusCreated)
var apiOrg api.Organization
DecodeJSON(t, resp, &apiOrg)
assert.Equal(t, org.UserName, apiOrg.UserName)
assert.Equal(t, org.FullName, apiOrg.FullName)
assert.Equal(t, org.Description, apiOrg.Description)
assert.Equal(t, org.Website, apiOrg.Website)
assert.Equal(t, org.Location, apiOrg.Location)
models.AssertExistsAndLoadBean(t, &models.User{
Name: org.UserName,
LowerName: strings.ToLower(org.UserName),
FullName: org.FullName,
})
}

View File

@@ -1,34 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"net/http"
"testing"
"code.gitea.io/gitea/models"
)
func TestAPIReposGitRefs(t *testing.T) {
prepareTestEnv(t)
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
// Login as User2.
session := loginUser(t, user.Name)
token := getTokenForLoggedInUser(t, session)
for _, ref := range [...]string{
"refs/heads/master", // Branch
"refs/tags/v1.1", // Tag
} {
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/%s?token="+token, user.Name, ref)
session.MakeRequest(t, req, http.StatusOK)
}
// Test getting all refs
req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs?token="+token, user.Name)
session.MakeRequest(t, req, http.StatusOK)
// Test getting non-existent refs
req = NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/git/refs/heads/unknown?token="+token, user.Name)
session.MakeRequest(t, req, http.StatusNotFound)
}

View File

@@ -164,7 +164,7 @@ func TestAPISearchRepo(t *testing.T) {
assert.Len(t, body.Data, expected.count) assert.Len(t, body.Data, expected.count)
for _, repo := range body.Data { for _, repo := range body.Data {
r := getRepo(t, repo.ID) r := getRepo(t, repo.ID)
hasAccess, err := models.HasAccess(userID, r) hasAccess, err := models.HasAccess(userID, r, models.AccessModeRead)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, hasAccess) assert.True(t, hasAccess)

View File

@@ -1,30 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.package models
package integrations
import (
"code.gitea.io/gitea/models"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"testing"
)
func TestUserHeatmap(t *testing.T) {
prepareTestEnv(t)
adminUsername := "user1"
normalUsername := "user2"
session := loginUser(t, adminUsername)
urlStr := fmt.Sprintf("/api/v1/users/%s/heatmap", normalUsername)
req := NewRequest(t, "GET", urlStr)
resp := session.MakeRequest(t, req, http.StatusOK)
var heatmap []*models.UserHeatmapData
DecodeJSON(t, resp, &heatmap)
var dummyheatmap []*models.UserHeatmapData
dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1540080000, Contributions: 1})
assert.Equal(t, dummyheatmap, heatmap)
}

View File

@@ -1,63 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.package models
package integrations
import (
"fmt"
"net/http"
"testing"
api "code.gitea.io/sdk/gitea"
"github.com/stretchr/testify/assert"
)
func TestUserOrgs(t *testing.T) {
prepareTestEnv(t)
adminUsername := "user1"
normalUsername := "user2"
session := loginUser(t, adminUsername)
token := getTokenForLoggedInUser(t, session)
urlStr := fmt.Sprintf("/api/v1/users/%s/orgs?token=%s", normalUsername, token)
req := NewRequest(t, "GET", urlStr)
resp := session.MakeRequest(t, req, http.StatusOK)
var orgs []*api.Organization
DecodeJSON(t, resp, &orgs)
assert.Equal(t, []*api.Organization{
{
ID: 3,
UserName: "user3",
FullName: "User Three",
AvatarURL: "https://secure.gravatar.com/avatar/97d6d9441ff85fdc730e02a6068d267b?d=identicon",
Description: "",
Website: "",
Location: "",
},
}, orgs)
}
func TestMyOrgs(t *testing.T) {
prepareTestEnv(t)
normalUsername := "user2"
session := loginUser(t, normalUsername)
token := getTokenForLoggedInUser(t, session)
req := NewRequest(t, "GET", "/api/v1/user/orgs?token="+token)
resp := session.MakeRequest(t, req, http.StatusOK)
var orgs []*api.Organization
DecodeJSON(t, resp, &orgs)
assert.Equal(t, []*api.Organization{
{
ID: 3,
UserName: "user3",
FullName: "User Three",
AvatarURL: "https://secure.gravatar.com/avatar/97d6d9441ff85fdc730e02a6068d267b?d=identicon",
Description: "",
Website: "",
Location: "",
},
}, orgs)
}

View File

@@ -43,7 +43,6 @@ var gitLDAPUsers = []ldapUser{
SSHKeys: []string{ SSHKeys: []string{
"SHA256:qLY06smKfHoW/92yXySpnxFR10QFrLdRjf/GNPvwcW8", "SHA256:qLY06smKfHoW/92yXySpnxFR10QFrLdRjf/GNPvwcW8",
"SHA256:QlVTuM5OssDatqidn2ffY+Lc4YA5Fs78U+0KOHI51jQ", "SHA256:QlVTuM5OssDatqidn2ffY+Lc4YA5Fs78U+0KOHI51jQ",
"SHA256:DXdeUKYOJCSSmClZuwrb60hUq7367j4fA+udNC3FdRI",
}, },
IsAdmin: true, IsAdmin: true,
}, },

View File

@@ -102,7 +102,7 @@ func BenchmarkRepoBranchCommit(b *testing.B) {
branchCount := len(branches) branchCount := len(branches)
b.ResetTimer() //We measure from here b.ResetTimer() //We measure from here
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
req := NewRequestf(b, "GET", "/%s/%s/commits/%s", owner.Name, repo.Name, branches[i%branchCount].Name) req := NewRequestf(b, "GET", "/%s/%s/commits/%s", owner.Name, repo.Name, branches[i%branchCount])
session.MakeRequest(b, req, http.StatusOK) session.MakeRequest(b, req, http.StatusOK)
} }
}) })

View File

@@ -1,24 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package integrations
import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDownloadByID(t *testing.T) {
prepareTestEnv(t)
session := loginUser(t, "user2")
// Request raw blob
req := NewRequest(t, "GET", "/user2/repo1/raw/blob/4b4851ad51df6a7d9f25c979345979eaeb5b349f")
resp := session.MakeRequest(t, req, http.StatusOK)
assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String())
}

View File

@@ -47,8 +47,6 @@ func TestMain(m *testing.M) {
helper = &testfixtures.PostgreSQL{} helper = &testfixtures.PostgreSQL{}
} else if setting.UseSQLite3 { } else if setting.UseSQLite3 {
helper = &testfixtures.SQLite{} helper = &testfixtures.SQLite{}
} else if setting.UseMSSQL {
helper = &testfixtures.SQLServer{}
} else { } else {
fmt.Println("Unsupported RDBMS for integration tests") fmt.Println("Unsupported RDBMS for integration tests")
os.Exit(1) os.Exit(1)
@@ -99,7 +97,6 @@ func initIntegrationTest() {
} }
setting.NewContext() setting.NewContext()
setting.CheckLFSVersion()
models.LoadConfigs() models.LoadConfigs()
switch { switch {
@@ -133,17 +130,6 @@ func initIntegrationTest() {
if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil { if _, err = db.Exec("CREATE DATABASE testgitea"); err != nil {
log.Fatalf("db.Exec: %v", err) log.Fatalf("db.Exec: %v", err)
} }
case setting.UseMSSQL:
host, port := models.ParseMSSQLHostPort(models.DbCfg.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", models.DbCfg.User, models.DbCfg.Passwd))
if err != nil {
log.Fatalf("sql.Open: %v", err)
}
if _, err := db.Exec("If(db_id(N'gitea') IS NULL) BEGIN CREATE DATABASE gitea; END;"); err != nil {
log.Fatalf("db.Exec: %v", err)
}
defer db.Close()
} }
routers.GlobalInit() routers.GlobalInit()
} }

View File

@@ -1,72 +0,0 @@
APP_NAME = Gitea: Git with a cup of tea
RUN_MODE = prod
[database]
DB_TYPE = mssql
HOST = {{TEST_MSSQL_HOST}}
NAME = {{TEST_MSSQL_DBNAME}}
USER = {{TEST_MSSQL_USERNAME}}
PASSWD = {{TEST_MSSQL_PASSWORD}}
SSL_MODE = disable
[indexer]
ISSUE_INDEXER_PATH = integrations/indexers-mssql/issues.bleve
REPO_INDEXER_ENABLED = true
REPO_INDEXER_PATH = integrations/indexers-mssql/repos.bleve
[repository]
ROOT = integrations/gitea-integration-mssql/gitea-repositories
[repository.local]
LOCAL_COPY_PATH = tmp/local-repo-mssql
LOCAL_WIKI_PATH = tmp/local-wiki-mssql
[server]
SSH_DOMAIN = localhost
HTTP_PORT = 3003
ROOT_URL = http://localhost:3003/
DISABLE_SSH = false
SSH_LISTEN_HOST = localhost
SSH_PORT = 2201
START_SSH_SERVER = true
LFS_START_SERVER = true
LFS_CONTENT_PATH = data/lfs-mssql
OFFLINE_MODE = false
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
APP_DATA_PATH = integrations/gitea-integration-mssql/data
[mailer]
ENABLED = false
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = false
ENABLE_CAPTCHA = false
REQUIRE_SIGNIN_VIEW = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
NO_REPLY_ADDRESS = noreply.example.org
[picture]
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = false
[session]
PROVIDER = file
PROVIDER_CONFIG = data/sessions-mssql
[log]
MODE = console,file
ROOT_PATH = mssql-log
[log.console]
LEVEL = Warn
[log.file]
LEVEL = Debug
[security]
INSTALL_LOCK = true
SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ

View File

@@ -77,19 +77,6 @@ func TestPullRebase(t *testing.T) {
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase) testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
} }
func TestPullRebaseMerge(t *testing.T) {
prepareTestEnv(t)
session := loginUser(t, "user1")
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
resp := testPullCreate(t, session, "user1", "repo1", "master", "This is a pull title")
elem := strings.Split(test.RedirectURL(resp), "/")
assert.EqualValues(t, "pulls", elem[3])
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
}
func TestPullSquash(t *testing.T) { func TestPullSquash(t *testing.T) {
prepareTestEnv(t) prepareTestEnv(t)
session := loginUser(t, "user1") session := loginUser(t, "user1")

View File

@@ -13,7 +13,6 @@ import (
"code.gitea.io/gitea/cmd" "code.gitea.io/gitea/cmd"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
// register supported doc types // register supported doc types
_ "code.gitea.io/gitea/modules/markup/csv" _ "code.gitea.io/gitea/modules/markup/csv"
_ "code.gitea.io/gitea/modules/markup/markdown" _ "code.gitea.io/gitea/modules/markup/markdown"
@@ -48,8 +47,6 @@ arguments - which can alternatively be run by running the subcommand web.`
cmd.CmdCert, cmd.CmdCert,
cmd.CmdAdmin, cmd.CmdAdmin,
cmd.CmdGenerate, cmd.CmdGenerate,
cmd.CmdMigrate,
cmd.CmdKeys,
} }
app.Flags = append(app.Flags, cmd.CmdWeb.Flags...) app.Flags = append(app.Flags, cmd.CmdWeb.Flags...)
app.Action = cmd.CmdWeb.Action app.Action = cmd.CmdWeb.Action

View File

@@ -80,6 +80,22 @@ func accessLevel(e Engine, userID int64, repo *Repository) (AccessMode, error) {
return a.Mode, nil return a.Mode, nil
} }
// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
// user does not have access.
func AccessLevel(userID int64, repo *Repository) (AccessMode, error) {
return accessLevel(x, userID, repo)
}
func hasAccess(e Engine, userID int64, repo *Repository, testMode AccessMode) (bool, error) {
mode, err := accessLevel(e, userID, repo)
return testMode <= mode, err
}
// HasAccess returns true if user has access to repo
func HasAccess(userID int64, repo *Repository, testMode AccessMode) (bool, error) {
return hasAccess(x, userID, repo, testMode)
}
type repoAccess struct { type repoAccess struct {
Access `xorm:"extends"` Access `xorm:"extends"`
Repository `xorm:"extends"` Repository `xorm:"extends"`

View File

@@ -20,28 +20,28 @@ var accessModes = []AccessMode{
func TestAccessLevel(t *testing.T) { func TestAccessLevel(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
user2 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) user1 := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
user5 := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User) user2 := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
// A public repository owned by User 2 // A public repository owned by User 2
repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repo1 := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
assert.False(t, repo1.IsPrivate) assert.False(t, repo1.IsPrivate)
// A private repository owned by Org 3 // A private repository owned by Org 3
repo3 := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
assert.True(t, repo3.IsPrivate) assert.True(t, repo2.IsPrivate)
level, err := AccessLevel(user2, repo1) level, err := AccessLevel(user1.ID, repo1)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, AccessModeOwner, level) assert.Equal(t, AccessModeOwner, level)
level, err = AccessLevel(user2, repo3) level, err = AccessLevel(user1.ID, repo2)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, AccessModeOwner, level) assert.Equal(t, AccessModeWrite, level)
level, err = AccessLevel(user5, repo1) level, err = AccessLevel(user2.ID, repo1)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, AccessModeRead, level) assert.Equal(t, AccessModeRead, level)
level, err = AccessLevel(user5, repo3) level, err = AccessLevel(user2.ID, repo2)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, AccessModeNone, level) assert.Equal(t, AccessModeNone, level)
} }
@@ -58,18 +58,23 @@ func TestHasAccess(t *testing.T) {
repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) repo2 := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
assert.True(t, repo2.IsPrivate) assert.True(t, repo2.IsPrivate)
has, err := HasAccess(user1.ID, repo1) for _, accessMode := range accessModes {
has, err := HasAccess(user1.ID, repo1, accessMode)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, has) assert.True(t, has)
has, err = HasAccess(user1.ID, repo2) has, err = HasAccess(user1.ID, repo2, accessMode)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, accessMode <= AccessModeWrite, has)
has, err = HasAccess(user2.ID, repo1) has, err = HasAccess(user2.ID, repo1, accessMode)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, accessMode <= AccessModeRead, has)
has, err = HasAccess(user2.ID, repo2) has, err = HasAccess(user2.ID, repo2, accessMode)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, accessMode <= AccessModeNone, has)
}
} }
func TestUser_GetRepositoryAccesses(t *testing.T) { func TestUser_GetRepositoryAccesses(t *testing.T) {

View File

@@ -194,10 +194,6 @@ func (a *Action) GetRepoLink() string {
// GetCommentLink returns link to action comment. // GetCommentLink returns link to action comment.
func (a *Action) GetCommentLink() string { func (a *Action) GetCommentLink() string {
return a.getCommentLink(x)
}
func (a *Action) getCommentLink(e Engine) string {
if a == nil { if a == nil {
return "#" return "#"
} }
@@ -217,15 +213,11 @@ func (a *Action) getCommentLink(e Engine) string {
return "#" return "#"
} }
issue, err := getIssueByID(e, issueID) issue, err := GetIssueByID(issueID)
if err != nil { if err != nil {
return "#" return "#"
} }
if err = issue.loadRepo(e); err != nil {
return "#"
}
return issue.HTMLURL() return issue.HTMLURL()
} }
@@ -339,14 +331,12 @@ type PushCommits struct {
CompareURL string CompareURL string
avatars map[string]string avatars map[string]string
emailUsers map[string]*User
} }
// NewPushCommits creates a new PushCommits object. // NewPushCommits creates a new PushCommits object.
func NewPushCommits() *PushCommits { func NewPushCommits() *PushCommits {
return &PushCommits{ return &PushCommits{
avatars: make(map[string]string), avatars: make(map[string]string),
emailUsers: make(map[string]*User),
} }
} }
@@ -354,35 +344,17 @@ func NewPushCommits() *PushCommits {
// api.PayloadCommit format. // api.PayloadCommit format.
func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit { func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit {
commits := make([]*api.PayloadCommit, len(pc.Commits)) commits := make([]*api.PayloadCommit, len(pc.Commits))
if pc.emailUsers == nil {
pc.emailUsers = make(map[string]*User)
}
var err error
for i, commit := range pc.Commits { for i, commit := range pc.Commits {
authorUsername := "" authorUsername := ""
author, ok := pc.emailUsers[commit.AuthorEmail] author, err := GetUserByEmail(commit.AuthorEmail)
if !ok {
author, err = GetUserByEmail(commit.AuthorEmail)
if err == nil { if err == nil {
authorUsername = author.Name authorUsername = author.Name
pc.emailUsers[commit.AuthorEmail] = author
} }
} else {
authorUsername = author.Name
}
committerUsername := "" committerUsername := ""
committer, ok := pc.emailUsers[commit.CommitterEmail] committer, err := GetUserByEmail(commit.CommitterEmail)
if !ok {
committer, err = GetUserByEmail(commit.CommitterEmail)
if err == nil { if err == nil {
// TODO: check errors other than email not found. // TODO: check errors other than email not found.
committerUsername = committer.Name committerUsername = committer.Name
pc.emailUsers[commit.CommitterEmail] = committer
}
} else {
committerUsername = committer.Name
} }
commits[i] = &api.PayloadCommit{ commits[i] = &api.PayloadCommit{
ID: commit.Sha1, ID: commit.Sha1,
@@ -407,28 +379,18 @@ func (pc *PushCommits) ToAPIPayloadCommits(repoLink string) []*api.PayloadCommit
// AvatarLink tries to match user in database with e-mail // AvatarLink tries to match user in database with e-mail
// in order to show custom avatar, and falls back to general avatar link. // in order to show custom avatar, and falls back to general avatar link.
func (pc *PushCommits) AvatarLink(email string) string { func (pc *PushCommits) AvatarLink(email string) string {
avatar, ok := pc.avatars[email] _, ok := pc.avatars[email]
if ok {
return avatar
}
u, ok := pc.emailUsers[email]
if !ok { if !ok {
var err error u, err := GetUserByEmail(email)
u, err = GetUserByEmail(email)
if err != nil { if err != nil {
pc.avatars[email] = base.AvatarLink(email) pc.avatars[email] = base.AvatarLink(email)
if !IsErrUserNotExist(err) { if !IsErrUserNotExist(err) {
log.Error(4, "GetUserByEmail: %v", err) log.Error(4, "GetUserByEmail: %v", err)
return ""
} }
} else { } else {
pc.emailUsers[email] = u
}
}
if u != nil {
pc.avatars[email] = u.RelAvatarLink() pc.avatars[email] = u.RelAvatarLink()
} }
}
return pc.avatars[email] return pc.avatars[email]
} }
@@ -517,8 +479,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
continue continue
} }
issue.Repo = repo if err = issue.ChangeStatus(doer, repo, true); err != nil {
if err = issue.ChangeStatus(doer, true); err != nil {
// Don't return an error when dependencies are open as this would let the push fail // Don't return an error when dependencies are open as this would let the push fail
if IsErrDependenciesLeft(err) { if IsErrDependenciesLeft(err) {
return nil return nil
@@ -543,8 +504,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
continue continue
} }
issue.Repo = repo if err = issue.ChangeStatus(doer, repo, false); err != nil {
if err = issue.ChangeStatus(doer, false); err != nil {
return err return err
} }
} }

View File

@@ -33,9 +33,6 @@ type ProtectedBranch struct {
EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"` EnableMergeWhitelist bool `xorm:"NOT NULL DEFAULT false"`
MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"` MergeWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"` MergeWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"`
CreatedUnix util.TimeStamp `xorm:"created"` CreatedUnix util.TimeStamp `xorm:"created"`
UpdatedUnix util.TimeStamp `xorm:"updated"` UpdatedUnix util.TimeStamp `xorm:"updated"`
} }
@@ -89,42 +86,6 @@ func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
return in return in
} }
// HasEnoughApprovals returns true if pr has enough granted approvals.
func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
if protectBranch.RequiredApprovals == 0 {
return true
}
return protectBranch.GetGrantedApprovalsCount(pr) >= protectBranch.RequiredApprovals
}
// 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)
if err != nil {
log.Error(1, "GetUniqueApprovalsByPullRequestID:", err)
return 0
}
approvals := int64(0)
userIDs := make([]int64, 0)
for _, review := range reviews {
if review.Type != ReviewTypeApprove {
continue
}
if base.Int64sContains(protectBranch.ApprovalsWhitelistUserIDs, review.ID) {
approvals++
continue
}
userIDs = append(userIDs, review.ID)
}
approvalTeamCount, err := UsersInTeamsCount(userIDs, protectBranch.ApprovalsWhitelistTeamIDs)
if err != nil {
log.Error(1, "UsersInTeamsCount:", err)
return 0
}
return approvalTeamCount + approvals
}
// GetProtectedBranchByRepoID getting protected branch by repo ID // GetProtectedBranchByRepoID getting protected branch by repo ID
func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) { func GetProtectedBranchByRepoID(RepoID int64) ([]*ProtectedBranch, error) {
protectedBranches := make([]*ProtectedBranch, 0) protectedBranches := make([]*ProtectedBranch, 0)
@@ -157,64 +118,40 @@ func GetProtectedBranchByID(id int64) (*ProtectedBranch, error) {
return rel, nil return rel, nil
} }
// WhitelistOptions represent all sorts of whitelists used for protected branches
type WhitelistOptions struct {
UserIDs []int64
TeamIDs []int64
MergeUserIDs []int64
MergeTeamIDs []int64
ApprovalsUserIDs []int64
ApprovalsTeamIDs []int64
}
// UpdateProtectBranch saves branch protection options of repository. // UpdateProtectBranch saves branch protection options of repository.
// If ID is 0, it creates a new record. Otherwise, updates existing record. // If ID is 0, it creates a new record. Otherwise, updates existing record.
// This function also performs check if whitelist user and team's IDs have been changed // This function also performs check if whitelist user and team's IDs have been changed
// to avoid unnecessary whitelist delete and regenerate. // to avoid unnecessary whitelist delete and regenerate.
func UpdateProtectBranch(repo *Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { func UpdateProtectBranch(repo *Repository, protectBranch *ProtectedBranch, whitelistUserIDs, whitelistTeamIDs, mergeWhitelistUserIDs, mergeWhitelistTeamIDs []int64) (err error) {
if err = repo.GetOwner(); err != nil { if err = repo.GetOwner(); err != nil {
return fmt.Errorf("GetOwner: %v", err) return fmt.Errorf("GetOwner: %v", err)
} }
whitelist, err := updateUserWhitelist(repo, protectBranch.WhitelistUserIDs, opts.UserIDs) whitelist, err := updateUserWhitelist(repo, protectBranch.WhitelistUserIDs, whitelistUserIDs)
if err != nil { if err != nil {
return err return err
} }
protectBranch.WhitelistUserIDs = whitelist protectBranch.WhitelistUserIDs = whitelist
whitelist, err = updateUserWhitelist(repo, protectBranch.MergeWhitelistUserIDs, opts.MergeUserIDs) whitelist, err = updateUserWhitelist(repo, protectBranch.MergeWhitelistUserIDs, mergeWhitelistUserIDs)
if err != nil { if err != nil {
return err return err
} }
protectBranch.MergeWhitelistUserIDs = whitelist protectBranch.MergeWhitelistUserIDs = whitelist
whitelist, err = updateUserWhitelist(repo, protectBranch.ApprovalsWhitelistUserIDs, opts.ApprovalsUserIDs)
if err != nil {
return err
}
protectBranch.ApprovalsWhitelistUserIDs = whitelist
// if the repo is in an organization // if the repo is in an organization
whitelist, err = updateTeamWhitelist(repo, protectBranch.WhitelistTeamIDs, opts.TeamIDs) whitelist, err = updateTeamWhitelist(repo, protectBranch.WhitelistTeamIDs, whitelistTeamIDs)
if err != nil { if err != nil {
return err return err
} }
protectBranch.WhitelistTeamIDs = whitelist protectBranch.WhitelistTeamIDs = whitelist
whitelist, err = updateTeamWhitelist(repo, protectBranch.MergeWhitelistTeamIDs, opts.MergeTeamIDs) whitelist, err = updateTeamWhitelist(repo, protectBranch.MergeWhitelistTeamIDs, mergeWhitelistTeamIDs)
if err != nil { if err != nil {
return err return err
} }
protectBranch.MergeWhitelistTeamIDs = whitelist protectBranch.MergeWhitelistTeamIDs = whitelist
whitelist, err = updateTeamWhitelist(repo, protectBranch.ApprovalsWhitelistTeamIDs, opts.ApprovalsTeamIDs)
if err != nil {
return err
}
protectBranch.ApprovalsWhitelistTeamIDs = whitelist
// Make sure protectBranch.ID is not 0 for whitelists // Make sure protectBranch.ID is not 0 for whitelists
if protectBranch.ID == 0 { if protectBranch.ID == 0 {
if _, err = x.Insert(protectBranch); err != nil { if _, err = x.Insert(protectBranch); err != nil {
@@ -276,7 +213,7 @@ func (repo *Repository) IsProtectedBranchForPush(branchName string, doer *User)
} }
// IsProtectedBranchForMerging checks if branch is protected for merging // IsProtectedBranchForMerging checks if branch is protected for merging
func (repo *Repository) IsProtectedBranchForMerging(pr *PullRequest, branchName string, doer *User) (bool, error) { func (repo *Repository) IsProtectedBranchForMerging(branchName string, doer *User) (bool, error) {
if doer == nil { if doer == nil {
return true, nil return true, nil
} }
@@ -290,7 +227,7 @@ func (repo *Repository) IsProtectedBranchForMerging(pr *PullRequest, branchName
if err != nil { if err != nil {
return true, err return true, err
} else if has { } else if has {
return !protectedBranch.CanUserMerge(doer.ID) || !protectedBranch.HasEnoughApprovals(pr), nil return !protectedBranch.CanUserMerge(doer.ID), nil
} }
return false, nil return false, nil
@@ -306,16 +243,10 @@ func updateUserWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6
whitelist = make([]int64, 0, len(newWhitelist)) whitelist = make([]int64, 0, len(newWhitelist))
for _, userID := range newWhitelist { for _, userID := range newWhitelist {
user, err := GetUserByID(userID) has, err := hasAccess(x, userID, repo, AccessModeWrite)
if err != nil { if err != nil {
return nil, fmt.Errorf("GetUserByID [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err) return nil, fmt.Errorf("HasAccess [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
} } else if !has {
perm, err := GetUserRepoPermission(repo, user)
if err != nil {
return nil, fmt.Errorf("GetUserRepoPermission [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err)
}
if !perm.CanWrite(UnitTypeCode) {
continue // Drop invalid user ID continue // Drop invalid user ID
} }
@@ -333,14 +264,14 @@ func updateTeamWhitelist(repo *Repository, currentWhitelist, newWhitelist []int6
return currentWhitelist, nil return currentWhitelist, nil
} }
teams, err := GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, AccessModeRead) teams, err := GetTeamsWithAccessToRepo(repo.OwnerID, repo.ID, AccessModeWrite)
if err != nil { if err != nil {
return nil, fmt.Errorf("GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err) return nil, fmt.Errorf("GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v", repo.OwnerID, repo.ID, err)
} }
whitelist = make([]int64, 0, len(teams)) whitelist = make([]int64, 0, len(teams))
for i := range teams { for i := range teams {
if com.IsSliceContainsInt64(newWhitelist, teams[i].ID) { if teams[i].HasWriteAccess() && com.IsSliceContainsInt64(newWhitelist, teams[i].ID) {
whitelist = append(whitelist, teams[i].ID) whitelist = append(whitelist, teams[i].ID)
} }
} }

View File

@@ -5,7 +5,6 @@
act_user_id: 2 act_user_id: 2
repo_id: 2 repo_id: 2
is_private: true is_private: true
created_unix: 1540139562
- -
id: 2 id: 2

View File

@@ -30,7 +30,7 @@
id: 5 id: 5
repo_id: 1 repo_id: 1
type: 3 type: 3
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowRebaseMerge\":true,\"AllowSquash\":true}" config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowSquash\":true}"
created_unix: 946684810 created_unix: 946684810
- -
@@ -51,7 +51,7 @@
id: 8 id: 8
repo_id: 3 repo_id: 3
type: 3 type: 3
config: "{\"IgnoreWhitespaceConflicts\":true,\"AllowMerge\":true,\"AllowRebase\":false,\"AllowRebaseMerge\":true,\"AllowSquash\":false}" config: "{\"IgnoreWhitespaceConflicts\":true,\"AllowMerge\":true,\"AllowRebase\":false,\"AllowSquash\":false}"
created_unix: 946684810 created_unix: 946684810
- -
@@ -109,115 +109,3 @@
type: 5 type: 5
config: "{}" config: "{}"
created_unix: 1535593231 created_unix: 1535593231
-
id: 17
repo_id: 4
type: 4
config: "{}"
created_unix: 946684810
-
id: 18
repo_id: 4
type: 5
config: "{}"
created_unix: 946684810
-
id: 19
repo_id: 4
type: 1
config: "{}"
created_unix: 946684810
-
id: 20
repo_id: 4
type: 2
config: "{\"EnableTimetracker\":true,\"AllowOnlyContributorsToTrackTime\":true}"
created_unix: 946684810
-
id: 21
repo_id: 4
type: 3
config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowSquash\":true}"
created_unix: 946684810
-
id: 22
repo_id: 2
type: 4
config: "{}"
created_unix: 946684810
-
id: 23
repo_id: 2
type: 5
config: "{}"
created_unix: 946684810
-
id: 24
repo_id: 2
type: 1
config: "{}"
created_unix: 946684810
-
id: 25
repo_id: 32
type: 1
config: "{}"
created_unix: 1524304355
-
id: 26
repo_id: 32
type: 2
config: "{}"
created_unix: 1524304355
-
id: 27
repo_id: 24
type: 1
config: "{}"
created_unix: 1524304355
-
id: 28
repo_id: 24
type: 2
config: "{}"
created_unix: 1524304355
-
id: 29
repo_id: 16
type: 1
config: "{}"
created_unix: 1524304355
-
id: 30
repo_id: 23
type: 1
config: "{}"
created_unix: 1524304355
-
id: 31
repo_id: 27
type: 1
config: "{}"
created_unix: 1524304355
-
id: 32
repo_id: 28
type: 1
config: "{}"
created_unix: 1524304355

View File

@@ -391,7 +391,7 @@
is_mirror: false is_mirror: false
- -
id: 32 # org public repo id: 32
owner_id: 3 owner_id: 3
lower_name: repo21 lower_name: repo21
name: repo21 name: repo21

View File

@@ -30,43 +30,3 @@
content: "Pending Review" content: "Pending Review"
updated_unix: 946684810 updated_unix: 946684810
created_unix: 946684810 created_unix: 946684810
-
id: 5
type: 2
reviewer_id: 1
issue_id: 3
content: "New review 1"
updated_unix: 946684810
created_unix: 946684810
-
id: 6
type: 0
reviewer_id: 2
issue_id: 3
content: "New review 3"
updated_unix: 946684810
created_unix: 946684810
-
id: 7
type: 3
reviewer_id: 3
issue_id: 3
content: "New review 4"
updated_unix: 946684810
created_unix: 946684810
-
id: 8
type: 1
reviewer_id: 4
issue_id: 3
content: "New review 5"
updated_unix: 946684810
created_unix: 946684810
-
id: 9
type: 3
reviewer_id: 2
issue_id: 3
content: "New review 3 rejected"
updated_unix: 946684810
created_unix: 946684810

View File

@@ -51,30 +51,3 @@
authorize: 4 # owner authorize: 4 # owner
num_repos: 2 num_repos: 2
num_members: 1 num_members: 1
-
id: 7
org_id: 3
lower_name: test_team
name: test_team
authorize: 2 # write
num_repos: 1
num_members: 1
-
id: 8
org_id: 17
lower_name: test_team
name: test_team
authorize: 2 # write
num_repos: 1
num_members: 1
-
id: 9
org_id: 17
lower_name: review_team
name: review_team
authorize: 1 # read
num_repos: 1
num_members: 1

View File

@@ -45,21 +45,3 @@
org_id: 3 org_id: 3
team_id: 1 team_id: 1
repo_id: 32 repo_id: 32
-
id: 9
org_id: 3
team_id: 7
repo_id: 32
-
id: 10
org_id: 17
team_id: 8
repo_id: 24
-
id: 11
org_id: 17
team_id: 9
repo_id: 24

View File

@@ -207,18 +207,3 @@
id: 42 id: 42
team_id: 6 team_id: 6
type: 7 type: 7
-
id: 43
team_id: 7
type: 2 # issues
-
id: 44
team_id: 8
type: 2 # issues
-
id: 45
team_id: 9
type: 1 # code

View File

@@ -45,21 +45,3 @@
org_id: 19 org_id: 19
team_id: 6 team_id: 6
uid: 20 uid: 20
-
id: 9
org_id: 3
team_id: 7
uid: 15
-
id: 10
org_id: 17
team_id: 8
uid: 2
-
id: 11
org_id: 17
team_id: 9
uid: 20

View File

@@ -47,7 +47,7 @@
avatar_email: user3@example.com avatar_email: user3@example.com
num_repos: 3 num_repos: 3
num_members: 2 num_members: 2
num_teams: 3 num_teams: 2
- -
id: 4 id: 4
@@ -266,7 +266,7 @@
num_repos: 2 num_repos: 2
is_active: true is_active: true
num_members: 2 num_members: 2
num_teams: 3 num_teams: 1
- -
id: 18 id: 18

View File

@@ -86,11 +86,6 @@ func (issue *Issue) IsOverdue() bool {
return util.TimeStampNow() >= issue.DeadlineUnix return util.TimeStampNow() >= issue.DeadlineUnix
} }
// LoadRepo loads issue's repository
func (issue *Issue) LoadRepo() error {
return issue.loadRepo(x)
}
func (issue *Issue) loadRepo(e Engine) (err error) { func (issue *Issue) loadRepo(e Engine) (err error) {
if issue.Repo == nil { if issue.Repo == nil {
issue.Repo, err = getRepositoryByID(e, issue.RepoID) issue.Repo, err = getRepositoryByID(e, issue.RepoID)
@@ -117,10 +112,6 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) {
} }
pr, err = getPullRequestByIssueID(x, issue.ID) pr, err = getPullRequestByIssueID(x, issue.ID)
if err != nil {
return nil, err
}
pr.Issue = issue
return return
} }
@@ -134,11 +125,6 @@ func (issue *Issue) loadLabels(e Engine) (err error) {
return nil return nil
} }
// LoadPoster loads poster
func (issue *Issue) LoadPoster() error {
return issue.loadPoster(x)
}
func (issue *Issue) loadPoster(e Engine) (err error) { func (issue *Issue) loadPoster(e Engine) (err error) {
if issue.Poster == nil { if issue.Poster == nil {
issue.Poster, err = getUserByID(e, issue.PosterID) issue.Poster, err = getUserByID(e, issue.PosterID)
@@ -164,16 +150,10 @@ func (issue *Issue) loadPullRequest(e Engine) (err error) {
} }
return fmt.Errorf("getPullRequestByIssueID [%d]: %v", issue.ID, err) return fmt.Errorf("getPullRequestByIssueID [%d]: %v", issue.ID, err)
} }
issue.PullRequest.Issue = issue
} }
return nil return nil
} }
// LoadPullRequest loads pull request info
func (issue *Issue) LoadPullRequest() error {
return issue.loadPullRequest(x)
}
func (issue *Issue) loadComments(e Engine) (err error) { func (issue *Issue) loadComments(e Engine) (err error) {
if issue.Comments != nil { if issue.Comments != nil {
return nil return nil
@@ -326,18 +306,11 @@ func (issue *Issue) State() api.StateType {
// Required - Poster, Labels, // Required - Poster, Labels,
// Optional - Milestone, Assignee, PullRequest // Optional - Milestone, Assignee, PullRequest
func (issue *Issue) APIFormat() *api.Issue { func (issue *Issue) APIFormat() *api.Issue {
return issue.apiFormat(x)
}
func (issue *Issue) apiFormat(e Engine) *api.Issue {
issue.loadLabels(e)
apiLabels := make([]*api.Label, len(issue.Labels)) apiLabels := make([]*api.Label, len(issue.Labels))
for i := range issue.Labels { for i := range issue.Labels {
apiLabels[i] = issue.Labels[i].APIFormat() apiLabels[i] = issue.Labels[i].APIFormat()
} }
issue.loadPoster(e)
issue.loadRepo(e)
apiIssue := &api.Issue{ apiIssue := &api.Issue{
ID: issue.ID, ID: issue.ID,
URL: issue.APIURL(), URL: issue.APIURL(),
@@ -359,8 +332,6 @@ func (issue *Issue) apiFormat(e Engine) *api.Issue {
if issue.Milestone != nil { if issue.Milestone != nil {
apiIssue.Milestone = issue.Milestone.APIFormat() apiIssue.Milestone = issue.Milestone.APIFormat()
} }
issue.loadAssignees(e)
if len(issue.Assignees) > 0 { if len(issue.Assignees) > 0 {
for _, assignee := range issue.Assignees { for _, assignee := range issue.Assignees {
apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat()) apiIssue.Assignees = append(apiIssue.Assignees, assignee.APIFormat())
@@ -368,7 +339,6 @@ func (issue *Issue) apiFormat(e Engine) *api.Issue {
apiIssue.Assignee = issue.Assignees[0].APIFormat() // For compatibility, we're keeping the first assignee as `apiIssue.Assignee` apiIssue.Assignee = issue.Assignees[0].APIFormat() // For compatibility, we're keeping the first assignee as `apiIssue.Assignee`
} }
if issue.IsPull { if issue.IsPull {
issue.loadPullRequest(e)
apiIssue.PullRequest = &api.PullRequestMeta{ apiIssue.PullRequest = &api.PullRequestMeta{
HasMerged: issue.PullRequest.HasMerged, HasMerged: issue.PullRequest.HasMerged,
} }
@@ -415,7 +385,7 @@ func (issue *Issue) sendLabelUpdatedWebhook(doer *User) {
return return
} }
mode, _ := AccessLevel(issue.Poster, issue.Repo) mode, _ := AccessLevel(issue.Poster.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
if err = issue.loadPullRequest(x); err != nil { if err = issue.loadPullRequest(x); err != nil {
log.Error(4, "loadPullRequest: %v", err) log.Error(4, "loadPullRequest: %v", err)
@@ -498,11 +468,9 @@ func (issue *Issue) RemoveLabel(doer *User, label *Label) error {
return err return err
} }
perm, err := GetUserRepoPermission(issue.Repo, doer) if has, err := HasAccess(doer.ID, issue.Repo, AccessModeWrite); err != nil {
if err != nil {
return err return err
} } else if !has {
if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
return ErrLabelNotExist{} return ErrLabelNotExist{}
} }
@@ -543,11 +511,9 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
return err return err
} }
perm, err := getUserRepoPermission(sess, issue.Repo, doer) if has, err := hasAccess(sess, doer.ID, issue.Repo, AccessModeWrite); err != nil {
if err != nil {
return err return err
} } else if !has {
if !perm.CanWriteIssuesOrPulls(issue.IsPull) {
return ErrLabelNotExist{} return ErrLabelNotExist{}
} }
@@ -563,7 +529,7 @@ func (issue *Issue) ClearLabels(doer *User) (err error) {
return fmt.Errorf("loadPoster: %v", err) return fmt.Errorf("loadPoster: %v", err)
} }
mode, _ := AccessLevel(issue.Poster, issue.Repo) mode, _ := AccessLevel(issue.Poster.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
err = issue.PullRequest.LoadIssue() err = issue.PullRequest.LoadIssue()
if err != nil { if err != nil {
@@ -682,16 +648,16 @@ func UpdateIssueCols(issue *Issue, cols ...string) error {
return updateIssueCols(x, issue, cols...) return updateIssueCols(x, issue, cols...)
} }
func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (err error) { func (issue *Issue) changeStatus(e *xorm.Session, doer *User, repo *Repository, isClosed bool) (err error) {
// Nothing should be performed if current status is same as target status // Nothing should be performed if current status is same as target status
if issue.IsClosed == isClosed { if issue.IsClosed == isClosed {
return nil return nil
} }
// Check for open dependencies // Check for open dependencies
if isClosed && issue.Repo.isDependenciesEnabled(e) { if isClosed && issue.Repo.IsDependenciesEnabled() {
// only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies
noDeps, err := issueNoDependenciesLeft(e, issue) noDeps, err := IssueNoDependenciesLeft(issue)
if err != nil { if err != nil {
return err return err
} }
@@ -733,7 +699,7 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (er
} }
// New action comment // New action comment
if _, err = createStatusComment(e, doer, issue); err != nil { if _, err = createStatusComment(e, doer, repo, issue); err != nil {
return err return err
} }
@@ -741,39 +707,29 @@ func (issue *Issue) changeStatus(e *xorm.Session, doer *User, isClosed bool) (er
} }
// ChangeStatus changes issue status to open or closed. // ChangeStatus changes issue status to open or closed.
func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) { func (issue *Issue) ChangeStatus(doer *User, repo *Repository, isClosed bool) (err error) {
sess := x.NewSession() sess := x.NewSession()
defer sess.Close() defer sess.Close()
if err = sess.Begin(); err != nil { if err = sess.Begin(); err != nil {
return err return err
} }
if err = issue.loadRepo(sess); err != nil { if err = issue.changeStatus(sess, doer, repo, isClosed); err != nil {
return err
}
if err = issue.loadPoster(sess); err != nil {
return err
}
if err = issue.changeStatus(sess, doer, isClosed); err != nil {
return err return err
} }
if err = sess.Commit(); err != nil { if err = sess.Commit(); err != nil {
return fmt.Errorf("Commit: %v", err) return fmt.Errorf("Commit: %v", err)
} }
sess.Close()
mode, _ := AccessLevel(issue.Poster, issue.Repo) mode, _ := AccessLevel(issue.Poster.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
if err = issue.loadPullRequest(sess); err != nil {
return err
}
// Merge pull request calls issue.changeStatus so we need to handle separately. // Merge pull request calls issue.changeStatus so we need to handle separately.
issue.PullRequest.Issue = issue
apiPullRequest := &api.PullRequestPayload{ apiPullRequest := &api.PullRequestPayload{
Index: issue.Index, Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(), PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.APIFormat(mode), Repository: repo.APIFormat(mode),
Sender: doer.APIFormat(), Sender: doer.APIFormat(),
} }
if isClosed { if isClosed {
@@ -781,12 +737,12 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) {
} else { } else {
apiPullRequest.Action = api.HookIssueReOpened apiPullRequest.Action = api.HookIssueReOpened
} }
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, apiPullRequest) err = PrepareWebhooks(repo, HookEventPullRequest, apiPullRequest)
} else { } else {
apiIssue := &api.IssuePayload{ apiIssue := &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: issue.APIFormat(), Issue: issue.APIFormat(),
Repository: issue.Repo.APIFormat(mode), Repository: repo.APIFormat(mode),
Sender: doer.APIFormat(), Sender: doer.APIFormat(),
} }
if isClosed { if isClosed {
@@ -794,12 +750,12 @@ func (issue *Issue) ChangeStatus(doer *User, isClosed bool) (err error) {
} else { } else {
apiIssue.Action = api.HookIssueReOpened apiIssue.Action = api.HookIssueReOpened
} }
err = PrepareWebhooks(issue.Repo, HookEventIssues, apiIssue) err = PrepareWebhooks(repo, HookEventIssues, apiIssue)
} }
if err != nil { if err != nil {
log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err) log.Error(4, "PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err)
} else { } else {
go HookQueue.Add(issue.Repo.ID) go HookQueue.Add(repo.ID)
} }
return nil return nil
@@ -820,10 +776,6 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
return fmt.Errorf("updateIssueCols: %v", err) return fmt.Errorf("updateIssueCols: %v", err)
} }
if err = issue.loadRepo(sess); err != nil {
return fmt.Errorf("loadRepo: %v", err)
}
if _, err = createChangeTitleComment(sess, doer, issue.Repo, issue, oldTitle, title); err != nil { if _, err = createChangeTitleComment(sess, doer, issue.Repo, issue, oldTitle, title); err != nil {
return fmt.Errorf("createChangeTitleComment: %v", err) return fmt.Errorf("createChangeTitleComment: %v", err)
} }
@@ -832,11 +784,8 @@ func (issue *Issue) ChangeTitle(doer *User, title string) (err error) {
return err return err
} }
mode, _ := AccessLevel(issue.Poster, issue.Repo) mode, _ := AccessLevel(issue.Poster.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
if err = issue.loadPullRequest(sess); err != nil {
return fmt.Errorf("loadPullRequest: %v", err)
}
issue.PullRequest.Issue = issue issue.PullRequest.Issue = issue
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueEdited, Action: api.HookIssueEdited,
@@ -901,7 +850,7 @@ func (issue *Issue) ChangeContent(doer *User, content string) (err error) {
return fmt.Errorf("UpdateIssueCols: %v", err) return fmt.Errorf("UpdateIssueCols: %v", err)
} }
mode, _ := AccessLevel(issue.Poster, issue.Repo) mode, _ := AccessLevel(issue.Poster.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
issue.PullRequest.Issue = issue issue.PullRequest.Issue = issue
err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ err = PrepareWebhooks(issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
@@ -996,13 +945,9 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
// Check for and validate assignees // Check for and validate assignees
if len(opts.AssigneeIDs) > 0 { if len(opts.AssigneeIDs) > 0 {
for _, assigneeID := range opts.AssigneeIDs { for _, assigneeID := range opts.AssigneeIDs {
user, err := getUserByID(e, assigneeID) valid, err := hasAccess(e, assigneeID, opts.Repo, AccessModeWrite)
if err != nil { if err != nil {
return fmt.Errorf("getUserByID [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err) return fmt.Errorf("hasAccess [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err)
}
valid, err := canBeAssigned(e, user, opts.Repo)
if err != nil {
return fmt.Errorf("canBeAssigned [user_id: %d, repo_id: %d]: %v", assigneeID, opts.Repo.ID, err)
} }
if !valid { if !valid {
return ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: opts.Repo.Name} return ErrUserDoesNotHaveAccessToRepo{UserID: assigneeID, RepoName: opts.Repo.Name}
@@ -1125,7 +1070,7 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
log.Error(4, "MailParticipants: %v", err) log.Error(4, "MailParticipants: %v", err)
} }
mode, _ := AccessLevel(issue.Poster, issue.Repo) mode, _ := AccessLevel(issue.Poster.ID, issue.Repo)
if err = PrepareWebhooks(repo, HookEventIssues, &api.IssuePayload{ if err = PrepareWebhooks(repo, HookEventIssues, &api.IssuePayload{
Action: api.HookIssueOpened, Action: api.HookIssueOpened,
Index: issue.Index, Index: issue.Index,
@@ -1141,8 +1086,8 @@ func NewIssue(repo *Repository, issue *Issue, labelIDs []int64, assigneeIDs []in
return nil return nil
} }
// GetIssueByIndex returns raw issue without loading attributes by index in a repository. // GetRawIssueByIndex returns raw issue without loading attributes by index in a repository.
func GetIssueByIndex(repoID, index int64) (*Issue, error) { func GetRawIssueByIndex(repoID, index int64) (*Issue, error) {
issue := &Issue{ issue := &Issue{
RepoID: repoID, RepoID: repoID,
Index: index, Index: index,
@@ -1156,9 +1101,9 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) {
return issue, nil return issue, nil
} }
// GetIssueWithAttrsByIndex returns issue by index in a repository. // GetIssueByIndex returns issue by index in a repository.
func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) { func GetIssueByIndex(repoID, index int64) (*Issue, error) {
issue, err := GetIssueByIndex(repoID, index) issue, err := GetRawIssueByIndex(repoID, index)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -1173,16 +1118,7 @@ func getIssueByID(e Engine, id int64) (*Issue, error) {
} else if !has { } else if !has {
return nil, ErrIssueNotExist{id, 0, 0} return nil, ErrIssueNotExist{id, 0, 0}
} }
return issue, nil return issue, issue.loadAttributes(e)
}
// GetIssueWithAttrsByID returns an issue with attributes by given ID.
func GetIssueWithAttrsByID(id int64) (*Issue, error) {
issue, err := getIssueByID(x, id)
if err != nil {
return nil, err
}
return issue, issue.loadAttributes(x)
} }
// GetIssueByID returns an issue by given ID. // GetIssueByID returns an issue by given ID.
@@ -1456,7 +1392,7 @@ type IssueStatsOptions struct {
AssigneeID int64 AssigneeID int64
MentionedID int64 MentionedID int64
PosterID int64 PosterID int64
IsPull util.OptionalBool IsPull bool
IssueIDs []int64 IssueIDs []int64
} }
@@ -1466,7 +1402,8 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
countSession := func(opts *IssueStatsOptions) *xorm.Session { countSession := func(opts *IssueStatsOptions) *xorm.Session {
sess := x. sess := x.
Where("issue.repo_id = ?", opts.RepoID) Where("issue.repo_id = ?", opts.RepoID).
And("issue.is_pull = ?", opts.IsPull)
if len(opts.IssueIDs) > 0 { if len(opts.IssueIDs) > 0 {
sess.In("issue.id", opts.IssueIDs) sess.In("issue.id", opts.IssueIDs)
@@ -1501,13 +1438,6 @@ func GetIssueStats(opts *IssueStatsOptions) (*IssueStats, error) {
And("issue_user.is_mentioned = ?", true) And("issue_user.is_mentioned = ?", true)
} }
switch opts.IsPull {
case util.OptionalBoolTrue:
sess.And("issue.is_pull=?", true)
case util.OptionalBoolFalse:
sess.And("issue.is_pull=?", false)
}
return sess return sess
} }

View File

@@ -159,14 +159,13 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
return fmt.Errorf("createAssigneeComment: %v", err) return fmt.Errorf("createAssigneeComment: %v", err)
} }
// if pull request is in the middle of creation - don't call webhook // if issue/pull is in the middle of creation - don't call webhook
if isCreate { if isCreate {
return nil return nil
} }
mode, _ := accessLevel(sess, doer.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
mode, _ := accessLevelUnit(sess, doer, issue.Repo, UnitTypePullRequests)
if err = issue.loadPullRequest(sess); err != nil { if err = issue.loadPullRequest(sess); err != nil {
return fmt.Errorf("loadPullRequest: %v", err) return fmt.Errorf("loadPullRequest: %v", err)
} }
@@ -174,7 +173,7 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
apiPullRequest := &api.PullRequestPayload{ apiPullRequest := &api.PullRequestPayload{
Index: issue.Index, Index: issue.Index,
PullRequest: issue.PullRequest.APIFormat(), PullRequest: issue.PullRequest.APIFormat(),
Repository: issue.Repo.innerAPIFormat(sess, mode, false), Repository: issue.Repo.APIFormat(mode),
Sender: doer.APIFormat(), Sender: doer.APIFormat(),
} }
if removed { if removed {
@@ -187,12 +186,10 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
return nil return nil
} }
} else { } else {
mode, _ := accessLevelUnit(sess, doer, issue.Repo, UnitTypeIssues)
apiIssue := &api.IssuePayload{ apiIssue := &api.IssuePayload{
Index: issue.Index, Index: issue.Index,
Issue: issue.apiFormat(sess), Issue: issue.APIFormat(),
Repository: issue.Repo.innerAPIFormat(sess, mode, false), Repository: issue.Repo.APIFormat(mode),
Sender: doer.APIFormat(), Sender: doer.APIFormat(),
} }
if removed { if removed {

View File

@@ -14,7 +14,7 @@ func TestUpdateAssignee(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
// Fake issue with assignees // Fake issue with assignees
issue, err := GetIssueWithAttrsByID(1) issue, err := GetIssueByID(1)
assert.NoError(t, err) assert.NoError(t, err)
// Assign multiple users // Assign multiple users

View File

@@ -150,6 +150,25 @@ func (c *Comment) LoadIssue() (err error) {
return return
} }
// AfterLoad is invoked from XORM after setting the values of all fields of this object.
func (c *Comment) AfterLoad(session *xorm.Session) {
var err error
c.Attachments, err = getAttachmentsByCommentID(session, c.ID)
if err != nil {
log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
}
c.Poster, err = getUserByID(session, c.PosterID)
if err != nil {
if IsErrUserNotExist(err) {
c.PosterID = -1
c.Poster = NewGhostUser()
} else {
log.Error(3, "getUserByID[%d]: %v", c.ID, err)
}
}
}
// AfterDelete is invoked from XORM after the object is deleted. // AfterDelete is invoked from XORM after the object is deleted.
func (c *Comment) AfterDelete() { func (c *Comment) AfterDelete() {
if c.ID <= 0 { if c.ID <= 0 {
@@ -170,11 +189,6 @@ func (c *Comment) HTMLURL() string {
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err) log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return "" return ""
} }
err = c.Issue.loadRepo(x)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
if c.Type == CommentTypeCode { if c.Type == CommentTypeCode {
if c.ReviewID == 0 { if c.ReviewID == 0 {
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag()) return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
@@ -203,12 +217,6 @@ func (c *Comment) IssueURL() string {
if c.Issue.IsPull { if c.Issue.IsPull {
return "" return ""
} }
err = c.Issue.loadRepo(x)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
return c.Issue.HTMLURL() return c.Issue.HTMLURL()
} }
@@ -220,12 +228,6 @@ func (c *Comment) PRURL() string {
return "" return ""
} }
err = c.Issue.loadRepo(x)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
if !c.Issue.IsPull { if !c.Issue.IsPull {
return "" return ""
} }
@@ -301,39 +303,6 @@ func (c *Comment) LoadMilestone() error {
return nil return nil
} }
// LoadPoster loads comment poster
func (c *Comment) LoadPoster() error {
if c.PosterID <= 0 || c.Poster != nil {
return nil
}
var err error
c.Poster, err = getUserByID(x, c.PosterID)
if err != nil {
if IsErrUserNotExist(err) {
c.PosterID = -1
c.Poster = NewGhostUser()
} else {
log.Error(3, "getUserByID[%d]: %v", c.ID, err)
}
}
return nil
}
// LoadAttachments loads attachments
func (c *Comment) LoadAttachments() error {
if len(c.Attachments) > 0 {
return nil
}
var err error
c.Attachments, err = getAttachmentsByCommentID(x, c.ID)
if err != nil {
log.Error(3, "getAttachmentsByCommentID[%d]: %v", c.ID, err)
}
return nil
}
// LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees // LoadAssigneeUser if comment.Type is CommentTypeAssignees, then load assignees
func (c *Comment) LoadAssigneeUser() error { func (c *Comment) LoadAssigneeUser() error {
var err error var err error
@@ -406,11 +375,9 @@ func (c *Comment) LoadReactions() error {
} }
func (c *Comment) loadReview(e Engine) (err error) { func (c *Comment) loadReview(e Engine) (err error) {
if c.Review == nil {
if c.Review, err = getReviewByID(e, c.ReviewID); err != nil { if c.Review, err = getReviewByID(e, c.ReviewID); err != nil {
return err return err
} }
}
return nil return nil
} }
@@ -487,11 +454,6 @@ func (c *Comment) CodeCommentURL() string {
log.Error(4, "LoadIssue(%d): %v", c.IssueID, err) log.Error(4, "LoadIssue(%d): %v", c.IssueID, err)
return "" return ""
} }
err = c.Issue.loadRepo(x)
if err != nil { // Silently dropping errors :unamused:
log.Error(4, "loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag()) return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
} }
@@ -639,7 +601,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
return nil return nil
} }
func createStatusComment(e *xorm.Session, doer *User, issue *Issue) (*Comment, error) { func createStatusComment(e *xorm.Session, doer *User, repo *Repository, issue *Issue) (*Comment, error) {
cmtType := CommentTypeClose cmtType := CommentTypeClose
if !issue.IsClosed { if !issue.IsClosed {
cmtType = CommentTypeReopen cmtType = CommentTypeReopen
@@ -647,7 +609,7 @@ func createStatusComment(e *xorm.Session, doer *User, issue *Issue) (*Comment, e
return createComment(e, &CreateCommentOptions{ return createComment(e, &CreateCommentOptions{
Type: cmtType, Type: cmtType,
Doer: doer, Doer: doer,
Repo: issue.Repo, Repo: repo,
Issue: issue, Issue: issue,
}) })
} }
@@ -708,10 +670,6 @@ func createDeadlineComment(e *xorm.Session, doer *User, issue *Issue, newDeadlin
content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02") content = newDeadlineUnix.Format("2006-01-02") + "|" + issue.DeadlineUnix.Format("2006-01-02")
} }
if err := issue.LoadRepo(); err != nil {
return nil, err
}
return createComment(e, &CreateCommentOptions{ return createComment(e, &CreateCommentOptions{
Type: commentType, Type: commentType,
Doer: doer, Doer: doer,
@@ -837,7 +795,7 @@ func CreateIssueComment(doer *User, repo *Repository, issue *Issue, content stri
return nil, fmt.Errorf("CreateComment: %v", err) return nil, fmt.Errorf("CreateComment: %v", err)
} }
mode, _ := AccessLevel(doer, repo) mode, _ := AccessLevel(doer.ID, repo)
if err = PrepareWebhooks(repo, HookEventIssueComment, &api.IssueCommentPayload{ if err = PrepareWebhooks(repo, HookEventIssueComment, &api.IssueCommentPayload{
Action: api.HookIssueCommentCreated, Action: api.HookIssueCommentCreated,
Issue: issue.APIFormat(), Issue: issue.APIFormat(),
@@ -1025,9 +983,6 @@ func UpdateComment(doer *User, c *Comment, oldContent string) error {
UpdateIssueIndexer(c.IssueID) UpdateIssueIndexer(c.IssueID)
} }
if err := c.LoadPoster(); err != nil {
return err
}
if err := c.LoadIssue(); err != nil { if err := c.LoadIssue(); err != nil {
return err return err
} }
@@ -1035,7 +990,7 @@ func UpdateComment(doer *User, c *Comment, oldContent string) error {
return err return err
} }
mode, _ := AccessLevel(doer, c.Issue.Repo) mode, _ := AccessLevel(doer.ID, c.Issue.Repo)
if err := PrepareWebhooks(c.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{ if err := PrepareWebhooks(c.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{
Action: api.HookIssueCommentEdited, Action: api.HookIssueCommentEdited,
Issue: c.Issue.APIFormat(), Issue: c.Issue.APIFormat(),
@@ -1085,9 +1040,6 @@ func DeleteComment(doer *User, comment *Comment) error {
UpdateIssueIndexer(comment.IssueID) UpdateIssueIndexer(comment.IssueID)
} }
if err := comment.LoadPoster(); err != nil {
return err
}
if err := comment.LoadIssue(); err != nil { if err := comment.LoadIssue(); err != nil {
return err return err
} }
@@ -1095,7 +1047,7 @@ func DeleteComment(doer *User, comment *Comment) error {
return err return err
} }
mode, _ := AccessLevel(doer, comment.Issue.Repo) mode, _ := AccessLevel(doer.ID, comment.Issue.Repo)
if err := PrepareWebhooks(comment.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{ if err := PrepareWebhooks(comment.Issue.Repo, HookEventIssueComment, &api.IssueCommentPayload{
Action: api.HookIssueCommentDeleted, Action: api.HookIssueCommentDeleted,
@@ -1143,10 +1095,6 @@ func fetchCodeCommentsByReview(e Engine, issue *Issue, currentUser *User, review
return nil, err return nil, err
} }
if err := CommentList(comments).loadPosters(e); err != nil {
return nil, err
}
if err := issue.loadRepo(e); err != nil { if err := issue.loadRepo(e); err != nil {
return nil, err return nil, err
} }

View File

@@ -1,58 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
// CommentList defines a list of comments
type CommentList []*Comment
func (comments CommentList) getPosterIDs() []int64 {
commentIDs := make(map[int64]struct{}, len(comments))
for _, comment := range comments {
if _, ok := commentIDs[comment.PosterID]; !ok {
commentIDs[comment.PosterID] = struct{}{}
}
}
return keysInt64(commentIDs)
}
// LoadPosters loads posters from database
func (comments CommentList) LoadPosters() error {
return comments.loadPosters(x)
}
func (comments CommentList) loadPosters(e Engine) error {
if len(comments) == 0 {
return nil
}
posterIDs := comments.getPosterIDs()
posterMaps := make(map[int64]*User, len(posterIDs))
var left = len(posterIDs)
for left > 0 {
var limit = defaultMaxInSize
if left < limit {
limit = left
}
err := e.
In("id", posterIDs[:limit]).
Find(&posterMaps)
if err != nil {
return err
}
left = left - limit
posterIDs = posterIDs[limit:]
}
for _, comment := range comments {
if comment.PosterID <= 0 {
continue
}
var ok bool
if comment.Poster, ok = posterMaps[comment.PosterID]; !ok {
comment.Poster = NewGhostUser()
}
}
return nil
}

View File

@@ -113,11 +113,8 @@ func issueDepExists(e Engine, issueID int64, depID int64) (bool, error) {
// IssueNoDependenciesLeft checks if issue can be closed // IssueNoDependenciesLeft checks if issue can be closed
func IssueNoDependenciesLeft(issue *Issue) (bool, error) { func IssueNoDependenciesLeft(issue *Issue) (bool, error) {
return issueNoDependenciesLeft(x, issue)
}
func issueNoDependenciesLeft(e Engine, issue *Issue) (bool, error) { exists, err := x.
exists, err := e.
Table("issue_dependency"). Table("issue_dependency").
Select("issue.*"). Select("issue.*").
Join("INNER", "issue", "issue.id = issue_dependency.dependency_id"). Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").
@@ -130,13 +127,9 @@ func issueNoDependenciesLeft(e Engine, issue *Issue) (bool, error) {
// IsDependenciesEnabled returns if dependecies are enabled and returns the default setting if not set. // IsDependenciesEnabled returns if dependecies are enabled and returns the default setting if not set.
func (repo *Repository) IsDependenciesEnabled() bool { func (repo *Repository) IsDependenciesEnabled() bool {
return repo.isDependenciesEnabled(x)
}
func (repo *Repository) isDependenciesEnabled(e Engine) bool {
var u *RepoUnit var u *RepoUnit
var err error var err error
if u, err = repo.getUnit(e, UnitTypeIssues); err != nil { if u, err = repo.GetUnit(UnitTypeIssues); err != nil {
log.Trace("%s", err) log.Trace("%s", err)
return setting.Service.DefaultEnableDependencies return setting.Service.DefaultEnableDependencies
} }

View File

@@ -19,11 +19,8 @@ func TestCreateIssueDependency(t *testing.T) {
issue1, err := GetIssueByID(1) issue1, err := GetIssueByID(1)
assert.NoError(t, err) assert.NoError(t, err)
issue1.LoadAttributes()
issue2, err := GetIssueByID(2) issue2, err := GetIssueByID(2)
assert.NoError(t, err) assert.NoError(t, err)
issue2.LoadAttributes()
// Create a dependency and check if it was successful // Create a dependency and check if it was successful
err = CreateIssueDependency(user1, issue1, issue2) err = CreateIssueDependency(user1, issue1, issue2)
@@ -47,7 +44,7 @@ func TestCreateIssueDependency(t *testing.T) {
assert.False(t, left) assert.False(t, left)
// Close #2 and check again // Close #2 and check again
err = issue2.ChangeStatus(user1, true) err = issue2.ChangeStatus(user1, issue2.Repo, true)
assert.NoError(t, err) assert.NoError(t, err)
left, err = IssueNoDependenciesLeft(issue1) left, err = IssueNoDependenciesLeft(issue1)

View File

@@ -134,7 +134,7 @@ func NewLabels(labels ...*Label) error {
// If pass repoID as 0, then ORM will ignore limitation of repository // If pass repoID as 0, then ORM will ignore limitation of repository
// and can return arbitrary label with any valid ID. // and can return arbitrary label with any valid ID.
func getLabelInRepoByName(e Engine, repoID int64, labelName string) (*Label, error) { func getLabelInRepoByName(e Engine, repoID int64, labelName string) (*Label, error) {
if len(labelName) == 0 { if len(labelName) <= 0 {
return nil, ErrLabelNotExist{0, repoID} return nil, ErrLabelNotExist{0, repoID}
} }

View File

@@ -39,7 +39,7 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
// In case the issue poster is not watching the repository and is active, // In case the issue poster is not watching the repository and is active,
// even if we have duplicated in watchers, can be safely filtered out. // even if we have duplicated in watchers, can be safely filtered out.
poster, err := getUserByID(e, issue.PosterID) poster, err := GetUserByID(issue.PosterID)
if err != nil { if err != nil {
return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err) return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err)
} }

View File

@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/util"
api "code.gitea.io/sdk/gitea" api "code.gitea.io/sdk/gitea"
"github.com/go-xorm/xorm" "github.com/go-xorm/xorm"
) )
@@ -122,18 +123,6 @@ func GetMilestoneByRepoID(repoID, id int64) (*Milestone, error) {
return getMilestoneByRepoID(x, repoID, id) return getMilestoneByRepoID(x, repoID, id)
} }
// GetMilestoneByID returns the milestone via id .
func GetMilestoneByID(id int64) (*Milestone, error) {
var m Milestone
has, err := x.ID(id).Get(&m)
if err != nil {
return nil, err
} else if !has {
return nil, ErrMilestoneNotExist{id, 0}
}
return &m, nil
}
// MilestoneList is a list of milestones offering additional functionality // MilestoneList is a list of milestones offering additional functionality
type MilestoneList []*Milestone type MilestoneList []*Milestone
@@ -189,11 +178,10 @@ func (milestones MilestoneList) getMilestoneIDs() []int64 {
return ids return ids
} }
// GetMilestonesByRepoID returns all opened milestones of a repository. // GetMilestonesByRepoID returns all milestones of a repository.
func GetMilestonesByRepoID(repoID int64) (MilestoneList, error) { func GetMilestonesByRepoID(repoID int64) (MilestoneList, error) {
miles := make([]*Milestone, 0, 10) miles := make([]*Milestone, 0, 10)
return miles, x.Where("repo_id = ? AND is_closed = ?", repoID, false). return miles, x.Where("repo_id = ?", repoID).Asc("deadline_unix").Find(&miles)
Asc("deadline_unix").Asc("id").Find(&miles)
} }
// GetMilestones returns a list of milestones of given repository and status. // GetMilestones returns a list of milestones of given repository and status.
@@ -389,7 +377,7 @@ func ChangeMilestoneAssign(issue *Issue, doer *User, oldMilestoneID int64) (err
return err return err
} }
mode, _ := AccessLevel(doer, issue.Repo) mode, _ := AccessLevel(doer.ID, issue.Repo)
if issue.IsPull { if issue.IsPull {
err = issue.PullRequest.LoadIssue() err = issue.PullRequest.LoadIssue()
if err != nil { if err != nil {

View File

@@ -49,10 +49,6 @@ func CreateOrStopIssueStopwatch(user *User, issue *Issue) error {
if err != nil { if err != nil {
return err return err
} }
if err := issue.loadRepo(x); err != nil {
return err
}
if exists { if exists {
// Create tracked time out of the time difference between start date and actual date // Create tracked time out of the time difference between start date and actual date
timediff := time.Now().Unix() - int64(sw.CreatedUnix) timediff := time.Now().Unix() - int64(sw.CreatedUnix)
@@ -116,10 +112,6 @@ func CancelStopwatch(user *User, issue *Issue) error {
return err return err
} }
if err := issue.loadRepo(x); err != nil {
return err
}
if _, err := CreateComment(&CreateCommentOptions{ if _, err := CreateComment(&CreateCommentOptions{
Doer: user, Doer: user,
Issue: issue, Issue: issue,

View File

@@ -90,9 +90,6 @@ func AddTime(user *User, issue *Issue, time int64) (*TrackedTime, error) {
if _, err := x.Insert(tt); err != nil { if _, err := x.Insert(tt); err != nil {
return nil, err return nil, err
} }
if err := issue.loadRepo(x); err != nil {
return nil, err
}
if _, err := CreateComment(&CreateCommentOptions{ if _, err := CreateComment(&CreateCommentOptions{
Issue: issue, Issue: issue,
Repo: issue.Repo, Repo: issue.Repo,

View File

@@ -139,11 +139,10 @@ func CheckLFSAccessForRepo(u *User, repo *Repository, mode AccessMode) error {
if u == nil { if u == nil {
return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode} return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode}
} }
perm, err := GetUserRepoPermission(repo, u) has, err := HasAccess(u.ID, repo, mode)
if err != nil { if err != nil {
return err return err
} } else if !has {
if !perm.CanAccess(mode, UnitTypeCode) {
return ErrLFSUnauthorizedAction{repo.ID, u.DisplayName(), mode} return ErrLFSUnauthorizedAction{repo.ID, u.DisplayName(), mode}
} }
return nil return nil

View File

@@ -393,13 +393,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR
return nil, ErrUserNotExist{0, login, 0} return nil, ErrUserNotExist{0, login, 0}
} }
var isAttributeSSHPublicKeySet = len(strings.TrimSpace(source.LDAP().AttributeSSHPublicKey)) > 0
if !autoRegister { if !autoRegister {
if isAttributeSSHPublicKeySet && synchronizeLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
RewriteAllPublicKeys()
}
return user, nil return user, nil
} }
@@ -427,14 +421,7 @@ func LoginViaLDAP(user *User, login, password string, source *LoginSource, autoR
IsActive: true, IsActive: true,
IsAdmin: sr.IsAdmin, IsAdmin: sr.IsAdmin,
} }
return user, CreateUser(user)
err := CreateUser(user)
if err == nil && isAttributeSSHPublicKeySet && addLdapSSHPublicKeys(user, source, sr.SSHPublicKey) {
RewriteAllPublicKeys()
}
return user, err
} }
// _________ __________________________ // _________ __________________________

View File

@@ -151,7 +151,6 @@ func composeTplData(subject, body, link string) map[string]interface{} {
func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message { func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message {
subject := issue.mailSubject() subject := issue.mailSubject()
issue.LoadRepo()
body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas())) body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas()))
data := make(map[string]interface{}, 10) data := make(map[string]interface{}, 10)

View File

@@ -200,12 +200,6 @@ var migrations = []Migration{
NewMigration("add review", addReview), NewMigration("add review", addReview),
// v73 -> v74 // v73 -> v74
NewMigration("add must_change_password column for users table", addMustChangePassword), NewMigration("add must_change_password column for users table", addMustChangePassword),
// v74 -> v75
NewMigration("add approval whitelists to protected branches", addApprovalWhitelistsToProtectedBranches),
// v75 -> v76
NewMigration("clear nonused data which not deleted when user was deleted", clearNonusedData),
// v76 -> v77
NewMigration("add pull request rebase with merge commit", addPullRequestRebaseWithMerge),
} }
// Migrate database to current version // Migrate database to current version

View File

@@ -205,6 +205,9 @@ func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
return err return err
} }
} }
if err := sess.Commit(); err != nil {
return err
}
return sess.Commit() return nil
} }

View File

@@ -44,7 +44,7 @@ func addScratchHash(x *xorm.Engine) error {
const batchSize = 100 const batchSize = 100
for start := 0; ; start += batchSize { for start := 0; ; start += batchSize {
tfas := make([]*TwoFactor, 0, batchSize) tfas := make([]*TwoFactor, 0, batchSize)
if err := sess.Limit(batchSize, start).Find(&tfas); err != nil { if err := x.Limit(batchSize, start).Find(&tfas); err != nil {
return err return err
} }
if len(tfas) == 0 { if len(tfas) == 0 {

View File

@@ -1,16 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import "github.com/go-xorm/xorm"
func addApprovalWhitelistsToProtectedBranches(x *xorm.Engine) error {
type ProtectedBranch struct {
ApprovalsWhitelistUserIDs []int64 `xorm:"JSON TEXT"`
ApprovalsWhitelistTeamIDs []int64 `xorm:"JSON TEXT"`
RequiredApprovals int64 `xorm:"NOT NULL DEFAULT 0"`
}
return x.Sync2(new(ProtectedBranch))
}

View File

@@ -1,33 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"github.com/go-xorm/builder"
"github.com/go-xorm/xorm"
)
func clearNonusedData(x *xorm.Engine) error {
condDelete := func(colName string) builder.Cond {
return builder.NotIn(colName, builder.Select("id").From("`user`"))
}
if _, err := x.Exec(builder.Delete(condDelete("uid")).From("team_user")); err != nil {
return err
}
if _, err := x.Exec(builder.Delete(condDelete("user_id")).From("collaboration")); err != nil {
return err
}
if _, err := x.Exec(builder.Delete(condDelete("user_id")).From("stopwatch")); err != nil {
return err
}
if _, err := x.Exec(builder.Delete(condDelete("owner_id")).From("gpg_key")); err != nil {
return err
}
return nil
}

View File

@@ -1,63 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package migrations
import (
"fmt"
"code.gitea.io/gitea/modules/util"
"github.com/go-xorm/xorm"
)
func addPullRequestRebaseWithMerge(x *xorm.Engine) error {
// RepoUnit describes all units of a repository
type RepoUnit struct {
ID int64
RepoID int64 `xorm:"INDEX(s)"`
Type int `xorm:"INDEX(s)"`
Config map[string]interface{} `xorm:"JSON"`
CreatedUnix util.TimeStamp `xorm:"INDEX CREATED"`
}
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
//Updating existing issue units
units := make([]*RepoUnit, 0, 100)
if err := sess.Where("`type` = ?", V16UnitTypePRs).Find(&units); err != nil {
return fmt.Errorf("Query repo units: %v", err)
}
for _, unit := range units {
if unit.Config == nil {
unit.Config = make(map[string]interface{})
}
// Allow the new merge style if all other merge styles are allowed
allowMergeRebase := true
if allowMerge, ok := unit.Config["AllowMerge"]; ok {
allowMergeRebase = allowMergeRebase && allowMerge.(bool)
}
if allowRebase, ok := unit.Config["AllowRebase"]; ok {
allowMergeRebase = allowMergeRebase && allowRebase.(bool)
}
if allowSquash, ok := unit.Config["AllowSquash"]; ok {
allowMergeRebase = allowMergeRebase && allowSquash.(bool)
}
if _, ok := unit.Config["AllowRebaseMerge"]; !ok {
unit.Config["AllowRebaseMerge"] = allowMergeRebase
}
if _, err := sess.ID(unit.ID).Cols("config").Update(unit); err != nil {
return err
}
}
return sess.Commit()
}

View File

@@ -36,7 +36,7 @@ type Engine interface {
Count(...interface{}) (int64, error) Count(...interface{}) (int64, error)
Decr(column string, arg ...interface{}) *xorm.Session Decr(column string, arg ...interface{}) *xorm.Session
Delete(interface{}) (int64, error) Delete(interface{}) (int64, error)
Exec(...interface{}) (sql.Result, error) Exec(string, ...interface{}) (sql.Result, error)
Find(interface{}, ...interface{}) error Find(interface{}, ...interface{}) error
Get(interface{}) (bool, error) Get(interface{}) (bool, error)
ID(interface{}) *xorm.Session ID(interface{}) *xorm.Session
@@ -200,8 +200,7 @@ func getPostgreSQLConnectionString(DBHost, DBUser, DBPasswd, DBName, DBParam, DB
return return
} }
// ParseMSSQLHostPort splits the host into host and port func parseMSSQLHostPort(info string) (string, string) {
func ParseMSSQLHostPort(info string) (string, string) {
host, port := "127.0.0.1", "1433" host, port := "127.0.0.1", "1433"
if strings.Contains(info, ":") { if strings.Contains(info, ":") {
host = strings.Split(info, ":")[0] host = strings.Split(info, ":")[0]
@@ -236,7 +235,7 @@ func getEngine() (*xorm.Engine, error) {
case "postgres": case "postgres":
connStr = getPostgreSQLConnectionString(DbCfg.Host, DbCfg.User, DbCfg.Passwd, DbCfg.Name, Param, DbCfg.SSLMode) connStr = getPostgreSQLConnectionString(DbCfg.Host, DbCfg.User, DbCfg.Passwd, DbCfg.Name, Param, DbCfg.SSLMode)
case "mssql": case "mssql":
host, port := ParseMSSQLHostPort(DbCfg.Host) host, port := parseMSSQLHostPort(DbCfg.Host)
connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, DbCfg.Name, DbCfg.User, DbCfg.Passwd) connStr = fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;", host, port, DbCfg.Name, DbCfg.User, DbCfg.Passwd)
case "sqlite3": case "sqlite3":
if !EnableSQLite3 { if !EnableSQLite3 {

View File

@@ -687,7 +687,7 @@ func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*Repository, error)
} }
repos := make([]*Repository, 0, len(repoIDs)) repos := make([]*Repository, 0, len(repoIDs))
if len(repoIDs) == 0 { if len(repoIDs) <= 0 {
return repos, nil return repos, nil
} }
@@ -715,7 +715,7 @@ func (env *accessibleReposEnv) MirrorRepos() ([]*Repository, error) {
} }
repos := make([]*Repository, 0, len(repoIDs)) repos := make([]*Repository, 0, len(repoIDs))
if len(repoIDs) == 0 { if len(repoIDs) <= 0 {
return repos, nil return repos, nil
} }

View File

@@ -177,7 +177,7 @@ func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (e
return fmt.Errorf("getTeamUsersByTeamID: %v", err) return fmt.Errorf("getTeamUsersByTeamID: %v", err)
} }
for _, teamUser := range teamUsers { for _, teamUser := range teamUsers {
has, err := hasAccess(e, teamUser.UID, repo) has, err := hasAccess(e, teamUser.UID, repo, AccessModeRead)
if err != nil { if err != nil {
return err return err
} else if has { } else if has {
@@ -434,7 +434,7 @@ func DeleteTeam(t *Team) error {
// Remove watches from all users and now unaccessible repos // Remove watches from all users and now unaccessible repos
for _, user := range t.Members { for _, user := range t.Members {
has, err := hasAccess(sess, user.ID, repo) has, err := hasAccess(sess, user.ID, repo, AccessModeRead)
if err != nil { if err != nil {
return err return err
} else if has { } else if has {
@@ -652,7 +652,7 @@ func removeTeamMember(e *xorm.Session, team *Team, userID int64) error {
} }
// Remove watches from now unaccessible // Remove watches from now unaccessible
has, err := hasAccess(e, userID, repo) has, err := hasAccess(e, userID, repo, AccessModeRead)
if err != nil { if err != nil {
return err return err
} else if has { } else if has {
@@ -700,14 +700,6 @@ func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
return x.Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser)) return x.Where("uid=?", userID).In("team_id", teamIDs).Exist(new(TeamUser))
} }
// 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 {
return 0, err
}
return
}
// ___________ __________ // ___________ __________
// \__ ___/___ _____ _____\______ \ ____ ______ ____ // \__ ___/___ _____ _____\______ \ ____ ______ ____
// | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \ // | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \

View File

@@ -243,7 +243,7 @@ func TestDeleteTeam(t *testing.T) {
// check that team members don't have "leftover" access to repos // check that team members don't have "leftover" access to repos
user := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User) user := AssertExistsAndLoadBean(t, &User{ID: 4}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) repo := AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository)
accessMode, err := AccessLevel(user, repo) accessMode, err := AccessLevel(user.ID, repo)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, accessMode < AccessModeWrite) assert.True(t, accessMode < AccessModeWrite)
} }
@@ -346,17 +346,3 @@ func TestHasTeamRepo(t *testing.T) {
test(2, 3, true) test(2, 3, true)
test(2, 5, false) test(2, 5, false)
} }
func TestUsersInTeamsCount(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
test := func(teamIDs []int64, userIDs []int64, expected int64) {
count, err := UsersInTeamsCount(teamIDs, userIDs)
assert.NoError(t, err)
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)
}

View File

@@ -84,10 +84,9 @@ func TestUser_GetTeams(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
assert.NoError(t, org.GetTeams()) assert.NoError(t, org.GetTeams())
if assert.Len(t, org.Teams, 3) { if assert.Len(t, org.Teams, 2) {
assert.Equal(t, int64(1), org.Teams[0].ID) assert.Equal(t, int64(1), org.Teams[0].ID)
assert.Equal(t, int64(2), org.Teams[1].ID) assert.Equal(t, int64(2), org.Teams[1].ID)
assert.Equal(t, int64(7), org.Teams[2].ID)
} }
} }

View File

@@ -67,7 +67,6 @@ type PullRequest struct {
HeadUserName string HeadUserName string
HeadBranch string HeadBranch string
BaseBranch string BaseBranch string
ProtectedBranch *ProtectedBranch `xorm:"-"`
MergeBase string `xorm:"VARCHAR(40)"` MergeBase string `xorm:"VARCHAR(40)"`
HasMerged bool `xorm:"INDEX"` HasMerged bool `xorm:"INDEX"`
@@ -111,21 +110,6 @@ func (pr *PullRequest) loadIssue(e Engine) (err error) {
return err return err
} }
// LoadProtectedBranch loads the protected branch of the base branch
func (pr *PullRequest) LoadProtectedBranch() (err error) {
if pr.BaseRepo == nil {
if pr.BaseRepoID == 0 {
return nil
}
pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
if err != nil {
return
}
}
pr.ProtectedBranch, err = GetProtectedBranchBy(pr.BaseRepo.ID, pr.BaseBranch)
return
}
// GetDefaultMergeMessage returns default message used when merging pull request // GetDefaultMergeMessage returns default message used when merging pull request
func (pr *PullRequest) GetDefaultMergeMessage() string { func (pr *PullRequest) GetDefaultMergeMessage() string {
if pr.HeadRepo == nil { if pr.HeadRepo == nil {
@@ -157,10 +141,6 @@ func (pr *PullRequest) GetGitRefName() string {
// Required - Issue // Required - Issue
// Optional - Merger // Optional - Merger
func (pr *PullRequest) APIFormat() *api.PullRequest { func (pr *PullRequest) APIFormat() *api.PullRequest {
return pr.apiFormat(x)
}
func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
var ( var (
baseBranch *Branch baseBranch *Branch
headBranch *Branch headBranch *Branch
@@ -168,20 +148,16 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
headCommit *git.Commit headCommit *git.Commit
err error err error
) )
if err = pr.Issue.loadRepo(e); err != nil { apiIssue := pr.Issue.APIFormat()
log.Error(log.ERROR, "loadRepo[%d]: %v", pr.ID, err)
return nil
}
apiIssue := pr.Issue.apiFormat(e)
if pr.BaseRepo == nil { if pr.BaseRepo == nil {
pr.BaseRepo, err = getRepositoryByID(e, pr.BaseRepoID) pr.BaseRepo, err = GetRepositoryByID(pr.BaseRepoID)
if err != nil { if err != nil {
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err) log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
return nil return nil
} }
} }
if pr.HeadRepo == nil { if pr.HeadRepo == nil {
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID) pr.HeadRepo, err = GetRepositoryByID(pr.HeadRepoID)
if err != nil { if err != nil {
log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err) log.Error(log.ERROR, "GetRepositoryById[%d]: %v", pr.ID, err)
return nil return nil
@@ -204,18 +180,15 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
Ref: pr.BaseBranch, Ref: pr.BaseBranch,
Sha: baseCommit.ID.String(), Sha: baseCommit.ID.String(),
RepoID: pr.BaseRepoID, RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false), Repository: pr.BaseRepo.APIFormat(AccessModeNone),
} }
apiHeadBranchInfo := &api.PRBranchInfo{ apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch, Name: pr.HeadBranch,
Ref: pr.HeadBranch, Ref: pr.HeadBranch,
Sha: headCommit.ID.String(), Sha: headCommit.ID.String(),
RepoID: pr.HeadRepoID, RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false), Repository: pr.HeadRepo.APIFormat(AccessModeNone),
} }
pr.Issue.loadRepo(e)
apiPullRequest := &api.PullRequest{ apiPullRequest := &api.PullRequest{
ID: pr.ID, ID: pr.ID,
Index: pr.Index, Index: pr.Index,
@@ -297,8 +270,6 @@ const (
MergeStyleMerge MergeStyle = "merge" MergeStyleMerge MergeStyle = "merge"
// MergeStyleRebase rebase before merging // MergeStyleRebase rebase before merging
MergeStyleRebase MergeStyle = "rebase" MergeStyleRebase MergeStyle = "rebase"
// MergeStyleRebaseMerge rebase before merging with merge commit (--no-ff)
MergeStyleRebaseMerge MergeStyle = "rebase-merge"
// MergeStyleSquash squash commits into single commit before merging // MergeStyleSquash squash commits into single commit before merging
MergeStyleSquash MergeStyle = "squash" MergeStyleSquash MergeStyle = "squash"
) )
@@ -317,7 +288,7 @@ func (pr *PullRequest) CheckUserAllowedToMerge(doer *User) (err error) {
} }
} }
if protected, err := pr.BaseRepo.IsProtectedBranchForMerging(pr, pr.BaseBranch, doer); err != nil { if protected, err := pr.BaseRepo.IsProtectedBranchForMerging(pr.BaseBranch, doer); err != nil {
return fmt.Errorf("IsProtectedBranch: %v", err) return fmt.Errorf("IsProtectedBranch: %v", err)
} else if protected { } else if protected {
return ErrNotAllowedToMerge{ return ErrNotAllowedToMerge{
@@ -436,41 +407,6 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
"git", "merge", "--ff-only", "-q", "head_repo_"+pr.HeadBranch); err != nil { "git", "merge", "--ff-only", "-q", "head_repo_"+pr.HeadBranch); err != nil {
return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr) return fmt.Errorf("git merge --ff-only [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
} }
case MergeStyleRebaseMerge:
// Checkout head branch
if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
"git", "checkout", "-b", "head_repo_"+pr.HeadBranch, "head_repo/"+pr.HeadBranch); err != nil {
return fmt.Errorf("git checkout: %s", stderr)
}
// Rebase before merging
if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git rebase): %s", tmpBasePath),
"git", "rebase", "-q", pr.BaseBranch); err != nil {
return fmt.Errorf("git rebase [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
// Checkout base branch again
if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git checkout): %s", tmpBasePath),
"git", "checkout", pr.BaseBranch); err != nil {
return fmt.Errorf("git checkout: %s", stderr)
}
// Prepare merge with commit
if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git merge): %s", tmpBasePath),
"git", "merge", "--no-ff", "--no-commit", "-q", "head_repo_"+pr.HeadBranch); err != nil {
return fmt.Errorf("git merge --no-ff [%s -> %s]: %s", headRepoPath, tmpBasePath, stderr)
}
// Set custom message and author and create merge commit
sig := doer.NewGitSig()
if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
fmt.Sprintf("PullRequest.Merge (git commit): %s", tmpBasePath),
"git", "commit", fmt.Sprintf("--author='%s <%s>'", sig.Name, sig.Email),
"-m", message); err != nil {
return fmt.Errorf("git commit [%s]: %v - %s", tmpBasePath, err, stderr)
}
case MergeStyleSquash: case MergeStyleSquash:
// Merge with squash // Merge with squash
if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath, if _, stderr, err = process.GetManager().ExecDir(-1, tmpBasePath,
@@ -522,7 +458,7 @@ func (pr *PullRequest) Merge(doer *User, baseGitRepo *git.Repository, mergeStyle
return nil return nil
} }
mode, _ := AccessLevel(doer, pr.Issue.Repo) mode, _ := AccessLevel(doer.ID, pr.Issue.Repo)
if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{ if err = PrepareWebhooks(pr.Issue.Repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueClosed, Action: api.HookIssueClosed,
Index: pr.Index, Index: pr.Index,
@@ -599,7 +535,7 @@ func (pr *PullRequest) setMerged() (err error) {
return err return err
} }
if err = pr.Issue.changeStatus(sess, pr.Merger, true); err != nil { if err = pr.Issue.changeStatus(sess, pr.Merger, pr.Issue.Repo, true); err != nil {
return fmt.Errorf("Issue.changeStatus: %v", err) return fmt.Errorf("Issue.changeStatus: %v", err)
} }
if _, err = sess.ID(pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil { if _, err = sess.ID(pr.ID).Cols("has_merged, status, merged_commit_id, merger_id, merged_unix").Update(pr); err != nil {
@@ -851,7 +787,7 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
pr.Issue = pull pr.Issue = pull
pull.PullRequest = pr pull.PullRequest = pr
mode, _ := AccessLevel(pull.Poster, repo) mode, _ := AccessLevel(pull.Poster.ID, repo)
if err = PrepareWebhooks(repo, HookEventPullRequest, &api.PullRequestPayload{ if err = PrepareWebhooks(repo, HookEventPullRequest, &api.PullRequestPayload{
Action: api.HookIssueOpened, Action: api.HookIssueOpened,
Index: pull.Index, Index: pull.Index,

View File

@@ -200,7 +200,7 @@ func CreateRelease(gitRepo *git.Repository, rel *Release, attachmentUUIDs []stri
if err := rel.LoadAttributes(); err != nil { if err := rel.LoadAttributes(); err != nil {
log.Error(2, "LoadAttributes: %v", err) log.Error(2, "LoadAttributes: %v", err)
} else { } else {
mode, _ := AccessLevel(rel.Publisher, rel.Repo) mode, _ := AccessLevel(rel.PublisherID, rel.Repo)
if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{ if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
Action: api.HookReleasePublished, Action: api.HookReleasePublished,
Release: rel.APIFormat(), Release: rel.APIFormat(),
@@ -392,7 +392,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
err = addReleaseAttachments(rel.ID, attachmentUUIDs) err = addReleaseAttachments(rel.ID, attachmentUUIDs)
mode, _ := AccessLevel(doer, rel.Repo) mode, _ := accessLevel(x, doer.ID, rel.Repo)
if err1 := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{ if err1 := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
Action: api.HookReleaseUpdated, Action: api.HookReleaseUpdated,
Release: rel.APIFormat(), Release: rel.APIFormat(),
@@ -419,6 +419,13 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error {
return fmt.Errorf("GetRepositoryByID: %v", err) return fmt.Errorf("GetRepositoryByID: %v", err)
} }
has, err := HasAccess(u.ID, repo, AccessModeWrite)
if err != nil {
return fmt.Errorf("HasAccess: %v", err)
} else if !has {
return fmt.Errorf("DeleteReleaseByID: permission denied")
}
if delTag { if delTag {
_, stderr, err := process.GetManager().ExecDir(-1, repo.RepoPath(), _, stderr, err := process.GetManager().ExecDir(-1, repo.RepoPath(),
fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID), fmt.Sprintf("DeleteReleaseByID (git tag -d): %d", rel.ID),
@@ -447,7 +454,7 @@ func DeleteReleaseByID(id int64, u *User, delTag bool) error {
return fmt.Errorf("LoadAttributes: %v", err) return fmt.Errorf("LoadAttributes: %v", err)
} }
mode, _ := AccessLevel(u, rel.Repo) mode, _ := accessLevel(x, u.ID, rel.Repo)
if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{ if err := PrepareWebhooks(rel.Repo, HookEventRelease, &api.ReleasePayload{
Action: api.HookReleaseDeleted, Action: api.HookReleaseDeleted,
Release: rel.APIFormat(), Release: rel.APIFormat(),
@@ -479,10 +486,10 @@ func SyncReleasesWithTags(repo *Repository, gitRepo *git.Repository) error {
continue continue
} }
commitID, err := gitRepo.GetTagCommitID(rel.TagName) commitID, err := gitRepo.GetTagCommitID(rel.TagName)
if err != nil && !git.IsErrNotExist(err) { if err != nil {
return fmt.Errorf("GetTagCommitID: %v", err) return fmt.Errorf("GetTagCommitID: %v", err)
} }
if git.IsErrNotExist(err) || commitID != rel.Sha1 { if !gitRepo.IsTagExist(rel.TagName) || commitID != rel.Sha1 {
if err := pushUpdateDeleteTag(repo, gitRepo, rel.TagName); err != nil { if err := pushUpdateDeleteTag(repo, gitRepo, rel.TagName); err != nil {
return fmt.Errorf("pushUpdateDeleteTag: %v", err) return fmt.Errorf("pushUpdateDeleteTag: %v", err)
} }

View File

@@ -94,58 +94,3 @@ func TestRelease_Create(t *testing.T) {
IsTag: true, IsTag: true,
}, nil)) }, nil))
} }
func TestRelease_MirrorDelete(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
repoPath := RepoPath(user.Name, repo.Name)
migrationOptions := MigrateRepoOptions{
Name: "test_mirror",
Description: "Test mirror",
IsPrivate: false,
IsMirror: true,
RemoteAddr: repoPath,
}
mirror, err := MigrateRepository(user, user, migrationOptions)
assert.NoError(t, err)
gitRepo, err := git.OpenRepository(repoPath)
assert.NoError(t, err)
findOptions := FindReleasesOptions{IncludeDrafts: true, IncludeTags: true}
initCount, err := GetReleaseCountByRepoID(mirror.ID, findOptions)
assert.NoError(t, err)
assert.NoError(t, CreateRelease(gitRepo, &Release{
RepoID: repo.ID,
PublisherID: user.ID,
TagName: "v0.2",
Target: "master",
Title: "v0.2 is released",
Note: "v0.2 is released",
IsDraft: false,
IsPrerelease: false,
IsTag: true,
}, nil))
err = mirror.GetMirror()
assert.NoError(t, err)
_, ok := mirror.Mirror.runSync()
assert.True(t, ok)
count, err := GetReleaseCountByRepoID(mirror.ID, findOptions)
assert.EqualValues(t, initCount+1, count)
release, err := GetRelease(repo.ID, "v0.2")
assert.NoError(t, err)
assert.NoError(t, DeleteReleaseByID(release.ID, user, true))
_, ok = mirror.Mirror.runSync()
assert.True(t, ok)
count, err = GetReleaseCountByRepoID(mirror.ID, findOptions)
assert.EqualValues(t, initCount, count)
}

View File

@@ -252,7 +252,7 @@ func (repo *Repository) APIURL() string {
// APIFormat converts a Repository to api.Repository // APIFormat converts a Repository to api.Repository
func (repo *Repository) APIFormat(mode AccessMode) *api.Repository { func (repo *Repository) APIFormat(mode AccessMode) *api.Repository {
return repo.innerAPIFormat(x, mode, false) return repo.innerAPIFormat(mode, false)
} }
// GetCommitsCountCacheKey returns cache key used for commits count caching. // GetCommitsCountCacheKey returns cache key used for commits count caching.
@@ -266,22 +266,22 @@ func (repo *Repository) GetCommitsCountCacheKey(contextName string, isRef bool)
return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName) return fmt.Sprintf("commits-count-%d-%s-%s", repo.ID, prefix, contextName)
} }
func (repo *Repository) innerAPIFormat(e Engine, mode AccessMode, isParent bool) *api.Repository { func (repo *Repository) innerAPIFormat(mode AccessMode, isParent bool) *api.Repository {
var parent *api.Repository var parent *api.Repository
cloneLink := repo.cloneLink(e, false) cloneLink := repo.CloneLink()
permission := &api.Permission{ permission := &api.Permission{
Admin: mode >= AccessModeAdmin, Admin: mode >= AccessModeAdmin,
Push: mode >= AccessModeWrite, Push: mode >= AccessModeWrite,
Pull: mode >= AccessModeRead, Pull: mode >= AccessModeRead,
} }
if !isParent { if !isParent {
err := repo.getBaseRepo(e) err := repo.GetBaseRepo()
if err != nil { if err != nil {
log.Error(4, "APIFormat: %v", err) log.Error(4, "APIFormat: %v", err)
} }
if repo.BaseRepo != nil { if repo.BaseRepo != nil {
parent = repo.BaseRepo.innerAPIFormat(e, mode, true) parent = repo.BaseRepo.innerAPIFormat(mode, true)
} }
} }
return &api.Repository{ return &api.Repository{
@@ -326,19 +326,63 @@ func (repo *Repository) CheckUnitUser(userID int64, isAdmin bool, unitType UnitT
} }
func (repo *Repository) checkUnitUser(e Engine, userID int64, isAdmin bool, unitType UnitType) bool { func (repo *Repository) checkUnitUser(e Engine, userID int64, isAdmin bool, unitType UnitType) bool {
if isAdmin { if err := repo.getUnitsByUserID(e, userID, isAdmin); err != nil {
return true
}
user, err := getUserByID(e, userID)
if err != nil {
return false
}
perm, err := getUserRepoPermission(e, repo, user)
if err != nil {
return false return false
} }
return perm.CanRead(unitType) for _, unit := range repo.Units {
if unit.Type == unitType {
return true
}
}
return false
}
// LoadUnitsByUserID loads units according userID's permissions
func (repo *Repository) LoadUnitsByUserID(userID int64, isAdmin bool) error {
return repo.getUnitsByUserID(x, userID, isAdmin)
}
func (repo *Repository) getUnitsByUserID(e Engine, userID int64, isAdmin bool) (err error) {
if repo.Units != nil {
return nil
}
if err = repo.getUnits(e); err != nil {
return err
} else if err = repo.getOwner(e); err != nil {
return err
}
if !repo.Owner.IsOrganization() || userID == 0 || isAdmin || !repo.IsPrivate {
return nil
}
// Collaborators will not be limited
if isCollaborator, err := repo.isCollaborator(e, userID); err != nil {
return err
} else if isCollaborator {
return nil
}
teams, err := getUserRepoTeams(e, repo.OwnerID, userID, repo.ID)
if err != nil {
return err
}
// unique
var newRepoUnits = make([]*RepoUnit, 0, len(repo.Units))
for _, u := range repo.Units {
for _, team := range teams {
if team.unitEnabled(e, u.Type) {
newRepoUnits = append(newRepoUnits, u)
break
}
}
}
repo.Units = newRepoUnits
return nil
} }
// UnitEnabled if this repository has the given unit enabled // UnitEnabled if this repository has the given unit enabled
@@ -354,6 +398,21 @@ func (repo *Repository) UnitEnabled(tp UnitType) bool {
return false return false
} }
// AnyUnitEnabled if this repository has the any of the given units enabled
func (repo *Repository) AnyUnitEnabled(tps ...UnitType) bool {
if err := repo.getUnits(x); err != nil {
log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error())
}
for _, unit := range repo.Units {
for _, tp := range tps {
if unit.Type == tp {
return true
}
}
}
return false
}
var ( var (
// ErrUnitNotExist organization does not exist // ErrUnitNotExist organization does not exist
ErrUnitNotExist = errors.New("Unit does not exist") ErrUnitNotExist = errors.New("Unit does not exist")
@@ -390,11 +449,7 @@ func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit {
// GetUnit returns a RepoUnit object // GetUnit returns a RepoUnit object
func (repo *Repository) GetUnit(tp UnitType) (*RepoUnit, error) { func (repo *Repository) GetUnit(tp UnitType) (*RepoUnit, error) {
return repo.getUnit(x, tp) if err := repo.getUnits(x); err != nil {
}
func (repo *Repository) getUnit(e Engine, tp UnitType) (*RepoUnit, error) {
if err := repo.getUnits(e); err != nil {
return nil, err return nil, err
} }
for _, unit := range repo.Units { for _, unit := range repo.Units {
@@ -542,6 +597,11 @@ func (repo *Repository) GetAssignees() (_ []*User, err error) {
return repo.getAssignees(x) return repo.getAssignees(x)
} }
// GetUserIfHasWriteAccess returns the user that has write access of repository by given ID.
func (repo *Repository) GetUserIfHasWriteAccess(userID int64) (*User, error) {
return GetUserIfHasWriteAccess(repo, userID)
}
// GetMilestoneByID returns the milestone belongs to repository by given ID. // GetMilestoneByID returns the milestone belongs to repository by given ID.
func (repo *Repository) GetMilestoneByID(milestoneID int64) (*Milestone, error) { func (repo *Repository) GetMilestoneByID(milestoneID int64) (*Milestone, error) {
return GetMilestoneByRepoID(repo.ID, milestoneID) return GetMilestoneByRepoID(repo.ID, milestoneID)
@@ -562,15 +622,11 @@ func (repo *Repository) GetMirror() (err error) {
// returns an error on failure (NOTE: no error is returned for // returns an error on failure (NOTE: no error is returned for
// non-fork repositories, and BaseRepo will be left untouched) // non-fork repositories, and BaseRepo will be left untouched)
func (repo *Repository) GetBaseRepo() (err error) { func (repo *Repository) GetBaseRepo() (err error) {
return repo.getBaseRepo(x)
}
func (repo *Repository) getBaseRepo(e Engine) (err error) {
if !repo.IsFork { if !repo.IsFork {
return nil return nil
} }
repo.BaseRepo, err = getRepositoryByID(e, repo.ForkID) repo.BaseRepo, err = GetRepositoryByID(repo.ForkID)
return err return err
} }
@@ -608,6 +664,12 @@ func (repo *Repository) ComposeCompareURL(oldCommitID, newCommitID string) strin
return fmt.Sprintf("%s/%s/compare/%s...%s", repo.MustOwner().Name, repo.Name, oldCommitID, newCommitID) return fmt.Sprintf("%s/%s/compare/%s...%s", repo.MustOwner().Name, repo.Name, oldCommitID, newCommitID)
} }
// HasAccess returns true when user has access to this repository
func (repo *Repository) HasAccess(u *User) bool {
has, _ := HasAccess(u.ID, repo, AccessModeRead)
return has
}
// UpdateDefaultBranch updates the default branch // UpdateDefaultBranch updates the default branch
func (repo *Repository) UpdateDefaultBranch() error { func (repo *Repository) UpdateDefaultBranch() error {
_, err := x.ID(repo.ID).Cols("default_branch").Update(repo) _, err := x.ID(repo.ID).Cols("default_branch").Update(repo)
@@ -635,6 +697,11 @@ func (repo *Repository) UpdateSize() error {
return repo.updateSize(x) return repo.updateSize(x)
} }
// CanBeForked returns true if repository meets the requirements of being forked.
func (repo *Repository) CanBeForked() bool {
return !repo.IsBare && repo.UnitEnabled(UnitTypeCode)
}
// CanUserFork returns true if specified user can fork repository. // CanUserFork returns true if specified user can fork repository.
func (repo *Repository) CanUserFork(user *User) (bool, error) { func (repo *Repository) CanUserFork(user *User) (bool, error) {
if user == nil { if user == nil {
@@ -827,7 +894,7 @@ func ComposeHTTPSCloneURL(owner, repo string) string {
return fmt.Sprintf("%s%s/%s.git", setting.AppURL, owner, repo) return fmt.Sprintf("%s%s/%s.git", setting.AppURL, owner, repo)
} }
func (repo *Repository) cloneLink(e Engine, isWiki bool) *CloneLink { func (repo *Repository) cloneLink(isWiki bool) *CloneLink {
repoName := repo.Name repoName := repo.Name
if isWiki { if isWiki {
repoName += ".wiki" repoName += ".wiki"
@@ -838,7 +905,7 @@ func (repo *Repository) cloneLink(e Engine, isWiki bool) *CloneLink {
sshUser = setting.SSH.BuiltinServerUser sshUser = setting.SSH.BuiltinServerUser
} }
repo.Owner = repo.mustOwner(e) repo.Owner = repo.MustOwner()
cl := new(CloneLink) cl := new(CloneLink)
if setting.SSH.Port != 22 { if setting.SSH.Port != 22 {
cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", sshUser, setting.SSH.Domain, setting.SSH.Port, repo.Owner.Name, repoName) cl.SSH = fmt.Sprintf("ssh://%s@%s:%d/%s/%s.git", sshUser, setting.SSH.Domain, setting.SSH.Port, repo.Owner.Name, repoName)
@@ -853,7 +920,7 @@ func (repo *Repository) cloneLink(e Engine, isWiki bool) *CloneLink {
// CloneLink returns clone URLs of repository. // CloneLink returns clone URLs of repository.
func (repo *Repository) CloneLink() (cl *CloneLink) { func (repo *Repository) CloneLink() (cl *CloneLink) {
return repo.cloneLink(x, false) return repo.cloneLink(false)
} }
// MigrateRepoOptions contains the repository migrate options // MigrateRepoOptions contains the repository migrate options
@@ -1135,7 +1202,7 @@ func getRepoInitFile(tp, name string) ([]byte, error) {
} }
} }
func prepareRepoCommit(e Engine, repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error { func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error {
// Clone to temporary path and do the init commit. // Clone to temporary path and do the init commit.
_, stderr, err := process.GetManager().Exec( _, stderr, err := process.GetManager().Exec(
fmt.Sprintf("initRepository(git clone): %s", repoPath), fmt.Sprintf("initRepository(git clone): %s", repoPath),
@@ -1151,7 +1218,7 @@ func prepareRepoCommit(e Engine, repo *Repository, tmpDir, repoPath string, opts
return fmt.Errorf("getRepoInitFile[%s]: %v", opts.Readme, err) return fmt.Errorf("getRepoInitFile[%s]: %v", opts.Readme, err)
} }
cloneLink := repo.cloneLink(e, false) cloneLink := repo.CloneLink()
match := map[string]string{ match := map[string]string{
"Name": repo.Name, "Name": repo.Name,
"Description": repo.Description, "Description": repo.Description,
@@ -1224,7 +1291,7 @@ func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts C
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
if err = prepareRepoCommit(e, repo, tmpDir, repoPath, opts); err != nil { if err = prepareRepoCommit(repo, tmpDir, repoPath, opts); err != nil {
return fmt.Errorf("prepareRepoCommit: %v", err) return fmt.Errorf("prepareRepoCommit: %v", err)
} }
@@ -1298,7 +1365,7 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
units = append(units, RepoUnit{ units = append(units, RepoUnit{
RepoID: repo.ID, RepoID: repo.ID,
Type: tp, Type: tp,
Config: &PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true}, Config: &PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowSquash: true},
}) })
} else { } else {
units = append(units, RepoUnit{ units = append(units, RepoUnit{
@@ -1329,7 +1396,7 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
return fmt.Errorf("addRepository: %v", err) return fmt.Errorf("addRepository: %v", err)
} else if err = prepareWebhooks(e, repo, HookEventRepository, &api.RepositoryPayload{ } else if err = prepareWebhooks(e, repo, HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated, Action: api.HookRepoCreated,
Repository: repo.innerAPIFormat(e, AccessModeOwner, false), Repository: repo.APIFormat(AccessModeOwner),
Organization: u.APIFormat(), Organization: u.APIFormat(),
Sender: doer.APIFormat(), Sender: doer.APIFormat(),
}); err != nil { }); err != nil {
@@ -2413,8 +2480,8 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
return nil, err return nil, err
} }
oldMode, _ := AccessLevel(doer, oldRepo) oldMode, _ := AccessLevel(doer.ID, oldRepo)
mode, _ := AccessLevel(doer, repo) mode, _ := AccessLevel(doer.ID, repo)
if err = PrepareWebhooks(oldRepo, HookEventFork, &api.ForkPayload{ if err = PrepareWebhooks(oldRepo, HookEventFork, &api.ForkPayload{
Forkee: oldRepo.APIFormat(oldMode), Forkee: oldRepo.APIFormat(oldMode),

View File

@@ -63,11 +63,7 @@ func (m *Mirror) AfterLoad(session *xorm.Session) {
// ScheduleNextUpdate calculates and sets next update time. // ScheduleNextUpdate calculates and sets next update time.
func (m *Mirror) ScheduleNextUpdate() { func (m *Mirror) ScheduleNextUpdate() {
if m.Interval != 0 {
m.NextUpdateUnix = util.TimeStampNow().AddDuration(m.Interval) m.NextUpdateUnix = util.TimeStampNow().AddDuration(m.Interval)
} else {
m.NextUpdateUnix = 0
}
} }
func remoteAddress(repoPath string) (string, error) { func remoteAddress(repoPath string) (string, error) {
@@ -306,7 +302,6 @@ func MirrorUpdate() {
if err := x. if err := x.
Where("next_update_unix<=?", time.Now().Unix()). Where("next_update_unix<=?", time.Now().Unix()).
And("next_update_unix!=0").
Iterate(new(Mirror), func(idx int, bean interface{}) error { Iterate(new(Mirror), func(idx int, bean interface{}) error {
m := bean.(*Mirror) m := bean.(*Mirror)
if m.Repo == nil { if m.Repo == nil {

View File

@@ -1,270 +0,0 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
// Permission contains all the permissions related variables to a repository for a user
type Permission struct {
AccessMode AccessMode
Units []*RepoUnit
UnitsMode map[UnitType]AccessMode
}
// IsOwner returns true if current user is the owner of repository.
func (p *Permission) IsOwner() bool {
return p.AccessMode >= AccessModeOwner
}
// IsAdmin returns true if current user has admin or higher access of repository.
func (p *Permission) IsAdmin() bool {
return p.AccessMode >= AccessModeAdmin
}
// HasAccess returns true if the current user has at least read access to any unit of this repository
func (p *Permission) HasAccess() bool {
if p.UnitsMode == nil {
return p.AccessMode >= AccessModeRead
}
return len(p.UnitsMode) > 0
}
// UnitAccessMode returns current user accessmode to the specify unit of the repository
func (p *Permission) UnitAccessMode(unitType UnitType) AccessMode {
if p.UnitsMode == nil {
for _, u := range p.Units {
if u.Type == unitType {
return p.AccessMode
}
}
return AccessModeNone
}
return p.UnitsMode[unitType]
}
// CanAccess returns true if user has mode access to the unit of the repository
func (p *Permission) CanAccess(mode AccessMode, unitType UnitType) bool {
return p.UnitAccessMode(unitType) >= mode
}
// CanAccessAny returns true if user has mode access to any of the units of the repository
func (p *Permission) CanAccessAny(mode AccessMode, unitTypes ...UnitType) bool {
for _, u := range unitTypes {
if p.CanAccess(mode, u) {
return true
}
}
return false
}
// CanRead returns true if user could read to this unit
func (p *Permission) CanRead(unitType UnitType) bool {
return p.CanAccess(AccessModeRead, unitType)
}
// CanReadAny returns true if user has read access to any of the units of the repository
func (p *Permission) CanReadAny(unitTypes ...UnitType) bool {
return p.CanAccessAny(AccessModeRead, unitTypes...)
}
// CanReadIssuesOrPulls returns true if isPull is true and user could read pull requests and
// returns true if isPull is false and user could read to issues
func (p *Permission) CanReadIssuesOrPulls(isPull bool) bool {
if isPull {
return p.CanRead(UnitTypePullRequests)
}
return p.CanRead(UnitTypeIssues)
}
// CanWrite returns true if user could write to this unit
func (p *Permission) CanWrite(unitType UnitType) bool {
return p.CanAccess(AccessModeWrite, unitType)
}
// CanWriteIssuesOrPulls returns true if isPull is true and user could write to pull requests and
// returns true if isPull is false and user could write to issues
func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool {
if isPull {
return p.CanWrite(UnitTypePullRequests)
}
return p.CanWrite(UnitTypeIssues)
}
// GetUserRepoPermission returns the user permissions to the repository
func GetUserRepoPermission(repo *Repository, user *User) (Permission, error) {
return getUserRepoPermission(x, repo, user)
}
func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permission, err error) {
// anonymous user visit private repo.
// TODO: anonymous user visit public unit of private repo???
if user == nil && repo.IsPrivate {
perm.AccessMode = AccessModeNone
return
}
if err = repo.getUnits(e); err != nil {
return
}
perm.Units = repo.Units
// anonymous visit public repo
if user == nil {
perm.AccessMode = AccessModeRead
return
}
// Admin or the owner has super access to the repository
if user.IsAdmin || user.ID == repo.OwnerID {
perm.AccessMode = AccessModeOwner
return
}
// plain user
perm.AccessMode, err = accessLevel(e, user.ID, repo)
if err != nil {
return
}
if err = repo.getOwner(e); err != nil {
return
}
if !repo.Owner.IsOrganization() {
return
}
perm.UnitsMode = make(map[UnitType]AccessMode)
// Collaborators on organization
if isCollaborator, err := repo.isCollaborator(e, user.ID); err != nil {
return perm, err
} else if isCollaborator {
for _, u := range repo.Units {
perm.UnitsMode[u.Type] = perm.AccessMode
}
}
// get units mode from teams
teams, err := getUserRepoTeams(e, repo.OwnerID, user.ID, repo.ID)
if err != nil {
return
}
for _, u := range repo.Units {
var found bool
for _, team := range teams {
if team.unitEnabled(e, u.Type) {
m := perm.UnitsMode[u.Type]
if m < team.Authorize {
perm.UnitsMode[u.Type] = team.Authorize
}
found = true
}
}
// for a public repo on an organization, user have read permission on non-team defined units.
if !found && !repo.IsPrivate {
if _, ok := perm.UnitsMode[u.Type]; !ok {
perm.UnitsMode[u.Type] = AccessModeRead
}
}
}
// remove no permission units
perm.Units = make([]*RepoUnit, 0, len(repo.Units))
for t := range perm.UnitsMode {
for _, u := range repo.Units {
if u.Type == t {
perm.Units = append(perm.Units, u)
}
}
}
return
}
// IsUserRepoAdmin return ture if user has admin right of a repo
func IsUserRepoAdmin(repo *Repository, user *User) (bool, error) {
return isUserRepoAdmin(x, repo, user)
}
func isUserRepoAdmin(e Engine, repo *Repository, user *User) (bool, error) {
if user == nil || repo == nil {
return false, nil
}
if user.IsAdmin {
return true, nil
}
mode, err := accessLevel(e, user.ID, repo)
if err != nil {
return false, err
}
if mode >= AccessModeAdmin {
return true, nil
}
teams, err := getUserRepoTeams(e, repo.OwnerID, user.ID, repo.ID)
if err != nil {
return false, err
}
for _, team := range teams {
if team.Authorize >= AccessModeAdmin {
return true, nil
}
}
return false, nil
}
// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
// user does not have access.
func AccessLevel(user *User, repo *Repository) (AccessMode, error) {
return accessLevelUnit(x, user, repo, UnitTypeCode)
}
func accessLevelUnit(e Engine, user *User, repo *Repository, unitType UnitType) (AccessMode, error) {
perm, err := getUserRepoPermission(e, repo, user)
if err != nil {
return AccessModeNone, err
}
return perm.UnitAccessMode(UnitTypeCode), nil
}
func hasAccessUnit(e Engine, user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {
mode, err := accessLevelUnit(e, user, repo, unitType)
return testMode <= mode, err
}
// HasAccessUnit returns ture if user has testMode to the unit of the repository
func HasAccessUnit(user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {
return hasAccessUnit(x, user, repo, unitType, testMode)
}
// canBeAssigned return true if user could be assigned to a repo
// FIXME: user could send PullRequest also could be assigned???
func canBeAssigned(e Engine, user *User, repo *Repository) (bool, error) {
return hasAccessUnit(e, user, repo, UnitTypeCode, AccessModeWrite)
}
func hasAccess(e Engine, userID int64, repo *Repository) (bool, error) {
var user *User
var err error
if userID > 0 {
user, err = getUserByID(e, userID)
if err != nil {
return false, err
}
}
perm, err := getUserRepoPermission(e, repo, user)
if err != nil {
return false, err
}
return perm.HasAccess(), nil
}
// HasAccess returns true if user has access to repo
func HasAccess(userID int64, repo *Repository) (bool, error) {
return hasAccess(x, userID, repo)
}

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