Skip to content

Commit 0ffc356

Browse files
authored
feat(registry): add configurable timeout for tag deletion (scaleway#5098)
1 parent df468d1 commit 0ffc356

11 files changed

+1095
-13
lines changed

cmd/scw/testdata/test-all-usage-registry-tag-delete-usage.golden

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ USAGE:
77

88
ARGS:
99
tag-id UUID of the tag
10+
[timeout] Maximum time to handle the request
1011
[region=fr-par] Region to target. If none is passed will use default region from the config (fr-par | nl-ams | pl-waw)
1112

1213
DEPRECATED ARGS:

core/testing.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,14 @@ func ExecBeforeCmdArgs(args []string) BeforeFunc {
679679
}
680680
}
681681

682+
// ExecBeforeCmdWithResult executes the given command and returns its result.
683+
func ExecBeforeCmdWithResult(ctx *BeforeFuncCtx, cmd string) any {
684+
args := cmdToArgs(ctx.Meta, cmd)
685+
ctx.Logger.Debugf("ExecBeforeCmd: args=%s\n", args)
686+
687+
return ctx.ExecuteCmd(args)
688+
}
689+
682690
// ExecAfterCmd executes the given before command.
683691
func ExecAfterCmd(cmd string) AfterFunc {
684692
return func(ctx *AfterFuncCtx) error {

docs/commands/registry.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ scw registry tag delete <tag-id ...> [arg=value ...]
332332
| Name | | Description |
333333
|------|---|-------------|
334334
| tag-id | Required | UUID of the tag |
335+
| timeout | | Maximum time to handle the request |
335336
| ~~force~~ | Deprecated | If two tags share the same digest the deletion will fail unless this parameter is set to true (deprecated) |
336337
| region | Default: `fr-par`<br />One of: `fr-par`, `nl-ams`, `pl-waw` | Region to target. If none is passed will use default region from the config |
337338

internal/namespaces/registry/v1/custom.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func GetCommands() *core.Commands {
2727
registryInstallDockerHelperCommand(),
2828
))
2929

30+
cmds.MustFind("registry", "tag", "delete").Override(tagDeleteBuilder)
3031
cmds.MustFind("registry", "tag", "get").Override(tagGetBuilder)
3132
cmds.MustFind("registry", "tag", "list").Override(tagListBuilder)
3233

internal/namespaces/registry/v1/custom_tag.go

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ package registry
33
import (
44
"context"
55
"fmt"
6+
"reflect"
7+
"time"
68

79
"github.com/fatih/color"
810
"github.com/scaleway/scaleway-cli/v2/core"
911
"github.com/scaleway/scaleway-cli/v2/core/human"
1012
"github.com/scaleway/scaleway-sdk-go/api/registry/v1"
1113
"github.com/scaleway/scaleway-sdk-go/logger"
14+
"github.com/scaleway/scaleway-sdk-go/scw"
1215
)
1316

1417
//
@@ -25,7 +28,7 @@ var (
2528
}
2629
)
2730

28-
type customTag struct {
31+
type CustomTag struct {
2932
registry.Tag
3033
FullName string
3134
}
@@ -59,7 +62,7 @@ func tagGetBuilder(c *core.Command) *core.Command {
5962
return getTagResp, nil
6063
}
6164

62-
res := customTag{
65+
res := CustomTag{
6366
Tag: *tag,
6467
FullName: fmt.Sprintf("%s/%s:%s", namespace.Endpoint, image.Name, tag.Name),
6568
}
@@ -112,9 +115,9 @@ func tagListBuilder(c *core.Command) *core.Command {
112115
return listTagResp, err
113116
}
114117

115-
var customRes []customTag
118+
var customRes []CustomTag
116119
for _, tag := range listTagResp.([]*registry.Tag) {
117-
customRes = append(customRes, customTag{
120+
customRes = append(customRes, CustomTag{
118121
Tag: *tag,
119122
FullName: fmt.Sprintf("%s/%s:%s",
120123
namespace.Endpoint,
@@ -129,3 +132,40 @@ func tagListBuilder(c *core.Command) *core.Command {
129132

130133
return c
131134
}
135+
136+
type customTagDeleteArgs struct {
137+
registry.DeleteTagRequest
138+
Timeout *string
139+
}
140+
141+
func tagDeleteBuilder(c *core.Command) *core.Command {
142+
c.ArgsType = reflect.TypeOf(customTagDeleteArgs{})
143+
c.ArgSpecs.AddBefore("force", &core.ArgSpec{
144+
Name: "timeout",
145+
Short: "Maximum time to handle the request",
146+
Required: false,
147+
Positional: false,
148+
})
149+
150+
c.Run = func(ctx context.Context, argsI any) (any, error) {
151+
client := core.ExtractClient(ctx)
152+
api := registry.NewAPI(client)
153+
args := argsI.(*customTagDeleteArgs)
154+
155+
if args.Timeout == nil {
156+
return api.DeleteTag(&args.DeleteTagRequest, scw.WithContext(ctx))
157+
}
158+
159+
timeout, err := time.ParseDuration(*args.Timeout)
160+
if err != nil {
161+
return nil, err
162+
}
163+
164+
ctxWithTimeout, cancel := context.WithTimeout(ctx, timeout)
165+
defer cancel()
166+
167+
return api.DeleteTag(&args.DeleteTagRequest, scw.WithContext(ctxWithTimeout))
168+
}
169+
170+
return c
171+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package registry_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/scaleway/scaleway-cli/v2/core"
8+
"github.com/scaleway/scaleway-cli/v2/internal/namespaces/registry/v1"
9+
"github.com/scaleway/scaleway-cli/v2/internal/testhelpers"
10+
)
11+
12+
func Test_RegistryTagDelete(t *testing.T) {
13+
registryNamespaceMetaKey := "RegistryNamespace"
14+
helloWorldImage := "hello-world:latest"
15+
helloWorldImageMetaKey := "HelloWorldImage"
16+
tagIDMetaKey := "TagID"
17+
18+
t.Run("simple", core.Test(&core.TestConfig{
19+
Commands: registry.GetCommands(),
20+
BeforeFunc: core.BeforeFuncCombine(
21+
core.ExecStoreBeforeCmd(
22+
registryNamespaceMetaKey,
23+
fmt.Sprintf("scw registry namespace create name=%s is-public=false",
24+
core.GetRandomName("test-rg-tag-delete"),
25+
),
26+
),
27+
core.BeforeFuncWhenUpdatingCassette(
28+
core.BeforeFuncCombine(
29+
core.ExecBeforeCmd("scw registry login"),
30+
testhelpers.PushRegistryImage(helloWorldImage, registryNamespaceMetaKey),
31+
),
32+
),
33+
testhelpers.StoreImageIdentifierInMeta(
34+
registryNamespaceMetaKey,
35+
helloWorldImage,
36+
helloWorldImageMetaKey,
37+
),
38+
testhelpers.StoreTagIDInMeta(registryNamespaceMetaKey, helloWorldImage, tagIDMetaKey),
39+
),
40+
Cmd: fmt.Sprintf("scw registry tag delete {{ .%s }}", tagIDMetaKey),
41+
Check: core.TestCheckCombine(
42+
core.TestCheckGolden(),
43+
core.TestCheckExitCode(0),
44+
),
45+
AfterFunc: func(ctx *core.AfterFuncCtx) error {
46+
return core.ExecAfterCmd(
47+
fmt.Sprintf(
48+
"scw registry namespace delete {{ .%s.ID }}",
49+
registryNamespaceMetaKey,
50+
),
51+
)(
52+
ctx,
53+
)
54+
},
55+
}))
56+
57+
t.Run("timeout-ok", core.Test(&core.TestConfig{
58+
Commands: registry.GetCommands(),
59+
BeforeFunc: core.BeforeFuncCombine(
60+
core.ExecStoreBeforeCmd(
61+
registryNamespaceMetaKey,
62+
fmt.Sprintf("scw registry namespace create name=%s is-public=false",
63+
core.GetRandomName("test-rg-tag-delete"),
64+
),
65+
),
66+
core.BeforeFuncWhenUpdatingCassette(
67+
core.BeforeFuncCombine(
68+
core.ExecBeforeCmd("scw registry login"),
69+
testhelpers.PushRegistryImage(helloWorldImage, registryNamespaceMetaKey),
70+
),
71+
),
72+
testhelpers.StoreImageIdentifierInMeta(
73+
registryNamespaceMetaKey,
74+
helloWorldImage,
75+
helloWorldImageMetaKey,
76+
),
77+
testhelpers.StoreTagIDInMeta(registryNamespaceMetaKey, helloWorldImage, tagIDMetaKey),
78+
),
79+
Cmd: fmt.Sprintf("scw registry tag delete {{ .%s }} timeout=1s", tagIDMetaKey),
80+
Check: core.TestCheckCombine(
81+
core.TestCheckGolden(),
82+
core.TestCheckExitCode(0),
83+
),
84+
AfterFunc: func(ctx *core.AfterFuncCtx) error {
85+
return core.ExecAfterCmd(
86+
fmt.Sprintf(
87+
"scw registry namespace delete {{ .%s.ID }}",
88+
registryNamespaceMetaKey,
89+
),
90+
)(
91+
ctx,
92+
)
93+
},
94+
}))
95+
}

0 commit comments

Comments
 (0)