Skip to content

Update Plugin API with optional New Resources#140

Merged
aufi merged 4 commits into
migtools:mainfrom
aufi:plugin-api-new-resources
Jul 3, 2026
Merged

Update Plugin API with optional New Resources#140
aufi merged 4 commits into
migtools:mainfrom
aufi:plugin-api-new-resources

Conversation

@aufi

@aufi aufi commented May 27, 2026

Copy link
Copy Markdown
Contributor

Update of crane-lib to allow transform plugins to generate entirely new Kubernetes resources. The implementation ensures full backward compatibility without the need for a V2 API.

Core Architecture Updates

  • Extended API: Both PluginResponse and RunnerResponse now include a NewResources field to hold standard Kubernetes unstructured objects.
  • Graceful Degradation: Relies on the JSON omitempty tag. Older plugins simply omit this field, which automatically resolves to an empty list without breaking the execution.
  • Simplified Runner Logic: The runner iterates through plugins and aggregates any NewResources provided. It avoids complex version validation, relying solely on whether the new resources array contains items.

Related to migtools/crane#415
Fixes #139

Summary by CodeRabbit

  • New Features

    • Plugins can now emit additional generated resources during processing; the runner collects and returns these alongside patches and whiteouts.
  • Tests

    • Added tests validating single/multiple generated resources, interactions with whiteouts, aggregation across plugins, empty outputs, backward compatibility, and runner construction/initialization.

Update of `crane-lib` to allow transform plugins to generate entirely new
Kubernetes resources. The implementation ensures full backward compatibility
without the need for a V2 API.

**Core Architecture Updates**

* **Extended API:** Both `PluginResponse` and `RunnerResponse` now include a `NewResources` field to hold standard Kubernetes unstructured objects.
* **Graceful Degradation:** Relies on the JSON `omitempty` tag. Older plugins simply omit this field, which automatically resolves to an empty list without breaking the execution.
* **Simplified Runner Logic:** The runner iterates through plugins and aggregates any `NewResources` provided. It avoids complex version validation, relying solely on whether the new resources array contains items.

Related to migtools/crane#415
Fixes migtools#139

Signed-off-by: Marek Aufart <maufart@redhat.com>
@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 670bafb4-1715-4226-b4bf-c2640c14929b

📥 Commits

Reviewing files that changed from the base of the PR and between cedf87c and 8573ded.

📒 Files selected for processing (1)
  • transform/runner_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • transform/runner_test.go

📝 Walkthrough

Walkthrough

Adds a NewResources field to PluginResponse and RunnerResponse, a NewRunner constructor, aggregates plugin-emitted new unstructured Kubernetes resources in Runner.Run, and extends tests to validate multiple generation and backward-compatibility scenarios.

Changes

Plugin-generated new resources API extension

Layer / File(s) Summary
Plugin response contract
transform/plugin.go
PluginResponse adds optional NewResources []unstructured.Unstructured with JSON tag json:"newResources,omitempty".
Runner factory and response
transform/runner.go
Adds NewRunner(logger, pluginPriorities, optionalFlags) and a NewResources []unstructured.Unstructured field on RunnerResponse.
Runner execution and aggregation
transform/runner.go
Runner.Run initializes newResources accumulator, appends each plugin's resp.NewResources with a debug log (plugin name and count), and returns aggregated NewResources in the final response.
Test scenarios and assertions
transform/runner_test.go
Test case struct gets ExpectedNewResources/ExpectedResources; cases cover single/multi new-resources, whiteout combos, multi-plugin aggregation, empty lists, patch-only compatibility, and adds TestNewRunner to verify constructor wiring.

Sequence Diagram

sequenceDiagram
  participant Runner
  participant Plugin
  participant Accumulator as newResources_Accumulator
  participant Response as RunnerResponse
  Runner->>Plugin: Execute plugin.Run
  Plugin-->>Runner: return PluginResponse (NewResources, Patches, IsWhiteOut, Version)
  Runner->>Accumulator: append PluginResponse.NewResources
  Runner->>Runner: debug log (plugin name, appended count)
  Accumulator-->>Response: aggregated NewResources
  Runner-->>Response: return RunnerResponse (NewResources, other fields)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Poem

🐰 I nibble code with joyful paws,

NewResources sprout without a pause,
Plugins hop and leave their seeds,
Runner gathers all their deeds,
Old patches kept — new growth proceeds.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: adding an optional NewResources field to the Plugin API for plugins to generate new Kubernetes resources.
Linked Issues check ✅ Passed The PR fully implements all coding requirements from issue #139: added NewResources field to PluginResponse and RunnerResponse, implemented JSON omitempty for backward compatibility, implemented aggregation logic in Runner, and provided comprehensive test coverage including single/multiple resources, whiteout scenarios, backward compatibility, and multi-plugin aggregation.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the NewResources feature: PluginResponse field addition, NewRunner constructor, RunnerResponse field, aggregation logic in Runner.Run, and comprehensive test coverage for the feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@transform/runner.go`:
- Around line 87-91: The call r.Log.Debugf(...) can panic if Runner.Log is nil
when a plugin returns NewResources; update the block handling resp.NewResources
in function/method that appends to newResources to first check for r.Log != nil
before calling Debugf (or use a nil-safe logger accessor), e.g. wrap the
r.Log.Debugf call in an if r.Log != nil { ... } guard and keep appending
resp.NewResources to newResources and using plugin.Metadata().Name and
len(resp.NewResources) only inside that guarded section so no nil dereference
occurs when Runner.Log is unset.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e62372c6-7321-4bda-9150-3773adcf9c4d

📥 Commits

Reviewing files that changed from the base of the PR and between a9f07d5 and b977127.

📒 Files selected for processing (3)
  • transform/plugin.go
  • transform/runner.go
  • transform/runner_test.go

Comment thread transform/runner.go
Signed-off-by: Marek Aufart <maufart@redhat.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
transform/runner.go (1)

25-30: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle nil logger input in NewRunner.

NewRunner accepts logger *logrus.Logger but does not guard nil. A nil input leaves Runner.Log nil and can still panic on later Debugf calls.

Suggested fix
 func NewRunner(logger *logrus.Logger, pluginPriorities map[string]int, optionalFlags map[string]string) *Runner {
+	if logger == nil {
+		logger = logrus.New()
+	}
 	return &Runner{
 		Log:              logger,
 		PluginPriorities: pluginPriorities,
 		OptionalFlags:    optionalFlags,
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@transform/runner.go` around lines 25 - 30, NewRunner currently assigns the
passed logger pointer directly to Runner.Log without guarding against nil, which
can cause panics on later calls like Runner.Log.Debugf; update NewRunner to
check if the supplied logger is nil and if so create and assign a default logger
(e.g., by calling logrus.New()) before returning the &Runner, keeping the
existing fields PluginPriorities and OptionalFlags unchanged so all callers (and
methods that call Debugf/Infof) always have a non-nil Log to use.
🧹 Nitpick comments (1)
transform/runner_test.go (1)

552-568: ⚡ Quick win

Add a nil-logger constructor test case.

TestNewRunner only validates non-nil input. Add a case for NewRunner(nil, ...) to prevent regressions on logger safety.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@transform/runner_test.go` around lines 552 - 568, TestNewRunner lacks a case
that passes a nil logger to NewRunner; add a subtest or additional assertions
that call NewRunner(nil, priorities, flags) and assert the returned runner has a
non-nil Log (i.e., NewRunner must guard against a nil logger), and still
correctly sets PluginPriorities and OptionalFlags. Locate NewRunner and
TestNewRunner in runner_test.go, create the nil-logger invocation, and verify
runner.Log != nil and runner.PluginPriorities["plugin1"] == 1 and
runner.OptionalFlags["flag1"] == "value1".
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@transform/runner.go`:
- Around line 25-30: NewRunner currently assigns the passed logger pointer
directly to Runner.Log without guarding against nil, which can cause panics on
later calls like Runner.Log.Debugf; update NewRunner to check if the supplied
logger is nil and if so create and assign a default logger (e.g., by calling
logrus.New()) before returning the &Runner, keeping the existing fields
PluginPriorities and OptionalFlags unchanged so all callers (and methods that
call Debugf/Infof) always have a non-nil Log to use.

---

Nitpick comments:
In `@transform/runner_test.go`:
- Around line 552-568: TestNewRunner lacks a case that passes a nil logger to
NewRunner; add a subtest or additional assertions that call NewRunner(nil,
priorities, flags) and assert the returned runner has a non-nil Log (i.e.,
NewRunner must guard against a nil logger), and still correctly sets
PluginPriorities and OptionalFlags. Locate NewRunner and TestNewRunner in
runner_test.go, create the nil-logger invocation, and verify runner.Log != nil
and runner.PluginPriorities["plugin1"] == 1 and runner.OptionalFlags["flag1"] ==
"value1".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 810a7a79-75f7-4ba8-9854-13dbcdc33364

📥 Commits

Reviewing files that changed from the base of the PR and between b977127 and 0807c63.

📒 Files selected for processing (2)
  • transform/runner.go
  • transform/runner_test.go

Comment thread transform/runner.go
Signed-off-by: Marek Aufart <maufart@redhat.com>
@aufi aufi requested a review from msajidmansoori12 May 29, 2026 14:05

@midays midays left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left one comment, otherwise LGTM

Comment thread transform/runner_test.go
Signed-off-by: Marek Aufart <maufart@redhat.com>
@aufi aufi requested a review from midays June 2, 2026 08:45

@stillalearner stillalearner left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@midays midays left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@aufi aufi merged commit fdff8c6 into migtools:main Jul 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update plugin API to allow new resources creation

4 participants