Added basic functionality:

* Add new dependecy
* Show dependencies

Signed-off-by: Konrad <konrad@kola-entertainments.de>
This commit is contained in:
Konrad Langenberg 2017-08-27 20:23:16 +02:00 committed by Konrad
parent 0a4925fb17
commit cf7e99fc4c
9 changed files with 159 additions and 25 deletions

View File

@ -379,7 +379,7 @@ MODE = console
; Buffer length of channel, keep it as it is if you don't know what it is. ; Buffer length of channel, keep it as it is if you don't know what it is.
BUFFER_LEN = 10000 BUFFER_LEN = 10000
; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace" ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
LEVEL = Trace LEVEL = Debug
; For "console" mode only ; For "console" mode only
[log.console] [log.console]

View File

@ -52,6 +52,8 @@ const (
CommentTypeChangeTitle CommentTypeChangeTitle
// Delete Branch // Delete Branch
CommentTypeDeleteBranch CommentTypeDeleteBranch
// Dependency added
CommentTypeAddedDependency
) )
// CommentTag defines comment tag type // CommentTag defines comment tag type

View File

@ -6,7 +6,6 @@ package models
import ( import (
"time" "time"
"fmt"
) )
// IssueDependency is connection request for receiving issue notification. // IssueDependency is connection request for receiving issue notification.
@ -43,18 +42,20 @@ func (iw *IssueDependency) BeforeUpdate() {
iw.UpdatedUnix = u iw.UpdatedUnix = u
} }
// CreateOrUpdateIssueDependency sets or updates a dependency for an issue // CreateOrUpdateIssueDependency creates a new dependency for an issue
func CreateOrUpdateIssueDependency(userID, issueID int64, depID int64) error { func CreateOrUpdateIssueDependency(userID, issueID int64, depID int64) (err error, exists bool) {
err := x.Sync(new(IssueDependency)) err = x.Sync(new(IssueDependency))
if err != nil { if err != nil {
return err return err, exists
} }
exists, err := issueDepExists(x, issueID, depID) // Check if it aleready exists
exists, err = issueDepExists(x, issueID, depID)
if err != nil { if err != nil {
return err return err, exists
} }
// If it not exists, create it, otherwise show an error message
if !exists { if !exists {
newId := new(IssueDependency) newId := new(IssueDependency)
newId.UserID = userID newId.UserID = userID
@ -62,20 +63,36 @@ func CreateOrUpdateIssueDependency(userID, issueID int64, depID int64) error {
newId.DependencyID = depID newId.DependencyID = depID
if _, err := x.Insert(newId); err != nil { if _, err := x.Insert(newId); err != nil {
return err return err, exists
}
// Add comment referencing to the stopwatch
comment := &Comment{
IssueID: issueID,
PosterID: userID,
Type: CommentTypeAddedDependency,
}
if _, err := x.Insert(comment); err != nil {
return err, exists
} }
} else {
fmt.Println("Dependency exists")
// TODO: Should display a message on issue page
} }
return nil return nil, exists
} }
// // Check if the dependency already exists
func issueDepExists(e Engine, issueID int64, depID int64) (exists bool, err error) { func issueDepExists(e Engine, issueID int64, depID int64) (exists bool, err error) {
var Dependencies = IssueDependency{IssueID: issueID, DependencyID: depID} var Dependencies = IssueDependency{IssueID: issueID, DependencyID: depID}
//err = e.Where("issue_id = ?", issueID).Where("dependency_id = ?", depID).Find(&Dependencies)
exists, err = e.Get(&Dependencies) exists, err = e.Get(&Dependencies)
// Check for dependencies the other way around
// Otherwise two issues could block each other which would result in none of them could be closed.
if !exists {
Dependencies.IssueID = depID
Dependencies.DependencyID = issueID
exists, err = e.Get(&Dependencies)
}
return return
} }

View File

@ -666,6 +666,40 @@ func (repo *Repository) CanEnableEditor() bool {
return !repo.IsMirror return !repo.IsMirror
} }
func (repo *Repository) BlockedByDependencies(issueID int64) (_ []*Issue, err error) {
issueDeps, err := repo.getBlockedByDependencies(x, issueID)
var issueDepsFull = make([]*Issue, 0)
for _, issueDep := range issueDeps{
issueDetails, _ := getIssueByID(x, issueDep.DependencyID)
issueDepsFull = append(issueDepsFull, issueDetails)
}
if err != nil {
return
}
return issueDepsFull, nil
}
func (repo *Repository) BlockingDependencies(issueID int64) (_ []*Issue, err error) {
issueDeps, err := repo.getBlockingDependencies(x, issueID)
var issueDepsFull = make([]*Issue, 0)
for _, issueDep := range issueDeps{
issueDetails, _ := getIssueByID(x, issueDep.IssueID)
issueDepsFull = append(issueDepsFull, issueDetails)
}
if err != nil {
return
}
return issueDepsFull, nil
}
// NextIssueIndex returns the next issue index // NextIssueIndex returns the next issue index
// FIXME: should have a mutex to prevent producing same index for two issues that are created // FIXME: should have a mutex to prevent producing same index for two issues that are created
// closely enough. // closely enough.
@ -2367,3 +2401,19 @@ func (repo *Repository) CreateNewBranch(doer *User, oldBranchName, branchName st
return nil return nil
} }
// Get Blocked By Dependencies, aka all issues this issue is blocked by.
func (repo *Repository) getBlockedByDependencies(e Engine, issueID int64) (_ []IssueDependency, err error) {
var dependencies []IssueDependency
err = e.Where("issue_id = ?", issueID).Find(&dependencies) //
return dependencies, err
}
// Get Blocking Dependencies, aka all issues this issue blocks.
func (repo *Repository) getBlockingDependencies(e Engine, issueID int64) (_ []IssueDependency, err error) {
var dependencies []IssueDependency
err = e.Where("dependency_id = ?", issueID).Find(&dependencies)
return dependencies, err
}

View File

@ -693,6 +693,13 @@ issues.attachment.open_tab = `Click to see "%s" in a new tab`
issues.attachment.download = `Click to download "%s"` issues.attachment.download = `Click to download "%s"`
issues.subscribe = Subscribe issues.subscribe = Subscribe
issues.unsubscribe = Unsubscribe issues.unsubscribe = Unsubscribe
issues.dependency.title = Dependencies
issues.dependency.no_dependencies = This issue currently doesn't have any dependencies.
issues.dependency.add = Add
issues.dependency.cancel = Cancel
issues.dependency.add_header = Add New Dependency
issues.dependency.issue_number = Issuenumber
issues.dependency.added_dependency = `<a href="%[1]s">%[2]s</a> added a new dependency %[3]s`
pulls.desc = Pulls management your code review and merge requests pulls.desc = Pulls management your code review and merge requests
pulls.new = New Pull Request pulls.new = New Pull Request

View File

@ -665,6 +665,10 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch) ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch)
} }
// Get Dependencies
ctx.Data["BlockedByDependencies"], err = repo.BlockedByDependencies(issue.ID)
ctx.Data["BlockingDependencies"], err = repo.BlockingDependencies(issue.ID)
ctx.Data["Participants"] = participants ctx.Data["Participants"] = participants
ctx.Data["NumParticipants"] = len(participants) ctx.Data["NumParticipants"] = len(participants)
ctx.Data["Issue"] = issue ctx.Data["Issue"] = issue

View File

@ -28,12 +28,16 @@ func AddDependency(c *context.Context) {
return return
} }
if err := models.CreateOrUpdateIssueDependency(c.User.ID, issue.ID, dep); err != nil { err, exists := models.CreateOrUpdateIssueDependency(c.User.ID, issue.ID, dep);
if err != nil {
c.Handle(http.StatusInternalServerError, "CreateOrUpdateIssueDependency", err) c.Handle(http.StatusInternalServerError, "CreateOrUpdateIssueDependency", err)
fmt.Println("updateerr")
return return
} }
if exists {
c.Flash.Error("Dependency already exists!")
}
url := fmt.Sprintf("%s/issues/%d", c.Repo.RepoLink, issueIndex) url := fmt.Sprintf("%s/issues/%d", c.Repo.RepoLink, issueIndex)
c.Redirect(url, http.StatusSeeOther) c.Redirect(url, http.StatusSeeOther)
} }

View File

@ -140,5 +140,15 @@
<span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a> <span class="text grey"><a href="{{.Poster.HomeLink}}">{{.Poster.Name}}</a>
{{$.i18n.Tr "repo.issues.delete_branch_at" .CommitSHA $createdStr | Safe}} {{$.i18n.Tr "repo.issues.delete_branch_at" .CommitSHA $createdStr | Safe}}
</span> </span>
{{else if eq .Type 12}}
<div class="event">
<span class="octicon octicon-primitive-dot"></span>
</div>
<a class="ui avatar image" href="{{.Poster.HomeLink}}">
<img src="{{.Poster.RelAvatarLink}}">
</a>
<span class="text grey">
{{$.i18n.Tr "repo.issues.dependency.added_dependency" .Poster.HomeLink .Poster.Name $createdStr | Safe}}
</span>
{{end}} {{end}}
{{end}} {{end}}

View File

@ -125,13 +125,53 @@
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="ui depending"> <div class="ui depending">
<span class="text"><strong>Dependencies</strong></span> <span class="text"><strong>{{.i18n.Tr "repo.issues.dependency.title"}}</strong></span>
<div> <br>
This issue currently doesn't have any dependencies. <span class="text">This issue is blocked by:</span>
<div class="ui relaxed divided list">
{{range .BlockedByDependencies}}
<div class="item">
<div class="right floated content">
{{if .IsClosed}}
<div class="ui red mini label">
<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 class="ui relaxed divided list">
<span class="text">This issue blocks the following issues:</span>
{{range .BlockingDependencies}}
<div class="item">
<div class="right floated content">
{{if .IsClosed}}
<div class="ui red mini label">
<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}}
<p>{{.i18n.Tr "repo.issues.dependency.no_dependencies"}}</p>
</div> </div>
<div> <div>
<button class="fluid green ui button" onclick="showAddDependencyModal();"> <button class="fluid green ui button" onclick="showAddDependencyModal();">
Add {{.i18n.Tr "repo.issues.dependency.add"}}
</button> </button>
</div> </div>
</div> </div>
@ -141,22 +181,22 @@
<div class="ui tiny modal"> <div class="ui tiny modal">
<div class="header"> <div class="header">
Add new Dependency {{.i18n.Tr "repo.issues.dependency.add_header"}}
</div> </div>
<div class="content"> <div class="content">
<form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/addDependency" id="addDependencyForm"> <form method="POST" action="{{$.RepoLink}}/issues/{{.Issue.Index}}/addDependency" id="addDependencyForm">
{{$.CsrfTokenHtml}} {{$.CsrfTokenHtml}}
<div class="ui input"> <div class="ui input">
<input type="text" name="newDependency" id="newDependency" placeholder="Issuenumber..."> <input type="text" name="newDependency" id="newDependency" placeholder='{{.i18n.Tr "repo.issues.dependency.issue_number"}}'>
</div> </div>
</form> </form>
</div> </div>
<div class="actions"> <div class="actions">
<div class="ui negative button"> <div class="ui negative button">
Cancel {{.i18n.Tr "repo.issues.dependency.cancel"}}
</div> </div>
<div class="ui positive right labeled icon button"> <div class="ui positive right labeled icon button">
Add {{.i18n.Tr "repo.issues.dependency.add"}}
<i class="add icon"></i> <i class="add icon"></i>
</div> </div>
</div> </div>