diff --git a/gobot/common/constants.go b/gobot/common/constants.go index 782ff0aa..78a3ef9e 100644 --- a/gobot/common/constants.go +++ b/gobot/common/constants.go @@ -25,6 +25,19 @@ const ( InstructLabBotUrl = "https://github.com/instructlab/instructlab-bot" ) +// Not sure we need all this, keeping for now until tested with just name +const ( + TrainingDataApproveCheck = "Training Data Approval Check" + TrainingDataApproveStatus = "Training Data Approval Status" + // TrainingDataAprroveLabelID int64 = 6964465752 + // TrainingDataApproveLabelNodeId = "LA_kwDOLf49gM8AAAABnx1QWA" + // TrainingDataApproveLabelURL = "https://api.github.com/repos/instructlab/instructlab-bot/labels/training-data-approved" + TrainingDataApproveLabelName = "training-data-approved" + // TrainingDataApproveLabelColor = "18F02A" + // TrainintDataApproveLabelDefault = false + // TrainingDataApproveLabelDescription = "generated seed data approved, you may run ilab train." +) + const ( RedisKeyJobs = "jobs" RedisKeyPRNumber = "pr_number" diff --git a/gobot/handlers/issue_comment_event.go b/gobot/handlers/issue_comment_event.go index 33167b36..f75325c6 100644 --- a/gobot/handlers/issue_comment_event.go +++ b/gobot/handlers/issue_comment_event.go @@ -128,6 +128,8 @@ func (h *PRCommentHandler) Handle(ctx context.Context, eventType, deliveryID str return h.precheckCommand(ctx, client, &prComment) case "generate": return h.sdgSvcCommand(ctx, client, &prComment) + case "approve": + return h.trainingDataApproveCommand(ctx, client, &prComment) default: return h.unknownCommand(ctx, client, &prComment) } @@ -464,3 +466,72 @@ func (h *PRCommentHandler) unknownCommand(ctx context.Context, client *github.Cl return nil } + +func (h *PRCommentHandler) trainingDataApproveCommand(ctx context.Context, client *github.Client, prComment *PRComment) error { + h.Logger.Infof("Approve command received on %s/%s#%d by %s", + prComment.repoOwner, prComment.repoName, prComment.prNum, prComment.author) + + statusParams := util.PullRequestStatusParams{ + Status: common.CheckComplete, + Conclusion: common.CheckStatusFailure, + CheckName: common.TrainingDataApproveCheck, + RepoOwner: prComment.repoOwner, + RepoName: prComment.repoName, + PrNum: prComment.prNum, + PrSha: prComment.prSha, + } + + labelParams := util.PullRequestLabelParams{ + Name: common.TrainingDataApproveLabelName, + RepoOwner: prComment.repoOwner, + RepoName: prComment.repoName, + PrNum: prComment.prNum, + PrSha: prComment.prSha, + } + + // Check if user is part of the teams that are allowed to enable the bot + isAllowed := h.checkAuthorPermission(ctx, client, prComment) + if !isAllowed { + statusParams.Comment = fmt.Sprintf("User %s is not allowed to run the InstructLab bot. Only %v teams are allowed to access the bot functions.", prComment.author, h.Maintainers) + + err := util.PostPullRequestComment(ctx, client, statusParams) + if err != nil { + h.Logger.Errorf("Failed to post comment on PR %s/%s#%d: %v", prComment.repoOwner, prComment.repoName, prComment.prNum, err) + return err + } + return nil + } + + present, err := util.CheckRequiredLabel(prComment.labels, h.RequiredLabels) + if err != nil { + h.Logger.Errorf("Failed to check required labels: %v", err) + } + if !present { + detailsMsg := fmt.Sprintf("Beep, boop 🤖: To proceed, the pull request must have one of the '%v' labels.", h.RequiredLabels) + if err != nil { + detailsMsg = fmt.Sprintf("%s\nError: %v", detailsMsg, err) + } + + statusParams.CheckSummary = LabelsNotFound + statusParams.CheckDetails = detailsMsg + + return util.PostPullRequestCheck(ctx, client, statusParams) + } + + // 1. Applies the label training-data-approved + err = util.PostPullRequestLabel(ctx, client, labelParams) + if err != nil { + h.Logger.Errorf("Failed to check required labels: %v", err) + } + + // 2. Prompt user to run the training + statusParams.Comment = fmt.Sprintf("the '%s' label has been applied to the PR. You may now run '@instruct-lab-bot train", common.TrainingDataApproveLabelName) + + err = util.PostPullRequestComment(ctx, client, statusParams) + if err != nil { + h.Logger.Errorf("Failed to post comment on PR %s/%s#%d: %v", prComment.repoOwner, prComment.repoName, prComment.prNum, err) + return err + } + + return nil +} diff --git a/gobot/util/pr_updates.go b/gobot/util/pr_updates.go index caf1756b..c05fec95 100644 --- a/gobot/util/pr_updates.go +++ b/gobot/util/pr_updates.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "os" "strings" "time" @@ -11,6 +12,22 @@ import ( "github.com/instructlab/instructlab-bot/gobot/common" ) +type PullRequestLabelParams struct { + // ID int64 + // URL string + Name string + Comment string + // Color string + // Description string + // Default bool + // NodeID string + + RepoOwner string + RepoName string + PrNum int + PrSha string +} + type PullRequestStatusParams struct { Status string Conclusion string @@ -64,7 +81,6 @@ func PostPullRequestComment(ctx context.Context, client *github.Client, params P } func PostPullRequestCheck(ctx context.Context, client *github.Client, params PullRequestStatusParams) error { - checkRequest := github.CreateCheckRunOptions{ Name: params.CheckName, HeadSHA: params.PrSha, @@ -90,6 +106,26 @@ func PostPullRequestCheck(ctx context.Context, client *github.Client, params Pul return nil } +func PostPullRequestLabel(ctx context.Context, client *github.Client, params PullRequestLabelParams) error { + // Not sure we need all this, keeping for now until tested with just name + label := &github.Label{ + // ID: ¶ms.ID, + // URL: ¶ms.URL, + Name: ¶ms.Name, + // Color: ¶ms.Color, + // Description: ¶ms.Description, + // Default: ¶ms.Default, + // NodeID: ¶ms.NodeID, + } + + _, _, err := client.Issues.AddLabelsToIssue(ctx, params.RepoOwner, params.RepoName, *¶ms.PrNum, []string{*label.Name}) + if err != nil { + fmt.Printf("Error adding label to pull request: %v\n", err) + os.Exit(1) + } + return nil +} + func PostPullRequestStatus(ctx context.Context, client *github.Client, params PullRequestStatusParams) error { status := &github.RepoStatus{ State: github.String(params.Conclusion), // Status state: success, failure, error, or pending