Skip to content

feat: add AddReference method to References#415

Open
yordis wants to merge 1 commit intocrossplane:mainfrom
yordis:feat-improve-sdk-reference
Open

feat: add AddReference method to References#415
yordis wants to merge 1 commit intocrossplane:mainfrom
yordis:feat-improve-sdk-reference

Conversation

@yordis
Copy link
Copy Markdown
Contributor

@yordis yordis commented Jun 2, 2024

Description of your changes

@haarchri was helping at crossplane-contrib/provider-upjet-digitalocean#41 (thank you), and during the code review, I noticed a oversee where he replaced the existing r.References as follow:

diff --git a/config/provider.go b/config/provider.go
index 83eada3..8e69d59 100644
--- a/config/provider.go
+++ b/config/provider.go
@@ -294,13 +294,9 @@ func GetProvider() *ujconfig.Provider {
 			Type:          referenceType(pc, “project”, “v1alpha1", “Project”),
 			TerraformName: “digitalocean_project”,
 		}
-
-		r.References = map[string]ujconfig.Reference{
-			“forwarding_rule.certificate_name”: {
-				TerraformName: “digitalocean_certificate”,
-			},
+		r.References[“forwarding_rule.certificate_name”] = ujconfig.Reference{
+			TerraformName: “digitalocean_certificate”,
 		}
-
 	})
 	pc.AddResourceConfigurator(“digitalocean_domain”, func(r *ujconfig.Resource) {
 		r.ShortGroup = “dns”

I am glad that I saw the diff, but honestly, this is a straightforward thing to miss when they are so much code-generated files noise, or people tend to ignore those.

As @haarchri explained, "That's why I prefer this, for example, https://github.com/crossplane-contrib/provider-upjet-aws/blob/main/config/elbv2/config.go#L13," which is a really common scenario.

I never considered using the existing style. I didn't think much about it. He didn’t try to break things. Still, we ran into the issue. Since we are talking about "style" here, it is really difficult to be objective and define who is more proper.

So, the fix here is to expose an SDK API that avoids such a mistake.

I am not proposing adding getters and setters everywhere either, just reacting to the situation and figuring out how to mitigate the issues in the future; as I usually say, "let the code teach you what to do, not the other way around."

I have:

  • Read and followed Upjet's contribution process.
  • Run make reviewable to ensure this PR is ready for review.
  • Added backport release-x.y labels to auto-backport this PR if necessary.

How has this code been tested

  • Unit Testing

@yordis yordis force-pushed the feat-improve-sdk-reference branch 2 times, most recently from 30b0582 to 3da3f28 Compare June 2, 2024 18:47
@yordis yordis marked this pull request as ready for review June 2, 2024 18:49
@yordis
Copy link
Copy Markdown
Contributor Author

yordis commented Jun 2, 2024

A few things from this,

  1. Should all documentation and code-generated code be updated to this?
  2. Should References be a private field instead of exposing it? You can still assign r.References. Ideally, Provider Authors shouldn't care about replacing the entire r.References, and in that case, we can add r.ReplaceReferences(references), but I am not sure when this would be necessary.

Comment thread pkg/config/resource.go
// in another object.
func (r References) AddReference(fieldPath string, ref Reference) error {
if _, ok := r[fieldPath]; ok {
return ErrReferenceAlreadyExists
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.

I don't love returning an error in this situation. My instinct is that the action of setting a reference should be idempotent; as you've implemented it all times it's invoked but the first will fail with an error.

Maybe it's ok because it would happen at generation time, although I don't know if we could guarantee that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have no strong opinions; either way it is fine by me

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hey @mbbush, what would be the resolution here? I am not sure if you requested some changes or not

@yordis yordis requested a review from mbbush June 27, 2024 18:04
@Upbound-CLA
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

1 similar comment
@Upbound-CLA
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@yordis yordis force-pushed the feat-improve-sdk-reference branch from 797d5c9 to 97604aa Compare April 30, 2026 20:41
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

📝 Walkthrough

Walkthrough

Introduces a new sentinel error ErrReferenceAlreadyExists and an AddReference method on the References type. The method safely registers field-path references by enforcing uniqueness, returning an error if the field path already exists or nil after successfully adding the reference.

Changes

Cohort / File(s) Summary
Reference Registration Safety
pkg/config/resource.go, pkg/config/resource_test.go
Adds sentinel error ErrReferenceAlreadyExists and References.AddReference() convenience method that checks for duplicate field paths before insertion. Includes comprehensive unit tests validating successful additions and duplicate-rejection behavior.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: adding a new AddReference method to the References type.
Description check ✅ Passed The description is well-related to the changeset, providing context about a real-world problem that motivated the addition of the AddReference method.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Configuration Api Breaking Changes ✅ Passed The pull request introduces only additive changes to the Configuration API: a new exported sentinel error variable and a new convenience method on the References type, with no breaking changes to existing exports.
Generated Code Manual Edits ✅ Passed The pull request modifies only hand-written source files (pkg/config/resource.go and pkg/config/resource_test.go), not generated code files matching zz_*.go pattern.
Template Breaking Changes ✅ Passed Pull request modifications are limited to configuration files (pkg/config/resource.go and pkg/config/resource_test.go) and do not modify any pkg/controller/external*.go template files.

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


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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
pkg/config/resource_test.go (1)

300-329: ⚡ Quick win

Please align this new test with the repo’s table-driven + PascalCase convention.

Could we rename TestReferences_AddReference to TestReferencesAddReference and convert the two scenarios into a small table (args/want) to match the file and repo standard? This should also make future AddReference cases easier to extend.

As per coding guidelines "**/*_test.go: Enforce table-driven test structure: PascalCase test names (no underscores), args/want pattern..."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/config/resource_test.go` around lines 300 - 329, Rename the test from
TestReferences_AddReference to TestReferencesAddReference and rewrite it as a
table-driven test using args/want style: create a test table with two cases
(e.g., "AddingReference" and "AddingDuplicateReference") each containing the
initial Resource/References state and the Reference to add, expected error (nil
or ErrReferenceAlreadyExists) and expected length; iterate cases calling
References.AddReference on Resource (use Resource and References.AddReference
symbols), assert error matches expected and length of r.References matches want;
keep PascalCase test name and args/want variables to conform to repo
conventions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pkg/config/resource_test.go`:
- Around line 309-311: The failure message when checking len(r.References) is
misleading because it prints the unrelated err; update the t.Fatalf in the test
that calls AddReference so it reports the actual length and contents of
r.References instead of "AddReference() got error". Concretely, change the
t.Fatalf that triggers on len(r.References) != 1 to something like: include
expected vs actual count and the r.References value (e.g., "AddReference():
expected 1 reference, got %d: %#v", len(r.References), r.References), and remove
the err value from that message.

---

Nitpick comments:
In `@pkg/config/resource_test.go`:
- Around line 300-329: Rename the test from TestReferences_AddReference to
TestReferencesAddReference and rewrite it as a table-driven test using args/want
style: create a test table with two cases (e.g., "AddingReference" and
"AddingDuplicateReference") each containing the initial Resource/References
state and the Reference to add, expected error (nil or
ErrReferenceAlreadyExists) and expected length; iterate cases calling
References.AddReference on Resource (use Resource and References.AddReference
symbols), assert error matches expected and length of r.References matches want;
keep PascalCase test name and args/want variables to conform to repo
conventions.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ac6358e0-043b-46ec-af7c-ef2e820654a5

📥 Commits

Reviewing files that changed from the base of the PR and between c6d5213 and 97604aa.

📒 Files selected for processing (2)
  • pkg/config/resource.go
  • pkg/config/resource_test.go

Comment on lines +309 to +311
if len(r.References) != 1 {
t.Fatalf("AddReference() got error: %v", err)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Line 310 has a misleading failure message.

When len(r.References) != 1, the test reports AddReference() got error, which can print <nil> and obscure the actual failure. Please report the map length/value mismatch instead.

Suggested fix
-		if len(r.References) != 1 {
-			t.Fatalf("AddReference() got error: %v", err)
-		}
+		if len(r.References) != 1 {
+			t.Fatalf("AddReference() expected 1 reference, got %d", len(r.References))
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(r.References) != 1 {
t.Fatalf("AddReference() got error: %v", err)
}
if len(r.References) != 1 {
t.Fatalf("AddReference() expected 1 reference, got %d", len(r.References))
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/config/resource_test.go` around lines 309 - 311, The failure message when
checking len(r.References) is misleading because it prints the unrelated err;
update the t.Fatalf in the test that calls AddReference so it reports the actual
length and contents of r.References instead of "AddReference() got error".
Concretely, change the t.Fatalf that triggers on len(r.References) != 1 to
something like: include expected vs actual count and the r.References value
(e.g., "AddReference(): expected 1 reference, got %d: %#v", len(r.References),
r.References), and remove the err value from that message.

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.

3 participants