mirror of https://github.com/harness/drone.git
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 yamlCODE-2402
parent
905d027cc3
commit
0af264d09f
|
@ -17,10 +17,15 @@ package aiagent
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
apiauth "github.com/harness/gitness/app/api/auth"
|
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/api/usererror"
|
||||||
"github.com/harness/gitness/app/auth"
|
"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"
|
||||||
"github.com/harness/gitness/types/enum"
|
"github.com/harness/gitness/types/enum"
|
||||||
)
|
)
|
||||||
|
@ -36,6 +41,7 @@ func (c *Controller) GetAnalysis(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, usererror.BadRequestf("failed to find repo %s", repoRef)
|
return nil, usererror.BadRequestf("failed to find repo %s", repoRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = apiauth.CheckPipeline(ctx, c.authorizer, session, repo.Path, pipelineIdentifier, enum.PermissionPipelineView)
|
err = apiauth.CheckPipeline(ctx, c.authorizer, session, repo.Path, pipelineIdentifier, enum.PermissionPipelineView)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, usererror.Forbidden(fmt.Sprintf("not allowed to view pipeline %s", pipelineIdentifier))
|
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 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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ package aiagent
|
||||||
import (
|
import (
|
||||||
"github.com/harness/gitness/app/auth/authz"
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
"github.com/harness/gitness/app/services/aiagent"
|
"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/store"
|
||||||
|
"github.com/harness/gitness/app/url"
|
||||||
|
"github.com/harness/gitness/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
|
@ -26,6 +29,9 @@ type Controller struct {
|
||||||
repoStore store.RepoStore
|
repoStore store.RepoStore
|
||||||
pipelineStore store.PipelineStore
|
pipelineStore store.PipelineStore
|
||||||
executionStore store.ExecutionStore
|
executionStore store.ExecutionStore
|
||||||
|
git git.Interface
|
||||||
|
urlProvider url.Provider
|
||||||
|
slackbot *messaging.Slack
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewController(
|
func NewController(
|
||||||
|
@ -34,6 +40,9 @@ func NewController(
|
||||||
repoStore store.RepoStore,
|
repoStore store.RepoStore,
|
||||||
pipelineStore store.PipelineStore,
|
pipelineStore store.PipelineStore,
|
||||||
executionStore store.ExecutionStore,
|
executionStore store.ExecutionStore,
|
||||||
|
git git.Interface,
|
||||||
|
urlProvider url.Provider,
|
||||||
|
slackbot *messaging.Slack,
|
||||||
) *Controller {
|
) *Controller {
|
||||||
return &Controller{
|
return &Controller{
|
||||||
authorizer: authorizer,
|
authorizer: authorizer,
|
||||||
|
@ -41,5 +50,8 @@ func NewController(
|
||||||
repoStore: repoStore,
|
repoStore: repoStore,
|
||||||
pipelineStore: pipelineStore,
|
pipelineStore: pipelineStore,
|
||||||
executionStore: executionStore,
|
executionStore: executionStore,
|
||||||
|
git: git,
|
||||||
|
urlProvider: urlProvider,
|
||||||
|
slackbot: slackbot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,13 @@ type GeneratePipelineInput struct {
|
||||||
RepoRef string `json:"repo_ref"`
|
RepoRef string `json:"repo_ref"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PipelineData struct {
|
||||||
|
YamlPipeline string `json:"yaml_pipeline"`
|
||||||
|
}
|
||||||
|
|
||||||
type GeneratePipelineOutput struct {
|
type GeneratePipelineOutput struct {
|
||||||
Yaml string `json:"yaml"`
|
Status string `json:"status"`
|
||||||
|
Data PipelineData `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) GeneratePipeline(
|
func (c *Controller) GeneratePipeline(
|
||||||
|
@ -38,11 +43,15 @@ func (c *Controller) GeneratePipeline(
|
||||||
Prompt: in.Prompt,
|
Prompt: in.Prompt,
|
||||||
RepoRef: in.RepoRef,
|
RepoRef: in.RepoRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := c.pipeline.Generate(ctx, generateRequest)
|
output, err := c.pipeline.Generate(ctx, generateRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("generate pipeline: %w", err)
|
return nil, fmt.Errorf("generate pipeline: %w", err)
|
||||||
}
|
}
|
||||||
return &GeneratePipelineOutput{
|
return &GeneratePipelineOutput{
|
||||||
Yaml: output.YAML,
|
Status: "SUCCESS",
|
||||||
|
Data: PipelineData{
|
||||||
|
YamlPipeline: output.YAML,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ func (c *Controller) SuggestPipeline(
|
||||||
RepoRef: in.RepoRef,
|
RepoRef: in.RepoRef,
|
||||||
Pipeline: in.Pipeline,
|
Pipeline: in.Pipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := c.pipeline.Suggest(ctx, suggestionRequest)
|
output, err := c.pipeline.Suggest(ctx, suggestionRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("suggest pipeline: %w", err)
|
return nil, fmt.Errorf("suggest pipeline: %w", err)
|
||||||
|
|
|
@ -21,6 +21,11 @@ import (
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UpdatePipelineOutput struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Data PipelineData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
type UpdatePipelineInput struct {
|
type UpdatePipelineInput struct {
|
||||||
Prompt string `json:"prompt"`
|
Prompt string `json:"prompt"`
|
||||||
RepoRef string `json:"repo_ref"`
|
RepoRef string `json:"repo_ref"`
|
||||||
|
@ -30,15 +35,21 @@ type UpdatePipelineInput struct {
|
||||||
func (c *Controller) UpdatePipeline(
|
func (c *Controller) UpdatePipeline(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
in *UpdatePipelineInput,
|
in *UpdatePipelineInput,
|
||||||
) (string, error) {
|
) (*UpdatePipelineOutput, error) {
|
||||||
generateRequest := &types.PipelineUpdateRequest{
|
generateRequest := &types.PipelineUpdateRequest{
|
||||||
Prompt: in.Prompt,
|
Prompt: in.Prompt,
|
||||||
RepoRef: in.RepoRef,
|
RepoRef: in.RepoRef,
|
||||||
Pipeline: in.Pipeline,
|
Pipeline: in.Pipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := c.pipeline.Update(ctx, generateRequest)
|
output, err := c.pipeline.Update(ctx, generateRequest)
|
||||||
if err != nil {
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@ package aiagent
|
||||||
import (
|
import (
|
||||||
"github.com/harness/gitness/app/auth/authz"
|
"github.com/harness/gitness/app/auth/authz"
|
||||||
"github.com/harness/gitness/app/services/aiagent"
|
"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/store"
|
||||||
|
"github.com/harness/gitness/app/url"
|
||||||
|
"github.com/harness/gitness/git"
|
||||||
|
|
||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
)
|
)
|
||||||
|
@ -33,6 +36,9 @@ func ProvideController(
|
||||||
repoStore store.RepoStore,
|
repoStore store.RepoStore,
|
||||||
pipelineStore store.PipelineStore,
|
pipelineStore store.PipelineStore,
|
||||||
executionStore store.ExecutionStore,
|
executionStore store.ExecutionStore,
|
||||||
|
git git.Interface,
|
||||||
|
urlProvider url.Provider,
|
||||||
|
slackbot *messaging.Slack,
|
||||||
) *Controller {
|
) *Controller {
|
||||||
return NewController(
|
return NewController(
|
||||||
authorizer,
|
authorizer,
|
||||||
|
@ -40,5 +46,8 @@ func ProvideController(
|
||||||
repoStore,
|
repoStore,
|
||||||
pipelineStore,
|
pipelineStore,
|
||||||
executionStore,
|
executionStore,
|
||||||
|
git,
|
||||||
|
urlProvider,
|
||||||
|
slackbot,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -39,8 +39,6 @@ func HandleGeneratePipeline(aiagentCtrl *aiagent.Controller) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/yaml; charset=utf-8")
|
render.JSON(w, http.StatusOK, pipeline)
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
_, _ = w.Write([]byte(pipeline.Yaml))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,8 +40,6 @@ func HandleUpdatePipeline(aiagentCtrl *aiagent.Controller) http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "text/yaml; charset=utf-8")
|
render.JSON(w, http.StatusOK, pipeline)
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
_, _ = w.Write([]byte(pipeline))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -528,6 +528,7 @@ func setupAiAgent(r chi.Router, aiagentCtrl *aiagent.Controller, capabilitiesCtr
|
||||||
r.Post("/capabilities", handlercapabilities.HandleRunCapabilities(capabilitiesCtrl))
|
r.Post("/capabilities", handlercapabilities.HandleRunCapabilities(capabilitiesCtrl))
|
||||||
r.Post("/suggest-pipeline", handleraiagent.HandleSuggestPipelines(aiagentCtrl))
|
r.Post("/suggest-pipeline", handleraiagent.HandleSuggestPipelines(aiagentCtrl))
|
||||||
r.Post("/analyse-execution", handleraiagent.HandleAnalyse(aiagentCtrl))
|
r.Post("/analyse-execution", handleraiagent.HandleAnalyse(aiagentCtrl))
|
||||||
|
r.Post("/slackbot", handleraiagent.HandleSlackMessage(aiagentCtrl))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,7 @@ func (s *HarnessIntelligence) Suggest(
|
||||||
_ context.Context,
|
_ context.Context,
|
||||||
_ *types.PipelineSuggestionsRequest) (*types.PipelineSuggestionsResponse, error) {
|
_ *types.PipelineSuggestionsRequest) (*types.PipelineSuggestionsResponse, error) {
|
||||||
return &types.PipelineSuggestionsResponse{
|
return &types.PipelineSuggestionsResponse{
|
||||||
|
// TODO Update to be V0 Yaml
|
||||||
Suggestions: []types.Suggestion{
|
Suggestions: []types.Suggestion{
|
||||||
{
|
{
|
||||||
ID: "add-testing-stage",
|
ID: "add-testing-stage",
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -93,6 +93,7 @@ import (
|
||||||
"github.com/harness/gitness/app/services/keywordsearch"
|
"github.com/harness/gitness/app/services/keywordsearch"
|
||||||
svclabel "github.com/harness/gitness/app/services/label"
|
svclabel "github.com/harness/gitness/app/services/label"
|
||||||
locker "github.com/harness/gitness/app/services/locker"
|
locker "github.com/harness/gitness/app/services/locker"
|
||||||
|
messagingservice "github.com/harness/gitness/app/services/messaging"
|
||||||
"github.com/harness/gitness/app/services/metric"
|
"github.com/harness/gitness/app/services/metric"
|
||||||
migrateservice "github.com/harness/gitness/app/services/migrate"
|
migrateservice "github.com/harness/gitness/app/services/migrate"
|
||||||
"github.com/harness/gitness/app/services/notification"
|
"github.com/harness/gitness/app/services/notification"
|
||||||
|
@ -268,6 +269,7 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
|
||||||
secretservice.WireSet,
|
secretservice.WireSet,
|
||||||
containerGit.WireSet,
|
containerGit.WireSet,
|
||||||
containerUser.WireSet,
|
containerUser.WireSet,
|
||||||
|
messagingservice.WireSet,
|
||||||
)
|
)
|
||||||
return &cliserver.System{}, nil
|
return &cliserver.System{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ import (
|
||||||
"github.com/harness/gitness/app/services/keywordsearch"
|
"github.com/harness/gitness/app/services/keywordsearch"
|
||||||
"github.com/harness/gitness/app/services/label"
|
"github.com/harness/gitness/app/services/label"
|
||||||
"github.com/harness/gitness/app/services/locker"
|
"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/metric"
|
||||||
"github.com/harness/gitness/app/services/migrate"
|
"github.com/harness/gitness/app/services/migrate"
|
||||||
"github.com/harness/gitness/app/services/notification"
|
"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 {
|
if err != nil {
|
||||||
return nil, err
|
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()
|
openapiService := openapi.ProvideOpenAPIService()
|
||||||
storageDriver, err := api2.BlobStorageProvider(config)
|
storageDriver, err := api2.BlobStorageProvider(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -64,6 +64,7 @@ require (
|
||||||
github.com/rs/zerolog v1.33.0
|
github.com/rs/zerolog v1.33.0
|
||||||
github.com/sercand/kuberesolver/v5 v5.1.1
|
github.com/sercand/kuberesolver/v5 v5.1.1
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
|
github.com/slack-go/slack v0.14.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/swaggest/openapi-go v0.2.23
|
github.com/swaggest/openapi-go v0.2.23
|
||||||
github.com/swaggest/swgui v1.8.1
|
github.com/swaggest/swgui v1.8.1
|
||||||
|
@ -121,6 +122,7 @@ require (
|
||||||
github.com/google/s2a-go v0.1.8 // indirect
|
github.com/google/s2a-go v0.1.8 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.13.0 // 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/h2non/filetype v1.1.3 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/invopop/yaml v0.2.0 // indirect
|
github.com/invopop/yaml v0.2.0 // indirect
|
||||||
|
|
6
go.sum
6
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 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
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-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 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
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.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.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.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.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 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
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 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
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 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 h1:7++suUs+HNHMnyz6/AW3SE+4EnBhupPSQTSI7QNijVc=
|
||||||
github.com/gotidy/ptr v1.4.0/go.mod h1:MjRBG6/IETiiZGWI8LrRtISXEji+8b/jigmj2q0mEyM=
|
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=
|
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.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
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/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/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
|
|
|
@ -21,5 +21,7 @@ type AnalyseExecutionInput struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnalyseExecutionOutput struct {
|
type AnalyseExecutionOutput struct {
|
||||||
Yaml string `json:"yaml"`
|
// high level summary of the changes
|
||||||
|
Branch string `json:"branch"`
|
||||||
|
Summary string `json:"summary"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue