Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch CLI parser from kingpin to kong. #455

Merged
merged 12 commits into from
Nov 7, 2022
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 appspec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import (
)

type AppSpecOption struct {
TaskDefinition *string
UpdateService *bool
TaskDefinition *string `help:"use task definition arn in AppSpec (latest, current or Arn)" default:"latest"`
UpdateService *bool `help:"update service definition with task definition arn" default:"true" negatable:""`
}

func (d *App) AppSpec(ctx context.Context, opt AppSpecOption) error {
Expand Down
208 changes: 104 additions & 104 deletions cli.go

Large diffs are not rendered by default.

70 changes: 51 additions & 19 deletions cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ var cliTests = []struct {
Events: ptr(10),
},
},
{
args: []string{
"--envfile", "tests/envfile",
"status",
"--envfile", "tests/envfile2",
},
sub: "status",
fn: func(t *testing.T) {
if v := os.Getenv("ECSPRESSO_TEST"); v != "ok2" {
t.Errorf("unexpected ECSPRESSO_TEST expected: %s, got: %s", "ok2", v)
}
if v := os.Getenv("ECSPRESSO_TEST2"); v != "ok2" {
t.Errorf("unexpected ECSPRESSO_TEST2 expected: %s, got: %s", "ok2", v)
}
},
},
{
args: []string{"status"},
sub: "status",
Expand Down Expand Up @@ -117,7 +133,8 @@ var cliTests = []struct {
args: []string{"deploy", "--resume-auto-scaling"},
sub: "deploy",
subOption: &ecspresso.DeployOption{
SuspendAutoScaling: ptr(false),
SuspendAutoScaling: nil,
ResumeAutoScaling: ptr(true),
DryRun: ptr(false),
DesiredCount: ptr(int32(-1)),
SkipTaskDefinition: ptr(false),
Expand All @@ -133,6 +150,7 @@ var cliTests = []struct {
sub: "deploy",
subOption: &ecspresso.DeployOption{
SuspendAutoScaling: ptr(true),
ResumeAutoScaling: nil,
DryRun: ptr(false),
DesiredCount: ptr(int32(-1)),
SkipTaskDefinition: ptr(false),
Expand All @@ -146,27 +164,18 @@ var cliTests = []struct {
{
args: []string{"scale", "--tasks=5"},
sub: "scale",
subOption: &ecspresso.DeployOption{
DryRun: ptr(false),
DesiredCount: ptr(int32(5)),
SkipTaskDefinition: ptr(true),
ForceNewDeployment: ptr(false),
NoWait: ptr(false),
UpdateService: ptr(false),
LatestTaskDefinition: ptr(false),
subOption: &ecspresso.ScaleOption{
DryRun: ptr(false),
DesiredCount: ptr(int32(5)),
NoWait: ptr(false),
},
},
{
args: []string{"refresh"},
sub: "refresh",
subOption: &ecspresso.DeployOption{
DryRun: ptr(false),
DesiredCount: nil,
SkipTaskDefinition: ptr(true),
ForceNewDeployment: ptr(true),
NoWait: ptr(false),
UpdateService: ptr(false),
LatestTaskDefinition: ptr(false),
subOption: &ecspresso.RefreshOption{
DryRun: ptr(false),
NoWait: ptr(false),
},
},
{
Expand Down Expand Up @@ -509,6 +518,29 @@ func TestParseCLI(t *testing.T) {
}
}

func ptr[T any](v T) *T {
return &v
func TestParseCLIv2(t *testing.T) {
for _, tt := range cliTests {
t.Run(strings.Join(tt.args, "_"), func(t *testing.T) {
sub, opt, err := ecspresso.ParseCLIv2(tt.args)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if sub != tt.sub {
t.Errorf("unexpected subcommand: expected %s, got %s", tt.sub, sub)
}
if tt.option != nil {
if diff := cmp.Diff(tt.option, opt.Option); diff != "" {
t.Errorf("unexpected option: diff %s", diff)
}
}
if tt.subOption != nil {
if diff := cmp.Diff(opt.ForSubCommand(sub), tt.subOption); diff != "" {
t.Errorf("unexpected subOption: diff %s", diff)
}
}
if tt.fn != nil {
tt.fn(t)
}
})
}
}
51 changes: 51 additions & 0 deletions cliv2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ecspresso

import (
"fmt"
"strings"

"github.com/alecthomas/kong"
)

func ParseCLIv2(args []string) (string, *CLIOptions, error) {
// compatible with v1
if len(args) == 0 || len(args) > 0 && args[0] == "help" {
args = []string{"--help"}
}

var opts CLIOptions
parser, err := kong.New(&opts, kong.Vars{"version": Version})
if err != nil {
return "", nil, fmt.Errorf("failed to new kong: %w", err)
}
c, err := parser.Parse(args)
if err != nil {
return "", nil, fmt.Errorf("failed to parse args: %w", err)
}
sub := strings.Fields(c.Command())[0]

for _, envFile := range opts.Envfile {
if err := ExportEnvFile(envFile); err != nil {
return sub, &opts, fmt.Errorf("failed to load envfile: %w", err)
}
}

opts.Option = &Option{
ConfigFilePath: opts.Config,
Debug: opts.Debug,
ExtStr: opts.ExtStr,
ExtCode: opts.ExtCode,
}
if opts.Option.ExtStr == nil {
opts.Option.ExtStr = map[string]string{}
}
if opts.Option.ExtCode == nil {
opts.Option.ExtCode = map[string]string{}
}
switch sub {
case "init":
opts.Init.ConfigFilePath = &opts.Config
opts.Option.InitOption = opts.Init
}
return sub, &opts, nil
}
9 changes: 8 additions & 1 deletion cmd/ecspresso/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ func main() {
ecspresso.Version = Version
ctx, stop := signal.NotifyContext(context.Background(), trapSignals...)
defer stop()
exitCode, err := ecspresso.CLI(ctx)

// switch cli parser
parse := ecspresso.ParseCLIv2
if v1 := os.Getenv("V1"); v1 != "" {
parse = ecspresso.ParseCLI
}

exitCode, err := ecspresso.CLI(ctx, parse)
if err != nil {
if errors.Is(err, context.Canceled) {
ecspresso.Log("[WARNING] Interrupted")
Expand Down
4 changes: 2 additions & 2 deletions delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
)

type DeleteOption struct {
DryRun *bool
Force *bool
DryRun *bool `help:"dry-run" default:"false"`
Force *bool `help:"delete without confirmation" default:"false"`
}

func (opt DeleteOption) DryRunString() string {
Expand Down
21 changes: 12 additions & 9 deletions deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ const (
)

type DeployOption struct {
DryRun *bool
DesiredCount *int32
SkipTaskDefinition *bool
ForceNewDeployment *bool
NoWait *bool
SuspendAutoScaling *bool
RollbackEvents *string
UpdateService *bool
LatestTaskDefinition *bool
DryRun *bool `help:"dry run" default:"false"`
DesiredCount *int32 `name:"tasks" help:"desired count of tasks" default:"-1"`
SkipTaskDefinition *bool `help:"skip register a new task definition" default:"false"`
ForceNewDeployment *bool `help:"force a new deployment of the service" default:"false"`
NoWait *bool `help:"exit ecspresso immediately after just deployed without waiting for service stable" default:"false"`
SuspendAutoScaling *bool `help:"suspend application auto-scaling attached with the ECS service"`
ResumeAutoScaling *bool `help:"resume application auto-scaling attached with the ECS service"`
RollbackEvents *string `help:"roll back when specified events happened (DEPLOYMENT_FAILURE,DEPLOYMENT_STOP_ON_ALARM,DEPLOYMENT_STOP_ON_REQUEST,...) CodeDeploy only." default:""`
UpdateService *bool `help:"update service attributes by service definition" default:"true" negatable:""`
LatestTaskDefinition *bool `help:"deploy with the latest task definition without registering a new task definition" default:"false"`
}

func (opt DeployOption) DryRunString() string {
Expand All @@ -56,6 +57,8 @@ func calcDesiredCount(sv *Service, opt DeployOption) *int32 {
}

func (d *App) Deploy(ctx context.Context, opt DeployOption) error {
d.Log("[DEBUG] deploy")
d.LogJSON(opt)
ctx, cancel := d.Start(ctx)
defer cancel()

Expand Down
8 changes: 4 additions & 4 deletions deregister.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import (
)

type DeregisterOption struct {
DryRun *bool
Keeps *int
Revision *int64
Force *bool
DryRun *bool `help:"dry run" default:"false"`
Keeps *int `help:"number of task definitions to keep except in-use" default:"0"`
Revision *int64 `help:"task definition revision to deregister" default:"0"`
Force *bool `help:"force deregister without confirmation" default:"false"`
}

func (opt DeregisterOption) DryRunString() string {
Expand Down
2 changes: 1 addition & 1 deletion diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
)

type DiffOption struct {
Unified *bool
Unified *bool `help:"unified diff format" default:"true" negatable:""`
}

func (d *App) Diff(ctx context.Context, opt DiffOption) error {
Expand Down
13 changes: 10 additions & 3 deletions ecspresso.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ var Version string
var delayForServiceChanged = 3 * time.Second
var spcIndent = " "

func ptr[T any](v T) *T {
return &v
}

type TaskDefinition = types.TaskDefinition

type TaskDefinitionInput = ecs.RegisterTaskDefinitionInput
Expand Down Expand Up @@ -142,7 +146,6 @@ type Option struct {
func (opt *Option) resolveDefaultConfigFilePath() (path string) {
path = DefaultConfigFilePath
defer func() {
log.Println("resolved config file path:", path)
opt.ConfigFilePath = path
if opt.InitOption != nil {
opt.InitOption.ConfigFilePath = &path
Expand Down Expand Up @@ -192,8 +195,12 @@ func (d *App) DescribeService(ctx context.Context) (*Service, error) {
if len(out.Services) == 0 {
return nil, ErrNotFound(fmt.Sprintf("service %s is not found", d.Service))
}
if s := aws.ToString(out.Services[0].Status); s == "INACTIVE" {
return nil, ErrNotFound(fmt.Sprintf("service %s is %s", d.Service, s))
status := aws.ToString(out.Services[0].Status)
switch status {
case "DRAINING":
d.Log("[WARNING] service %s is %s", d.Service, status)
case "INACTIVE":
return nil, ErrNotFound(fmt.Sprintf("service %s is %s", d.Service, status))
}
return newServiceFromTypes(out.Services[0]), nil
}
Expand Down
4 changes: 4 additions & 0 deletions ecspresso_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import (
"github.com/kayac/ecspresso"
)

func ptr[T any](v T) *T {
return &v
}

func TestLoadTaskDefinition(t *testing.T) {
ctx := context.Background()
for _, path := range []string{
Expand Down
12 changes: 6 additions & 6 deletions exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import (
)

type ExecOption struct {
ID *string
Command *string
Container *string
ID *string `help:"task ID" default:""`
Command *string `help:"command to execute" default:"sh"`
Container *string `help:"container name" default:""`

PortForward *bool
LocalPort *int
Port *int
PortForward *bool `help:"enable port forward" default:"false"`
LocalPort *int `help:"local port number" default:"0"`
Port *int `help:"remote port number (required for --port-forward)" default:"0"`
}

func (d *App) NewEcsta(ctx context.Context) (*ecsta.Ecsta, error) {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.18
require (
github.com/Songmu/prompter v0.5.1
github.com/alecthomas/kingpin v1.3.8-0.20190930021037-0a108b7f5563
github.com/alecthomas/kong v0.7.0
github.com/aws/aws-sdk-go-v2 v1.16.16
github.com/aws/aws-sdk-go-v2/config v1.17.7
github.com/aws/aws-sdk-go-v2/credentials v1.12.20
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,12 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Songmu/prompter v0.5.1 h1:IAsttKsOZWSDw7bV1mtGn9TAmLFAjXbp9I/eYmUUogo=
github.com/Songmu/prompter v0.5.1/go.mod h1:CS3jEPD6h9IaLaG6afrl1orTgII9+uDWuw95dr6xHSw=
github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0=
github.com/alecthomas/kingpin v1.3.8-0.20190930021037-0a108b7f5563 h1:en74MYF4/T3bxeT3QRhSSlv3LT54JEunh7Q1BupAimc=
github.com/alecthomas/kingpin v1.3.8-0.20190930021037-0a108b7f5563/go.mod h1:idxgS9pV6OOpAhZvx+gcoGRMX9/tt0iqkw/pNxI0C14=
github.com/alecthomas/kong v0.7.0 h1:YIjJUiR7AcmHxL87UlbPn0gyIGwl4+nYND0OQ4ojP7k=
github.com/alecthomas/kong v0.7.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
Expand Down
14 changes: 7 additions & 7 deletions init.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ import (
var CreateFileMode = os.FileMode(0644)

type InitOption struct {
Region *string
Cluster *string
Service *string
TaskDefinitionPath *string
ServiceDefinitionPath *string
Region *string `help:"AWS region" env:"AWS_REGION" default:""`
Cluster *string `help:"ECS cluster name" default:"default"`
Service *string `help:"ECS service name" default:"" required:""`
TaskDefinitionPath *string `help:"path to output task definition file" default:"ecs-task-def.json"`
ServiceDefinitionPath *string `help:"path to output service definition file" default:"ecs-service-def.json"`
ConfigFilePath *string
ForceOverwrite *bool
Jsonnet *bool
ForceOverwrite *bool `help:"overwrite existing files" default:"false"`
Jsonnet *bool `help:"output files as jsonnet format" default:"false"`
}

func (opt *InitOption) NewConfig(ctx context.Context) (*Config, error) {
Expand Down
2 changes: 1 addition & 1 deletion logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ func (d *App) LogJSON(v interface{}) {
d.logger.Printf("[WARNING] failed to marshal json: %s", err)
return
}
d.logger.Println("[INFO] " + string(b))
d.logger.Println("[DEBUG] " + string(b))
}
19 changes: 19 additions & 0 deletions refresh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ecspresso

type RefreshOption struct {
DryRun *bool `help:"dry run" default:"false"`
NoWait *bool `help:"exit ecspresso immediately after just deployed without waiting for service stable" default:"false"`
}

func (o *RefreshOption) DeployOption() DeployOption {
return DeployOption{
DryRun: o.DryRun,
DesiredCount: nil,
SkipTaskDefinition: ptr(true),
ForceNewDeployment: ptr(true),
NoWait: o.NoWait,
RollbackEvents: ptr(""),
UpdateService: ptr(false),
LatestTaskDefinition: ptr(false),
}
}
Loading