Swap from 'package' to 'instance' and use new v1 API where able#225
Swap from 'package' to 'instance' and use new v1 API where able#225chrisghill wants to merge 3 commits intomainfrom
Conversation
| Deprecated: "This has been moved under `package`. This command will be removed in v2.", | ||
| Args: cobra.ExactArgs(1), | ||
| RunE: runPkgConfigure, | ||
| RunE: runInstanceConfigure, |
There was a problem hiding this comment.
we should drop application command for our v1 release.
| "testing" | ||
|
|
||
| "github.com/massdriver-cloud/mass/internal/api" | ||
| "github.com/massdriver-cloud/mass/internal/api/v0" |
There was a problem hiding this comment.
I'm not sure we shoud keep v0 in the next release at all. I think we just make a new major version of the cli that is for our v1 and drop v0. the API still exists, if someone wants to call it they can use the old CLI for now
There was a problem hiding this comment.
I completely agree, I was just planning for this to be iterative as apposed to all-at-once. We can swap everything over v1 in a single PR if you prefer.
There was a problem hiding this comment.
Pull request overview
This PR refactors the CLI and internal API client to align terminology around “instances” (vs “packages”) and introduces a new internal/api/v1 client where available, while moving the existing GraphQL client to internal/api/v0.
Changes:
- Split the internal API client into versioned packages (
internal/api/v0andinternal/api/v1) and update call sites/imports accordingly. - Replace the top-level
mass packagecommand implementation withmass instance(keeping legacy naming via aliases) and adjust templates/docs. - Update various commands and TUIs to use the versioned API clients and new URL helper semantics.
Reviewed changes
Copilot reviewed 91 out of 136 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/tui/components/artifacttable/model.go | Switch TUI component to import internal/api/v0. |
| internal/tui/components/artifacttable/model_test.go | Update tests to use internal/api/v0. |
| internal/tui/components/artdeftable/model.go | Switch TUI component to import internal/api/v0. |
| internal/tui/components/artdeftable/model_test.go | Update tests to use internal/api/v0. |
| internal/definition/publish.go | Update definition publishing to use internal/api/v0. |
| internal/definition/publish_test.go | Update tests to use internal/api/v0. |
| internal/definition/get.go | Update definition retrieval to use internal/api/v0. |
| internal/definition/get_test.go | Update tests to use internal/api/v0. |
| internal/definition/delete.go | Update definition deletion to use internal/api/v0. |
| internal/commands/project/export.go | Update project export command to use internal/api/v0. |
| internal/commands/preview/new.go | Update preview flow to use internal/api/v0. |
| internal/commands/preview/new_test.go | Update tests to use internal/api/v0. |
| internal/commands/preview/model.go | Update preview model to use internal/api/v0. |
| internal/commands/preview/deploy.go | Update preview deploy to use internal/api/v0. |
| internal/commands/preview/deploy_test.go | Update tests to use internal/api/v0. |
| internal/commands/preview/decommission.go | Update preview decommission to use internal/api/v0. |
| internal/commands/instance/reset.go | Rename package to instance command package and move to internal/api/v0. |
| internal/commands/instance/reset_test.go | Update reset tests for instance terminology and v0 API. |
| internal/commands/instance/patch.go | Rename package to instance command package and move to internal/api/v0. |
| internal/commands/instance/patch_test.go | Update patch tests for instance terminology and v0 API. |
| internal/commands/instance/export.go | Rename package to instance command package and move to internal/api/v0. |
| internal/commands/instance/export_test.go | Update export tests for instance terminology and v0 API. |
| internal/commands/instance/deploy.go | Rename package to instance and update deploy docs/vars and v0 API import. |
| internal/commands/instance/deploy_test.go | Update deploy tests to use internal/api/v0 and commands/instance. |
| internal/commands/instance/configure.go | Rename package to instance and update v0 API import. |
| internal/commands/instance/configure_test.go | Update configure tests to use internal/api/v0 and commands/instance. |
| internal/commands/image/push.go | Update image push to use internal/api/v0. |
| internal/commands/image/push_test.go | Update image push tests to use internal/api/v0. |
| internal/commands/image/docker_client.go | Update docker client integration to use internal/api/v0. |
| internal/commands/environment/export.go | Swap environment export to use commands/instance and internal/api/v0. |
| internal/commands/bundle/pull.go | Update bundle pull to use internal/api/v0. |
| internal/commands/bundle/publish.go | Update bundle publish to use internal/api/v0. |
| internal/commands/artifact/update.go | Update artifact update to use internal/api/v0. |
| internal/commands/artifact/import.go | Update artifact import to use internal/api/v0. |
| internal/artifact/import_prompt.go | Update artifact import prompting to use internal/api/v0. |
| internal/api/v1/tools.go | Add tools-only file to pin genqlient generator deps. |
| internal/api/v1/scalars/json.go | Add v1 JSON scalar marshaling/unmarshaling helpers. |
| internal/api/v1/scalars/json_test.go | Add tests for scalar JSON helpers. |
| internal/api/v1/scalars/cursor.go | Add v1 Cursor scalar struct. |
| internal/api/v1/project.go | Implement v1 Project API wrapper functions. |
| internal/api/v1/project_test.go | Add tests for v1 Project API wrappers. |
| internal/api/v1/main.go | Add go:generate for genqlient in v1. |
| internal/api/v1/instance.go | Add v1 Instance model. |
| internal/api/v1/genqlient.yaml | Configure genqlient generation/bindings for v1. |
| internal/api/v1/genqlient.graphql | Add v1 GraphQL operations (projects/environments). |
| internal/api/v1/error.go | Add v1 mutation error type. |
| internal/api/v1/environment.go | Implement v1 Environment API wrapper functions. |
| internal/api/v1/environment_test.go | Add tests for v1 Environment API wrappers. |
| internal/api/v1/cost.go | Add v1 cost models. |
| internal/api/v1/bundle.go | Add v1 bundle model. |
| internal/api/v1/blueprint.go | Add v1 blueprint model. |
| internal/api/v0/zz_generated.go | Update generated v0 client imports and deployedVersion pointer handling. |
| internal/api/v0/urls.go | Rename URL helper methods and shift naming toward IDs/instances. |
| internal/api/v0/server.go | Add v0 Server API wrapper. |
| internal/api/v0/server_test.go | Update server tests to use internal/api/v0. |
| internal/api/v0/scalars/json.go | Add v0 JSON scalar marshaling/unmarshaling helpers. |
| internal/api/v0/scalars/json_test.go | Update scalar tests to use internal/api/v0/scalars. |
| internal/api/v0/scalars/cursor.go | Add v0 Cursor scalar struct. |
| internal/api/v0/repo.go | Update repo client to use versioned scalars import. |
| internal/api/v0/repo_test.go | Update repo tests to use internal/api/v0. |
| internal/api/v0/project.go | Add v0 Project API wrapper (migrated from unversioned). |
| internal/api/v0/project_test.go | Update project tests to use internal/api/v0. |
| internal/api/v0/preview_environment.go | Add v0 preview environment API wrapper. |
| internal/api/v0/preview_environment_test.go | Update preview env tests to use internal/api/v0. |
| internal/api/v0/preview_config.go | Add v0 preview config models. |
| internal/api/v0/preview_config_test.go | Update preview config tests to use internal/api/v0. |
| internal/api/v0/package.go | Add v0 Package API wrapper/models with pointer deployedVersion handling. |
| internal/api/v0/package_test.go | Update package tests to use internal/api/v0. |
| internal/api/v0/oci.go | Add v0 OCI repo wrapper. |
| internal/api/v0/oci_test.go | Update OCI tests to use internal/api/v0. |
| internal/api/v0/manifest.go | Add v0 manifest wrapper. |
| internal/api/v0/main.go | Add go:generate for genqlient in v0. |
| internal/api/v0/genqlient.yaml | Fix v0 genqlient bindings to point to internal scalars. |
| internal/api/v0/genqlient.graphql | Add v0 GraphQL operations file for genqlient. |
| internal/api/v0/error.go | Add v0 mutation error type. |
| internal/api/v0/error_test.go | Update error tests to use internal/api/v0. |
| internal/api/v0/environment.go | Add v0 Environment wrapper/model (includes URL helper). |
| internal/api/v0/environment_test.go | Update environment tests to use internal/api/v0. |
| internal/api/v0/deployment.go | Add v0 deployment wrapper/models and log retrieval. |
| internal/api/v0/deployment_test.go | Update deployment tests to use internal/api/v0. |
| internal/api/v0/credential.go | Add v0 credential/artifact listing helpers. |
| internal/api/v0/credential_test.go | Update credential tests to use internal/api/v0. |
| internal/api/v0/cost.go | Add v0 cost models. |
| internal/api/v0/container_repository.go | Add v0 container repository wrapper. |
| internal/api/v0/container_repository_test.go | Update container repository tests to use internal/api/v0. |
| internal/api/v0/bundle.go | Add v0 bundle wrapper. |
| internal/api/v0/bundle_test.go | Update bundle tests to use internal/api/v0. |
| internal/api/v0/artifact.go | Add v0 artifact CRUD wrappers. |
| internal/api/v0/artifact_test.go | Update artifact tests to use internal/api/v0. |
| internal/api/v0/artifact_definitions.go | Add v0 artifact definition wrappers. |
| internal/api/v0/artifact_definitions_test.go | Update artifact definition tests to use internal/api/v0. |
| internal/api/main.go | Remove unversioned internal/api entrypoint. |
| go.sum | Update sums for new dependencies / sdk version. |
| go.mod | Update Go version directive and bump massdriver-sdk-go requirement. |
| docs/helpdocs/instance/version.md | Add instance command helpdoc (currently still package-centric wording/examples). |
| docs/helpdocs/instance/reset.md | Add instance reset helpdoc (currently still package-centric wording/examples). |
| docs/helpdocs/instance/patch.md | Add instance patch helpdoc. |
| docs/helpdocs/instance/list.md | Add instance list helpdoc. |
| docs/helpdocs/instance/get.md | Add instance get helpdoc. |
| docs/helpdocs/instance/export.md | Add instance export helpdoc. |
| docs/helpdocs/instance/deploy.md | Add instance deploy helpdoc. |
| docs/helpdocs/instance/create.md | Add instance create helpdoc. |
| docs/helpdocs/instance/configure.md | Add instance configure helpdoc. |
| docs/helpdocs/instance.md | Add top-level instance helpdoc page. |
| docs/generated/mass.md | Update generated CLI docs index to list mass instance instead of mass package. |
| docs/generated/mass_instance.md | Add generated docs for instance root command. |
| docs/generated/mass_instance_version.md | Add generated docs for instance version subcommand. |
| docs/generated/mass_instance_reset.md | Add generated docs for instance reset subcommand. |
| docs/generated/mass_instance_patch.md | Add generated docs for instance patch subcommand. |
| docs/generated/mass_instance_list.md | Add generated docs for instance list subcommand. |
| docs/generated/mass_instance_get.md | Add generated docs for instance get subcommand. |
| docs/generated/mass_instance_export.md | Add generated docs for instance export subcommand. |
| docs/generated/mass_instance_destroy.md | Add generated docs for instance destroy subcommand. |
| docs/generated/mass_instance_deploy.md | Add generated docs for instance deploy subcommand. |
| docs/generated/mass_instance_create.md | Add generated docs for instance create subcommand. |
| docs/generated/mass_instance_configure.md | Add generated docs for instance configure subcommand. |
| cmd/version.go | Switch CLI version command to import internal/api/v0. |
| cmd/templates/project.get.md.tmpl | Update project template fields (ID + new cost field names). |
| cmd/templates/instance.get.md.tmpl | Add new instance “get” template (renders v0 Package as instance). |
| cmd/templates/environment.get.md.tmpl | Update environment template to v1 fields/instances list and new cost fields. |
| cmd/root.go | Swap root command from NewCmdPkg() to NewCmdInstance(). |
| cmd/project.go | Update project CLI to v1 project APIs and adjust displayed fields/URLs. |
| cmd/preview.go | Switch preview command to import internal/api/v0. |
| cmd/package.go | Remove legacy mass package command implementation. |
| cmd/logs.go | Switch logs command to import internal/api/v0. |
| cmd/instance.go | Add new mass instance command implementation (replacement for package). |
| cmd/infrastructure.go | Update deprecated infra command wiring to point at instance handlers/flags. |
| cmd/environment.go | Update environment CLI to use v1 for get/create and v0 for list/default URL helper. |
| cmd/definition.go | Switch definition command to import internal/api/v0. |
| cmd/credential.go | Switch credential command to import internal/api/v0. |
| cmd/bundle.go | Switch bundle command to import internal/api/v0. |
| cmd/artifact.go | Switch artifact command to import internal/api/v0. |
| cmd/application.go | Update deprecated app command wiring to point at instance handlers/flags. |
Comments suppressed due to low confidence (1)
internal/api/v0/urls.go:53
- InstanceURL’s doc comment still says it returns a URL for a "package". Since this helper was renamed to InstanceURL, update the comment to refer to an instance (and consider mentioning that the query parameter name is still
packageif that’s intentional for the app URL scheme).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import ( | ||
| "reflect" | ||
| "testing" | ||
|
|
||
| "github.com/massdriver-cloud/mass/internal/api/v0/scalars" | ||
| ) |
There was a problem hiding this comment.
This test file is in the v1 scalars package but it imports and exercises the v0 scalars implementation, so it won’t catch regressions in internal/api/v1/scalars. Import internal/api/v1/scalars here (or alias the import) so the v1 bindings are actually tested.
| ## Instances | ||
| | Name | Bundle | Status | | ||
| | ---- | ------ | ------ | | ||
| {{- range .Packages}} | ||
| | **{{.Manifest.Name}}** | {{.Bundle.Name}} | {{.Status}} | | ||
| {{- range .Blueprint.Instances}} | ||
| | **{{.Name}}** | {{.Bundle.Name}} | {{.Status}} | | ||
| {{- end}} |
There was a problem hiding this comment.
This template ranges over .Blueprint.Instances unconditionally. In the v1 API conversion, Blueprint is only set when there are instances, so .Blueprint can be nil and this will error at render time for environments with zero instances. Guard with an {{if .Blueprint}}...{{end}} (or ensure Blueprint is always non-nil in the API type).
| if err == nil && instanceDetails.Environment != nil && instanceDetails.Environment.Project != nil && instanceDetails.Manifest != nil { | ||
| urlHelper, urlErr := apiv0.NewURLHelper(ctx, mdClient) | ||
| if urlErr == nil { | ||
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instanceDetails.Environment.Project.ID, instanceDetails.Environment.ID, instanceDetails.Manifest.ID)) |
There was a problem hiding this comment.
This URL is built using instanceDetails.Manifest.ID as the package query parameter. Elsewhere (e.g., create) this helper is called with the manifest slug, and the actual instance/package also has its own ID. Please use a single, correct identifier consistently (likely instanceDetails.ID if the UI expects the package/instance ID, or instanceDetails.Manifest.Slug if it expects the manifest slug), otherwise the generated link can point to the wrong canvas node.
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instanceDetails.Environment.Project.ID, instanceDetails.Environment.ID, instanceDetails.Manifest.ID)) | |
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instanceDetails.Environment.Project.ID, instanceDetails.Environment.ID, instanceDetails.ID)) |
| if err == nil && instanceDetails.Environment != nil && instanceDetails.Environment.Project != nil && instanceDetails.Manifest != nil { | ||
| urlHelper, urlErr := apiv0.NewURLHelper(ctx, mdClient) | ||
| if urlErr == nil { | ||
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instanceDetails.Environment.Project.ID, instanceDetails.Environment.ID, instanceDetails.Manifest.ID)) |
There was a problem hiding this comment.
Same issue as configure: this URL uses instanceDetails.Manifest.ID for the package query parameter. Use the correct identifier consistently (instance/package ID vs manifest slug) to avoid generating broken links.
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instanceDetails.Environment.Project.ID, instanceDetails.Environment.ID, instanceDetails.Manifest.ID)) | |
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instanceDetails.Environment.Project.ID, instanceDetails.Environment.ID, updatedPkg.ID)) |
| if instance.Environment != nil && instance.Environment.Project != nil && instance.Manifest != nil { | ||
| urlHelper, urlErr := apiv0.NewURLHelper(ctx, mdClient) | ||
| if urlErr == nil { | ||
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instance.Environment.Project.ID, instance.Environment.ID, instance.Manifest.ID)) |
There was a problem hiding this comment.
Same issue as configure/version: this URL uses instance.Manifest.ID for the package query parameter. Use the correct identifier consistently (instance/package ID vs manifest slug) to avoid generating broken links.
| if instance.Environment != nil && instance.Environment.Project != nil && instance.Manifest != nil { | |
| urlHelper, urlErr := apiv0.NewURLHelper(ctx, mdClient) | |
| if urlErr == nil { | |
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instance.Environment.Project.ID, instance.Environment.ID, instance.Manifest.ID)) | |
| if instance.Environment != nil && instance.Environment.Project != nil { | |
| urlHelper, urlErr := apiv0.NewURLHelper(ctx, mdClient) | |
| if urlErr == nil { | |
| fmt.Printf("🔗 %s\n", urlHelper.InstanceURL(instance.Environment.Project.ID, instance.Environment.ID, instance.ID)) |
| tbl := cli.NewTable("ID/Slug", "Name", "Description", "Monthly $", "Daily $") | ||
|
|
||
| for _, project := range projects { | ||
| monthly := "" | ||
| daily := "" | ||
| if project.Cost.Monthly.Average.Amount != nil { | ||
| monthly = fmt.Sprintf("%v", *project.Cost.Monthly.Average.Amount) | ||
| if project.Cost.MonthlyAverage.Amount != nil { | ||
| monthly = fmt.Sprintf("%v", *project.Cost.MonthlyAverage.Amount) | ||
| } | ||
| if project.Cost.Daily.Average.Amount != nil { | ||
| daily = fmt.Sprintf("%v", *project.Cost.Daily.Average.Amount) | ||
| if project.Cost.DailyAverage.Amount != nil { | ||
| daily = fmt.Sprintf("%v", *project.Cost.DailyAverage.Amount) | ||
| } | ||
| description := cli.TruncateString(project.Description, 60) | ||
| tbl.AddRow(project.Slug, project.Name, description, monthly, daily) | ||
| tbl.AddRow(project.ID, project.Name, description, monthly, daily) | ||
| } |
There was a problem hiding this comment.
This table now prints project.ID values, but the header still says "ID/Slug". Update the header to just "ID" (or include both fields) to keep CLI output accurate.
| } | ||
|
|
||
| tbl := cli.NewTable("ID/Slug", "Name", "Description", "Monthly $", "Daily $") | ||
| tbl := cli.NewTable("ID", "Name", "Description", "Monthly $", "Daily $") |
There was a problem hiding this comment.
The table header was updated to "ID", but the rows below still add env.Slug as the first column. Update either the header (back to "Slug"/"ID/Slug") or the row value (to env.ID) so the output matches what’s displayed.
| tbl := cli.NewTable("ID", "Name", "Description", "Monthly $", "Daily $") | |
| tbl := cli.NewTable("Slug", "Name", "Description", "Monthly $", "Daily $") |
No description provided.