Skip to content

Commit 991a6e5

Browse files
committed
Merge branch 'feature'
2 parents 2ce2fa5 + 9bb83c7 commit 991a6e5

File tree

23 files changed

+857
-60
lines changed

23 files changed

+857
-60
lines changed

internal/cloud/aws/lambda/category.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ func NewWorkflowsCategory(profile, region string) *WorkflowsCategory {
2121

2222
// Register operations
2323
category.operations = append(category.operations, NewFunctionStatusOperation(profile, region))
24+
category.operations = append(category.operations, NewLambdaExecuteOperation(profile, region))
2425

2526
return category
2627
}

internal/cloud/aws/lambda/operations.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package lambda
22

33
import (
44
"context"
5+
"encoding/base64"
56
"errors"
67
"fmt"
78

@@ -152,3 +153,98 @@ func listFunctions(ctx context.Context, client *lambda.Client) ([]types.Function
152153

153154
return functions, nil
154155
}
156+
157+
// Common errors for Lambda execution.
158+
var (
159+
ErrInvokeFunction = errors.New("failed to invoke function")
160+
)
161+
162+
// LambdaExecuteOperation represents an operation to execute a Lambda function.
163+
type LambdaExecuteOperation struct {
164+
profile string
165+
region string
166+
}
167+
168+
// NewLambdaExecuteOperation creates a new Lambda execute operation.
169+
func NewLambdaExecuteOperation(profile, region string) *LambdaExecuteOperation {
170+
return &LambdaExecuteOperation{
171+
profile: profile,
172+
region: region,
173+
}
174+
}
175+
176+
// Name returns the operation's name.
177+
func (o *LambdaExecuteOperation) Name() string {
178+
return "Execute Function"
179+
}
180+
181+
// Description returns the operation's description.
182+
func (o *LambdaExecuteOperation) Description() string {
183+
return "Execute Lambda Function with JSON Payload"
184+
}
185+
186+
// IsUIVisible returns whether this operation should be visible in the UI.
187+
func (o *LambdaExecuteOperation) IsUIVisible() bool {
188+
return true
189+
}
190+
191+
// ExecuteFunction executes a Lambda function with the given payload.
192+
func (o *LambdaExecuteOperation) ExecuteFunction(ctx context.Context, functionName string, payload string) (*cloud.LambdaExecuteResult, error) {
193+
// Create a new AWS SDK client
194+
client, err := getClient(ctx, o.profile, o.region)
195+
if err != nil {
196+
return nil, err
197+
}
198+
199+
// Invoke the function
200+
input := &lambda.InvokeInput{
201+
FunctionName: aws.String(functionName),
202+
Payload: []byte(payload),
203+
LogType: types.LogTypeTail, // Include logs in the response
204+
}
205+
206+
output, err := client.Invoke(ctx, input)
207+
if err != nil {
208+
return nil, fmt.Errorf("%w: %w", ErrInvokeFunction, err)
209+
}
210+
211+
// Decode the base64-encoded logs
212+
logResult := ""
213+
if output.LogResult != nil {
214+
decodedLogs, err := base64.StdEncoding.DecodeString(*output.LogResult)
215+
if err == nil {
216+
logResult = string(decodedLogs)
217+
}
218+
}
219+
220+
// Convert the payload to a string
221+
payloadStr := ""
222+
if output.Payload != nil {
223+
payloadStr = string(output.Payload)
224+
}
225+
226+
// Create the result
227+
result := &cloud.LambdaExecuteResult{
228+
StatusCode: int(output.StatusCode),
229+
ExecutedVersion: aws.ToString(output.ExecutedVersion),
230+
Payload: payloadStr,
231+
LogResult: logResult,
232+
}
233+
234+
return result, nil
235+
}
236+
237+
// Execute executes the operation with the given parameters.
238+
func (o *LambdaExecuteOperation) Execute(ctx context.Context, params map[string]interface{}) (interface{}, error) {
239+
functionName, ok := params["functionName"].(string)
240+
if !ok {
241+
return nil, fmt.Errorf("function name is required")
242+
}
243+
244+
payload, ok := params["payload"].(string)
245+
if !ok {
246+
return nil, fmt.Errorf("payload is required")
247+
}
248+
249+
return o.ExecuteFunction(ctx, functionName, payload)
250+
}

internal/cloud/aws/provider.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ func (p *Provider) GetFunctionStatusOperation() (cloud.FunctionStatusOperation,
7070
return lambda.NewFunctionStatusOperation(p.profile, p.region), nil
7171
}
7272

73+
// GetLambdaExecuteOperation returns the Lambda execute operation
74+
func (p *Provider) GetLambdaExecuteOperation() (cloud.LambdaExecuteOperation, error) {
75+
if p.profile == "" || p.region == "" {
76+
return nil, ErrNotAuthenticated
77+
}
78+
return lambda.NewLambdaExecuteOperation(p.profile, p.region), nil
79+
}
80+
7381
// GetCodePipelineManualApprovalOperation returns the CodePipeline manual approval operation
7482
func (p *Provider) GetCodePipelineManualApprovalOperation() (cloud.CodePipelineManualApprovalOperation, error) {
7583
if p.profile == "" || p.region == "" {

internal/cloud/types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ type Provider interface {
2424
// GetFunctionStatusOperation returns the function status operation
2525
GetFunctionStatusOperation() (FunctionStatusOperation, error)
2626

27+
// GetLambdaExecuteOperation returns the Lambda execute operation
28+
GetLambdaExecuteOperation() (LambdaExecuteOperation, error)
29+
2730
// GetCodePipelineManualApprovalOperation returns the CodePipeline manual approval operation
2831
GetCodePipelineManualApprovalOperation() (CodePipelineManualApprovalOperation, error)
2932

@@ -160,6 +163,14 @@ type FunctionStatus struct {
160163
LogGroup string
161164
}
162165

166+
// LambdaExecuteResult represents the result of a Lambda function execution
167+
type LambdaExecuteResult struct {
168+
StatusCode int
169+
ExecutedVersion string
170+
Payload string
171+
LogResult string
172+
}
173+
163174
// CodePipelineManualApprovalOperation represents a manual approval operation for AWS CodePipeline
164175
type CodePipelineManualApprovalOperation interface {
165176
UIOperation
@@ -194,3 +205,11 @@ type FunctionStatusOperation interface {
194205
// GetFunctionStatus returns the status of all Lambda functions
195206
GetFunctionStatus(ctx context.Context) ([]FunctionStatus, error)
196207
}
208+
209+
// LambdaExecuteOperation represents an operation to execute a Lambda function
210+
type LambdaExecuteOperation interface {
211+
UIOperation
212+
213+
// ExecuteFunction executes a Lambda function with the given payload
214+
ExecuteFunction(ctx context.Context, functionName string, payload string) (*LambdaExecuteResult, error)
215+
}

internal/cloudproviders/aws_wrapper.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@ func (w *AWSProviderWrapper) GetStartPipelineOperation() (cloud.StartPipelineOpe
152152
return w.provider.GetStartPipelineOperation()
153153
}
154154

155+
// GetLambdaExecuteOperation returns the Lambda execute operation
156+
func (w *AWSProviderWrapper) GetLambdaExecuteOperation() (cloud.LambdaExecuteOperation, error) {
157+
return w.provider.GetLambdaExecuteOperation()
158+
}
159+
155160
// GetAuthenticationMethods returns the available authentication methods
156161
func (w *AWSProviderWrapper) GetAuthenticationMethods() []string {
157162
return w.provider.GetAuthenticationMethods()

internal/ui/constants/colors.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ const (
1313
ColorSubtle = "#718096" // Gray for subtle elements
1414

1515
// Status colors
16-
ColorSuccess = "#38A169" // Subdued green for success messages (previously #00FF7F)
17-
ColorError = "#E53E3E" // Red for error messages
18-
ColorWarning = "#DD6B20" // Orange for warnings
19-
ColorInfo = "#4299E1" // Brighter blue for info messages and column headers (previously #3182CE)
16+
ColorSuccess = "#38A169" // Subdued green for success messages (previously #00FF7F)
17+
ColorError = "#E53E3E" // Red for error messages
18+
ColorWarning = "#DD6B20" // Orange for warnings
19+
ColorInfo = "#4299E1" // Brighter blue for info messages and column headers (previously #3182CE)
20+
ColorHighlight = "#F6E05E" // Yellow for highlighting focused elements
2021

2122
// Background colors
2223
ColorBg = "#1A202C" // Dark background

internal/ui/constants/dimensions.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ const (
1515
TextInputCharLimit = 100
1616

1717
// App dimensions
18-
AppMaxWidth = 100
19-
AppHeight = 17
2018
AppContentLines = 5 // Number of content lines in the UI layout
2119

2220
// Padding and margins
2321
PaddingX = 1
2422
PaddingY = 2
23+
24+
// Component heights
25+
HeaderHeight = 2 // Height for headers/titles
26+
FooterHeight = 1 // Height for footers
27+
28+
// Viewport dimensions
29+
ViewportMarginX = 2 // Horizontal margin for viewport
30+
ViewportMarginY = 3 // Vertical margin for viewport (header + footer)
2531
)

internal/ui/constants/keys.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ package constants
22

33
// Key constants for keyboard input
44
const (
5-
KeyQ = "q"
6-
KeyCtrlC = "ctrl+c"
7-
KeyEnter = "enter"
8-
KeyEsc = "esc"
9-
KeyUp = "up"
10-
KeyDown = "down"
11-
KeyAltUp = "k"
12-
KeyAltDown = "j"
13-
KeyAltBack = "-"
14-
KeyTab = "tab"
5+
KeyQ = "q"
6+
KeyCtrlC = "ctrl+c"
7+
KeyEnter = "enter"
8+
KeyCtrlEnter = "ctrl+enter"
9+
KeyShiftEnter = "shift+enter"
10+
KeyF5 = "f5"
11+
KeyEsc = "esc"
12+
KeyUp = "up"
13+
KeyDown = "down"
14+
KeyAltUp = "k"
15+
KeyAltDown = "j"
16+
KeyAltBack = "-"
17+
KeyTab = "tab"
1518

1619
// Vim-like navigation keys
1720
KeyGotoTop = "g"

internal/ui/constants/messages.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const (
1111
MsgLoadingFunctions = "Loading functions..."
1212
MsgStartingPipeline = "Starting pipeline..."
1313
MsgExecutingApproval = "Executing approval action..."
14+
MsgExecutingLambda = "Executing Lambda function..."
1415

1516
// Input placeholders
1617
MsgEnterProfile = "Enter AWS profile name..."
@@ -19,17 +20,22 @@ const (
1920
MsgEnterApprovalComment = "Enter approval comment..."
2021
MsgEnterRejectionComment = "Enter rejection comment..."
2122
MsgEnterCommitID = "Enter commit ID..."
23+
MsgEnterLambdaPayload = "Enter Lambda JSON payload..."
2224

2325
// Success messages
2426
MsgApprovalSuccess = "Successfully approved pipeline: %s, stage: %s, action: %s"
2527
MsgRejectionSuccess = "Successfully rejected pipeline: %s, stage: %s, action: %s"
2628
MsgPipelineStartSuccess = "Successfully started pipeline: %s"
29+
MsgLambdaExecuteSuccess = "Successfully executed Lambda function: %s"
2730

2831
// Error messages
2932
MsgErrorGeneric = "Error: %s"
3033
MsgErrorNoApproval = "No approval selected"
3134
MsgErrorNoPipeline = "No pipeline selected"
3235
MsgErrorNoFunction = "No function selected"
36+
MsgNoFunctionSelected = "No function selected"
37+
MsgLambdaExecuteError = "Error executing Lambda function %s: %v"
3338
MsgErrorEmptyCommitID = "Commit ID cannot be empty"
3439
MsgErrorEmptyComment = "Comment cannot be empty"
40+
MsgErrorInvalidJSON = "Invalid JSON payload"
3541
)

internal/ui/constants/titles.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ const (
2020
TitleHelp = "Help"
2121
TitleFunctionStatus = "Lambda Functions"
2222
TitleFunctionDetails = "Function Details"
23+
TitleLambdaExecute = "Lambda Payload (JSON)"
24+
TitleLambdaResponse = "Lambda Response"
2325
)

0 commit comments

Comments
 (0)