Skip to content

Commit

Permalink
Automatically infer latest spec revision when importing deployments (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
timburks authored Mar 10, 2023
1 parent b9f77d1 commit 827307f
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 5 deletions.
27 changes: 22 additions & 5 deletions cmd/registry/patch/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,29 @@ func relativeSpecRevisionName(apiName names.Api, spec string) string {
return spec
}

// optionalSpecRevisionName returns a spec revision name if the subpath is not empty
func optionalSpecRevisionName(deploymentName names.Deployment, subpath string) string {
// resolveSpecRevisionName returns a "full-resolved" spec revision name
// that is relative to the root ("/") and includes a revision ID.
func resolveSpecRevisionName(ctx context.Context, client *gapic.RegistryClient, deploymentName names.Deployment, subpath string) (string, error) {
if subpath == "" {
return ""
return "", nil
}
specName := deploymentName.Api().String() + "/versions/" + subpath
specRevisionName, err := names.ParseSpecRevision(specName)
if err == nil && specRevisionName.RevisionID != "" {
// this already includes a revision, we're good
return specName, nil
}
_, err = names.ParseSpec(specName)
if err != nil {
// this isn't a valid spec name, so filter it out
return "", err
}
// Get the latest revision of this spec
spec, err := client.GetApiSpec(ctx, &rpc.GetApiSpecRequest{Name: specName})
if err != nil {
return "", err
}
return deploymentName.Api().String() + "/versions/" + subpath
return spec.Name + "@" + spec.RevisionId, nil
}

// NewApiDeployment allows an API deployment to be individually exported as a YAML file.
Expand Down Expand Up @@ -128,7 +145,7 @@ func applyApiDeploymentPatch(
},
AllowMissing: true,
}
req.ApiDeployment.ApiSpecRevision = optionalSpecRevisionName(name, deployment.Data.ApiSpecRevision)
req.ApiDeployment.ApiSpecRevision, err = resolveSpecRevisionName(ctx, client, name, deployment.Data.ApiSpecRevision)
if err != nil {
return err
}
Expand Down
52 changes: 52 additions & 0 deletions cmd/registry/patch/patch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/apigee/registry/server/registry/test/seeder"
metrics "github.com/google/gnostic/metrics"
"github.com/google/go-cmp/cmp"
"google.golang.org/api/iterator"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
)
Expand Down Expand Up @@ -1345,3 +1346,54 @@ func TestEmptyArtifactPatches(t *testing.T) {
})
}
}

func TestDeploymentImports(t *testing.T) {
tests := []struct {
desc string
root string
}{
{
desc: "sample-nested",
root: "testdata/deployments-nested",
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
ctx := context.Background()
project := names.Project{ProjectID: "patch-deployments-test"}

registryClient, _ := grpctest.SetupRegistry(ctx, t, "patch-empty-test", []seeder.RegistryResource{
&rpc.Project{
Name: project.String(),
},
})

// set the configured registry.project to the test project
config, err := connection.ActiveConfig()
if err != nil {
t.Fatalf("Setup: Failed to get registry configuration: %s", err)
}
config.Project = project.ProjectID
connection.SetConfig(config)

// apply the api and deployments
if err := Apply(ctx, registryClient, nil, test.root, project.String()+"/locations/global", true, 10); err != nil {
t.Fatalf("Apply() returned error: %s", err)
}

// verify that all the spec references are to specific revisions
it := registryClient.ListApiDeployments(ctx, &rpc.ListApiDeploymentsRequest{
Parent: project.Api("registry").String(),
})
for d, err := it.Next(); err != iterator.Done; d, err = it.Next() {
specName, err := names.ParseSpecRevision(d.ApiSpecRevision)
if err != nil {
t.Errorf("failed to parse spec name %s", d.ApiSpecRevision)
}
if specName.RevisionID == "" {
t.Errorf("spec revision ID should not be empty: %s", d.ApiSpecRevision)
}
}
})
}
}
37 changes: 37 additions & 0 deletions cmd/registry/patch/testdata/deployments-nested/registry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
apiVersion: apigeeregistry/v1
kind: API
metadata:
name: registry
data:
displayName: Apigee Registry API
description: The Registry API allows teams to track and manage machine-readable descriptions of APIs.
availability: Preview
recommendedVersion: v1
recommendedDeployment: prod
versions:
- metadata:
name: v1
data:
displayName: v1
description: New in 2022
state: Staging
primarySpec: apis/registry/versions/v1/specs/openapi
specs:
- metadata:
name: openapi
data:
filename: openapi.yaml
description: OpenAPI description of the Registry API
mimeType: application/x.openapi+gzip;version=3
sourceURI: https://raw.githubusercontent.com/apigee/registry/main/openapi.yaml
deployments:
- metadata:
name: specific-revision
data:
apiSpecRevision: v1/specs/openapi@latest
endpointURI: https://apigeeregistry.googleapis.com
- metadata:
name: inferred-revision
data:
apiSpecRevision: v1/specs/openapi
endpointURI: https://apigeeregistry.googleapis.com
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: apigeeregistry/v1
kind: Deployment
metadata:
name: prod-separate
parent: apis/registry
data:
displayName: Production
description: The hosted deployment of the Registry API
apiSpecRevision: v1/specs/openapi

0 comments on commit 827307f

Please sign in to comment.