mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-10 15:32:55 +09:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f71571305 | ||
|
|
a182a80f7c | ||
|
|
89c57487cd | ||
|
|
bb609cacee | ||
|
|
e7f6da386f | ||
|
|
7727f84fe8 | ||
|
|
5d2676089e | ||
|
|
9bea8d825b | ||
|
|
3cc728870a | ||
|
|
0793b5e9c0 | ||
|
|
bb423f9350 | ||
|
|
4d6c8d9b13 | ||
|
|
b6b1560701 | ||
|
|
30dbddcc4d | ||
|
|
c491c22279 | ||
|
|
5649f0d2b3 | ||
|
|
7dd726faeb | ||
|
|
14c979c1b2 | ||
|
|
6b84a1d72b | ||
|
|
68424eddf0 | ||
|
|
ab23e4b7f4 | ||
|
|
1bb88dad20 | ||
|
|
94f0151789 | ||
|
|
1e2fe9f0b4 | ||
|
|
f3496c88b2 | ||
|
|
89915ca8a0 | ||
|
|
24fa56830f | ||
|
|
0fa9ea516a | ||
|
|
9b95b41aa8 | ||
|
|
38e799779f | ||
|
|
4f39e56795 | ||
|
|
7b92f91e88 | ||
|
|
aea49d0b92 | ||
|
|
1b5908fb6a | ||
|
|
65a76b7cb0 | ||
|
|
c6f1825fe9 | ||
|
|
4f5dbc4d00 | ||
|
|
4ee8982e91 | ||
|
|
0d10482168 | ||
|
|
6d441de2bd | ||
|
|
d15e49f7ff | ||
|
|
39da4ac6d4 |
103
.drone.yml
103
.drone.yml
@@ -362,7 +362,7 @@ steps:
|
|||||||
|
|
||||||
- name: static
|
- name: static
|
||||||
pull: always
|
pull: always
|
||||||
image: techknowlogick/xgo:latest
|
image: techknowlogick/xgo:go-1.12.x
|
||||||
commands:
|
commands:
|
||||||
- export PATH=$PATH:$GOPATH/bin
|
- export PATH=$PATH:$GOPATH/bin
|
||||||
- make generate
|
- make generate
|
||||||
@@ -463,7 +463,7 @@ steps:
|
|||||||
|
|
||||||
- name: static
|
- name: static
|
||||||
pull: always
|
pull: always
|
||||||
image: techknowlogick/xgo:latest
|
image: techknowlogick/xgo:go-1.12.x
|
||||||
commands:
|
commands:
|
||||||
- export PATH=$PATH:$GOPATH/bin
|
- export PATH=$PATH:$GOPATH/bin
|
||||||
- make generate
|
- make generate
|
||||||
@@ -558,7 +558,7 @@ steps:
|
|||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
name: docker
|
name: docker-linux-amd64
|
||||||
|
|
||||||
platform:
|
platform:
|
||||||
os: linux
|
os: linux
|
||||||
@@ -594,6 +594,7 @@ steps:
|
|||||||
settings:
|
settings:
|
||||||
dry_run: true
|
dry_run: true
|
||||||
repo: gitea/gitea
|
repo: gitea/gitea
|
||||||
|
tags: linux-amd64
|
||||||
when:
|
when:
|
||||||
event:
|
event:
|
||||||
- pull_request
|
- pull_request
|
||||||
@@ -603,6 +604,7 @@ steps:
|
|||||||
image: plugins/docker:linux-amd64
|
image: plugins/docker:linux-amd64
|
||||||
settings:
|
settings:
|
||||||
auto_tag: true
|
auto_tag: true
|
||||||
|
auto_tag_suffix: linux-amd64
|
||||||
repo: gitea/gitea
|
repo: gitea/gitea
|
||||||
password:
|
password:
|
||||||
from_secret: docker_password
|
from_secret: docker_password
|
||||||
@@ -613,6 +615,97 @@ steps:
|
|||||||
exclude:
|
exclude:
|
||||||
- pull_request
|
- 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
|
kind: pipeline
|
||||||
name: notify
|
name: notify
|
||||||
@@ -635,7 +728,9 @@ depends_on:
|
|||||||
- translations
|
- translations
|
||||||
- release-version
|
- release-version
|
||||||
- release-master
|
- release-master
|
||||||
- docker
|
- docker-linux-amd64
|
||||||
|
- docker-linux-arm64
|
||||||
|
- docker-manifest
|
||||||
- docs
|
- docs
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
56
CHANGELOG.md
56
CHANGELOG.md
@@ -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
|
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.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
|
## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
|
||||||
* BREAKING
|
* BREAKING
|
||||||
* Better logging (#6038) (#6095)
|
* Better logging (#6038) (#6095)
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ func runHookPreReceive(c *cli.Context) error {
|
|||||||
UserID: userID,
|
UserID: userID,
|
||||||
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
|
GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
|
||||||
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
|
GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
|
||||||
|
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
||||||
ProtectedBranchID: prID,
|
ProtectedBranchID: prID,
|
||||||
})
|
})
|
||||||
switch statusCode {
|
switch statusCode {
|
||||||
|
|||||||
19
docker/manifest.tmpl
vendored
Normal file
19
docker/manifest.tmpl
vendored
Normal 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
|
||||||
@@ -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 := 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("Accept", "application/vnd.git-lfs+json")
|
||||||
req.Header.Set("Content-Type", "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 {
|
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 {
|
for _, id := range test.addTime {
|
||||||
resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
|
resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
|
||||||
}
|
}
|
||||||
@@ -124,6 +127,7 @@ func TestAPILFSLocksLogged(t *testing.T) {
|
|||||||
for i, lock := range lfsLocks.Locks {
|
for i, lock := range lfsLocks.Locks {
|
||||||
assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
|
assert.EqualValues(t, test.locksOwners[i].DisplayName(), lock.Owner.Name)
|
||||||
assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 3*time.Second)
|
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{})
|
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
|
||||||
|
|||||||
@@ -24,20 +24,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func withKeyFile(t *testing.T, keyname string, callback func(string)) {
|
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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
//Setup ssh wrapper
|
//Setup ssh wrapper
|
||||||
os.Setenv("GIT_SSH_COMMAND",
|
os.Setenv("GIT_SSH_COMMAND",
|
||||||
"ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "+
|
"ssh -o \"UserKnownHostsFile=/dev/null\" -o \"StrictHostKeyChecking=no\" -o \"IdentitiesOnly=yes\" -i \""+keyFile+"\"")
|
||||||
filepath.Join(setting.AppWorkPath, keyFile))
|
|
||||||
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
os.Setenv("GIT_SSH_VARIANT", "ssh")
|
||||||
|
|
||||||
callback(keyFile)
|
callback(keyFile)
|
||||||
|
|
||||||
defer os.RemoveAll(keyFile)
|
|
||||||
defer os.RemoveAll(keyFile + ".pub")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createSSHUrl(gitPath string, u *url.URL) *url.URL {
|
func createSSHUrl(gitPath string, u *url.URL) *url.URL {
|
||||||
|
|||||||
BIN
integrations/migration-test/gitea-v1.3.3.sqlite3.sql.gz
Normal file
BIN
integrations/migration-test/gitea-v1.3.3.sqlite3.sql.gz
Normal file
Binary file not shown.
@@ -54,6 +54,10 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
|
|||||||
|
|
||||||
func TestPullMerge(t *testing.T) {
|
func TestPullMerge(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
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")
|
session := loginUser(t, "user1")
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
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), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleMerge)
|
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) {
|
func TestPullRebase(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
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")
|
session := loginUser(t, "user1")
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
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), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebase)
|
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) {
|
func TestPullRebaseMerge(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
prepareTestEnv(t)
|
prepareTestEnv(t)
|
||||||
|
|
||||||
|
hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
|
||||||
|
assert.NoError(t, err)
|
||||||
|
hookTasksLenBefore := len(hookTasks)
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
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), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleRebaseMerge)
|
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) {
|
func TestPullSquash(t *testing.T) {
|
||||||
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
|
||||||
prepareTestEnv(t)
|
prepareTestEnv(t)
|
||||||
|
|
||||||
|
hookTasks, err := models.HookTasks(1, 1) //Retrieve previous hook number
|
||||||
|
assert.NoError(t, err)
|
||||||
|
hookTasksLenBefore := len(hookTasks)
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||||
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
|
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), "/")
|
elem := strings.Split(test.RedirectURL(resp), "/")
|
||||||
assert.EqualValues(t, "pulls", elem[3])
|
assert.EqualValues(t, "pulls", elem[3])
|
||||||
testPullMerge(t, session, elem[1], elem[2], elem[4], models.MergeStyleSquash)
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,10 +5,13 @@
|
|||||||
package integrations
|
package integrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -67,6 +70,29 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
|
|||||||
for _, class := range classes {
|
for _, class := range classes {
|
||||||
assert.True(t, sel.HasClass(class))
|
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) {
|
func TestRepoCommitsWithStatusPending(t *testing.T) {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func (status *CommitStatus) loadRepo(e Engine) (err error) {
|
|||||||
// APIURL returns the absolute APIURL to this commit-status.
|
// APIURL returns the absolute APIURL to this commit-status.
|
||||||
func (status *CommitStatus) APIURL() string {
|
func (status *CommitStatus) APIURL() string {
|
||||||
_ = status.loadRepo(x)
|
_ = 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)
|
setting.AppURL, status.Repo.FullName(), status.SHA)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,20 +19,25 @@ func TestGetCommitStatuses(t *testing.T) {
|
|||||||
|
|
||||||
statuses, err := GetCommitStatuses(repo1, sha1, 0)
|
statuses, err := GetCommitStatuses(repo1, sha1, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, statuses, 5) {
|
assert.Len(t, statuses, 5)
|
||||||
assert.Equal(t, statuses[0].Context, "ci/awesomeness")
|
|
||||||
assert.Equal(t, statuses[0].State, CommitStatusPending)
|
|
||||||
|
|
||||||
assert.Equal(t, statuses[1].Context, "cov/awesomeness")
|
assert.Equal(t, "ci/awesomeness", statuses[0].Context)
|
||||||
assert.Equal(t, statuses[1].State, CommitStatusWarning)
|
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, "cov/awesomeness", statuses[1].Context)
|
||||||
assert.Equal(t, statuses[2].State, CommitStatusSuccess)
|
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, "cov/awesomeness", statuses[2].Context)
|
||||||
assert.Equal(t, statuses[3].State, CommitStatusFailure)
|
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, "ci/awesomeness", statuses[3].Context)
|
||||||
assert.Equal(t, statuses[4].State, CommitStatusError)
|
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())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func (l *LFSLock) APIFormat() *api.LFSLock {
|
|||||||
return &api.LFSLock{
|
return &api.LFSLock{
|
||||||
ID: strconv.FormatInt(l.ID, 10),
|
ID: strconv.FormatInt(l.ID, 10),
|
||||||
Path: l.Path,
|
Path: l.Path,
|
||||||
LockedAt: l.Created,
|
LockedAt: l.Created.Round(time.Second),
|
||||||
Owner: &api.LFSLockOwner{
|
Owner: &api.LFSLockOwner{
|
||||||
Name: l.Owner.DisplayName(),
|
Name: l.Owner.DisplayName(),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -62,38 +62,50 @@ func insertIssue(sess *xorm.Session, issue *Issue) error {
|
|||||||
if _, err := sess.Insert(issueLabels); err != nil {
|
if _, err := sess.Insert(issueLabels); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cols := make([]string, 0)
|
||||||
if !issue.IsPull {
|
if !issue.IsPull {
|
||||||
sess.ID(issue.RepoID).Incr("num_issues")
|
sess.ID(issue.RepoID).Incr("num_issues")
|
||||||
|
cols = append(cols, "num_issues")
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
sess.Incr("num_closed_issues")
|
sess.Incr("num_closed_issues")
|
||||||
|
cols = append(cols, "num_closed_issues")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sess.ID(issue.RepoID).Incr("num_pulls")
|
sess.ID(issue.RepoID).Incr("num_pulls")
|
||||||
|
cols = append(cols, "num_pulls")
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
sess.Incr("num_closed_pulls")
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cols = []string{"num_issues"}
|
||||||
sess.Incr("num_issues")
|
sess.Incr("num_issues")
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
sess.Incr("num_closed_issues")
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.MilestoneID > 0 {
|
if issue.MilestoneID > 0 {
|
||||||
|
cols = []string{"num_issues"}
|
||||||
sess.Incr("num_issues")
|
sess.Incr("num_issues")
|
||||||
|
cl := "num_closed_issues"
|
||||||
if issue.IsClosed {
|
if issue.IsClosed {
|
||||||
sess.Incr("num_closed_issues")
|
sess.Incr("num_closed_issues")
|
||||||
|
cols = append(cols, "num_closed_issues")
|
||||||
|
cl = "(num_closed_issues + 1)"
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := sess.ID(issue.MilestoneID).
|
if _, err := sess.ID(issue.MilestoneID).
|
||||||
SetExpr("completeness", "num_closed_issues * 100 / num_issues").
|
SetExpr("completeness", cl+" * 100 / (num_issues + 1)").
|
||||||
NoAutoTime().
|
NoAutoTime().Cols(cols...).
|
||||||
Update(new(Milestone)); err != nil {
|
Update(new(Milestone)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,11 +321,25 @@ func dropTableColumns(sess *xorm.Session, tableName string, columnNames ...strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tableSQL := string(res[0]["sql"])
|
tableSQL := string(res[0]["sql"])
|
||||||
|
|
||||||
|
// Separate out the column definitions
|
||||||
tableSQL = tableSQL[strings.Index(tableSQL, "("):]
|
tableSQL = tableSQL[strings.Index(tableSQL, "("):]
|
||||||
|
|
||||||
|
// Remove the required columnNames
|
||||||
for _, name := range 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)
|
columns := regexp.MustCompile("`([^`]*)`").FindAllString(tableSQL, -1)
|
||||||
|
|
||||||
tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
|
tableSQL = fmt.Sprintf("CREATE TABLE `new_%s_new` ", tableName) + tableSQL
|
||||||
|
|||||||
@@ -5,13 +5,7 @@
|
|||||||
package migrations
|
package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"xorm.io/core"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
|
func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
|
||||||
@@ -21,73 +15,28 @@ func renameRepoIsBareToIsEmpty(x *xorm.Engine) error {
|
|||||||
IsEmpty bool `xorm:"INDEX"`
|
IsEmpty bool `xorm:"INDEX"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// First remove the index
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
if err := sess.Sync2(new(Repository)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := sess.Exec("UPDATE repository SET is_empty = is_bare;"); err != nil {
|
if _, err := sess.Exec("UPDATE repository SET is_empty = is_bare;"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := sess.Commit(); err != nil {
|
||||||
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 {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if models.DbCfg.Type == core.SQLITE {
|
if err := sess.Begin(); err != nil {
|
||||||
log.Warn("TABLE repository's COLUMN is_bare should be DROP but sqlite is not supported, you could manually do that.")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
if err := dropTableColumns(sess, "repository", "is_bare"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"xorm.io/core"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
|
||||||
"code.gitea.io/gitea/modules/generate"
|
"code.gitea.io/gitea/modules/generate"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
@@ -37,41 +35,6 @@ func hashAppToken(x *xorm.Engine) error {
|
|||||||
// First remove the index
|
// First remove the index
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
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 {
|
if err := sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -81,7 +44,7 @@ func hashAppToken(x *xorm.Engine) error {
|
|||||||
return fmt.Errorf("Sync2: %v", err)
|
return fmt.Errorf("Sync2: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = sess.Commit(); err != nil {
|
if err := sess.Commit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -755,11 +755,14 @@ func IsUserInTeams(userID int64, teamIDs []int64) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
|
// UsersInTeamsCount counts the number of users which are in userIDs and teamIDs
|
||||||
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (count int64, err error) {
|
func UsersInTeamsCount(userIDs []int64, teamIDs []int64) (int64, error) {
|
||||||
if count, err = x.In("uid", userIDs).In("team_id", teamIDs).Count(new(TeamUser)); err != nil {
|
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 0, err
|
||||||
}
|
}
|
||||||
return
|
return int64(len(ids)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ___________ __________
|
// ___________ __________
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ func TestUsersInTeamsCount(t *testing.T) {
|
|||||||
assert.Equal(t, expected, count)
|
assert.Equal(t, expected, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
test([]int64{2}, []int64{1, 2, 3, 4}, 2)
|
test([]int64{2}, []int64{1, 2, 3, 4}, 1) // only userid 2
|
||||||
test([]int64{1, 2, 3, 4, 5}, []int64{2, 5}, 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)
|
test([]int64{1, 2, 3, 4, 5}, []int64{2, 3, 5}, 3) // userid 2,4,5
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -598,7 +598,7 @@ func (pr *PullRequest) testPatch(e Engine) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
for i := range patchConflicts {
|
for i := range patchConflicts {
|
||||||
if strings.Contains(stderr, patchConflicts[i]) {
|
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:"
|
const prefix = "error: patch failed:"
|
||||||
pr.Status = PullRequestStatusConflict
|
pr.Status = PullRequestStatusConflict
|
||||||
pr.ConflictedFiles = make([]string, 0, 5)
|
pr.ConflictedFiles = make([]string, 0, 5)
|
||||||
@@ -661,13 +661,16 @@ func NewPullRequest(repo *Repository, pull *Issue, labelIDs []int64, uuids []str
|
|||||||
}
|
}
|
||||||
|
|
||||||
pr.Index = pull.Index
|
pr.Index = pull.Index
|
||||||
if err = repo.savePatch(sess, pr.Index, patch); err != nil {
|
|
||||||
return fmt.Errorf("SavePatch: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pr.BaseRepo = repo
|
pr.BaseRepo = repo
|
||||||
if err = pr.testPatch(sess); err != nil {
|
pr.Status = PullRequestStatusChecking
|
||||||
return fmt.Errorf("testPatch: %v", err)
|
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.
|
// No conflict appears after test means mergeable.
|
||||||
if pr.Status == PullRequestStatusChecking {
|
if pr.Status == PullRequestStatusChecking {
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ func UpdateRelease(doer *User, gitRepo *git.Repository, rel *Release, attachment
|
|||||||
Action: api.HookReleaseUpdated,
|
Action: api.HookReleaseUpdated,
|
||||||
Release: rel.APIFormat(),
|
Release: rel.APIFormat(),
|
||||||
Repository: rel.Repo.APIFormat(mode),
|
Repository: rel.Repo.APIFormat(mode),
|
||||||
Sender: rel.Publisher.APIFormat(),
|
Sender: doer.APIFormat(),
|
||||||
}); err1 != nil {
|
}); err1 != nil {
|
||||||
log.Error("PrepareWebhooks: %v", err)
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
} else {
|
} 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.
|
// 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)
|
rel, err := GetReleaseByID(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetReleaseByID: %v", err)
|
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)
|
return fmt.Errorf("LoadAttributes: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mode, _ := AccessLevel(u, rel.Repo)
|
mode, _ := AccessLevel(doer, 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(),
|
||||||
Repository: rel.Repo.APIFormat(mode),
|
Repository: rel.Repo.APIFormat(mode),
|
||||||
Sender: rel.Publisher.APIFormat(),
|
Sender: doer.APIFormat(),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Error("PrepareWebhooks: %v", err)
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1791,6 +1791,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
|||||||
&HookTask{RepoID: repoID},
|
&HookTask{RepoID: repoID},
|
||||||
&Notification{RepoID: repoID},
|
&Notification{RepoID: repoID},
|
||||||
&CommitStatus{RepoID: repoID},
|
&CommitStatus{RepoID: repoID},
|
||||||
|
&RepoIndexerStatus{RepoID: repoID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ func addUpdate(update fileUpdate, repo *Repository, batch rupture.FlushingBatch)
|
|||||||
if size, err := strconv.Atoi(strings.TrimSpace(stdout)); err != nil {
|
if size, err := strconv.Atoi(strings.TrimSpace(stdout)); err != nil {
|
||||||
return fmt.Errorf("Misformatted git cat-file output: %v", err)
|
return fmt.Errorf("Misformatted git cat-file output: %v", err)
|
||||||
} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
|
} else if int64(size) > setting.Indexer.MaxIndexerFileSize {
|
||||||
return nil
|
return addDelete(update.Filename, repo, batch)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileContents, err := git.NewCommand("cat-file", "blob", update.BlobSha).
|
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)
|
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
|
// parseGitLsTreeOutput parses the output of a `git ls-tree -r --full-name` command
|
||||||
func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
|
func parseGitLsTreeOutput(stdout []byte) ([]fileUpdate, error) {
|
||||||
entries, err := git.ParseTreeEntries(stdout)
|
entries, err := git.ParseTreeEntries(stdout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var idxCount = 0
|
||||||
updates := make([]fileUpdate, len(entries))
|
updates := make([]fileUpdate, len(entries))
|
||||||
for i, entry := range entries {
|
for _, entry := range entries {
|
||||||
updates[i] = fileUpdate{
|
if isIndexable(entry) {
|
||||||
Filename: entry.Name(),
|
updates[idxCount] = fileUpdate{
|
||||||
BlobSha: entry.ID.String(),
|
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
|
// genesisChanges get changes to add repo to the indexer for the first time
|
||||||
|
|||||||
@@ -642,12 +642,14 @@ func rewriteAllPublicKeys(e Engine) error {
|
|||||||
}
|
}
|
||||||
_, err = t.WriteString(line + "\n")
|
_, err = t.WriteString(line + "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Close()
|
||||||
return os.Rename(tmpPath, fPath)
|
return os.Rename(tmpPath, fPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1376,9 +1376,7 @@ type SearchUserOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (opts *SearchUserOptions) toConds() builder.Cond {
|
func (opts *SearchUserOptions) toConds() builder.Cond {
|
||||||
|
var cond builder.Cond = builder.Eq{"type": opts.Type}
|
||||||
var cond = builder.NewCond()
|
|
||||||
cond = cond.And(builder.Eq{"type": opts.Type})
|
|
||||||
|
|
||||||
if len(opts.Keyword) > 0 {
|
if len(opts.Keyword) > 0 {
|
||||||
lowerKeyword := strings.ToLower(opts.Keyword)
|
lowerKeyword := strings.ToLower(opts.Keyword)
|
||||||
@@ -1647,7 +1645,12 @@ func SyncExternalUsers() {
|
|||||||
return
|
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 {
|
for _, su := range sr {
|
||||||
if len(su.Username) == 0 {
|
if len(su.Username) == 0 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -890,7 +890,6 @@ func DeliverHooks() {
|
|||||||
for _, t := range tasks {
|
for _, t := range tasks {
|
||||||
if err = t.deliver(); err != nil {
|
if err = t.deliver(); err != nil {
|
||||||
log.Error("deliver: %v", err)
|
log.Error("deliver: %v", err)
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ func getSlackDeletePayload(p *api.DeletePayload, slack *SlackMeta) (*SlackPayloa
|
|||||||
|
|
||||||
// getSlackForkPayload composes Slack payload for forked by a repository.
|
// getSlackForkPayload composes Slack payload for forked by a repository.
|
||||||
func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
|
func getSlackForkPayload(p *api.ForkPayload, slack *SlackMeta) (*SlackPayload, error) {
|
||||||
baseLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
|
baseLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
|
||||||
forkLink := 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)
|
text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
|
||||||
return &SlackPayload{
|
return &SlackPayload{
|
||||||
Channel: slack.Channel,
|
Channel: slack.Channel,
|
||||||
|
|||||||
@@ -308,12 +308,12 @@ func (ls *Source) UsePagedSearch() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchEntries : search an LDAP source for all users matching userFilter
|
// 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)
|
l, err := dial(ls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LDAP Connect error, %s:%v", ls.Host, err)
|
log.Error("LDAP Connect error, %s:%v", ls.Host, err)
|
||||||
ls.Enabled = false
|
ls.Enabled = false
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close()
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
|||||||
err := l.Bind(ls.BindDN, ls.BindPassword)
|
err := l.Bind(ls.BindDN, ls.BindPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("Failed to bind as BindDN[%s]: %v", ls.BindDN, err)
|
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)
|
log.Trace("Bound as BindDN %s", ls.BindDN)
|
||||||
} else {
|
} else {
|
||||||
@@ -350,7 +350,7 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("LDAP Search failed unexpectedly! (%v)", err)
|
log.Error("LDAP Search failed unexpectedly! (%v)", err)
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make([]*SearchResult, len(sr.Entries))
|
result := make([]*SearchResult, len(sr.Entries))
|
||||||
@@ -368,5 +368,5 @@ func (ls *Source) SearchEntries() []*SearchResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -249,6 +249,19 @@ func Contexter() macaron.Handler {
|
|||||||
if ctx.Query("go-get") == "1" {
|
if ctx.Query("go-get") == "1" {
|
||||||
ownerName := c.Params(":username")
|
ownerName := c.Params(":username")
|
||||||
repoName := c.Params(":reponame")
|
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"
|
branchName := "master"
|
||||||
|
|
||||||
repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
|
repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
|
||||||
@@ -276,7 +289,7 @@ func Contexter() macaron.Handler {
|
|||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`, map[string]string{
|
`, map[string]string{
|
||||||
"GoGetImport": ComposeGoGetImport(ownerName, strings.TrimSuffix(repoName, ".git")),
|
"GoGetImport": ComposeGoGetImport(ownerName, trimmedRepoName),
|
||||||
"CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName),
|
"CloneLink": models.ComposeHTTPSCloneURL(ownerName, repoName),
|
||||||
"GoDocDirectory": prefix + "{/dir}",
|
"GoDocDirectory": prefix + "{/dir}",
|
||||||
"GoDocFile": prefix + "{/dir}/{file}#L{line}",
|
"GoDocFile": prefix + "{/dir}/{file}#L{line}",
|
||||||
|
|||||||
@@ -201,10 +201,14 @@ func ComposeGoGetImport(owner, repo string) string {
|
|||||||
// .netrc file.
|
// .netrc file.
|
||||||
func EarlyResponseForGoGetMeta(ctx *Context) {
|
func EarlyResponseForGoGetMeta(ctx *Context) {
|
||||||
username := ctx.Params(":username")
|
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}">`,
|
ctx.PlainText(200, []byte(com.Expand(`<meta name="go-import" content="{GoGetImport} git {CloneLink}">`,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"GoGetImport": ComposeGoGetImport(username, strings.TrimSuffix(reponame, ".git")),
|
"GoGetImport": ComposeGoGetImport(username, reponame),
|
||||||
"CloneLink": models.ComposeHTTPSCloneURL(username, reponame),
|
"CloneLink": models.ComposeHTTPSCloneURL(username, reponame),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,7 @@ func AddChanges(repoPath string, all bool, files ...string) error {
|
|||||||
if all {
|
if all {
|
||||||
cmd.AddArguments("--all")
|
cmd.AddArguments("--all")
|
||||||
}
|
}
|
||||||
|
cmd.AddArguments("--")
|
||||||
_, err := cmd.AddArguments(files...).RunInDir(repoPath)
|
_, err := cmd.AddArguments(files...).RunInDir(repoPath)
|
||||||
return err
|
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
|
// 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) {
|
func (c *Commit) FileChangedSinceCommit(filename, pastCommit string) (bool, error) {
|
||||||
return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
|
return c.repo.FileChangedBetweenCommits(filename, pastCommit, c.ID.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,8 +187,7 @@ func Pull(repoPath string, opts PullRemoteOptions) error {
|
|||||||
if opts.All {
|
if opts.All {
|
||||||
cmd.AddArguments("--all")
|
cmd.AddArguments("--all")
|
||||||
} else {
|
} else {
|
||||||
cmd.AddArguments(opts.Remote)
|
cmd.AddArguments("--", opts.Remote, opts.Branch)
|
||||||
cmd.AddArguments(opts.Branch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Timeout <= 0 {
|
if opts.Timeout <= 0 {
|
||||||
@@ -213,7 +212,7 @@ func Push(repoPath string, opts PushOptions) error {
|
|||||||
if opts.Force {
|
if opts.Force {
|
||||||
cmd.AddArguments("-f")
|
cmd.AddArguments("-f")
|
||||||
}
|
}
|
||||||
cmd.AddArguments(opts.Remote, opts.Branch)
|
cmd.AddArguments("--", opts.Remote, opts.Branch)
|
||||||
_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
|
_, err := cmd.RunInDirWithEnv(repoPath, opts.Env)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) erro
|
|||||||
cmd.AddArguments("-d")
|
cmd.AddArguments("-d")
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddArguments(name)
|
cmd.AddArguments("--", name)
|
||||||
_, err := cmd.RunInDir(repo.Path)
|
_, err := cmd.RunInDir(repo.Path)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -117,20 +117,26 @@ func (repo *Repository) getCommit(id SHA1) (*Commit, error) {
|
|||||||
return commit, nil
|
return commit, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommit returns commit object of by ID string.
|
// ConvertToSHA1 returns a Hash object from a potential ID string
|
||||||
func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
|
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
|
||||||
if len(commitID) != 40 {
|
if len(commitID) != 40 {
|
||||||
var err error
|
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 err != nil {
|
||||||
if strings.Contains(err.Error(), "unknown revision or path") {
|
if strings.Contains(err.Error(), "unknown revision or path") ||
|
||||||
return nil, ErrNotExist{commitID, ""}
|
strings.Contains(err.Error(), "fatal: Needed a single revision") {
|
||||||
|
return SHA1{}, ErrNotExist{commitID, ""}
|
||||||
}
|
}
|
||||||
return nil, err
|
return SHA1{}, err
|
||||||
}
|
}
|
||||||
commitID = actualCommitID
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// 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) {
|
func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bool, error) {
|
||||||
stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
|
stdout, err := NewCommand("diff", "--name-only", "-z", id1, id2, "--", filename).RunInDirBytes(repo.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -55,5 +55,5 @@ func TestGetCommitWithBadCommitID(t *testing.T) {
|
|||||||
commit, err := bareRepo1.GetCommit("bad_branch")
|
commit, err := bareRepo1.GetCommit("bad_branch")
|
||||||
assert.Nil(t, commit)
|
assert.Nil(t, commit)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.EqualError(t, err, "object does not exist [id: bad_branch, rel_path: ]")
|
assert.True(t, IsErrNotExist(err))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
return strings.TrimSpace(stdout), base, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string)
|
|||||||
if repo.Path != basePath {
|
if repo.Path != basePath {
|
||||||
// Add a temporary remote
|
// Add a temporary remote
|
||||||
tmpRemote = strconv.FormatInt(time.Now().UnixNano(), 10)
|
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)
|
return nil, fmt.Errorf("AddRemote: %v", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// ReadTreeToIndex reads a treeish to the index
|
// ReadTreeToIndex reads a treeish to the index
|
||||||
func (repo *Repository) ReadTreeToIndex(treeish string) error {
|
func (repo *Repository) ReadTreeToIndex(treeish string) error {
|
||||||
if len(treeish) != 40 {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ func (repo *Repository) IsTagExist(name string) bool {
|
|||||||
|
|
||||||
// CreateTag create one tag in the repository
|
// CreateTag create one tag in the repository
|
||||||
func (repo *Repository) CreateTag(name, revision string) error {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateAnnotatedTag create one annotated tag in the repository
|
// CreateAnnotatedTag create one annotated tag in the repository
|
||||||
func (repo *Repository) CreateAnnotatedTag(name, message, revision string) error {
|
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
|
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)
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
fields := strings.Fields(stdout)
|
// Make sure exact match is used: "v1" != "release/v1"
|
||||||
if len(fields) != 2 {
|
for _, line := range strings.Split(stdout, "\n") {
|
||||||
return "", ErrNotExist{ID: name}
|
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.
|
// GetTag returns a Git tag by given name.
|
||||||
|
|||||||
@@ -62,6 +62,16 @@ func TestRepository_GetTag(t *testing.T) {
|
|||||||
assert.NotEqual(t, aTagID, aTag.Object.String())
|
assert.NotEqual(t, aTagID, aTag.Object.String())
|
||||||
assert.EqualValues(t, aTagCommitID, aTag.Object.String())
|
assert.EqualValues(t, aTagCommitID, aTag.Object.String())
|
||||||
assert.EqualValues(t, "tag", aTag.Type)
|
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) {
|
func TestRepository_GetAnnotatedTag(t *testing.T) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
|
|||||||
// GetTree find the tree object in the repository.
|
// GetTree find the tree object in the repository.
|
||||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
|
||||||
if len(idStr) != 40 {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// 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) {
|
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
|
// Because this may call hooks we should pass in the environment
|
||||||
env := append(os.Environ(),
|
env := append(os.Environ(),
|
||||||
|
|||||||
@@ -108,6 +108,11 @@ func (te *TreeEntry) IsRegular() bool {
|
|||||||
return te.gogitTreeEntry.Mode == filemode.Regular
|
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
|
// Blob returns the blob object the entry
|
||||||
func (te *TreeEntry) Blob() *Blob {
|
func (te *TreeEntry) Blob() *Blob {
|
||||||
encodedObj, err := te.ptree.repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, te.gogitTreeEntry.Hash)
|
encodedObj, err := te.ptree.repo.gogitRepo.Storer.EncodedObject(plumbing.AnyObject, te.gogitTreeEntry.Hash)
|
||||||
|
|||||||
@@ -29,12 +29,13 @@ type HookOptions struct {
|
|||||||
UserName string
|
UserName string
|
||||||
GitObjectDirectory string
|
GitObjectDirectory string
|
||||||
GitAlternativeObjectDirectories string
|
GitAlternativeObjectDirectories string
|
||||||
|
GitQuarantinePath string
|
||||||
ProtectedBranchID int64
|
ProtectedBranchID int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// HookPreReceive check whether the provided commits are allowed
|
// HookPreReceive check whether the provided commits are allowed
|
||||||
func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string) {
|
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(ownerName),
|
||||||
url.PathEscape(repoName),
|
url.PathEscape(repoName),
|
||||||
url.QueryEscape(opts.OldCommitID),
|
url.QueryEscape(opts.OldCommitID),
|
||||||
@@ -43,6 +44,7 @@ func HookPreReceive(ownerName, repoName string, opts HookOptions) (int, string)
|
|||||||
opts.UserID,
|
opts.UserID,
|
||||||
url.QueryEscape(opts.GitObjectDirectory),
|
url.QueryEscape(opts.GitObjectDirectory),
|
||||||
url.QueryEscape(opts.GitAlternativeObjectDirectories),
|
url.QueryEscape(opts.GitAlternativeObjectDirectories),
|
||||||
|
url.QueryEscape(opts.GitQuarantinePath),
|
||||||
opts.ProtectedBranchID,
|
opts.ProtectedBranchID,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -292,39 +292,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
|
|||||||
go models.HookQueue.Add(pr.Issue.Repo.ID)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,8 +299,7 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
|
|||||||
getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) {
|
getDiffTreeFromBranch := func(repoPath, baseBranch, headBranch string) (string, error) {
|
||||||
var outbuf, errbuf strings.Builder
|
var outbuf, errbuf strings.Builder
|
||||||
// Compute the diff-tree for sparse-checkout
|
// 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 "", fmt.Errorf("git diff-tree [%s base:%s head:%s]: %s", repoPath, baseBranch, headBranch, errbuf.String())
|
||||||
}
|
}
|
||||||
return outbuf.String(), nil
|
return outbuf.String(), nil
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
|
|||||||
// Assigned LastCommitID in opts if it hasn't been set
|
// Assigned LastCommitID in opts if it hasn't been set
|
||||||
if opts.LastCommitID == "" {
|
if opts.LastCommitID == "" {
|
||||||
opts.LastCommitID = commit.ID.String()
|
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
|
// Get the files in the index
|
||||||
@@ -172,32 +178,6 @@ func DeleteRepoFile(repo *models.Repository, doer *models.User, opts *DeleteRepo
|
|||||||
return nil, err
|
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)
|
commit, err = t.GetCommit(commitHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -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
|
// 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) {
|
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()
|
authorSig := author.NewGitSig()
|
||||||
committerSig := committer.NewGitSig()
|
committerSig := committer.NewGitSig()
|
||||||
|
|
||||||
|
|||||||
@@ -188,6 +188,13 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
|
|||||||
// Assigned LastCommitID in opts if it hasn't been set
|
// Assigned LastCommitID in opts if it hasn't been set
|
||||||
if opts.LastCommitID == "" {
|
if opts.LastCommitID == "" {
|
||||||
opts.LastCommitID = commit.ID.String()
|
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"
|
encoding := "UTF-8"
|
||||||
@@ -387,32 +394,6 @@ func CreateOrUpdateRepoFile(repo *models.Repository, doer *models.User, opts *Up
|
|||||||
return nil, err
|
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)
|
commit, err = t.GetCommit(commitHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/git"
|
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
)
|
)
|
||||||
@@ -177,31 +176,5 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep
|
|||||||
return err
|
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...)
|
return models.DeleteUploads(uploads...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 (optional) for the commit of this file. if not supplied, a default message will be used
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
// branch (optional) to base this file from. if not given, the default branch is used
|
// 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
|
// 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` 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"`
|
Author Identity `json:"author"`
|
||||||
Committer Identity `json:"committer"`
|
Committer Identity `json:"committer"`
|
||||||
|
|||||||
@@ -623,6 +623,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
|
|||||||
.repository #commits-table thead .sha{width:140px}
|
.repository #commits-table thead .sha{width:140px}
|
||||||
.repository #commits-table thead .shatd{text-align:center}
|
.repository #commits-table thead .shatd{text-align:center}
|
||||||
.repository #commits-table td.sha .sha.label{margin:0}
|
.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.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,.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}
|
.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 .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{clear:right}
|
||||||
.repository .diff-file-box.file-content img{max-width:100%;padding:5px 5px 0 5px}
|
.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 .code-view{overflow:auto;overflow-x:auto;overflow-y:hidden}
|
||||||
.repository .repo-search-result{padding-top:10px;padding-bottom:10px}
|
.repository .repo-search-result{padding-top:10px;padding-bottom:10px}
|
||||||
.repository .repo-search-result .lines-num a{color:inherit}
|
.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{display:table-cell}
|
||||||
.stats-table .table-cell.tiny{height:.5em}
|
.stats-table .table-cell.tiny{height:.5em}
|
||||||
tbody.commit-list{vertical-align:baseline}
|
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{overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 50px);display:inline-block;vertical-align:middle}
|
||||||
.commit-list .message-wrapper .commit-status-link{display:inline-block;vertical-align:middle}
|
.commit-list .commit-status-link{display:inline-block;vertical-align:middle}
|
||||||
.commit-body{white-space:pre-wrap}
|
.commit-body{white-space:pre-wrap}
|
||||||
.git-notes.top{text-align:left}
|
.git-notes.top{text-align:left}
|
||||||
.git-notes .commit-body{margin:0}
|
.git-notes .commit-body{margin:0}
|
||||||
|
|||||||
@@ -1265,6 +1265,10 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.message {
|
||||||
|
text-overflow: unset;
|
||||||
|
}
|
||||||
|
|
||||||
&.ui.basic.striped.table tbody tr:nth-child(2n) {
|
&.ui.basic.striped.table tbody tr:nth-child(2n) {
|
||||||
background-color: rgba(0, 0, 0, 0.02) !important;
|
background-color: rgba(0, 0, 0, 0.02) !important;
|
||||||
}
|
}
|
||||||
@@ -1540,6 +1544,9 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
padding: 5px 5px 0 5px;
|
padding: 5px 5px 0 5px;
|
||||||
}
|
}
|
||||||
|
img.emoji {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
clear: right;
|
clear: right;
|
||||||
}
|
}
|
||||||
@@ -2302,12 +2309,12 @@ tbody.commit-list {
|
|||||||
.commit-list .message-wrapper {
|
.commit-list .message-wrapper {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
max-width: calc(100% - 24px);
|
max-width: calc(100% - 50px);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.commit-list .message-wrapper .commit-status-link {
|
.commit-list .commit-status-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,6 +82,15 @@ func GetAllOrgs(ctx *context.APIContext) {
|
|||||||
// summary: List all organizations
|
// summary: List all organizations
|
||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - 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:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/OrganizationList"
|
// "$ref": "#/responses/OrganizationList"
|
||||||
@@ -90,7 +99,9 @@ func GetAllOrgs(ctx *context.APIContext) {
|
|||||||
users, _, err := models.SearchUsers(&models.SearchUserOptions{
|
users, _, err := models.SearchUsers(&models.SearchUserOptions{
|
||||||
Type: models.UserTypeOrganization,
|
Type: models.UserTypeOrganization,
|
||||||
OrderBy: models.SearchOrderByAlphabetically,
|
OrderBy: models.SearchOrderByAlphabetically,
|
||||||
PageSize: -1,
|
Page: ctx.QueryInt("page"),
|
||||||
|
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
|
||||||
|
Private: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(500, "SearchOrganizations", err)
|
ctx.Error(500, "SearchOrganizations", err)
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ import (
|
|||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
"code.gitea.io/gitea/routers/api/v1/user"
|
||||||
|
|
||||||
"github.com/go-macaron/binding"
|
"github.com/go-macaron/binding"
|
||||||
"github.com/go-macaron/cors"
|
|
||||||
macaron "gopkg.in/macaron.v1"
|
macaron "gopkg.in/macaron.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -501,12 +500,6 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Get("/swagger", misc.Swagger) //Render V1 by default
|
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() {
|
m.Group("/v1", func() {
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
if setting.API.EnableSwagger {
|
if setting.API.EnableSwagger {
|
||||||
@@ -852,7 +845,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Group("/topics", func() {
|
m.Group("/topics", func() {
|
||||||
m.Get("/search", repo.TopicSearch)
|
m.Get("/search", repo.TopicSearch)
|
||||||
})
|
})
|
||||||
}, handlers...)
|
}, securityHeaders(), context.APIContexter(), sudo())
|
||||||
}
|
}
|
||||||
|
|
||||||
func securityHeaders() macaron.Handler {
|
func securityHeaders() macaron.Handler {
|
||||||
|
|||||||
@@ -71,19 +71,22 @@ func GetGitRefs(ctx *context.APIContext) {
|
|||||||
getGitRefsInternal(ctx, ctx.Params("*"))
|
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())
|
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(500, "OpenRepository", err)
|
return nil, "OpenRepository", err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if len(filter) > 0 {
|
if len(filter) > 0 {
|
||||||
filter = "refs/" + filter
|
filter = "refs/" + filter
|
||||||
}
|
}
|
||||||
|
|
||||||
refs, err := gitRepo.GetRefsFiltered(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 {
|
if err != nil {
|
||||||
ctx.Error(500, "GetRefsFiltered", err)
|
ctx.Error(500, lastMethodName, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,8 @@ func CreateReleaseAttachment(ctx *context.APIContext) {
|
|||||||
allowed := false
|
allowed := false
|
||||||
for _, t := range allowedTypes {
|
for _, t := range allowedTypes {
|
||||||
t := strings.Trim(t, " ")
|
t := strings.Trim(t, " ")
|
||||||
if t == "*/*" || t == fileType {
|
if t == "*/*" || t == fileType ||
|
||||||
|
strings.HasPrefix(fileType, t+";") {
|
||||||
allowed = true
|
allowed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -646,89 +646,102 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.HasIssues != nil {
|
if opts.HasIssues == nil {
|
||||||
if *opts.HasIssues {
|
// If HasIssues setting not touched, rewrite existing repo unit
|
||||||
// We don't currently allow setting individual issue settings through the API,
|
if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
|
||||||
// only can enable/disable issues, so when enabling issues,
|
units = append(units, *unit)
|
||||||
// we either get the existing config which means it was already enabled,
|
} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
|
||||||
// or create a new config since it doesn't exist.
|
units = append(units, *unit)
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
} 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 == nil {
|
||||||
if *opts.HasWiki {
|
// If HasWiki setting not touched, rewrite existing repo unit
|
||||||
// We don't currently allow setting individual wiki settings through the API,
|
if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
|
||||||
// only can enable/disable the wiki, so when enabling the wiki,
|
units = append(units, *unit)
|
||||||
// we either get the existing config which means it was already enabled,
|
} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
|
||||||
// or create a new config since it doesn't exist.
|
units = append(units, *unit)
|
||||||
config := &models.UnitConfig{}
|
|
||||||
units = append(units, models.RepoUnit{
|
|
||||||
RepoID: repo.ID,
|
|
||||||
Type: models.UnitTypeWiki,
|
|
||||||
Config: config,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
} 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 == nil {
|
||||||
if *opts.HasPullRequests {
|
// If HasPullRequest setting not touched, rewrite existing repo unit
|
||||||
// We do allow setting individual PR settings through the API, so
|
if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
|
||||||
// we get the config settings and then set them
|
units = append(units, *unit)
|
||||||
// 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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
} 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 {
|
if err := models.UpdateRepositoryUnits(repo, units); err != nil {
|
||||||
|
|||||||
@@ -46,10 +46,7 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) {
|
|||||||
// "$ref": "#/responses/StatusList"
|
// "$ref": "#/responses/StatusList"
|
||||||
sha := ctx.Params("sha")
|
sha := ctx.Params("sha")
|
||||||
if len(sha) == 0 {
|
if len(sha) == 0 {
|
||||||
sha = ctx.Params("ref")
|
ctx.Error(400, "sha not given", nil)
|
||||||
}
|
|
||||||
if len(sha) == 0 {
|
|
||||||
ctx.Error(400, "ref/sha not given", nil)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
status := &models.CommitStatus{
|
status := &models.CommitStatus{
|
||||||
@@ -121,7 +118,38 @@ func GetCommitStatusesByRef(ctx *context.APIContext) {
|
|||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/StatusList"
|
// "$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) {
|
func getCommitStatuses(ctx *context.APIContext, sha string) {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) {
|
|||||||
userID := ctx.QueryInt64("userID")
|
userID := ctx.QueryInt64("userID")
|
||||||
gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
|
gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
|
||||||
gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
|
gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
|
||||||
|
gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath")
|
||||||
prID := ctx.QueryInt64("prID")
|
prID := ctx.QueryInt64("prID")
|
||||||
|
|
||||||
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
|
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
|
||||||
@@ -63,11 +64,19 @@ func HookPreReceive(ctx *macaron.Context) {
|
|||||||
|
|
||||||
// detect force push
|
// detect force push
|
||||||
if git.EmptySHA != oldCommitID {
|
if git.EmptySHA != oldCommitID {
|
||||||
env := append(os.Environ(),
|
env := os.Environ()
|
||||||
private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories,
|
if gitAlternativeObjectDirectories != "" {
|
||||||
private.GitObjectDirectory+"="+gitObjectDirectory,
|
env = append(env,
|
||||||
private.GitQuarantinePath+"="+gitObjectDirectory,
|
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)
|
output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ func UploadAttachment(ctx *context.Context) {
|
|||||||
allowed := false
|
allowed := false
|
||||||
for _, t := range allowedTypes {
|
for _, t := range allowedTypes {
|
||||||
t := strings.Trim(t, " ")
|
t := strings.Trim(t, " ")
|
||||||
if t == "*/*" || t == fileType {
|
if t == "*/*" || t == fileType ||
|
||||||
|
strings.HasPrefix(fileType, t+";") {
|
||||||
allowed = true
|
allowed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,6 +162,12 @@ func loadBranches(ctx *context.Context) []*Branch {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("GetProtectedBranches", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
branches := make([]*Branch, len(rawBranches))
|
branches := make([]*Branch, len(rawBranches))
|
||||||
for i := range rawBranches {
|
for i := range rawBranches {
|
||||||
commit, err := rawBranches[i].GetCommit()
|
commit, err := rawBranches[i].GetCommit()
|
||||||
@@ -170,11 +176,13 @@ func loadBranches(ctx *context.Context) []*Branch {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isProtected bool
|
||||||
branchName := rawBranches[i].Name
|
branchName := rawBranches[i].Name
|
||||||
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
|
for _, b := range protectedBranches {
|
||||||
if err != nil {
|
if b.BranchName == branchName {
|
||||||
ctx.ServerError("IsProtectedBranch", err)
|
isProtected = true
|
||||||
return nil
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
|
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
|
||||||
|
|||||||
@@ -292,6 +292,13 @@ func CompareDiff(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Data["PageIsComparePull"] == true {
|
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)
|
pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !models.IsErrPullRequestNotExist(err) {
|
if !models.IsErrPullRequestNotExist(err) {
|
||||||
@@ -312,13 +319,6 @@ func CompareDiff(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
headBranches, err := headGitRepo.GetBranches()
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetBranches", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data["HeadBranches"] = headBranches
|
|
||||||
}
|
}
|
||||||
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
|
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
|
||||||
afterCommitID := ctx.Data["AfterCommitID"].(string)
|
afterCommitID := ctx.Data["AfterCommitID"].(string)
|
||||||
|
|||||||
@@ -628,7 +628,8 @@ func UploadFileToServer(ctx *context.Context) {
|
|||||||
allowed := false
|
allowed := false
|
||||||
for _, t := range setting.Repository.Upload.AllowedTypes {
|
for _, t := range setting.Repository.Upload.AllowedTypes {
|
||||||
t := strings.Trim(t, " ")
|
t := strings.Trim(t, " ")
|
||||||
if t == "*/*" || t == fileType {
|
if t == "*/*" || t == fileType ||
|
||||||
|
strings.HasPrefix(fileType, t+";") {
|
||||||
allowed = true
|
allowed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1047,11 +1047,14 @@ func UpdateIssueTitle(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
oldTitle := issue.Title
|
||||||
if err := issue.ChangeTitle(ctx.User, title); err != nil {
|
if err := issue.ChangeTitle(ctx.User, title); err != nil {
|
||||||
ctx.ServerError("ChangeTitle", err)
|
ctx.ServerError("ChangeTitle", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle)
|
||||||
|
|
||||||
ctx.JSON(200, map[string]interface{}{
|
ctx.JSON(200, map[string]interface{}{
|
||||||
"title": issue.Title,
|
"title": issue.Title,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -253,6 +253,11 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
|
|||||||
milestoneID := ctx.ParamsInt64(":id")
|
milestoneID := ctx.ParamsInt64(":id")
|
||||||
milestone, err := models.GetMilestoneByID(milestoneID)
|
milestone, err := models.GetMilestoneByID(milestoneID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if models.IsErrMilestoneNotExist(err) {
|
||||||
|
ctx.NotFound("GetMilestoneByID", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.ServerError("GetMilestoneByID", err)
|
ctx.ServerError("GetMilestoneByID", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import (
|
|||||||
"github.com/go-macaron/binding"
|
"github.com/go-macaron/binding"
|
||||||
"github.com/go-macaron/cache"
|
"github.com/go-macaron/cache"
|
||||||
"github.com/go-macaron/captcha"
|
"github.com/go-macaron/captcha"
|
||||||
|
"github.com/go-macaron/cors"
|
||||||
"github.com/go-macaron/csrf"
|
"github.com/go-macaron/csrf"
|
||||||
"github.com/go-macaron/i18n"
|
"github.com/go-macaron/i18n"
|
||||||
"github.com/go-macaron/session"
|
"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("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||||
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
|
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.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
|
||||||
m.Get("/:id", repo.WebHooksEdit)
|
m.Get("/:id", repo.WebHooksEdit)
|
||||||
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
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("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||||
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
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)
|
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)
|
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() {
|
m.Group("/api", func() {
|
||||||
apiv1.RegisterRoutes(m)
|
apiv1.RegisterRoutes(m)
|
||||||
}, ignSignIn)
|
}, handlers...)
|
||||||
|
|
||||||
m.Group("/api/internal", func() {
|
m.Group("/api/internal", func() {
|
||||||
// package name internal is ideal but Golang is not allowed, so we use private as package name.
|
// package name internal is ideal but Golang is not allowed, so we use private as package name.
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
<img class="img-13" src="{{AppSubUrl}}/img/discord.png">
|
<img class="img-13" src="{{AppSubUrl}}/img/discord.png">
|
||||||
{{else if eq .HookType "dingtalk"}}
|
{{else if eq .HookType "dingtalk"}}
|
||||||
<img class="img-13" src="{{AppSubUrl}}/img/dingtalk.ico">
|
<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"}}
|
{{else if eq .HookType "msteams"}}
|
||||||
<img class="img-13" src="{{AppSubUrl}}/img/msteams.png">
|
<img class="img-13" src="{{AppSubUrl}}/img/msteams.png">
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -31,6 +33,7 @@
|
|||||||
{{template "repo/settings/webhook/slack" .}}
|
{{template "repo/settings/webhook/slack" .}}
|
||||||
{{template "repo/settings/webhook/discord" .}}
|
{{template "repo/settings/webhook/discord" .}}
|
||||||
{{template "repo/settings/webhook/dingtalk" .}}
|
{{template "repo/settings/webhook/dingtalk" .}}
|
||||||
|
{{template "repo/settings/webhook/telegram" .}}
|
||||||
{{template "repo/settings/webhook/msteams" .}}
|
{{template "repo/settings/webhook/msteams" .}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
<div class="eight wide right aligned column">
|
<div class="eight wide right aligned column">
|
||||||
<div class="ui right file-actions">
|
<div class="ui right file-actions">
|
||||||
<div class="ui buttons">
|
<div class="ui buttons">
|
||||||
|
<a class="ui button" href="{{EscapePound $.RawFileLink}}">{{.i18n.Tr "repo.file_raw"}}</a>
|
||||||
{{if not .IsViewCommit}}
|
{{if not .IsViewCommit}}
|
||||||
<a class="ui button" href="{{.RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a>
|
<a class="ui button" href="{{.RepoLink}}/src/commit/{{.CommitID}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.file_permalink"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="ui button" href="{{.RepoLink}}/src/{{EscapePound .BranchNameSubURL}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.normal_view"}}</a>
|
<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="{{.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>
|
</div>
|
||||||
{{if .Repository.CanEnableEditor}}
|
{{if .Repository.CanEnableEditor}}
|
||||||
{{if .CanEditFile}}
|
{{if .CanEditFile}}
|
||||||
|
|||||||
@@ -46,11 +46,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="author">
|
<td class="author">
|
||||||
{{if .User}}
|
{{if .User}}
|
||||||
{{if .User.FullName}}
|
{{if .User.FullName}}
|
||||||
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/> <a href="{{AppSubUrl}}/{{.User.Name}}">{{.User.FullName}}</a>
|
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/> <a href="{{AppSubUrl}}/{{.User.Name}}">{{.User.FullName}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/> <a href="{{AppSubUrl}}/{{.User.Name}}">{{.Author.Name}}</a>
|
<img class="ui avatar image" src="{{.User.RelAvatarLink}}" alt=""/> <a href="{{AppSubUrl}}/{{.User.Name}}">{{.Author.Name}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/> {{.Author.Name}}
|
<img class="ui avatar image" src="{{AvatarLink .Author.Email}}" alt=""/> {{.Author.Name}}
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -71,13 +71,15 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="message">
|
<td class="message">
|
||||||
<span class="message-wrapper">
|
<span class="message-wrapper">
|
||||||
<span class="commit-summary has-emoji{{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary}}</span>
|
<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>
|
</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}}
|
{{template "repo/commit_status" .Status}}
|
||||||
|
{{if IsMultilineCommitMessage .Message}}
|
||||||
|
<pre class="commit-body" style="display: none;">{{RenderCommitBody .Message $.RepoLink $.Repository.ComposeMetas}}</pre>
|
||||||
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td class="grey text right aligned">{{TimeSince .Author.When $.Lang}}</td>
|
<td class="grey text right aligned">{{TimeSince .Author.When $.Lang}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -81,8 +81,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
{{end}}
|
{{end}}
|
||||||
<td class="message has-emoji">
|
<td class="message">
|
||||||
<span class="truncate">
|
<span class="truncate has-emoji">
|
||||||
<a href="{{$.RepoLink}}/commit/{{$commit.ID}}" title="{{$commit.Summary}}">{{$commit.Summary}}</a>
|
<a href="{{$.RepoLink}}/commit/{{$commit.ID}}" title="{{$commit.Summary}}">{{$commit.Summary}}</a>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -33,6 +33,20 @@
|
|||||||
],
|
],
|
||||||
"summary": "List all organizations",
|
"summary": "List all organizations",
|
||||||
"operationId": "adminGetAllOrgs",
|
"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": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"$ref": "#/responses/OrganizationList"
|
"$ref": "#/responses/OrganizationList"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
{{$.i18n.Tr "settings.delete_key"}}
|
{{$.i18n.Tr "settings.delete_key"}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</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">
|
<div class="content">
|
||||||
{{range .Emails}}<strong>{{.Email}} </strong>{{end}}
|
{{range .Emails}}<strong>{{.Email}} </strong>{{end}}
|
||||||
<div class="print meta">
|
<div class="print meta">
|
||||||
|
|||||||
Reference in New Issue
Block a user