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.

144 lines
3.9 KiB

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