Skip to content

poc: Add JSON output to workspace list in a way that's non-breaking for human output#38159

Closed
SarahFrench wants to merge 20 commits intomainfrom
sarah/workspace-list-json-output-nonbreaking
Closed

poc: Add JSON output to workspace list in a way that's non-breaking for human output#38159
SarahFrench wants to merge 20 commits intomainfrom
sarah/workspace-list-json-output-nonbreaking

Conversation

@SarahFrench
Copy link
Copy Markdown
Member

@SarahFrench SarahFrench commented Feb 12, 2026

Related to #37439

This PR

This PR shows how a command that still uses cli.Ui for human output could be changed to enable JSON output.

These changes include:

1. Making the command process arguments using the arguments package

// c.Meta.process removes global flags (-no-color, -compact-warnings) and uses them to configure the Ui and View.
//
// Other command implementations remove those arguments via arguments.ParseView, instead. That is only possible if views
// are used for both human and machine output. This command still uses cli.Ui for human output, so c.Meta.process is necessary.
rawArgs = c.Meta.process(rawArgs)
// Parse command-specific arguments.
args, diags := arguments.ParseWorkspace(rawArgs)

2. Making the command use a views-like pattern to control how output is sent to streams, but preserving human-readable output being produced via cli.Ui to avoid breaking changes

// newWorkspaceList returns a views.WorkspaceList interface.
//
// When human-readable output is migrated from cli.Ui to views.View this method should be deleted and
// replaced with using views.NewWorkspaceList directly.
func newWorkspaceList(vt arguments.ViewType, view *views.View, ui cli.Ui, meta *Meta) views.WorkspaceList {

3. The config path is now obtained like this, to avoid the ModulePath method that makes it hard to add new arguments/flags to arguments (see also #38358):

configPath := c.WorkingDir.RootModuleDir()

4. I refactored the command's Run method to use a single List method on the view to render results and/or diagnostics:

Happy path:

view.List(env, states, diags)

Unhappy path example:

if wDiags.HasErrors() {
view.List("", nil, diags)
return 1
}

Details

WorkspaceList interface

This PR adds an interface in the views package called WorkspaceList:

type WorkspaceList interface {
List(selected string, list []string, diags tfdiags.Diagnostics)
}

When JSON output is produced it uses an implementation of that interface that's in the views package. That implementation uses a View internally.

When human-readable output is produced the WorkspaceList implementation is defined in the command package, because that implementation uses cli.Ui internally. This has to live in the command package as use of cli.Ui is coupled to the Meta.

JSON output is a static log

The new JSON output is a static log. Its top-level structure is the same regardless of outcome, making the JSON easier to consume.

In the happy path, including a warning, output looks like:

{
  "workspaces": [
    {
      "name": "default",
      "is_current": true
    },
    {
      "name": "dev",
      "is_current": false
    },
    {
      "name": "stage",
      "is_current": false
    },
    {
      "name": "prod",
      "is_current": false
    }
  ],
  "diagnostics": [
    {
      "severity": "warning",
      "summary": "Warning!",
      "detail": "Consider yourself warned."
    }
  ]
}

In the unhappy path output looks like:

{
  "workspaces": [],
  "diagnostics": [
    {
      "severity": "error",
      "summary": "Error from test",
      "detail": "This is a error from the mocked state store."
    }
  ]
}

Target Release

N/A

Rollback Plan

  • If a change needs to be reverted, we will roll out an update to the code within 7 days.

Changes to Security Controls

Are there any changes to security controls (access controls, encryption, logging) in this pull request? If so, explain.

CHANGELOG entry

  • This change is user-facing and I added a changelog entry.
  • This change is not user-facing.

@SarahFrench SarahFrench changed the title Sarah/workspace list json output nonbreaking experiment: Add JSON output to workspace list in a way that's non-breaking for human output Apr 8, 2026
@SarahFrench SarahFrench changed the title experiment: Add JSON output to workspace list in a way that's non-breaking for human output poc: Add JSON output to workspace list in a way that's non-breaking for human output Apr 8, 2026
@SarahFrench SarahFrench force-pushed the sarah/workspace-list-json-output-nonbreaking branch from 5adbd34 to 8e52692 Compare April 8, 2026 10:02
@SarahFrench SarahFrench force-pushed the sarah/workspace-list-json-output-nonbreaking branch from 536526f to 1115d1a Compare April 8, 2026 14:11
…or human output. Update how output is returned by the command to use a single List method.
…de a WorkingDir value.

This is necessary after the changes in b32b60f
@SarahFrench
Copy link
Copy Markdown
Member Author

Closing in favour of 2 PRs

@SarahFrench SarahFrench reopened this Apr 16, 2026
@SarahFrench SarahFrench force-pushed the sarah/workspace-list-json-output-nonbreaking branch from 1ebe8f2 to 90f3986 Compare April 16, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant