Skip to content

Commit

Permalink
Allow multiple kubechecks instances with the same token (#370)
Browse files Browse the repository at this point in the history
  • Loading branch information
MeNsaaH authored Feb 24, 2025
1 parent 8a8ebbe commit 7a476ba
Show file tree
Hide file tree
Showing 9 changed files with 30 additions and 18 deletions.
3 changes: 3 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ func init() {
newStringOpts().
withDefault("kubechecks again"))
stringSliceFlag(flags, "additional-apps-namespaces", "Additional namespaces other than the ArgoCDNamespace to monitor for applications.")
stringFlag(flags, "identifier", "Identifier for the kubechecks instance. Used to differentiate between multiple kubechecks instances.",
newStringOpts().
withDefault(""))

panicIfError(viper.BindPFlags(flags))
setupLogOutput()
Expand Down
1 change: 1 addition & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ The full list of supported environment variables is described below:
|`KUBECHECKS_GITHUB_APP_ID`|Github App ID.|`0`|
|`KUBECHECKS_GITHUB_INSTALLATION_ID`|Github Installation ID.|`0`|
|`KUBECHECKS_GITHUB_PRIVATE_KEY`|Github App Private Key.||
|`KUBECHECKS_IDENTIFIER`|Identifier for the kubechecks instance. Used to differentiate between multiple kubechecks instances.||
|`KUBECHECKS_KUBERNETES_CLUSTERID`|Kubernetes Cluster ID, must be specified if kubernetes-type is eks.||
|`KUBECHECKS_KUBERNETES_CONFIG`|Path to your kubernetes config file, used to monitor applications.||
|`KUBECHECKS_KUBERNETES_TYPE`|Kubernetes Type One of eks, or local.|`local`|
Expand Down
2 changes: 1 addition & 1 deletion localdev/kubechecks/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ configMap:
# KUBECHECKS_SCHEMAS_LOCATION: https://github.com/zapier/kubecheck-schemas.git
KUBECHECKS_TIDY_OUTDATED_COMMENTS_MODE: "delete"
KUBECHECKS_ENABLE_CONFTEST: "false"

KUBECHECKS_IDENTIFIER: "test"

deployment:
annotations:
Expand Down
1 change: 1 addition & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ type ServerConfig struct {
MaxQueueSize int64 `mapstructure:"max-queue-size"`
MaxConcurrenctChecks int `mapstructure:"max-concurrenct-checks"`
ReplanCommentMessage string `mapstructure:"replan-comment-msg"`
Identifier string `mapstructure:"identifier"`
}

func New() (ServerConfig, error) {
Expand Down
11 changes: 8 additions & 3 deletions pkg/events/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,10 @@ func (ce *CheckEvent) Process(ctx context.Context) error {

if len(ce.affectedItems.Applications) <= 0 && len(ce.affectedItems.ApplicationSets) <= 0 {
ce.logger.Info().Msg("No affected apps or appsets, skipping")
if _, err := ce.ctr.VcsClient.PostMessage(ctx, ce.pullRequest, "No changes"); err != nil {
if _, err := ce.ctr.VcsClient.PostMessage(ctx, ce.pullRequest, fmt.Sprintf(`
## Kubechecks %s Report
No changes
`, ce.ctr.Config.Identifier)); err != nil {
return errors.Wrap(err, "failed to post changes")
}
return nil
Expand Down Expand Up @@ -325,7 +328,7 @@ func (ce *CheckEvent) Process(ctx context.Context) error {

ce.logger.Info().Msg("Finished")

comment := ce.vcsNote.BuildComment(ctx, start, ce.pullRequest.SHA, ce.ctr.Config.LabelFilter, ce.ctr.Config.ShowDebugInfo)
comment := ce.vcsNote.BuildComment(ctx, start, ce.pullRequest.SHA, ce.ctr.Config.LabelFilter, ce.ctr.Config.ShowDebugInfo, ce.ctr.Config.Identifier)

if err = ce.ctr.VcsClient.UpdateMessage(ctx, ce.vcsNote, comment); err != nil {
return errors.Wrap(err, "failed to push comment")
Expand Down Expand Up @@ -403,5 +406,7 @@ func (ce *CheckEvent) createNote(ctx context.Context) (*msg.Message, error) {

ce.logger.Info().Msgf("Creating note")

return ce.ctr.VcsClient.PostMessage(ctx, ce.pullRequest, ":hourglass: kubechecks running ... ")
return ce.ctr.VcsClient.PostMessage(ctx, ce.pullRequest, fmt.Sprintf(`
## Kubechecks %s Report
:hourglass: kubechecks running ... `, ce.ctr.Config.Identifier))
}
4 changes: 2 additions & 2 deletions pkg/msg/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,14 @@ func (m *Message) buildFooter(start time.Time, commitSHA, labelFilter string, sh
}

// BuildComment iterates the map of all apps in this message, building a final comment from their current state
func (m *Message) BuildComment(ctx context.Context, start time.Time, commitSHA, labelFilter string, showDebugInfo bool) string {
func (m *Message) BuildComment(ctx context.Context, start time.Time, commitSHA, labelFilter string, showDebugInfo bool, identifier string) string {
_, span := tracer.Start(ctx, "buildComment")
defer span.End()

names := getSortedKeys(m.apps)

var sb strings.Builder
sb.WriteString("# Kubechecks Report\n")
sb.WriteString(fmt.Sprintf("# Kubechecks %s Report\n", identifier))

updateWritten := false
for _, appName := range names {
Expand Down
10 changes: 5 additions & 5 deletions pkg/msg/message_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ func TestBuildComment(t *testing.T) {
}
m := NewMessage("message", 1, 2, fakeEmojiable{":test:"})
m.apps = appResults
comment := m.BuildComment(context.TODO(), time.Now(), "commit-sha", "label-filter", false)
assert.Equal(t, `# Kubechecks Report
comment := m.BuildComment(context.TODO(), time.Now(), "commit-sha", "label-filter", false, "test-identifier")
assert.Equal(t, `# Kubechecks test-identifier Report
<details>
<summary>
Expand Down Expand Up @@ -79,8 +79,8 @@ func TestBuildComment_SkipUnchanged(t *testing.T) {

m := NewMessage("message", 1, 2, fakeEmojiable{":test:"})
m.apps = appResults
comment := m.BuildComment(context.TODO(), time.Now(), "commit-sha", "label-filter", false)
assert.Equal(t, `# Kubechecks Report
comment := m.BuildComment(context.TODO(), time.Now(), "commit-sha", "label-filter", false, "test-identifier")
assert.Equal(t, `# Kubechecks test-identifier Report
<details>
<summary>
Expand Down Expand Up @@ -183,7 +183,7 @@ func TestMultipleItemsWithNewlines(t *testing.T) {
Summary: "summary-2",
Details: "detail-2",
})
result := message.BuildComment(context.TODO(), time.Now(), "commit-sha", "label-filter", false)
result := message.BuildComment(context.TODO(), time.Now(), "commit-sha", "label-filter", false, "test-identifier")

// header rows need double newlines before and after
index := 0
Expand Down
4 changes: 2 additions & 2 deletions pkg/vcs/github_client/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (c *Client) pruneOldComments(ctx context.Context, pr vcs.PullRequest, comme
log.Debug().Msgf("Pruning messages from PR %d in repo %s", pr.CheckID, pr.FullName)

for _, comment := range comments {
if strings.EqualFold(comment.GetUser().GetLogin(), c.username) {
if strings.EqualFold(comment.GetUser().GetLogin(), c.username) || strings.Contains(*comment.Body, fmt.Sprintf("Kubechecks %s Report", c.cfg.Identifier)) {
_, err := c.googleClient.Issues.DeleteComment(ctx, pr.Owner, pr.Name, *comment.ID)
if err != nil {
return fmt.Errorf("failed to delete comment: %w", err)
Expand All @@ -104,7 +104,7 @@ func (c *Client) hideOutdatedMessages(ctx context.Context, pr vcs.PullRequest, c
log.Debug().Msgf("Hiding kubecheck messages in PR %d in repo %s", pr.CheckID, pr.FullName)

for _, comment := range comments {
if strings.EqualFold(comment.GetUser().GetLogin(), c.username) {
if strings.EqualFold(comment.GetUser().GetLogin(), c.username) || strings.Contains(*comment.Body, fmt.Sprintf("Kubechecks %s Report", c.cfg.Identifier)) {
// Github API does not expose minimizeComment API. IT's only available from the GraphQL API
// https://docs.github.com/en/graphql/reference/mutations#minimizecomment
var m struct {
Expand Down
12 changes: 7 additions & 5 deletions pkg/vcs/gitlab_client/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,26 @@ func (c *Client) hideOutdatedMessages(ctx context.Context, projectName string, m

log.Debug().Msg("hiding outdated comments")

// loop through notes and collapse any that are from the current user
// loop through notes and collapse any that are from the current user and current identifier
for _, note := range notes {

// Do not try to hide the note if
// note user is not the gitlabTokenUser
// note is an internal system note such as notes on commit messages
// note is already hidden
if note.Author.Username != c.username || note.System || strings.Contains(note.Body, "<summary><i>OUTDATED: Kubechecks Report</i></summary>") {
if note.Author.Username != c.username || note.System ||
strings.Contains(note.Body, fmt.Sprintf("<summary><i>OUTDATED: Kubechecks %s Report</i></summary>", c.cfg.Identifier)) ||
!strings.Contains(note.Body, fmt.Sprintf("Kubechecks %s Report", c.cfg.Identifier)) {
continue
}

newBody := fmt.Sprintf(`
<details>
<summary><i>OUTDATED: Kubechecks Report</i></summary>
<summary><i>OUTDATED: Kubechecks %s Report</i></summary>
%s
</details>
`, note.Body)
`, c.cfg.Identifier, note.Body)

if len(newBody) > MaxCommentLength {
log.Warn().Int("original_length", len(newBody)).Msg("trimming the comment size")
Expand Down Expand Up @@ -114,7 +116,7 @@ func (c *Client) pruneOldComments(ctx context.Context, projectName string, mrID
log.Debug().Msg("deleting outdated comments")

for _, note := range notes {
if note.Author.Username == c.username {
if note.Author.Username == c.username && strings.Contains(note.Body, fmt.Sprintf("Kubechecks %s Report", c.cfg.Identifier)) {
log.Debug().Int("mr", mrID).Int("note", note.ID).Msg("deleting old comment")
_, err := c.c.Notes.DeleteMergeRequestNote(projectName, mrID, note.ID)
if err != nil {
Expand Down

0 comments on commit 7a476ba

Please sign in to comment.