Skip to content

Commit

Permalink
⚠️ change structure to store crdVersion and webhkversion (go/v3-alpha)
Browse files Browse the repository at this point in the history
  • Loading branch information
Camila Macedo committed Dec 15, 2020
1 parent a4ad49a commit 90a7ad3
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 133 deletions.
110 changes: 85 additions & 25 deletions pkg/model/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type Config struct {

// Resources tracks scaffolded resources in the project
// This info is tracked only in project with version 2
Resources []GVK `json:"resources,omitempty"`
Resources []ResourceData `json:"resources,omitempty"`

// Multigroup tracks if the project has more than one group
MultiGroup bool `json:"multigroup,omitempty"`
Expand Down Expand Up @@ -78,32 +78,30 @@ func (c Config) IsV3() bool {
return c.Version == Version3Alpha
}

// HasResource returns true if API resource is already tracked
func (c Config) HasResource(target GVK) bool {
// GetResource returns the GKV if the resource is found
func (c Config) GetResource(target ResourceData) *ResourceData {
// Return true if the target resource is found in the tracked resources
for _, r := range c.Resources {
if r.isEqualTo(target) {
return true
if r.isGVKEqualTo(target) {
return &r
}
}

// Return false otherwise
return false
return nil
}

// UpdateResources either adds gvk to the tracked set or, if the resource already exists,
// updates the the equivalent resource in the set.
func (c *Config) UpdateResources(gvk GVK) {
func (c *Config) UpdateResources(resource ResourceData) {
// If the resource already exists, update it.
for i, r := range c.Resources {
if r.isEqualTo(gvk) {
c.Resources[i].merge(gvk)
if r.isGVKEqualTo(resource) {
c.Resources[i].merge(resource)
return
}
}

// The resource does not exist, append the resource to the tracked ones.
c.Resources = append(c.Resources, gvk)
c.Resources = append(c.Resources, resource)
}

// HasGroup returns true if group is already tracked
Expand Down Expand Up @@ -136,9 +134,13 @@ func (c Config) resourceAPIVersionCompatible(verType, version string) bool {
var currVersion string
switch verType {
case "crd":
currVersion = res.CRDVersion
if res.API != nil {
currVersion = res.API.CRDVersion
}
case "webhook":
currVersion = res.WebhookVersion
if res.Webhooks != nil {
currVersion = res.Webhooks.WebhookVersion
}
}
if currVersion != "" && version != currVersion {
return false
Expand All @@ -147,33 +149,71 @@ func (c Config) resourceAPIVersionCompatible(verType, version string) bool {
return true
}

// GVK contains information about scaffolded resources
type GVK struct {
// ResourceData contains information about scaffolded resources
type ResourceData struct {
Group string `json:"group,omitempty"`
Version string `json:"version,omitempty"`
Kind string `json:"kind,omitempty"`

// CRDVersion holds the CustomResourceDefinition API version used for the GVK.
// API holds the API data
API *API `json:"api,omitempty"`

// Webhooks holds the Webhooks data
Webhooks *Webhooks `json:"webhooks,omitempty"`
}

// API contains information about scaffolded APIs
type API struct {
// CRDVersion holds the CustomResourceDefinition API version used for the ResourceData.
CRDVersion string `json:"crdVersion,omitempty"`
// WebhookVersion holds the {Validating,Mutating}WebhookConfiguration API version used for the GVK.
}

// Webhooks contains information about scaffolded webhooks
type Webhooks struct {
// WebhookVersion holds the {Validating,Mutating}WebhookConfiguration API version used for the Options.
WebhookVersion string `json:"webhookVersion,omitempty"`
}

// isEqualTo compares it with another resource
func (r GVK) isEqualTo(other GVK) bool {
// isGVKEqualTo compares it with another resource
func (r ResourceData) isGVKEqualTo(other ResourceData) bool {
return r.Group == other.Group &&
r.Version == other.Version &&
r.Kind == other.Kind
}

// merge combines fields of two GVKs that have matching group, version, and kind,
// favoring the receiver's values.
func (r *GVK) merge(other GVK) {
if r.CRDVersion == "" && other.CRDVersion != "" {
r.CRDVersion = other.CRDVersion
func (r *ResourceData) merge(other ResourceData) {
if other.Webhooks != nil {
if r.Webhooks == nil {
r.Webhooks = other.Webhooks
} else {
r.Webhooks.merge(other.Webhooks)
}
}
if r.WebhookVersion == "" && other.WebhookVersion != "" {
r.WebhookVersion = other.WebhookVersion

if other.API != nil {
if r.API == nil {
r.API = other.API
} else {
r.API.merge(other.API)
}
}
}

// merge compares it with another webhook by setting each webhook type individually so existing values are
// not overwritten.
func (w *Webhooks) merge(other *Webhooks) {
if w.WebhookVersion == "" && other.WebhookVersion != "" {
w.WebhookVersion = other.WebhookVersion
}
}

// merge compares it with another api by setting each api type individually so existing values are
// not overwritten.
func (a *API) merge(other *API) {
if a.CRDVersion == "" && other.CRDVersion != "" {
a.CRDVersion = other.CRDVersion
}
}

Expand All @@ -182,6 +222,26 @@ func (c Config) Marshal() ([]byte, error) {
// Ignore extra fields at first.
cfg := c
cfg.Plugins = nil

// Ignore some fields if v2.
if cfg.IsV2() {
for i := range cfg.Resources {
cfg.Resources[i].API = nil
cfg.Resources[i].Webhooks = nil
}
}

for i, r := range cfg.Resources {
// If API is empty, omit it (prevents `api: {}`).
if r.API != nil && r.API.CRDVersion == "" {
cfg.Resources[i].API = nil
}
// If Webhooks is empty, omit it (prevents `webhooks: {}`).
if r.Webhooks != nil && r.Webhooks.WebhookVersion == "" {
cfg.Resources[i].Webhooks = nil
}
}

content, err := yaml.Marshal(cfg)
if err != nil {
return nil, fmt.Errorf("error marshalling project configuration: %v", err)
Expand Down
105 changes: 73 additions & 32 deletions pkg/model/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,28 @@ var _ = Describe("PluginConfig", func() {
Data1 string `json:"data-1"`
Data2 string `json:"data-2"`
}
const defaultWebhookVersion = "v1"

resource := ResourceData{Group: "Foo", Kind: "Baz", Version: "v1"}
resource.Webhooks = &Webhooks{defaultWebhookVersion}

It("should return true when has the ResourceData is equals", func() {
Expect(resource.isGVKEqualTo(ResourceData{Group: "Foo", Kind: "Baz", Version: "v1"})).To(BeTrue())
})

It("should return false when ResourceData is NOT equals", func() {
Expect(resource.isGVKEqualTo(ResourceData{Group: "Foo", Kind: "Baz", Version: "v2"})).To(BeFalse())
})

It("IsV2 should return true when the config is V2", func() {
cfg := Config{Version: Version2}
Expect(cfg.IsV2()).To(BeTrue())
})

It("IsV3 should return true when the config is V3", func() {
cfg := Config{Version: Version3Alpha}
Expect(cfg.IsV3()).To(BeTrue())
})

It("should encode correctly", func() {
var (
Expand Down Expand Up @@ -165,56 +187,61 @@ var _ = Describe("PluginConfig", func() {
})
})

var _ = Describe("Resource Version Compatibility", func() {
var _ = Describe("ResourceData Version Compatibility", func() {

var (
c *Config
gvk1, gvk2 GVK
c *Config
resource1, resource2 ResourceData

defaultVersion = "v1"
)

BeforeEach(func() {
c = &Config{}
gvk1 = GVK{Group: "example", Version: "v1", Kind: "TestKind"}
gvk2 = GVK{Group: "example", Version: "v1", Kind: "TestKind2"}
resource1 = ResourceData{Group: "example", Version: "v1", Kind: "TestKind"}
resource2 = ResourceData{Group: "example", Version: "v1", Kind: "TestKind2"}
})

Context("resourceAPIVersionCompatible", func() {
It("returns true for a list of empty resources", func() {
Expect(c.resourceAPIVersionCompatible("crd", defaultVersion)).To(BeTrue())
Expect(c.resourceAPIVersionCompatible("webhook", defaultVersion)).To(BeTrue())
})
It("returns true for one resource with an empty version", func() {
c.Resources = []GVK{gvk1}
c.Resources = []ResourceData{resource1}
Expect(c.resourceAPIVersionCompatible("crd", defaultVersion)).To(BeTrue())
Expect(c.resourceAPIVersionCompatible("webhook", defaultVersion)).To(BeTrue())
})
It("returns true for one resource with matching version", func() {
gvk1.CRDVersion = defaultVersion
c.Resources = []GVK{gvk1}
resource1.API = &API{CRDVersion: defaultVersion}
resource1.Webhooks = &Webhooks{WebhookVersion: defaultVersion}
c.Resources = []ResourceData{resource1}
Expect(c.resourceAPIVersionCompatible("crd", defaultVersion)).To(BeTrue())
Expect(c.resourceAPIVersionCompatible("webhook", defaultVersion)).To(BeTrue())
})
It("returns true for two resources with matching versions", func() {
gvk1.CRDVersion = defaultVersion
gvk2.CRDVersion = defaultVersion
c.Resources = []GVK{gvk1, gvk2}
resource1.API = &API{CRDVersion: defaultVersion}
resource1.Webhooks = &Webhooks{WebhookVersion: defaultVersion}
resource2.API = &API{CRDVersion: defaultVersion}
resource2.Webhooks = &Webhooks{WebhookVersion: defaultVersion}
c.Resources = []ResourceData{resource1, resource2}
Expect(c.resourceAPIVersionCompatible("crd", defaultVersion)).To(BeTrue())
Expect(c.resourceAPIVersionCompatible("webhook", defaultVersion)).To(BeTrue())
})
It("returns false for one resource with a non-matching version", func() {
gvk1.CRDVersion = v1beta1
c.Resources = []GVK{gvk1}
resource1.API = &API{CRDVersion: v1beta1}
resource1.Webhooks = &Webhooks{WebhookVersion: v1beta1}
c.Resources = []ResourceData{resource1}
Expect(c.resourceAPIVersionCompatible("crd", defaultVersion)).To(BeFalse())
Expect(c.resourceAPIVersionCompatible("webhook", defaultVersion)).To(BeFalse())
})
It("returns false for two resources containing a non-matching version", func() {
gvk1.CRDVersion = v1beta1
gvk2.CRDVersion = defaultVersion
c.Resources = []GVK{gvk1, gvk2}
resource1.API = &API{CRDVersion: v1beta1}
resource1.Webhooks = &Webhooks{WebhookVersion: v1beta1}
resource2.API = &API{CRDVersion: defaultVersion}
resource2.Webhooks = &Webhooks{WebhookVersion: defaultVersion}
c.Resources = []ResourceData{resource1, resource2}
Expect(c.resourceAPIVersionCompatible("crd", defaultVersion)).To(BeFalse())
})

It("returns false for two resources containing a non-matching version (webhooks)", func() {
gvk1.WebhookVersion = v1beta1
gvk2.WebhookVersion = defaultVersion
c.Resources = []GVK{gvk1, gvk2}
Expect(c.resourceAPIVersionCompatible("webhook", defaultVersion)).To(BeFalse())
})
})
Expand All @@ -223,35 +250,49 @@ var _ = Describe("Resource Version Compatibility", func() {
var _ = Describe("Config", func() {
var (
c *Config
gvk1, gvk2 GVK
gvk1, gvk2 ResourceData
)

BeforeEach(func() {
c = &Config{}
gvk1 = GVK{Group: "example", Version: "v1", Kind: "TestKind"}
gvk2 = GVK{Group: "example", Version: "v1", Kind: "TestKind2"}
gvk1 = ResourceData{Group: "example", Version: "v1", Kind: "TestKind"}
gvk2 = ResourceData{Group: "example", Version: "v1", Kind: "TestKind2"}
})

Context("UpdateResource", func() {
It("Adds a non-existing resource", func() {
c.UpdateResources(gvk1)
Expect(c.Resources).To(Equal([]GVK{gvk1}))
Expect(c.Resources).To(Equal([]ResourceData{gvk1}))
// Update again to ensure idempotency.
c.UpdateResources(gvk1)
Expect(c.Resources).To(Equal([]GVK{gvk1}))
Expect(c.Resources).To(Equal([]ResourceData{gvk1}))
})
It("Updates an existing resource", func() {
c.UpdateResources(gvk1)
gvk := GVK{Group: gvk1.Group, Version: gvk1.Version, Kind: gvk1.Kind, CRDVersion: "v1"}
c.UpdateResources(gvk)
Expect(c.Resources).To(Equal([]GVK{gvk}))
resource := ResourceData{Group: gvk1.Group, Version: gvk1.Version, Kind: gvk1.Kind}
c.UpdateResources(resource)
Expect(c.Resources).To(Equal([]ResourceData{resource}))
})
It("Updates an existing resource with more than one resource present", func() {
c.UpdateResources(gvk1)
c.UpdateResources(gvk2)
gvk := GVK{Group: gvk1.Group, Version: gvk1.Version, Kind: gvk1.Kind, CRDVersion: "v1"}
gvk := ResourceData{Group: gvk1.Group, Version: gvk1.Version, Kind: gvk1.Kind}
c.UpdateResources(gvk)
Expect(c.Resources).To(Equal([]GVK{gvk, gvk2}))
Expect(c.Resources).To(Equal([]ResourceData{gvk, gvk2}))
})
})

Context("HasGroup", func() {
It("should return true when config has a resource with the group", func() {
c.UpdateResources(gvk1)
Expect(c.Resources).To(Equal([]ResourceData{gvk1}))
Expect(c.HasGroup(gvk1.Group)).To(BeTrue())
})
It("should return false when config has a resource with not the same group", func() {
c.UpdateResources(gvk1)
Expect(c.Resources).To(Equal([]ResourceData{gvk1}))
Expect(c.HasGroup("hasNot")).To(BeFalse())
})

})
})
Loading

0 comments on commit 90a7ad3

Please sign in to comment.