Skip to content
This repository was archived by the owner on May 26, 2023. It is now read-only.

Commit 4ed7c7e

Browse files
committed
add set command to modify comp desc
1 parent 4ff44b4 commit 4ed7c7e

File tree

6 files changed

+255
-7
lines changed

6 files changed

+255
-7
lines changed

pkg/commands/componentarchive/componentarchive.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/gardener/component-cli/pkg/commands/componentarchive/componentreferences"
2222
"github.com/gardener/component-cli/pkg/commands/componentarchive/remote"
2323
"github.com/gardener/component-cli/pkg/commands/componentarchive/resources"
24+
"github.com/gardener/component-cli/pkg/commands/componentarchive/set"
2425
"github.com/gardener/component-cli/pkg/commands/componentarchive/sources"
2526
ctfcmd "github.com/gardener/component-cli/pkg/commands/ctf"
2627
"github.com/gardener/component-cli/pkg/componentarchive"
@@ -74,6 +75,7 @@ func NewComponentArchiveCommand(ctx context.Context) *cobra.Command {
7475
cmd.AddCommand(resources.NewResourcesCommand(ctx))
7576
cmd.AddCommand(componentreferences.NewCompRefCommand(ctx))
7677
cmd.AddCommand(sources.NewSourcesCommand(ctx))
78+
cmd.AddCommand(set.NewSetCommand(ctx))
7779
return cmd
7880
}
7981

@@ -110,6 +112,7 @@ func (o *ComponentArchiveOptions) Run(ctx context.Context, log logr.Logger, fs v
110112
return fmt.Errorf("unable to add component archive to ctf: %w", err)
111113
}
112114
log.Info("Successfully added ctf\n")
115+
return nil
113116
}
114117

115118
// only copy essential files to the temp dir

pkg/commands/componentarchive/create.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package componentarchive
66

77
import (
88
"context"
9+
"errors"
910
"fmt"
1011
"os"
1112

@@ -70,6 +71,11 @@ func (o *CreateOptions) Complete(args []string) error {
7071
}
7172

7273
func (o *CreateOptions) validate() error {
74+
if o.Overwrite && len(o.Name) != 0 {
75+
if len(o.Version) == 0 {
76+
return errors.New("a version has to be provided for a minimal component descriptor")
77+
}
78+
}
7379
return o.BuilderOptions.Validate()
7480
}
7581

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package set
6+
7+
import (
8+
"context"
9+
"errors"
10+
"fmt"
11+
"os"
12+
"path/filepath"
13+
14+
cdvalidation "github.com/gardener/component-spec/bindings-go/apis/v2/validation"
15+
"github.com/gardener/component-spec/bindings-go/ctf"
16+
"github.com/go-logr/logr"
17+
"github.com/mandelsoft/vfs/pkg/osfs"
18+
"github.com/mandelsoft/vfs/pkg/vfs"
19+
"github.com/spf13/cobra"
20+
"github.com/spf13/pflag"
21+
"sigs.k8s.io/yaml"
22+
23+
"github.com/gardener/component-cli/pkg/componentarchive"
24+
"github.com/gardener/component-cli/pkg/logger"
25+
"github.com/gardener/component-cli/pkg/template"
26+
)
27+
28+
// Options defines the options that are used to add resources to a component descriptor
29+
type Options struct {
30+
componentarchive.BuilderOptions
31+
TemplateOptions template.Options
32+
}
33+
34+
// NewAddCommand creates a command to add additional resources to a component descriptor.
35+
func NewSetCommand(ctx context.Context) *cobra.Command {
36+
opts := &Options{}
37+
cmd := &cobra.Command{
38+
Use: "set COMPONENT_ARCHIVE_PATH [options...]",
39+
Args: cobra.MinimumNArgs(0),
40+
Short: "set some component descriptor properties",
41+
Long: `
42+
the set command sets some component descriptor properies like the component name and/or version.
43+
44+
The component archive can be specified by the first argument, the flag "--archive" or as env var "COMPONENT_ARCHIVE_PATH".
45+
The component archive is expected to be a filesystem archive.
46+
`,
47+
Run: func(cmd *cobra.Command, args []string) {
48+
if err := opts.Complete(args); err != nil {
49+
fmt.Println(err.Error())
50+
os.Exit(1)
51+
}
52+
53+
if err := opts.Run(ctx, logger.Log, osfs.New()); err != nil {
54+
fmt.Println(err.Error())
55+
os.Exit(1)
56+
}
57+
},
58+
}
59+
60+
opts.AddFlags(cmd.Flags())
61+
62+
return cmd
63+
}
64+
65+
func (o *Options) Run(ctx context.Context, log logr.Logger, fs vfs.FileSystem) error {
66+
compDescFilePath := filepath.Join(o.ComponentArchivePath, ctf.ComponentDescriptorFileName)
67+
68+
o.Modify = true
69+
archive, err := o.BuilderOptions.Build(fs)
70+
if err != nil {
71+
return err
72+
}
73+
74+
if len(o.Name) != 0 {
75+
archive.ComponentDescriptor.Name = o.Name
76+
}
77+
if len(o.Version) != 0 {
78+
archive.ComponentDescriptor.Version = o.Version
79+
}
80+
81+
if err := cdvalidation.Validate(archive.ComponentDescriptor); err != nil {
82+
return fmt.Errorf("invalid component descriptor: %w", err)
83+
}
84+
85+
data, err := yaml.Marshal(archive.ComponentDescriptor)
86+
if err != nil {
87+
return fmt.Errorf("unable to encode component descriptor: %w", err)
88+
}
89+
if err := vfs.WriteFile(fs, compDescFilePath, data, 0664); err != nil {
90+
return fmt.Errorf("unable to write modified comonent descriptor: %w", err)
91+
}
92+
log.V(2).Info("Successfully changed component descriptor")
93+
return nil
94+
}
95+
96+
func (o *Options) Complete(args []string) error {
97+
args = o.TemplateOptions.Parse(args)
98+
99+
if len(args) == 0 {
100+
return errors.New("at least a component archive path argument has to be defined")
101+
}
102+
o.BuilderOptions.ComponentArchivePath = args[0]
103+
o.BuilderOptions.Default()
104+
105+
return o.validate()
106+
}
107+
108+
func (o *Options) validate() error {
109+
return o.BuilderOptions.Validate()
110+
}
111+
112+
func (o *Options) AddFlags(fs *pflag.FlagSet) {
113+
o.BuilderOptions.AddFlags(fs)
114+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors.
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
package set_test
6+
7+
import (
8+
"context"
9+
"path/filepath"
10+
"testing"
11+
12+
cdv2 "github.com/gardener/component-spec/bindings-go/apis/v2"
13+
"github.com/gardener/component-spec/bindings-go/codec"
14+
"github.com/gardener/component-spec/bindings-go/ctf"
15+
"github.com/go-logr/logr"
16+
"github.com/mandelsoft/vfs/pkg/layerfs"
17+
"github.com/mandelsoft/vfs/pkg/memoryfs"
18+
"github.com/mandelsoft/vfs/pkg/osfs"
19+
"github.com/mandelsoft/vfs/pkg/projectionfs"
20+
"github.com/mandelsoft/vfs/pkg/vfs"
21+
. "github.com/onsi/ginkgo"
22+
. "github.com/onsi/gomega"
23+
. "github.com/onsi/gomega/gstruct"
24+
25+
"github.com/gardener/component-cli/pkg/commands/componentarchive/set"
26+
"github.com/gardener/component-cli/pkg/componentarchive"
27+
)
28+
29+
func TestConfig(t *testing.T) {
30+
RegisterFailHandler(Fail)
31+
RunSpecs(t, "Resources Test Suite")
32+
}
33+
34+
var _ = Describe("Set", func() {
35+
36+
var testdataFs vfs.FileSystem
37+
38+
BeforeEach(func() {
39+
fs, err := projectionfs.New(osfs.New(), "./testdata")
40+
Expect(err).ToNot(HaveOccurred())
41+
testdataFs = layerfs.New(memoryfs.New(), fs)
42+
})
43+
44+
It("should set name", func() {
45+
opts := &set.Options{
46+
BuilderOptions: componentarchive.BuilderOptions{
47+
ComponentArchivePath: "./00-component",
48+
Name: "xxxx.xx/name",
49+
},
50+
}
51+
52+
Expect(opts.Run(context.TODO(), logr.Discard(), testdataFs)).To(Succeed())
53+
54+
data, err := vfs.ReadFile(testdataFs, filepath.Join(opts.ComponentArchivePath, ctf.ComponentDescriptorFileName))
55+
Expect(err).ToNot(HaveOccurred())
56+
57+
cd := &cdv2.ComponentDescriptor{}
58+
Expect(codec.Decode(data, cd)).To(Succeed())
59+
60+
Expect(cd.Resources).To(HaveLen(1))
61+
Expect(cd.Resources[0].IdentityObjectMeta).To(MatchFields(IgnoreExtras, Fields{
62+
"Name": Equal("ubuntu"),
63+
"Version": Equal("v0.0.1"),
64+
"Type": Equal("ociImage"),
65+
"ExtraIdentity": HaveLen(0),
66+
}))
67+
Expect(cd.Resources[0]).To(MatchFields(IgnoreExtras, Fields{
68+
"Relation": Equal(cdv2.ResourceRelation("external")),
69+
}))
70+
Expect(cd.Resources[0].Access.Object).To(HaveKeyWithValue("type", "ociRegistry"))
71+
Expect(cd.Resources[0].Access.Object).To(HaveKeyWithValue("imageReference", "ubuntu:18.0"))
72+
73+
Expect(cd.Name).To(Equal("xxxx.xx/name"))
74+
Expect(cd.Version).To(Equal("v0.0.0"))
75+
})
76+
77+
It("should set version", func() {
78+
opts := &set.Options{
79+
BuilderOptions: componentarchive.BuilderOptions{
80+
ComponentArchivePath: "./00-component",
81+
Version: "v1",
82+
},
83+
}
84+
85+
Expect(opts.Run(context.TODO(), logr.Discard(), testdataFs)).To(Succeed())
86+
87+
data, err := vfs.ReadFile(testdataFs, filepath.Join(opts.ComponentArchivePath, ctf.ComponentDescriptorFileName))
88+
Expect(err).ToNot(HaveOccurred())
89+
90+
cd := &cdv2.ComponentDescriptor{}
91+
Expect(codec.Decode(data, cd)).To(Succeed())
92+
93+
Expect(cd.Resources).To(HaveLen(1))
94+
Expect(cd.Resources[0].IdentityObjectMeta).To(MatchFields(IgnoreExtras, Fields{
95+
"Name": Equal("ubuntu"),
96+
"Version": Equal("v0.0.1"),
97+
"Type": Equal("ociImage"),
98+
"ExtraIdentity": HaveLen(0),
99+
}))
100+
Expect(cd.Resources[0]).To(MatchFields(IgnoreExtras, Fields{
101+
"Relation": Equal(cdv2.ResourceRelation("external")),
102+
}))
103+
Expect(cd.Resources[0].Access.Object).To(HaveKeyWithValue("type", "ociRegistry"))
104+
Expect(cd.Resources[0].Access.Object).To(HaveKeyWithValue("imageReference", "ubuntu:18.0"))
105+
106+
Expect(cd.Name).To(Equal("example.com/component"))
107+
Expect(cd.Version).To(Equal("v1"))
108+
})
109+
110+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
component:
2+
componentReferences: []
3+
name: example.com/component
4+
provider: internal
5+
repositoryContexts:
6+
- baseUrl: eu.gcr.io/gardener-project/components/dev
7+
type: ociRegistry
8+
resources:
9+
- name: 'ubuntu'
10+
version: 'v0.0.1'
11+
type: 'ociImage'
12+
relation: 'external'
13+
access:
14+
type: 'ociRegistry'
15+
imageReference: 'ubuntu:18.0'
16+
sources: []
17+
version: v0.0.0
18+
meta:
19+
schemaVersion: v2

pkg/componentarchive/archive.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type BuilderOptions struct {
3434
ComponentNameMapping string
3535

3636
Overwrite bool
37+
Modify bool
3738
}
3839

3940
func (o *BuilderOptions) AddFlags(fs *pflag.FlagSet) {
@@ -58,11 +59,6 @@ func (o *BuilderOptions) Validate() error {
5859
return errors.New("a component archive path must be defined")
5960
}
6061

61-
if len(o.Name) != 0 {
62-
if len(o.Version) == 0 {
63-
return errors.New("a version has to be provided for a minimal component descriptor")
64-
}
65-
}
6662
if len(o.ComponentNameMapping) != 0 {
6763
if o.ComponentNameMapping != string(cdv2.OCIRegistryURLPathMapping) &&
6864
o.ComponentNameMapping != string(cdv2.OCIRegistryDigestMapping) {
@@ -100,14 +96,14 @@ func (o *BuilderOptions) Build(fs vfs.FileSystem) (*ctf.ComponentArchive, error)
10096
cd := archive.ComponentDescriptor
10197

10298
if o.Name != "" {
103-
if cd.Name != "" && cd.Name != o.Name {
99+
if !o.Modify && cd.Name != "" && cd.Name != o.Name {
104100
return nil, errors.New("unable to overwrite the existing component name: forbidden")
105101
}
106102
cd.Name = o.Name
107103
}
108104

109105
if o.Version != "" {
110-
if cd.Version != "" && cd.Version != o.Version {
106+
if !o.Modify && cd.Version != "" && cd.Version != o.Version {
111107
return nil, errors.New("unable to overwrite the existing component version: forbidden")
112108
}
113109
cd.Version = o.Version

0 commit comments

Comments
 (0)