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
CODE-2402
Yogesh Chauhan 2024-09-09 17:49:44 +00:00 committed by Harness
parent 905d027cc3
commit 0af264d09f
20 changed files with 336 additions and 73 deletions

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

@ -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
}

View File

@ -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,
)
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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))
})
}

View File

@ -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",

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

2
go.mod
View File

@ -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

6
go.sum
View File

@ -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=

View File

@ -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"`
}