mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-08 05:02:38 +09:00
Compare commits
24 Commits
v1.11.0-rc
...
v1.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9169b39458 | ||
|
|
80eb50655a | ||
|
|
b16c555541 | ||
|
|
b5b44364e3 | ||
|
|
6af58022c8 | ||
|
|
e48b460a0a | ||
|
|
2cd2614eaa | ||
|
|
0129e76ef5 | ||
|
|
6896dad675 | ||
|
|
1ed4323005 | ||
|
|
049af0d3d0 | ||
|
|
f5727d83dd | ||
|
|
912ce27421 | ||
|
|
b3549bb5ec | ||
|
|
491cbeca67 | ||
|
|
895d92ffe5 | ||
|
|
4b11f967bd | ||
|
|
1e73dd2446 | ||
|
|
315026c2c5 | ||
|
|
16dfd9ffbe | ||
|
|
16f7b43903 | ||
|
|
043febdbc9 | ||
|
|
60f91d56f0 | ||
|
|
16fc15ae6a |
@@ -1,4 +1,14 @@
|
||||
# The full repository name
|
||||
repo: go-gitea/gitea
|
||||
|
||||
# Service type (gitea or github)
|
||||
service: github
|
||||
|
||||
# Base URL for Gitea instance if using gitea service type (optional)
|
||||
# Default: https://gitea.com
|
||||
base-url:
|
||||
|
||||
# Changelog groups and which labeled PRs to add to each group
|
||||
groups:
|
||||
-
|
||||
name: BREAKING
|
||||
@@ -42,3 +52,6 @@ groups:
|
||||
-
|
||||
name: MISC
|
||||
default: true
|
||||
|
||||
# regex indicating which labels to skip for the changelog
|
||||
skip-labels: skip-changelog|backport\/.+
|
||||
|
||||
139
CHANGELOG.md
139
CHANGELOG.md
@@ -4,69 +4,22 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.11.0-RC2](https://github.com/go-gitea/gitea/releases/tag/v1.11.0-rc2) - 2020-01-18
|
||||
## [1.11.0](https://github.com/go-gitea/gitea/releases/tag/v1.11.0) - 2020-02-10
|
||||
* BREAKING
|
||||
* Fix followers and following tabs in profile (#10202) (#10203)
|
||||
* Make CertFile and KeyFile relative to CustomPath (#9868) (#9874)
|
||||
* SECURITY
|
||||
* Never allow an empty password to validate (#9682) (#9683)
|
||||
* Prevent redirect to Host (#9678) (#9679)
|
||||
* BUGFIXES
|
||||
* Don't convert ellipsis in markdown (#9905) (#9937)
|
||||
* Fixed repo link in generated comment for cross repository dependency (#9863) (#9935)
|
||||
* Check if diff actually contains sections when rendering (#9926) (#9933)
|
||||
* Fix wrong hint when status checking is running on pull request view (#9886) (#9928)
|
||||
* Fix RocketChat (#9908) (#9921)
|
||||
* Do not try to recreate ldap user if they are already created (#9900) (#9919)
|
||||
* Create terminated channel in queue_redis (#9910) (#9911)
|
||||
* Prevent empty LDAP search result from deactivating all users (#9879) (#9896)
|
||||
* Fix wrong permissions check when issues/prs shared operations (#9885) (#9889)
|
||||
* Check user != nil before checking values (#9881) (#9883)
|
||||
* Allow hyphen in language name (#9873) (#9880)
|
||||
* Ensure that 2fa is checked on reset-password (#9857) (#9876)
|
||||
* Fix issues/pulls dependencies problems (#9842) (#9864)
|
||||
* Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855)
|
||||
* Fix markdown anchor links (#9673) (#9840)
|
||||
* Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9837)
|
||||
* Fix download file wrong content-type (#9825) (#9834)
|
||||
* Fix wrong poster identity on a migrated pull request when submit review (#9827) (#9830)
|
||||
* Fix database dump when log directory is missing (#9818) (#9819)
|
||||
* Fix compare (#9808) (#9814)
|
||||
* Fix push-to-create (#9772) (#9797)
|
||||
* Fix missing msteam webhook on organization (#9781) (#9794)
|
||||
* Fix missing unlock in uniquequeue (#9790) (#9791)
|
||||
* Fix add team on collaborator page when same name as organization (#9778)
|
||||
* DeleteRepoFile incorrectly handles Delete to new branch (#9769) (#9775)
|
||||
* Fix milestones page (#9771)
|
||||
* Fix SimpleMDE quote reply (#9757) (#9768)
|
||||
* Fix missing updated time on migrated issues and comments (#9744) (#9764)
|
||||
* Move Errored PRs out of StatusChecking (#9675) (#9726)
|
||||
* Make hook status printing configurable with delay (#9641) (#9725)
|
||||
* Fix /repos/issues/search (#9698) (#9724)
|
||||
* Silence fomantic error regarding tabs (#9713) (#9718)
|
||||
* Remove unused lock (#9709) (#9710)
|
||||
* Remove q.lock.Unlock() in setInternal to prevent panic (#9705) (#9706)
|
||||
* Load milestone in API PR list (#9671) (#9700)
|
||||
* Don't attempt to close issue if already closed (#9696) (#9699)
|
||||
* Remove google font call (#9668) (#9681)
|
||||
* Eliminate horizontal scroll caused by footer (#9674)
|
||||
* Fix nil reference in repo generation (#9660) (#9666)
|
||||
* Add HTML URL to API Issues (#9654) (#9661)
|
||||
* Add PR review webhook to Telegram (#9653) (#9655)
|
||||
* Use filepath.IsAbs instead of path.IsAbs (#9651) (#9652)
|
||||
* TRANSLATION
|
||||
* Fix Korean locales (#9761) (#9780)
|
||||
* BUILD
|
||||
* Fix webpack polyfills (#9735) (#9738)
|
||||
* MISC
|
||||
* Backport Locales [2020-01-14] (#9773)
|
||||
|
||||
## [1.11.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.11.0-rc1) - 2020-01-07
|
||||
* BREAKING
|
||||
* Remove unused endpoints (#9538)
|
||||
* Prefix all user-generated IDs in markup (#9477)
|
||||
* Enforce Gitea environment for pushes (#8982)
|
||||
* Hide some user information via API if user have no enough permission (#8655)
|
||||
* Hide some user information via API if user have not enough permissions (#8655)
|
||||
* Move startpage/homepage translation to crowdin (#8596)
|
||||
* SECURITY
|
||||
* Never allow an empty password to validate (#9682) (#9683)
|
||||
* Prevent redirect to Host (#9678) (#9679)
|
||||
* Swagger hide search field (#9554)
|
||||
* Add "search" to reserved usernames (#9063)
|
||||
* Switch to fomantic-ui (#9374)
|
||||
* Only serve attachments when linked to issue/release and if accessible by user (#9340)
|
||||
* FEATURES
|
||||
* Webhooks should only show sender if it makes sense (#9601)
|
||||
* Provide Default messages for merges (#9393)
|
||||
@@ -100,6 +53,68 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631)
|
||||
* Add basic repository lfs management (#7199)
|
||||
* BUGFIXES
|
||||
* Fix code-expansion arc-green theme bug (#10180) (#10185)
|
||||
* Prevent double wait-group decrement (#10170) (#10175)
|
||||
* Allow emoji on review head comments (#10159) (#10174)
|
||||
* Fix issue/pull link (#10158) (#10173)
|
||||
* Fix push-create SSH bugs (#10145) (#10151)
|
||||
* Prevent DeleteUser API abuse (#10125) (#10128)
|
||||
* Fix issues/pulls dashboard paging error (#10114) (#10115)
|
||||
* Add button to revert SimpleMDE to plain textarea (#10099) (#10102)
|
||||
* Fix branch page pull request title and link error (#10092) (#10097)
|
||||
* Fix PR API: Only try to get HeadBranch if HeadRepo exist (#10029) (#10088)
|
||||
* Update topics repo count when deleting repository (#10051) (#10081)
|
||||
* Show pull icon on pull requests (#10061) (#10062)
|
||||
* Fix milestone API state parameter unhandled (#10049) (#10052)
|
||||
* Move to using a temporary repo for pushing new PRs (#10009) (#10042)
|
||||
* Fix wiki raw view on sub path (#10002) (#10040)
|
||||
* Ensure that feeds are appropriately restricted (#10018) (#10019)
|
||||
* Sanitize credentials in mirror form (#9975) (#9991)
|
||||
* Close related pull requests when deleting head repository or head branch (#9927) (#9974)
|
||||
* Switch to use -f instead of -F for sendmail (#9961) (#9970)
|
||||
* Fix file rename/copy not supported by indexer (#9965) (#9967)
|
||||
* Fix repo indexer not updating upon push (#9957) (#9963)
|
||||
* Don't convert ellipsis in markdown (#9905) (#9937)
|
||||
* Fixed repo link in generated comment for cross repository dependency (#9863) (#9935)
|
||||
* Check if diff actually contains sections when rendering (#9926) (#9933)
|
||||
* Fix wrong hint when status checking is running on pull request view (#9886) (#9928)
|
||||
* Fix RocketChat (#9908) (#9921)
|
||||
* Do not try to recreate ldap user if they are already created (#9900) (#9919)
|
||||
* Create terminated channel in queue_redis (#9910) (#9911)
|
||||
* Prevent empty LDAP search result from deactivating all users (#9879) (#9896)
|
||||
* Fix wrong permissions check when issues/prs shared operations (#9885) (#9889)
|
||||
* Check user != nil before checking values (#9881) (#9883)
|
||||
* Allow hyphen in language name (#9873) (#9880)
|
||||
* Ensure that 2fa is checked on reset-password (#9857) (#9876)
|
||||
* Fix issues/pulls dependencies problems (#9842) (#9864)
|
||||
* Fix markdown anchor links (#9673) (#9840)
|
||||
* Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9837)
|
||||
* Fix download file wrong content-type (#9825) (#9834)
|
||||
* Fix wrong poster identity on a migrated pull request when submit review (#9827) (#9830)
|
||||
* Fix database dump when log directory is missing (#9818) (#9819)
|
||||
* Fix compare (#9808) (#9814)
|
||||
* Fix push-to-create (#9772) (#9797)
|
||||
* Fix missing msteam webhook on organization (#9781) (#9794)
|
||||
* Fix missing unlock in uniquequeue (#9790) (#9791)
|
||||
* Fix add team on collaborator page when same name as organization (#9778)
|
||||
* DeleteRepoFile incorrectly handles Delete to new branch (#9769) (#9775)
|
||||
* Fix milestones page (#9771)
|
||||
* Fix SimpleMDE quote reply (#9757) (#9768)
|
||||
* Fix missing updated time on migrated issues and comments (#9744) (#9764)
|
||||
* Move Errored PRs out of StatusChecking (#9675) (#9726)
|
||||
* Make hook status printing configurable with delay (#9641) (#9725)
|
||||
* Fix /repos/issues/search (#9698) (#9724)
|
||||
* Silence fomantic error regarding tabs (#9713) (#9718)
|
||||
* Remove unused lock (#9709) (#9710)
|
||||
* Remove q.lock.Unlock() in setInternal to prevent panic (#9705) (#9706)
|
||||
* Load milestone in API PR list (#9671) (#9700)
|
||||
* Don't attempt to close issue if already closed (#9696) (#9699)
|
||||
* Remove google font call (#9668) (#9681)
|
||||
* Eliminate horizontal scroll caused by footer (#9674)
|
||||
* Fix nil reference in repo generation (#9660) (#9666)
|
||||
* Add HTML URL to API Issues (#9654) (#9661)
|
||||
* Add PR review webhook to Telegram (#9653) (#9655)
|
||||
* Use filepath.IsAbs instead of path.IsAbs (#9651) (#9652)
|
||||
* Disable remove button on repository teams when have access to all (#9640)
|
||||
* Clean up old references on branch delete (#9614)
|
||||
* Hide public repos owned by private orgs (#9609)
|
||||
@@ -231,6 +246,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* Fix migrate mirror 500 bug (#8526)
|
||||
* Fix password complexity regex for special characters (on master) (#8525)
|
||||
* ENHANCEMENTS
|
||||
* Explicitly refer to PR in squash-merge commit message in case of external tracker (#9844) (#9855)
|
||||
* Add a /user/login landing page option (#9622)
|
||||
* Some more e-mail notification fixes (#9596)
|
||||
* Add branch protection option to block merge on requested changes. (#9592)
|
||||
@@ -347,12 +363,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* wiki - add 'write' 'preview' buttons to wiki edit like in issues (#7241)
|
||||
* Change target branch for pull request (#6488)
|
||||
* Display PR commits and diffs using base repo rather than forked (#3648)
|
||||
* SECURITY
|
||||
* Swagger hide search field (#9554)
|
||||
* Add "search" to reserved usernames (#9063)
|
||||
* Switch to fomantic-ui (#9374)
|
||||
* Only serve attachments when linked to issue/release and if accessible by user (#9340)
|
||||
* Hide credentials when submitting migration through API (#9102)
|
||||
* TESTING
|
||||
* Add debug option to serv to help debug problems (#9492)
|
||||
* Fix the intermittent TestGPGGit failures (#9360)
|
||||
@@ -366,10 +376,12 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* Update Github Migration Tests (#8893) (#8938)
|
||||
* Update heatmap fixtures to restore tests (#8615)
|
||||
* TRANSLATION
|
||||
* Fix Korean locales (#9761) (#9780)
|
||||
* Fix placeholders in the error message (#9060)
|
||||
* Fix spelling of admin.users.max_repo_creation (#8934)
|
||||
* Improve german translation of homepage (#8549)
|
||||
* BUILD
|
||||
* Fix webpack polyfills (#9735) (#9738)
|
||||
* Update gitea.com/macaron to 1.4.0 (#9608)
|
||||
* Upgrade lato fonts to v16. (#9498)
|
||||
* Update alpine to 3.11 (#9440)
|
||||
@@ -400,6 +412,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
* Update the provided gitea.service to mention socket activation (#8531)
|
||||
* Doc added how to setup email (#8520)
|
||||
* MISC
|
||||
* Backport Locales [2020-01-14] (#9773)
|
||||
* Add translatable Powered by Gitea text in footer (#9600)
|
||||
* Add contrib/environment-to-ini (#9519)
|
||||
* Remove unnecessary loading of settings in update hook (#9496)
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -72,6 +73,7 @@ var (
|
||||
"git-receive-pack": models.AccessModeWrite,
|
||||
lfsAuthenticateVerb: models.AccessModeNone,
|
||||
}
|
||||
alphaDashDotPattern = regexp.MustCompile(`[^\w-\.]`)
|
||||
)
|
||||
|
||||
func fail(userMessage, logMessage string, args ...interface{}) {
|
||||
@@ -147,6 +149,10 @@ func runServ(c *cli.Context) error {
|
||||
username := strings.ToLower(rr[0])
|
||||
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
||||
|
||||
if alphaDashDotPattern.MatchString(reponame) {
|
||||
fail("Invalid repo name", "Invalid repo name: %s", reponame)
|
||||
}
|
||||
|
||||
if setting.EnablePprof || c.Bool("enable-pprof") {
|
||||
if err := os.MkdirAll(setting.PprofDataPath, os.ModePerm); err != nil {
|
||||
fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
|
||||
|
||||
@@ -18,7 +18,7 @@ params:
|
||||
description: Git with a cup of tea
|
||||
author: The Gitea Authors
|
||||
website: https://docs.gitea.io
|
||||
version: 1.10.2
|
||||
version: 1.11.0
|
||||
|
||||
outputs:
|
||||
home:
|
||||
|
||||
47
integrations/api_issue_milestone_test.go
Normal file
47
integrations/api_issue_milestone_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAPIIssuesMilestone(t *testing.T) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
milestone := models.AssertExistsAndLoadBean(t, &models.Milestone{ID: 1}).(*models.Milestone)
|
||||
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: milestone.RepoID}).(*models.Repository)
|
||||
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||
assert.Equal(t, int64(1), int64(milestone.NumIssues))
|
||||
assert.Equal(t, structs.StateOpen, milestone.State())
|
||||
|
||||
session := loginUser(t, owner.Name)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// update values of issue
|
||||
milestoneState := "closed"
|
||||
|
||||
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, milestone.ID, token)
|
||||
req := NewRequestWithJSON(t, "PATCH", urlStr, structs.EditMilestoneOption{
|
||||
State: &milestoneState,
|
||||
})
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiMilestone structs.Milestone
|
||||
DecodeJSON(t, resp, &apiMilestone)
|
||||
assert.EqualValues(t, "closed", apiMilestone.State)
|
||||
|
||||
req = NewRequest(t, "GET", urlStr)
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
var apiMilestone2 structs.Milestone
|
||||
DecodeJSON(t, resp, &apiMilestone2)
|
||||
assert.EqualValues(t, "closed", apiMilestone2.State)
|
||||
}
|
||||
@@ -422,6 +422,9 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", ctx.Reponame)
|
||||
assert.NoError(t, err)
|
||||
|
||||
_, err = git.NewCommand("clone", u.String()).RunInDir(tmpDir)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = git.InitRepository(tmpDir, false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -449,6 +452,13 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
|
||||
_, err = git.NewCommand("remote", "add", "origin", u.String()).RunInDir(tmpDir)
|
||||
assert.NoError(t, err)
|
||||
|
||||
invalidCtx := ctx
|
||||
invalidCtx.Reponame = fmt.Sprintf("invalid/repo-tmp-push-create-%s", u.Scheme)
|
||||
u.Path = invalidCtx.GitPath()
|
||||
|
||||
_, err = git.NewCommand("remote", "add", "invalid", u.String()).RunInDir(tmpDir)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Push to create disabled
|
||||
setting.Repository.EnablePushCreateUser = false
|
||||
_, err = git.NewCommand("push", "origin", "master").RunInDir(tmpDir)
|
||||
@@ -456,6 +466,12 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) {
|
||||
|
||||
// Push to create enabled
|
||||
setting.Repository.EnablePushCreateUser = true
|
||||
|
||||
// Invalid repo
|
||||
_, err = git.NewCommand("push", "invalid", "master").RunInDir(tmpDir)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Valid repo
|
||||
_, err = git.NewCommand("push", "origin", "master").RunInDir(tmpDir)
|
||||
assert.NoError(t, err)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3
|
||||
423313fbd38093bb10d0c8387db9105409c6f196
|
||||
|
||||
@@ -106,3 +106,57 @@ func TestPullCreate_TitleEscape(t *testing.T) {
|
||||
assert.Equal(t, "<u>XSS PR</u>", titleHTML)
|
||||
})
|
||||
}
|
||||
|
||||
func testUIDeleteBranch(t *testing.T, session *TestSession, ownerName, repoName, branchName string) {
|
||||
relURL := "/" + path.Join(ownerName, repoName, "branches")
|
||||
req := NewRequest(t, "GET", relURL)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
req = NewRequestWithValues(t, "POST", relURL+"/delete", map[string]string{
|
||||
"_csrf": getCsrf(t, htmlDoc.doc),
|
||||
"name": branchName,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
}
|
||||
|
||||
func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoName string) {
|
||||
relURL := "/" + path.Join(ownerName, repoName, "settings")
|
||||
req := NewRequest(t, "GET", relURL)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
req = NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{
|
||||
"_csrf": getCsrf(t, htmlDoc.doc),
|
||||
"repo_name": repoName,
|
||||
})
|
||||
session.MakeRequest(t, req, http.StatusFound)
|
||||
}
|
||||
|
||||
func TestPullBranchDelete(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
defer prepareTestEnv(t)()
|
||||
|
||||
session := loginUser(t, "user1")
|
||||
testRepoFork(t, session, "user2", "repo1", "user1", "repo1")
|
||||
testCreateBranch(t, session, "user1", "repo1", "branch/master", "master1", http.StatusFound)
|
||||
testEditFile(t, session, "user1", "repo1", "master1", "README.md", "Hello, World (Edited)\n")
|
||||
resp := testPullCreate(t, session, "user1", "repo1", "master1", "This is a pull title")
|
||||
|
||||
// check the redirected URL
|
||||
url := resp.HeaderMap.Get("Location")
|
||||
assert.Regexp(t, "^/user2/repo1/pulls/[0-9]*$", url)
|
||||
req := NewRequest(t, "GET", url)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// delete head branch and confirm pull page is ok
|
||||
testUIDeleteBranch(t, session, "user1", "repo1", "master1")
|
||||
req = NewRequest(t, "GET", url)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
// delete head repository and confirm pull page is ok
|
||||
testDeleteRepository(t, session, "user1", "repo1")
|
||||
req = NewRequest(t, "GET", url)
|
||||
session.MakeRequest(t, req, http.StatusOK)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -432,6 +432,8 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
|
||||
}
|
||||
|
||||
cond = cond.And(builder.In("repo_id", repoIDs))
|
||||
} else {
|
||||
cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.RequestingUserID)))
|
||||
}
|
||||
|
||||
cond = cond.And(builder.Eq{"user_id": opts.RequestedUser.ID})
|
||||
|
||||
@@ -6,6 +6,7 @@ package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
@@ -95,6 +96,8 @@ func NewMilestone(m *Milestone) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
m.Name = strings.TrimSpace(m.Name)
|
||||
|
||||
if _, err = sess.Insert(m); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -268,6 +271,7 @@ func GetMilestones(repoID int64, page int, isClosed bool, sortType string) (Mile
|
||||
}
|
||||
|
||||
func updateMilestone(e Engine, m *Milestone) error {
|
||||
m.Name = strings.TrimSpace(m.Name)
|
||||
_, err := e.ID(m.ID).AllCols().
|
||||
SetExpr("num_issues", builder.Select("count(*)").From("issue").Where(
|
||||
builder.Eq{"milestone_id": m.ID},
|
||||
@@ -283,12 +287,33 @@ func updateMilestone(e Engine, m *Milestone) error {
|
||||
}
|
||||
|
||||
// UpdateMilestone updates information of given milestone.
|
||||
func UpdateMilestone(m *Milestone) error {
|
||||
if err := updateMilestone(x, m); err != nil {
|
||||
func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return updateMilestoneCompleteness(x, m.ID)
|
||||
if m.IsClosed && !oldIsClosed {
|
||||
m.ClosedDateUnix = timeutil.TimeStampNow()
|
||||
}
|
||||
|
||||
if err := updateMilestone(sess, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := updateMilestoneCompleteness(sess, m.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if IsClosed changed, update milestone numbers of repository
|
||||
if oldIsClosed != m.IsClosed {
|
||||
if err := updateRepoMilestoneNum(sess, m.RepoID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
}
|
||||
|
||||
func updateMilestoneCompleteness(e Engine, milestoneID int64) error {
|
||||
|
||||
@@ -158,10 +158,11 @@ func TestUpdateMilestone(t *testing.T) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
|
||||
milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
|
||||
milestone.Name = "newMilestoneName"
|
||||
milestone.Name = " newMilestoneName "
|
||||
milestone.Content = "newMilestoneContent"
|
||||
assert.NoError(t, UpdateMilestone(milestone))
|
||||
AssertExistsAndLoadBean(t, milestone)
|
||||
assert.NoError(t, UpdateMilestone(milestone, milestone.IsClosed))
|
||||
milestone = AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
|
||||
assert.EqualValues(t, "newMilestoneName", milestone.Name)
|
||||
CheckConsistencyFor(t, &Milestone{})
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,11 @@ type PullRequest struct {
|
||||
// MustHeadUserName returns the HeadRepo's username if failed return blank
|
||||
func (pr *PullRequest) MustHeadUserName() string {
|
||||
if err := pr.LoadHeadRepo(); err != nil {
|
||||
log.Error("LoadHeadRepo: %v", err)
|
||||
if !IsErrRepoNotExist(err) {
|
||||
log.Error("LoadHeadRepo: %v", err)
|
||||
} else {
|
||||
log.Warn("LoadHeadRepo %d but repository does not exist: %v", pr.HeadRepoID, err)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return pr.HeadRepo.MustOwnerName()
|
||||
@@ -416,7 +420,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
|
||||
err error
|
||||
)
|
||||
if err = pr.Issue.loadRepo(e); err != nil {
|
||||
log.Error("loadRepo[%d]: %v", pr.ID, err)
|
||||
log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
apiIssue := pr.Issue.apiFormat(e)
|
||||
@@ -427,19 +431,14 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if pr.HeadRepo == nil {
|
||||
if pr.HeadRepoID != 0 && pr.HeadRepo == nil {
|
||||
pr.HeadRepo, err = getRepositoryByID(e, pr.HeadRepoID)
|
||||
if err != nil {
|
||||
if err != nil && !IsErrRepoNotExist(err) {
|
||||
log.Error("GetRepositoryById[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if err = pr.Issue.loadRepo(e); err != nil {
|
||||
log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
apiPullRequest := &api.PullRequest{
|
||||
ID: pr.ID,
|
||||
URL: pr.Issue.HTMLURL(),
|
||||
@@ -491,33 +490,41 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
|
||||
apiPullRequest.Base = apiBaseBranchInfo
|
||||
}
|
||||
|
||||
headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
|
||||
if err != nil {
|
||||
if git.IsErrBranchNotExist(err) {
|
||||
apiPullRequest.Head = nil
|
||||
} else {
|
||||
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
apiHeadBranchInfo := &api.PRBranchInfo{
|
||||
Name: pr.HeadBranch,
|
||||
Ref: pr.HeadBranch,
|
||||
RepoID: pr.HeadRepoID,
|
||||
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
|
||||
}
|
||||
headCommit, err = headBranch.GetCommit()
|
||||
if pr.HeadRepo != nil {
|
||||
headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
apiHeadBranchInfo.Sha = ""
|
||||
if git.IsErrBranchNotExist(err) {
|
||||
apiPullRequest.Head = nil
|
||||
} else {
|
||||
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
|
||||
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
apiHeadBranchInfo.Sha = headCommit.ID.String()
|
||||
apiHeadBranchInfo := &api.PRBranchInfo{
|
||||
Name: pr.HeadBranch,
|
||||
Ref: pr.HeadBranch,
|
||||
RepoID: pr.HeadRepoID,
|
||||
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
|
||||
}
|
||||
headCommit, err = headBranch.GetCommit()
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
apiHeadBranchInfo.Sha = ""
|
||||
} else {
|
||||
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
apiHeadBranchInfo.Sha = headCommit.ID.String()
|
||||
}
|
||||
apiPullRequest.Head = apiHeadBranchInfo
|
||||
}
|
||||
} else {
|
||||
apiPullRequest.Head = &api.PRBranchInfo{
|
||||
Name: pr.HeadBranch,
|
||||
Ref: fmt.Sprintf("refs/pull/%d/head", pr.Index),
|
||||
RepoID: -1,
|
||||
}
|
||||
apiPullRequest.Head = apiHeadBranchInfo
|
||||
}
|
||||
|
||||
if pr.Status != PullRequestStatusChecking {
|
||||
|
||||
@@ -204,6 +204,14 @@ type Repository struct {
|
||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||
}
|
||||
|
||||
// SanitizedOriginalURL returns a sanitized OriginalURL
|
||||
func (repo *Repository) SanitizedOriginalURL() string {
|
||||
if repo.OriginalURL == "" {
|
||||
return ""
|
||||
}
|
||||
return util.SanitizeURLCredentials(repo.OriginalURL, false)
|
||||
}
|
||||
|
||||
// ColorFormat returns a colored string to represent this repo
|
||||
func (repo *Repository) ColorFormat(s fmt.State) {
|
||||
var ownerName interface{}
|
||||
@@ -1902,6 +1910,12 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(repo.Topics) > 0 {
|
||||
if err = removeTopicsFromRepo(sess, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Remove repository files should be executed after transaction succeed.
|
||||
repoPath := repo.repoPath(sess)
|
||||
removeAllWithNotice(sess, "Delete repository files", repoPath)
|
||||
|
||||
@@ -315,6 +315,17 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
||||
|
||||
// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
|
||||
func accessibleRepositoryCondition(userID int64) builder.Cond {
|
||||
if userID <= 0 {
|
||||
return builder.And(
|
||||
builder.Eq{"`repository`.is_private": false},
|
||||
builder.Or(
|
||||
// A. Aren't in organisations __OR__
|
||||
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"type": UserTypeOrganization})),
|
||||
// B. Is a public organisation.
|
||||
builder.In("`repository`.owner_id", builder.Select("id").From("`user`").Where(builder.Eq{"visibility": structs.VisibleTypePublic}))),
|
||||
)
|
||||
}
|
||||
|
||||
return builder.Or(
|
||||
// 1. Be able to see all non-private repositories that either:
|
||||
builder.And(
|
||||
@@ -349,6 +360,12 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
|
||||
return SearchRepository(opts)
|
||||
}
|
||||
|
||||
// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered.
|
||||
func AccessibleRepoIDsQuery(userID int64) *builder.Builder {
|
||||
// NB: Please note this code needs to still work if user is nil
|
||||
return builder.Select("id").From("repository").Where(accessibleRepositoryCondition(userID))
|
||||
}
|
||||
|
||||
// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
|
||||
func FindUserAccessibleRepoIDs(userID int64) ([]int64, error) {
|
||||
var accessCond builder.Cond = builder.Eq{"is_private": false}
|
||||
|
||||
@@ -129,7 +129,7 @@ func addTopicByNameToRepo(e Engine, repoID int64, topicName string) (*Topic, err
|
||||
}
|
||||
|
||||
// removeTopicFromRepo remove a topic from a repo and decrements the topic repo count
|
||||
func removeTopicFromRepo(repoID int64, topic *Topic, e Engine) error {
|
||||
func removeTopicFromRepo(e Engine, repoID int64, topic *Topic) error {
|
||||
topic.RepoCount--
|
||||
if _, err := e.ID(topic.ID).Cols("repo_count").Update(topic); err != nil {
|
||||
return err
|
||||
@@ -145,6 +145,24 @@ func removeTopicFromRepo(repoID int64, topic *Topic, e Engine) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeTopicsFromRepo remove all topics from the repo and decrements respective topics repo count
|
||||
func removeTopicsFromRepo(e Engine, repoID int64) error {
|
||||
_, err := e.Where(
|
||||
builder.In("id",
|
||||
builder.Select("topic_id").From("repo_topic").Where(builder.Eq{"repo_id": repoID}),
|
||||
),
|
||||
).Cols("repo_count").SetExpr("repo_count", "repo_count-1").Update(&Topic{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = e.Delete(&RepoTopic{RepoID: repoID}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindTopicOptions represents the options when fdin topics
|
||||
type FindTopicOptions struct {
|
||||
RepoID int64
|
||||
@@ -217,7 +235,7 @@ func DeleteTopic(repoID int64, topicName string) (*Topic, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err = removeTopicFromRepo(repoID, topic, x)
|
||||
err = removeTopicFromRepo(x, repoID, topic)
|
||||
|
||||
return topic, err
|
||||
}
|
||||
@@ -278,7 +296,7 @@ func SaveTopics(repoID int64, topicNames ...string) error {
|
||||
}
|
||||
|
||||
for _, topic := range removeTopics {
|
||||
err := removeTopicFromRepo(repoID, topic, sess)
|
||||
err := removeTopicFromRepo(sess, repoID, topic)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -215,9 +216,12 @@ func (wl *wrappedListener) Accept() (net.Conn, error) {
|
||||
}
|
||||
}
|
||||
|
||||
closed := int32(0)
|
||||
|
||||
c = wrappedConn{
|
||||
Conn: c,
|
||||
server: wl.server,
|
||||
closed: &closed,
|
||||
}
|
||||
|
||||
wl.server.wg.Add(1)
|
||||
@@ -241,12 +245,12 @@ func (wl *wrappedListener) File() (*os.File, error) {
|
||||
type wrappedConn struct {
|
||||
net.Conn
|
||||
server *Server
|
||||
closed *int32
|
||||
}
|
||||
|
||||
func (w wrappedConn) Close() error {
|
||||
err := w.Conn.Close()
|
||||
if err == nil {
|
||||
if atomic.CompareAndSwapInt32(w.closed, 0, 1) {
|
||||
w.server.wg.Done()
|
||||
}
|
||||
return err
|
||||
return w.Conn.Close()
|
||||
}
|
||||
|
||||
@@ -116,7 +116,12 @@ func nonGenesisChanges(repo *models.Repository, revision string) (*repoChanges,
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
filename := strings.TrimSpace(line[1:])
|
||||
fields := strings.Split(line, "\t")
|
||||
if len(fields) < 2 {
|
||||
log.Warn("Unparseable output for diff --name-status: `%s`)", line)
|
||||
continue
|
||||
}
|
||||
filename := fields[1]
|
||||
if len(filename) == 0 {
|
||||
continue
|
||||
} else if filename[0] == '"' {
|
||||
@@ -126,11 +131,31 @@ func nonGenesisChanges(repo *models.Repository, revision string) (*repoChanges,
|
||||
}
|
||||
}
|
||||
|
||||
switch status := line[0]; status {
|
||||
switch status := fields[0][0]; status {
|
||||
case 'M', 'A':
|
||||
updatedFilenames = append(updatedFilenames, filename)
|
||||
case 'D':
|
||||
changes.RemovedFilenames = append(changes.RemovedFilenames, filename)
|
||||
case 'R', 'C':
|
||||
if len(fields) < 3 {
|
||||
log.Warn("Unparseable output for diff --name-status: `%s`)", line)
|
||||
continue
|
||||
}
|
||||
dest := fields[2]
|
||||
if len(dest) == 0 {
|
||||
log.Warn("Unparseable output for diff --name-status: `%s`)", line)
|
||||
continue
|
||||
}
|
||||
if dest[0] == '"' {
|
||||
dest, err = strconv.Unquote(dest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if status == 'R' {
|
||||
changes.RemovedFilenames = append(changes.RemovedFilenames, filename)
|
||||
}
|
||||
updatedFilenames = append(updatedFilenames, dest)
|
||||
default:
|
||||
log.Warn("Unrecognized status: %c (line=%s)", status, line)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package indexer
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
code_indexer "code.gitea.io/gitea/modules/indexer/code"
|
||||
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
@@ -118,7 +119,7 @@ func (r *indexerNotifier) NotifyMigrateRepository(doer *models.User, u *models.U
|
||||
}
|
||||
|
||||
func (r *indexerNotifier) NotifyPushCommits(pusher *models.User, repo *models.Repository, refName, oldCommitID, newCommitID string, commits *models.PushCommits) {
|
||||
if setting.Indexer.RepoIndexerEnabled && refName == repo.DefaultBranch {
|
||||
if setting.Indexer.RepoIndexerEnabled && refName == git.BranchPrefix+repo.DefaultBranch {
|
||||
code_indexer.UpdateRepoIndexer(repo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,9 +475,18 @@ func PushUpdate(repo *models.Repository, branch string, opts PushUpdateOptions)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name)
|
||||
if !isDelRef {
|
||||
if err = models.RemoveDeletedBranch(repo.ID, opts.Branch); err != nil {
|
||||
log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, opts.Branch, err)
|
||||
}
|
||||
|
||||
go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true)
|
||||
log.Trace("TriggerTask '%s/%s' by %s", repo.Name, branch, pusher.Name)
|
||||
|
||||
go pull_service.AddTestPullRequestTask(pusher, repo.ID, branch, true)
|
||||
// close all related pulls
|
||||
} else if err = pull_service.CloseBranchPulls(pusher, repo.ID, branch); err != nil {
|
||||
log.Error("close related pull request failed: %v", err)
|
||||
}
|
||||
|
||||
if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
|
||||
log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
|
||||
@@ -524,12 +533,15 @@ func PushUpdates(repo *models.Repository, optsList []*PushUpdateOptions) error {
|
||||
if err = models.RemoveDeletedBranch(repo.ID, opts.Branch); err != nil {
|
||||
log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, opts.Branch, err)
|
||||
}
|
||||
|
||||
log.Trace("TriggerTask '%s/%s' by %s", repo.Name, opts.Branch, pusher.Name)
|
||||
|
||||
go pull_service.AddTestPullRequestTask(pusher, repo.ID, opts.Branch, true)
|
||||
// close all related pulls
|
||||
} else if err = pull_service.CloseBranchPulls(pusher, repo.ID, opts.Branch); err != nil {
|
||||
log.Error("close related pull request failed: %v", err)
|
||||
}
|
||||
|
||||
log.Trace("TriggerTask '%s/%s' by %s", repo.Name, opts.Branch, pusher.Name)
|
||||
|
||||
go pull_service.AddTestPullRequestTask(pusher, repo.ID, opts.Branch, true)
|
||||
|
||||
if err = models.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil {
|
||||
log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ package util
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// urlSafeError wraps an error whose message may contain a sensitive URL
|
||||
@@ -36,6 +38,7 @@ func SanitizeMessage(message, unsanitizedURL string) string {
|
||||
func SanitizeURLCredentials(unsanitizedURL string, usePlaceholder bool) string {
|
||||
u, err := url.Parse(unsanitizedURL)
|
||||
if err != nil {
|
||||
log.Error("parse url %s failed: %v", unsanitizedURL, err)
|
||||
// don't log the error, since it might contain unsanitized URL.
|
||||
return "(unparsable url)"
|
||||
}
|
||||
|
||||
25
modules/util/sanitize_test.go
Normal file
25
modules/util/sanitize_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSanitizeURLCredentials(t *testing.T) {
|
||||
var kases = map[string]string{
|
||||
"https://github.com/go-gitea/test_repo.git": "https://github.com/go-gitea/test_repo.git",
|
||||
"https://mytoken@github.com/go-gitea/test_repo.git": "https://github.com/go-gitea/test_repo.git",
|
||||
"http://github.com/go-gitea/test_repo.git": "http://github.com/go-gitea/test_repo.git",
|
||||
"/test/repos/repo1": "/test/repos/repo1",
|
||||
"git@github.com:go-gitea/test_repo.git": "(unparsable url)",
|
||||
}
|
||||
|
||||
for source, value := range kases {
|
||||
assert.EqualValues(t, value, SanitizeURLCredentials(source, false))
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
@@ -226,6 +227,11 @@ func DeleteUser(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if u.IsOrganization() {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", u.Name))
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.DeleteUser(u); err != nil {
|
||||
if models.IsErrUserOwnRepos(err) ||
|
||||
models.IsErrUserHasOrgs(err) {
|
||||
|
||||
@@ -194,7 +194,12 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
|
||||
milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
if err := models.UpdateMilestone(milestone); err != nil {
|
||||
var oldIsClosed = milestone.IsClosed
|
||||
if form.State != nil {
|
||||
milestone.IsClosed = *form.State == string(api.StateClosed)
|
||||
}
|
||||
|
||||
if err := models.UpdateMilestone(milestone, oldIsClosed); err != nil {
|
||||
ctx.ServerError("UpdateMilestone", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ func SettingsDeleteAvatar(ctx *context.Context) {
|
||||
ctx.Redirect(ctx.Org.OrgLink + "/settings")
|
||||
}
|
||||
|
||||
// SettingsDelete response for delete repository
|
||||
// SettingsDelete response for deleting an organization
|
||||
func SettingsDelete(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("org.settings")
|
||||
ctx.Data["PageIsSettingsDelete"] = true
|
||||
|
||||
@@ -68,7 +68,6 @@ func ServNoCommand(ctx *macaron.Context) {
|
||||
|
||||
// ServCommand returns information about the provided keyid
|
||||
func ServCommand(ctx *macaron.Context) {
|
||||
// Although we provide the verbs we don't need them at present they're just for logging purposes
|
||||
keyID := ctx.ParamsInt64(":keyid")
|
||||
ownerName := ctx.Params(":owner")
|
||||
repoName := ctx.Params(":repo")
|
||||
@@ -105,6 +104,17 @@ func ServCommand(ctx *macaron.Context) {
|
||||
if err != nil {
|
||||
if models.IsErrRepoNotExist(err) {
|
||||
repoExist = false
|
||||
for _, verb := range ctx.QueryStrings("verb") {
|
||||
if "git-upload-pack" == verb {
|
||||
// User is fetching/cloning a non-existent repository
|
||||
ctx.JSON(http.StatusNotFound, map[string]interface{}{
|
||||
"results": results,
|
||||
"type": "ErrRepoNotExist",
|
||||
"err": fmt.Sprintf("Cannot find repository: %s/%s", results.OwnerName, results.RepoName),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
|
||||
@@ -238,6 +238,7 @@ func loadBranches(ctx *context.Context) []*Branch {
|
||||
} else {
|
||||
repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo
|
||||
}
|
||||
pr.Issue.Repo = pr.BaseRepo
|
||||
|
||||
if pr.HasMerged {
|
||||
baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
|
||||
@@ -260,7 +261,6 @@ func loadBranches(ctx *context.Context) []*Branch {
|
||||
mergeMovedOn = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
isIncluded := divergence.Ahead == 0 && ctx.Repo.Repository.DefaultBranch != branchName
|
||||
|
||||
@@ -192,7 +192,7 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
m.Name = form.Title
|
||||
m.Content = form.Content
|
||||
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||
if err = models.UpdateMilestone(m); err != nil {
|
||||
if err = models.UpdateMilestone(m, m.IsClosed); err != nil {
|
||||
ctx.ServerError("UpdateMilestone", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -66,27 +66,20 @@ type PageMeta struct {
|
||||
|
||||
// findEntryForFile finds the tree entry for a target filepath.
|
||||
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) {
|
||||
entries, err := commit.ListEntries()
|
||||
if err != nil {
|
||||
entry, err := commit.GetTreeEntryByPath(target)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
// The longest name should be checked first
|
||||
for _, entry := range entries {
|
||||
if entry.IsRegular() && entry.Name() == target {
|
||||
return entry, nil
|
||||
}
|
||||
if entry != nil {
|
||||
return entry, nil
|
||||
}
|
||||
|
||||
// Then the unescaped, shortest alternative
|
||||
var unescapedTarget string
|
||||
if unescapedTarget, err = url.QueryUnescape(target); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if entry.IsRegular() && entry.Name() == unescapedTarget {
|
||||
return entry, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return commit.GetTreeEntryByPath(unescapedTarget)
|
||||
}
|
||||
|
||||
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
|
||||
@@ -123,10 +116,9 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
|
||||
// wikiContentsByName returns the contents of a wiki page, along with a boolean
|
||||
// indicating whether the page exists. Writes to ctx if an error occurs.
|
||||
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) {
|
||||
var entry *git.TreeEntry
|
||||
var err error
|
||||
pageFilename := wiki_service.NameToFilename(wikiName)
|
||||
if entry, err = findEntryForFile(commit, pageFilename); err != nil {
|
||||
entry, err := findEntryForFile(commit, pageFilename)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("findEntryForFile", err)
|
||||
return nil, nil, "", false
|
||||
} else if entry == nil {
|
||||
@@ -518,7 +510,7 @@ func WikiRaw(ctx *context.Context) {
|
||||
if commit != nil {
|
||||
// Try to find a file with that name
|
||||
entry, err = findEntryForFile(commit, providedPath)
|
||||
if err != nil {
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("findFile", err)
|
||||
return
|
||||
}
|
||||
@@ -531,7 +523,7 @@ func WikiRaw(ctx *context.Context) {
|
||||
|
||||
wikiPath := wiki_service.NameToFilename(providedPath)
|
||||
entry, err = findEntryForFile(commit, wikiPath)
|
||||
if err != nil {
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
ctx.ServerError("findFile", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -192,6 +192,7 @@ func TestDeleteWikiPagePost(t *testing.T) {
|
||||
func TestWikiRaw(t *testing.T) {
|
||||
for filepath, filetype := range map[string]string{
|
||||
"jpeg.jpg": "image/jpeg",
|
||||
"images/jpeg.jpg": "image/jpeg",
|
||||
"Page With Spaced Name": "text/plain; charset=utf-8",
|
||||
"Page-With-Spaced-Name": "text/plain; charset=utf-8",
|
||||
"Page With Spaced Name.md": "text/plain; charset=utf-8",
|
||||
|
||||
@@ -475,12 +475,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
// ***** END: Admin *****
|
||||
|
||||
m.Group("", func() {
|
||||
m.Group("/:username", func() {
|
||||
m.Get("", user.Profile)
|
||||
m.Get("/followers", user.Followers)
|
||||
m.Get("/following", user.Following)
|
||||
})
|
||||
|
||||
m.Get("/:username", user.Profile)
|
||||
m.Get("/attachments/:uuid", repo.GetAttachment)
|
||||
}, ignSignIn)
|
||||
|
||||
|
||||
@@ -142,11 +142,17 @@ func Dashboard(ctx *context.Context) {
|
||||
ctx.Data["MirrorCount"] = len(mirrors)
|
||||
ctx.Data["Mirrors"] = mirrors
|
||||
|
||||
requestingUserID := int64(0)
|
||||
if ctx.User != nil {
|
||||
requestingUserID = ctx.User.ID
|
||||
}
|
||||
|
||||
retrieveFeeds(ctx, models.GetFeedsOptions{
|
||||
RequestedUser: ctxUser,
|
||||
IncludePrivate: true,
|
||||
OnlyPerformedBy: false,
|
||||
IncludeDeleted: false,
|
||||
RequestedUser: ctxUser,
|
||||
RequestingUserID: requestingUserID,
|
||||
IncludePrivate: true,
|
||||
OnlyPerformedBy: false,
|
||||
IncludeDeleted: false,
|
||||
})
|
||||
|
||||
if ctx.Written() {
|
||||
@@ -519,13 +525,17 @@ func Issues(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
issueStats, err := models.GetUserIssueStats(models.UserIssueStatsOptions{
|
||||
issueStatsOpts := models.UserIssueStatsOptions{
|
||||
UserID: ctxUser.ID,
|
||||
UserRepoIDs: userRepoIDs,
|
||||
FilterMode: filterMode,
|
||||
IsPull: isPullList,
|
||||
IsClosed: isShowClosed,
|
||||
})
|
||||
}
|
||||
if len(repoIDs) > 0 {
|
||||
issueStatsOpts.UserRepoIDs = repoIDs
|
||||
}
|
||||
issueStats, err := models.GetUserIssueStats(issueStatsOpts)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetUserIssueStats", err)
|
||||
return
|
||||
|
||||
@@ -11,16 +11,10 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/org"
|
||||
"code.gitea.io/gitea/routers/repo"
|
||||
)
|
||||
|
||||
const (
|
||||
tplFollowers base.TplName = "user/meta/followers"
|
||||
)
|
||||
|
||||
// GetUserByName get user by name
|
||||
@@ -156,14 +150,38 @@ func Profile(ctx *context.Context) {
|
||||
orderBy = models.SearchOrderByRecentUpdated
|
||||
}
|
||||
|
||||
requestingUserID := int64(0)
|
||||
if ctx.User != nil {
|
||||
requestingUserID = ctx.User.ID
|
||||
}
|
||||
|
||||
keyword := strings.Trim(ctx.Query("q"), " ")
|
||||
ctx.Data["Keyword"] = keyword
|
||||
switch tab {
|
||||
case "followers":
|
||||
items, err := ctxUser.GetFollowers(page)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetFollowers", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Cards"] = items
|
||||
|
||||
total = ctxUser.NumFollowers
|
||||
case "following":
|
||||
items, err := ctxUser.GetFollowing(page)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetFollowing", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Cards"] = items
|
||||
|
||||
total = ctxUser.NumFollowing
|
||||
case "activity":
|
||||
retrieveFeeds(ctx, models.GetFeedsOptions{RequestedUser: ctxUser,
|
||||
IncludePrivate: showPrivate,
|
||||
OnlyPerformedBy: true,
|
||||
IncludeDeleted: false,
|
||||
RequestingUserID: requestingUserID,
|
||||
IncludePrivate: showPrivate,
|
||||
OnlyPerformedBy: true,
|
||||
IncludeDeleted: false,
|
||||
})
|
||||
if ctx.Written() {
|
||||
return
|
||||
@@ -223,32 +241,6 @@ func Profile(ctx *context.Context) {
|
||||
ctx.HTML(200, tplProfile)
|
||||
}
|
||||
|
||||
// Followers render user's followers page
|
||||
func Followers(ctx *context.Context) {
|
||||
u := GetUserByParams(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
ctx.Data["Title"] = u.DisplayName()
|
||||
ctx.Data["CardsTitle"] = ctx.Tr("user.followers")
|
||||
ctx.Data["PageIsFollowers"] = true
|
||||
ctx.Data["Owner"] = u
|
||||
repo.RenderUserCards(ctx, u.NumFollowers, u.GetFollowers, tplFollowers)
|
||||
}
|
||||
|
||||
// Following render user's followering page
|
||||
func Following(ctx *context.Context) {
|
||||
u := GetUserByParams(ctx)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
ctx.Data["Title"] = u.DisplayName()
|
||||
ctx.Data["CardsTitle"] = ctx.Tr("user.following")
|
||||
ctx.Data["PageIsFollowing"] = true
|
||||
ctx.Data["Owner"] = u
|
||||
repo.RenderUserCards(ctx, u.NumFollowing, u.GetFollowing, tplFollowers)
|
||||
}
|
||||
|
||||
// Action response for follow/unfollow user request
|
||||
func Action(ctx *context.Context) {
|
||||
u := GetUserByParams(ctx)
|
||||
|
||||
@@ -213,7 +213,7 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error {
|
||||
var closeError error
|
||||
var waitError error
|
||||
|
||||
args := []string{"-F", from, "-i"}
|
||||
args := []string{"-f", from, "-i"}
|
||||
args = append(args, setting.MailService.SendmailArgs...)
|
||||
args = append(args, to...)
|
||||
log.Trace("Sending with: %s %v", setting.MailService.SendmailPath, args)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
@@ -217,23 +218,39 @@ func AddTestPullRequestTask(doer *models.User, repoID int64, branch string, isSy
|
||||
func PushToBaseRepo(pr *models.PullRequest) (err error) {
|
||||
log.Trace("PushToBaseRepo[%d]: pushing commits to base repo '%s'", pr.BaseRepoID, pr.GetGitRefName())
|
||||
|
||||
// Clone base repo.
|
||||
tmpBasePath, err := models.CreateTemporaryPath("pull")
|
||||
if err != nil {
|
||||
log.Error("CreateTemporaryPath: %v", err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
err := models.RemoveTemporaryPath(tmpBasePath)
|
||||
if err != nil {
|
||||
log.Error("Error whilst removing temporary path: %s Error: %v", tmpBasePath, err)
|
||||
}
|
||||
}()
|
||||
|
||||
headRepoPath := pr.HeadRepo.RepoPath()
|
||||
headGitRepo, err := git.OpenRepository(headRepoPath)
|
||||
|
||||
if err := git.Clone(headRepoPath, tmpBasePath, git.CloneRepoOptions{
|
||||
Bare: true,
|
||||
Shared: true,
|
||||
Branch: pr.HeadBranch,
|
||||
Quiet: true,
|
||||
}); err != nil {
|
||||
log.Error("git clone tmpBasePath: %v", err)
|
||||
return err
|
||||
}
|
||||
gitRepo, err := git.OpenRepository(tmpBasePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("OpenRepository: %v", err)
|
||||
}
|
||||
defer headGitRepo.Close()
|
||||
|
||||
tmpRemoteName := fmt.Sprintf("tmp-pull-%d", pr.ID)
|
||||
if err = headGitRepo.AddRemote(tmpRemoteName, pr.BaseRepo.RepoPath(), false); err != nil {
|
||||
return fmt.Errorf("headGitRepo.AddRemote: %v", err)
|
||||
if err := gitRepo.AddRemote("base", pr.BaseRepo.RepoPath(), false); err != nil {
|
||||
return fmt.Errorf("tmpGitRepo.AddRemote: %v", err)
|
||||
}
|
||||
// Make sure to remove the remote even if the push fails
|
||||
defer func() {
|
||||
if err := headGitRepo.RemoveRemote(tmpRemoteName); err != nil {
|
||||
log.Error("PushToBaseRepo: RemoveRemote: %s", err)
|
||||
}
|
||||
}()
|
||||
defer gitRepo.Close()
|
||||
|
||||
headFile := pr.GetGitRefName()
|
||||
|
||||
@@ -249,15 +266,91 @@ func PushToBaseRepo(pr *models.PullRequest) (err error) {
|
||||
return fmt.Errorf("unable to load poster %d for pr %d: %v", pr.Issue.PosterID, pr.ID, err)
|
||||
}
|
||||
|
||||
if err = git.Push(headRepoPath, git.PushOptions{
|
||||
Remote: tmpRemoteName,
|
||||
if err = git.Push(tmpBasePath, git.PushOptions{
|
||||
Remote: "base",
|
||||
Branch: fmt.Sprintf("%s:%s", pr.HeadBranch, headFile),
|
||||
Force: true,
|
||||
// Use InternalPushingEnvironment here because we know that pre-receive and post-receive do not run on a refs/pulls/...
|
||||
Env: models.InternalPushingEnvironment(pr.Issue.Poster, pr.BaseRepo),
|
||||
}); err != nil {
|
||||
return fmt.Errorf("Push: %v", err)
|
||||
return fmt.Errorf("Push: %s:%s %s:%s %v", pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseRepo.FullName(), headFile, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type errlist []error
|
||||
|
||||
func (errs errlist) Error() string {
|
||||
if len(errs) > 0 {
|
||||
var buf strings.Builder
|
||||
for i, err := range errs {
|
||||
if i > 0 {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
buf.WriteString(err.Error())
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// CloseBranchPulls close all the pull requests who's head branch is the branch
|
||||
func CloseBranchPulls(doer *models.User, repoID int64, branch string) error {
|
||||
prs, err := models.GetUnmergedPullRequestsByHeadInfo(repoID, branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prs2, err := models.GetUnmergedPullRequestsByBaseInfo(repoID, branch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
prs = append(prs, prs2...)
|
||||
if err := models.PullRequestList(prs).LoadAttributes(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var errs errlist
|
||||
for _, pr := range prs {
|
||||
if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !models.IsErrIssueWasClosed(err) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseRepoBranchesPulls close all pull requests which head branches are in the given repository
|
||||
func CloseRepoBranchesPulls(doer *models.User, repo *models.Repository) error {
|
||||
branches, err := git.GetBranchesByPath(repo.RepoPath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var errs errlist
|
||||
for _, branch := range branches {
|
||||
prs, err := models.GetUnmergedPullRequestsByHeadInfo(repo.ID, branch.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = models.PullRequestList(prs).LoadAttributes(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, pr := range prs {
|
||||
if err = issue_service.ChangeStatus(pr.Issue, doer, true); err != nil && !models.IsErrIssueWasClosed(err) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
)
|
||||
|
||||
// CreateRepository creates a repository for the user/organization.
|
||||
@@ -48,6 +49,10 @@ func ForkRepository(doer, u *models.User, oldRepo *models.Repository, name, desc
|
||||
|
||||
// DeleteRepository deletes a repository for a user or organization.
|
||||
func DeleteRepository(doer *models.User, repo *models.Repository) error {
|
||||
if err := pull_service.CloseRepoBranchesPulls(doer, repo); err != nil {
|
||||
log.Error("CloseRepoBranchesPulls failed: %v", err)
|
||||
}
|
||||
|
||||
if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</td>
|
||||
<td class="two wide right aligned">
|
||||
<td class="three wide right aligned">
|
||||
{{if not .LatestPullRequest}}
|
||||
{{if .IsIncluded}}
|
||||
<a class="ui poping up orange small label" data-content="{{$.i18n.Tr "repo.branch.included_desc"}}" data-variation="tiny inverted" data-position="top right">
|
||||
@@ -91,13 +91,13 @@
|
||||
</a>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}">#{{.LatestPullRequest.Issue.Index}}</a>
|
||||
<a href="{{.LatestPullRequest.Issue.HTMLURL}}">{{if ne .LatestPullRequest.BaseRepoID .LatestPullRequest.HeadRepoID}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
|
||||
{{if .LatestPullRequest.HasMerged}}
|
||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui purple small label"><i class="octicon octicon-git-pull-request"></i> {{$.i18n.Tr "repo.pulls.merged"}}</a>
|
||||
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui purple mini label"><i class="octicon octicon-git-pull-request"></i> {{$.i18n.Tr "repo.pulls.merged"}}</a>
|
||||
{{else if .LatestPullRequest.Issue.IsClosed}}
|
||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui red small label"><i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.closed_title"}}</a>
|
||||
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui red mini label"><i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.closed_title"}}</a>
|
||||
{{else}}
|
||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui green small label"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.open_title"}}</a>
|
||||
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui green mini label"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.open_title"}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</td>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
{{if and .RelAvatarLink .IsPrivate}}<i class="mega-octicon octicon-lock"></i>{{end}}
|
||||
{{if .IsTemplate}}<i class="icon fa-copy"></i>{{end}}
|
||||
{{if .IsArchived}}<i class="archive icon archived-icon"></i>{{end}}
|
||||
{{if .IsMirror}}<div class="fork-flag">{{$.i18n.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener noreferrer" href="{{MirrorAddress $.Mirror}}">{{MirrorAddress $.Mirror}}</a></div>{{end}}
|
||||
{{if .IsMirror}}<div class="fork-flag">{{$.i18n.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener noreferrer" href="{{if .SanitizedOriginalURL}}{{.SanitizedOriginalURL}}{{else}}{{MirrorAddress $.Mirror}}{{end}}">{{if .SanitizedOriginalURL}}{{.SanitizedOriginalURL}}{{else}}{{MirrorAddress $.Mirror}}{{end}}</a></div>{{end}}
|
||||
{{if .IsFork}}<div class="fork-flag">{{$.i18n.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{SubStr .BaseRepo.RelLink 1 -1}}</a></div>{{end}}
|
||||
{{if .IsGenerated}}<div class="fork-flag">{{$.i18n.Tr "repo.generated_from"}} <a href="{{.TemplateRepo.Link}}">{{SubStr .TemplateRepo.RelLink 1 -1}}</a></div>{{end}}
|
||||
</div>
|
||||
|
||||
@@ -336,7 +336,7 @@
|
||||
{{if .Content}}
|
||||
<div class="detail">
|
||||
<span class="octicon octicon-quote"></span>
|
||||
<span class="text grey">{{.Content}}</span>
|
||||
<span class="text grey has-emoji">{{.Content}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
{{ range $filename, $lines := .Review.CodeComments}}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
<div class="ui purple large label"><i class="octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls.merged"}}</div>
|
||||
{{else if .Issue.IsClosed}}
|
||||
<div class="ui red large label"><i class="octicon octicon-issue-closed"></i> {{.i18n.Tr "repo.issues.closed_title"}}</div>
|
||||
{{else if .Issue.IsPull}}
|
||||
<div class="ui green large label"><i class="octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.issues.open_title"}}</div>
|
||||
{{else}}
|
||||
<div class="ui green large label"><i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues.open_title"}}</div>
|
||||
{{end}}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<div class="ui container user-cards">
|
||||
{{if .CardsTitle}}
|
||||
<h2 class="ui dividing header">
|
||||
{{.CardsTitle}}
|
||||
</h2>
|
||||
{{end}}
|
||||
<ul class="list">
|
||||
{{range .Cards}}
|
||||
<li class="item ui segment">
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
{{if .Repo}}
|
||||
<li class="item">
|
||||
<div class="ui label">{{.Repo.FullName}}#{{.Index}}</div>
|
||||
<a class="title has-emoji" href="{{AppSubUrl}}/{{.Repo.Owner.Name}}/{{.Repo.Name}}/issues/{{.Index}}">{{.Title}}</a>
|
||||
<a class="title has-emoji" href="{{.HTMLURL}}">{{.Title}}</a>
|
||||
|
||||
{{if .IsPull }}
|
||||
{{if (index $.CommitStatus .PullRequest.ID)}}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{{template "base/head" .}}
|
||||
<div class="user followers">
|
||||
{{template "user/meta/header" .}}
|
||||
{{template "repo/user_cards" .}}
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
@@ -1,24 +0,0 @@
|
||||
{{with .Owner}}
|
||||
<div class="ui container">
|
||||
<img class="ui avatar image" src="{{.RelAvatarLink}}">
|
||||
<span class="header name">
|
||||
<a href="{{.HomeLink}}">{{.Name}}</a>
|
||||
{{with .FullName}}({{.}}){{end}}
|
||||
</span>
|
||||
|
||||
<div class="ui right">
|
||||
{{if or $.PageIsFollowers $.PageIsFollowing}}
|
||||
{{if and $.IsSigned (ne $.SignedUserName .Name)}}
|
||||
<div class="follow">
|
||||
{{if $.SignedUser.IsFollowing .ID}}
|
||||
<a class="ui small basic red button" href="{{.HomeLink}}/action/unfollow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{$.i18n.Tr "user.unfollow"}}</a>
|
||||
{{else}}
|
||||
<a class="ui small basic green button" href="{{.HomeLink}}/action/follow?redirect_to={{$.Link}}"><i class="octicon octicon-person"></i> {{$.i18n.Tr "user.follow"}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="ui divider"></div>
|
||||
@@ -49,24 +49,6 @@
|
||||
{{end}}
|
||||
{{end}}
|
||||
<li><i class="octicon octicon-clock"></i> {{.i18n.Tr "user.join_on"}} {{.Owner.CreatedUnix.FormatShort}}</li>
|
||||
<li>
|
||||
<i class="octicon octicon-person"></i>
|
||||
<a href="{{.Owner.HomeLink}}/followers">
|
||||
{{.Owner.NumFollowers}} {{.i18n.Tr "user.followers"}}
|
||||
</a>
|
||||
-
|
||||
<a href="{{.Owner.HomeLink}}/following">
|
||||
{{.Owner.NumFollowing}} {{.i18n.Tr "user.following"}}
|
||||
</a>
|
||||
</li>
|
||||
{{/*
|
||||
<li>
|
||||
<i class="octicon octicon-star"></i>
|
||||
<a href="{{.Owner.HomeLink}}/stars">
|
||||
{{.Owner.NumStars}} {{.i18n.Tr "user.starred"}}
|
||||
</a>
|
||||
</li>
|
||||
*/}}
|
||||
{{if and .Orgs .HasOrgsVisible}}
|
||||
<li>
|
||||
<ul class="user-orgs">
|
||||
@@ -95,7 +77,7 @@
|
||||
</div>
|
||||
<div class="ui eleven wide column">
|
||||
<div class="ui secondary stackable pointing menu">
|
||||
<a class='{{if and (ne .TabName "activity") (ne .TabName "stars")}}active{{end}} item' href="{{.Owner.HomeLink}}">
|
||||
<a class='{{if and (ne .TabName "activity") (ne .TabName "following") (ne .TabName "followers") (ne .TabName "stars")}}active{{end}} item' href="{{.Owner.HomeLink}}">
|
||||
<i class="octicon octicon-repo"></i> {{.i18n.Tr "user.repositories"}}
|
||||
</a>
|
||||
<a class='{{if eq .TabName "activity"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=activity">
|
||||
@@ -103,6 +85,15 @@
|
||||
</a>
|
||||
<a class='{{if eq .TabName "stars"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=stars">
|
||||
<i class="octicon octicon-star"></i> {{.i18n.Tr "user.starred"}}
|
||||
<div class="ui label">{{.Owner.NumStars}}</div>
|
||||
</a>
|
||||
<a class='{{if eq .TabName "following"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=following">
|
||||
<i class="octicon octicon-person"></i> {{.i18n.Tr "user.following"}}
|
||||
<div class="ui label">{{.Owner.NumFollowing}}</div>
|
||||
</a>
|
||||
<a class='{{if eq .TabName "followers"}}active{{end}} item' href="{{.Owner.HomeLink}}?tab=followers">
|
||||
<i class="octicon octicon-person"></i> {{.i18n.Tr "user.followers"}}
|
||||
<div class="ui label">{{.Owner.NumFollowers}}</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -126,6 +117,10 @@
|
||||
{{template "explore/repo_list" .}}
|
||||
{{template "base/paginate" .}}
|
||||
</div>
|
||||
{{else if eq .TabName "following"}}
|
||||
{{template "repo/user_cards" .}}
|
||||
{{else if eq .TabName "followers"}}
|
||||
{{template "repo/user_cards" .}}
|
||||
{{else}}
|
||||
{{template "explore/repo_search" .}}
|
||||
{{template "explore/repo_list" .}}
|
||||
|
||||
@@ -1362,7 +1362,16 @@ function initWikiForm() {
|
||||
}, '|',
|
||||
'unordered-list', 'ordered-list', '|',
|
||||
'link', 'image', 'table', 'horizontal-rule', '|',
|
||||
'clean-block', 'preview', 'fullscreen', 'side-by-side']
|
||||
'clean-block', 'preview', 'fullscreen', 'side-by-side', '|',
|
||||
{
|
||||
name: 'revert-to-textarea',
|
||||
action(e) {
|
||||
e.toTextArea();
|
||||
},
|
||||
className: 'fa fa-file',
|
||||
title: 'Revert to simple textarea',
|
||||
},
|
||||
]
|
||||
});
|
||||
$(simplemde.codemirror.getInputField()).addClass('js-quick-submit');
|
||||
|
||||
@@ -1466,7 +1475,16 @@ function setSimpleMDE($editArea) {
|
||||
'code', 'quote', '|',
|
||||
'unordered-list', 'ordered-list', '|',
|
||||
'link', 'image', 'table', 'horizontal-rule', '|',
|
||||
'clean-block', 'preview', 'fullscreen', 'side-by-side']
|
||||
'clean-block', 'preview', 'fullscreen', 'side-by-side', '|',
|
||||
{
|
||||
name: 'revert-to-textarea',
|
||||
action(e) {
|
||||
e.toTextArea();
|
||||
},
|
||||
className: 'fa fa-file',
|
||||
title: 'Revert to simple textarea',
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -1488,7 +1506,16 @@ function setCommentSimpleMDE($editArea) {
|
||||
'code', 'quote', '|',
|
||||
'unordered-list', 'ordered-list', '|',
|
||||
'link', 'image', 'table', 'horizontal-rule', '|',
|
||||
'clean-block']
|
||||
'clean-block', '|',
|
||||
{
|
||||
name: 'revert-to-textarea',
|
||||
action(e) {
|
||||
e.toTextArea();
|
||||
},
|
||||
className: 'fa fa-file',
|
||||
title: 'Revert to simple textarea',
|
||||
},
|
||||
]
|
||||
});
|
||||
simplemde.codemirror.setOption('extraKeys', {
|
||||
Enter: () => {
|
||||
|
||||
@@ -1111,6 +1111,9 @@ input {
|
||||
.lines-code .hljs {
|
||||
background-color: #2a2e3a !important;
|
||||
}
|
||||
td.blob-excerpt {
|
||||
background-color: rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.code-view .active {
|
||||
background: #554a00;
|
||||
|
||||
Reference in New Issue
Block a user