package milestones import ( "fmt" "strconv" "time" "edge-infra.dev/pkg/f8n/devinfra/reports" "edge-infra.dev/pkg/f8n/devinfra/jack/constants" "github.com/google/go-github/v47/github" "edge-infra.dev/pkg/f8n/devinfra/database/psql" "edge-infra.dev/pkg/f8n/devinfra/jack/plugin" ) const dbUser = "jack-bot@ret-edge-dev-infra.iam" func init() { plugin.RegisterTimeEventHandler(constants.PluginMilestone, handleTime) } func handleTime(hp plugin.HandlerParams) { var movers = make(map[int][]int) hp.Log.WithName(constants.PluginMilestone) milestones, _, err := hp.Client.Issues().ListMilestones(hp.Ctx, hp.Org, hp.Repo, &github.MilestoneListOptions{}) // Sorted by due_on ascending, only showing open milestones if err != nil { hp.Log.Error(err, "Failed to list milestones") } now := time.Now() for _, milestone := range milestones { dueOn := milestone.GetDueOn() closing := dueOn.AddDate(0, 0, 2) currentMilestone := milestone.GetNumber() title := milestone.GetTitle() // no need to keep going dump issues and bounce if now.Before(closing) { moveIssues(hp, currentMilestone, title, movers) return } // if a milestone has no due date github assigns it 0001-01-01 we dont want to close those noDueDate := time.Date(int(0001), time.January, int(1), int(0), int(0), int(0), int(0), time.UTC) if dueOn == noDueDate { continue } if now.After(closing) { // create before we close snapshots for ease of indexing err := createSnapshot(hp) if err != nil { hp.Log.Error(err, "unable to create snapshot") } githubIssueBody := &github.Milestone{State: github.String("closed")} hp.Log.Info(fmt.Sprintf("Closing milestone %v", title)) _, _, err = hp.Client.Issues().EditMilestone(hp.Ctx, hp.Org, hp.Repo, currentMilestone, githubIssueBody) if err != nil { hp.Log.Error(err, "Failed to close milestone") return } grabIssues(hp, currentMilestone, movers) } } } func grabIssues(hp plugin.HandlerParams, currentMilestone int, movers map[int][]int) { stringNum := strconv.Itoa(currentMilestone) opts := &github.IssueListByRepoOptions{Milestone: stringNum} issues, _, err := hp.Client.Issues().ListByRepo(hp.Ctx, hp.Org, hp.Repo, opts) if err != nil { hp.Log.Error(err, "Failed to grab issues in milestone") } for _, issue := range issues { issueNum := issue.GetNumber() movers[currentMilestone] = append(movers[currentMilestone], issueNum) } } func moveIssues(hp plugin.HandlerParams, currentMilestone int, title string, movers map[int][]int) { githubIssueBody := &github.IssueRequest{Milestone: github.Int(currentMilestone)} for _, issues := range movers { for _, num := range issues { hp.Log.Info(fmt.Sprintf("Moving issue %d to milestone: %v", num, title)) _, _, err := hp.Client.Issues().Edit(hp.Ctx, hp.Org, hp.Repo, num, githubIssueBody) if err != nil { hp.Log.Error(err, "Failed to change issue's milestone") return } } } } // var ( // sizes = map[string][]int{ // "size/xs": {0, 1}, // "size/s": {1, 2}, // "size/m": {3, 5}, // "size/l": {6, 10}, // "size/xl": {11, 20}, // } // ) // func timeEstimate(hp plugin.HandlerParams, ce github.IssuesEvent) { // //not used yet, may be included in snapshot // opts := &github.IssueListByRepoOptions{State: "closed"} // issues, _, err := hp.Client.Issues().ListByRepo(hp.Ctx, hp.Org, hp.Repo, opts) // if err != nil { // hp.Log.Error().Err(err).Msg("Failed to grab issues") // } // for _, issue := range issues { // openedAt := issue.CreatedAt // closedAt := issue.ClosedAt // issueLife := closedAt.Sub((*openedAt)) // log.Print(issueLife) // labels := issue.Labels // for _, label := range labels { // title := label.GetName() // if strings.Contains(title, "size") { // est := sizes[title] // log.Print(est) // } // } // } // } func createSnapshot(hp plugin.HandlerParams) error { milestones, _, err := hp.Client.Issues().ListMilestones(hp.Ctx, hp.Org, hp.Repo, &github.MilestoneListOptions{}) if err != nil { return err } psql, err := psql.New(psql.WithUser(dbUser)) if err != nil { return err } timeStamp := time.Now() for _, milestone := range milestones { msNum := milestone.GetNumber() stringNum := strconv.Itoa(msNum) opts := &github.IssueListByRepoOptions{Milestone: stringNum} issues, _, err := hp.Client.Issues().ListByRepo(hp.Ctx, hp.Org, hp.Repo, opts) if err != nil { hp.Log.Error(err, "Failed to grab issues in milestone") return err } for _, issue := range issues { insertion := reports.CreateInsertion(issue) _, err := insertion.GetOrAddIssue(psql) if err != nil { return err } issueNum := issue.GetNumber() row, err := psql.DB.Prepare("insert into snapshots values ($1, $2, $3)") if err != nil { return err } _, err = row.Exec(timeStamp, issueNum, msNum) if err != nil { return err } } } return nil }