Skip to content

Commit

Permalink
Merge branch 'master' into web-sign
Browse files Browse the repository at this point in the history
  • Loading branch information
zeripath authored Oct 14, 2019
2 parents a1f4a0d + f9aba9b commit e1979a7
Show file tree
Hide file tree
Showing 48 changed files with 1,907 additions and 635 deletions.
5 changes: 5 additions & 0 deletions custom/conf/app.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,11 @@ SCHEDULE = @every 24h
; or only create new users if UPDATE_EXISTING is set to false
UPDATE_EXISTING = true

; Update migrated repositories' issues and comments' posterid, it will always attempt synchronization when the instance starts.
[cron.update_migration_post_id]
; Interval as a duration between each synchronization. (default every 24h)
SCHEDULE = @every 24h

[git]
; The path of git executable. If empty, Gitea searches through the PATH environment.
PATH =
Expand Down
4 changes: 4 additions & 0 deletions docs/content/doc/advanced/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,10 @@ NB: You must `REDIRECT_MACARON_LOG` and have `DISABLE_ROUTER_LOG` set to `false`
- `RUN_AT_START`: **true**: Run repository statistics check at start time.
- `SCHEDULE`: **@every 24h**: Cron syntax for scheduling repository statistics check.

### Cron - Update Migration Poster ID (`cron.update_migration_post_id`)

- `SCHEDULE`: **@every 24h** : Interval as a duration between each synchronization, it will always attempt synchronization when the instance starts.

## Git (`git`)

- `PATH`: **""**: The path of git executable. If empty, Gitea searches through the PATH environment.
Expand Down
6 changes: 5 additions & 1 deletion docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ menu:
### Cron - Repository Statistics Check (`cron.check_repo_stats`)

- `RUN_AT_START`: 是否启动时自动运行仓库统计。
- `SCHEDULE`: 藏亏统计时的Cron 语法,比如:`@every 24h`.
- `SCHEDULE`: 仓库统计时的Cron 语法,比如:`@every 24h`.

### Cron - Update Migration Poster ID (`cron.update_migration_post_id`)

- `SCHEDULE`: **@every 24h** : 每次同步的间隔时间。此任务总是在启动时自动进行。

## Git (`git`)

Expand Down
2 changes: 1 addition & 1 deletion docs/content/doc/help/seek-help.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ If you found a bug, please create an [issue on GitHub](https://github.com/go-git

## Chinese Support

Support for the Chinese language is provided at [gocn.io](https://gocn.io/topic/Gitea).
Support for the Chinese language is provided at [gocn.vip](https://gocn.vip/topic/gitea).
2 changes: 1 addition & 1 deletion docs/content/doc/help/seek-help.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ menu:
如果您在使用或者开发过程中遇到问题,请到以下渠道咨询:

-[Github issue](https://github.com/go-gitea/gitea/issues)提问(因为项目维护人员来自世界各地,为保证沟通顺畅,请使用英文提问)
- 中文问题到[gocn.io](https://gocn.io/topic/Gitea)提问
- 中文问题到[gocn.vip](https://gocn.vip/topic/gitea)提问
- 访问 [Discord server - 英文](https://discord.gg/NsatcWJ)
- 加入 QQ群 328432459 获得进一步的支持
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ require (
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/stretchr/testify.v1 v1.2.2 // indirect
gopkg.in/testfixtures.v2 v2.5.0
mvdan.cc/xurls/v2 v2.0.0
mvdan.cc/xurls/v2 v2.1.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.6
xorm.io/core v0.7.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -812,8 +812,8 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
mvdan.cc/xurls/v2 v2.0.0 h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc=
mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU=
mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA=
mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=
Expand Down
13 changes: 7 additions & 6 deletions integrations/issue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"testing"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/references"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"

Expand Down Expand Up @@ -207,7 +208,7 @@ func TestIssueCrossReference(t *testing.T) {
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNone})
RefAction: references.XRefActionNone})

// Edit title, neuter ref
testIssueChangeInfo(t, "user2", issueRefURL, "title", "Title no ref")
Expand All @@ -217,7 +218,7 @@ func TestIssueCrossReference(t *testing.T) {
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNeutered})
RefAction: references.XRefActionNeutered})

// Ref from issue content
issueRefURL, issueRef = testIssueWithBean(t, "user2", 1, "TitleXRef", fmt.Sprintf("Description ref #%d", issueBase.Index))
Expand All @@ -227,7 +228,7 @@ func TestIssueCrossReference(t *testing.T) {
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNone})
RefAction: references.XRefActionNone})

// Edit content, neuter ref
testIssueChangeInfo(t, "user2", issueRefURL, "content", "Description no ref")
Expand All @@ -237,7 +238,7 @@ func TestIssueCrossReference(t *testing.T) {
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNeutered})
RefAction: references.XRefActionNeutered})

// Ref from a comment
session := loginUser(t, "user2")
Expand All @@ -248,7 +249,7 @@ func TestIssueCrossReference(t *testing.T) {
RefIssueID: issueRef.ID,
RefCommentID: commentID,
RefIsPull: false,
RefAction: models.XRefActionNone}
RefAction: references.XRefActionNone}
models.AssertExistsAndLoadBean(t, comment)

// Ref from a different repository
Expand All @@ -259,7 +260,7 @@ func TestIssueCrossReference(t *testing.T) {
RefIssueID: issueRef.ID,
RefCommentID: 0,
RefIsPull: false,
RefAction: models.XRefActionNone})
RefAction: references.XRefActionNone})
}

func testIssueWithBean(t *testing.T, user string, repoID int64, title, content string) (string, *models.Issue) {
Expand Down
177 changes: 37 additions & 140 deletions models/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@ import (
"fmt"
"html"
"path"
"regexp"
"strconv"
"strings"
"time"
"unicode"

"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/references"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
Expand Down Expand Up @@ -54,29 +53,6 @@ const (
ActionMirrorSyncDelete // 20
)

var (
// Same as GitHub. See
// https://help.github.com/articles/closing-issues-via-commit-messages
issueCloseKeywords = []string{"close", "closes", "closed", "fix", "fixes", "fixed", "resolve", "resolves", "resolved"}
issueReopenKeywords = []string{"reopen", "reopens", "reopened"}

issueCloseKeywordsPat, issueReopenKeywordsPat *regexp.Regexp
issueReferenceKeywordsPat *regexp.Regexp
)

const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+`
const issueRefRegexpStrNoKeyword = `(?:\s|^|\(|\[)(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))`

func assembleKeywordsPattern(words []string) string {
return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
}

func init() {
issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword)
}

// Action represents user operation type and other information to
// repository. It implemented interface base.Actioner so that can be
// used in template render.
Expand Down Expand Up @@ -351,10 +327,6 @@ func RenameRepoAction(actUser *User, oldRepoName string, repo *Repository) error
return renameRepoAction(x, actUser, oldRepoName, repo)
}

func issueIndexTrimRight(c rune) bool {
return !unicode.IsDigit(c)
}

// PushCommit represents a commit in a push operation.
type PushCommit struct {
Sha1 string
Expand Down Expand Up @@ -480,39 +452,9 @@ func (pc *PushCommits) AvatarLink(email string) string {
}

// getIssueFromRef returns the issue referenced by a ref. Returns a nil *Issue
// if the provided ref is misformatted or references a non-existent issue.
func getIssueFromRef(repo *Repository, ref string) (*Issue, error) {
ref = ref[strings.IndexByte(ref, ' ')+1:]
ref = strings.TrimRightFunc(ref, issueIndexTrimRight)

var refRepo *Repository
poundIndex := strings.IndexByte(ref, '#')
if poundIndex < 0 {
return nil, nil
} else if poundIndex == 0 {
refRepo = repo
} else {
slashIndex := strings.IndexByte(ref, '/')
if slashIndex < 0 || slashIndex >= poundIndex {
return nil, nil
}
ownerName := ref[:slashIndex]
repoName := ref[slashIndex+1 : poundIndex]
var err error
refRepo, err = GetRepositoryByOwnerAndName(ownerName, repoName)
if err != nil {
if IsErrRepoNotExist(err) {
return nil, nil
}
return nil, err
}
}
issueIndex, err := strconv.ParseInt(ref[poundIndex+1:], 10, 64)
if err != nil {
return nil, nil
}

issue, err := GetIssueByIndex(refRepo.ID, issueIndex)
// if the provided ref references a non-existent issue.
func getIssueFromRef(repo *Repository, index int64) (*Issue, error) {
issue, err := GetIssueByIndex(repo.ID, index)
if err != nil {
if IsErrIssueNotExist(err) {
return nil, nil
Expand All @@ -522,20 +464,7 @@ func getIssueFromRef(repo *Repository, ref string) (*Issue, error) {
return issue, nil
}

func changeIssueStatus(repo *Repository, doer *User, ref string, refMarked map[int64]bool, status bool) error {
issue, err := getIssueFromRef(repo, ref)
if err != nil {
return err
}

if issue == nil || refMarked[issue.ID] {
return nil
}
refMarked[issue.ID] = true

if issue.RepoID != repo.ID || issue.IsClosed == status {
return nil
}
func changeIssueStatus(repo *Repository, issue *Issue, doer *User, status bool) error {

stopTimerIfAvailable := func(doer *User, issue *Issue) error {

Expand All @@ -549,7 +478,7 @@ func changeIssueStatus(repo *Repository, doer *User, ref string, refMarked map[i
}

issue.Repo = repo
if err = issue.ChangeStatus(doer, status); err != nil {
if err := issue.ChangeStatus(doer, status); err != nil {
// Don't return an error when dependencies are open as this would let the push fail
if IsErrDependenciesLeft(err) {
return stopTimerIfAvailable(doer, issue)
Expand All @@ -566,99 +495,67 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit, bra
for i := len(commits) - 1; i >= 0; i-- {
c := commits[i]

refMarked := make(map[int64]bool)
type markKey struct {
ID int64
Action references.XRefAction
}

refMarked := make(map[markKey]bool)
var refRepo *Repository
var refIssue *Issue
var err error
for _, m := range issueReferenceKeywordsPat.FindAllStringSubmatch(c.Message, -1) {
if len(m[3]) == 0 {
continue
}
ref := m[3]
for _, ref := range references.FindAllIssueReferences(c.Message) {

// issue is from another repo
if len(m[1]) > 0 && len(m[2]) > 0 {
refRepo, err = GetRepositoryFromMatch(m[1], m[2])
if len(ref.Owner) > 0 && len(ref.Name) > 0 {
refRepo, err = GetRepositoryFromMatch(ref.Owner, ref.Name)
if err != nil {
continue
}
} else {
refRepo = repo
}
issue, err := getIssueFromRef(refRepo, ref)
if err != nil {
if refIssue, err = getIssueFromRef(refRepo, ref.Index); err != nil {
return err
}

if issue == nil || refMarked[issue.ID] {
if refIssue == nil {
continue
}
refMarked[issue.ID] = true

message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, html.EscapeString(c.Message))
if err = CreateRefComment(doer, refRepo, issue, message, c.Sha1); err != nil {
perm, err := GetUserRepoPermission(refRepo, doer)
if err != nil {
return err
}
}

// Change issue status only if the commit has been pushed to the default branch.
// and if the repo is configured to allow only that
if repo.DefaultBranch != branchName && !repo.CloseIssuesViaCommitInAnyBranch {
continue
}
refMarked = make(map[int64]bool)
for _, m := range issueCloseKeywordsPat.FindAllStringSubmatch(c.Message, -1) {
if len(m[3]) == 0 {
key := markKey{ID: refIssue.ID, Action: ref.Action}
if refMarked[key] {
continue
}
ref := m[3]
refMarked[key] = true

// issue is from another repo
if len(m[1]) > 0 && len(m[2]) > 0 {
refRepo, err = GetRepositoryFromMatch(m[1], m[2])
if err != nil {
continue
}
} else {
refRepo = repo
}

perm, err := GetUserRepoPermission(refRepo, doer)
if err != nil {
return err
}
// only close issues in another repo if user has push access
if perm.CanWrite(UnitTypeCode) {
if err := changeIssueStatus(refRepo, doer, ref, refMarked, true); err != nil {
// only create comments for issues if user has permission for it
if perm.IsAdmin() || perm.IsOwner() || perm.CanWrite(UnitTypeIssues) {
message := fmt.Sprintf(`<a href="%s/commit/%s">%s</a>`, repo.Link(), c.Sha1, html.EscapeString(c.Message))
if err = CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil {
return err
}
}
}

// It is conflict to have close and reopen at same time, so refsMarked doesn't need to reinit here.
for _, m := range issueReopenKeywordsPat.FindAllStringSubmatch(c.Message, -1) {
if len(m[3]) == 0 {
// Process closing/reopening keywords
if ref.Action != references.XRefActionCloses && ref.Action != references.XRefActionReopens {
continue
}
ref := m[3]

// issue is from another repo
if len(m[1]) > 0 && len(m[2]) > 0 {
refRepo, err = GetRepositoryFromMatch(m[1], m[2])
if err != nil {
continue
}
} else {
refRepo = repo
}

perm, err := GetUserRepoPermission(refRepo, doer)
if err != nil {
return err
// Change issue status only if the commit has been pushed to the default branch.
// and if the repo is configured to allow only that
// FIXME: we should be using Issue.ref if set instead of repo.DefaultBranch
if repo.DefaultBranch != branchName && !repo.CloseIssuesViaCommitInAnyBranch {
continue
}

// only reopen issues in another repo if user has push access
if perm.CanWrite(UnitTypeCode) {
if err := changeIssueStatus(refRepo, doer, ref, refMarked, false); err != nil {
// only close issues in another repo if user has push access
if perm.IsAdmin() || perm.IsOwner() || perm.CanWrite(UnitTypeCode) {
if err := changeIssueStatus(refRepo, refIssue, doer, ref.Action == references.XRefActionCloses); err != nil {
return err
}
}
Expand Down
Loading

0 comments on commit e1979a7

Please sign in to comment.