diff --git a/gobot/cmd/root.go b/gobot/cmd/root.go index 9ac0fa7d..89c709cc 100644 --- a/gobot/cmd/root.go +++ b/gobot/cmd/root.go @@ -16,6 +16,7 @@ import ( gosmee "github.com/chmouel/gosmee/gosmee" "github.com/go-redis/redis" "github.com/gregjones/httpcache" + "github.com/instructlab/instructlab-bot/gobot/common" "github.com/instructlab/instructlab-bot/gobot/handlers" "github.com/instructlab/instructlab-bot/gobot/util" "github.com/palantir/go-githubapp/githubapp" @@ -257,13 +258,13 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar if result == "" { continue } - prNumber, err := r.Get(buildRedisKey(result, handlers.RedisKeyPRNumber)).Result() + prNumber, err := r.Get(buildRedisKey(result, common.RedisKeyPRNumber)).Result() if err != nil || prNumber == "" { logger.Errorf("No PR number found for job %s", result) continue } - installID, err := r.Get(buildRedisKey(result, handlers.RedisKeyInstallationID)).Result() + installID, err := r.Get(buildRedisKey(result, common.RedisKeyInstallationID)).Result() if err != nil || installID == "" { logger.Errorf("No installation ID found for job %s", result) continue @@ -274,31 +275,31 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar continue } - repoOwner, err := r.Get(buildRedisKey(result, handlers.RedisKeyRepoOwner)).Result() + repoOwner, err := r.Get(buildRedisKey(result, common.RedisKeyRepoOwner)).Result() if err != nil || repoOwner == "" { logger.Errorf("No repo owner found for job %s", result) continue } - repoName, err := r.Get(buildRedisKey(result, handlers.RedisKeyRepoName)).Result() + repoName, err := r.Get(buildRedisKey(result, common.RedisKeyRepoName)).Result() if err != nil || repoName == "" { logger.Errorf("No repo name found for job %s", result) continue } - jobType, err := r.Get(buildRedisKey(result, handlers.RedisKeyJobType)).Result() + jobType, err := r.Get(buildRedisKey(result, common.RedisKeyJobType)).Result() if err != nil || jobType == "" { logger.Errorf("No job type found for job %s", result) continue } - prSha, err := r.Get(buildRedisKey(result, handlers.RedisKeyPRSHA)).Result() + prSha, err := r.Get(buildRedisKey(result, common.RedisKeyPRSHA)).Result() if err != nil || prSha == "" { logger.Errorf("No PR SHA found for job %s", result) continue } - requestTimeStr, err := r.Get(buildRedisKey(result, handlers.RedisKeyRequestTime)).Result() + requestTimeStr, err := r.Get(buildRedisKey(result, common.RedisKeyRequestTime)).Result() if err != nil || requestTimeStr == "" { logger.Errorf("No request time found for job %s", result) continue @@ -312,7 +313,7 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar prURL := fmt.Sprintf("https://github.com/%s/%s/pull/%s", repoOwner, repoName, prNumber) - jobDuration, err := r.Get(buildRedisKey(result, handlers.RedisKeyDuration)).Result() + jobDuration, err := r.Get(buildRedisKey(result, common.RedisKeyDuration)).Result() if err != nil || jobDuration == "" { logger.Infof("Job result for %s/%s#%s, job ID: %s, GitHub URL: %s (No job duration time found for job)", repoOwner, repoName, prNumber, result, prURL) } else { @@ -329,11 +330,11 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar var statusContext string switch jobType { case "generate": - statusContext = util.GenerateLocalCheck + statusContext = common.GenerateLocalCheck case "precheck": - statusContext = util.PrecheckCheck + statusContext = common.PrecheckCheck case "sdg-svc": - statusContext = util.GenerateSDGCheck + statusContext = common.GenerateSDGCheck default: logger.Errorf("Unknown job type: %s", jobType) } @@ -356,8 +357,8 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar errCommentBody := fmt.Sprintf("An error occurred while processing your request, please review the following log for job id %s :\n\n```\n%s\n```", result, prErrors) params := util.PullRequestStatusParams{ - Status: util.CheckComplete, - Conclusion: util.CheckStatusFailure, + Status: common.CheckComplete, + Conclusion: common.CheckStatusFailure, CheckName: statusContext, CheckSummary: JobFailed, CheckDetails: errCommentBody, @@ -378,6 +379,9 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar if err != nil { logger.Errorf("Failed to update error message on PR for job %s error: %v", result, err) } + + // Enable redis keys deletion once we have solution for persisting the job history + // cleanupRedisKeys(logger, r, result) continue } @@ -405,8 +409,8 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar summaryMsg := fmt.Sprintf("Job ID: %s completed successfully. Check Details.", result) params := util.PullRequestStatusParams{ - Status: util.CheckComplete, - Conclusion: util.CheckStatusSuccess, + Status: common.CheckComplete, + Conclusion: common.CheckStatusSuccess, JobID: result, JobType: jobType, CheckName: statusContext, @@ -428,11 +432,40 @@ func receiveResults(ctx context.Context, redisHostPort string, logger *zap.Sugar if err != nil { logger.Errorf("Failed to post comment on pr %s/%s#%d: %v", params.RepoOwner, params.RepoName, params.PrNum, err) } + // Enable redis keys deletion once we have solution for persisting the job history + // cleanupRedisKeys(logger, r, result) } } } // buildRedisKey constructs a Redis key for job attributes. func buildRedisKey(jobID, keyType string) string { - return fmt.Sprintf("%s:%s:%s", handlers.RedisKeyJobs, jobID, keyType) + return fmt.Sprintf("%s:%s:%s", common.RedisKeyJobs, jobID, keyType) +} + +//lint:ignore U1000 +func cleanupRedisKeys(logger *zap.SugaredLogger, r *redis.Client, jobID string) { + matchKey := fmt.Sprintf("%s:%s:*", common.RedisKeyJobs, jobID) + var cursor uint64 = 0 + + for { + keys, nextCursor, err := r.Scan(cursor, matchKey, 0).Result() + if err != nil { + logger.Errorf("Error scanning keys matching to %s: %v", matchKey, err) + return + } + + for _, key := range keys { + err := r.Del(key).Err() + if err != nil { + logger.Warnf("Error deleting key %s: %v", key, err) + } + } + + cursor = nextCursor + if cursor == 0 { + break + } + } + logger.Infof("Deleted all keys matching to %s", matchKey) } diff --git a/gobot/common/constants.go b/gobot/common/constants.go new file mode 100644 index 00000000..782ff0aa --- /dev/null +++ b/gobot/common/constants.go @@ -0,0 +1,41 @@ +package common + +const ( + RepoName = "taxonomy" + + CheckComplete = "completed" + CheckQueued = "queued" + CheckInProgress = "in_progress" + CheckStatusSuccess = "success" + CheckStatusFailure = "failure" + CheckStatusError = "error" + CheckStatusPending = "pending" + + BotReadyStatus = "InstructLab Bot" + BotReadyStatusMsg = "InstructLab bot is ready to assist!!" + + PrecheckCheck = "Precheck Check" + GenerateLocalCheck = "Generate Local Check" + GenerateSDGCheck = "Generate SDG Check" + + PrecheckStatus = "Precheck Status" + GenerateLocalStatus = "Generate Local Status" + GenerateSDGStatus = "Generate SDG Status" + + InstructLabBotUrl = "https://github.com/instructlab/instructlab-bot" +) + +const ( + RedisKeyJobs = "jobs" + RedisKeyPRNumber = "pr_number" + RedisKeyPRSHA = "pr_sha" + RedisKeyAuthor = "author" + RedisKeyInstallationID = "installation_id" + RedisKeyRepoOwner = "repo_owner" + RedisKeyRepoName = "repo_name" + RedisKeyJobType = "job_type" + RedisKeyErrors = "errors" + RedisKeyRequestTime = "request_time" + RedisKeyDuration = "duration" + RedisKeyStatus = "status" +) diff --git a/gobot/handlers/issue_comment.go b/gobot/handlers/issue_comment.go index 1c92dd4c..81ce74ee 100644 --- a/gobot/handlers/issue_comment.go +++ b/gobot/handlers/issue_comment.go @@ -10,6 +10,7 @@ import ( "github.com/go-redis/redis/v8" "github.com/google/go-github/v60/github" + "github.com/instructlab/instructlab-bot/gobot/common" "github.com/instructlab/instructlab-bot/gobot/util" "github.com/palantir/go-githubapp/githubapp" "github.com/pkg/errors" @@ -24,21 +25,6 @@ const ( BotEnabled = "Bot is successfully enabled." ) -const ( - RedisKeyJobs = "jobs" - RedisKeyPRNumber = "pr_number" - RedisKeyPRSHA = "pr_sha" - RedisKeyAuthor = "author" - RedisKeyInstallationID = "installation_id" - RedisKeyRepoOwner = "repo_owner" - RedisKeyRepoName = "repo_name" - RedisKeyJobType = "job_type" - RedisKeyErrors = "errors" - RedisKeyRequestTime = "request_time" - RedisKeyDuration = "duration" - RedisKeyStatus = "status" -) - type PRCommentHandler struct { githubapp.ClientCreator Logger *zap.SugaredLogger @@ -71,6 +57,12 @@ func (h *PRCommentHandler) Handle(ctx context.Context, eventType, deliveryID str return errors.Wrap(err, "failed to parse issue comment event payload") } + if event.GetRepo().GetName() != common.RepoName { + h.Logger.Warnf("Received unexpected event %s from %s/%s repo. Skipping the event.", + eventType, event.GetOrganization().GetLogin(), event.GetRepo().GetName()) + return nil + } + if !event.GetIssue().IsPullRequest() { return nil } @@ -152,57 +144,57 @@ func (h *PRCommentHandler) queueGenerateJob(ctx context.Context, client *github. DB: 0, // use default DB }) - jobNumber, err := r.Incr(ctx, RedisKeyJobs).Result() + jobNumber, err := r.Incr(ctx, common.RedisKeyJobs).Result() if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyPRNumber, prComment.prNum) + err = setJobKey(r, jobNumber, common.RedisKeyPRNumber, prComment.prNum) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyPRSHA, prComment.prSha) + err = setJobKey(r, jobNumber, common.RedisKeyPRSHA, prComment.prSha) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyAuthor, prComment.author) + err = setJobKey(r, jobNumber, common.RedisKeyAuthor, prComment.author) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyInstallationID, prComment.installID) + err = setJobKey(r, jobNumber, common.RedisKeyInstallationID, prComment.installID) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyRepoOwner, prComment.repoOwner) + err = setJobKey(r, jobNumber, common.RedisKeyRepoOwner, prComment.repoOwner) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyRepoName, prComment.repoName) + err = setJobKey(r, jobNumber, common.RedisKeyRepoName, prComment.repoName) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyJobType, jobType) + err = setJobKey(r, jobNumber, common.RedisKeyJobType, jobType) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyErrors, "") + err = setJobKey(r, jobNumber, common.RedisKeyErrors, "") if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyStatus, util.CheckStatusPending) + err = setJobKey(r, jobNumber, common.RedisKeyStatus, common.CheckStatusPending) if err != nil { return err } - err = setJobKey(r, jobNumber, RedisKeyRequestTime, strconv.FormatInt(time.Now().Unix(), 10)) + err = setJobKey(r, jobNumber, common.RedisKeyRequestTime, strconv.FormatInt(time.Now().Unix(), 10)) if err != nil { return err } @@ -225,20 +217,20 @@ func (h *PRCommentHandler) queueGenerateJob(ctx context.Context, client *github. var statusName string switch jobType { case "generate": - checkName = util.GenerateLocalCheck - statusName = util.GenerateLocalStatus + checkName = common.GenerateLocalCheck + statusName = common.GenerateLocalStatus case "precheck": - checkName = util.PrecheckCheck - statusName = util.PrecheckStatus + checkName = common.PrecheckCheck + statusName = common.PrecheckStatus case "sdg-svc": - checkName = util.GenerateSDGCheck - statusName = util.GenerateSDGStatus + checkName = common.GenerateSDGCheck + statusName = common.GenerateSDGStatus default: h.Logger.Errorf("Unknown job type: %s", jobType) } params := util.PullRequestStatusParams{ - Status: util.CheckInProgress, + Status: common.CheckInProgress, CheckSummary: summaryMsg, CheckDetails: detailsMsg, Comment: commentMsg, @@ -340,9 +332,9 @@ func (h *PRCommentHandler) generateCommand(ctx context.Context, client *github.C prComment.repoOwner, prComment.repoName, prComment.prNum, prComment.author) params := util.PullRequestStatusParams{ - Status: util.CheckComplete, - Conclusion: util.CheckStatusFailure, - CheckName: util.GenerateLocalCheck, + Status: common.CheckComplete, + Conclusion: common.CheckStatusFailure, + CheckName: common.GenerateLocalCheck, RepoOwner: prComment.repoOwner, RepoName: prComment.repoName, PrNum: prComment.prNum, @@ -387,9 +379,9 @@ func (h *PRCommentHandler) precheckCommand(ctx context.Context, client *github.C prComment.repoOwner, prComment.repoName, prComment.prNum, prComment.author) params := util.PullRequestStatusParams{ - Status: util.CheckComplete, - Conclusion: util.CheckStatusFailure, - CheckName: util.PrecheckCheck, + Status: common.CheckComplete, + Conclusion: common.CheckStatusFailure, + CheckName: common.PrecheckCheck, RepoOwner: prComment.repoOwner, RepoName: prComment.repoName, PrNum: prComment.prNum, @@ -433,9 +425,9 @@ func (h *PRCommentHandler) sdgSvcCommand(ctx context.Context, client *github.Cli prComment.repoOwner, prComment.repoName, prComment.prNum, prComment.author) params := util.PullRequestStatusParams{ - Status: util.CheckComplete, - Conclusion: util.CheckStatusFailure, - CheckName: util.GenerateSDGCheck, + Status: common.CheckComplete, + Conclusion: common.CheckStatusFailure, + CheckName: common.GenerateSDGCheck, RepoOwner: prComment.repoOwner, RepoName: prComment.repoName, PrNum: prComment.prNum, diff --git a/gobot/handlers/pull_request.go b/gobot/handlers/pull_request.go index 2eb5a770..28b54c4d 100644 --- a/gobot/handlers/pull_request.go +++ b/gobot/handlers/pull_request.go @@ -5,6 +5,7 @@ import ( "encoding/json" "github.com/google/go-github/v60/github" + "github.com/instructlab/instructlab-bot/gobot/common" "github.com/instructlab/instructlab-bot/gobot/util" "github.com/palantir/go-githubapp/githubapp" "github.com/pkg/errors" @@ -29,6 +30,12 @@ func (h *PullRequestHandler) Handle(ctx context.Context, eventType, deliveryID s return errors.Wrap(err, "failed to parse issue comment event payload") } + if event.GetRepo().GetName() != common.RepoName { + h.Logger.Warnf("Received unexpected event %s from %s/%s repo. Skipping the event.", + eventType, event.GetOrganization().GetLogin(), event.GetRepo().GetName()) + return nil + } + if event.GetAction() != "labeled" { return nil } @@ -62,7 +69,7 @@ func (h *PullRequestHandler) Handle(ctx context.Context, eventType, deliveryID s } params := util.PullRequestStatusParams{ - CheckName: util.BotReadyStatus, + CheckName: common.BotReadyStatus, RepoOwner: repoOwner, RepoName: repoName, PrNum: prNum, @@ -70,7 +77,7 @@ func (h *PullRequestHandler) Handle(ctx context.Context, eventType, deliveryID s } // Check if the bot readiness status already exists - enable, err := util.StatusExist(ctx, client, params, util.BotReadyStatus) + enable, err := util.StatusExist(ctx, client, params, common.BotReadyStatus) if err != nil { h.Logger.Errorf("Failed to check bot enable status: %v", err) return nil diff --git a/gobot/util/pr_updates.go b/gobot/util/pr_updates.go index c579dd9a..d88e6187 100644 --- a/gobot/util/pr_updates.go +++ b/gobot/util/pr_updates.go @@ -8,29 +8,7 @@ import ( "time" "github.com/google/go-github/v60/github" -) - -const ( - CheckComplete = "completed" - CheckQueued = "queued" - CheckInProgress = "in_progress" - CheckStatusSuccess = "success" - CheckStatusFailure = "failure" - CheckStatusError = "error" - CheckStatusPending = "pending" - - BotReadyStatus = "InstructLab Bot" - BotReadyStatusMsg = "InstructLab bot is ready to assist!!" - - PrecheckCheck = "Precheck Check" - GenerateLocalCheck = "Generate Local Check" - GenerateSDGCheck = "Generate SDG Check" - - PrecheckStatus = "Precheck Status" - GenerateLocalStatus = "Generate Local Status" - GenerateSDGStatus = "Generate SDG Status" - - InstructLabBotUrl = "https://github.com/instructlab/instructlab-bot" + "github.com/instructlab/instructlab-bot/gobot/common" ) type PullRequestStatusParams struct { @@ -114,10 +92,10 @@ func PostPullRequestCheck(ctx context.Context, client *github.Client, params Pul 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 - Description: github.String(params.StatusDesc), // Status description - Context: github.String(params.CheckName), // Status context - TargetURL: github.String(InstructLabBotUrl), // Target URL to redirect + State: github.String(params.Conclusion), // Status state: success, failure, error, or pending + Description: github.String(params.StatusDesc), // Status description + Context: github.String(params.CheckName), // Status context + TargetURL: github.String(common.InstructLabBotUrl), // Target URL to redirect } _, _, err := client.Repositories.CreateStatus(ctx, params.RepoOwner, params.RepoName, params.PrSha, status) if err != nil { @@ -128,7 +106,7 @@ func PostPullRequestStatus(ctx context.Context, client *github.Client, params Pu func PostBotWelcomeMessage(ctx context.Context, client *github.Client, repoOwner string, repoName string, prNum int, prSha string, botName string, maintainers []string) error { params := PullRequestStatusParams{ - CheckName: BotReadyStatus, + CheckName: common.BotReadyStatus, RepoOwner: repoOwner, RepoName: repoName, PrNum: prNum, @@ -147,12 +125,12 @@ func PostBotWelcomeMessage(ctx context.Context, client *github.Client, repoOwner if len(maintainers) > 0 { detailsMsg += fmt.Sprintf("> [!NOTE] \n > **Currently only maintainers belongs to [%v] teams are allowed to run these commands**.\n", maintainers) } - params.Status = CheckComplete - params.Conclusion = CheckStatusSuccess - params.CheckSummary = BotReadyStatusMsg + params.Status = common.CheckComplete + params.Conclusion = common.CheckStatusSuccess + params.CheckSummary = common.BotReadyStatusMsg params.CheckDetails = detailsMsg params.Comment = detailsMsg - params.StatusDesc = BotReadyStatusMsg + params.StatusDesc = common.BotReadyStatusMsg err := PostPullRequestComment(ctx, client, params) if err != nil { diff --git a/gobot/util/utils.go b/gobot/util/utils.go index 5f635c96..affd7b22 100644 --- a/gobot/util/utils.go +++ b/gobot/util/utils.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/google/go-github/v60/github" + "github.com/instructlab/instructlab-bot/gobot/common" ) func CheckBotEnableStatus(ctx context.Context, client *github.Client, params PullRequestStatusParams) (bool, error) { @@ -16,7 +17,7 @@ func CheckBotEnableStatus(ctx context.Context, client *github.Client, params Pul if response.StatusCode == http.StatusOK { for _, status := range checkStatus.CheckRuns { if status.GetHeadSHA() == params.PrSha && - status.GetConclusion() == CheckStatusSuccess && + status.GetConclusion() == common.CheckStatusSuccess && status.GetName() == params.CheckName { return true, nil }