Skip to content

Commit

Permalink
Add generate bundle --ignore-if-only-createdAt option
Browse files Browse the repository at this point in the history
Signed-off-by: Tiger Kaovilai <tkaovila@redhat.com>
  • Loading branch information
kaovilai committed May 4, 2023
1 parent af14062 commit 5747337
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 4 deletions.
38 changes: 38 additions & 0 deletions changelog/fragments/6419.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# entries is a list of entries to include in
# release notes and/or the migration guide
entries:
- description: >
Add ability to ignore bundle updates on `generate bundle` command if createdAt timestamp is the only change.
The flag to use is `--ignore-if-only-createdAt`.
# kind is one of:
# - addition
# - change
# - deprecation
# - removal
# - bugfix
kind: "addition"
# Is this a breaking change?
breaking: false
# NOTE: ONLY USE `pull_request_override` WHEN ADDING THIS
# FILE FOR A PREVIOUSLY MERGED PULL_REQUEST!
#
# The generator auto-detects the PR number from the commit
# message in which this file was originally added.
#
# What is the pull request number (without the "#")?
# pull_request_override: 0
# Migration can be defined to automatically add a section to
# the migration guide. This is required for breaking changes.
# migration:
# header: Header text for the migration section
# body: |
# Body of the migration section. This should be formatted as markdown and can
# span multiple lines.
# Using the YAML string '|' operator means that newlines in this string will
# be honored and interpretted as newlines in the rendered markdown.
4 changes: 4 additions & 0 deletions internal/cmd/operator-sdk/generate/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ func (c bundleCmd) runManifests() (err error) {
opts = append(opts, gencsv.WithWriter(stdout))
} else {
opts = append(opts, gencsv.WithBundleWriter(c.outputDir))
if c.ignoreIfOnlyCreatedAt && genutil.IsExist(c.outputDir) {
opts = append(opts, gencsv.WithBundleReader(c.outputDir))
opts = append(opts, gencsv.WithIgnoreIfOnlyCreatedAt())
}
}

csvGen := gencsv.Generator{
Expand Down
8 changes: 5 additions & 3 deletions internal/cmd/operator-sdk/generate/bundle/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ type bundleCmd struct {
extraServiceAccounts []string

// Metadata options.
channels string
defaultChannel string
overwrite bool
channels string
defaultChannel string
overwrite bool
ignoreIfOnlyCreatedAt bool

// These are set if a PROJECT config is not present.
layout string
Expand Down Expand Up @@ -138,6 +139,7 @@ func (c *bundleCmd) addFlagsTo(fs *pflag.FlagSet) {
"Names of service accounts, outside of the operator's Deployment account, "+
"that have bindings to {Cluster}Roles that should be added to the CSV")
fs.BoolVar(&c.overwrite, "overwrite", true, "Overwrite the bundle's metadata and Dockerfile if they exist")
fs.BoolVar(&c.ignoreIfOnlyCreatedAt, "ignore-if-only-createdAt", false, "Ignore if only createdAt is changed")
fs.BoolVarP(&c.quiet, "quiet", "q", false, "Run in quiet mode")
fs.BoolVar(&c.stdout, "stdout", false, "Write bundle manifest to stdout")

Expand Down
49 changes: 48 additions & 1 deletion internal/generate/clusterserviceversion/clusterserviceversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"io"
"path/filepath"
"reflect"
"strings"

"github.com/blang/semver/v4"
Expand Down Expand Up @@ -61,6 +62,10 @@ type Generator struct {

// Func that returns the writer the generated CSV's bytes are written to.
getWriter func() (io.Writer, error)
// Func that returns the reader the previous CSV's bytes are read from.
getReader func() (io.Reader, error)

ignoreIfOnlyCreatedAt bool
}

// Option is a function that modifies a Generator.
Expand Down Expand Up @@ -88,6 +93,18 @@ func WithBundleWriter(dir string) Option {
}
}

// WithBundleGetter sets a Generator's getter to a bundle CSV file under
// <dir>/manifests.
func WithBundleReader(dir string) Option {
return func(g *Generator) error {
fileName := makeCSVFileName(g.OperatorName)
g.getReader = func() (io.Reader, error) {
return genutil.Open(filepath.Join(dir, bundle.ManifestsDir), fileName)
}
return nil
}
}

// WithPackageWriter sets a Generator's writer to a package CSV file under
// <dir>/<version>.
func WithPackageWriter(dir string) Option {
Expand All @@ -100,6 +117,13 @@ func WithPackageWriter(dir string) Option {
}
}

func WithIgnoreIfOnlyCreatedAt() Option {
return func(g *Generator) error {
g.ignoreIfOnlyCreatedAt = true
return nil
}
}

// Generate configures the generator with col and opts then runs it.
func (g *Generator) Generate(opts ...Option) (err error) {
for _, opt := range opts {
Expand All @@ -119,7 +143,30 @@ func (g *Generator) Generate(opts ...Option) (err error) {

// Add extra annotations to csv
g.setAnnotations(csv)

// If a reader is set, and there is a flag to not update createdAt, then
// set the CSV's createdAt to the previous CSV's createdAt if its the only change.
if g.ignoreIfOnlyCreatedAt && g.getReader != nil {
r, err := g.getReader()
if err != nil {
return err
}
var prevCSV operatorsv1alpha1.ClusterServiceVersion
err = genutil.ReadObject(r, &prevCSV)
if err != nil {
return err
}
if prevCSV.ObjectMeta.Annotations["createdAt"] != "" {
csvWithoutCreatedAtChange := csv.DeepCopy()
// Set WebhookDefinitions if not nil to avoid diffing on it
if prevCSV.Spec.WebhookDefinitions == nil {
prevCSV.Spec.WebhookDefinitions = []operatorsv1alpha1.WebhookDescription{}
}
csvWithoutCreatedAtChange.ObjectMeta.Annotations["createdAt"] = prevCSV.ObjectMeta.Annotations["createdAt"]
if reflect.DeepEqual(csvWithoutCreatedAtChange, &prevCSV) {
csv = csvWithoutCreatedAtChange
}
}
}
w, err := g.getWriter()
if err != nil {
return err
Expand Down
10 changes: 10 additions & 0 deletions internal/generate/internal/genutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"os"
"path/filepath"

"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"

"github.com/operator-framework/operator-sdk/internal/util/k8sutil"
Expand Down Expand Up @@ -111,3 +112,12 @@ func IsNotExist(path string) bool {
_, err := os.Stat(path)
return err != nil && errors.Is(err, os.ErrNotExist)
}

func ReadObject(r io.Reader, obj client.Object) error {
var buf bytes.Buffer
if _, err := buf.ReadFrom(r); err != nil {
return err
}
k8sutil.GetObjectFromBytes(buf.Bytes(), obj)
return nil
}
9 changes: 9 additions & 0 deletions internal/util/k8sutil/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package k8sutil

import (
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/yaml"
)

type MarshalFunc func(interface{}) ([]byte, error)
Expand Down Expand Up @@ -53,3 +54,11 @@ func deleteKeyFromUnstructured(u map[string]interface{}, key string) {
}
}
}

func GetObjectFromBytes(b []byte, obj interface{}) (interface{}, error) {
var u map[string]interface{}
if err := yaml.Unmarshal(b, &u); err != nil {
return nil, err
}
return runtime.DefaultUnstructuredConverter.FromUnstructured(u, obj), nil
}

0 comments on commit 5747337

Please sign in to comment.