1 package milestones
2
3 import (
4 "fmt"
5 "strconv"
6 "time"
7
8 "edge-infra.dev/pkg/f8n/devinfra/reports"
9
10 "edge-infra.dev/pkg/f8n/devinfra/jack/constants"
11
12 "github.com/google/go-github/v47/github"
13
14 "edge-infra.dev/pkg/f8n/devinfra/database/psql"
15
16 "edge-infra.dev/pkg/f8n/devinfra/jack/plugin"
17 )
18
19 const dbUser = "jack-bot@ret-edge-dev-infra.iam"
20
21 func init() {
22 plugin.RegisterTimeEventHandler(constants.PluginMilestone, handleTime)
23 }
24
25 func handleTime(hp plugin.HandlerParams) {
26 var movers = make(map[int][]int)
27
28 hp.Log.WithName(constants.PluginMilestone)
29 milestones, _, err := hp.Client.Issues().ListMilestones(hp.Ctx, hp.Org, hp.Repo, &github.MilestoneListOptions{})
30
31 if err != nil {
32 hp.Log.Error(err, "Failed to list milestones")
33 }
34 now := time.Now()
35 for _, milestone := range milestones {
36 dueOn := milestone.GetDueOn()
37 closing := dueOn.AddDate(0, 0, 2)
38 currentMilestone := milestone.GetNumber()
39 title := milestone.GetTitle()
40
41 if now.Before(closing) {
42 moveIssues(hp, currentMilestone, title, movers)
43 return
44 }
45
46 noDueDate := time.Date(int(0001), time.January, int(1), int(0), int(0), int(0), int(0), time.UTC)
47 if dueOn == noDueDate {
48 continue
49 }
50 if now.After(closing) {
51
52 err := createSnapshot(hp)
53 if err != nil {
54 hp.Log.Error(err, "unable to create snapshot")
55 }
56 githubIssueBody := &github.Milestone{State: github.String("closed")}
57 hp.Log.Info(fmt.Sprintf("Closing milestone %v", title))
58 _, _, err = hp.Client.Issues().EditMilestone(hp.Ctx, hp.Org, hp.Repo, currentMilestone, githubIssueBody)
59 if err != nil {
60 hp.Log.Error(err, "Failed to close milestone")
61 return
62 }
63 grabIssues(hp, currentMilestone, movers)
64 }
65 }
66 }
67 func grabIssues(hp plugin.HandlerParams, currentMilestone int, movers map[int][]int) {
68 stringNum := strconv.Itoa(currentMilestone)
69 opts := &github.IssueListByRepoOptions{Milestone: stringNum}
70 issues, _, err := hp.Client.Issues().ListByRepo(hp.Ctx, hp.Org, hp.Repo, opts)
71 if err != nil {
72 hp.Log.Error(err, "Failed to grab issues in milestone")
73 }
74 for _, issue := range issues {
75 issueNum := issue.GetNumber()
76 movers[currentMilestone] = append(movers[currentMilestone], issueNum)
77 }
78 }
79 func moveIssues(hp plugin.HandlerParams, currentMilestone int, title string, movers map[int][]int) {
80 githubIssueBody := &github.IssueRequest{Milestone: github.Int(currentMilestone)}
81 for _, issues := range movers {
82 for _, num := range issues {
83 hp.Log.Info(fmt.Sprintf("Moving issue %d to milestone: %v", num, title))
84 _, _, err := hp.Client.Issues().Edit(hp.Ctx, hp.Org, hp.Repo, num, githubIssueBody)
85 if err != nil {
86 hp.Log.Error(err, "Failed to change issue's milestone")
87 return
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 func createSnapshot(hp plugin.HandlerParams) error {
127 milestones, _, err := hp.Client.Issues().ListMilestones(hp.Ctx, hp.Org, hp.Repo, &github.MilestoneListOptions{})
128 if err != nil {
129 return err
130 }
131 psql, err := psql.New(psql.WithUser(dbUser))
132 if err != nil {
133 return err
134 }
135 timeStamp := time.Now()
136 for _, milestone := range milestones {
137 msNum := milestone.GetNumber()
138 stringNum := strconv.Itoa(msNum)
139 opts := &github.IssueListByRepoOptions{Milestone: stringNum}
140 issues, _, err := hp.Client.Issues().ListByRepo(hp.Ctx, hp.Org, hp.Repo, opts)
141 if err != nil {
142 hp.Log.Error(err, "Failed to grab issues in milestone")
143 return err
144 }
145 for _, issue := range issues {
146 insertion := reports.CreateInsertion(issue)
147 _, err := insertion.GetOrAddIssue(psql)
148 if err != nil {
149 return err
150 }
151 issueNum := issue.GetNumber()
152 row, err := psql.DB.Prepare("insert into snapshots values ($1, $2, $3)")
153 if err != nil {
154 return err
155 }
156 _, err = row.Exec(timeStamp, issueNum, msNum)
157 if err != nil {
158 return err
159 }
160 }
161 }
162 return nil
163 }
164
View as plain text