From 0af264d09f7f65b50b53a7a917667e936ee0f300 Mon Sep 17 00:00:00 2001 From: Yogesh Chauhan Date: Mon, 9 Sep 2024 17:49:44 +0000 Subject: [PATCH] feat: [ML-338]: APIs for Harness Intelligence (#2667) * Return empty summary/branch for now * Fix Lint Issues * feat: [ML-288]: API skeletons for Harness Intelligence * fix ai pipelines (#2659) * fix ai pipelines * Update pipeline name (#2658) * Update pipeline name * fix: [ML-288]: update remediation prompt and suggestions (#2652) * fix: [ML-288]: update remediation prompt and suggestions * fix: [ML-288]: update url for artifact registry (#2651) * fix: [ML-288]: update url for artifact registry * Add snippet to mark code as written by Harness Intelligence (#2628) * Add snippet to mark code as written by Harness Intelligence * Add snippet to mark code as written by Harness Intelligence (#2626) * Add snippet to mark code as written by Harness Intelligence * feat: [ML-288]: link to harness artifact registry (#2619) * some linting fixes * feat: [ML-288]: link to harness artifact registry * feat: [ML-286]: updating pipeline suggestions (#2620) * updating suggestions * feat: [ML-286]: updating pipeline suggestions * feat: [ML-288]: adding slackbot (#2603) * updating slack responses * prevent responding to any bot messages * feat: [ML-288]: adding slackbot * throw error for commit * commit stubbed * feat: [ML-286]: moving stubbed response earlier in execution (#2602) * feat: [ML-286]: moving stubbed response earlier in execution * feat: [ML-286]: adding stubbed response for analyze execution (#2600) * updating branch name * adding updated-main for analyse-execution endpoint * feat: [ML-286]: adding stubbed response for analyze execution * Update AnalyseExecutionOutput to contain multi file diff (#2592) * Create branch and commit changes on analyse * Simplify AnalyseExecutionOutput to contain only high level summary and branch * Update AnalyseExecutionOutput to contain multi file diff * updating endpoints for unscripted demo (#2594) * cleaning up code, adding suggested pipeline response * updating suggestions api * updating endpoints for unscripted demo * Stub out generate pipeline yaml --- .../controller/aiagent/analyse_execution.go | 81 ++++++++++++++++++- app/api/controller/aiagent/controller.go | 12 +++ .../controller/aiagent/generate_pipeline.go | 13 ++- app/api/controller/aiagent/slackbot.go | 48 +++++++++++ .../controller/aiagent/suggest_pipelines.go | 1 + app/api/controller/aiagent/update_pipeline.go | 17 +++- app/api/controller/aiagent/wire.go | 9 +++ app/api/controller/execution/analyse.go | 59 -------------- app/api/handler/aiagent/generate_pipeline.go | 4 +- app/api/handler/aiagent/slackbot.go | 68 ++++++++++++++++ app/api/handler/aiagent/update_pipeline.go | 4 +- app/router/api.go | 1 + app/services/aiagent/aiagent.go | 1 + app/services/messaging/slack.go | 39 +++++++++ app/services/messaging/wire.go | 31 +++++++ cmd/gitness/wire.go | 2 + cmd/gitness/wire_gen.go | 7 +- go.mod | 2 + go.sum | 6 ++ types/execution_analysis.go | 4 +- 20 files changed, 336 insertions(+), 73 deletions(-) create mode 100644 app/api/controller/aiagent/slackbot.go delete mode 100644 app/api/controller/execution/analyse.go create mode 100644 app/api/handler/aiagent/slackbot.go create mode 100644 app/services/messaging/slack.go create mode 100644 app/services/messaging/wire.go diff --git a/app/api/controller/aiagent/analyse_execution.go b/app/api/controller/aiagent/analyse_execution.go index f0accdaf9..6593b0981 100644 --- a/app/api/controller/aiagent/analyse_execution.go +++ b/app/api/controller/aiagent/analyse_execution.go @@ -17,10 +17,15 @@ package aiagent import ( "context" "fmt" + "time" apiauth "github.com/harness/gitness/app/api/auth" + "github.com/harness/gitness/app/api/controller" "github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/auth" + "github.com/harness/gitness/app/bootstrap" + "github.com/harness/gitness/git" + "github.com/harness/gitness/git/sha" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" ) @@ -36,6 +41,7 @@ func (c *Controller) GetAnalysis( if err != nil { return nil, usererror.BadRequestf("failed to find repo %s", repoRef) } + err = apiauth.CheckPipeline(ctx, c.authorizer, session, repo.Path, pipelineIdentifier, enum.PermissionPipelineView) if err != nil { return nil, usererror.Forbidden(fmt.Sprintf("not allowed to view pipeline %s", pipelineIdentifier)) @@ -55,5 +61,78 @@ func (c *Controller) GetAnalysis( return nil, usererror.BadRequestf("execution %d is not a failed execution", executionNum) } - return &types.AnalyseExecutionOutput{Yaml: "a:1"}, nil + // ToDo: put actual values + payload := &CommitPayload{} + branch := "" + + _, err = c.commit(ctx, session, repo, payload) + if err != nil { + return &types.AnalyseExecutionOutput{}, err + } + + return &types.AnalyseExecutionOutput{Branch: branch, Summary: ""}, nil +} + +type CommitPayload struct { + Title string + Message string + Branch string + NewBranch string + Files []*Files +} + +type Files struct { + action git.FileAction + path string + content string + SHA sha.SHA +} + +func (c *Controller) commit(ctx context.Context, + session *auth.Session, + repo *types.Repository, + payload *CommitPayload) (types.CommitFilesResponse, error) { + files := payload.Files + actions := make([]git.CommitFileAction, len(files)) + for i, file := range files { + rawPayload := []byte(file.content) + actions[i] = git.CommitFileAction{ + Action: file.action, + Path: file.path, + Payload: rawPayload, + SHA: file.SHA, + } + } + + writeParams, err := controller.CreateRPCInternalWriteParams(ctx, c.urlProvider, session, repo) + if err != nil { + return types.CommitFilesResponse{}, fmt.Errorf("failed to create RPC write params: %w", err) + } + now := time.Now() + commit, err := c.git.CommitFiles(ctx, &git.CommitFilesParams{ + WriteParams: writeParams, + Title: payload.Title, + Message: payload.Message, + Branch: payload.Branch, + NewBranch: payload.NewBranch, + Actions: actions, + Committer: identityFromPrincipal(bootstrap.NewSystemServiceSession().Principal), + CommitterDate: &now, + Author: identityFromPrincipal(session.Principal), + AuthorDate: &now, + }) + if err != nil { + return types.CommitFilesResponse{}, err + } + + return types.CommitFilesResponse{ + CommitID: commit.CommitID.String(), + }, nil +} + +func identityFromPrincipal(p types.Principal) *git.Identity { + return &git.Identity{ + Name: p.DisplayName, + Email: p.Email, + } } diff --git a/app/api/controller/aiagent/controller.go b/app/api/controller/aiagent/controller.go index 0af06a124..5ffbc7e33 100644 --- a/app/api/controller/aiagent/controller.go +++ b/app/api/controller/aiagent/controller.go @@ -17,7 +17,10 @@ package aiagent import ( "github.com/harness/gitness/app/auth/authz" "github.com/harness/gitness/app/services/aiagent" + "github.com/harness/gitness/app/services/messaging" "github.com/harness/gitness/app/store" + "github.com/harness/gitness/app/url" + "github.com/harness/gitness/git" ) type Controller struct { @@ -26,6 +29,9 @@ type Controller struct { repoStore store.RepoStore pipelineStore store.PipelineStore executionStore store.ExecutionStore + git git.Interface + urlProvider url.Provider + slackbot *messaging.Slack } func NewController( @@ -34,6 +40,9 @@ func NewController( repoStore store.RepoStore, pipelineStore store.PipelineStore, executionStore store.ExecutionStore, + git git.Interface, + urlProvider url.Provider, + slackbot *messaging.Slack, ) *Controller { return &Controller{ authorizer: authorizer, @@ -41,5 +50,8 @@ func NewController( repoStore: repoStore, pipelineStore: pipelineStore, executionStore: executionStore, + git: git, + urlProvider: urlProvider, + slackbot: slackbot, } } diff --git a/app/api/controller/aiagent/generate_pipeline.go b/app/api/controller/aiagent/generate_pipeline.go index 5a9a124f0..dc3b32893 100644 --- a/app/api/controller/aiagent/generate_pipeline.go +++ b/app/api/controller/aiagent/generate_pipeline.go @@ -26,8 +26,13 @@ type GeneratePipelineInput struct { RepoRef string `json:"repo_ref"` } +type PipelineData struct { + YamlPipeline string `json:"yaml_pipeline"` +} + type GeneratePipelineOutput struct { - Yaml string `json:"yaml"` + Status string `json:"status"` + Data PipelineData `json:"data"` } func (c *Controller) GeneratePipeline( @@ -38,11 +43,15 @@ func (c *Controller) GeneratePipeline( Prompt: in.Prompt, RepoRef: in.RepoRef, } + output, err := c.pipeline.Generate(ctx, generateRequest) if err != nil { return nil, fmt.Errorf("generate pipeline: %w", err) } return &GeneratePipelineOutput{ - Yaml: output.YAML, + Status: "SUCCESS", + Data: PipelineData{ + YamlPipeline: output.YAML, + }, }, nil } diff --git a/app/api/controller/aiagent/slackbot.go b/app/api/controller/aiagent/slackbot.go new file mode 100644 index 000000000..dac70251d --- /dev/null +++ b/app/api/controller/aiagent/slackbot.go @@ -0,0 +1,48 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aiagent + +import ( + "context" + "fmt" + + "github.com/slack-go/slack/slackevents" +) + +type SlackbotOutput struct { + Success bool +} + +func (c *Controller) HandleEvent( + _ context.Context, + eventsAPIEvent slackevents.EventsAPIEvent) (*SlackbotOutput, error) { + if eventsAPIEvent.Type == slackevents.CallbackEvent { + success, err := c.HandleCallbackEvent(eventsAPIEvent.InnerEvent) + if err != nil { + return nil, err + } + return &SlackbotOutput{Success: success}, nil + } + return nil, fmt.Errorf("unknown event type: %s", eventsAPIEvent.Type) +} + +func (c *Controller) HandleCallbackEvent(innerEvent slackevents.EventsAPIInnerEvent) (bool, error) { + switch innerEvent.Data.(type) { + case *slackevents.AppMentionEvent: + default: + // no action needed for unhandled event types + } + return true, nil +} diff --git a/app/api/controller/aiagent/suggest_pipelines.go b/app/api/controller/aiagent/suggest_pipelines.go index 9598fcd53..b30161a0c 100644 --- a/app/api/controller/aiagent/suggest_pipelines.go +++ b/app/api/controller/aiagent/suggest_pipelines.go @@ -34,6 +34,7 @@ func (c *Controller) SuggestPipeline( RepoRef: in.RepoRef, Pipeline: in.Pipeline, } + output, err := c.pipeline.Suggest(ctx, suggestionRequest) if err != nil { return nil, fmt.Errorf("suggest pipeline: %w", err) diff --git a/app/api/controller/aiagent/update_pipeline.go b/app/api/controller/aiagent/update_pipeline.go index ae986a4af..f8a849101 100644 --- a/app/api/controller/aiagent/update_pipeline.go +++ b/app/api/controller/aiagent/update_pipeline.go @@ -21,6 +21,11 @@ import ( "github.com/harness/gitness/types" ) +type UpdatePipelineOutput struct { + Status string `json:"status"` + Data PipelineData `json:"data"` +} + type UpdatePipelineInput struct { Prompt string `json:"prompt"` RepoRef string `json:"repo_ref"` @@ -30,15 +35,21 @@ type UpdatePipelineInput struct { func (c *Controller) UpdatePipeline( ctx context.Context, in *UpdatePipelineInput, -) (string, error) { +) (*UpdatePipelineOutput, error) { generateRequest := &types.PipelineUpdateRequest{ Prompt: in.Prompt, RepoRef: in.RepoRef, Pipeline: in.Pipeline, } + output, err := c.pipeline.Update(ctx, generateRequest) if err != nil { - return "", fmt.Errorf("update pipeline: %w", err) + return nil, fmt.Errorf("update pipeline: %w", err) } - return output.YAML, nil + return &UpdatePipelineOutput{ + Status: "SUCCESS", + Data: PipelineData{ + YamlPipeline: output.YAML, + }, + }, nil } diff --git a/app/api/controller/aiagent/wire.go b/app/api/controller/aiagent/wire.go index dafa74fcd..9a3c72ff2 100644 --- a/app/api/controller/aiagent/wire.go +++ b/app/api/controller/aiagent/wire.go @@ -17,7 +17,10 @@ package aiagent import ( "github.com/harness/gitness/app/auth/authz" "github.com/harness/gitness/app/services/aiagent" + "github.com/harness/gitness/app/services/messaging" "github.com/harness/gitness/app/store" + "github.com/harness/gitness/app/url" + "github.com/harness/gitness/git" "github.com/google/wire" ) @@ -33,6 +36,9 @@ func ProvideController( repoStore store.RepoStore, pipelineStore store.PipelineStore, executionStore store.ExecutionStore, + git git.Interface, + urlProvider url.Provider, + slackbot *messaging.Slack, ) *Controller { return NewController( authorizer, @@ -40,5 +46,8 @@ func ProvideController( repoStore, pipelineStore, executionStore, + git, + urlProvider, + slackbot, ) } diff --git a/app/api/controller/execution/analyse.go b/app/api/controller/execution/analyse.go deleted file mode 100644 index 78e3da765..000000000 --- a/app/api/controller/execution/analyse.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2023 Harness, Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package execution - -import ( - "context" - "fmt" - - apiauth "github.com/harness/gitness/app/api/auth" - "github.com/harness/gitness/app/api/usererror" - "github.com/harness/gitness/app/auth" - "github.com/harness/gitness/types" - "github.com/harness/gitness/types/enum" -) - -func (c *Controller) GetAnalysis( - ctx context.Context, - session *auth.Session, - repoRef string, - pipelineIdentifier string, - executionNum int64, -) (*types.AnalyseExecutionOutput, error) { - repo, err := c.repoStore.FindByRef(ctx, repoRef) - if err != nil { - return nil, usererror.BadRequestf("failed to find repo %s", repoRef) - } - err = apiauth.CheckPipeline(ctx, c.authorizer, session, repo.Path, pipelineIdentifier, enum.PermissionPipelineView) - if err != nil { - return nil, usererror.Forbidden(fmt.Sprintf("not allowed to view pipeline %s", pipelineIdentifier)) - } - - pipeline, err := c.pipelineStore.FindByIdentifier(ctx, repo.ID, pipelineIdentifier) - if err != nil { - return nil, usererror.BadRequestf("failed to find pipeline: %s", pipelineIdentifier) - } - - execution, err := c.executionStore.FindByNumber(ctx, pipeline.ID, executionNum) - if err != nil { - return nil, usererror.BadRequestf("failed to find execution %d", executionNum) - } - - if execution.Status == enum.CIStatusSuccess { - return nil, usererror.BadRequestf("execution %d is not a failed execution", executionNum) - } - - return &types.AnalyseExecutionOutput{Yaml: "a:1"}, nil -} diff --git a/app/api/handler/aiagent/generate_pipeline.go b/app/api/handler/aiagent/generate_pipeline.go index f2d180f1a..79e2bb9db 100644 --- a/app/api/handler/aiagent/generate_pipeline.go +++ b/app/api/handler/aiagent/generate_pipeline.go @@ -39,8 +39,6 @@ func HandleGeneratePipeline(aiagentCtrl *aiagent.Controller) http.HandlerFunc { return } - w.Header().Set("Content-Type", "text/yaml; charset=utf-8") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(pipeline.Yaml)) + render.JSON(w, http.StatusOK, pipeline) } } diff --git a/app/api/handler/aiagent/slackbot.go b/app/api/handler/aiagent/slackbot.go new file mode 100644 index 000000000..d50a86d37 --- /dev/null +++ b/app/api/handler/aiagent/slackbot.go @@ -0,0 +1,68 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aiagent + +import ( + "encoding/json" + "io" + "net/http" + + "github.com/harness/gitness/app/api/controller/aiagent" + "github.com/harness/gitness/app/api/render" + + "github.com/slack-go/slack/slackevents" +) + +func HandleSlackMessage(aiagentCtrl *aiagent.Controller) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "Failed to read request body", http.StatusInternalServerError) + return + } + + eventsAPIEvent, err := slackevents.ParseEvent( + body, + // Use slackevents.OptionVerifyToken(&slackevents.TokenComparator{VerificationToken: "your_verification_token"}) + // to verify token + slackevents.OptionNoVerifyToken(), + ) + if err != nil { + http.Error(w, "Failed to parse slack event", http.StatusInternalServerError) + return + } + + if eventsAPIEvent.Type == slackevents.URLVerification { + var r *slackevents.ChallengeResponse + if err := json.Unmarshal(body, &r); err != nil { + http.Error(w, "Failed to parse challenge request", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "text/plain") + _, _ = w.Write([]byte(r.Challenge)) + return + } + + slackbotOutput, err := aiagentCtrl.HandleEvent(ctx, eventsAPIEvent) + if err != nil { + render.TranslatedUserError(ctx, w, err) + return + } + + render.JSON(w, http.StatusOK, slackbotOutput) + } +} diff --git a/app/api/handler/aiagent/update_pipeline.go b/app/api/handler/aiagent/update_pipeline.go index af91f01de..6223bac38 100644 --- a/app/api/handler/aiagent/update_pipeline.go +++ b/app/api/handler/aiagent/update_pipeline.go @@ -40,8 +40,6 @@ func HandleUpdatePipeline(aiagentCtrl *aiagent.Controller) http.HandlerFunc { return } - w.Header().Set("Content-Type", "text/yaml; charset=utf-8") - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte(pipeline)) + render.JSON(w, http.StatusOK, pipeline) } } diff --git a/app/router/api.go b/app/router/api.go index 08dbad61b..be2fe448d 100644 --- a/app/router/api.go +++ b/app/router/api.go @@ -528,6 +528,7 @@ func setupAiAgent(r chi.Router, aiagentCtrl *aiagent.Controller, capabilitiesCtr r.Post("/capabilities", handlercapabilities.HandleRunCapabilities(capabilitiesCtrl)) r.Post("/suggest-pipeline", handleraiagent.HandleSuggestPipelines(aiagentCtrl)) r.Post("/analyse-execution", handleraiagent.HandleAnalyse(aiagentCtrl)) + r.Post("/slackbot", handleraiagent.HandleSlackMessage(aiagentCtrl)) }) } diff --git a/app/services/aiagent/aiagent.go b/app/services/aiagent/aiagent.go index 5304cfb77..7063e1315 100644 --- a/app/services/aiagent/aiagent.go +++ b/app/services/aiagent/aiagent.go @@ -186,6 +186,7 @@ func (s *HarnessIntelligence) Suggest( _ context.Context, _ *types.PipelineSuggestionsRequest) (*types.PipelineSuggestionsResponse, error) { return &types.PipelineSuggestionsResponse{ + // TODO Update to be V0 Yaml Suggestions: []types.Suggestion{ { ID: "add-testing-stage", diff --git a/app/services/messaging/slack.go b/app/services/messaging/slack.go new file mode 100644 index 000000000..e3947559d --- /dev/null +++ b/app/services/messaging/slack.go @@ -0,0 +1,39 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package messaging + +import ( + "os" + + "github.com/slack-go/slack" +) + +const ( + SlackBotToken = "HARNESS_INTELLIGENCE_SLACK_BOT_TOKEN" +) + +type Slack struct { + Client *slack.Client + SlackBotID string +} + +func NewSlack() *Slack { + token := os.Getenv(SlackBotToken) + api := slack.New(token) + + return &Slack{ + Client: api, + } +} diff --git a/app/services/messaging/wire.go b/app/services/messaging/wire.go new file mode 100644 index 000000000..b72b8c3b7 --- /dev/null +++ b/app/services/messaging/wire.go @@ -0,0 +1,31 @@ +// Copyright 2023 Harness, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package messaging + +import ( + "github.com/harness/gitness/app/store" + "github.com/harness/gitness/git" + + "github.com/google/wire" +) + +var WireSet = wire.NewSet( + ProvideSlack, +) + +func ProvideSlack(_ store.RepoStore, _ git.Interface) (*Slack, error) { + slack := NewSlack() + return slack, nil +} diff --git a/cmd/gitness/wire.go b/cmd/gitness/wire.go index 2446f791a..7e717b58d 100644 --- a/cmd/gitness/wire.go +++ b/cmd/gitness/wire.go @@ -93,6 +93,7 @@ import ( "github.com/harness/gitness/app/services/keywordsearch" svclabel "github.com/harness/gitness/app/services/label" locker "github.com/harness/gitness/app/services/locker" + messagingservice "github.com/harness/gitness/app/services/messaging" "github.com/harness/gitness/app/services/metric" migrateservice "github.com/harness/gitness/app/services/migrate" "github.com/harness/gitness/app/services/notification" @@ -268,6 +269,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e secretservice.WireSet, containerGit.WireSet, containerUser.WireSet, + messagingservice.WireSet, ) return &cliserver.System{}, nil } diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index 508859590..2c897fc3d 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -84,6 +84,7 @@ import ( "github.com/harness/gitness/app/services/keywordsearch" "github.com/harness/gitness/app/services/label" "github.com/harness/gitness/app/services/locker" + "github.com/harness/gitness/app/services/messaging" "github.com/harness/gitness/app/services/metric" "github.com/harness/gitness/app/services/migrate" "github.com/harness/gitness/app/services/notification" @@ -413,7 +414,11 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro if err != nil { return nil, err } - aiagentController := aiagent2.ProvideController(authorizer, harnessIntelligence, repoStore, pipelineStore, executionStore) + slack, err := messaging.ProvideSlack(repoStore, gitInterface) + if err != nil { + return nil, err + } + aiagentController := aiagent2.ProvideController(authorizer, harnessIntelligence, repoStore, pipelineStore, executionStore, gitInterface, provider, slack) openapiService := openapi.ProvideOpenAPIService() storageDriver, err := api2.BlobStorageProvider(config) if err != nil { diff --git a/go.mod b/go.mod index 8977cb618..9d902910a 100644 --- a/go.mod +++ b/go.mod @@ -64,6 +64,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/sercand/kuberesolver/v5 v5.1.1 github.com/sirupsen/logrus v1.9.3 + github.com/slack-go/slack v0.14.0 github.com/stretchr/testify v1.9.0 github.com/swaggest/openapi-go v0.2.23 github.com/swaggest/swgui v1.8.1 @@ -121,6 +122,7 @@ require ( github.com/google/s2a-go v0.1.8 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect github.com/h2non/filetype v1.1.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/invopop/yaml v0.2.0 // indirect diff --git a/go.sum b/go.sum index 398899cc0..6a39abbbf 100644 --- a/go.sum +++ b/go.sum @@ -256,6 +256,7 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -303,6 +304,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -339,6 +341,8 @@ github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotidy/ptr v1.4.0 h1:7++suUs+HNHMnyz6/AW3SE+4EnBhupPSQTSI7QNijVc= github.com/gotidy/ptr v1.4.0/go.mod h1:MjRBG6/IETiiZGWI8LrRtISXEji+8b/jigmj2q0mEyM= github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -697,6 +701,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/slack-go/slack v0.14.0 h1:6c0UTfbRnvRssZUsZ2qe0Iu07VAMPjRqOa6oX8ewF4k= +github.com/slack-go/slack v0.14.0/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= diff --git a/types/execution_analysis.go b/types/execution_analysis.go index 51254671d..f4a71372e 100644 --- a/types/execution_analysis.go +++ b/types/execution_analysis.go @@ -21,5 +21,7 @@ type AnalyseExecutionInput struct { } type AnalyseExecutionOutput struct { - Yaml string `json:"yaml"` + // high level summary of the changes + Branch string `json:"branch"` + Summary string `json:"summary"` }