forked from MichaelMure/git-bug
/
workflow.go
137 lines (126 loc) · 4 KB
/
workflow.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package bug
import (
"fmt"
)
type ValidationFunc func(snap *Snapshot, next Status) error
type Transition struct {
start Status
end Status
hook []ValidationFunc
}
type Workflow struct {
label Label
initialState Status
transitions []Transition
}
var workflowStore []Workflow
// FindWorkflow searches a list of labels and attempts to match them to a workflow, returning the first found
func FindWorkflow(names []Label) *Workflow {
for _, l := range names {
if l.IsWorkflow() {
for wf := range workflowStore {
if workflowStore[wf].label == l {
return &workflowStore[wf]
}
}
}
}
return nil
}
// GetWorkflowLabels returns a slice of all the available workflow labels
func GetWorkflowLabels() []Label {
var labels []Label
for _, wf := range workflowStore {
labels = append(labels, wf.label)
}
return labels
}
// NextStatuses returns a slice of next possible statuses in the workflow
// for the given one
func (w *Workflow) NextStatuses(s Status) []Status {
var validStatuses []Status
for _, t := range w.transitions {
if t.start == s {
validStatuses = append(validStatuses, t.end)
}
}
return validStatuses
}
// ValidateTransition checks if the transition is valid for a given start and end
func (w *Workflow) ValidateTransition(snap *Snapshot, to Status) error {
for _, t := range w.transitions {
if t.start == snap.Status && t.end == to {
if t.hook != nil {
for _, v := range t.hook {
if err := v(snap, to); err != nil {
return err
}
}
}
return nil
}
}
// invalid transition, return error with list of valid transitions
nextStatuses := w.NextStatuses(snap.Status)
return fmt.Errorf("invalid transition %s->%s, possible next statuses: %s", snap.Status, to, nextStatuses)
}
func init() {
// Initialise list of workflows
workflowStore = []Workflow{
{label: "workflow:eng",
initialState: ProposedStatus,
transitions: []Transition{
{start: ProposedStatus, end: VettedStatus,
hook: []ValidationFunc{ValidateCcb}},
{start: ProposedStatus, end: RejectedStatus},
{start: VettedStatus, end: InProgressStatus,
hook: []ValidationFunc{ValidateAssigneeSet}},
{start: VettedStatus, end: RejectedStatus,
hook: []ValidationFunc{ValidateCcb}},
{start: InProgressStatus, end: VettedStatus},
{start: InProgressStatus, end: InReviewStatus},
{start: InProgressStatus, end: RejectedStatus,
hook: []ValidationFunc{ValidateCcb}},
{start: InReviewStatus, end: InProgressStatus},
{start: InReviewStatus, end: ReviewedStatus},
{start: InReviewStatus, end: RejectedStatus,
hook: []ValidationFunc{ValidateCcb}},
{start: ReviewedStatus, end: InProgressStatus},
{start: ReviewedStatus, end: AcceptedStatus,
hook: []ValidationFunc{ValidateCcb,
ValidateChecklistsCompleted}},
{start: ReviewedStatus, end: RejectedStatus,
hook: []ValidationFunc{ValidateCcb}},
{start: AcceptedStatus, end: MergedStatus},
{start: AcceptedStatus, end: RejectedStatus,
hook: []ValidationFunc{ValidateCcb}},
{start: MergedStatus, end: AcceptedStatus},
{start: RejectedStatus, end: ProposedStatus},
},
},
{label: "workflow:qa",
initialState: ProposedStatus,
transitions: []Transition{
{start: ProposedStatus, end: InProgressStatus,
hook: []ValidationFunc{ValidateAssigneeSet}},
{start: ProposedStatus, end: RejectedStatus},
{start: InProgressStatus, end: DoneStatus},
{start: InProgressStatus, end: RejectedStatus},
{start: DoneStatus, end: InProgressStatus},
{start: RejectedStatus, end: ProposedStatus},
},
},
{label: "workflow:change",
initialState: ProposedStatus,
transitions: []Transition{
{start: ProposedStatus, end: InProgressStatus,
hook: []ValidationFunc{ValidateAssigneeSet}},
{start: ProposedStatus, end: RejectedStatus},
{start: InProgressStatus, end: DoneStatus},
{start: InProgressStatus, end: RejectedStatus},
{start: DoneStatus, end: InProgressStatus},
{start: RejectedStatus, end: ProposedStatus},
},
},
}
}