Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/app/pipedv1/plugin/example/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
}

// BuildPipelineSyncStages implements sdk.PipelineSyncPlugin.
func (p *plugin) BuildPipelineSyncStages(context.Context, *config, *sdk.Client, sdk.TODO) (sdk.TODO, error) {
return sdk.TODO{}, nil
func (p *plugin) BuildPipelineSyncStages(context.Context, *config, *sdk.Client, *sdk.BuildPipelineSyncStagesRequest) (*sdk.BuildPipelineSyncStagesResponse, error) {
return &sdk.BuildPipelineSyncStagesResponse{}, nil

Check warning on line 40 in pkg/app/pipedv1/plugin/example/plugin.go

View check run for this annotation

Codecov / codecov/patch

pkg/app/pipedv1/plugin/example/plugin.go#L39-L40

Added lines #L39 - L40 were not covered by tests
}

// ExecuteStage implements sdk.PipelineSyncPlugin.
Expand Down
141 changes: 138 additions & 3 deletions pkg/plugin/sdk/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
"context"
"encoding/json"
"fmt"
"time"

"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

config "github.com/pipe-cd/pipecd/pkg/configv1"
"github.com/pipe-cd/pipecd/pkg/model"
"github.com/pipe-cd/pipecd/pkg/plugin/api/v1alpha1/deployment"
"github.com/pipe-cd/pipecd/pkg/plugin/logpersister"
"github.com/pipe-cd/pipecd/pkg/plugin/pipedapi"
Expand Down Expand Up @@ -71,7 +73,7 @@
// FetchDefinedStages returns the list of stages that the plugin can execute.
FetchDefinedStages() []string
// BuildPipelineSyncStages builds the stages that will be executed by the plugin.
BuildPipelineSyncStages(context.Context, *Config, *Client, TODO) (TODO, error)
BuildPipelineSyncStages(context.Context, *Config, *Client, *BuildPipelineSyncStagesRequest) (*BuildPipelineSyncStagesResponse, error)
// ExecuteStage executes the given stage.
ExecuteStage(context.Context, *Config, []*DeployTarget[DeployTargetConfig], *Client, logpersister.StageLogPersister, TODO) (TODO, error)
}
Expand Down Expand Up @@ -156,7 +158,7 @@
return nil, status.Errorf(codes.Unimplemented, "method DetermineStrategy not implemented")
}
func (s *DeploymentPluginServiceServer[Config, DeployTargetConfig]) BuildPipelineSyncStages(ctx context.Context, request *deployment.BuildPipelineSyncStagesRequest) (*deployment.BuildPipelineSyncStagesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BuildPipelineSyncStages not implemented")
return buildPipelineSyncStages(ctx, s.base, &s.config, nil, request) // TODO: pass the real client

Check warning on line 161 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L161

Added line #L161 was not covered by tests
}
func (s *DeploymentPluginServiceServer[Config, DeployTargetConfig]) BuildQuickSyncStages(context.Context, *deployment.BuildQuickSyncStagesRequest) (*deployment.BuildQuickSyncStagesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BuildQuickSyncStages not implemented")
Expand Down Expand Up @@ -213,11 +215,144 @@
return &deployment.DetermineStrategyResponse{Unsupported: true}, nil
}
func (s *PipelineSyncPluginServiceServer[Config, DeployTargetConfig]) BuildPipelineSyncStages(ctx context.Context, request *deployment.BuildPipelineSyncStagesRequest) (*deployment.BuildPipelineSyncStagesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BuildPipelineSyncStages not implemented")
return buildPipelineSyncStages(ctx, s.base, &s.config, nil, request) // TODO: pass the real client

Check warning on line 218 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L218

Added line #L218 was not covered by tests
}
func (s *PipelineSyncPluginServiceServer[Config, DeployTargetConfig]) BuildQuickSyncStages(context.Context, *deployment.BuildQuickSyncStagesRequest) (*deployment.BuildQuickSyncStagesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method BuildQuickSyncStages not implemented")
}
func (s *PipelineSyncPluginServiceServer[Config, DeployTargetConfig]) ExecuteStage(context.Context, *deployment.ExecuteStageRequest) (*deployment.ExecuteStageResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ExecuteStage not implemented")
}

// buildPipelineSyncStages builds the stages that will be executed by the plugin.
func buildPipelineSyncStages[Config, DeployTargetConfig any](ctx context.Context, plugin PipelineSyncPlugin[Config, DeployTargetConfig], config *Config, client *Client, request *deployment.BuildPipelineSyncStagesRequest) (*deployment.BuildPipelineSyncStagesResponse, error) {
resp, err := plugin.BuildPipelineSyncStages(ctx, config, client, newPipelineSyncStagesRequest(request))
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to build pipeline sync stages: %v", err)
}
return newPipelineSyncStagesResponse(plugin, time.Now(), request, resp)

Check warning on line 233 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L228-L233

Added lines #L228 - L233 were not covered by tests
}

// ManualOperation represents the manual operation that the user can perform.
type ManualOperation int

const (
// ManualOperationNone indicates that there is no manual operation.
ManualOperationNone ManualOperation = iota
// ManualOperationSkip indicates that the manual operation is to skip the stage.
ManualOperationSkip
// ManualOperationApprove indicates that the manual operation is to approve the stage.
ManualOperationApprove
)

// toModelEnum converts the ManualOperation to the model.ManualOperation.
func (o ManualOperation) toModelEnum() model.ManualOperation {
switch o {
case ManualOperationNone:
return model.ManualOperation_MANUAL_OPERATION_NONE
case ManualOperationSkip:
return model.ManualOperation_MANUAL_OPERATION_SKIP
case ManualOperationApprove:
return model.ManualOperation_MANUAL_OPERATION_APPROVE
default:
return model.ManualOperation_MANUAL_OPERATION_UNKNOWN

Check warning on line 258 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L249-L258

Added lines #L249 - L258 were not covered by tests
}
}

// newPipelineSyncStagesRequest converts the request to the internal representation.
func newPipelineSyncStagesRequest(request *deployment.BuildPipelineSyncStagesRequest) *BuildPipelineSyncStagesRequest {
stages := make([]StageConfig, 0, len(request.Stages))
for _, s := range request.GetStages() {
stages = append(stages, StageConfig{
Index: int(s.GetIndex()),
Name: s.GetName(),
Config: s.GetConfig(),
})
}
return &BuildPipelineSyncStagesRequest{
Rollback: request.GetRollback(),
Stages: stages,
}

Check warning on line 275 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L263-L275

Added lines #L263 - L275 were not covered by tests
}

// newPipelineSyncStagesResponse converts the response to the external representation.
func newPipelineSyncStagesResponse(plugin Plugin, now time.Time, request *deployment.BuildPipelineSyncStagesRequest, response *BuildPipelineSyncStagesResponse) (*deployment.BuildPipelineSyncStagesResponse, error) {
// Convert the request stages to a map for easier access.
requestStages := make(map[int]*deployment.BuildPipelineSyncStagesRequest_StageConfig, len(request.GetStages()))
for _, s := range request.GetStages() {
requestStages[int(s.GetIndex())] = s
}

Check warning on line 284 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L279-L284

Added lines #L279 - L284 were not covered by tests

stages := make([]*model.PipelineStage, 0, len(response.Stages))
for _, s := range response.Stages {
// Find the corresponding stage in the request.
requestStage, ok := requestStages[s.Index]
if !ok {
return nil, status.Errorf(codes.Internal, "missing stage with index %d in the request, it's unexpected behavior of the plugin", s.Index)
}
id := requestStage.GetId()
if id == "" {
id = fmt.Sprintf("%s-stage-%d", plugin.Name(), s.Index)
}
stages = append(stages, &model.PipelineStage{
Id: id,
Name: s.Name,
Desc: requestStage.GetDesc(),
Index: int32(s.Index),
Status: model.StageStatus_STAGE_NOT_STARTED_YET,
StatusReason: "", // TODO: set the reason
Metadata: s.Metadata,
Rollback: s.Rollback,
CreatedAt: now.Unix(),
UpdatedAt: now.Unix(),
AvailableOperation: s.AvailableOperation.toModelEnum(),
})

Check warning on line 309 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L286-L309

Added lines #L286 - L309 were not covered by tests
}
return &deployment.BuildPipelineSyncStagesResponse{
Stages: stages,
}, nil

Check warning on line 313 in pkg/plugin/sdk/deployment.go

View check run for this annotation

Codecov / codecov/patch

pkg/plugin/sdk/deployment.go#L311-L313

Added lines #L311 - L313 were not covered by tests
}

// BuildPipelineSyncStagesRequest is the request to build pipeline sync stages.
// Rollback indicates whether the stages for rollback are requested.
type BuildPipelineSyncStagesRequest struct {
// Rollback indicates whether the stages for rollback are requested.
Rollback bool
// Stages contains the stage names and their configurations.
Stages []StageConfig
}

// StageConfig represents the configuration of a stage.
type StageConfig struct {
// Index is the order of the stage in the pipeline.
Index int
// Name is the name of the stage.
// It must be one of the stages returned by FetchDefinedStages.
Name string
// Config is the configuration of the stage.
// It should be marshaled to JSON bytes.
// The plugin should unmarshal it to the appropriate struct.
Config []byte
}

// BuildPipelineSyncStagesResponse is the response of the request to build pipeline sync stages.
type BuildPipelineSyncStagesResponse struct {
Stages []PipelineStage
}

// PipelineStage represents a stage in the pipeline.
type PipelineStage struct {
// Index is the order of the stage in the pipeline.
// The value must be one of the index of the stage in the request.
// The rollback stage should have the same index as the original stage.
Index int
// Name is the name of the stage.
// It must be one of the stages returned by FetchDefinedStages.
Name string
// Rollback indicates whether the stage is for rollback.
Rollback bool
// Metadata contains the metadata of the stage.
Metadata map[string]string
// AvailableOperation indicates the manual operation that the user can perform.
AvailableOperation ManualOperation
}