Skip to content

bump crossplane-runtime and crossplane/apis to v2.3.3 - #664

Merged
jonasz-lasut merged 6 commits into
crossplane:mainfrom
jschoombee:crossplane-runtime-v2.3.1
Jul 27, 2026
Merged

bump crossplane-runtime and crossplane/apis to v2.3.3#664
jonasz-lasut merged 6 commits into
crossplane:mainfrom
jschoombee:crossplane-runtime-v2.3.1

Conversation

@jschoombee

@jschoombee jschoombee commented May 31, 2026

Copy link
Copy Markdown
Contributor

Description of your changes

This PR adopts crossplane-runtime v2.3.x in upjet/v2, pinned to the latest patch v2.3.3 (along with crossplane/apis/v2 v2.3.3).

The v2.3.0 release relocated the common APIs out of crossplane-runtime into the consolidated github.com/crossplane/crossplane/apis/v2/core/v2 package and renamed the inline-embedded spec/status types. Today upjet still imports the removed paths, so any downstream provider that wants to pick up v2.3.x is blocked.

API compatibility

The two renamed embeds are structurally identical to the originals — same fields, same JSON tags, same kubebuilder defaults:

Old (crossplane-runtime/v2/apis/common/v1) New (crossplane/apis/v2/core/v2)
ResourceSpec (cluster-scoped MRs) ClusterManagedResourceSpec
ResourceStatus ManagedResourceStatus

All other common symbols (Reference, Selector, SecretReference, SecretKeySelector, LocalSecretReference, LocalSecretKeySelector, NamespacedReference, NamespacedSelector, Condition*, ManagementAction*, ManagementPolicies, DeletionPolicy, …) keep their names — only the import path changes. So providers that regenerate after this lands see no CRD schema drift.

Migration applied

  1. Imports across 17 hand-written files (pkg/config, pkg/controller, pkg/resource, pkg/terraform, pkg/types, pkg/pipeline, tests/conversion, plus the GoMock fake at pkg/resource/fake/mocks/mock.go): swap the three retired package paths (apis/common, apis/common/v1, apis/common/v2) for github.com/crossplane/crossplane/apis/v2/core/v2. gci re-ordered into the project's import sections.
  2. Codegen constants in pkg/types/reference.go: both PackagePathXPCommonAPIs and PackagePathXPV2CommonAPIs now resolve to the consolidated path. They're kept as two constants for source-level backward compatibility — typewriter's UsePackage dedupes by path so emitted imports collapse to a single alias. The types.NewPackage package-name argument corrected from "v1" to "v2" to match the real package declaration.
  3. Codegen template in pkg/pipeline/templates/crd_types.go.tmpl:
    • ResourceSpecClusterManagedResourceSpec for cluster-scoped CRDs.
    • ResourceStatusManagedResourceStatus for the embedded status (both scopes).
  4. Embedded type-string fixtures in pkg/types/builder_test.go refreshed to match the new fully-qualified path.
  5. tests/conversion/test_resource.go field embeds renamed to ClusterManagedResourceSpec / ManagedResourceStatus.
  6. pkg/pipeline/hooks_test.go golden fixture aligned with the updated crd_types.go.tmpl output.
  7. .github/workflows/ci.yml: switched all jobs from a pinned GO_VERSION env var to go-version-file: go.mod (including the race-tests job which was missed in the initial commit and caused a GOTOOLCHAIN=local failure against the runner's Go 1.24). The minimum Go floor is now 1.25.11 (set by crossplane-runtime v2.3.3 via go mod tidy).
  8. go.mod: crossplane-runtime/v2 v2.2.0v2.3.3; new direct require on crossplane/apis/v2 v2.3.3; go mod tidy.
  9. docs/upjet-v2-upgrade.md: new "v2.3 common-API migration" subsection with corrected prerequisite ordering (step 1 go mod tidy must succeed before step 2 make generate), plus a scope note on the existing apis section to prevent readers migrating from v2→v2.3 from copying the v1-era import paths below it.

Fixes #663

Note for reviewers: CodeRabbit's path filters exclude go.mod, go.sum, pkg/pipeline/templates/crd_types.go.tmpl, and pkg/resource/fake/mocks/mock.go from automated review. The template change in particular is the most consequential part of the PR — eyes welcome there.

The two codegen constants PackagePathXPCommonAPIs / PackagePathXPV2CommonAPIs are intentionally kept as separate constants (now with identical values) to avoid a source-level break for any downstream that references them directly. Collapsing them to a single constant and simplifying the template's dual-alias scheme is left for a follow-up.

I have:

  • Read and followed Upjet's contribution process.
  • Verified locally: go vet ./..., gci write with the repo's section config, go generate ./... (no diff), and go test ./... -count=1 (all packages green, including tests/conversion/TestConversionIntegration which exercises the codegen template end-to-end).
  • Verified on CI: workflow_dispatch of ci.yml on the fork's branch — lint, unit-tests, check-diff, and race-tests all pass.
  • Added backport release-x.y labels — intentionally not requesting a backport: release-2.2 is pinned to a pseudo-version of crossplane-runtime/v2 (pre-v2.2.0) and Go 1.24.13, so pulling v2.3 onto that maintenance line would defeat the point of the line. Forward-only.

How has this code been tested

  • go build ./... clean.
  • go test ./... -count=1 clean across all 23 packages.
  • tests/conversion/TestConversionIntegration exercises the codegen pipeline end-to-end against a test provider and asserts roundtrip conversions across versions, covering the updated crd_types.go.tmpl and new package path constants.
  • Fork-side CI (workflow_dispatch): lint, unit-tests, check-diff, and race-tests all green.

@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates Crossplane common API imports and symbols to github.com/crossplane/crossplane/apis/v2/core/v2 across controllers, resources, tests, codegen constants, CI workflow, and upgrade docs.

Changes

Common API Package Migration

Layer / File(s) Summary
Controller & config imports
pkg/config/resource.go, pkg/controller/api.go, pkg/controller/external.go, pkg/controller/external_async_tfpluginfw.go, pkg/controller/external_async_tfpluginsdk.go, pkg/controller/external_test.go, pkg/controller/external_tfpluginfw.go, pkg/controller/external_tfpluginsdk.go
Update imports to github.com/crossplane/crossplane/apis/v2/core/v2 and switch management-policy, readiness/availability, and reconcile-condition symbols to xpv2 usage.
Resource conditions, sensitive handling, terraform files & tests
pkg/resource/conditions.go, pkg/resource/sensitive.go, pkg/resource/sensitive_test.go, pkg/terraform/files.go, pkg/terraform/files_test.go, pkg/terraform/* tests
Migrate condition reason constants and helpers, SecretReference/SecretKeySelector types, SecretClient signatures, GetSensitiveObservation, connection secret reference helpers, and many gomock expectations to core v2 types.
Codegen constants and builder test expectations
pkg/types/reference.go, pkg/types/builder_test.go, pkg/pipeline/hooks_test.go
Update package-path constants to core v2 and update builder test expected generated forProvider types and embedded test snippet import paths to reference core v2 selector/reference types.
Test fixtures and conversion resource updates
tests/conversion/test_resource.go, pkg/pipeline/hooks_test.go
Update conversion test resource embeds to ClusterManagedResourceSpec/ManagedResourceStatus and switch test imports/mocks to xpv2 types.
CI workflow and docs
.github/workflows/ci.yml, docs/upjet-v2-upgrade.md
Bump CI env.GO_VERSION and have setup-go use go-version-file: go.mod; add upgrade guide describing import/embed migrations and regeneration steps.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • ulucinar
  • sergenyalcin
🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Linked Issues check ✅ Passed All coding requirements from issue #663 are met: imports migrated to consolidated path, codegen constants updated, template modified for renamed types, test fixtures refreshed, go.mod bumped, and Go version updated.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #663's requirements: API migration, codegen updates, dependency bumps, documentation, and CI toolchain alignment. No unrelated modifications detected.
Configuration Api Breaking Changes ✅ Passed pkg/config/resource.go contains only internal implementation changes (xpv1→xpv2 dependency migration); no exported types/functions/signatures changed, confirming the PR summary statement.
Generated Code Manual Edits ✅ Passed No files matching 'zz_*.go' pattern were modified in this PR. All 19 changed files are hand-written source files and documentation, not generated code.
Template Breaking Changes ✅ Passed Changes to pkg/controller/external*.go are type/import migrations (xpv1→xpv2 APIs) with no business logic or control flow alterations; no actual controller templates were modified.
Title check ✅ Passed The title is concise, under 72 characters, and clearly describes the Crossplane v2.3.3 bump.
Description check ✅ Passed The description directly matches the changeset by explaining the v2.3.x API migration, dependency bump, and related codegen updates.

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.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/pipeline/hooks_test.go (1)

167-178: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Migration looks half-applied in this fixture — import moved, but the embedded type names didn't. 🧐

The import on Line 167 now points to github.com/crossplane/crossplane/apis/v2/core/v2, but Lines 171 and 176 still embed v1.ResourceSpec / v1.ResourceStatus, which were renamed to ClusterManagedResourceSpec / ManagedResourceStatus at the consolidated path. Since baseContent is only a string fixture for marker manipulation (not compiled), the tests still pass — so no functional breakage here. That said, given the crd_types.go.tmpl template now emits the renamed types, updating the fixture keeps it faithful to real generated output and avoids confusing the next maintainer. Was leaving the old names here intentional?

📝 Suggested fixture alignment
 type MemberSpec struct {
-	v1.ResourceSpec ` + "`json:\",inline\"`" + `
+	v1.ClusterManagedResourceSpec ` + "`json:\",inline\"`" + `
 	ForProvider     MemberParameters ` + "`json:\"forProvider\"`" + `
 }

 type MemberStatus struct {
-	v1.ResourceStatus ` + "`json:\",inline\"`" + `
+	v1.ManagedResourceStatus ` + "`json:\",inline\"`" + `
 	AtProvider        MemberObservation ` + "`json:\"atProvider,omitempty\"`" + `
 }
🤖 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 `@pkg/pipeline/hooks_test.go` around lines 167 - 178, The fixture import was
updated to github.com/crossplane/crossplane/apis/v2/core/v2 but the embedded
types in MemberSpec and MemberStatus still reference v1.ResourceSpec and
v1.ResourceStatus; update those embeddings to the consolidated names
ClusterManagedResourceSpec and ManagedResourceStatus respectively (e.g., replace
v1.ResourceSpec with ClusterManagedResourceSpec and v1.ResourceStatus with
ManagedResourceStatus in the MemberSpec and MemberStatus structs) so the test
fixture matches the output produced by crd_types.go.tmpl.
🤖 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 `@pkg/types/reference.go`:
- Around line 22-29: The doc comments above the constants
PackagePathXPCommonAPIs and PackagePathXPV2CommonAPIs are stale/misleading (they
say “Crossplane Runtime package” vs actual target) — update both comments to
describe that they point to the Crossplane core APIs package (e.g., “Crossplane
core APIs”) and optionally note that types like Reference, Selector,
SecretKeySelector, SecretReference, LocalSecretReference,
LocalSecretKeySelector, NamespacedReference, and NamespacedSelector are exported
from github.com/crossplane/crossplane/apis/v2/core/v2 so the consolidation is
safe; change only the comment text near PackagePathXPCommonAPIs and
PackagePathXPV2CommonAPIs without modifying the constant values or other code.

---

Outside diff comments:
In `@pkg/pipeline/hooks_test.go`:
- Around line 167-178: The fixture import was updated to
github.com/crossplane/crossplane/apis/v2/core/v2 but the embedded types in
MemberSpec and MemberStatus still reference v1.ResourceSpec and
v1.ResourceStatus; update those embeddings to the consolidated names
ClusterManagedResourceSpec and ManagedResourceStatus respectively (e.g., replace
v1.ResourceSpec with ClusterManagedResourceSpec and v1.ResourceStatus with
ManagedResourceStatus in the MemberSpec and MemberStatus structs) so the test
fixture matches the output produced by crd_types.go.tmpl.
🪄 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: a1dd9105-d8ff-4e29-a6ae-70adbb07c1d0

📥 Commits

Reviewing files that changed from the base of the PR and between 4edc29a and ab80340.

⛔ Files ignored due to path filters (4)
  • go.mod is excluded by none and included by none
  • go.sum is excluded by !**/*.sum and included by none
  • pkg/pipeline/templates/crd_types.go.tmpl is excluded by none and included by none
  • pkg/resource/fake/mocks/mock.go is excluded by !**/fake/** and included by **/*.go
📒 Files selected for processing (17)
  • pkg/config/resource.go
  • pkg/controller/api.go
  • pkg/controller/external.go
  • pkg/controller/external_async_tfpluginfw.go
  • pkg/controller/external_async_tfpluginsdk.go
  • pkg/controller/external_test.go
  • pkg/controller/external_tfpluginfw.go
  • pkg/controller/external_tfpluginsdk.go
  • pkg/pipeline/hooks_test.go
  • pkg/resource/conditions.go
  • pkg/resource/sensitive.go
  • pkg/resource/sensitive_test.go
  • pkg/terraform/files.go
  • pkg/terraform/files_test.go
  • pkg/types/builder_test.go
  • pkg/types/reference.go
  • tests/conversion/test_resource.go

Comment thread pkg/types/reference.go
@Upbound-CLA

Upbound-CLA commented Jun 2, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Comment thread .github/workflows/ci.yml Outdated
env:
# Common versions
GO_VERSION: "1.25.8"
GO_VERSION: "1.25.10"

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.

Out of the scope of this PR, but we can use go-version-file: go.mod in the setup-go action to avoid this coupling.

Comment thread pkg/controller/external.go Outdated
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 8, 2026
The common APIs were relocated to a v2 package, so the xpv1 alias no
longer reflects the import path. Standardise on xpv2 across all
hand-written files; also unify the lone v1 alias in sensitive.go onto
the same name. mockgen-generated fake still uses its default basename
alias (v2) since it is regenerated.

Addresses review feedback on crossplane#664.
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 8, 2026
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 8, 2026
The common APIs were relocated to a v2 package, so the xpv1 alias no
longer reflects the import path. Standardise on xpv2 across all
hand-written files; also unify the lone v1 alias in sensitive.go onto
the same name. mockgen-generated fake still uses its default basename
alias (v2) since it is regenerated.

Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 8, 2026
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
@jschoombee
jschoombee force-pushed the crossplane-runtime-v2.3.1 branch from eb242fc to 7aa83b7 Compare June 8, 2026 14:30
@jschoombee

jschoombee commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @fernandezcuesta — both addressed:

  • xpv1xpv2 everywhere (also caught a stray v1 alias in sensitive.go). 8f76572
  • go-version-file: go.mod across all three jobs, dropped the env var. 7aa83b7

Fork CI green.

jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 29, 2026
The common APIs were relocated to a v2 package, so the xpv1 alias no
longer reflects the import path. Standardise on xpv2 across all
hand-written files; also unify the lone v1 alias in sensitive.go onto
the same name. mockgen-generated fake still uses its default basename
alias (v2) since it is regenerated.

Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
@jschoombee
jschoombee force-pushed the crossplane-runtime-v2.3.1 branch from 7aa83b7 to 2b10525 Compare June 29, 2026 19:59
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 29, 2026
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
@jschoombee jschoombee changed the title bump crossplane-runtime to v2.3.1 bump crossplane-runtime and crossplane/apis to v2.3.3 Jun 29, 2026
@jschoombee
jschoombee force-pushed the crossplane-runtime-v2.3.1 branch from 09f1f25 to bc24ab9 Compare June 29, 2026 20:30
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 29, 2026
The common APIs were relocated to a v2 package, so the xpv1 alias no
longer reflects the import path. Standardise on xpv2 across all
hand-written files; also unify the lone v1 alias in sensitive.go onto
the same name. mockgen-generated fake still uses its default basename
alias (v2) since it is regenerated.

Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jun 29, 2026
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
@jschoombee
jschoombee force-pushed the crossplane-runtime-v2.3.1 branch from bc24ab9 to 10c27c6 Compare June 29, 2026 20:47
Duologic added a commit to grafana/crossplane-provider-grafana that referenced this pull request Jul 2, 2026
The Grafana TF provider v4.39.x pulls in the k8s.io v0.36 stack (via
grafana-app-sdk and grafana/apps/provisioning). client-go v0.36 added
HasSyncedChecker() to cache.ResourceEventHandlerRegistration, which the
controller-runtime v0.22 pinned by crossplane-runtime v2.1.x does not
implement, breaking codegen.

The k8s.io modules are a co-versioned set and cannot straddle
v0.35/v0.36 individually, so pin the whole stack (api, apimachinery,
apiserver, apiextensions-apiserver, client-go, code-generator,
component-base) back to v0.35.3 as a matched set until controller-runtime
v0.24 lands via crossplane-runtime (crossplane/crossplane-runtime#1037)
and upjet adopts it (crossplane/upjet#664).

Includes regenerated code from 'make generate' for the v4.39.1 schema.

Refs #601
Duologic added a commit to grafana/crossplane-provider-grafana that referenced this pull request Jul 3, 2026
## Resolution

The `make generate` failure was caused by `terraform-provider-grafana`
v4.39.x pulling in the **k8s.io v0.36** stack while crossplane-runtime
v2.1.x still pins **controller-runtime v0.22** (which does not implement
client-go v0.36's `HasSyncedChecker()` on
`cache.ResourceEventHandlerRegistration`).

As a temporary workaround, this PR pins the whole k8s.io stack back to
v0.35.3 via `replace` directives (they're a co-versioned set and can't
straddle v0.35/v0.36 individually). `make submodules && make generate`
now completes and the regenerated code is committed.

- Removal of the `replace` block is tracked in #622 (blocked on
controller-runtime v0.24 upstream: crossplane/crossplane-runtime#1037 +
crossplane/upjet#664).

Closes #601

---

## Automated dependency update

Updates `terraform-provider-grafana` to v4.39.1.

**Release**:
https://github.com/grafana/terraform-provider-grafana/releases/tag/v4.39.1

### Changelog

### Bug Fixes
- **appplatform:** retry transient referential-integrity and server
errors
([#2838](grafana/terraform-provider-grafana#2838))
by @rknightion
- **appplatform:** exponential backoff for retries via k8s wait.Backoff
([#2844](grafana/terraform-provider-grafana#2844))
by @MissingRoberto
- **asserts:** omit empty match values for null-check operators
([#2854](grafana/terraform-provider-grafana#2854))
by @vpadi
- **deps:** update module github.com/prometheus/common to v0.69.0
([#2827](grafana/terraform-provider-grafana#2827))
by @renovate-sh-app[bot]

### CI/CD
- **workflows:** add workflow for validation of unpublished builds
([#2780](grafana/terraform-provider-grafana#2780))
by @suntala
- **workflows:** align validate-unpublished-provider with field-eng
([#2845](grafana/terraform-provider-grafana#2845))
by @suntala
- **workflows:** poll cloud acceptance gate until tests finish
([#2855](grafana/terraform-provider-grafana#2855))
by @suntala

### Documentation
- clarify provider config for git sync App Platform resources
([#2843](grafana/terraform-provider-grafana#2843))
by @MissingRoberto

### Miscellaneous
- **cloud:** move to new stacks connections endpoint
([#2840](grafana/terraform-provider-grafana#2840))
by @nachogiljaldo

**Full Changelog**:
[v4.39.0...v4.39.1](grafana/terraform-provider-grafana@v4.39.0...v4.39.1)

---
*This PR was automatically created by the
[update-terraform-provider](https://github.com/grafana/crossplane-provider-grafana/actions/workflows/update-terraform-provider.yaml)
workflow.*

---------

Co-authored-by: terraform-provider-grafana[bot] <220933401+terraform-provider-grafana[bot]@users.noreply.github.com>
Co-authored-by: Duologic <jeroen@simplistic.be>
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jul 16, 2026
The common APIs were relocated to a v2 package, so the xpv1 alias no
longer reflects the import path. Standardise on xpv2 across all
hand-written files; also unify the lone v1 alias in sensitive.go onto
the same name. mockgen-generated fake still uses its default basename
alias (v2) since it is regenerated.

Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
@jschoombee
jschoombee force-pushed the crossplane-runtime-v2.3.1 branch from 10c27c6 to afe599f Compare July 16, 2026 07:41
jschoombee added a commit to jschoombee/upjet that referenced this pull request Jul 16, 2026
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
….3.x

crossplane-runtime v2.3.0 moved the common APIs (formerly
crossplane-runtime/v2/apis/common/{v1,v2} and the unversioned apis/common
mock surface) into a single consolidated package at
github.com/crossplane/crossplane/apis/v2/core/v2, and renamed the
inline-embedded spec/status types:

- v1.ResourceSpec     → v2.ClusterManagedResourceSpec (cluster-scoped)
                      → v2.ManagedResourceSpec        (namespaced; existing)
- v1.ResourceStatus   → v2.ManagedResourceStatus
- v1/v2 SecretReference, SecretKeySelector, Reference, Selector, Condition,
  ManagementAction*, ManagementPolicies, DeletionPolicy, etc. — same names,
  new package path.

Migration in this commit:
- Bulk-swap every Go import of the three removed paths to the consolidated
  path across pkg/, tests/, and the GoMock fake (apis/common at root).
- Refresh the embedded type-string fixtures in pkg/types/builder_test.go
  to match the new fully-qualified path.
- Update pkg/types/reference.go PackagePath* constants so generated CRD
  types reference the new package (both XPCommonAPIs and XPV2CommonAPIs
  now point at the same consolidated package, kept as separate constants
  for source-level backward compatibility).
- Update pkg/pipeline/templates/crd_types.go.tmpl to emit
  ClusterManagedResourceSpec for cluster-scoped MRs and
  ManagedResourceStatus for the embedded status — both required by the
  consolidated v2 API.
- Hand-edit tests/conversion/test_resource.go ResourceSpec/Status
  references to use the new cluster-scoped type names.
- go.mod: bump crossplane-runtime/v2 v2.2.0 → v2.3.1, add direct require
  on crossplane/apis/v2 v2.3.1; go mod tidy.

Unblocks providers (e.g. provider-wiz) that consume upjet and want to
adopt crossplane-runtime v2.3.x.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
… in test fixtures

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
… package name in type builder

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
The common APIs were relocated to a v2 package, so the xpv1 alias no
longer reflects the import path. Standardise on xpv2 across all
hand-written files; also unify the lone v1 alias in sensitive.go onto
the same name. mockgen-generated fake still uses its default basename
alias (v2) since it is regenerated.

Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
@jonasz-lasut
jonasz-lasut force-pushed the crossplane-runtime-v2.3.1 branch from afe599f to 6e54b16 Compare July 27, 2026 14:24
@jonasz-lasut

Copy link
Copy Markdown
Collaborator

Hi @jschoombee thank you for opening this PR! I've pushed a commit to rebase your branch against main as we've had some changes and go.mod was stale.

@jonasz-lasut

Copy link
Copy Markdown
Collaborator

Runbook for taking a generic upjet v2 provider to crossplane-runtime v2.3.x. Written while migrating provider-upjet-azure, with every command validated against that repo — details in How this was validated at the end.

crossplane-runtime v2.3.0 deleted apis/common/v1 and apis/common/v2. Both collapsed into a single package in a different module: github.com/crossplane/crossplane/apis/v2/core/v2.

TL;DR

Everything, in order, from the provider root:

# --- 1. modules: one resolution pass -----------------------------------------
go get github.com/crossplane/crossplane-runtime/v2@v2.3.3 \
       github.com/crossplane/crossplane/apis/v2@v2.3.3 \
       github.com/crossplane/crossplane-tools@v0.0.0-20260715161912-60e57f817ad1

# --- 2. the rewriter ---------------------------------------------------------
cat > /tmp/rewrite.sh <<'SH'
#!/usr/bin/env bash
# rewrite.sh <alias> <file>...
set -euo pipefail

NEW='github.com/crossplane/crossplane/apis/v2/core/v2'
OLD1='github.com/crossplane/crossplane-runtime/v2/apis/common/v1'
OLD2='github.com/crossplane/crossplane-runtime/v2/apis/common/v2'

A="$1"; shift

# GNU sed wants -i, BSD/macOS sed wants -i ''
if sed --version >/dev/null 2>&1; then INPLACE=(-i); else INPLACE=(-i ''); fi

# Addresses use \|...|d, not /.../d: the import paths contain slashes.
sed -E "${INPLACE[@]}" \
  -e "s|^([[:space:]]+)\"${OLD1}\"$|\1\"${NEW}\"|" \
  -e "s|^([[:space:]]+)[A-Za-z0-9_]+ \"${OLD1}\"$|\1${A} \"${NEW}\"|" \
  -e "s|^import [A-Za-z0-9_]+ \"${OLD1}\"$|import ${A} \"${NEW}\"|" \
  -e "\\|^[[:space:]]+([A-Za-z0-9_]+ )?\"${OLD2}\"$|d" \
  -e "\\|^import ([A-Za-z0-9_]+ )?\"${OLD2}\"$|d" \
  -e "s|([^[:alnum:]_])(xp)?v1\.ResourceSpec|\1${A}.ClusterManagedResourceSpec|g" \
  -e "s|([^[:alnum:]_])(xp)?v1\.ResourceStatus|\1${A}.ManagedResourceStatus|g" \
  -e "s|([^[:alnum:]_])(in\|out)\.ResourceSpec([^[:alnum:]_])|\1\2.ClusterManagedResourceSpec\3|g" \
  -e "s|([^[:alnum:]_])(in\|out)\.ResourceStatus([^[:alnum:]_])|\1\2.ManagedResourceStatus\3|g" \
  -e "s|([^[:alnum:]_])(xp)?v[12]\.ResourceCredentialsSecret|\1${A}.CredentialsSecret|g" \
  -e "s|([^[:alnum:]_])(xp)?v1\.|\1${A}.|g" \
  -e "s|([^[:alnum:]_])(xp)?v2\.|\1${A}.|g" \
  "$@"
SH
chmod +x /tmp/rewrite.sh

# --- 3. rewrite: one pass per generator, then reformat -----------------------
SRC="apis internal cmd config"

find $SRC -type f \( -name 'zz_*_types.go' -o -name 'zz_generated.deepcopy.go' \) \
  -exec /tmp/rewrite.sh v2 {} +

find $SRC -type f \( -name 'zz_generated.managed.go' -o -name 'zz_generated.managedlist.go' \
  -o -name 'zz_generated.pc.go' -o -name 'zz_generated.pcu.go' \
  -o -name 'zz_generated.pculist.go' -o -name 'zz_generated.resolvers.go' \) \
  -exec /tmp/rewrite.sh xpv2 {} +

find $SRC -type f -name '*.go' ! -name 'zz_*' -exec /tmp/rewrite.sh xpv2 {} +

gofmt -l -w $SRC

# --- 4. must be 0 before continuing ------------------------------------------
grep -rl 'crossplane-runtime/v2/apis/common' --include='*.go' $SRC | wc -l

# --- 5. canonical regeneration -------------
go mod tidy
make generate
go mod tidy

runbook

Confirmed (module cache, crossplane-runtime/v2@v2.3.3): the apis/ tree now contains only changelogs/, pipelineinspector/ and proto/ — there is no common/ at all.

The ordering constraint that shapes everything below: go mod tidy cannot run until the import paths are already rewritten. Tidy resolves imports from source, and an import of a package that exists in no version of any module is a hard failure, not a warning:

go: finding module for package github.com/crossplane/crossplane-runtime/v2/apis/common/v1
go: github.com/upbound/provider-azure/v2/apis/cluster/alertsmanagement/v1beta1 imports
	github.com/crossplane/upjet/v2/pkg/resource imports
	github.com/crossplane/crossplane-runtime/v2/apis/common/v1: module github.com/crossplane/crossplane-runtime/v2@latest found (v2.3.3), but does not contain package github.com/crossplane/crossplane-runtime/v2/apis/common/v1

So the sequence is: edit go.mod → rewrite imports → gofmt → tidy → make generate → tidy again.

Environment

Validated against:

provider provider-upjet-azure, module github.com/upbound/provider-azure/v2
from → to crossplane-runtime/v2 v2.2.1v2.3.3
crossplane/apis/v2 v2.3.3 (new direct require)
crossplane-tools v0.0.0-20251017183449-dd4517244339v0.0.0-20260715161912-60e57f817ad1
upjet/v2 v2.3.1-0.20260713112758-3dc7c7822463
held at k8s.io/* v0.35.5, sigs.k8s.io/controller-runtime v0.23.3
scale 2299 .go files touched — 2290 generated, 9 hand-written
toolchain Go 1.26.5, macOS (BSD sed/xargs)

go.mod changes

module action
github.com/crossplane/crossplane-runtime/v2 bump to v2.3.3
github.com/crossplane/crossplane/apis/v2 add at v2.3.3 — new direct require
github.com/crossplane/crossplane-tools bump to v0.0.0-20260715161912-60e57f817ad1
github.com/crossplane/upjet/v2 bump to a build that already emits core/v2

Do it in one go get so MVS resolves once, minimally:

go get github.com/crossplane/crossplane-runtime/v2@v2.3.3 \
       github.com/crossplane/crossplane/apis/v2@v2.3.3 \
       github.com/crossplane/crossplane-tools@v0.0.0-20260715161912-60e57f817ad1

crossplane/apis/v2 lands as // indirect until the imports are rewritten; the final tidy promotes it to direct. That is expected, not a mistake.

Caution

The crossplane-tools bump is mandatory and silent if missed. angryjet generates zz_generated.managed.go, .managedlist.go, .pc.go, .pcu.go, .pculist.go and .resolvers.go. Older builds only know the old paths, so make generate happily regenerates hundreds of files importing a package that no longer exists — in provider-upjet-azure that was 249 files.

Confirmed (source, cmd/angryjet/main.go:54-57 at v0.0.0-20260715161912-60e57f817ad1): from that pseudo-version on, angryjet carries both constants and auto-detects which to emit from the embedded spec type.

RuntimeAlias  = "xpv1"
RuntimeImport = "github.com/crossplane/crossplane-runtime/v2/apis/common/v1"

RuntimeV2Alias  = "xpv2"
RuntimeV2Import = "github.com/crossplane/crossplane/apis/v2/core/v2"

Verify whatever pin you pick:

grep -rn 'RuntimeV2Import' "$(go env GOMODCACHE)"/github.com/crossplane/crossplane-tools@*/cmd/angryjet/main.go

Symbol mapping

Import path changes only, names unchanged: Reference, NamespacedReference, Selector, NamespacedSelector, SecretReference, SecretKeySelector, LocalSecretReference, LocalSecretKeySelector, TypedReference, Condition, ConditionType, ConditionReason, ConditionedStatus, ObservedStatus, ManagementAction, ManagementPolicies, DeletionPolicy, UpdatePolicy, CredentialsSource, CommonCredentialSelectors, EnvSelector, FsSelector, ProviderConfigReference, ProviderConfigStatus, ProviderConfigUsage, TypedProviderConfigUsage, ManagedResourceSpec, Policy, ResolvePolicy, ResolutionPolicy, CompositeDeletePolicy.

Actually renamed:

old new
ResourceSpec ClusterManagedResourceSpec
ResourceStatus ManagedResourceStatus
ResourceCredentialsSecretEndpointKey CredentialsSecretEndpointKey
ResourceCredentialsSecretPortKey CredentialsSecretPortKey
ResourceCredentialsSecretUserKey CredentialsSecretUserKey
ResourceCredentialsSecretPasswordKey CredentialsSecretPasswordKey
ResourceCredentialsSecretCAKey CredentialsSecretCAKey
ResourceCredentialsSecretClientCertKey CredentialsSecretClientCertKey
ResourceCredentialsSecretClientKeyKey CredentialsSecretClientKeyKey
ResourceCredentialsSecretTokenKey CredentialsSecretTokenKey
ResourceCredentialsSecretKubeconfigKey CredentialsSecretKubeconfigKey

Deleted outright: MergeOptions, TargetSpec, TargetStatus.

Confirmed (field-by-field diff of both packages in the module cache): v1.ResourceSpec and core/v2.ClusterManagedResourceSpec are structurally identical, as are v1.ResourceStatus and core/v2.ManagedResourceStatus. The ResourceCredentialsSecret* constants kept their values ("endpoint", "port", "username", …) and only lost the Resource prefix.

Important

The entire ResourceCredentialsSecret*CredentialsSecret* family is not mentioned in upjet's docs/upjet-v2-upgrade.md, which documents only the two embeds. I found it by diffing the packages after the build failed on it. Re-derive the real list for your runtime version instead of trusting any doc, including this one:

OLD="$(go env GOMODCACHE)/github.com/crossplane/crossplane-runtime/v2@v2.2.1/apis/common"
NEW="$(go env GOMODCACHE)/github.com/crossplane/crossplane/apis/v2@v2.3.3/core/v2"
diff <(grep -rhoE '^(type [A-Za-z0-9_]+|	[A-Z][A-Za-z0-9_]+ =)' "$OLD" | sort -u) \
     <(grep -rhoE '^(type [A-Za-z0-9_]+|	[A-Z][A-Za-z0-9_]+ =)' "$NEW" | sort -u)

Renaming an embed also renames the field

An embedded field's name is its type name, so zz_generated.deepcopy.go changes too:

in.ResourceSpec.DeepCopyInto(&out.ResourceSpec)                                // before
in.ClusterManagedResourceSpec.DeepCopyInto(&out.ClusterManagedResourceSpec)     // after

These are unqualified identifiers. A rewrite that only touches import qualifiers compiles everything else and then fails here — this is the single easiest thing to miss.

Which alias goes in which file

Match what each generator emits, or the next make generate produces a large spurious diff on top of the real change.

files generator alias
zz_*_types.go upjet v2
zz_generated.deepcopy.go controller-gen v2, and unaliased imports stay unaliased
zz_generated.{managed,managedlist,pc,pcu,pculist,resolvers}.go angryjet xpv2
everything hand-written you xpv2, matching upjet's own source

Confirmed (source, upjet/pkg/types/reference.go:25-28 + pkg/pipeline/crd.go:127-128): PackagePathXPCommonAPIs and PackagePathXPV2CommonAPIs are now the same string, so typewriter's UsePackage returns one alias for both, derived from the last path element — v2. That is why generated types files end up with a single v2 import where they previously had two.

Six import shapes exist in practice, and a rewrite must handle all of them:

	v1 "…/apis/common/v1"          // block, aliased
	xpv1 "…/apis/common/v1"        // block, aliased
	"…/apis/common/v1"             // block, UNALIASED (controller-gen) — qualifier is still v1.
	v2 "…/apis/common/v2"          // block, aliased
	xpv2 "…/apis/common/v2"        // block, aliased
import xpv1 "…/apis/common/v1"     // single-line, no block (angryjet)

Inventory and pre-flight guards

Scope every search to the source dirs. At the repo root, recursive search descends into .work/ — the vendored Terraform provider checkout — and takes minutes or appears to hang.

SRC="apis internal cmd config"

# how big is this job
grep -rl 'crossplane-runtime/v2/apis/common' --include='*.go' $SRC | wc -l

# breakdown by generator, so you know which alias each group needs
grep -rl 'crossplane-runtime/v2/apis/common' --include='*.go' $SRC \
  | sed 's|.*/||' | sort | uniq -c | sort -rn

# every distinct import shape actually present
grep -rh 'apis/common' --include='*.go' $SRC | sort | uniq -c

# hand-written files, which need review rather than bulk rewriting
grep -rl 'crossplane-runtime/v2/apis/common' --include='*.go' $SRC | grep -v '/zz_'

The rewrite deletes the common/v2 import line and folds its symbols onto the common/v1 alias. That is only valid under two assumptions, both of which are worth proving rather than trusting:

# MUST print nothing — files importing common/v2 but not common/v1
grep -rl 'apis/common/v2"' --include='*.go' $SRC | xargs grep -L 'apis/common/v1"'

# MUST print nothing — unaliased imports outside deepcopy, where target alias != package name
grep -rlE '^[[:space:]]+"github.com/crossplane/crossplane-runtime/v2/apis/common/v1"$' \
  --include='*.go' $SRC | grep -v 'zz_generated.deepcopy.go'

# the unversioned apis/common package (mock surfaces) also vanished in v2.3 — check for it
grep -rn 'apis/common"' --include='*.go' $SRC

If the second command prints files, an unaliased import in a group whose target alias is not v2 will break: the import stays unaliased so the qualifier is v2., while the symbols get rewritten to xpv2.. Move those files into the v2 pass or add the alias by hand.

The rewrite

rewrite.sh — handles all six import shapes, collapses the double import, applies every rename. Portable across BSD/macOS and GNU sed.
#!/usr/bin/env bash
# rewrite.sh <alias> <file>...
set -euo pipefail

NEW='github.com/crossplane/crossplane/apis/v2/core/v2'
OLD1='github.com/crossplane/crossplane-runtime/v2/apis/common/v1'
OLD2='github.com/crossplane/crossplane-runtime/v2/apis/common/v2'

A="$1"; shift

# GNU sed wants -i, BSD/macOS sed wants -i ''
if sed --version >/dev/null 2>&1; then INPLACE=(-i); else INPLACE=(-i ''); fi

# Addresses use \|...|d, not /.../d: the import paths contain slashes.
sed -E "${INPLACE[@]}" \
  -e "s|^([[:space:]]+)\"${OLD1}\"$|\1\"${NEW}\"|" \
  -e "s|^([[:space:]]+)[A-Za-z0-9_]+ \"${OLD1}\"$|\1${A} \"${NEW}\"|" \
  -e "s|^import [A-Za-z0-9_]+ \"${OLD1}\"$|import ${A} \"${NEW}\"|" \
  -e "\\|^[[:space:]]+([A-Za-z0-9_]+ )?\"${OLD2}\"$|d" \
  -e "\\|^import ([A-Za-z0-9_]+ )?\"${OLD2}\"$|d" \
  -e "s|([^[:alnum:]_])(xp)?v1\.ResourceSpec|\1${A}.ClusterManagedResourceSpec|g" \
  -e "s|([^[:alnum:]_])(xp)?v1\.ResourceStatus|\1${A}.ManagedResourceStatus|g" \
  -e "s|([^[:alnum:]_])(in\|out)\.ResourceSpec([^[:alnum:]_])|\1\2.ClusterManagedResourceSpec\3|g" \
  -e "s|([^[:alnum:]_])(in\|out)\.ResourceStatus([^[:alnum:]_])|\1\2.ManagedResourceStatus\3|g" \
  -e "s|([^[:alnum:]_])(xp)?v[12]\.ResourceCredentialsSecret|\1${A}.CredentialsSecret|g" \
  -e "s|([^[:alnum:]_])(xp)?v1\.|\1${A}.|g" \
  -e "s|([^[:alnum:]_])(xp)?v2\.|\1${A}.|g" \
  "$@"

Why each odd construct is there — all four were found by a failing test, not by inspection:

  • \|…|d instead of /…/d. Import paths contain /, which closes a /-delimited address early. BSD sed then reads crossplane as a c command:
    sed: 1: "/^[[:space:]]+([A-Za-z0 ...": command c expects \ followed by text
    
    The failure mode is nasty because sed exits non-zero per invocation while find -exec keeps going, so a whole pass can no-op while looking busy.
  • ([^[:alnum:]_]) instead of \b. BSD sed has no \b. This also protects metav1. and corev1. for free: the character before v1 there is a word character, so the pattern cannot match.
  • (in|out)\. guards the embedded-field rewrite. An unguarded bare ResourceStatus rewrite corrupts provider API fields that legitimately carry that name — plenty of Azure observation structs have one.
  • Renames run before the generic alias swap, otherwise the generic rule consumes the qualifier first and the renames never fire.

Three passes, one per alias group:

SRC="apis internal cmd config"

# 1. upjet types + controller-gen deepcopy -> v2
find $SRC -type f \( -name 'zz_*_types.go' -o -name 'zz_generated.deepcopy.go' \) \
  -exec ./rewrite.sh v2 {} +

# 2. angryjet -> xpv2
find $SRC -type f \( -name 'zz_generated.managed.go' -o -name 'zz_generated.managedlist.go' \
  -o -name 'zz_generated.pc.go' -o -name 'zz_generated.pcu.go' \
  -o -name 'zz_generated.pculist.go' -o -name 'zz_generated.resolvers.go' \) \
  -exec ./rewrite.sh xpv2 {} +

# 3. hand-written -> xpv2
find $SRC -type f -name '*.go' ! -name 'zz_*' -exec ./rewrite.sh xpv2 {} +

# renamed embeds change identifier widths, which breaks struct-tag alignment
gofmt -l -w $SRC

Use find -exec … {} +, not xargs. BSD xargs has no -a, and a plain xargs split silently ran only the first batch for me — 2041 of 2290 files rewritten, with a success message and no error.

Verify, then tidy

# MUST be 0
grep -rl 'crossplane-runtime/v2/apis/common' --include='*.go' $SRC | wc -l

# alias distribution should match the table above
grep -rhoE '^(	|import )([A-Za-z0-9_]+ )?"github.com/crossplane/crossplane/apis/v2/core/v2"' \
  --include='*.go' $SRC | sort | uniq -c

# no leftovers of the renamed symbols anywhere
grep -rnE '(xp)?v[12]\.(ResourceSpec|ResourceStatus|ResourceCredentialsSecret)' --include='*.go' $SRC

go mod tidy && go build ./...

Tidy should now exit 0 and promote crossplane/apis/v2 to a direct require.

make generate, then tidy a second time

make generate
go mod tidy          # <- do not skip this

Caution

The second tidy is not optional. make generate begins by deleting the generated tree — cmd/provider/*/zz_main.go, internal/controller/zz_*, conversion hubs and spokes, 3649 files in provider-upjet-azure. Tidying while they are absent demotes direct requires that only generated code imports. In my run it silently pushed google.golang.org/grpc, k8s.io/client-go and k8s.io/apiextensions-apiserver out of the direct require block. Always tidy on a fully generated tree.

@jonasz-lasut jonasz-lasut left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM thank you @jschoombee for the contribution!

@jonasz-lasut
jonasz-lasut merged commit cf798c5 into crossplane:main Jul 27, 2026
9 checks passed
ulucinar pushed a commit to ulucinar/upbound-upjet that referenced this pull request Jul 28, 2026
Removes the env-var coupling so the workflow's Go version follows
whatever go.mod declares. Addresses review feedback on crossplane#664.

Signed-off-by: JP Schoombee <jpschoombee@gmail.com>
(cherry picked from commit 6e54b16)
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.

Adopt crossplane-runtime v2.3.x: migrate common APIs to crossplane/apis/v2/core/v2

4 participants