Skip to content

Commit

Permalink
Feat/ai fix feedback command [IDE-634] (#672)
Browse files Browse the repository at this point in the history
  • Loading branch information
acke authored Sep 26, 2024
1 parent 1c41d37 commit 9dd78b9
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 50 deletions.
17 changes: 10 additions & 7 deletions domain/ide/command/code_fix_feedback.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ package command

import (
"context"

"github.com/snyk/snyk-ls/application/config"
"github.com/snyk/snyk-ls/internal/types"
)

type SnykCodeHttpClient interface {
SubmitAutofixFeedback(ctx context.Context, fixId string, positive bool) error
SubmitAutofixFeedback(ctx context.Context, fixId string, positive string) error
}

type codeFixFeedback struct {
Expand All @@ -38,11 +38,14 @@ func (cmd *codeFixFeedback) Command() types.CommandData {
func (cmd *codeFixFeedback) Execute(ctx context.Context) (any, error) {
args := cmd.command.Arguments
fixId := args[0].(string)
positive := args[1].(bool)
err := cmd.apiClient.SubmitAutofixFeedback(ctx, fixId, positive)
if err != nil {
return nil, err
}
feedback := args[1].(string)

go func() {
err := cmd.apiClient.SubmitAutofixFeedback(ctx, fixId, feedback)
if err != nil {
config.CurrentConfig().Logger().Err(err).Str("fixId", fixId).Str("feedback", feedback).Msg("failed to submit autofix feedback")
}
}()

return nil, nil
}
45 changes: 24 additions & 21 deletions domain/ide/command/code_fix_feedback_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,53 +19,56 @@ package command
import (
"context"
"errors"
"sync"
"testing"
"time"

"github.com/stretchr/testify/assert"

"github.com/snyk/snyk-ls/infrastructure/code"
"github.com/snyk/snyk-ls/internal/types"
)

type fakeCodeHttpClient struct {
shouldError bool
feedbackSubmitted bool
feedbackSubmitted string
fixId string
mu sync.Mutex
}

func (c *fakeCodeHttpClient) SubmitAutofixFeedback(ctx context.Context, fixId string, positive bool) error {
func (c *fakeCodeHttpClient) SubmitAutofixFeedback(ctx context.Context, fixId string, feedback string) error {
c.mu.Lock()
c.feedbackSubmitted = feedback
c.fixId = fixId
c.mu.Unlock()

if !c.shouldError {
c.feedbackSubmitted = true
return nil
}

return errors.New("api call failed")
}

func Test_codeFixFeedback_SubmittedSuccessfully(t *testing.T) {
apiClient := fakeCodeHttpClient{}
codeFixFeedbackCmd := codeFixFeedback{
command: types.CommandData{
Arguments: []any{"fixId", true},
},
apiClient: &apiClient,
}
func FeedbackSubmitted(c *fakeCodeHttpClient) string {
c.mu.Lock()
defer c.mu.Unlock()

_, err := codeFixFeedbackCmd.Execute(context.Background())
assert.NoError(t, err)
assert.True(t, apiClient.feedbackSubmitted)
return c.feedbackSubmitted
}

func Test_codeFixFeedback_SubmissionFailed(t *testing.T) {
apiClient := fakeCodeHttpClient{
shouldError: true,
}
func Test_codeFixFeedback_SubmittedSuccessfully(t *testing.T) {
apiClient := fakeCodeHttpClient{}
codeFixFeedbackCmd := codeFixFeedback{
command: types.CommandData{
Arguments: []any{"fixId", true},
Arguments: []any{"fixId", code.FixPositiveFeedback},
},
apiClient: &apiClient,
}

_, err := codeFixFeedbackCmd.Execute(context.Background())
assert.Error(t, err)
assert.False(t, apiClient.feedbackSubmitted)

assert.NoError(t, err)
assert.Eventually(t, func() bool {
return FeedbackSubmitted(&apiClient) != ""
}, 2*time.Second, time.Millisecond)
}
22 changes: 22 additions & 0 deletions infrastructure/code/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* © 2024 Snyk Limited
*
* 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 code

const (
FixPositiveFeedback string = "FIX_POSITIVE_FEEDBACK"
FixNegativeFeedback string = "FIX_NEGATIVE_FEEDBACK"
)
2 changes: 1 addition & 1 deletion infrastructure/code/fake_snyk_code_api_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,6 @@ func (f *FakeSnykCodeClient) GetAutofixSuggestions(
return suggestions, AutofixStatus{message: "COMPLETE"}, nil
}

func (f *FakeSnykCodeClient) SubmitAutofixFeedback(_ context.Context, _ string, _ bool) error {
func (f *FakeSnykCodeClient) SubmitAutofixFeedback(_ context.Context, _ string, _ string) error {
return nil
}
8 changes: 4 additions & 4 deletions infrastructure/code/issue_enhancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,16 +251,16 @@ func ToEncodedNormalizedPath(rootPath string, filePath string) (string, error) {
}

func (b *IssueEnhancer) autofixFeedbackActions(fixId string) (*data_structure.OrderedMap[types.MessageAction, types.CommandData], error) {
createCommandData := func(positive bool) types.CommandData {
createCommandData := func(feedback string) types.CommandData {
return types.CommandData{
Title: types.CodeSubmitFixFeedback,
CommandId: types.CodeSubmitFixFeedback,
Arguments: []any{fixId, positive},
Arguments: []any{fixId, feedback},
}
}
actionCommandMap := data_structure.NewOrderedMap[types.MessageAction, types.CommandData]()
positiveFeedbackCmd := createCommandData(true)
negativeFeedbackCmd := createCommandData(false)
positiveFeedbackCmd := createCommandData(FixPositiveFeedback)
negativeFeedbackCmd := createCommandData(FixNegativeFeedback)

actionCommandMap.Add("👍", positiveFeedbackCmd)
actionCommandMap.Add("👎", negativeFeedbackCmd)
Expand Down
8 changes: 4 additions & 4 deletions infrastructure/code/issue_enhancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,12 @@ func Test_autofixFunc(t *testing.T) {
commandData1 := types.CommandData{
Title: types.CodeSubmitFixFeedback,
CommandId: types.CodeSubmitFixFeedback,
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", true},
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", FixPositiveFeedback},
}
commandData2 := types.CommandData{
Title: types.CodeSubmitFixFeedback,
CommandId: types.CodeSubmitFixFeedback,
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", false},
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", FixNegativeFeedback},
}
positiveFeedback := types.MessageAction("👍")
negativeFeedback := types.MessageAction("👎")
Expand Down Expand Up @@ -156,12 +156,12 @@ func Test_autofixFunc(t *testing.T) {
commandData1 := types.CommandData{
Title: types.CodeSubmitFixFeedback,
CommandId: types.CodeSubmitFixFeedback,
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", true},
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", FixPositiveFeedback},
}
commandData2 := types.CommandData{
Title: types.CodeSubmitFixFeedback,
CommandId: types.CodeSubmitFixFeedback,
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", false},
Arguments: []any{"123e4567-e89b-12d3-a456-426614174000/1", FixNegativeFeedback},
}
positiveFeedback := types.MessageAction("👍")
negativeFeedback := types.MessageAction("👎")
Expand Down
22 changes: 10 additions & 12 deletions infrastructure/code/snyk_code_http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ func (s *SnykCodeHTTPClient) autofixRequestBody(options *AutofixOptions) ([]byte
return requestBody, err
}

func (s *SnykCodeHTTPClient) SubmitAutofixFeedback(ctx context.Context, fixId string, positive bool) error {
func (s *SnykCodeHTTPClient) SubmitAutofixFeedback(ctx context.Context, fixId string, feedback string) error {
method := "code.SubmitAutofixFeedback"
span := s.instrumentor.StartSpan(ctx, method)
defer s.instrumentor.Finish(span)
Expand All @@ -562,25 +562,23 @@ func (s *SnykCodeHTTPClient) SubmitAutofixFeedback(ctx context.Context, fixId st
s.c.Logger().Debug().Str("method", method).Str("requestId", requestId).Msg("API: Submitting Autofix feedback")
defer s.c.Logger().Debug().Str("method", method).Str("requestId", requestId).Msg("API: Submitting Autofix feedback done")

var feedback string
if positive {
feedback = "POSITIVE"
} else {
feedback = "NEGATIVE"
request := map[string]interface{}{
"channel": "IDE",
"eventType": feedback,
"eventDetails": map[string]string{
"fixId": fixId,
},
"analysisContext": newCodeRequestContext(),
}

request := AutofixFeedback{
FixId: fixId,
Feedback: feedback,
AnalysisContext: newCodeRequestContext(),
}
requestBody, err := json.Marshal(request)
s.c.Logger().Err(err).Str("method", method).Str("requestBody", string(requestBody)).Msg("request body for autofix feedback")
if err != nil {
s.c.Logger().Err(err).Str("method", method).Str("requestBody", string(requestBody)).Msg("error creating request body for autofix feedback")
return err
}

responseBody, err := s.doCall(span.Context(), "POST", "/autofix/feedback", requestBody)
responseBody, err := s.doCall(span.Context(), "POST", "/autofix/event", requestBody)
if err != nil {
s.c.Logger().Err(err).Str("method", method).Str("responseBody", string(responseBody)).Msg("error response for autofix feedback")
return err
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/code/snyk_code_http_client_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ type SnykCodeClient interface {
error,
)

SubmitAutofixFeedback(ctx context.Context, fixId string, positive bool) error
SubmitAutofixFeedback(ctx context.Context, fixId string, result string) error

GetAutoFixDiffs(ctx context.Context, baseDir string, options AutofixOptions) (unifiedDiffSuggestions []AutofixUnifiedDiffSuggestion, err error)
}

0 comments on commit 9dd78b9

Please sign in to comment.