diff --git a/cmd/crossplane/project/run.go b/cmd/crossplane/project/run.go index 73ba0ad7..6c7093e2 100644 --- a/cmd/crossplane/project/run.go +++ b/cmd/crossplane/project/run.go @@ -40,7 +40,6 @@ import ( xpkgv1beta1 "github.com/crossplane/crossplane/apis/v2/pkg/v1beta1" devv1alpha1 "github.com/crossplane/cli/v2/apis/dev/v1alpha1" - "github.com/crossplane/cli/v2/cmd/crossplane/render" "github.com/crossplane/cli/v2/internal/async" "github.com/crossplane/cli/v2/internal/config" "github.com/crossplane/cli/v2/internal/dependency" @@ -53,6 +52,7 @@ import ( "github.com/crossplane/cli/v2/internal/schemas/runner" "github.com/crossplane/cli/v2/internal/terminal" clixpkg "github.com/crossplane/cli/v2/internal/xpkg" + "github.com/crossplane/cli/v2/pkg/render" _ "embed" ) diff --git a/cmd/crossplane/render/op/cmd.go b/cmd/crossplane/render/op/cmd.go index 065eb6a8..8af4ecbc 100644 --- a/cmd/crossplane/render/op/cmd.go +++ b/cmd/crossplane/render/op/cmd.go @@ -37,7 +37,6 @@ import ( opsv1alpha1 "github.com/crossplane/crossplane/apis/v2/ops/v1alpha1" pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/render" "github.com/crossplane/cli/v2/cmd/crossplane/render/contextfn" "github.com/crossplane/cli/v2/internal/async" "github.com/crossplane/cli/v2/internal/config" @@ -50,6 +49,7 @@ import ( "github.com/crossplane/cli/v2/internal/schemas/runner" "github.com/crossplane/cli/v2/internal/terminal" clixpkg "github.com/crossplane/cli/v2/internal/xpkg" + "github.com/crossplane/cli/v2/pkg/render" _ "embed" ) diff --git a/cmd/crossplane/render/op/cmd_test.go b/cmd/crossplane/render/op/cmd_test.go index ce8614b4..ed68908e 100644 --- a/cmd/crossplane/render/op/cmd_test.go +++ b/cmd/crossplane/render/op/cmd_test.go @@ -35,9 +35,9 @@ import ( pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/render" "github.com/crossplane/cli/v2/internal/config" "github.com/crossplane/cli/v2/internal/terminal" + "github.com/crossplane/cli/v2/pkg/render" renderv1alpha1 "github.com/crossplane/cli/v2/proto/render/v1alpha1" _ "embed" diff --git a/cmd/crossplane/render/xr/cmd.go b/cmd/crossplane/render/xr/cmd.go index 10cd4332..0cce6e80 100644 --- a/cmd/crossplane/render/xr/cmd.go +++ b/cmd/crossplane/render/xr/cmd.go @@ -44,7 +44,6 @@ import ( apiextensionsv1 "github.com/crossplane/crossplane/apis/v2/apiextensions/v1" pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/render" "github.com/crossplane/cli/v2/cmd/crossplane/render/contextfn" "github.com/crossplane/cli/v2/internal/async" "github.com/crossplane/cli/v2/internal/config" @@ -57,6 +56,7 @@ import ( "github.com/crossplane/cli/v2/internal/schemas/runner" "github.com/crossplane/cli/v2/internal/terminal" clixpkg "github.com/crossplane/cli/v2/internal/xpkg" + "github.com/crossplane/cli/v2/pkg/render" xrpkg "github.com/crossplane/cli/v2/pkg/xr" _ "embed" diff --git a/cmd/crossplane/render/xr/cmd_test.go b/cmd/crossplane/render/xr/cmd_test.go index 65316d8c..dbd0d3db 100644 --- a/cmd/crossplane/render/xr/cmd_test.go +++ b/cmd/crossplane/render/xr/cmd_test.go @@ -35,9 +35,9 @@ import ( pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/render" "github.com/crossplane/cli/v2/internal/config" "github.com/crossplane/cli/v2/internal/terminal" + "github.com/crossplane/cli/v2/pkg/render" renderv1alpha1 "github.com/crossplane/cli/v2/proto/render/v1alpha1" _ "embed" diff --git a/cmd/crossplane/simulate/simulate.go b/cmd/crossplane/simulate/simulate.go index adaff9c2..e4e6f843 100644 --- a/cmd/crossplane/simulate/simulate.go +++ b/cmd/crossplane/simulate/simulate.go @@ -51,7 +51,6 @@ import ( pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" pkgv1beta1 "github.com/crossplane/crossplane/apis/v2/pkg/v1beta1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/load" "github.com/crossplane/cli/v2/internal/async" "github.com/crossplane/cli/v2/internal/containerruntime" "github.com/crossplane/cli/v2/internal/diffserver" @@ -61,6 +60,7 @@ import ( "github.com/crossplane/cli/v2/internal/project/projectfile" "github.com/crossplane/cli/v2/internal/terminal" clixpkg "github.com/crossplane/cli/v2/internal/xpkg" + "github.com/crossplane/cli/v2/pkg/load" _ "embed" ) diff --git a/cmd/crossplane/trace/internal/printer/default.go b/cmd/crossplane/trace/internal/printer/default.go index b0412155..32f69618 100644 --- a/cmd/crossplane/trace/internal/printer/default.go +++ b/cmd/crossplane/trace/internal/printer/default.go @@ -34,8 +34,8 @@ import ( xpv2 "github.com/crossplane/crossplane/apis/v2/core/v2" pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource/xpkg" + "github.com/crossplane/cli/v2/pkg/resource" + "github.com/crossplane/cli/v2/pkg/resource/xpkg" ) const ( diff --git a/cmd/crossplane/trace/internal/printer/default_test.go b/cmd/crossplane/trace/internal/printer/default_test.go index 667f9c32..a2ef73a3 100644 --- a/cmd/crossplane/trace/internal/printer/default_test.go +++ b/cmd/crossplane/trace/internal/printer/default_test.go @@ -25,7 +25,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/test" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) func TestDefaultPrinterPrint(t *testing.T) { diff --git a/cmd/crossplane/trace/internal/printer/dot.go b/cmd/crossplane/trace/internal/printer/dot.go index c3357ad0..3fd18887 100644 --- a/cmd/crossplane/trace/internal/printer/dot.go +++ b/cmd/crossplane/trace/internal/printer/dot.go @@ -13,8 +13,8 @@ import ( xpv2 "github.com/crossplane/crossplane/apis/v2/core/v2" v1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource/xpkg" + "github.com/crossplane/cli/v2/pkg/resource" + "github.com/crossplane/cli/v2/pkg/resource/xpkg" ) // DotPrinter defines the DotPrinter configuration. diff --git a/cmd/crossplane/trace/internal/printer/dot_test.go b/cmd/crossplane/trace/internal/printer/dot_test.go index 74478d5d..c28ec6c3 100644 --- a/cmd/crossplane/trace/internal/printer/dot_test.go +++ b/cmd/crossplane/trace/internal/printer/dot_test.go @@ -8,7 +8,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/test" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // Define a test for PrintDotGraph. diff --git a/cmd/crossplane/trace/internal/printer/json.go b/cmd/crossplane/trace/internal/printer/json.go index 939436cf..26f258fc 100644 --- a/cmd/crossplane/trace/internal/printer/json.go +++ b/cmd/crossplane/trace/internal/printer/json.go @@ -23,7 +23,7 @@ import ( "github.com/pkg/errors" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) const ( diff --git a/cmd/crossplane/trace/internal/printer/json_test.go b/cmd/crossplane/trace/internal/printer/json_test.go index 9ceccbbf..e94daa74 100644 --- a/cmd/crossplane/trace/internal/printer/json_test.go +++ b/cmd/crossplane/trace/internal/printer/json_test.go @@ -25,7 +25,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/test" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) func TestJSONPrinterPrint(t *testing.T) { diff --git a/cmd/crossplane/trace/internal/printer/printer.go b/cmd/crossplane/trace/internal/printer/printer.go index 2b41bd85..9a954557 100644 --- a/cmd/crossplane/trace/internal/printer/printer.go +++ b/cmd/crossplane/trace/internal/printer/printer.go @@ -23,7 +23,7 @@ import ( "github.com/pkg/errors" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) const ( diff --git a/cmd/crossplane/trace/internal/printer/printer_test.go b/cmd/crossplane/trace/internal/printer/printer_test.go index 60ecc744..a3923041 100644 --- a/cmd/crossplane/trace/internal/printer/printer_test.go +++ b/cmd/crossplane/trace/internal/printer/printer_test.go @@ -27,7 +27,7 @@ import ( xpv2 "github.com/crossplane/crossplane/apis/v2/core/v2" v1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // DummyManifestOpt can be passed to customize a dummy manifest. diff --git a/cmd/crossplane/trace/internal/printer/yaml.go b/cmd/crossplane/trace/internal/printer/yaml.go index d98589f7..7c4070c8 100644 --- a/cmd/crossplane/trace/internal/printer/yaml.go +++ b/cmd/crossplane/trace/internal/printer/yaml.go @@ -23,7 +23,7 @@ import ( "github.com/pkg/errors" "sigs.k8s.io/yaml" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) const ( diff --git a/cmd/crossplane/trace/internal/printer/yaml_test.go b/cmd/crossplane/trace/internal/printer/yaml_test.go index 58454fe4..3f612673 100644 --- a/cmd/crossplane/trace/internal/printer/yaml_test.go +++ b/cmd/crossplane/trace/internal/printer/yaml_test.go @@ -25,7 +25,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/test" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) func TestYAMLPrinterPrint(t *testing.T) { diff --git a/cmd/crossplane/trace/trace.go b/cmd/crossplane/trace/trace.go index 302482e1..7444d54a 100644 --- a/cmd/crossplane/trace/trace.go +++ b/cmd/crossplane/trace/trace.go @@ -36,12 +36,12 @@ import ( "github.com/crossplane/crossplane/apis/v2/pkg" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource/xpkg" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource/xrm" "github.com/crossplane/cli/v2/cmd/crossplane/internal" "github.com/crossplane/cli/v2/cmd/crossplane/trace/internal/printer" "github.com/crossplane/cli/v2/internal/kube" + "github.com/crossplane/cli/v2/pkg/resource" + "github.com/crossplane/cli/v2/pkg/resource/xpkg" + "github.com/crossplane/cli/v2/pkg/resource/xrm" _ "embed" ) diff --git a/cmd/crossplane/trace/watch.go b/cmd/crossplane/trace/watch.go index d7fef013..a49e0ff6 100644 --- a/cmd/crossplane/trace/watch.go +++ b/cmd/crossplane/trace/watch.go @@ -34,8 +34,8 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" "github.com/crossplane/crossplane-runtime/v2/pkg/logging" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" "github.com/crossplane/cli/v2/cmd/crossplane/trace/internal/printer" + "github.com/crossplane/cli/v2/pkg/resource" ) // Bubble Tea messages for watch mode. diff --git a/cmd/crossplane/validate/cache.go b/cmd/crossplane/validate/cache.go index 4572f927..60d3b598 100644 --- a/cmd/crossplane/validate/cache.go +++ b/cmd/crossplane/validate/cache.go @@ -30,7 +30,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" - "github.com/crossplane/cli/v2/cmd/crossplane/common/load" + "github.com/crossplane/cli/v2/pkg/load" ) // Cache defines an interface for caching schemas. diff --git a/cmd/crossplane/validate/cmd.go b/cmd/crossplane/validate/cmd.go index 5eefbfb2..813ce26e 100644 --- a/cmd/crossplane/validate/cmd.go +++ b/cmd/crossplane/validate/cmd.go @@ -29,7 +29,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" "github.com/crossplane/crossplane-runtime/v2/pkg/logging" - "github.com/crossplane/cli/v2/cmd/crossplane/common/load" + "github.com/crossplane/cli/v2/pkg/load" pkgvalidate "github.com/crossplane/cli/v2/pkg/validate" "github.com/crossplane/cli/v2/pkg/validate/output" diff --git a/cmd/crossplane/validate/image.go b/cmd/crossplane/validate/image.go index 4177e6a8..8be89323 100644 --- a/cmd/crossplane/validate/image.go +++ b/cmd/crossplane/validate/image.go @@ -34,7 +34,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" - "github.com/crossplane/cli/v2/cmd/crossplane/common/load" + "github.com/crossplane/cli/v2/pkg/load" ) const maxDecompressedSize = 200 * 1024 * 1024 // 200 MB diff --git a/cmd/crossplane/xpkg/get_crds.go b/cmd/crossplane/xpkg/get_crds.go index 23696b05..4bb4c9eb 100644 --- a/cmd/crossplane/xpkg/get_crds.go +++ b/cmd/crossplane/xpkg/get_crds.go @@ -30,9 +30,9 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" "github.com/crossplane/crossplane-runtime/v2/pkg/logging" - "github.com/crossplane/cli/v2/cmd/crossplane/common/load" "github.com/crossplane/cli/v2/cmd/crossplane/validate" "github.com/crossplane/cli/v2/internal/schemas/generator" + "github.com/crossplane/cli/v2/pkg/load" _ "embed" ) diff --git a/cmd/crossplane/xr/generate.go b/cmd/crossplane/xr/generate.go index 0ee26a92..cf8bf0b2 100644 --- a/cmd/crossplane/xr/generate.go +++ b/cmd/crossplane/xr/generate.go @@ -20,16 +20,12 @@ import ( "github.com/alecthomas/kong" "github.com/spf13/afero" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/util/uuid" - "k8s.io/apiserver/pkg/storage/names" "sigs.k8s.io/yaml" "github.com/crossplane/crossplane-runtime/v2/pkg/errors" - "github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath" - "github.com/crossplane/crossplane-runtime/v2/pkg/resource/unstructured/composite" commonIO "github.com/crossplane/cli/v2/cmd/crossplane/convert/io" + xrpkg "github.com/crossplane/cli/v2/pkg/xr" _ "embed" ) @@ -74,7 +70,7 @@ func (c *generateCmd) Run(k *kong.Context) error { } // Convert to XR - xr, err := ConvertClaimToXR(claim, Options{ + xr, err := xrpkg.ConvertClaimToXR(claim, xrpkg.Options{ Name: c.Name, Kind: c.Kind, Direct: c.Direct, @@ -105,141 +101,3 @@ func (c *generateCmd) Run(k *kong.Context) error { return nil } - -const ( - labelClaimName = "crossplane.io/claim-name" - labelClaimNamespace = "crossplane.io/claim-namespace" - labelComposite = "crossplane.io/composite" -) - -// Options configures ConvertClaimToXR. -type Options struct { - // Name is the XR name. Empty falls back to: - // - claim.Name when Direct is true - // - claim.Name with a random suffix when Direct is false - // A non-empty Name overrides both fallbacks. - Name string - - // Kind is the XR kind. Empty defaults to "X" + claim.Kind. - Kind string - - // Direct controls XR linkage to the claim: - // - true: no spec.claimRef; no claim-name/claim-namespace labels - // - false: spec.claimRef is set; claim-name/claim-namespace labels added - Direct bool - - // GenerateUID, when true, sets metadata.uid to a fresh random UUID. - GenerateUID bool -} - -// ConvertClaimToXR converts a Crossplane Claim to a Composite Resource (XR). -func ConvertClaimToXR(claim *unstructured.Unstructured, opts Options) (*composite.Unstructured, error) { - if claim == nil { - return nil, errors.New("input is nil") - } - - if claim.Object == nil { - return nil, errors.New("invalid Claim YAML: parsed object is empty") - } - - // Get Claim's properties - claimName := claim.GetName() - - claimKind := claim.GetKind() - if claimKind == "" { - return nil, errors.New("no kind section in Claim") - } - - apiVersion := claim.GetAPIVersion() - if apiVersion == "" { - return nil, errors.New("no apiVersion in Claim") - } - - if _, err := schema.ParseGroupVersion(apiVersion); err != nil { - return nil, errors.Wrap(err, "cannot parse Claim APIVersion") - } - - annotations := claim.GetAnnotations() - - labels := claim.GetLabels() - if labels == nil { - labels = make(map[string]string) - } - - claimSpec, ok := claim.Object["spec"].(map[string]any) - if !ok || claimSpec == nil { - return nil, errors.New("no spec section in Claim") - } - - // Create a new XR and pave it for manipulation - xr := composite.New() - - xrPaved, err := fieldpath.PaveObject(xr) - if err != nil { - return nil, errors.Wrap(err, "cannot pave object") - } - - if err := xrPaved.SetString("apiVersion", apiVersion); err != nil { - return nil, errors.Wrap(err, "cannot set apiVersion") - } - - // Set XR kind - either from opts or by prepending X to Claim's kind - kind := opts.Kind - if kind == "" { - kind = "X" + claimKind - } - - if err := xrPaved.SetString("kind", kind); err != nil { - return nil, errors.Wrap(err, "cannot set kind") - } - - if len(annotations) > 0 { - if err := xrPaved.SetValue("metadata.annotations", annotations); err != nil { - return nil, errors.Wrap(err, "cannot set annotations") - } - } - - if err := xrPaved.SetValue("spec", claimSpec); err != nil { - return nil, errors.Wrap(err, "cannot set spec") - } - - xrName := claimName - - if !opts.Direct { - xrName = names.SimpleNameGenerator.GenerateName(claimName + "-") - labels[labelClaimName] = claim.GetName() - - labels[labelClaimNamespace] = claim.GetNamespace() - if err := xrPaved.SetValue("spec.claimRef", map[string]any{ - "apiVersion": apiVersion, - "kind": claimKind, - "name": claimName, - "namespace": claim.GetNamespace(), - }); err != nil { - return nil, errors.Wrap(err, "cannot set claimRef") - } - } - - // Explicit Name overrides both Direct's claim-name default and the generated suffix. - if opts.Name != "" { - xrName = opts.Name - } - - if err := xrPaved.SetString("metadata.name", xrName); err != nil { - return nil, errors.Wrap(err, "cannot set name") - } - - if len(labels) > 0 { - delete(labels, labelComposite) - - if err := xrPaved.SetValue("metadata.labels", labels); err != nil { - return nil, errors.Wrap(err, "cannot set labels") - } - } - - if opts.GenerateUID { - xr.SetUID(uuid.NewUUID()) - } - - return xr, nil -} diff --git a/cmd/crossplane/xr/patch.go b/cmd/crossplane/xr/patch.go index 7b260518..489767f2 100644 --- a/cmd/crossplane/xr/patch.go +++ b/cmd/crossplane/xr/patch.go @@ -25,7 +25,7 @@ import ( "github.com/crossplane/crossplane-runtime/v2/pkg/errors" commonIO "github.com/crossplane/cli/v2/cmd/crossplane/convert/io" - "github.com/crossplane/cli/v2/cmd/crossplane/render" + "github.com/crossplane/cli/v2/pkg/render" xrpkg "github.com/crossplane/cli/v2/pkg/xr" _ "embed" diff --git a/cmd/crossplane/common/crd/crd.go b/pkg/crd/crd.go similarity index 93% rename from cmd/crossplane/common/crd/crd.go rename to pkg/crd/crd.go index 9ed9dc21..6ae959ac 100644 --- a/cmd/crossplane/common/crd/crd.go +++ b/pkg/crd/crd.go @@ -1,4 +1,4 @@ -// Package crd provides functions and helpers shared between CLI utilities, available for import by external tools interacting with Crossplane. +// Package crd provides helpers for converting Crossplane XRDs to CRDs, available for import by external tools interacting with Crossplane. package crd import ( diff --git a/cmd/crossplane/common/load/loader.go b/pkg/load/loader.go similarity index 100% rename from cmd/crossplane/common/load/loader.go rename to pkg/load/loader.go diff --git a/cmd/crossplane/common/load/loader_test.go b/pkg/load/loader_test.go similarity index 100% rename from cmd/crossplane/common/load/loader_test.go rename to pkg/load/loader_test.go diff --git a/cmd/crossplane/common/load/testdata/folder/nested-folder/resource-a.yaml b/pkg/load/testdata/folder/nested-folder/resource-a.yaml similarity index 100% rename from cmd/crossplane/common/load/testdata/folder/nested-folder/resource-a.yaml rename to pkg/load/testdata/folder/nested-folder/resource-a.yaml diff --git a/cmd/crossplane/common/load/testdata/folder/resource-b.yaml b/pkg/load/testdata/folder/resource-b.yaml similarity index 100% rename from cmd/crossplane/common/load/testdata/folder/resource-b.yaml rename to pkg/load/testdata/folder/resource-b.yaml diff --git a/cmd/crossplane/common/load/testdata/resources.yaml b/pkg/load/testdata/resources.yaml similarity index 100% rename from cmd/crossplane/common/load/testdata/resources.yaml rename to pkg/load/testdata/resources.yaml diff --git a/cmd/crossplane/common/load/testutils/mocks.go b/pkg/load/testutils/mocks.go similarity index 100% rename from cmd/crossplane/common/load/testutils/mocks.go rename to pkg/load/testutils/mocks.go diff --git a/cmd/crossplane/render/annotation.go b/pkg/render/annotation.go similarity index 100% rename from cmd/crossplane/render/annotation.go rename to pkg/render/annotation.go diff --git a/cmd/crossplane/render/context.go b/pkg/render/context.go similarity index 100% rename from cmd/crossplane/render/context.go rename to pkg/render/context.go diff --git a/cmd/crossplane/render/convert.go b/pkg/render/convert.go similarity index 100% rename from cmd/crossplane/render/convert.go rename to pkg/render/convert.go diff --git a/cmd/crossplane/render/convert_test.go b/pkg/render/convert_test.go similarity index 100% rename from cmd/crossplane/render/convert_test.go rename to pkg/render/convert_test.go diff --git a/cmd/crossplane/render/engine.go b/pkg/render/engine.go similarity index 100% rename from cmd/crossplane/render/engine.go rename to pkg/render/engine.go diff --git a/cmd/crossplane/render/engine_docker.go b/pkg/render/engine_docker.go similarity index 100% rename from cmd/crossplane/render/engine_docker.go rename to pkg/render/engine_docker.go diff --git a/cmd/crossplane/render/engine_docker_test.go b/pkg/render/engine_docker_test.go similarity index 100% rename from cmd/crossplane/render/engine_docker_test.go rename to pkg/render/engine_docker_test.go diff --git a/cmd/crossplane/render/engine_local.go b/pkg/render/engine_local.go similarity index 100% rename from cmd/crossplane/render/engine_local.go rename to pkg/render/engine_local.go diff --git a/cmd/crossplane/render/engine_local_test.go b/pkg/render/engine_local_test.go similarity index 100% rename from cmd/crossplane/render/engine_local_test.go rename to pkg/render/engine_local_test.go diff --git a/cmd/crossplane/render/engine_mock.go b/pkg/render/engine_mock.go similarity index 100% rename from cmd/crossplane/render/engine_mock.go rename to pkg/render/engine_mock.go diff --git a/cmd/crossplane/render/load.go b/pkg/render/load.go similarity index 100% rename from cmd/crossplane/render/load.go rename to pkg/render/load.go diff --git a/cmd/crossplane/render/load_test.go b/pkg/render/load_test.go similarity index 100% rename from cmd/crossplane/render/load_test.go rename to pkg/render/load_test.go diff --git a/cmd/crossplane/render/network.go b/pkg/render/network.go similarity index 100% rename from cmd/crossplane/render/network.go rename to pkg/render/network.go diff --git a/cmd/crossplane/render/network_test.go b/pkg/render/network_test.go similarity index 100% rename from cmd/crossplane/render/network_test.go rename to pkg/render/network_test.go diff --git a/cmd/crossplane/render/output.go b/pkg/render/output.go similarity index 100% rename from cmd/crossplane/render/output.go rename to pkg/render/output.go diff --git a/cmd/crossplane/render/output_test.go b/pkg/render/output_test.go similarity index 100% rename from cmd/crossplane/render/output_test.go rename to pkg/render/output_test.go diff --git a/cmd/crossplane/render/render.go b/pkg/render/render.go similarity index 98% rename from cmd/crossplane/render/render.go rename to pkg/render/render.go index fffda1b6..9e9da0e7 100644 --- a/cmd/crossplane/render/render.go +++ b/pkg/render/render.go @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package render implements helpers shared by the render subcommands -// (xr and op). +// Package render implements the composition and operation rendering engine, +// available for import by external tools interacting with Crossplane. package render import ( diff --git a/cmd/crossplane/render/render_test.go b/pkg/render/render_test.go similarity index 100% rename from cmd/crossplane/render/render_test.go rename to pkg/render/render_test.go diff --git a/cmd/crossplane/render/runtime.go b/pkg/render/runtime.go similarity index 100% rename from cmd/crossplane/render/runtime.go rename to pkg/render/runtime.go diff --git a/cmd/crossplane/render/runtime_development.go b/pkg/render/runtime_development.go similarity index 100% rename from cmd/crossplane/render/runtime_development.go rename to pkg/render/runtime_development.go diff --git a/cmd/crossplane/render/runtime_docker.go b/pkg/render/runtime_docker.go similarity index 100% rename from cmd/crossplane/render/runtime_docker.go rename to pkg/render/runtime_docker.go diff --git a/cmd/crossplane/render/runtime_docker_test.go b/pkg/render/runtime_docker_test.go similarity index 100% rename from cmd/crossplane/render/runtime_docker_test.go rename to pkg/render/runtime_docker_test.go diff --git a/cmd/crossplane/render/schemas.go b/pkg/render/schemas.go similarity index 100% rename from cmd/crossplane/render/schemas.go rename to pkg/render/schemas.go diff --git a/cmd/crossplane/render/schemas_test.go b/pkg/render/schemas_test.go similarity index 100% rename from cmd/crossplane/render/schemas_test.go rename to pkg/render/schemas_test.go diff --git a/cmd/crossplane/render/session_test.go b/pkg/render/session_test.go similarity index 100% rename from cmd/crossplane/render/session_test.go rename to pkg/render/session_test.go diff --git a/cmd/crossplane/render/testdata/composition.yaml b/pkg/render/testdata/composition.yaml similarity index 100% rename from cmd/crossplane/render/testdata/composition.yaml rename to pkg/render/testdata/composition.yaml diff --git a/cmd/crossplane/render/testdata/extra-resources.yaml b/pkg/render/testdata/extra-resources.yaml similarity index 100% rename from cmd/crossplane/render/testdata/extra-resources.yaml rename to pkg/render/testdata/extra-resources.yaml diff --git a/cmd/crossplane/render/testdata/functions.yaml b/pkg/render/testdata/functions.yaml similarity index 100% rename from cmd/crossplane/render/testdata/functions.yaml rename to pkg/render/testdata/functions.yaml diff --git a/cmd/crossplane/render/testdata/observed.yaml b/pkg/render/testdata/observed.yaml similarity index 100% rename from cmd/crossplane/render/testdata/observed.yaml rename to pkg/render/testdata/observed.yaml diff --git a/cmd/crossplane/render/testdata/xr.yaml b/pkg/render/testdata/xr.yaml similarity index 100% rename from cmd/crossplane/render/testdata/xr.yaml rename to pkg/render/testdata/xr.yaml diff --git a/cmd/crossplane/render/testdata/xrd.yaml b/pkg/render/testdata/xrd.yaml similarity index 100% rename from cmd/crossplane/render/testdata/xrd.yaml rename to pkg/render/testdata/xrd.yaml diff --git a/cmd/crossplane/common/resource/client.go b/pkg/resource/client.go similarity index 100% rename from cmd/crossplane/common/resource/client.go rename to pkg/resource/client.go diff --git a/cmd/crossplane/common/resource/resource.go b/pkg/resource/resource.go similarity index 100% rename from cmd/crossplane/common/resource/resource.go rename to pkg/resource/resource.go diff --git a/cmd/crossplane/common/resource/xpkg/client.go b/pkg/resource/xpkg/client.go similarity index 99% rename from cmd/crossplane/common/resource/xpkg/client.go rename to pkg/resource/xpkg/client.go index f806bdc9..0431d23b 100644 --- a/cmd/crossplane/common/resource/xpkg/client.go +++ b/pkg/resource/xpkg/client.go @@ -36,7 +36,7 @@ import ( pkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" pkgv1beta1 "github.com/crossplane/crossplane/apis/v2/pkg/v1beta1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // Client to get a Package with all its dependencies. diff --git a/cmd/crossplane/common/resource/xpkg/client_test.go b/pkg/resource/xpkg/client_test.go similarity index 99% rename from cmd/crossplane/common/resource/xpkg/client_test.go rename to pkg/resource/xpkg/client_test.go index c0924aad..3f232bf0 100644 --- a/cmd/crossplane/common/resource/xpkg/client_test.go +++ b/pkg/resource/xpkg/client_test.go @@ -21,7 +21,7 @@ import ( xpkgv1 "github.com/crossplane/crossplane/apis/v2/pkg/v1" "github.com/crossplane/crossplane/apis/v2/pkg/v1beta1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // TODO add more cases, fake client diff --git a/cmd/crossplane/common/resource/xpkg/xpkg.go b/pkg/resource/xpkg/xpkg.go similarity index 100% rename from cmd/crossplane/common/resource/xpkg/xpkg.go rename to pkg/resource/xpkg/xpkg.go diff --git a/cmd/crossplane/common/resource/xpkg/xpkg_test.go b/pkg/resource/xpkg/xpkg_test.go similarity index 100% rename from cmd/crossplane/common/resource/xpkg/xpkg_test.go rename to pkg/resource/xpkg/xpkg_test.go diff --git a/cmd/crossplane/common/resource/xrm/client.go b/pkg/resource/xrm/client.go similarity index 98% rename from cmd/crossplane/common/resource/xrm/client.go rename to pkg/resource/xrm/client.go index f1d854ff..4c930aa7 100644 --- a/cmd/crossplane/common/resource/xrm/client.go +++ b/pkg/resource/xrm/client.go @@ -33,7 +33,7 @@ import ( "github.com/crossplane/crossplane/apis/v2/apiextensions/v1alpha1" "github.com/crossplane/crossplane/apis/v2/apiextensions/v1beta1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // defaultConcurrency is the concurrency using which the resource tree if loaded when not explicitly specified. diff --git a/cmd/crossplane/common/resource/xrm/client_test.go b/pkg/resource/xrm/client_test.go similarity index 99% rename from cmd/crossplane/common/resource/xrm/client_test.go rename to pkg/resource/xrm/client_test.go index 3b661d7a..26fd3398 100644 --- a/cmd/crossplane/common/resource/xrm/client_test.go +++ b/pkg/resource/xrm/client_test.go @@ -31,7 +31,7 @@ import ( xpv2 "github.com/crossplane/crossplane/apis/v2/core/v2" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) type xrcOpt func(c *claim.Unstructured) diff --git a/cmd/crossplane/common/resource/xrm/loader.go b/pkg/resource/xrm/loader.go similarity index 98% rename from cmd/crossplane/common/resource/xrm/loader.go rename to pkg/resource/xrm/loader.go index 3dcb0355..e6d0893a 100644 --- a/cmd/crossplane/common/resource/xrm/loader.go +++ b/pkg/resource/xrm/loader.go @@ -23,7 +23,7 @@ import ( v1 "k8s.io/api/core/v1" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // defaultChannelCapacity is the buffer size of the processing channel, should be a high value diff --git a/cmd/crossplane/common/resource/xrm/loader_test.go b/pkg/resource/xrm/loader_test.go similarity index 98% rename from cmd/crossplane/common/resource/xrm/loader_test.go rename to pkg/resource/xrm/loader_test.go index 551811cd..35c84b56 100644 --- a/cmd/crossplane/common/resource/xrm/loader_test.go +++ b/pkg/resource/xrm/loader_test.go @@ -10,7 +10,7 @@ import ( v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "github.com/crossplane/cli/v2/cmd/crossplane/common/resource" + "github.com/crossplane/cli/v2/pkg/resource" ) // simpleGenerator generates a tree of resources for a specific depth and the number of children to diff --git a/pkg/xr/claim.go b/pkg/xr/claim.go new file mode 100644 index 00000000..5ff7bcef --- /dev/null +++ b/pkg/xr/claim.go @@ -0,0 +1,166 @@ +/* +Copyright 2026 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package xr + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/uuid" + "k8s.io/apiserver/pkg/storage/names" + + "github.com/crossplane/crossplane-runtime/v2/pkg/errors" + "github.com/crossplane/crossplane-runtime/v2/pkg/fieldpath" + "github.com/crossplane/crossplane-runtime/v2/pkg/resource/unstructured/composite" +) + +const ( + labelClaimName = "crossplane.io/claim-name" + labelClaimNamespace = "crossplane.io/claim-namespace" + labelComposite = "crossplane.io/composite" +) + +// Options configures ConvertClaimToXR. +type Options struct { + // Name is the XR name. Empty falls back to: + // - claim.Name when Direct is true + // - claim.Name with a random suffix when Direct is false + // A non-empty Name overrides both fallbacks. + Name string + + // Kind is the XR kind. Empty defaults to "X" + claim.Kind. + Kind string + + // Direct controls XR linkage to the claim: + // - true: no spec.claimRef; no claim-name/claim-namespace labels + // - false: spec.claimRef is set; claim-name/claim-namespace labels added + Direct bool + + // GenerateUID, when true, sets metadata.uid to a fresh random UUID. + GenerateUID bool +} + +// ConvertClaimToXR converts a Crossplane Claim to a Composite Resource (XR). +func ConvertClaimToXR(claim *unstructured.Unstructured, opts Options) (*composite.Unstructured, error) { + if claim == nil { + return nil, errors.New("input is nil") + } + + if claim.Object == nil { + return nil, errors.New("invalid Claim YAML: parsed object is empty") + } + + // Get Claim's properties + claimName := claim.GetName() + + claimKind := claim.GetKind() + if claimKind == "" { + return nil, errors.New("no kind section in Claim") + } + + apiVersion := claim.GetAPIVersion() + if apiVersion == "" { + return nil, errors.New("no apiVersion in Claim") + } + + if _, err := schema.ParseGroupVersion(apiVersion); err != nil { + return nil, errors.Wrap(err, "cannot parse Claim APIVersion") + } + + annotations := claim.GetAnnotations() + + labels := claim.GetLabels() + if labels == nil { + labels = make(map[string]string) + } + + claimSpec, ok := claim.Object["spec"].(map[string]any) + if !ok || claimSpec == nil { + return nil, errors.New("no spec section in Claim") + } + + // Create a new XR and pave it for manipulation + xr := composite.New() + + xrPaved, err := fieldpath.PaveObject(xr) + if err != nil { + return nil, errors.Wrap(err, "cannot pave object") + } + + if err := xrPaved.SetString("apiVersion", apiVersion); err != nil { + return nil, errors.Wrap(err, "cannot set apiVersion") + } + + // Set XR kind - either from opts or by prepending X to Claim's kind + kind := opts.Kind + if kind == "" { + kind = "X" + claimKind + } + + if err := xrPaved.SetString("kind", kind); err != nil { + return nil, errors.Wrap(err, "cannot set kind") + } + + if len(annotations) > 0 { + if err := xrPaved.SetValue("metadata.annotations", annotations); err != nil { + return nil, errors.Wrap(err, "cannot set annotations") + } + } + + if err := xrPaved.SetValue("spec", claimSpec); err != nil { + return nil, errors.Wrap(err, "cannot set spec") + } + + xrName := claimName + + if !opts.Direct { + xrName = names.SimpleNameGenerator.GenerateName(claimName + "-") + labels[labelClaimName] = claim.GetName() + + labels[labelClaimNamespace] = claim.GetNamespace() + if err := xrPaved.SetValue("spec.claimRef", map[string]any{ + "apiVersion": apiVersion, + "kind": claimKind, + "name": claimName, + "namespace": claim.GetNamespace(), + }); err != nil { + return nil, errors.Wrap(err, "cannot set claimRef") + } + } + + // Explicit Name overrides both Direct's claim-name default and the generated suffix. + if opts.Name != "" { + xrName = opts.Name + } + + if err := xrPaved.SetString("metadata.name", xrName); err != nil { + return nil, errors.Wrap(err, "cannot set name") + } + + if len(labels) > 0 { + delete(labels, labelComposite) + + if err := xrPaved.SetValue("metadata.labels", labels); err != nil { + return nil, errors.Wrap(err, "cannot set labels") + } + } + + if opts.GenerateUID { + xr.SetUID(uuid.NewUUID()) + } + + return xr, nil +} diff --git a/cmd/crossplane/xr/generate_test.go b/pkg/xr/claim_test.go similarity index 100% rename from cmd/crossplane/xr/generate_test.go rename to pkg/xr/claim_test.go