Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gemini/journals/cloudnumberregistry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
### [2026-06-09] CloudNumberRegistry Custom Range Greenfield Scaffolding
- **Context**: Implementing `CloudNumberRegistryCustomRange` types and identity in `v1alpha1`
- **Problem**: The required `google.cloud.numberregistry.v1alpha` proto is only present in extremely recent commits of `googleapis` (on or after May 21, 2026) but the global pin in `apis/git.versions` is set to an older commit (`1765b559c42386788ff0c6412491277b4791107a`). Updating `apis/git.versions` globally triggers code regeneration on dozens of other resources, polluting the PR and violating targeted changes.
- **Solution**: Compiled a custom, service-specific `googleapis-numberregistry.pb` by checking out `fe9f668e59b5448d27564d2b89b5aed97b74f8d7` only inside `generate.sh`. Restored the default global `apis/git.versions` and `googleapis.pb` to their original states. Updated the generation tool flags with `--proto-source-path` pointing to the custom `.pb` file.
- **Impact**: Keeps PRs clean, avoids code-generation pollution of other services, and enables implementing greenfield APIs that depend on more recent googleapis commits than what is globally pinned in the repository.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2026 Google LLC
//
// 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 v1alpha1

import (
"context"
"fmt"

"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common"
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common/identity"
refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/gcpurls"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
_ identity.IdentityV2 = &CloudNumberRegistryCustomRangeIdentity{}
_ identity.Resource = &CloudNumberRegistryCustomRange{}
)

var CloudNumberRegistryCustomRangeIdentityFormat = gcpurls.Template[CloudNumberRegistryCustomRangeIdentity]("cloudnumberregistry.googleapis.com", "projects/{project}/locations/{location}/customRanges/{customrange}")

// CloudNumberRegistryCustomRangeIdentity is the identity of a GCP CloudNumberRegistryCustomRange resource.
// +k8s:deepcopy-gen=false
type CloudNumberRegistryCustomRangeIdentity struct {
Project string
Location string
CustomRange string
}

func (i *CloudNumberRegistryCustomRangeIdentity) String() string {
return CloudNumberRegistryCustomRangeIdentityFormat.ToString(*i)
}

func (i *CloudNumberRegistryCustomRangeIdentity) FromExternal(ref string) error {
parsed, match, err := CloudNumberRegistryCustomRangeIdentityFormat.Parse(ref)
if err != nil {
return fmt.Errorf("format of CloudNumberRegistryCustomRange external=%q was not known (use %s): %w", ref, CloudNumberRegistryCustomRangeIdentityFormat.CanonicalForm(), err)
}
if !match {
return fmt.Errorf("format of CloudNumberRegistryCustomRange external=%q was not known (use %s)", ref, CloudNumberRegistryCustomRangeIdentityFormat.CanonicalForm())
}

*i = *parsed
return nil
}

func (i *CloudNumberRegistryCustomRangeIdentity) Host() string {
return CloudNumberRegistryCustomRangeIdentityFormat.Host()
}

func getIdentityFromCloudNumberRegistryCustomRangeSpec(ctx context.Context, reader client.Reader, obj *CloudNumberRegistryCustomRange) (*CloudNumberRegistryCustomRangeIdentity, error) {
resourceID, err := refs.GetResourceID(obj)
if err != nil {
return nil, fmt.Errorf("cannot resolve resource ID")
}

location, err := refs.GetLocation(obj)
if err != nil {
return nil, fmt.Errorf("cannot resolve location")
}

projectID, err := refs.ResolveProjectID(ctx, reader, obj)
if err != nil {
return nil, fmt.Errorf("cannot resolve project")
}

identity := &CloudNumberRegistryCustomRangeIdentity{
Project: projectID,
Location: location,
CustomRange: resourceID,
}
return identity, nil
}

func (obj *CloudNumberRegistryCustomRange) GetIdentity(ctx context.Context, reader client.Reader) (identity.Identity, error) {
specIdentity, err := getIdentityFromCloudNumberRegistryCustomRangeSpec(ctx, reader, obj)
if err != nil {
return nil, err
}

// Cross-check the identity against the status value, if present.
externalRef := common.ValueOf(obj.Status.ExternalRef)
if externalRef != "" {
statusIdentity := &CloudNumberRegistryCustomRangeIdentity{}
if err := statusIdentity.FromExternal(externalRef); err != nil {
return nil, err
}

if statusIdentity.String() != specIdentity.String() {
return nil, fmt.Errorf("cannot change CloudNumberRegistryCustomRange identity (old=%q, new=%q)", statusIdentity.String(), specIdentity.String())
}
}

return specIdentity, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright 2026 Google LLC
//
// 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 v1alpha1

import (
"testing"

"github.com/google/go-cmp/cmp"
)

func TestCloudNumberRegistryCustomRangeIdentity_FromExternal(t *testing.T) {
tests := []struct {
name string
ref string
wantErr bool
want *CloudNumberRegistryCustomRangeIdentity
}{
{
name: "valid reference",
ref: "projects/my-project/locations/global/customRanges/my-custom-range",
want: &CloudNumberRegistryCustomRangeIdentity{
Project: "my-project",
Location: "global",
CustomRange: "my-custom-range",
},
},
{
name: "invalid reference format",
ref: "invalid/format",
wantErr: true,
},
{
name: "full url",
ref: "https://cloudnumberregistry.googleapis.com/projects/my-project/locations/global/customRanges/my-custom-range",
want: &CloudNumberRegistryCustomRangeIdentity{
Project: "my-project",
Location: "global",
CustomRange: "my-custom-range",
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
i := &CloudNumberRegistryCustomRangeIdentity{}
err := i.FromExternal(tt.ref)
if (err != nil) != tt.wantErr {
t.Errorf("FromExternal() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
if diff := cmp.Diff(tt.want, i); diff != "" {
t.Errorf("FromExternal() mismatch (-want +got):\n%s", diff)
}
}
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright 2026 Google LLC
//
// 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 v1alpha1

import (
"context"

"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common"
"github.com/GoogleCloudPlatform/k8s-config-connector/apis/common/identity"
refs "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var _ refs.Ref = &CloudNumberRegistryCustomRangeRef{}

// CloudNumberRegistryCustomRangeRef is a reference to a GCP CloudNumberRegistryCustomRange.
type CloudNumberRegistryCustomRangeRef struct {
// A reference to an externally managed CloudNumberRegistryCustomRange resource. Should be in the format "projects/{{projectID}}/locations/{{location}}/customRanges/{{customRangeID}}"
External string `json:"external,omitempty"`

// The name of a CloudNumberRegistryCustomRange resource.
Name string `json:"name,omitempty"`

// The namespace of a CloudNumberRegistryCustomRange resource.
Namespace string `json:"namespace,omitempty"`
}

func init() {
refs.Register(&CloudNumberRegistryCustomRangeRef{})
}

func (r *CloudNumberRegistryCustomRangeRef) GetGVK() schema.GroupVersionKind {
return CloudNumberRegistryCustomRangeGVK
}

func (r *CloudNumberRegistryCustomRangeRef) GetNamespacedName() types.NamespacedName {
return types.NamespacedName{
Name: r.Name,
Namespace: r.Namespace,
}
}

func (r *CloudNumberRegistryCustomRangeRef) GetExternal() string {
return r.External
}

func (r *CloudNumberRegistryCustomRangeRef) SetExternal(ref string) {
r.External = ref
r.Name = ""
r.Namespace = ""
}

func (r *CloudNumberRegistryCustomRangeRef) ValidateExternal(ref string) error {
id := &CloudNumberRegistryCustomRangeIdentity{}
if err := id.FromExternal(ref); err != nil {
return err
}
return nil
}

func (r *CloudNumberRegistryCustomRangeRef) ParseExternalToIdentity() (identity.Identity, error) {
id := &CloudNumberRegistryCustomRangeIdentity{}
if err := id.FromExternal(r.External); err != nil {
return nil, err
}
return id, nil
}

func (r *CloudNumberRegistryCustomRangeRef) Normalize(ctx context.Context, reader client.Reader, defaultNamespace string) error {
fallback := func(u *unstructured.Unstructured) string {
obj, err := common.ToStructuredType[*CloudNumberRegistryCustomRange](u)
if err != nil {
return ""
}
identity, err := getIdentityFromCloudNumberRegistryCustomRangeSpec(ctx, reader, obj)
if err != nil {
return ""
}
return identity.String()
}
return refs.NormalizeWithFallback(ctx, reader, r, defaultNamespace, fallback)
}
Loading
Loading