Skip to content

Commit fdc7e33

Browse files
authored
Merge branch 'master' into v1.6510.0
2 parents 5705007 + 416b188 commit fdc7e33

31 files changed

+9224
-5364
lines changed

cmd/scw/testdata/test-all-usage-iam-api-key-get-usage.golden

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ USAGE:
66
scw iam api-key get <access-key ...> [arg=value ...]
77

88
ARGS:
9-
access-key Access key to search for
9+
access-key Access key to search for
10+
[with-policies=true] Display the set of policies associated with the API key
1011

1112
FLAGS:
1213
-h, --help help for get

core/human/marshal.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ func Marshal(data interface{}, opt *MarshalOpt) (string, error) {
4545
}
4646

4747
rType := rValue.Type()
48-
4948
// safely get the marshalerFunc
5049
marshalerFunc, _ := getMarshalerFunc(rType)
5150
isNil := isInterfaceNil(data)
@@ -84,6 +83,9 @@ func Marshal(data interface{}, opt *MarshalOpt) (string, error) {
8483
case rType.Kind() == reflect.Struct:
8584
return marshalStruct(rValue, opt)
8685

86+
case rType.Kind() == reflect.Map:
87+
return MarshalMap(rValue, opt)
88+
8789
// by default we use defaultMarshalerFunc
8890
default:
8991
return defaultMarshalerFunc(rValue.Interface(), opt)
@@ -481,3 +483,40 @@ func getDefaultFieldsOpt(t reflect.Type) []*MarshalFieldOpt {
481483

482484
return results
483485
}
486+
487+
func MarshalMap(m reflect.Value, opt *MarshalOpt) (string, error) {
488+
buffer := bytes.Buffer{}
489+
490+
w := tabwriter.NewWriter(&buffer, 5, 1, colPadding, ' ', tabwriter.ANSIGraphicsRendition)
491+
492+
mapKeys := m.MapKeys()
493+
sort.Slice(mapKeys, func(i, j int) bool {
494+
return mapKeys[i].String() < mapKeys[j].String()
495+
})
496+
497+
for _, mapKey := range mapKeys {
498+
mapValue := m.MapIndex(mapKey)
499+
500+
if mapValue.Type().Kind() == reflect.Slice {
501+
sort.Slice(mapValue.Interface(), func(i, j int) bool {
502+
return mapValue.Index(i).String() < mapValue.Index(j).String()
503+
})
504+
sliceLen := mapValue.Len()
505+
values := make([]string, sliceLen)
506+
for i := range sliceLen {
507+
values[i] = fmt.Sprint(mapValue.Index(i).Interface())
508+
}
509+
fmt.Fprintf(w, "%s\t%s\n", mapKey.String(), strings.Join(values, " "))
510+
} else {
511+
content, err := Marshal(mapValue.Interface(), opt)
512+
if err != nil {
513+
return "", err
514+
}
515+
fmt.Fprintf(w, "%s\t%s\n", mapKey.String(), content)
516+
}
517+
}
518+
519+
w.Flush()
520+
521+
return strings.TrimSpace(buffer.String()), nil
522+
}

core/human/marshal_test.go

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,20 @@ import (
1414
)
1515

1616
type Struct struct {
17-
String string
18-
Int int
19-
Bool bool
20-
Strings []string
21-
Time time.Time
22-
Struct *Struct
23-
Nil *Struct
24-
Structs []*Struct
25-
Map map[string]string
26-
Stringer Stringer
27-
StringerPtr *Stringer
28-
Size *scw.Size
29-
Bytes []byte
17+
String string
18+
Int int
19+
Bool bool
20+
Strings []string
21+
Time time.Time
22+
Struct *Struct
23+
Nil *Struct
24+
Structs []*Struct
25+
Map map[string]string
26+
Stringer Stringer
27+
StringerPtr *Stringer
28+
Size *scw.Size
29+
Bytes []byte
30+
MapStringList map[string][]string
3031
}
3132

3233
type StructAny struct {
@@ -112,6 +113,77 @@ func TestMarshal(t *testing.T) {
112113
"key1": "v1",
113114
"key2": "v2",
114115
},
116+
MapStringList: map[string][]string{
117+
"key1": {"v1", "v2"},
118+
"key2": {"v3", "v4"},
119+
},
120+
Stringer: Stringer{},
121+
StringerPtr: &Stringer{},
122+
Size: scw.SizePtr(13200),
123+
Bytes: []byte{0, 1},
124+
},
125+
result: `
126+
String This is a string
127+
Int 42
128+
Bool true
129+
Strings.0 s1
130+
Strings.1 s2
131+
Time ` + humanDate + `
132+
Struct.String -
133+
Struct.Int 0
134+
Struct.Bool false
135+
Struct.Time a long while ago
136+
Struct.Stringer a stringer
137+
Structs.0.String Nested string
138+
Structs.0.Int 0
139+
Structs.0.Bool false
140+
Structs.0.Time a long while ago
141+
Structs.0.Stringer a stringer
142+
Map.key1 v1
143+
Map.key2 v2
144+
Stringer a stringer
145+
StringerPtr a stringer
146+
Size 13 kB
147+
Bytes AAE=
148+
MapStringList.key1.0 v1
149+
MapStringList.key1.1 v2
150+
MapStringList.key2.0 v3
151+
MapStringList.key2.1 v4
152+
`,
153+
}))
154+
155+
t.Run("structWithMapsInSection", run(&testCase{
156+
opt: &human.MarshalOpt{
157+
Sections: []*human.MarshalSection{
158+
{
159+
FieldName: "MapStringList",
160+
},
161+
{
162+
FieldName: "Map",
163+
},
164+
},
165+
},
166+
data: &Struct{
167+
String: "This is a string",
168+
Int: 42,
169+
Bool: true,
170+
Strings: []string{"s1", "s2"},
171+
Time: date,
172+
Struct: &Struct{},
173+
Nil: nil,
174+
Structs: []*Struct{
175+
{
176+
String: "Nested string",
177+
},
178+
},
179+
Map: map[string]string{
180+
"key1": "v1",
181+
"key2": "v2",
182+
},
183+
MapStringList: map[string][]string{
184+
"key1": {"v1", "v2"},
185+
"key2": {"v3", "v4"},
186+
},
115187
Stringer: Stringer{},
116188
StringerPtr: &Stringer{},
117189
Size: scw.SizePtr(13200),
@@ -123,7 +195,7 @@ func TestMarshal(t *testing.T) {
123195
Bool true
124196
Strings.0 s1
125197
Strings.1 s2
126-
Time ` + humanDate + `
198+
Time 34 years ago
127199
Struct.String -
128200
Struct.Int 0
129201
Struct.Bool false
@@ -134,12 +206,18 @@ func TestMarshal(t *testing.T) {
134206
Structs.0.Bool false
135207
Structs.0.Time a long while ago
136208
Structs.0.Stringer a stringer
137-
Map.key1 v1
138-
Map.key2 v2
139209
Stringer a stringer
140210
StringerPtr a stringer
141211
Size 13 kB
142212
Bytes AAE=
213+
214+
Map String List:
215+
key1 v1 v2
216+
key2 v3 v4
217+
218+
Map:
219+
key1 v1
220+
key2 v2
143221
`,
144222
}))
145223

@@ -338,7 +416,7 @@ func Test_getStructFieldsIndex(t *testing.T) {
338416
},
339417
),
340418
},
341-
want: [][]int{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}},
419+
want: [][]int{{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}},
342420
},
343421
}
344422
for _, tt := range tests {

core/testing.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,19 @@ func ExecStoreBeforeCmd(metaKey, cmd string) BeforeFunc {
590590
}
591591
}
592592

593+
// ExecStoreBeforeCmdWithResulter executes the given before command and register the result
594+
// in the context Meta at metaKey. The result is transformed by the resulter function.
595+
func ExecStoreBeforeCmdWithResulter(metaKey, cmd string, resulter func(any) any) BeforeFunc {
596+
return func(ctx *BeforeFuncCtx) error {
597+
args := cmdToArgs(ctx.Meta, cmd)
598+
ctx.Logger.Debugf("ExecStoreBeforeCmd: metaKey=%s args=%s\n", metaKey, args)
599+
result := ctx.ExecuteCmd(args)
600+
ctx.Meta[metaKey] = resulter(result)
601+
602+
return nil
603+
}
604+
}
605+
593606
func BeforeFuncOsExec(cmd string, args ...string) BeforeFunc {
594607
return func(ctx *BeforeFuncCtx) error {
595608
ctx.Logger.Debugf("BeforeFuncOsExec: cmd=%s args=%s\n", cmd, args)

core/testing_recorder.go

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,15 @@ import (
1818
func cassetteRequestFilter(i *cassette.Interaction) error {
1919
delete(i.Request.Headers, "x-auth-token")
2020
delete(i.Request.Headers, "X-Auth-Token")
21-
22-
orgIDRegex := regexp.MustCompile(`^organization_id=[0-9a-f-]{36}$`)
21+
orgIDRegex := regexp.MustCompile(`(.+)organization_id=[0-9a-f-]{36}(.+)`)
2322
tokenRegex := regexp.MustCompile(`^https://api\.scaleway\.com/account/v1/tokens/[0-9a-f-]{36}$`)
24-
apiKeyRegex := regexp.MustCompile(
25-
`^https://api\.scaleway\.com/iam/v1alpha1/api-keys/SCW[0-9A-Z]{17}$`,
26-
)
2723

2824
i.URL = orgIDRegex.ReplaceAllString(
2925
i.URL,
30-
"organization_id=11111111-1111-1111-1111-111111111111")
26+
"${1}organization_id=11111111-1111-1111-1111-111111111111${2}")
3127
i.URL = tokenRegex.ReplaceAllString(
3228
i.URL,
3329
"api.scaleway.com/account/v1/tokens/11111111-1111-1111-1111-111111111111")
34-
i.URL = apiKeyRegex.ReplaceAllString(
35-
i.URL,
36-
"api.scaleway.com/iam/v1alpha1/api-keys/SCWXXXXXXXXXXXXXXXXX")
3730

3831
return nil
3932
}

docs/commands/iam.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ scw iam api-key get <access-key ...> [arg=value ...]
135135
| Name | | Description |
136136
|------|---|-------------|
137137
| access-key | Required | Access key to search for |
138+
| with-policies | Default: `true` | Display the set of policies associated with the API key |
138139

139140

140141

docs/commands/index.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ You can use the CLI as you would run any Docker image:
6969
docker run -i --rm scaleway/cli:latest
7070
```
7171

72-
See more in-depth information about running the CLI in Docker [here](/docs/docker.md)
72+
See more in-depth information about running the CLI in Docker [here](https://github.com/scaleway/scaleway-cli/blob/master/docs/docker.md).
7373

7474
# Getting Started
7575

@@ -100,14 +100,14 @@ scw k8s cluster create name=foo version=1.17.4 pools.0.size=3 pools.0.node-type=
100100

101101
You can configure your config or enable functionalities with environment variables.
102102

103-
Variables to override config are describe in [config documentation](/docs/commands/config.md).
103+
Variables to override config are describe in [config documentation](https://cli.scaleway.com/config/).
104104
To enable beta features, you can set `SCW_ENABLE_BETA=1` in your environment.
105105

106106
## Build it yourself
107107

108108
### Build Locally
109109

110-
If you have a >= Go 1.13 environment, you can install the `HEAD` version to test the latest features or to [contribute](/.github/CONTRIBUTING.md).
110+
If you have a >= Go 1.13 environment, you can install the `HEAD` version to test the latest features or to [contribute](https://github.com/scaleway/scaleway-cli/blob/master/.github/CONTRIBUTING.md).
111111
Note that this development version could include bugs, use [tagged releases](https://github.com/scaleway/scaleway-cli/releases/latest) if you need stability.
112112

113113
```bash
@@ -130,12 +130,12 @@ Once built, you can then use the CLI as you would run any image:
130130
docker run -i --rm scaleway/cli
131131
```
132132

133-
See more in-depth information about running the CLI in Docker [here](/docs/docker.md)
133+
See more in-depth information about running the CLI in Docker [here](https://github.com/scaleway/scaleway-cli/blob/master/docs/docker.md)
134134

135135
# Development
136136

137137
This repository is at its early stage and is still in active development.
138-
If you are looking for a way to contribute please read [CONTRIBUTING.md](/.github/CONTRIBUTING.md).
138+
If you are looking for a way to contribute please read [CONTRIBUTING.md](https://github.com/scaleway/scaleway-cli/blob/master/.github/CONTRIBUTING.md).
139139

140140
# Reach Us
141141

internal/namespaces/file/v1alpha1/file_cli.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,8 @@ func fileFilesystemGet() *core.Command {
8989

9090
func fileFilesystemList() *core.Command {
9191
return &core.Command{
92-
Short: `List all filesystems`,
93-
Long: `Retrieve all filesystems in the specified region. Results are ordered by creation date in ascending order by default.
94-
Use the order_by parameter to modify the sorting behavior.`,
92+
Short: `List all filesystems`,
93+
Long: `Retrieve all filesystems in the specified region. By default, the filesystems listed are ordered by creation date in ascending order. This can be modified using the ` + "`" + `order_by` + "`" + ` field.`,
9594
Namespace: "file",
9695
Resource: "filesystem",
9796
Verb: "list",
@@ -120,7 +119,7 @@ Use the order_by parameter to modify the sorting behavior.`,
120119
},
121120
{
122121
Name: "name",
123-
Short: `Filter the return filesystems by their names`,
122+
Short: `Filter the returned filesystems by their names`,
124123
Required: false,
125124
Deprecated: false,
126125
Positional: false,
@@ -161,8 +160,7 @@ func fileAttachmentList() *core.Command {
161160
return &core.Command{
162161
Short: `List filesystems attachments`,
163162
Long: `List all existing attachments in a specified region.
164-
By default, the attachments listed are ordered by creation date in ascending order.
165-
This can be modified using the ` + "`" + `order_by` + "`" + ` field.`,
163+
By default, the attachments listed are ordered by creation date in ascending order. This can be modified using the ` + "`" + `order_by` + "`" + ` field.`,
166164
Namespace: "file",
167165
Resource: "attachment",
168166
Verb: "list",
@@ -229,7 +227,7 @@ This can be modified using the ` + "`" + `order_by` + "`" + ` field.`,
229227
func fileFilesystemCreate() *core.Command {
230228
return &core.Command{
231229
Short: `Create a new filesystem`,
232-
Long: `To create a new filesystem, you need to provide a name, a size, and a project ID.`,
230+
Long: `To create a new filesystem, you must specify a name, a size, and a project ID.`,
233231
Namespace: "file",
234232
Resource: "filesystem",
235233
Verb: "create",

internal/namespaces/iam/v1alpha1/custom.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ func GetCommands() *core.Commands {
5252
cmds.MustFind("iam", "policy", "create").Override(iamPolicyCreateBuilder)
5353
cmds.MustFind("iam", "policy", "get").Override(iamPolicyGetBuilder)
5454

55+
iamCmd := cmds.MustFind("iam", "api-key", "get")
56+
iamCmd.ArgsType = iamApiKeyCustomBuilder.argType
57+
iamCmd.ArgSpecs = iamApiKeyCustomBuilder.argSpecs
58+
iamCmd.Run = iamApiKeyCustomBuilder.run
59+
human.RegisterMarshalerFunc(apiKeyResponse{}, apiKeyMarshalerFunc)
60+
5561
return cmds
5662
}
5763

0 commit comments

Comments
 (0)