return max | return max | ||||
} | } | ||||
// FIXME: do corss-comparison so reduce deletions and additions to the minimum? | |||||
// FIXME: do cross-comparison so reduce deletions and additions to the minimum? | |||||
func (repo *Repository) refreshAccesses(e Engine, accessMap map[int64]AccessMode) (err error) { | func (repo *Repository) refreshAccesses(e Engine, accessMap map[int64]AccessMode) (err error) { | ||||
minMode := AccessModeRead | minMode := AccessModeRead | ||||
if !repo.IsPrivate { | if !repo.IsPrivate { |
} | } | ||||
// ShortRepoPath returns the virtual path to the action repository | // ShortRepoPath returns the virtual path to the action repository | ||||
// trimed to max 20 + 1 + 33 chars. | |||||
// trimmed to max 20 + 1 + 33 chars. | |||||
func (a *Action) ShortRepoPath() string { | func (a *Action) ShortRepoPath() string { | ||||
return path.Join(a.ShortRepoUserName(), a.ShortRepoName()) | return path.Join(a.ShortRepoUserName(), a.ShortRepoName()) | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// It is conflict to have close and reopen at same time, so refsMarkd doesn't need to reinit here. | |||||
// It is conflict to have close and reopen at same time, so refsMarked doesn't need to reinit here. | |||||
for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) { | for _, ref := range issueReopenKeywordsPat.FindAllString(c.Message, -1) { | ||||
ref = ref[strings.IndexByte(ref, byte(' '))+1:] | ref = ref[strings.IndexByte(ref, byte(' '))+1:] | ||||
ref = strings.TrimRightFunc(ref, issueIndexTrimRight) | ref = strings.TrimRightFunc(ref, issueIndexTrimRight) |
IssueID int64 | IssueID int64 | ||||
HeadRepoID int64 | HeadRepoID int64 | ||||
BaseRepoID int64 | BaseRepoID int64 | ||||
HeadBarcnh string | |||||
HeadBranch string | |||||
BaseBranch string | BaseBranch string | ||||
} | } | ||||
func (err ErrPullRequestNotExist) Error() string { | func (err ErrPullRequestNotExist) Error() string { | ||||
return fmt.Sprintf("pull request does not exist [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]", | return fmt.Sprintf("pull request does not exist [id: %d, issue_id: %d, head_repo_id: %d, base_repo_id: %d, head_branch: %s, base_branch: %s]", | ||||
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBarcnh, err.BaseBranch) | |||||
err.ID, err.IssueID, err.HeadRepoID, err.BaseRepoID, err.HeadBranch, err.BaseBranch) | |||||
} | } | ||||
// ErrPullRequestAlreadyExists represents a "PullRequestAlreadyExists"-error | // ErrPullRequestAlreadyExists represents a "PullRequestAlreadyExists"-error |
func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { | func diffToHTML(diffs []diffmatchpatch.Diff, lineType DiffLineType) template.HTML { | ||||
buf := bytes.NewBuffer(nil) | buf := bytes.NewBuffer(nil) | ||||
// Reproduce signs which are cutted for inline diff before. | |||||
// Reproduce signs which are cut for inline diff before. | |||||
switch lineType { | switch lineType { | ||||
case DiffLineAdd: | case DiffLineAdd: | ||||
buf.WriteByte('+') | buf.WriteByte('+') | ||||
// ParsePatch builds a Diff object from a io.Reader and some | // ParsePatch builds a Diff object from a io.Reader and some | ||||
// parameters. | // parameters. | ||||
// TODO: move this function to gogits/git-module | // TODO: move this function to gogits/git-module | ||||
func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) { | |||||
func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*Diff, error) { | |||||
var ( | var ( | ||||
diff = &Diff{Files: make([]*DiffFile, 0)} | diff = &Diff{Files: make([]*DiffFile, 0)} | ||||
curFileLinesCount++ | curFileLinesCount++ | ||||
lineCount++ | lineCount++ | ||||
// Diff data too large, we only show the first about maxlines lines | |||||
if curFileLinesCount >= maxLines || len(line) >= maxLineCharacteres { | |||||
// Diff data too large, we only show the first about maxLines lines | |||||
if curFileLinesCount >= maxLines || len(line) >= maxLineCharacters { | |||||
curFile.IsIncomplete = true | curFile.IsIncomplete = true | ||||
} | } | ||||
// GetDiffRange builds a Diff between two commits of a repository. | // GetDiffRange builds a Diff between two commits of a repository. | ||||
// passing the empty string as beforeCommitID returns a diff from the | // passing the empty string as beforeCommitID returns a diff from the | ||||
// parent commit. | // parent commit. | ||||
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) { | |||||
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int) (*Diff, error) { | |||||
gitRepo, err := git.OpenRepository(repoPath) | gitRepo, err := git.OpenRepository(repoPath) | ||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
pid := process.Add(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath), cmd) | pid := process.Add(fmt.Sprintf("GetDiffRange [repo_path: %s]", repoPath), cmd) | ||||
defer process.Remove(pid) | defer process.Remove(pid) | ||||
diff, err := ParsePatch(maxLines, maxLineCharacteres, maxFiles, stdout) | |||||
diff, err := ParsePatch(maxLines, maxLineCharacters, maxFiles, stdout) | |||||
if err != nil { | if err != nil { | ||||
return nil, fmt.Errorf("ParsePatch: %v", err) | return nil, fmt.Errorf("ParsePatch: %v", err) | ||||
} | } | ||||
} | } | ||||
// GetDiffCommit builds a Diff representing the given commitID. | // GetDiffCommit builds a Diff representing the given commitID. | ||||
func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) { | |||||
return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacteres, maxFiles) | |||||
func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacters, maxFiles int) (*Diff, error) { | |||||
return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacters, maxFiles) | |||||
} | } |
// GetCommitGraph return a list of commit (GraphItems) from all branches | // GetCommitGraph return a list of commit (GraphItems) from all branches | ||||
func GetCommitGraph(r *git.Repository) (GraphItems, error) { | func GetCommitGraph(r *git.Repository) (GraphItems, error) { | ||||
var Commitgraph []GraphItem | |||||
var CommitGraph []GraphItem | |||||
format := "DATA:|%d|%H|%ad|%an|%ae|%h|%s" | format := "DATA:|%d|%H|%ad|%an|%ae|%h|%s" | ||||
) | ) | ||||
graph, err := graphCmd.RunInDir(r.Path) | graph, err := graphCmd.RunInDir(r.Path) | ||||
if err != nil { | if err != nil { | ||||
return Commitgraph, err | |||||
return CommitGraph, err | |||||
} | } | ||||
Commitgraph = make([]GraphItem, 0, 100) | |||||
CommitGraph = make([]GraphItem, 0, 100) | |||||
for _, s := range strings.Split(graph, "\n") { | for _, s := range strings.Split(graph, "\n") { | ||||
GraphItem, err := graphItemFromString(s, r) | GraphItem, err := graphItemFromString(s, r) | ||||
if err != nil { | if err != nil { | ||||
return Commitgraph, err | |||||
return CommitGraph, err | |||||
} | } | ||||
Commitgraph = append(Commitgraph, GraphItem) | |||||
CommitGraph = append(CommitGraph, GraphItem) | |||||
} | } | ||||
return Commitgraph, nil | |||||
return CommitGraph, nil | |||||
} | } | ||||
func graphItemFromString(s string, r *git.Repository) (GraphItem, error) { | func graphItemFromString(s string, r *git.Repository) (GraphItem, error) { | ||||
rows[5], | rows[5], | ||||
rows[6], | rows[6], | ||||
rows[7], | rows[7], | ||||
len(rows[2]) == 0, // no commits refered to, only relation in current line. | |||||
len(rows[2]) == 0, // no commits referred to, only relation in current line. | |||||
} | } | ||||
return gi, nil | return gi, nil | ||||
} | } |
// |___/____ >____ >____/ \___ >_______ (____ /___ /\___ >____/ | // |___/____ >____ >____/ \___ >_______ (____ /___ /\___ >____/ | ||||
// \/ \/ \/ \/ \/ \/ \/ | // \/ \/ \/ \/ \/ \/ \/ | ||||
// IssueLabel represetns an issue-lable relation. | |||||
// IssueLabel represents an issue-label relation. | |||||
type IssueLabel struct { | type IssueLabel struct { | ||||
ID int64 `xorm:"pk autoincr"` | ID int64 `xorm:"pk autoincr"` | ||||
IssueID int64 `xorm:"UNIQUE(s)"` | IssueID int64 `xorm:"UNIQUE(s)"` |
return nil | return nil | ||||
} | } | ||||
// Mail wahtcers. | |||||
// Mail watchers. | |||||
watchers, err := GetWatchers(issue.RepoID) | watchers, err := GetWatchers(issue.RepoID) | ||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("GetWatchers [%d]: %v", issue.RepoID, err) | return fmt.Errorf("GetWatchers [%d]: %v", issue.RepoID, err) |
n.UpdatedUnix = nowUnix | n.UpdatedUnix = nowUnix | ||||
} | } | ||||
// BeforeUpdate runs while updateing a record | |||||
// BeforeUpdate runs while updating a record | |||||
func (n *Notification) BeforeUpdate() { | func (n *Notification) BeforeUpdate() { | ||||
var ( | var ( | ||||
now = time.Now() | now = time.Now() |
// TODO: when squash commits, no need to append merge commit. | // TODO: when squash commits, no need to append merge commit. | ||||
// It is possible that head branch is not fully sync with base branch for merge commits, | // 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 manully | |||||
// so we need to get latest head commit and append merge commit manually | |||||
// to avoid strange diff commits produced. | // to avoid strange diff commits produced. | ||||
mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch) | mergeCommit, err := baseGitRepo.GetBranchCommit(pr.BaseBranch) | ||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("BaseRepo.PatchPath: %v", err) | return fmt.Errorf("BaseRepo.PatchPath: %v", err) | ||||
} | } | ||||
// Fast fail if patch does not exist, this assumes data is cruppted. | |||||
// Fast fail if patch does not exist, this assumes data is corrupted. | |||||
if !com.IsFile(patchPath) { | if !com.IsFile(patchPath) { | ||||
log.Trace("PullRequest[%d].testPatch: ignored cruppted data", pr.ID) | |||||
log.Trace("PullRequest[%d].testPatch: ignored corrupted data", pr.ID) | |||||
return nil | return nil | ||||
} | } | ||||
return prs, maxResults, findSession.Find(&prs) | return prs, maxResults, findSession.Find(&prs) | ||||
} | } | ||||
// GetUnmergedPullRequest returnss a pull request that is open and has not been merged | |||||
// GetUnmergedPullRequest returns a pull request that is open and has not been merged | |||||
// by given head/base and repo/branch. | // by given head/base and repo/branch. | ||||
func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string) (*PullRequest, error) { | func GetUnmergedPullRequest(headRepoID, baseRepoID int64, headBranch, baseBranch string) (*PullRequest, error) { | ||||
pr := new(PullRequest) | pr := new(PullRequest) | ||||
return pr, nil | return pr, nil | ||||
} | } | ||||
// GetUnmergedPullRequestsByHeadInfo returnss all pull requests that are open and has not been merged | |||||
// GetUnmergedPullRequestsByHeadInfo returns all pull requests that are open and has not been merged | |||||
// by given head information (repo and branch). | // by given head information (repo and branch). | ||||
func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) { | func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequest, error) { | ||||
prs := make([]*PullRequest, 0, 2) | prs := make([]*PullRequest, 0, 2) | ||||
Find(&prs) | Find(&prs) | ||||
} | } | ||||
// GetUnmergedPullRequestsByBaseInfo returnss all pull requests that are open and has not been merged | |||||
// GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged | |||||
// by given base information (repo and branch). | // by given base information (repo and branch). | ||||
func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) { | func GetUnmergedPullRequestsByBaseInfo(repoID int64, branch string) ([]*PullRequest, error) { | ||||
prs := make([]*PullRequest, 0, 2) | prs := make([]*PullRequest, 0, 2) | ||||
return err | return err | ||||
} | } | ||||
// checkAndUpdateStatus checks if pull request is possible to levaing checking status, | |||||
// checkAndUpdateStatus checks if pull request is possible to leaving checking status, | |||||
// and set to be either conflict or mergeable. | // and set to be either conflict or mergeable. | ||||
func (pr *PullRequest) checkAndUpdateStatus() { | func (pr *PullRequest) checkAndUpdateStatus() { | ||||
// Status is not changed to conflict means mergeable. | // Status is not changed to conflict means mergeable. | ||||
pr.Status = PullRequestStatusMergeable | pr.Status = PullRequestStatusMergeable | ||||
} | } | ||||
// Make sure there is no waiting test to process before levaing the checking status. | |||||
// Make sure there is no waiting test to process before leaving the checking status. | |||||
if !pullRequestQueue.Exist(pr.ID) { | if !pullRequestQueue.Exist(pr.ID) { | ||||
if err := pr.UpdateCols("status"); err != nil { | if err := pr.UpdateCols("status"); err != nil { | ||||
log.Error(4, "Update[%d]: %v", pr.ID, err) | log.Error(4, "Update[%d]: %v", pr.ID, err) |
// MustOwner always returns a valid *User object to avoid | // MustOwner always returns a valid *User object to avoid | ||||
// conceptually impossible error handling. | // conceptually impossible error handling. | ||||
// It creates a fake object that contains error deftail | |||||
// It creates a fake object that contains error details | |||||
// when error occurs. | // when error occurs. | ||||
func (repo *Repository) MustOwner() *User { | func (repo *Repository) MustOwner() *User { | ||||
return repo.mustOwner(x) | return repo.mustOwner(x) | ||||
} | } | ||||
func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error { | func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRepoOptions) error { | ||||
// Clone to temprory path and do the init commit. | |||||
// Clone to temporary path and do the init commit. | |||||
_, stderr, err := process.Exec( | _, stderr, err := process.Exec( | ||||
fmt.Sprintf("initRepository(git clone): %s", repoPath), "git", "clone", repoPath, tmpDir) | fmt.Sprintf("initRepository(git clone): %s", repoPath), "git", "clone", repoPath, tmpDir) | ||||
if err != nil { | if err != nil { | ||||
return fmt.Errorf("getOwner: %v", err) | return fmt.Errorf("getOwner: %v", err) | ||||
} | } | ||||
if repo.Owner.IsOrganization() { | if repo.Owner.IsOrganization() { | ||||
// Organization repository need to recalculate access table when visivility is changed. | |||||
// Organization repository need to recalculate access table when visibility is changed. | |||||
if err = repo.recalculateTeamAccesses(e, 0); err != nil { | if err = repo.recalculateTeamAccesses(e, 0); err != nil { | ||||
return fmt.Errorf("recalculateTeamAccesses: %v", err) | return fmt.Errorf("recalculateTeamAccesses: %v", err) | ||||
} | } |
} | } | ||||
} | } | ||||
// InitSyncMirrors initializes a go routine to sync the mirros | |||||
// InitSyncMirrors initializes a go routine to sync the mirrors | |||||
func InitSyncMirrors() { | func InitSyncMirrors() { | ||||
go SyncMirrors() | go SyncMirrors() | ||||
} | } |
return nil | return nil | ||||
} | } | ||||
// checkKeyContent onlys checks if key content has been used as public key, | |||||
// checkKeyContent only checks if key content has been used as public key, | |||||
// it is OK to use same key as deploy key for multiple repositories/users. | // it is OK to use same key as deploy key for multiple repositories/users. | ||||
func checkKeyContent(content string) error { | func checkKeyContent(content string) error { | ||||
has, err := x.Get(&PublicKey{ | has, err := x.Get(&PublicKey{ | ||||
// RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again. | // RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again. | ||||
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function | // Note: x.Iterate does not get latest data after insert/delete, so we have to call this function | ||||
// outsite any session scope independently. | |||||
// outside any session scope independently. | |||||
func RewriteAllPublicKeys() error { | func RewriteAllPublicKeys() error { | ||||
sshOpLocker.Lock() | sshOpLocker.Lock() | ||||
defer sshOpLocker.Unlock() | defer sshOpLocker.Unlock() |
Find(&users) | Find(&users) | ||||
} | } | ||||
// get user by erify code | |||||
// get user by verify code | |||||
func getVerifyUser(code string) (user *User) { | func getVerifyUser(code string) (user *User) { | ||||
if len(code) <= base.TimeLimitCodeLength { | if len(code) <= base.TimeLimitCodeLength { | ||||
return nil | return nil | ||||
*git.Commit | *git.Commit | ||||
} | } | ||||
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user. | |||||
// ValidateCommitWithEmail check if author's e-mail of commit is corresponding to a user. | |||||
func ValidateCommitWithEmail(c *git.Commit) *User { | func ValidateCommitWithEmail(c *git.Commit) *User { | ||||
u, err := GetUserByEmail(c.Author.Email) | u, err := GetUserByEmail(c.Author.Email) | ||||
if err != nil { | if err != nil { | ||||
return sess.Commit() | return sess.Commit() | ||||
} | } | ||||
// UnfollowUser unmarks someone be another's follower. | |||||
// UnfollowUser unmarks someone as another's follower. | |||||
func UnfollowUser(userID, followID int64) (err error) { | func UnfollowUser(userID, followID int64) (err error) { | ||||
if userID == followID || !IsFollowing(userID, followID) { | if userID == followID || !IsFollowing(userID, followID) { | ||||
return nil | return nil |
} | } | ||||
} | } | ||||
// We alway want the primary email address displayed, even if it's not in | |||||
// the emailaddress table (yet). | |||||
// We always want the primary email address displayed, even if it's not in | |||||
// the email address table (yet). | |||||
if !isPrimaryFound { | if !isPrimaryFound { | ||||
emails = append(emails, &EmailAddress{ | emails = append(emails, &EmailAddress{ | ||||
Email: u.Email, | Email: u.Email, |
"code.gitea.io/gitea/modules/setting" | "code.gitea.io/gitea/modules/setting" | ||||
) | ) | ||||
// SlackMeta contains the slack metdata | |||||
// SlackMeta contains the slack metadata | |||||
type SlackMeta struct { | type SlackMeta struct { | ||||
Channel string `json:"channel"` | Channel string `json:"channel"` | ||||
Username string `json:"username"` | Username string `json:"username"` | ||||
return s | return s | ||||
} | } | ||||
// SlackLinkFormatter creates a link compatablie with slack | |||||
// SlackLinkFormatter creates a link compatible with slack | |||||
func SlackLinkFormatter(url string, text string) string { | func SlackLinkFormatter(url string, text string) string { | ||||
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text)) | return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text)) | ||||
} | } |