Skip to content
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
c24329a
Add pipectl init command but not implemented
t-kikuc Dec 22, 2023
6170b7d
Modify init command
t-kikuc Dec 24, 2023
30f7554
Rename init command to initialize
t-kikuc Dec 24, 2023
419aa6b
Create pipectl int for ECS
t-kikuc Dec 25, 2023
546e2cd
Add init for ECS
t-kikuc Dec 25, 2023
4141bbf
Convert json.RawMessage to struct
t-kikuc Dec 26, 2023
d877787
Use original structs of ECS for pipectl init
t-kikuc Dec 26, 2023
4097fb7
Init k8s app for pipectl init, but not implemented
t-kikuc Dec 26, 2023
e4d71d2
Fix init input(wip)
t-kikuc Dec 27, 2023
608c91e
Add mock prompt reader
t-kikuc Dec 27, 2023
a819e97
Reractor prompt reader
t-kikuc Dec 27, 2023
3e813b7
Modify mock reader to public
t-kikuc Dec 27, 2023
c9ef764
Refactored prompt reader
t-kikuc Dec 27, 2023
6b18136
Add yaml snapshot test
t-kikuc Dec 27, 2023
757b637
Revert "Init k8s app for pipectl init, but not implemented"
t-kikuc Dec 27, 2023
299c464
Refactor pipectl init
t-kikuc Dec 27, 2023
85184b2
Remove go-yaml from go.mod
t-kikuc Dec 27, 2023
0efa6ea
Modify tests to Parallel
t-kikuc Dec 27, 2023
32c41e2
Fix reference of loop variable in tests
t-kikuc Dec 27, 2023
f3f121f
Enable interruption signal for pipectl init
t-kikuc Dec 27, 2023
6c1182f
Add LoadBalancerName to ECS TargetGroup
t-kikuc Dec 28, 2023
9fb9056
Merge branch 'master' into pipectl-init-ecs
t-kikuc Jan 4, 2024
02cd0bf
Use Reader in tests
t-kikuc Jan 9, 2024
cb6dab2
Remove stdinReader
t-kikuc Jan 9, 2024
bd35685
Remove mockReader
t-kikuc Jan 9, 2024
4813398
Add Prompt and PromptInput types
t-kikuc Jan 10, 2024
4800de6
Remove promptReader
t-kikuc Jan 10, 2024
8081826
Refactored init,exporter
t-kikuc Jan 11, 2024
77c8c92
Update Copyright
t-kikuc Jan 11, 2024
76f89d0
Refactored nits
t-kikuc Jan 11, 2024
cf7dfa4
Add reference to the blog that shows how to install control plane on …
ffjlabo Jan 10, 2024
8b95253
Bump follow-redirects from 1.15.2 to 1.15.4 in /web (#4747)
dependabot[bot] Jan 15, 2024
e797d9b
Add RC Release Procedure (#4749)
t-kikuc Jan 15, 2024
2714de4
Merge branch 'master' of https://github.com/pipe-cd/pipecd into pipec…
t-kikuc Jan 19, 2024
85814be
Fix nits
t-kikuc Jan 19, 2024
2a4339a
Fix error variable name
t-kikuc Jan 19, 2024
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
2 changes: 2 additions & 0 deletions cmd/pipectl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/deployment"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/encrypt"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/event"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/initialize"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/piped"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/planpreview"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/cmd/quickstart"
Expand All @@ -41,6 +42,7 @@ func main() {
piped.NewCommand(),
encrypt.NewCommand(),
quickstart.NewCommand(),
initialize.NewCommand(),
)

if err := app.Run(); err != nil {
Expand Down
99 changes: 99 additions & 0 deletions pkg/app/pipectl/cmd/initialize/ecs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2024 The PipeCD Authors.
//
// 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 initialize

import (
"github.com/pipe-cd/pipecd/pkg/app/pipectl/prompt"
"github.com/pipe-cd/pipecd/pkg/config"
)

// Use genericConfigs in order to simplify using the GenericApplicationSpec and keep the order as we want.
type genericECSApplicationSpec struct {
Name string `json:"name"`
Input config.ECSDeploymentInput `json:"input"`
Description string `json:"description,omitempty"`
}

func generateECSConfig(p prompt.Prompt) (*genericConfig, error) {
// inputs
var (
appName string
serviceDefFile string
taskDefFile string
targetGroupArn string
containerName string
containerPort int
)
inputs := []prompt.Input{
{
Message: "Name of the application",
TargetPointer: &appName,
Required: true,
},
{
Message: "Name of the service definition file (e.g. serviceDef.yaml)",
TargetPointer: &serviceDefFile,
Required: true,
},
{
Message: "Name of the task definition file (e.g. taskDef.yaml)",
TargetPointer: &taskDefFile,
Required: true,
},
// target group inputs
{
Message: "ARN of the target group to the service",
TargetPointer: &targetGroupArn,
Required: false,
},
{
Message: "Name of the container of the target group",
TargetPointer: &containerName,
Required: false,
},
{
Message: "Port number of the container of the target group",
TargetPointer: &containerPort,
Required: false,
},
}

err := p.RunSlice(inputs)
if err != nil {
return nil, err
}

spec := &genericECSApplicationSpec{
Name: appName,
Input: config.ECSDeploymentInput{
ServiceDefinitionFile: serviceDefFile,
TaskDefinitionFile: taskDefFile,
TargetGroups: config.ECSTargetGroups{
Primary: &config.ECSTargetGroup{
TargetGroupArn: targetGroupArn,
ContainerName: containerName,
ContainerPort: containerPort,
},
},
},
Description: "Generated by `pipectl init`. See https://pipecd.dev/docs/user-guide/configuration-reference/ for more.",
}

return &genericConfig{
Kind: config.KindECSApp,
APIVersion: config.VersionV1Beta1,
ApplicationSpec: spec,
}, nil
}
84 changes: 84 additions & 0 deletions pkg/app/pipectl/cmd/initialize/ecs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright 2024 The PipeCD Authors.
//
// 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 initialize

import (
"os"
"strings"
"testing"

"github.com/goccy/go-yaml"
"github.com/stretchr/testify/assert"

"github.com/pipe-cd/pipecd/pkg/app/pipectl/prompt"
"github.com/pipe-cd/pipecd/pkg/config"
)

func TestGenerateECSConfig(t *testing.T) {
t.Parallel()

testcases := []struct {
name string
inputs string // mock for user's input
expectedFile string
expectedErr bool
}{
{
name: "valid inputs",
inputs: `myApp
serviceDef.yaml
taskDef.yaml
arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/xxx/xxx
web
80
`,
expectedFile: "testdata/ecs-app.yaml",
expectedErr: false,
},
{
name: "missing required",
inputs: `myApp
serviceDef.yaml
`,
expectedFile: "",
expectedErr: true,
},
Comment on lines +36 to +57

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] Add testcase for failed case 👀

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I added a failure case.

}

for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
Comment on lines +50 to +62

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] add tc := tc

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I fixed with adding T.Parallel()

reader := strings.NewReader(tc.inputs)
prompt := prompt.NewPrompt(reader)

// Generate the config
cfg, err := generateECSConfig(prompt)
assert.Equal(t, tc.expectedErr, err != nil)

if err == nil {
// Compare the YAML output
yml, err := yaml.Marshal(cfg)
assert.NoError(t, err)
file, err := os.ReadFile(tc.expectedFile)
assert.NoError(t, err)
assert.Equal(t, string(file), string(yml))

// Check if the YAML output is compatible with the original Config model
_, err = config.DecodeYAML(yml)
assert.NoError(t, err)
}
})
}
}
160 changes: 160 additions & 0 deletions pkg/app/pipectl/cmd/initialize/initialize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// Copyright 2024 The PipeCD Authors.
//
// 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 initialize

import (
"context"
"fmt"
"os"
"os/signal"
"syscall"

"github.com/goccy/go-yaml"
"github.com/spf13/cobra"

"github.com/pipe-cd/pipecd/pkg/app/pipectl/exporter"
"github.com/pipe-cd/pipecd/pkg/app/pipectl/prompt"
"github.com/pipe-cd/pipecd/pkg/cli"
"github.com/pipe-cd/pipecd/pkg/config"
)

type command struct {
// Add flags if needed.
}

const (
platformKubernetes string = "0"
platformECS string = "1"
)
Comment on lines +37 to +41

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] Add comments :)


// Use genericConfigs in order to simplify using the spec.
type genericConfig struct {
APIVersion string `json:"apiVersion"`
Kind config.Kind `json:"kind"`
ApplicationSpec interface{} `json:"spec"`
}

func NewCommand() *cobra.Command {
c := &command{}
cmd := &cobra.Command{
Use: "init",
Short: "Generate a app.pipecd.yaml easily and interactively",
Example: ` pipectl init`,
Long: "Generate a app.pipecd.yaml easily, interactively selecting options.",
RunE: cli.WithContext(c.run),
}

return cmd
}

func (c *command) run(ctx context.Context, input cli.Input) error {
// Enable interrupt signal.
ctx, cancel := context.WithCancel(ctx)
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt, syscall.SIGHUP, syscall.SIGTERM)

defer func() {
signal.Stop(signals)
cancel()
}()

go func() {
select {
case s := <-signals:
fmt.Printf("Interrupted by signal: %v\n", s)
cancel()
os.Exit(1)
case <-ctx.Done():
}
}()

p := prompt.NewPrompt(os.Stdin)
return generateConfig(ctx, input, p)
}

func generateConfig(ctx context.Context, input cli.Input, p prompt.Prompt) error {
// user's inputs
var (
platform string
exportPath string
)

platformInput := prompt.Input{
Message: fmt.Sprintf("Which platform? Enter the number [%s]Kubernetes [%s]ECS", platformKubernetes, platformECS),
TargetPointer: &platform,
Required: true,
}
exportPathInput := prompt.Input{
Message: "Path to save the config (if not specified, it goes to stdout)",
TargetPointer: &exportPath,
Required: false,
}

err := p.Run(platformInput)
if err != nil {
return fmt.Errorf("invalid platform number: %v", err)
}

var cfg *genericConfig
switch platform {
case platformKubernetes:
panic("not implemented")
case platformECS:
cfg, err = generateECSConfig(p)
default:
return fmt.Errorf("invalid platform number: %s", platform)
}

if err != nil {
return err
}

cfgBytes, err := yaml.Marshal(cfg)
if err != nil {
return err
}

fmt.Println("### The config model was successfully prepared. Move on to exporting. ###")
err = p.Run(exportPathInput)
if err != nil {
printConfig(cfgBytes)
return err
}
err = export(cfgBytes, exportPath)
if err != nil {
return nil
}

return nil
}

func export(cfgBytes []byte, exportPath string) error {
if len(exportPath) == 0 {
// if the path is not specified, print to stdout
printConfig(cfgBytes)
return nil
}
err := exporter.Export(cfgBytes, exportPath)
if err != nil {
printConfig(cfgBytes)
return err
}
return nil
}

// Print the config to stdout.
func printConfig(configBytes []byte) {
fmt.Printf("\n### Generated Config is below ###\n%s\n", string(configBytes))
}
13 changes: 13 additions & 0 deletions pkg/app/pipectl/cmd/initialize/testdata/ecs-app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: pipecd.dev/v1beta1
kind: ECSApp
spec:
name: myApp
input:
serviceDefinitionFile: serviceDef.yaml
taskDefinitionFile: taskDef.yaml
targetGroups:
primary:
targetGroupArn: arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:targetgroup/xxx/xxx
containerName: web
containerPort: 80
description: Generated by `pipectl init`. See https://pipecd.dev/docs/user-guide/configuration-reference/ for more.
Loading