Skip to content

Commit e2d70e4

Browse files
committed
refactor: reorganize AWS cloud layer implementation & bug discovered
- Split monolithic cloud_ui_operations.go into smaller, focused files - Move operation implementations to dedicated operations.go files - Create separate category.go for category implementations - Simplify service.go to focus on service definition - Remove redundant code and improve organization - Maintain same functionality with better code structure - Discovered bug: 'j/k' keys not working when in text input mode
1 parent 0ad9c1e commit e2d70e4

File tree

6 files changed

+294
-687
lines changed

6 files changed

+294
-687
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package codepipeline
2+
3+
import (
4+
"github.com/HenryOwenz/cloudgate/internal/cloud"
5+
)
6+
7+
// WorkflowsCategory represents the CodePipeline workflows category.
8+
type WorkflowsCategory struct {
9+
profile string
10+
region string
11+
operations []cloud.Operation
12+
}
13+
14+
// NewWorkflowsCategory creates a new CodePipeline workflows category.
15+
func NewWorkflowsCategory(profile, region string) *WorkflowsCategory {
16+
category := &WorkflowsCategory{
17+
profile: profile,
18+
region: region,
19+
operations: make([]cloud.Operation, 0),
20+
}
21+
22+
// Register operations
23+
category.operations = append(category.operations, NewCloudPipelineStatusOperation(profile, region))
24+
category.operations = append(category.operations, NewCloudStartPipelineOperation(profile, region))
25+
category.operations = append(category.operations, NewCloudManualApprovalOperation(profile, region))
26+
27+
return category
28+
}
29+
30+
// Name returns the category's name.
31+
func (c *WorkflowsCategory) Name() string {
32+
return "Workflows"
33+
}
34+
35+
// Description returns the category's description.
36+
func (c *WorkflowsCategory) Description() string {
37+
return "CodePipeline Workflows"
38+
}
39+
40+
// Operations returns all available operations for this category.
41+
func (c *WorkflowsCategory) Operations() []cloud.Operation {
42+
return c.operations
43+
}
44+
45+
// IsUIVisible returns whether this category should be visible in the UI.
46+
func (c *WorkflowsCategory) IsUIVisible() bool {
47+
return true
48+
}
49+
50+
// InternalOperationsCategory represents the CodePipeline internal operations category.
51+
type InternalOperationsCategory struct {
52+
profile string
53+
region string
54+
operations []cloud.Operation
55+
}
56+
57+
// NewInternalOperationsCategory creates a new CodePipeline internal operations category.
58+
func NewInternalOperationsCategory(profile, region string) *InternalOperationsCategory {
59+
category := &InternalOperationsCategory{
60+
profile: profile,
61+
region: region,
62+
operations: make([]cloud.Operation, 0),
63+
}
64+
65+
// Register operations
66+
category.operations = append(category.operations, NewCloudManualApprovalOperation(profile, region))
67+
68+
return category
69+
}
70+
71+
// Name returns the category's name.
72+
func (c *InternalOperationsCategory) Name() string {
73+
return "Internal Operations"
74+
}
75+
76+
// Description returns the category's description.
77+
func (c *InternalOperationsCategory) Description() string {
78+
return "CodePipeline Internal Operations"
79+
}
80+
81+
// Operations returns all available operations for this category.
82+
func (c *InternalOperationsCategory) Operations() []cloud.Operation {
83+
return c.operations
84+
}
85+
86+
// IsUIVisible returns whether this category should be visible in the UI.
87+
func (c *InternalOperationsCategory) IsUIVisible() bool {
88+
return false
89+
}

internal/cloud/aws/codepipeline/cloud_ui_operations.go renamed to internal/cloud/aws/codepipeline/operations.go

Lines changed: 50 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -67,26 +67,26 @@ func (o *CloudManualApprovalOperation) GetPendingApprovals(ctx context.Context)
6767

6868
var approvals []cloud.ApprovalAction
6969

70-
// Check each pipeline for pending approvals
70+
// Get approvals for each pipeline
7171
for _, pipeline := range pipelineOutput.Pipelines {
7272
// Get pipeline details
73-
pipelineOutput, err := client.GetPipeline(ctx, &codepipeline.GetPipelineInput{
73+
pipelineResp, err := client.GetPipeline(ctx, &codepipeline.GetPipelineInput{
7474
Name: pipeline.Name,
7575
})
7676
if err != nil {
7777
return nil, fmt.Errorf("failed to get pipeline details: %w", err)
7878
}
7979

8080
// Get pipeline state
81-
stateOutput, err := client.GetPipelineState(ctx, &codepipeline.GetPipelineStateInput{
81+
stateResp, err := client.GetPipelineState(ctx, &codepipeline.GetPipelineStateInput{
8282
Name: pipeline.Name,
8383
})
8484
if err != nil {
8585
return nil, fmt.Errorf("failed to get pipeline state: %w", err)
8686
}
8787

8888
// Find pending approvals
89-
pipelineApprovals := findCloudPendingApprovals(*pipeline.Name, pipelineOutput.Pipeline.Stages, stateOutput.StageStates)
89+
pipelineApprovals := findCloudPendingApprovals(*pipeline.Name, pipelineResp.Pipeline.Stages, stateResp.StageStates)
9090
approvals = append(approvals, pipelineApprovals...)
9191
}
9292

@@ -106,20 +106,22 @@ func (o *CloudManualApprovalOperation) ApproveAction(ctx context.Context, action
106106

107107
client := codepipeline.NewFromConfig(cfg)
108108

109-
status := cpTypes.ApprovalStatusApproved
110-
if !approved {
111-
status = cpTypes.ApprovalStatusRejected
109+
// Set the approval status
110+
status := cpTypes.ApprovalStatusRejected
111+
if approved {
112+
status = cpTypes.ApprovalStatusApproved
112113
}
113114

115+
// Put the approval result
114116
_, err = client.PutApprovalResult(ctx, &codepipeline.PutApprovalResultInput{
115117
ActionName: aws.String(action.ActionName),
116118
PipelineName: aws.String(action.PipelineName),
119+
StageName: aws.String(action.StageName),
117120
Result: &cpTypes.ApprovalResult{
118121
Status: status,
119122
Summary: aws.String(comment),
120123
},
121-
StageName: aws.String(action.StageName),
122-
Token: aws.String(action.Token),
124+
Token: aws.String(action.Token),
123125
})
124126
if err != nil {
125127
return fmt.Errorf("failed to put approval result: %w", err)
@@ -254,7 +256,7 @@ func (o *CloudStartPipelineOperation) Name() string {
254256

255257
// Description returns the operation's description.
256258
func (o *CloudStartPipelineOperation) Description() string {
257-
return "Trigger Pipeline Execution"
259+
return "Start Pipeline Execution"
258260
}
259261

260262
// IsUIVisible returns whether this operation should be visible in the UI.
@@ -264,21 +266,20 @@ func (o *CloudStartPipelineOperation) IsUIVisible() bool {
264266

265267
// Execute executes the operation with the given parameters.
266268
func (o *CloudStartPipelineOperation) Execute(ctx context.Context, params map[string]interface{}) (interface{}, error) {
267-
pipelineName, ok := params["pipelineName"].(string)
269+
// Get pipeline name and commit ID from parameters
270+
pipelineName, ok := params["pipeline_name"].(string)
268271
if !ok {
269-
return nil, fmt.Errorf("pipelineName parameter is required")
272+
return nil, fmt.Errorf("pipeline_name parameter is required")
270273
}
271274

272-
commitID, ok := params["commitID"].(string)
273-
if !ok {
274-
commitID = "" // Default to empty string if not provided
275-
}
275+
commitID, _ := params["commit_id"].(string)
276276

277+
// Start the pipeline
277278
return nil, o.StartPipelineExecution(ctx, pipelineName, commitID)
278279
}
279280

280281
// StartPipelineExecution starts a pipeline execution.
281-
func (o *CloudStartPipelineOperation) StartPipelineExecution(ctx context.Context, pipelineName string, commitID string) error {
282+
func (o *CloudStartPipelineOperation) StartPipelineExecution(ctx context.Context, pipelineName, commitID string) error {
282283
// Create a new AWS SDK client
283284
cfg, err := config.LoadDefaultConfig(ctx,
284285
config.WithSharedConfigProfile(o.profile),
@@ -290,15 +291,12 @@ func (o *CloudStartPipelineOperation) StartPipelineExecution(ctx context.Context
290291

291292
client := codepipeline.NewFromConfig(cfg)
292293

294+
// Create the input
293295
input := &codepipeline.StartPipelineExecutionInput{
294296
Name: aws.String(pipelineName),
295297
}
296298

297-
// Add commit ID if provided
298-
if commitID != "" {
299-
input.ClientRequestToken = aws.String(commitID)
300-
}
301-
299+
// Start the pipeline execution
302300
_, err = client.StartPipelineExecution(ctx, input)
303301
if err != nil {
304302
return fmt.Errorf("failed to start pipeline execution: %w", err)
@@ -307,69 +305,68 @@ func (o *CloudStartPipelineOperation) StartPipelineExecution(ctx context.Context
307305
return nil
308306
}
309307

310-
// Helper functions
311-
312-
// findCloudPendingApprovals returns a list of pending approval actions from the given stages and their states.
308+
// findCloudPendingApprovals finds all pending manual approval actions in a pipeline.
313309
func findCloudPendingApprovals(pipelineName string, stages []cpTypes.StageDeclaration, stageStates []cpTypes.StageState) []cloud.ApprovalAction {
314-
var approvals []cloud.ApprovalAction
310+
// Build a map of action types for quick lookup
315311
actionTypes := buildCloudActionTypeMap(stages)
316-
stateMap := buildCloudStageStateMap(stageStates)
317312

313+
// Build a map of stage states for quick lookup
314+
stageStateMap := buildCloudStageStateMap(stageStates)
315+
316+
// Find pending approvals in each stage
317+
var approvals []cloud.ApprovalAction
318318
for _, stage := range stages {
319-
if state, ok := stateMap[*stage.Name]; ok {
320-
stageApprovals := findCloudStageApprovals(pipelineName, stage, state, actionTypes)
321-
approvals = append(approvals, stageApprovals...)
319+
if state, ok := stageStateMap[*stage.Name]; ok {
320+
approvals = append(approvals, findCloudStageApprovals(pipelineName, stage, state, actionTypes)...)
322321
}
323322
}
324323

325324
return approvals
326325
}
327326

328-
// buildCloudActionTypeMap creates a map of action names to their categories for quick lookup.
327+
// buildCloudActionTypeMap builds a map of action types for quick lookup.
329328
func buildCloudActionTypeMap(stages []cpTypes.StageDeclaration) map[string]cpTypes.ActionCategory {
330329
actionTypes := make(map[string]cpTypes.ActionCategory)
331330
for _, stage := range stages {
332331
for _, action := range stage.Actions {
333332
actionTypes[*action.Name] = action.ActionTypeId.Category
334333
}
335334
}
336-
337335
return actionTypes
338336
}
339337

340-
// buildCloudStageStateMap creates a map of stage names to their states for quick lookup.
338+
// buildCloudStageStateMap builds a map of stage states for quick lookup.
341339
func buildCloudStageStateMap(stageStates []cpTypes.StageState) map[string]cpTypes.StageState {
342-
stateMap := make(map[string]cpTypes.StageState)
340+
stageStateMap := make(map[string]cpTypes.StageState)
343341
for _, state := range stageStates {
344-
stateMap[*state.StageName] = state
342+
stageStateMap[*state.StageName] = state
345343
}
346-
347-
return stateMap
344+
return stageStateMap
348345
}
349346

350-
// findCloudStageApprovals returns a list of pending approval actions from a single stage.
347+
// findCloudStageApprovals finds all pending manual approval actions in a stage.
351348
func findCloudStageApprovals(pipelineName string, stage cpTypes.StageDeclaration, state cpTypes.StageState, actionTypes map[string]cpTypes.ActionCategory) []cloud.ApprovalAction {
352349
var approvals []cloud.ApprovalAction
353350
for _, actionState := range state.ActionStates {
354-
if actionState.ActionName != nil && isCloudApprovalAction(actionState, actionTypes) {
355-
approval := cloud.ApprovalAction{
356-
PipelineName: pipelineName,
357-
StageName: *stage.Name,
358-
ActionName: *actionState.ActionName,
359-
Token: *actionState.LatestExecution.Token,
351+
if actionState.ActionName != nil && isCloudApprovalAction(*actionState.ActionName, actionTypes) {
352+
// Check if the action is waiting for approval
353+
if actionState.LatestExecution != nil && actionState.LatestExecution.Status == cpTypes.ActionExecutionStatusInProgress {
354+
if actionState.LatestExecution.Token != nil {
355+
approvals = append(approvals, cloud.ApprovalAction{
356+
PipelineName: pipelineName,
357+
StageName: *state.StageName,
358+
ActionName: *actionState.ActionName,
359+
Token: *actionState.LatestExecution.Token,
360+
})
361+
}
360362
}
361-
approvals = append(approvals, approval)
362363
}
363364
}
364-
365365
return approvals
366366
}
367367

368-
// isCloudApprovalAction checks if the given action state represents a pending manual approval.
369-
func isCloudApprovalAction(actionState cpTypes.ActionState, actionTypes map[string]cpTypes.ActionCategory) bool {
370-
return actionState.LatestExecution != nil &&
371-
actionState.LatestExecution.Token != nil &&
372-
actionState.LatestExecution.Status == cpTypes.ActionExecutionStatusInProgress &&
373-
actionState.ActionName != nil &&
374-
actionTypes[*actionState.ActionName] == cpTypes.ActionCategoryApproval
368+
// isCloudApprovalAction checks if an action is a manual approval action.
369+
func isCloudApprovalAction(actionName string, actionTypes map[string]cpTypes.ActionCategory) bool {
370+
category, ok := actionTypes[actionName]
371+
return ok && category == cpTypes.ActionCategoryApproval
375372
}

0 commit comments

Comments
 (0)