Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
80437f8ce7
|
|
@ -470,7 +470,12 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for dependencies, if there aren't any, close it
|
// Check for dependencies, if there aren't any, close it
|
||||||
if IssueNoDependenciesLeft(issue) {
|
noDeps, err := IssueNoDependenciesLeft(issue)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if noDeps {
|
||||||
if err = issue.ChangeStatus(doer, repo, true); err != nil {
|
if err = issue.ChangeStatus(doer, repo, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,16 +52,12 @@ func CreateIssueDependency(user *User, issue, dep *Issue) (exists bool, err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add comment referencing the new dependency
|
// Add comment referencing the new dependency
|
||||||
_, err = createIssueDependencyComment(sess, user, issue, dep, true)
|
if _, err = createIssueDependencyComment(sess, user, issue, dep, true); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return exists, err
|
return exists, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new comment for the dependent issue
|
// Create a new comment for the dependent issue
|
||||||
_, err = createIssueDependencyComment(sess, user, dep, issue, true)
|
if _, err = createIssueDependencyComment(sess, user, dep, issue, true); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return exists, err
|
return exists, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,8 +69,8 @@ func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType Depende
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
|
|
||||||
// Check if it exists
|
// Check if it exists
|
||||||
exists, err := issueDepExists(x, issue.ID, dep.ID)
|
var exists bool
|
||||||
if err != nil {
|
if exists, err = issueDepExists(x, issue.ID, dep.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,22 +88,17 @@ func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType Depende
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := x.Delete(&issueDepToDelete)
|
if _, err := x.Delete(&issueDepToDelete); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add comment referencing the removed dependency
|
// Add comment referencing the removed dependency
|
||||||
_, err = createIssueDependencyComment(sess, user, issue, dep, false)
|
if _, err = createIssueDependencyComment(sess, user, issue, dep, false); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new comment for the dependent issue
|
// Create a new comment for the dependent issue
|
||||||
_, err = createIssueDependencyComment(sess, user, dep, issue, false)
|
if _, err = createIssueDependencyComment(sess, user, dep, issue, false); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,11 +110,7 @@ func issueDepExists(e Engine, issueID int64, depID int64) (exists bool, err erro
|
||||||
|
|
||||||
exists, err = e.Where("(issue_id = ? AND dependency_id = ?) OR (issue_id = ? AND dependency_id = ?)", issueID, depID, depID, issueID).Exist(&IssueDependency{})
|
exists, err = e.Where("(issue_id = ? AND dependency_id = ?) OR (issue_id = ? AND dependency_id = ?)", issueID, depID, depID, issueID).Exist(&IssueDependency{})
|
||||||
|
|
||||||
if err != nil {
|
return
|
||||||
return exists, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return exists, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueDependencyIssue custom type for mysql join
|
// IssueDependencyIssue custom type for mysql join
|
||||||
|
|
@ -138,7 +125,7 @@ func (IssueDependencyIssue) TableName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueNoDependenciesLeft checks if issue can be closed
|
// IssueNoDependenciesLeft checks if issue can be closed
|
||||||
func IssueNoDependenciesLeft(issue *Issue) bool {
|
func IssueNoDependenciesLeft(issue *Issue) (bool, error) {
|
||||||
|
|
||||||
exists, err := x.
|
exists, err := x.
|
||||||
Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").
|
Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").
|
||||||
|
|
@ -146,9 +133,5 @@ func IssueNoDependenciesLeft(issue *Issue) bool {
|
||||||
And("issue.is_closed = ?", "0").
|
And("issue.is_closed = ?", "0").
|
||||||
Exist(&IssueDependencyIssue{})
|
Exist(&IssueDependencyIssue{})
|
||||||
|
|
||||||
if err != nil {
|
return !exists, err
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return !exists
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,7 @@ func addIssueDependencyTables(x *xorm.Engine) (err error) {
|
||||||
UpdatedUnix int64 `xorm:"updated"`
|
UpdatedUnix int64 `xorm:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
err = x.Sync(new(IssueDependency))
|
if err = x.Sync(new(IssueDependency)); err != nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error creating issue_dependency_table column definition: %v", err)
|
return fmt.Errorf("Error creating issue_dependency_table column definition: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ func init() {
|
||||||
new(TrackedTime),
|
new(TrackedTime),
|
||||||
new(DeletedBranch),
|
new(DeletedBranch),
|
||||||
new(RepoIndexerStatus),
|
new(RepoIndexerStatus),
|
||||||
|
new(IssueDependency),
|
||||||
)
|
)
|
||||||
|
|
||||||
gonicNames := []string{"SSL", "UID"}
|
gonicNames := []string{"SSL", "UID"}
|
||||||
|
|
|
||||||
|
|
@ -2457,8 +2457,7 @@ func (repo *Repository) GetUserFork(userID int64) (*Repository, error) {
|
||||||
func (repo *Repository) getBlockedByDependencies(e Engine, issueID int64) (_ []*IssueDependencyIssue, err error) {
|
func (repo *Repository) getBlockedByDependencies(e Engine, issueID int64) (_ []*IssueDependencyIssue, err error) {
|
||||||
var issueDeps []*IssueDependencyIssue
|
var issueDeps []*IssueDependencyIssue
|
||||||
|
|
||||||
err = x.Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").Where("issue_id = ?", issueID).Find(&issueDeps)
|
if err = x.Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").Where("issue_id = ?", issueID).Find(&issueDeps); err != nil {
|
||||||
if err != nil {
|
|
||||||
return issueDeps, err
|
return issueDeps, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2466,11 +2465,10 @@ func (repo *Repository) getBlockedByDependencies(e Engine, issueID int64) (_ []*
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Blocking Dependencies, aka all issues this issue blocks.
|
// Get Blocking Dependencies, aka all issues this issue blocks.
|
||||||
func (repo *Repository) getBlockingDependencies(e Engine, issueID int64) (_ []*IssueDependencyIssue, err error) {
|
func (repo *Repository) getBlockingDependencies(e Engine, issueID int64) ([]*IssueDependencyIssue, error) {
|
||||||
var issueDeps []*IssueDependencyIssue
|
var issueDeps []*IssueDependencyIssue
|
||||||
|
|
||||||
err = x.Join("INNER", "issue", "issue.id = issue_dependency.issue_id").Where("dependency_id = ?", issueID).Find(&issueDeps)
|
if err := x.Join("INNER", "issue", "issue.id = issue_dependency.issue_id").Where("dependency_id = ?", issueID).Find(&issueDeps); err != nil {
|
||||||
if err != nil {
|
|
||||||
return issueDeps, err
|
return issueDeps, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -937,7 +937,12 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||||
!(issue.IsPull && issue.PullRequest.HasMerged) {
|
!(issue.IsPull && issue.PullRequest.HasMerged) {
|
||||||
|
|
||||||
// Check for open dependencies
|
// Check for open dependencies
|
||||||
if form.Status == "close" && !models.IssueNoDependenciesLeft(issue) {
|
noDeps, err := models.IssueNoDependenciesLeft(issue)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.Status == "close" && !noDeps {
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
ctx.Flash.Error("You need to close all issues blocking this pull request before you can merge it!")
|
ctx.Flash.Error("You need to close all issues blocking this pull request before you can merge it!")
|
||||||
ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index))
|
ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index))
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,6 @@ import (
|
||||||
// AddDependency adds new dependencies
|
// AddDependency adds new dependencies
|
||||||
func AddDependency(c *context.Context) {
|
func AddDependency(c *context.Context) {
|
||||||
|
|
||||||
// TODO: should should an issue only have dependencies in it's own repo?
|
|
||||||
|
|
||||||
depID, err := strconv.ParseInt(c.Req.PostForm.Get("newDependency"), 10, 64)
|
depID, err := strconv.ParseInt(c.Req.PostForm.Get("newDependency"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Handle(http.StatusBadRequest, "issue ID is not int", err)
|
c.Handle(http.StatusBadRequest, "issue ID is not int", err)
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,7 @@ func RemoveDependency(c *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = models.RemoveIssueDependency(c.User, issue, dep, depType)
|
if err = models.RemoveIssueDependency(c.User, issue, dep, depType); err != nil {
|
||||||
if err != nil {
|
|
||||||
c.Handle(http.StatusInternalServerError, "CreateOrUpdateIssueDependency", err)
|
c.Handle(http.StatusInternalServerError, "CreateOrUpdateIssueDependency", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -495,7 +495,12 @@ func MergePullRequest(ctx *context.Context) {
|
||||||
pr.Issue = issue
|
pr.Issue = issue
|
||||||
pr.Issue.Repo = ctx.Repo.Repository
|
pr.Issue.Repo = ctx.Repo.Repository
|
||||||
|
|
||||||
if !models.IssueNoDependenciesLeft(issue) {
|
noDeps, err := models.IssueNoDependenciesLeft(issue)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !noDeps {
|
||||||
ctx.Flash.Error("You need to close all issues blocking this pull request before you can merge it!")
|
ctx.Flash.Error("You need to close all issues blocking this pull request before you can merge it!")
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -193,97 +193,97 @@
|
||||||
|
|
||||||
{{if .IsSigned}}
|
{{if .IsSigned}}
|
||||||
{{if .IssueDependenciesEnabled}}
|
{{if .IssueDependenciesEnabled}}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
<div class="ui depending">
|
<div class="ui depending">
|
||||||
<span class="text"><strong>{{.i18n.Tr "repo.issues.dependency.title"}}</strong></span>
|
<span class="text"><strong>{{.i18n.Tr "repo.issues.dependency.title"}}</strong></span>
|
||||||
<br>
|
<br>
|
||||||
{{if .BlockedByDependencies}}
|
{{if .BlockedByDependencies}}
|
||||||
<span class="text" data-tooltip="{{if .Issue.IsPull}}
|
<span class="text" data-tooltip="{{if .Issue.IsPull}}
|
||||||
{{.i18n.Tr "repo.issues.dependency.issue_closing_blockedby"}}
|
{{.i18n.Tr "repo.issues.dependency.issue_closing_blockedby"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.i18n.Tr "repo.issues.dependency.pr_closing_blockedby"}}
|
{{.i18n.Tr "repo.issues.dependency.pr_closing_blockedby"}}
|
||||||
{{end}}" data-inverted="">
|
{{end}}" data-inverted="">
|
||||||
{{.i18n.Tr "repo.issues.dependency.blocked_by_short"}}:
|
{{.i18n.Tr "repo.issues.dependency.blocked_by_short"}}:
|
||||||
</span>
|
</span>
|
||||||
<div class="ui relaxed divided list">
|
<div class="ui relaxed divided list">
|
||||||
{{range .BlockedByDependencies}}
|
{{range .BlockedByDependencies}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="right floated content">
|
<div class="right floated content">
|
||||||
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.Issue.ID}}, 'blockedBy');">
|
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.Issue.ID}}, 'blockedBy');">
|
||||||
<i class="delete icon text red"></i>
|
<i class="delete icon text red"></i>
|
||||||
</a>
|
</a>
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
<div class="ui red mini label">
|
<div class="ui red mini label">
|
||||||
<i class="octicon octicon-issue-closed"></i>
|
<i class="octicon octicon-issue-closed"></i>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="ui green mini label">
|
||||||
|
<i class="octicon octicon-issue-opened"></i>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="ui black label">#{{.Index}}</div>
|
||||||
|
<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{end}}
|
||||||
<div class="ui green mini label">
|
|
||||||
<i class="octicon octicon-issue-opened"></i>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div class="ui black label">#{{.Index}}</div>
|
|
||||||
<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if .BlockingDependencies}}
|
{{if .BlockingDependencies}}
|
||||||
<span class="text" data-tooltip="{{if .Issue.IsPull}}
|
<span class="text" data-tooltip="{{if .Issue.IsPull}}
|
||||||
{{.i18n.Tr "repo.issues.dependency.pr_close_blocks"}}
|
{{.i18n.Tr "repo.issues.dependency.pr_close_blocks"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{.i18n.Tr "repo.issues.dependency.issue_close_blocks"}}
|
{{.i18n.Tr "repo.issues.dependency.issue_close_blocks"}}
|
||||||
{{end}}" data-inverted="">
|
{{end}}" data-inverted="">
|
||||||
{{.i18n.Tr "repo.issues.dependency.blocks_short"}}:
|
{{.i18n.Tr "repo.issues.dependency.blocks_short"}}:
|
||||||
</span>
|
</span>
|
||||||
<div class="ui relaxed divided list">
|
<div class="ui relaxed divided list">
|
||||||
{{range .BlockingDependencies}}
|
{{range .BlockingDependencies}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="right floated content">
|
<div class="right floated content">
|
||||||
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.Issue.ID}}, 'blocking');">
|
<a class="delete-dependency-button" onclick="deleteDependencyModal({{.Issue.ID}}, 'blocking');">
|
||||||
<i class="delete icon text red"></i>
|
<i class="delete icon text red"></i>
|
||||||
</a>
|
</a>
|
||||||
{{if .IsClosed}}
|
{{if .IsClosed}}
|
||||||
<div class="ui red tiny label">
|
<div class="ui red tiny label">
|
||||||
<i class="octicon octicon-issue-closed"></i>
|
<i class="octicon octicon-issue-closed"></i>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="ui green mini label">
|
||||||
|
<i class="octicon octicon-issue-opened"></i>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="ui black label">#{{.Index}}</div>
|
||||||
|
<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{end}}
|
||||||
<div class="ui green mini label">
|
|
||||||
<i class="octicon octicon-issue-opened"></i>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
<div class="ui black label">#{{.Index}}</div>
|
|
||||||
<a class="title has-emoji" href="{{$.RepoLink}}/issues/{{.Index}}">{{.Title}}</a>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{if (and (not .BlockedByDependencies) (not .BlockingDependencies))}}
|
{{if (and (not .BlockedByDependencies) (not .BlockingDependencies))}}
|
||||||
<p>{{.i18n.Tr "repo.issues.dependency.no_dependencies"}}</p>
|
<p>{{.i18n.Tr "repo.issues.dependency.no_dependencies"}}</p>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div>
|
<div>
|
||||||
<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/dependency/add" id="addDependencyForm">
|
<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/dependency/add" id="addDependencyForm">
|
||||||
{{$.CsrfTokenHtml}}
|
{{$.CsrfTokenHtml}}
|
||||||
<div class="ui fluid action input">
|
<div class="ui fluid action input">
|
||||||
<div class="ui search selection dropdown new-dependency-drop-list" style="min-width: 13.9rem;border-radius: 4px 0 0 4px;border-right: 0;white-space: nowrap;">
|
<div class="ui search selection dropdown new-dependency-drop-list" style="min-width: 13.9rem;border-radius: 4px 0 0 4px;border-right: 0;white-space: nowrap;">
|
||||||
<input name="newDependency" type="hidden">
|
<input name="newDependency" type="hidden">
|
||||||
<i class="dropdown icon"></i>
|
<i class="dropdown icon"></i>
|
||||||
<div class="default text">{{.i18n.Tr "repo.issues.dependency.add"}}</div>
|
<div class="default text">{{.i18n.Tr "repo.issues.dependency.add"}}</div>
|
||||||
<div class="menu new-dependency-dropdown">
|
<div class="menu new-dependency-dropdown">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="ui green icon button">
|
||||||
|
<i class="plus icon"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
<button class="ui green icon button">
|
|
||||||
<i class="plus icon"></i>
|
|
||||||
</button><!-- {{.i18n.Tr "repo.issues.dependency.add"}} -->
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user