-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added dependencies for issues (#2196) #2531
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rebase to master.
models/issue_dependency.go
Outdated
sess := x.NewSession() | ||
|
||
// TODO: Move this to the appropriate place | ||
err = x.Sync(new(IssueDependency)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to a migration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As i stated above:
There is some work to be done with migrations etc, currently i simply put the xorm-call at the beginning of the function, which probably shouldn't be there. Where is the appropriate place to put this?
Where?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Migrations are found in models/migrations. Create a new one and call from migrations.go.
models/issue_dependency.go
Outdated
sess := x.NewSession() | ||
|
||
// TODO: Same as above | ||
err = x.Sync(new(IssueDependency)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to a migration.
models/repo.go
Outdated
@@ -666,6 +668,41 @@ func (repo *Repository) CanEnableEditor() bool { | |||
return !repo.IsMirror | |||
} | |||
|
|||
// Find all Dependencies an issue is blocked by | |||
func (repo *Repository) BlockedByDependencies(issueID int64) (_ []*Issue, err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace _ []*Issue
with issueDepsFull []*Issue
and remove var issueDepsFull = make([]*Issue, 0)
.
models/issue_dependency.go
Outdated
} | ||
|
||
// RemoveIssueDependency removes a dependency from an issue | ||
func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType int64) (err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create custom type for depType
and constant for each type. Maybe type issueDependencyType int
. Also why int64 when you are using only 1 or 2? Even byte would be sufficient.
models/issue_dependency.go
Outdated
// If it exists, remove it, otherwise show an error message | ||
if exists { | ||
|
||
if depType == 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use custom type and define constants instead of hardcoded values.
models/issue_dependency.go
Outdated
} | ||
} | ||
|
||
if depType == 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use custom type and define constants instead of hardcoded values.
return | ||
} | ||
|
||
if depType != 1 && depType != 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use custom type and define constants instead of hardcoded values.
} | ||
|
||
// Dependency Type | ||
// Types: 1 = blockedBy, 2 = blocking |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create constants for known options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now you don't need these comments if you have custom types (or you define map as suggested in aother comment)
models/issue_dependency.go
Outdated
func IssueNoDependenciesLeft(issue *Issue) bool { | ||
|
||
var issueDeps []IssueDependency | ||
err := x.Where("issue_id = ?", issue.ID).Find(&issueDeps) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create just one, complex query (join IssueDependecy
and Issue
table).
models/repo.go
Outdated
// BlockedByDependencies finds all Dependencies an issue is blocked by | ||
func (repo *Repository) BlockedByDependencies(issueID int64) (_ []*Issue, err error) { | ||
|
||
issueDeps, err := repo.getBlockedByDependencies(x, issueID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create one complex query to find all issues.
models/repo.go
Outdated
// BlockingDependencies returns all blocking dependencies | ||
func (repo *Repository) BlockingDependencies(issueID int64) (_ []*Issue, err error) { | ||
|
||
issueDeps, err := repo.getBlockingDependencies(x, issueID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create one complex query to find all issues.
routers/repo/issue.go
Outdated
|
||
canbeClosed := models.IssueNoDependenciesLeft(issue) | ||
|
||
if !canbeClosed { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if !models.IssueNoDependenciesLeft(issue)
routers/repo/pull.go
Outdated
@@ -428,6 +428,14 @@ func MergePullRequest(ctx *context.Context) { | |||
|
|||
pr.Issue = issue | |||
pr.Issue.Repo = ctx.Repo.Repository | |||
canbeClosed := models.IssueNoDependenciesLeft(issue) | |||
|
|||
if !canbeClosed { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if !models.IssueNoDependenciesLeft(issue)
@Morlinest @JonasFranzDEV Done. |
@kolaente conflicting files. |
@lunny Done. |
models/issue_dependency.go
Outdated
@@ -15,43 +15,21 @@ type IssueDependency struct { | |||
IssueID int64 `xorm:"UNIQUE(watch) NOT NULL"` | |||
DependencyID int64 `xorm:"UNIQUE(watch) NOT NULL"` | |||
Created time.Time `xorm:"-"` | |||
CreatedUnix int64 `xorm:"NOT NULL"` | |||
CreatedUnix int64 `xorm:"INDEX created"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
INDEX
is optional, don't know if you need it or just used code from previous review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i've just used it, think it works.
models/issue_dependency.go
Outdated
// Define Dependency Type Constants | ||
const ( | ||
DependencyTypeBlockedBy int64 = 1 | ||
DependencyTypeBlocking int64 = 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type DependencyType int
const (
DependencyTypeBlockedBy DependencyType = iota
DependencyTypeBlocking
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But how do i check for the given type by the user in routers/repo/issue_dependency_remove.go:33?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please read all comments first. I think I've already answered it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the compiler complains because i cannot compare an int with a custom type DepenencyType
(although they both are ints).
Or did I overlooked something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't have place where you compare int with custom type. What error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error was something like "You cannot compare a variable of type int
with a variable of type DependencyType
". But it's ok i guess, i've solved it differently.
models/issue_dependency.go
Outdated
} | ||
|
||
// RemoveIssueDependency removes a dependency from an issue | ||
func RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType int64) (err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RemoveIssueDependency(user *User, issue *Issue, dep *Issue, depType DependencyType)
|
||
// Dependency Type | ||
// Types: 1 = blockedBy, 2 = blocking | ||
depType, err := strconv.ParseInt(c.Req.PostForm.Get("dependencyType"), 10, 64) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use map. Eg:
depTypes := map[int]DependencyType{1: DependencyTypeBlockedBy, 2: DependencyTypeBlocking}
and check:
depType, ok := depTypes[c.QueryInt("dependencyType")]
if !ok {
c.Handle(http.StatusBadRequest, "GetDependecyType", nil)
return
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
like the idea, but wouldn't this mean i had to define the dependency types two times? (which i'd rather want to avoid)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think no. This is mapping. Actualy I think you can change it from int
to string
and use strings in post calls (as it would be more descriptive). Something like:
map[int]DependencyType{"blockedby": DependencyTypeBlockedBy, "blocking": DependencyTypeBlocking}
You know that DependencyTypeXYZ
is also int, but in reality it is custom type that can be anything. If you use constnants you don't care about real type (it can be type DependencyType string
for example). Also it's not same number:
const (
DependencyTypeBlockedBy DependencyType = iota // = 0
DependencyTypeBlocking // = 1
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solved it without a map.
models/issue_dependency.go
Outdated
} | ||
} | ||
|
||
if depType == DependencyTypeBlocking { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use else if
or switch
. What if depType
has other values? You shoould check that too. Also you can store IssueDependency
in variable and then call x.Delete()
. Eg:
var issueDepToDelete IssueDependency
switch depType {
case DependencyTypeBlockedBy:
issueDepToDelete = IssueDependency{IssueID: issue.ID, DependencyID: dep.ID}
case DependencyTypeBlocking:
issueDepToDelete = IssueDependency{IssueID: dep.ID, DependencyID: issue.ID}
default:
// return error
}
_, err := x.Delete(&issueDepToDelete)
if err != nil {
return err
}
models/issue_dependency.go
Outdated
sess := x.NewSession() | ||
|
||
// Check if it exists | ||
exists, err := issueDepExists(x, issue.ID, dep.ID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You do check where you switch issue for dep, but later you are deleting in given order. What it should do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It checks if the dependency already exists as you send it to the backend, but it also checks the other way around to prevent to issues blocking each other. This would result in none of them could be closed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
models/issue_dependency.go
Outdated
} | ||
|
||
// Check if the dependency already exists | ||
func issueDepExists(e Engine, issueID int64, depID int64) (exists bool, err error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like names issueID
and depID
because you are switching their meaning inside function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First issueID
means issueID
and second time issueID
means depID
. I think both arguments are equivalent because you are trying to find dependency between them not matter which way. Variable names should reflect this fact (eg. issue1ID, issue2ID int64
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I try to find all dependencies, no matter of direction.
But: issueID
is the issue we're currently on, depID
is the other issue we want to look for. I think it would be more confunsing to rename the variables to issue1ID
etc. I would prefer keeping it the way it is.
To be more clear, an example:
When I'm on issue #1 and want to add a new dependency of #2 i send a request to the backend saying something like "Hi, I'm issue #1 and want to add #2 as my dependent issue.". The dependend issue (#2) becomes depID
, the issue we're on becomes isuueID
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am ok with that as long as issueDepExists
stays unexported and is used only for your mentioned scenario.
I was thinking about it in more general way. Like using this function for checking (from any place of code) any dependency between two issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, cool.
I think to be more general, it would need to return a struct with both issues, but i dont see a usecase for this (yet).
models/issue_dependency.go
Outdated
} | ||
} | ||
|
||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move err check before range
.
} | ||
|
||
// Dependency Type | ||
// Types: 1 = blockedBy, 2 = blocking |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now you don't need these comments if you have custom types (or you define map as suggested in aother comment)
routers/repo/issue.go
Outdated
// Check for open dependencies | ||
if form.Status == "close" { | ||
|
||
if models.IssueNoDependenciesLeft(issue) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if form.Status == "close" && models.IssueNoDependenciesLeft(issue)
@@ -1,7 +1,7 @@ | |||
{{range .Issue.Comments}} | |||
{{ $createdStr:= TimeSince .Created $.Lang }} | |||
|
|||
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING, 13 = STOP_TRACKING, 14 = ADD_TIME_MANUAL --> | |||
<!-- 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE_REF, 4 = COMMIT_REF, 5 = COMMENT_REF, 6 = PULL_REF, 7 = COMMENT_LABEL, 12 = START_TRACKING, 13 = STOP_TRACKING, 14 = ADD_TIME_MANUAL, 15 = CANCEL_TIME_TRACKING, 16 = ADDED_DEPENDENCY, 17 = REMOVED_DEPENDENCY --> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
16 = ADD_DEPENDENCY, 17 = REMOVE_DEPENDENCY
Can you add some screenshots pls? |
@Morlinest of course, please see my updated first comment. |
And we really need a better way to search for other issues (see my first question) |
@kolaente Thx for screenshots. And yes, we need better search. Adding issue search api would be great. |
|
Yes, as another PR. Maybe I can do something with it. |
I've created a seperate issue for the api endpoint so we dont forget it: #2597 |
However, am i right when i say this pr is blocked until we have an apiendpoint to search for issues? |
@kolaente No. Searching can be added later. Also I am working on issue search api right now, There is api endpoint for issues, but doesn't contains search by part of ID. You can wait for it or use it as it is now, without partialy ID matching. |
Ok, cool. But i should change it so you only need the issue index, not its id (as it is right now). Also, a more general question: should we allow dependencies across repositories? It doesn't check currently which repository the id belongs to you give it. (For now, I think I'll just implement it with the issue index, later, when we have the search we could probably think about dependencies across repositories) |
It should be possible to add dependency only on same repository. One of reasons (for me) is security and access rights. |
@kolaente I've finished (at least first version, but working very nice) index search for issues api. Will send PR tomorrow. |
Ok, then i'll wait until this is merged to master (or shouldn't I?) |
Don't wait. Maybe changes to current api is not needed for this feature (read #2606 - you can use existing api and load latests issues for making suggestions). |
The problem is, there is no apiendpoint to get a list of issues (not even one issue). Or did i overlooked something? |
Yes, overlooked :) |
@JonasFranzDEV fixed. |
@Morlinest @lafriks please approve. |
@Morlinest @lafriks please approve. |
Thanks @Morlinest ! |
@lafriks please approve. |
# Conflicts: # options/locale/locale_en-US.ini # templates/repo/issue/view_content/sidebar.tmpl
Sry for taking so long to approve, nice work 👍 |
@lafriks Thank you! |
LGTM |
In the dependencies list it only lists the last 10 issues relative to that one. Edit: |
@AragurDEV Fast search: issues search api (/api/v1/repos/:username/:reponame/issues) uses
I tested it, you can search only with full words, in your example it would be "test", "issue". But I can confirm, this feature is little buggy right now and UI does not fully work as expected in my tests. |
@Morlinest thanks a lot! |
@AragurDEV Please create an issue so we can discuss there. This feature needs little tweaks. |
Prepare for wild/v1.6 branch * BREAKING * Respect email privacy option in user search via API (go-gitea#4512) * Simply remove tidb and deps (go-gitea#3993) * Swagger.v1.json template (go-gitea#3572) * FEATURE * Pull request review/approval and comment on code (go-gitea#3748) * Added dependencies for issues (go-gitea#2196) (go-gitea#2531) * Add the ability to have built in themes in Gitea and provide dark theme arc-green (go-gitea#4198) * Add sudo functionality to the API (go-gitea#4809) * Add oauth providers via cli (go-gitea#4591) * Disable merging a WIP Pull request (go-gitea#4529) * Force user to change password (go-gitea#4489) * Add letsencrypt to Gitea (go-gitea#4189) * Add push webhook support for mirrored repositories (go-gitea#4127) * Add csv file render support defaultly (go-gitea#4105) * Add Recaptcha functionality to Gitea (go-gitea#4044) * BUGFIXES * Fix release creation via API (go-gitea#5076) * Remove links from topics in edit mode (go-gitea#5026) * Fix missing AppSubUrl in few more templates (fixup) (go-gitea#5021) * Fix missing AppSubUrl in some templates (go-gitea#5020) * Hide outdated comments in file view (go-gitea#5017) * Upgrade gopkg.in/testfixtures.v2 (go-gitea#4999) * Disable debug routes unless PPROF is enabled in configuration (go-gitea#4995) * Fix user menu item styling (go-gitea#4985) * Fix layout of the topics editing form (go-gitea#4971) * Fix null pointer dereference in ParseCommitWithSignature (go-gitea#4962) * Fix url in discord webhook (go-gitea#4953) * Detect charset and convert non UTF-8 files for display (go-gitea#4950) * Make sure to catch the right error so it is displayed on the UI (go-gitea#4945) * Fix(topics): don't redirect to explore page. (go-gitea#4938) * Fix bug forget to remove Stopwatch when remove repository (go-gitea#4928) * Fix bug when repo remained bare if multiple branches pushed in single push (go-gitea#4923) * Fix: Let's Encrypt configuration settings (go-gitea#4911) * Fix: Crippled diff (go-gitea#4726) (go-gitea#4900) * Fix trimming of markup section names (go-gitea#4863) * Issues api allow pulls and fix go-gitea#4832 (go-gitea#4852) * Do not autocreate directory for new users/orgs (go-gitea#4828) (go-gitea#4849) * Fix redirect with non-ascii branch names (go-gitea#4764) (go-gitea#4810) * Fix missing release title in webhook (go-gitea#4783) (go-gitea#4796) * User shouldn't be able to approve or reject his/her own PR (go-gitea#4729) * Make sure to reset commit count in the cache on mirror syncing (go-gitea#4720) * Fixed bug where team with admin privelege type doesn't get any unit (go-gitea#4719) * Fix incorrect caption of webhook setting (go-gitea#4701) (go-gitea#4717) * Allow WIP marker to contains < or > (go-gitea#4709) * Hide org/create menu item in Dashboard if user has no rights (go-gitea#4678) (go-gitea#4680) * Site admin could create repos even MAX_CREATION_LIMIT=0 (go-gitea#4645) * Fix custom templates being ignored (go-gitea#4638) * Fix starring icon after semantic ui update (go-gitea#4628) * Fix Split-View line adjustment (go-gitea#4622) * Fix integer constant overflows in tests (go-gitea#4616) * Push whitelist now doesn't apply to branch deletion (go-gitea#4601) (go-gitea#4607) * Fix bugs when too many IN variables (go-gitea#4594) * Fix failure on creating pull request with assignees (go-gitea#4419) (go-gitea#4583) * Fix panic issue on update avatar email (go-gitea#4580) (go-gitea#4581) * Fix status code label for a successful webhook (go-gitea#4540) * An inactive user shouldn't be able to be added as a collaborator (go-gitea#4535) * Don't fail silently if trying to add a collaborator twice (go-gitea#4533) * Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (go-gitea#4519) (go-gitea#4525) * Fix out-of-transaction query in removeOrgUser (go-gitea#4521) (go-gitea#4522) * Fix migration from older releases (go-gitea#4495) * Accept 'Data:' in commit graph (go-gitea#4487) * Update xorm to latest version and fix correct `user` table referencing in sql (go-gitea#4473) * Relative URLs for LibreJS page (go-gitea#4460) * Redirect to correct page after using scratch token (go-gitea#4458) * Fix column droping for MSSQL that need new transaction for that (go-gitea#4440) * Replace src with raw to fix image paths (go-gitea#4377) * Add default merge options when creating new repository (go-gitea#4369) * Fix docker build (go-gitea#4358) * Fixes repo membership check in API (go-gitea#4341) * Dep upgrade mysql lib (go-gitea#4161) * Fix some issues with special chars in branch names (go-gitea#3767) * Responsive design fixes (go-gitea#4508) * ENHANCEMENT * Fix milestones sorted wrongly (go-gitea#4987) * Allow api to create tags for releases if they don't exist (go-gitea#4890) * Fix go-gitea#4877 to follow the OpenID Connect Audiences spec (go-gitea#4878) * Enforce token on api routes [fixed critical security issue go-gitea#4357] (go-gitea#4840) * Update legacy branch and tag URLs in dashboard to new format (go-gitea#4812) * Slack webhook channel name cannot be empty or just contain an hashtag (go-gitea#4786) * Add whitespace handling to PR-comparsion (go-gitea#4683) * Make reverse proxy auth optional (go-gitea#4643) * MySQL TLS (go-gitea#4642) * Make sure to set PR split view when creating/previewing a pull request (go-gitea#4617) * Log user in after a successful sign up (go-gitea#4615) * Fix typo IsPullReuqestBroken -> IsPullRequestBroken (go-gitea#4578) * Allow admin toggle forcing a password change for newly created users (go-gitea#4563) * Update jQuery to v1.12.4 (go-gitea#4551) * Env var GITEA_PUSHER_EMAIL (go-gitea#4516) * Feat(repo): support search repository by topic name (go-gitea#4505) * Small improvements to dependency UI (go-gitea#4503) * Make max commits in graph configurable (go-gitea#4498) * Add valid for lfs oid (go-gitea#4461) * Add shortcut to save wiki page (go-gitea#4452) * Allow administrator to create repository for any organization (go-gitea#4368) * Fix repository last updated time update when delete a user who watched the repo (go-gitea#4363) * Switch plaintext scratch tokens to use hash instead (go-gitea#4331) * Increase default TOTP secret size to 320 bits (go-gitea#4287) * Keep preseeded database password (go-gitea#4284) * Implemented hover text showing user FullName (go-gitea#4261) * Add ability to delete a token (go-gitea#4235) * Fix typos in i18n variable names. (go-gitea#4080) * Api: repos/search: add parameters to control the sort order (go-gitea#3964) * Add missing path in the Docker app.ini template (go-gitea#2181) * Add file name and branch to page title (go-gitea#4902) * Offline use of google fonts (go-gitea#4872) * Add missing History link to directory listings v2 (go-gitea#4829) * Locale for Edit and Remove due date issue (go-gitea#4802) * Disable 'May Import Local Repository' when is disabled by setting (Is… (go-gitea#4780) * API /admin/users/{username} missing parameter (go-gitea#4775) * Display error when adding a user to a team twice (go-gitea#4746) * Remove UsePrivilegeSeparation from the Docker sshd_config, see go-gitea#2876 (go-gitea#4722) * Focus title input when clicking helper link (go-gitea#4696) * Add vendor to user reserved words and format words list according alphabet (go-gitea#4685) * Add gitea/issues link to 500 page (go-gitea#4654) * Hide home button when landing page is not set to home (go-gitea#4651) * Remove link to GitHub issues in 404 template (go-gitea#4639) * Cmd/serve: pprof cpu and memory profile dumps to disk (go-gitea#4560) * Add flash message after an account has been successfully activated (go-gitea#4510) * Prevent html entity escaping on delete branch (go-gitea#4471) * Locale for button Edit on protected branch (go-gitea#4442) * Update notification icon (go-gitea#4343) * Added front-end topics validation (go-gitea#4316) * Don't display buttons if there are no system notifications (go-gitea#4280) * Issue due date api (go-gitea#3890) * SECURITY * Improve URL validation for external wiki and external issues (go-gitea#4710) * Make cookies HttpOnly and obey COOKIE_SECURE flag (go-gitea#4706) * Don't disclose emails of all users when sending out emails (go-gitea#4664) * Check that repositories can only be migrated to own user or organizations (go-gitea#4366) * TRANSLATION * Fix punctuation in English translation (go-gitea#4958) * Fix translation (go-gitea#4355)
Introduction
This PR implements dependencies for issues, as described in #2196.
It lets you define anonther issue as a dependency for an issue. You the cannot close the issue if it has any dependent issues which aren't closed. If you try to autoclose an issue via commit message which still has dependencies left, autoclose will simply not close the issue, but the commit will not fail.
You can disable dependencies in the repo settings.
Example: You set #2, #3 and #4 as a dependency of #1. Now you need to close all #2, #3 and #4, before you can close #1.
Screenshots
Overview of Issue Dependencies (sidebar):
Comments after adding a new dependency:
Questions
Currently, i would describe this as "working, but not finished", as there are some questions i have:
If such thing already exists, please point me to it, I haven't found any.
This is my first time I've done something like this in Go, before i've only played around with Go but never really did anything bigger. So, there are probably some things I didn't got right as a novice. Looking forward to hear your improvents to be made! Also thanks to @JonasFranzDEV who has helped me a lot.