diff --git a/pkg/machinery/file.go b/pkg/machinery/file.go index bf053d14ce5..2782b4038fa 100644 --- a/pkg/machinery/file.go +++ b/pkg/machinery/file.go @@ -30,6 +30,17 @@ const ( OverwriteFile ) +// IfNotExistsAction determines what to do if a file to be updated does not exist +type IfNotExistsAction int + +const ( + // ErrorIfNotExist returns an error and stops processing (default behavior) + ErrorIfNotExist IfNotExistsAction = iota + + // IgnoreFile skips the file and logs a message if it does not exist + IgnoreFile +) + // File describes a file that will be written type File struct { // Path is the file to write @@ -40,4 +51,7 @@ type File struct { // IfExistsAction determines what to do if the file exists IfExistsAction IfExistsAction + + // IfNotExistsAction determines what to do if the file is missing (optional updates only) + IfNotExistsAction IfNotExistsAction } diff --git a/pkg/machinery/interfaces.go b/pkg/machinery/interfaces.go index 4b83e219f7c..7182a05daf5 100644 --- a/pkg/machinery/interfaces.go +++ b/pkg/machinery/interfaces.go @@ -59,6 +59,11 @@ type Inserter interface { GetCodeFragments() CodeFragmentsMap } +// HasIfNotExistsAction allows a template to define an action if the file is missing +type HasIfNotExistsAction interface { + GetIfNotExistsAction() IfNotExistsAction +} + // HasDomain allows the domain to be used on a template type HasDomain interface { // InjectDomain sets the template domain diff --git a/pkg/machinery/mixins.go b/pkg/machinery/mixins.go index 0f14935288b..9b594eb7d39 100644 --- a/pkg/machinery/mixins.go +++ b/pkg/machinery/mixins.go @@ -153,3 +153,14 @@ func (m *ResourceMixin) InjectResource(res *resource.Resource) { m.Resource = res } } + +// IfNotExistsActionMixin provides file builders with an if-not-exists-action field +type IfNotExistsActionMixin struct { + // IfNotExistsAction determines what to do if the file does not exist + IfNotExistsAction IfNotExistsAction +} + +// GetIfNotExistsAction implements Inserter +func (m *IfNotExistsActionMixin) GetIfNotExistsAction() IfNotExistsAction { + return m.IfNotExistsAction +} diff --git a/pkg/machinery/scaffold.go b/pkg/machinery/scaffold.go index 1e564676ce9..392b6596042 100644 --- a/pkg/machinery/scaffold.go +++ b/pkg/machinery/scaffold.go @@ -237,13 +237,21 @@ func doTemplate(t Template) ([]byte, error) { func (s Scaffold) updateFileModel(i Inserter, models map[string]*File) error { m, err := s.loadPreviousModel(i, models) if err != nil { - // TODO(kubebuilder/issues/4960): Create Machinery implementation to allow defining IfNotExistsAction - // If the file path starts with test/, warn and skip - // Workaround to allow projects be backwards compatible with previous versions - if strings.HasPrefix(i.GetPath(), "test/") { - log.Warn("Skipping missing test file", "file_path", i.GetPath()) - log.Warn("The code fragments will not be inserted.") - return nil + if os.IsNotExist(err) { + if withOptionalBehavior, ok := i.(HasIfNotExistsAction); ok { + switch withOptionalBehavior.GetIfNotExistsAction() { + case IgnoreFile: + log.Warn("Skipping missing file", "file", i.GetPath()) + log.Warn("The code fragments will not be inserted.") + return nil + case ErrorIfNotExist: + return err + default: + return err + } + } + // If inserter doesn't implement HasIfNotExistsAction, return the original error + return err } return fmt.Errorf("failed to load previous model for %s: %w", i.GetPath(), err) } diff --git a/pkg/plugins/golang/v4/scaffolds/internal/templates/webhooks/webhook_test_template.go b/pkg/plugins/golang/v4/scaffolds/internal/templates/webhooks/webhook_test_template.go index db17c6feb4b..db1c7fc79ab 100644 --- a/pkg/plugins/golang/v4/scaffolds/internal/templates/webhooks/webhook_test_template.go +++ b/pkg/plugins/golang/v4/scaffolds/internal/templates/webhooks/webhook_test_template.go @@ -33,6 +33,7 @@ type WebhookTest struct { machinery.MultiGroupMixin machinery.BoilerplateMixin machinery.ResourceMixin + machinery.IfNotExistsActionMixin Force bool @@ -78,6 +79,7 @@ func (f *WebhookTest) SetTemplateDefaults() error { if f.Force { f.IfExistsAction = machinery.OverwriteFile } + f.IfNotExistsAction = machinery.IgnoreFile return nil }