You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

issue_dependency.go 4.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // Copyright 2018 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "code.gitea.io/gitea/models/db"
  7. "code.gitea.io/gitea/modules/log"
  8. "code.gitea.io/gitea/modules/setting"
  9. "code.gitea.io/gitea/modules/timeutil"
  10. )
  11. // IssueDependency represents an issue dependency
  12. type IssueDependency struct {
  13. ID int64 `xorm:"pk autoincr"`
  14. UserID int64 `xorm:"NOT NULL"`
  15. IssueID int64 `xorm:"UNIQUE(issue_dependency) NOT NULL"`
  16. DependencyID int64 `xorm:"UNIQUE(issue_dependency) NOT NULL"`
  17. CreatedUnix timeutil.TimeStamp `xorm:"created"`
  18. UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
  19. }
  20. func init() {
  21. db.RegisterModel(new(IssueDependency))
  22. }
  23. // DependencyType Defines Dependency Type Constants
  24. type DependencyType int
  25. // Define Dependency Types
  26. const (
  27. DependencyTypeBlockedBy DependencyType = iota
  28. DependencyTypeBlocking
  29. )
  30. // CreateIssueDependency creates a new dependency for an issue
  31. func CreateIssueDependency(user *User, issue, dep *Issue) error {
  32. sess := db.NewSession(db.DefaultContext)
  33. defer sess.Close()
  34. if err := sess.Begin(); err != nil {
  35. return err
  36. }
  37. // Check if it aleready exists
  38. exists, err := issueDepExists(sess, issue.ID, dep.ID)
  39. if err != nil {
  40. return err
  41. }
  42. if exists {
  43. return ErrDependencyExists{issue.ID, dep.ID}
  44. }
  45. // And if it would be circular
  46. circular, err := issueDepExists(sess, dep.ID, issue.ID)
  47. if err != nil {
  48. return err
  49. }
  50. if circular {
  51. return ErrCircularDependency{issue.ID, dep.ID}
  52. }
  53. if _, err := sess.Insert(&IssueDependency{
  54. UserID: user.ID,
  55. IssueID: issue.ID,
  56. DependencyID: dep.ID,
  57. }); err != nil {
  58. return err
  59. }
  60. // Add comment referencing the new dependency
  61. if err = createIssueDependencyComment(sess, user, issue, dep, true); err != nil {
  62. return err
  63. }
  64. return sess.Commit()
  65. }
  66. // RemoveIssueDependency removes a dependency from an issue
  67. func RemoveIssueDependency(user *User, issue, dep *Issue, depType DependencyType) (err error) {
  68. sess := db.NewSession(db.DefaultContext)
  69. defer sess.Close()
  70. if err = sess.Begin(); err != nil {
  71. return err
  72. }
  73. var issueDepToDelete IssueDependency
  74. switch depType {
  75. case DependencyTypeBlockedBy:
  76. issueDepToDelete = IssueDependency{IssueID: issue.ID, DependencyID: dep.ID}
  77. case DependencyTypeBlocking:
  78. issueDepToDelete = IssueDependency{IssueID: dep.ID, DependencyID: issue.ID}
  79. default:
  80. return ErrUnknownDependencyType{depType}
  81. }
  82. affected, err := sess.Delete(&issueDepToDelete)
  83. if err != nil {
  84. return err
  85. }
  86. // If we deleted nothing, the dependency did not exist
  87. if affected <= 0 {
  88. return ErrDependencyNotExists{issue.ID, dep.ID}
  89. }
  90. // Add comment referencing the removed dependency
  91. if err = createIssueDependencyComment(sess, user, issue, dep, false); err != nil {
  92. return err
  93. }
  94. return sess.Commit()
  95. }
  96. // Check if the dependency already exists
  97. func issueDepExists(e db.Engine, issueID, depID int64) (bool, error) {
  98. return e.Where("(issue_id = ? AND dependency_id = ?)", issueID, depID).Exist(&IssueDependency{})
  99. }
  100. // IssueNoDependenciesLeft checks if issue can be closed
  101. func IssueNoDependenciesLeft(issue *Issue) (bool, error) {
  102. return issueNoDependenciesLeft(db.GetEngine(db.DefaultContext), issue)
  103. }
  104. func issueNoDependenciesLeft(e db.Engine, issue *Issue) (bool, error) {
  105. exists, err := e.
  106. Table("issue_dependency").
  107. Select("issue.*").
  108. Join("INNER", "issue", "issue.id = issue_dependency.dependency_id").
  109. Where("issue_dependency.issue_id = ?", issue.ID).
  110. And("issue.is_closed = ?", "0").
  111. Exist(&Issue{})
  112. return !exists, err
  113. }
  114. // IsDependenciesEnabled returns if dependencies are enabled and returns the default setting if not set.
  115. func (repo *Repository) IsDependenciesEnabled() bool {
  116. return repo.isDependenciesEnabled(db.GetEngine(db.DefaultContext))
  117. }
  118. func (repo *Repository) isDependenciesEnabled(e db.Engine) bool {
  119. var u *RepoUnit
  120. var err error
  121. if u, err = repo.getUnit(e, UnitTypeIssues); err != nil {
  122. log.Trace("%s", err)
  123. return setting.Service.DefaultEnableDependencies
  124. }
  125. return u.IssuesConfig().EnableDependencies
  126. }