1package operations
2
3import (
4 "fmt"
5 "sort"
6
7 "github.com/MichaelMure/git-bug/bug"
8)
9
10var _ bug.Operation = LabelChangeOperation{}
11
12// LabelChangeOperation define a Bug operation to add or remove labels
13type LabelChangeOperation struct {
14 bug.OpBase
15 Added []bug.Label `json:"added"`
16 Removed []bug.Label `json:"removed"`
17}
18
19// Apply apply the operation
20func (op LabelChangeOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {
21 // Add in the set
22AddLoop:
23 for _, added := range op.Added {
24 for _, label := range snapshot.Labels {
25 if label == added {
26 // Already exist
27 continue AddLoop
28 }
29 }
30
31 snapshot.Labels = append(snapshot.Labels, added)
32 }
33
34 // Remove in the set
35 for _, removed := range op.Removed {
36 for i, label := range snapshot.Labels {
37 if label == removed {
38 snapshot.Labels[i] = snapshot.Labels[len(snapshot.Labels)-1]
39 snapshot.Labels = snapshot.Labels[:len(snapshot.Labels)-1]
40 }
41 }
42 }
43
44 // Sort
45 sort.Slice(snapshot.Labels, func(i, j int) bool {
46 return string(snapshot.Labels[i]) < string(snapshot.Labels[j])
47 })
48
49 return snapshot
50}
51
52func NewLabelChangeOperation(author bug.Person, added, removed []bug.Label) LabelChangeOperation {
53 return LabelChangeOperation{
54 OpBase: bug.NewOpBase(bug.LabelChangeOp, author),
55 Added: added,
56 Removed: removed,
57 }
58}
59
60// ChangeLabels is a convenience function to apply the operation
61func ChangeLabels(b bug.Interface, author bug.Person, add, remove []string) ([]LabelChangeResult, error) {
62 var added, removed []bug.Label
63 var results []LabelChangeResult
64
65 snap := b.Compile()
66
67 for _, str := range add {
68 label := bug.Label(str)
69
70 // check for duplicate
71 if labelExist(added, label) {
72 results = append(results, LabelChangeResult{Label: label, Status: LabelChangeDuplicateInOp})
73 continue
74 }
75
76 // check that the label doesn't already exist
77 if labelExist(snap.Labels, label) {
78 results = append(results, LabelChangeResult{Label: label, Status: LabelChangeAlreadySet})
79 continue
80 }
81
82 added = append(added, label)
83 results = append(results, LabelChangeResult{Label: label, Status: LabelChangeAdded})
84 }
85
86 for _, str := range remove {
87 label := bug.Label(str)
88
89 // check for duplicate
90 if labelExist(removed, label) {
91 results = append(results, LabelChangeResult{Label: label, Status: LabelChangeDuplicateInOp})
92 continue
93 }
94
95 // check that the label actually exist
96 if !labelExist(snap.Labels, label) {
97 results = append(results, LabelChangeResult{Label: label, Status: LabelChangeDoesntExist})
98 continue
99 }
100
101 removed = append(removed, label)
102 results = append(results, LabelChangeResult{Label: label, Status: LabelChangeRemoved})
103 }
104
105 if len(added) == 0 && len(removed) == 0 {
106 return results, fmt.Errorf("no label added or removed")
107 }
108
109 labelOp := NewLabelChangeOperation(author, added, removed)
110
111 b.Append(labelOp)
112
113 return results, nil
114}
115
116func labelExist(labels []bug.Label, label bug.Label) bool {
117 for _, l := range labels {
118 if l == label {
119 return true
120 }
121 }
122
123 return false
124}
125
126type LabelChangeStatus int
127
128const (
129 _ LabelChangeStatus = iota
130 LabelChangeAdded
131 LabelChangeRemoved
132 LabelChangeDuplicateInOp
133 LabelChangeAlreadySet
134 LabelChangeDoesntExist
135)
136
137type LabelChangeResult struct {
138 Label bug.Label
139 Status LabelChangeStatus
140}