parent.go
1package main
2
3import (
4 "fmt"
5
6 "github.com/git-bug/git-bug/cache"
7 "github.com/git-bug/git-bug/entities/bug"
8 "github.com/git-bug/git-bug/entity"
9 "github.com/git-bug/git-bug/repository"
10)
11
12// parentMetadataKey is the CreateOp metadata key holding the full ID
13// of the parent bug. Absent means "no parent".
14//
15// git-bug metadata keys are immutable once set: a later SetMetadata
16// cannot overwrite or delete the key. Parent links can therefore only
17// be added to bugs that have none; they cannot be changed or removed.
18const parentMetadataKey = "parent"
19
20// currentParentID returns the bug's current parent full ID, or "".
21func currentParentID(snap *bug.Snapshot) string {
22 if parent, ok := snap.GetCreateMetadata(parentMetadataKey); ok && parent != "" {
23 return parent
24 }
25 return ""
26}
27
28// createsParentCycle reports whether linking bugFullID under parentFullID
29// would close a dependency cycle (i.e. bugFullID is already an ancestor
30// of parentFullID). Self-links are also reported as cycles.
31func createsParentCycle(issues []BugIssue, bugFullID, parentFullID string) bool {
32 if bugFullID == parentFullID {
33 return true
34 }
35 byID := make(map[string]BugIssue, len(issues))
36 for _, issue := range issues {
37 byID[issue.FullID] = issue
38 }
39 for current := parentFullID; current != ""; {
40 if current == bugFullID {
41 return true
42 }
43 ancestor, ok := byID[current]
44 if !ok {
45 return false
46 }
47 current = ancestor.ParentID
48 }
49 return false
50}
51
52// setBugParentLink records parentFullID on the bug's create operation.
53// The caller must ensure the bug has no parent yet: overwriting an
54// existing key is silently ignored by git-bug.
55func setBugParentLink(repo repository.ClockedRepo, b *bug.Bug, createOpID entity.Id, parentFullID string) error {
56 cacheInstance, err := cache.NewRepoCacheNoEvents(repo)
57 if err != nil {
58 return fmt.Errorf("failed to create cache: %w", err)
59 }
60 defer cacheInstance.Close()
61 bc, err := cacheInstance.Bugs().Resolve(b.Id())
62 if err != nil {
63 return fmt.Errorf("failed to resolve bug: %w", err)
64 }
65 if _, err := bc.SetMetadata(createOpID, map[string]string{parentMetadataKey: parentFullID}); err != nil {
66 return fmt.Errorf("failed to set parent: %w", err)
67 }
68 if err := bc.CommitAsNeeded(); err != nil {
69 return fmt.Errorf("failed to commit parent link: %w", err)
70 }
71 return nil
72}