Skip to content

Add repository option to crossplane project init#105

Open
bobh66 wants to merge 4 commits into
crossplane:mainfrom
bobh66:initrepo
Open

Add repository option to crossplane project init#105
bobh66 wants to merge 4 commits into
crossplane:mainfrom
bobh66:initrepo

Conversation

@bobh66

@bobh66 bobh66 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Description of your changes

Added the --repository option to crossplane project init to override the default example.com/my-org values.

Made the directory name truly optional.

I have:

Need help with this checklist? See the cheat sheet.

@bobh66 bobh66 requested review from a team, jcogilvie and tampakrap as code owners June 12, 2026 17:28
@bobh66 bobh66 requested review from jbw976 and removed request for a team June 12, 2026 17:28
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The crossplane project init command adds a Registry flag and Repository argument with defaults, imports a containerregistry validation library, normalizes and validates the repository input at runtime, and uses the computed repository string to populate spec.repository in the generated project YAML.

Changes

Project initialization repository configuration

Layer / File(s) Summary
CLI argument declarations
cmd/crossplane/project/init.go
initCmd struct tags updated: Name and Directory are standardized, and new Registry flag added with default example.com/my-org and short flag -r; Repository field added as an optional argument.
Repository construction and validation
cmd/crossplane/project/init.go
Import of github.com/google/go-containerregistry/pkg/name for validation; Run trims and validates Registry (error if empty after normalization), defaults Repository to Name when blank, and constructs the final repository via name.NewRepository(registryPrefix + "/" + repositoryName).
Template repository formatting
cmd/crossplane/project/init.go
Generated crossplane-project.yaml spec.repository now renders the computed repository string (.String()) instead of the hardcoded example.com/my-org/<name> template.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately describes the main change: adding a --repository option to the crossplane project init command, and it meets the 72-character limit.
Description check ✅ Passed The description is directly related to the changeset, explaining the new --repository option and how it overrides default values, which aligns with the code changes.
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.
Breaking Changes ✅ Passed PR adds two optional flags (--registry and --repository) to initCmd in cmd/crossplane/project/init.go with no removal/renaming of fields, no required fields added, and maintains backward compatibil...
Feature Gate Requirement ✅ Passed PR adds CLI flags to existing crossplane project init command to configure existing API fields; doesn't introduce new experimental features to APIs or require feature gates.

✏️ 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

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 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 `@cmd/crossplane/project/init.go`:
- Around line 77-78: Normalize and validate the repository base (c.Repository)
before composing spec.repository: ensure c.Repository is non-empty and trim any
trailing slashes or whitespace, then join it with c.Name using a safe join
(e.g., path.Join or by appending "/" then name) instead of raw "%s/%s"
concatenation so you never produce double slashes; update the code that formats
spec.repository (the spot using c.Repository and c.Name) to use the normalized
value and return or surface a validation error if repository is empty/invalid.
- Line 42: The Directory field in the project init command is currently declared
as a positional arg (arg:"") but also has a short flag, so --directory/-d won't
parse; change Directory in cmd/crossplane/project/init.go from a positional to a
real flag by removing arg:"" and replacing it with a name tag and the existing
short/help/type tags (e.g. name:"directory" short:"d" help:"Directory to
initialize..." type:"path"), and if you instead prefer a second positional arg
update the command help/examples in cmd/crossplane/project/help/init.md to show
the positional usage; locate the Directory field in the relevant struct to apply
the change.
🪄 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: cb516f46-3c47-48a4-a6a1-4696dba3d528

📥 Commits

Reviewing files that changed from the base of the PR and between 079254b and 3943268.

📒 Files selected for processing (1)
  • cmd/crossplane/project/init.go

Comment thread cmd/crossplane/project/init.go Outdated
Comment thread cmd/crossplane/project/init.go Outdated
Make the directory name truly optional.

Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>
Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>

@coderabbitai coderabbitai Bot 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.

♻️ Duplicate comments (1)
cmd/crossplane/project/init.go (1)

65-68: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Whitespace-only repository values can pass validation and generate invalid spec.repository.

Could you confirm whether --repository " " should be rejected? On Line 65, only trailing / is trimmed; on Line 66 the emptiness check can be bypassed by whitespace, which then propagates to Line 81 and fails later in downstream repository parsing.

Suggested minimal fix
-	repo := strings.TrimRight(c.Repository, "/")
+	repo := strings.TrimRight(strings.TrimSpace(c.Repository), "/")
 	if repo == "" {
 		return errors.New("repository cannot be empty; set --repository to an OCI repository prefix like 'xpkg.crossplane.io/my-org'")
 	}
🤖 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 `@cmd/crossplane/project/init.go` around lines 65 - 68, The current validation
trims only trailing slashes and allows all-whitespace repository values to pass;
update the handling of c.Repository by applying strings.TrimSpace (and still
TrimRight for slashes if needed) to produce repo, then validate repo == "" after
trimming so that inputs like "--repository \"   \"" are rejected; ensure the
rest of the function (where repo is used to set spec.repository) uses this
trimmed repo variable (referencing c.Repository, repo) so downstream parsing no
longer sees whitespace-only values.
🧹 Nitpick comments (1)
cmd/crossplane/project/init.go (1)

50-83: ⚡ Quick win

Please add focused tests for repository normalization and optional directory behavior.

Thanks for the feature update — would you add table-driven coverage for: default repository, trailing slash trimming, whitespace-only rejection, and omitted directory defaulting to project name? This should lock in the intended CLI UX and prevent regressions.

🤖 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 `@cmd/crossplane/project/init.go` around lines 50 - 83, Add table-driven unit
tests for initCmd.Run to validate repository normalization and directory
defaulting: create test cases for (1) default repository value (empty repo
should error with the same message as currently returned for repo == ""), (2)
repository with trailing slash gets normalized (strings.TrimRight) and appears
in generated content, (3) whitespace-only repository is rejected, and (4)
omitted Directory results in c.Directory being set to c.Name and used to create
projectFileName content; instantiate initCmd with appropriate fields, call Run
with a no-op SpinnerPrinter or wrap the inner logic (refer to initCmd.Run,
c.Repository, c.Directory, checkTargetDirectory, and projectFileName) and assert
expected errors or generated file/content behavior for each table row.
🤖 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 `@cmd/crossplane/project/init.go`:
- Around line 65-68: The current validation trims only trailing slashes and
allows all-whitespace repository values to pass; update the handling of
c.Repository by applying strings.TrimSpace (and still TrimRight for slashes if
needed) to produce repo, then validate repo == "" after trimming so that inputs
like "--repository \"   \"" are rejected; ensure the rest of the function (where
repo is used to set spec.repository) uses this trimmed repo variable
(referencing c.Repository, repo) so downstream parsing no longer sees
whitespace-only values.

---

Nitpick comments:
In `@cmd/crossplane/project/init.go`:
- Around line 50-83: Add table-driven unit tests for initCmd.Run to validate
repository normalization and directory defaulting: create test cases for (1)
default repository value (empty repo should error with the same message as
currently returned for repo == ""), (2) repository with trailing slash gets
normalized (strings.TrimRight) and appears in generated content, (3)
whitespace-only repository is rejected, and (4) omitted Directory results in
c.Directory being set to c.Name and used to create projectFileName content;
instantiate initCmd with appropriate fields, call Run with a no-op
SpinnerPrinter or wrap the inner logic (refer to initCmd.Run, c.Repository,
c.Directory, checkTargetDirectory, and projectFileName) and assert expected
errors or generated file/content behavior for each table row.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 93e17c21-4531-4195-950c-bdee283d8b13

📥 Commits

Reviewing files that changed from the base of the PR and between 3943268 and 92b63fa.

📒 Files selected for processing (1)
  • cmd/crossplane/project/init.go

Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>
@bobh66

bobh66 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

Docs PR crossplane/docs#1108

Comment thread cmd/crossplane/project/init.go Outdated
Comment on lines +81 to +82
repository: %s/%s
`, c.Name, repo, c.Name)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd prefer to just use repo when it's specified, rather than appending the project name. OCI defines two things: registries and repositories; the in-between of a partially-specified repository isn't really a concept.

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.

Don't we really have three parts - the registry, the org and the repository? Maybe the option should be registryPath or similar to include both the registry and the org? I'd like to be able to default the repository name to the project name rather than have to specify it again in the registry path.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The first component of the repository being an organization name is just a convention, not specified by OCI. That said, it is a very common convention - every public registry I can think of follows it (GHCR, Docker Hub, Upbound marketplace, etc.).

Agreed it's a nice UX to not require repeating the project name. I think making the argument --registry (not technically correct, but less surprising to append to it) or --repository-prefix would make sense. That would allow for a --repository flag to provide the full path as well, if users want the repository name to not match the project name.

Comment thread cmd/crossplane/project/init.go Outdated

repo := strings.TrimRight(strings.TrimSpace(c.Repository), "/")
if repo == "" {
return errors.New("repository cannot be empty; set --repository to an OCI repository prefix like 'xpkg.crossplane.io/my-org'")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Might be worth validating that repo is a valid, fully-qualified repository by calling name.NewRepository.

Signed-off-by: Bob Haddleton <bob.haddleton@nokia.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 3

🤖 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 `@cmd/crossplane/project/init.go`:
- Around line 74-77: The error message in the repository creation block uses
internal wording "cannot build function reference" which is confusing in the
project init command context. Replace this error message with user-facing
wording that clearly indicates the problem is with invalid registry or
repository parameters provided via the --registry and --repository command
flags. Keep the same error wrapping structure but update the message text to be
more actionable and appropriate for the project init command path.
- Around line 61-63: In the Repository field initialization block, the TrimSpace
function is only used for the emptiness check, but the untrimmed value is still
assigned to c.Repository when empty. Persist the trimmed value by assigning the
result of strings.TrimSpace(c.Repository) back to c.Repository before the
fallback check, so that any subsequent validation or usage of the Repository
field at line 74 or elsewhere operates on the normalized value without
accidental leading or trailing whitespace.
- Around line 70-72: The error message returned when the registry path is empty
references the incorrect flag name. In the if block that checks if rp == "",
update the error message to reference the actual flag name `--registry` instead
of `--registryPath` to match the flag definition on line 44 and provide users
with accurate guidance for fixing the issue.
🪄 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: cf7f8fff-566c-4f03-8e2e-bd789ffec85c

📥 Commits

Reviewing files that changed from the base of the PR and between 4675ae8 and 81a8e27.

📒 Files selected for processing (1)
  • cmd/crossplane/project/init.go

Comment on lines +61 to +63
if strings.TrimSpace(c.Repository) == "" {
c.Repository = c.Name
}

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize Repository after trimming, before fallback and validation.

Right now TrimSpace is only used for the emptiness check, but Line 74 still consumes the untrimmed value. Could we persist the trimmed value so accidental leading/trailing spaces don’t cause avoidable parse failures?

Suggested patch
-	if strings.TrimSpace(c.Repository) == "" {
+	c.Repository = strings.TrimSpace(c.Repository)
+	if c.Repository == "" {
 		c.Repository = c.Name
 	}
🤖 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 `@cmd/crossplane/project/init.go` around lines 61 - 63, In the Repository field
initialization block, the TrimSpace function is only used for the emptiness
check, but the untrimmed value is still assigned to c.Repository when empty.
Persist the trimmed value by assigning the result of
strings.TrimSpace(c.Repository) back to c.Repository before the fallback check,
so that any subsequent validation or usage of the Repository field at line 74 or
elsewhere operates on the normalized value without accidental leading or
trailing whitespace.

Comment on lines +70 to +72
if rp == "" {
return errors.New("registry cannot be empty; set --registryPath to an OCI registry prefix like 'xpkg.crossplane.io/my-org'")
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the actual flag name in the empty-registry error message.

Line 71 points users to --registryPath, but the command defines --registry (Line 44). Could we update this so users can recover immediately?

Suggested patch
-		return errors.New("registry cannot be empty; set --registryPath to an OCI registry prefix like 'xpkg.crossplane.io/my-org'")
+		return errors.New("registry cannot be empty; set --registry to an OCI repository prefix like 'xpkg.crossplane.io/my-org'")

As per coding guidelines, CLI errors in cmd/** should provide actionable user guidance.

🤖 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 `@cmd/crossplane/project/init.go` around lines 70 - 72, The error message
returned when the registry path is empty references the incorrect flag name. In
the if block that checks if rp == "", update the error message to reference the
actual flag name `--registry` instead of `--registryPath` to match the flag
definition on line 44 and provide users with accurate guidance for fixing the
issue.

Source: Coding guidelines

Comment on lines +74 to +77
r, err := name.NewRepository(rp + "/" + c.Repository)
if err != nil {
return errors.Wrapf(err, "cannot build function reference from repository \"%s/%s\"", rp, c.Repository)
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace internal “function reference” wording with project init context.

The wrapped message says “cannot build function reference…”, which is confusing in this command path. Please use user-facing wording tied to invalid --registry/--repository input.

Suggested patch
-		return errors.Wrapf(err, "cannot build function reference from repository \"%s/%s\"", rp, c.Repository)
+		return errors.Wrapf(err, "invalid repository value %q from --registry/--repository", rp+"/"+c.Repository)

Based on learnings, concise error strings are preferred when they clearly state the issue; as per coding guidelines for cmd/**, error text should remain user-facing and actionable.

🤖 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 `@cmd/crossplane/project/init.go` around lines 74 - 77, The error message in
the repository creation block uses internal wording "cannot build function
reference" which is confusing in the project init command context. Replace this
error message with user-facing wording that clearly indicates the problem is
with invalid registry or repository parameters provided via the --registry and
--repository command flags. Keep the same error wrapping structure but update
the message text to be more actionable and appropriate for the project init
command path.

Sources: Coding guidelines, Learnings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants