diff --git a/server/registry/actions_artifacts.go b/server/registry/actions_artifacts.go index 7ee2880f8..b3c9023d6 100644 --- a/server/registry/actions_artifacts.go +++ b/server/registry/actions_artifacts.go @@ -94,6 +94,10 @@ func (s *RegistryServer) CreateArtifact(ctx context.Context, req *rpc.CreateArti if _, err := db.GetSpec(ctx, parent); err != nil { return nil, err } + case names.Deployment: + if _, err := db.GetDeployment(ctx, parent); err != nil { + return nil, err + } } artifact, err := models.NewArtifact(name, req.GetArtifact()) @@ -235,6 +239,12 @@ func (s *RegistryServer) ListArtifacts(ctx context.Context, req *rpc.ListArtifac Filter: req.GetFilter(), Token: req.GetPageToken(), }) + case names.Deployment: + listing, err = db.ListDeploymentArtifacts(ctx, parent, storage.PageOptions{ + Size: req.GetPageSize(), + Filter: req.GetFilter(), + Token: req.GetPageToken(), + }) } if err != nil { return nil, err diff --git a/server/registry/actions_artifacts_test.go b/server/registry/actions_artifacts_test.go index 15b57cbdd..69c3527e9 100644 --- a/server/registry/actions_artifacts_test.go +++ b/server/registry/actions_artifacts_test.go @@ -192,15 +192,55 @@ func TestCreateArtifact(t *testing.T) { func TestCreateArtifactResponseCodes(t *testing.T) { tests := []struct { desc string - seed *rpc.Project + seed seeder.RegistryResource req *rpc.CreateArtifactRequest want codes.Code }{ { - desc: "parent not found", + desc: "parent project not found", + seed: &rpc.Project{Name: "projects/other-project"}, + req: &rpc.CreateArtifactRequest{ + Parent: "projects/my-project/locations/global", + ArtifactId: "valid-id", + Artifact: &rpc.Artifact{}, + }, + want: codes.NotFound, + }, + { + desc: "parent api not found", seed: &rpc.Project{Name: "projects/my-project"}, req: &rpc.CreateArtifactRequest{ - Parent: "projects/other-project/locations/global", + Parent: "projects/my-project/locations/global/apis/a", + ArtifactId: "valid-id", + Artifact: &rpc.Artifact{}, + }, + want: codes.NotFound, + }, + { + desc: "parent version not found", + seed: &rpc.Api{Name: "projects/my-project/locations/global/apis/a"}, + req: &rpc.CreateArtifactRequest{ + Parent: "projects/my-project/locations/global/apis/a/versions/v", + ArtifactId: "valid-id", + Artifact: &rpc.Artifact{}, + }, + want: codes.NotFound, + }, + { + desc: "parent spec not found", + seed: &rpc.ApiVersion{Name: "projects/my-project/locations/global/apis/a/versions/v"}, + req: &rpc.CreateArtifactRequest{ + Parent: "projects/my-project/locations/global/apis/a/versions/v/specs/s", + ArtifactId: "valid-id", + Artifact: &rpc.Artifact{}, + }, + want: codes.NotFound, + }, + { + desc: "parent deployment not found", + seed: &rpc.Api{Name: "projects/my-project/locations/global/apis/a"}, + req: &rpc.CreateArtifactRequest{ + Parent: "projects/my-project/locations/global/apis/a/deployments/d", ArtifactId: "valid-id", Artifact: &rpc.Artifact{}, }, @@ -292,7 +332,7 @@ func TestCreateArtifactResponseCodes(t *testing.T) { t.Run(test.desc, func(t *testing.T) { ctx := context.Background() server := defaultTestServer(t) - if err := seeder.SeedProjects(ctx, server, test.seed); err != nil { + if err := seeder.SeedRegistry(ctx, server, test.seed); err != nil { t.Fatalf("Setup/Seeding: Failed to seed registry: %s", err) } @@ -630,6 +670,25 @@ func TestListArtifacts(t *testing.T) { }, }, }, + { + desc: "artifacts owned by a deployment", + seed: []*rpc.Artifact{ + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d1/artifacts/artifact1"}, + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d1/artifacts/artifact2"}, + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d1/artifacts/artifact3"}, + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d2/artifacts/artifact4"}, + }, + req: &rpc.ListArtifactsRequest{ + Parent: "projects/my-project/locations/global/apis/my-api/deployments/d1", + }, + want: &rpc.ListArtifactsResponse{ + Artifacts: []*rpc.Artifact{ + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d1/artifacts/artifact1"}, + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d1/artifacts/artifact2"}, + {Name: "projects/my-project/locations/global/apis/my-api/deployments/d1/artifacts/artifact3"}, + }, + }, + }, } for _, test := range tests { diff --git a/server/registry/internal/storage/artifacts.go b/server/registry/internal/storage/artifacts.go index 23f9d44e6..33c7244b0 100644 --- a/server/registry/internal/storage/artifacts.go +++ b/server/registry/internal/storage/artifacts.go @@ -143,6 +143,53 @@ func (d *Client) ListVersionArtifacts(ctx context.Context, parent names.Version, }) } +func (d *Client) ListDeploymentArtifacts(ctx context.Context, parent names.Deployment, opts PageOptions) (ArtifactList, error) { + q := d.NewQuery(gorm.ArtifactEntityName) + q = q.Require("SpecID", "") + q = q.Require("VersionID", "") + + token, err := decodeToken(opts.Token) + if err != nil { + return ArtifactList{}, status.Errorf(codes.InvalidArgument, "invalid page token %q: %s", opts.Token, err.Error()) + } + + if err := token.ValidateFilter(opts.Filter); err != nil { + return ArtifactList{}, status.Errorf(codes.InvalidArgument, "invalid filter %q: %s", opts.Filter, err) + } else { + token.Filter = opts.Filter + } + + q = q.ApplyOffset(token.Offset) + + if id := parent.ProjectID; id != "-" { + q = q.Require("ProjectID", id) + } + if id := parent.ApiID; id != "-" { + q = q.Require("ApiID", id) + } + if id := parent.DeploymentID; id != "-" { + q = q.Require("DeploymentID", id) + } + + if parent.ProjectID != "-" && parent.ApiID != "-" && parent.DeploymentID != "-" { + if _, err := d.GetDeployment(ctx, parent); err != nil { + return ArtifactList{}, err + } + } else if parent.ProjectID != "-" && parent.ApiID != "-" && parent.DeploymentID == "-" { + if _, err := d.GetApi(ctx, parent.Api()); err != nil { + return ArtifactList{}, err + } + } else if parent.ProjectID != "-" && parent.ApiID == "-" && parent.DeploymentID == "-" { + if _, err := d.GetProject(ctx, parent.Project()); err != nil { + return ArtifactList{}, err + } + } + + return d.listArtifacts(ctx, d.Run(ctx, q), opts, func(a *models.Artifact) bool { + return a.ProjectID != "" && a.ApiID != "" && a.DeploymentID != "" + }) +} + func (d *Client) ListApiArtifacts(ctx context.Context, parent names.Api, opts PageOptions) (ArtifactList, error) { q := d.NewQuery(gorm.ArtifactEntityName) q = q.Require("VersionID", "")