Compare commits

...

42 Commits

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

* Fix ref to 8071

* Correct punctuation

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

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

* Apply suggested changes from #8100

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

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

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

* Generate css via command

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

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

* Add docker-linux-arm64 pipeline

* add arm 64 build to manifest

* tag dry-run + indent

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

* test returned locked_at values

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

* Update CHANGELOG.md

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

* mention releases build by go1.12.8

* Update CHANGELOG.md

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

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

* search refs before passing sha

* adjust tests

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

* fix comment

* de-duplicate code

* test: use relative setting.AppURL

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

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

* remove return

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

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

* fix tests

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

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

* golang-ci fixes

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

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

* Include "executable" files in the index, as they are not necessarily binary
2019-08-02 22:40:15 +08:00
Lunny Xiao
d15e49f7ff improve branches list performance and fix protected branch icon when no-login (#7695) (#7704) 2019-08-01 11:40:00 -04:00
zeripath
39da4ac6d4 Correct wrong datetime format for git (#7689) (#7690) 2019-07-31 22:13:15 +01:00
70 changed files with 724 additions and 440 deletions

View File

@@ -362,7 +362,7 @@ steps:
- name: static
pull: always
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.12.x
commands:
- export PATH=$PATH:$GOPATH/bin
- make generate
@@ -463,7 +463,7 @@ steps:
- name: static
pull: always
image: techknowlogick/xgo:latest
image: techknowlogick/xgo:go-1.12.x
commands:
- export PATH=$PATH:$GOPATH/bin
- make generate
@@ -558,7 +558,7 @@ steps:
---
kind: pipeline
name: docker
name: docker-linux-amd64
platform:
os: linux
@@ -594,6 +594,7 @@ steps:
settings:
dry_run: true
repo: gitea/gitea
tags: linux-amd64
when:
event:
- pull_request
@@ -603,6 +604,7 @@ steps:
image: plugins/docker:linux-amd64
settings:
auto_tag: true
auto_tag_suffix: linux-amd64
repo: gitea/gitea
password:
from_secret: docker_password
@@ -613,6 +615,97 @@ steps:
exclude:
- pull_request
---
kind: pipeline
name: docker-linux-arm64
platform:
os: linux
arch: arm64
workspace:
base: /go
path: src/code.gitea.io/gitea
depends_on:
- testing
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
- "refs/pull/**"
steps:
- name: fetch-tags
pull: default
image: docker:git
commands:
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: dryrun
pull: always
image: plugins/docker:linux-arm64
settings:
dry_run: true
repo: gitea/gitea
tags: linux-arm64
when:
event:
- pull_request
- name: publish
pull: always
image: plugins/docker:linux-arm64
settings:
auto_tag: true
auto_tag_suffix: linux-arm64
repo: gitea/gitea
password:
from_secret: docker_password
username:
from_secret: docker_username
when:
event:
exclude:
- pull_request
---
kind: pipeline
name: docker-manifest
platform:
os: linux
arch: amd64
steps:
- name: manifest
pull: always
image: plugins/manifest
settings:
auto_tag: true
ignore_missing: true
spec: docker/manifest.tmpl
password:
from_secret: docker_password
username:
from_secret: docker_username
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
depends_on:
- docker-linux-amd64
- docker-linux-arm64
---
kind: pipeline
name: notify
@@ -635,7 +728,9 @@ depends_on:
- translations
- release-version
- release-master
- docker
- docker-linux-amd64
- docker-linux-arm64
- docker-manifest
- docs
steps:

View File

@@ -4,6 +4,62 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06
* BUGFIXES
* Fix go get from a private repository with Go 1.13 (#8100)
* Strict name matching for Repository.GetTagID() (#8082)
* Avoid ambiguity of branch/directory names for the git-diff-tree command (#8070)
* Add change title notification for issues (#8064)
* Run CORS handler first for /api routes (#7967) (#8053)
* Evaluate emojis in commit messages in list view (#8044)
* Fix failed to synchronize tags to releases for repository (#7990) (#7994)
* Fix adding default Telegram webhook (#7972) (#7992)
* Abort synchronization from LDAP source if there is some error (#7965)
* Fix deformed emoji in commit message (#8071)
* ENHANCEMENT
* Keep blame view buttons sequence consistent with normal view when viewing a file (#8007) (#8009)
## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22
* BUGFIXES
* Fix wrong sender when send slack webhook (#7918) (#7924)
* Upload support text/plain; charset=utf8 (#7899)
* Lfs/lock: round locked_at timestamp to second (#7872) (#7875)
* Fix non existent milestone with 500 error (#7867) (#7873)
* SECURITY
* Fix No PGP signature on 1.9.1 tag (#7874)
* Release built with go 1.12.9 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ
* ENHANCEMENT
* Fix pull creation with empty changes (#7920) (#7926)
* BUILD
* Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884)
## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14
* BREAKING
* Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752)
* SECURITY
* Be more strict with git arguments (#7715) (#7762)
* Release built with go 1.12.8 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA
* BUGFIXES
* Fix local runs of ssh-requiring integration tests (#7855) (#7857)
* Fix hook problem (#7856) (#7754)
* Use .ExpiredUnix.IsZero to display green color of forever valid gpg key (#7850) (#7846)
* Do not fetch all refs (#7797) (#7837)
* Fix duplicate call of webhook (#7824) (#7821)
* Enable switching to a different source branch when PR already exists (#7823)
* Rewrite existing repo units if setting is not included in api body (#7811)
* Prevent Commit Status and Message From Overflowing On Branch Page (#7800) (#7808)
* API: fix multiple bugs with statuses endpoints (Backport #7785) (#7807)
* Fix Slack webhook fork message (1.9 release backport) (#7783)
* Fix approvals counting (#7757) (#7777)
* Fix rename failed when rewrite public keys (#7761) (#7769)
* Fix dropTableColumns sqlite implementation (#7710) (#7765)
* Fix repo_index_status lingering when deleting a repository (#7738)
* Fix milestone completness calculation when migrating (#7725) (#7732)
* Fixes indexed repos keeping outdated indexes when files grow too large (#7731)
* Skip non-regular files (e.g. submodules) on repo indexing (#7717)
* Improve branches list performance and fix protected branch icon when no-login (#7695) (#7704)
* Correct wrong datetime format for git (#7689) (#7690)
## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
* BREAKING
* Better logging (#6038) (#6095)

View File

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

19
docker/manifest.tmpl vendored Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -598,7 +598,7 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
if err != nil {
for i := range patchConflicts {
if strings.Contains(stderr, patchConflicts[i]) {
log.Trace("PullRequest[%d].testPatch (apply): has conflict", pr.ID)
log.Trace("PullRequest[%d].testPatch (apply): has conflict: %s", pr.ID, stderr)
const prefix = "error: patch failed:"
pr.Status = PullRequestStatusConflict
pr.ConflictedFiles = make([]string, 0, 5)
@@ -661,13 +661,16 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
}
pr.Index = pull.Index
if err = repo.savePatch(sess, pr.Index, patch); err != nil {
return fmt.Errorf("SavePatch: %v", err)
}
pr.BaseRepo = repo
if err = pr.testPatch(sess); err != nil {
return fmt.Errorf("testPatch: %v", err)
pr.Status = PullRequestStatusChecking
if len(patch) > 0 {
if err = repo.savePatch(sess, pr.Index, patch); err != nil {
return fmt.Errorf("SavePatch: %v", err)
}
if err = pr.testPatch(sess); err != nil {
return fmt.Errorf("testPatch: %v", err)
}
}
// No conflict appears after test means mergeable.
if pr.Status == PullRequestStatusChecking {

View File

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

View File

@@ -1791,6 +1791,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
&HookTask{RepoID: repoID},
&Notification{RepoID: repoID},
&CommitStatus{RepoID: repoID},
&RepoIndexerStatus{RepoID: repoID},
); err != nil {
return fmt.Errorf("deleteBeans: %v", err)
}

View File

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

View File

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

View File

@@ -1376,9 +1376,7 @@ type SearchUserOptions struct {
}
func (opts *SearchUserOptions) toConds() builder.Cond {
var cond = builder.NewCond()
cond = cond.And(builder.Eq{"type": opts.Type})
var cond builder.Cond = builder.Eq{"type": opts.Type}
if len(opts.Keyword) > 0 {
lowerKeyword := strings.ToLower(opts.Keyword)
@@ -1647,7 +1645,12 @@ func SyncExternalUsers() {
return
}
sr := s.LDAP().SearchEntries()
sr, err := s.LDAP().SearchEntries()
if err != nil {
log.Error("SyncExternalUsers LDAP source failure [%s], skipped", s.Name)
continue
}
for _, su := range sr {
if len(su.Username) == 0 {
continue

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -623,6 +623,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository #commits-table thead .sha{width:140px}
.repository #commits-table thead .shatd{text-align:center}
.repository #commits-table td.sha .sha.label{margin:0}
.repository #commits-table td.message{text-overflow:unset}
.repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n){background-color:rgba(0,0,0,.02)!important}
.repository #commits-table td.sha .sha.label.isSigned,.repository #repo-files-table .sha.label.isSigned{border:1px solid #bbb}
.repository #commits-table td.sha .sha.label.isSigned .detail.icon,.repository #repo-files-table .sha.label.isSigned .detail.icon{background:#fafafa;margin:-6px -10px -4px 0;padding:5px 3px 5px 6px;border-left:1px solid #bbb;border-top-left-radius:0;border-bottom-left-radius:0}
@@ -667,6 +668,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository .diff-file-box .code-diff-split tbody tr td:nth-child(4){border-left-width:1px;border-left-style:solid}
.repository .diff-file-box.file-content{clear:right}
.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}
.repository .diff-file-box.file-content img.emoji{padding:0}
.repository .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}
.repository .repo-search-result{padding-top:10px;padding-bottom:10px}
.repository .repo-search-result .lines-num a{color:inherit}
@@ -817,8 +819,8 @@ footer .ui.left,footer .ui.right{line-height:40px}
.stats-table .table-cell{display:table-cell}
.stats-table .table-cell.tiny{height:.5em}
tbody.commit-list{vertical-align:baseline}
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 24px);display:inline-block;vertical-align:middle}
.commit-list .message-wrapper .commit-status-link{display:inline-block;vertical-align:middle}
.commit-list .message-wrapper{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 50px);display:inline-block;vertical-align:middle}
.commit-list .commit-status-link{display:inline-block;vertical-align:middle}
.commit-body{white-space:pre-wrap}
.git-notes.top{text-align:left}
.git-notes .commit-body{margin:0}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) {
userID := ctx.QueryInt64("userID")
gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath")
prID := ctx.QueryInt64("prID")
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
@@ -63,11 +64,19 @@ func HookPreReceive(ctx *macaron.Context) {
// detect force push
if git.EmptySHA != oldCommitID {
env := append(os.Environ(),
private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories,
private.GitObjectDirectory+"="+gitObjectDirectory,
private.GitQuarantinePath+"="+gitObjectDirectory,
)
env := os.Environ()
if gitAlternativeObjectDirectories != "" {
env = append(env,
private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories)
}
if gitObjectDirectory != "" {
env = append(env,
private.GitObjectDirectory+"="+gitObjectDirectory)
}
if gitQuarantinePath != "" {
env = append(env,
private.GitQuarantinePath+"="+gitQuarantinePath)
}
output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env)
if err != nil {

View File

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

View File

@@ -162,6 +162,12 @@ func loadBranches(ctx *context.Context) []*Branch {
return nil
}
protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
if err != nil {
ctx.ServerError("GetProtectedBranches", err)
return nil
}
branches := make([]*Branch, len(rawBranches))
for i := range rawBranches {
commit, err := rawBranches[i].GetCommit()
@@ -170,11 +176,13 @@ func loadBranches(ctx *context.Context) []*Branch {
return nil
}
var isProtected bool
branchName := rawBranches[i].Name
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
if err != nil {
ctx.ServerError("IsProtectedBranch", err)
return nil
for _, b := range protectedBranches {
if b.BranchName == branchName {
isProtected = true
break
}
}
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)

View File

@@ -292,6 +292,13 @@ func CompareDiff(ctx *context.Context) {
}
if ctx.Data["PageIsComparePull"] == true {
headBranches, err := headGitRepo.GetBranches()
if err != nil {
ctx.ServerError("GetBranches", err)
return
}
ctx.Data["HeadBranches"] = headBranches
pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
if err != nil {
if !models.IsErrPullRequestNotExist(err) {
@@ -312,13 +319,6 @@ func CompareDiff(ctx *context.Context) {
return
}
}
headBranches, err := headGitRepo.GetBranches()
if err != nil {
ctx.ServerError("GetBranches", err)
return
}
ctx.Data["HeadBranches"] = headBranches
}
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
afterCommitID := ctx.Data["AfterCommitID"].(string)

View File

@@ -628,7 +628,8 @@ func UploadFileToServer(ctx *context.Context) {
allowed := false
for _, t := range setting.Repository.Upload.AllowedTypes {
t := strings.Trim(t, " ")
if t == "*/*" || t == fileType {
if t == "*/*" || t == fileType ||
strings.HasPrefix(fileType, t+";") {
allowed = true
break
}

View File

@@ -1047,11 +1047,14 @@ func UpdateIssueTitle(ctx *context.Context) {
return
}
oldTitle := issue.Title
if err := issue.ChangeTitle(ctx.User, title); err != nil {
ctx.ServerError("ChangeTitle", err)
return
}
notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle)
ctx.JSON(200, map[string]interface{}{
"title": issue.Title,
})

View File

@@ -253,6 +253,11 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
milestoneID := ctx.ParamsInt64(":id")
milestone, err := models.GetMilestoneByID(milestoneID)
if err != nil {
if models.IsErrMilestoneNotExist(err) {
ctx.NotFound("GetMilestoneByID", err)
return
}
ctx.ServerError("GetMilestoneByID", err)
return
}

View File

@@ -38,6 +38,7 @@ import (
"github.com/go-macaron/binding"
"github.com/go-macaron/cache"
"github.com/go-macaron/captcha"
"github.com/go-macaron/cors"
"github.com/go-macaron/csrf"
"github.com/go-macaron/i18n"
"github.com/go-macaron/session"
@@ -440,6 +441,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Get("/:id", repo.WebHooksEdit)
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
@@ -447,6 +449,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
})
@@ -945,9 +948,14 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/swagger.v1.json", templates.JSONRenderer(), routers.SwaggerV1Json)
}
var handlers []macaron.Handler
if setting.EnableCORS {
handlers = append(handlers, cors.CORS(setting.CORSConfig))
}
handlers = append(handlers, ignSignIn)
m.Group("/api", func() {
apiv1.RegisterRoutes(m)
}, ignSignIn)
}, handlers...)
m.Group("/api/internal", func() {
// package name internal is ideal but Golang is not allowed, so we use private as package name.

View File

@@ -20,6 +20,8 @@
<img class="img-13" src="{{AppSubUrl}}/img/discord.png">
{{else if eq .HookType "dingtalk"}}
<img class="img-13" src="{{AppSubUrl}}/img/dingtalk.ico">
{{else if eq .HookType "telegram"}}
<img class="img-13" src="{{AppSubUrl}}/img/telegram.png">
{{else if eq .HookType "msteams"}}
<img class="img-13" src="{{AppSubUrl}}/img/msteams.png">
{{end}}
@@ -31,6 +33,7 @@
{{template "repo/settings/webhook/slack" .}}
{{template "repo/settings/webhook/discord" .}}
{{template "repo/settings/webhook/dingtalk" .}}
{{template "repo/settings/webhook/telegram" .}}
{{template "repo/settings/webhook/msteams" .}}
</div>

View File

@@ -9,12 +9,12 @@
<div class="eight wide right aligned column">
<div class="ui right file-actions">
<div class="ui buttons">
<a class="ui button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a>
{{if not .IsViewCommit}}
<a class="ui button" href="{{.RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a>
{{end}}
<a class="ui button" href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.normal_view"}}</a>
<a class="ui button" href="{{.RepoLink}}/commits/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_history"}}</a>
<a class="ui button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a>
</div>
{{if .Repository.CanEnableEditor}}
{{if .CanEditFile}}

View File

@@ -46,11 +46,11 @@
<tr>
<td class="author">
{{if .User}}
{{if .User.FullName}}
{{if .User.FullName}}
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/>&nbsp;&nbsp;<a href="{{AppSubUrl}}/{{.User.Name}}">{{.User.FullName}}</a>
{{else}}
{{else}}
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/>&nbsp;&nbsp;<a href="{{AppSubUrl}}/{{.User.Name}}">{{.Author.Name}}</a>
{{end}}
{{end}}
{{else}}
<img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/>&nbsp;&nbsp;{{.Author.Name}}
{{end}}
@@ -71,13 +71,15 @@
</td>
<td class="message">
<span class="message-wrapper">
<span class="commit-summary has-emoji{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary}}</span>
{{if IsMultilineCommitMessage .Message}}
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
<pre class="commit-body" style="display: none;">{{RenderCommitBody .Message $.RepoLink $.Repository.ComposeMetas}}</pre>
{{end}}
<span class="commit-summary has-emoji{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary}}</span>
</span>
{{if IsMultilineCommitMessage .Message}}
<button class="basic compact mini ui icon button commit-button"><i class="ellipsis horizontal icon"></i></button>
{{end}}
{{template "repo/commit_status" .Status}}
{{if IsMultilineCommitMessage .Message}}
<pre class="commit-body" style="display: none;">{{RenderCommitBody .Message $.RepoLink $.Repository.ComposeMetas}}</pre>
{{end}}
</td>
<td class="grey text right aligned">{{TimeSince .Author.When $.Lang}}</td>
</tr>

View File

@@ -81,8 +81,8 @@
</span>
</td>
{{end}}
<td class="message has-emoji">
<span class="truncate">
<td class="message">
<span class="truncate has-emoji">
<a href="{{$.RepoLink}}/commit/{{$commit.ID}}" title="{{$commit.Summary}}">{{$commit.Summary}}</a>
</span>
</td>

View File

@@ -33,6 +33,20 @@
],
"summary": "List all organizations",
"operationId": "adminGetAllOrgs",
"parameters": [
{
"type": "integer",
"description": "page number of results to return (1-based)",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "page size of results, maximum page size is 50",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"$ref": "#/responses/OrganizationList"

View File

@@ -16,7 +16,7 @@
{{$.i18n.Tr "settings.delete_key"}}
</button>
</div>
<i class="mega-octicon octicon-key {{if or (eq .ExpiredUnix 0) ($.PageStartTime.Before .ExpiredUnix.AsTime)}}green{{end}}"></i>
<i class="mega-octicon octicon-key {{if or .ExpiredUnix.IsZero ($.PageStartTime.Before .ExpiredUnix.AsTime)}}green{{end}}"></i>
<div class="content">
{{range .Emails}}<strong>{{.Email}} </strong>{{end}}
<div class="print meta">