Skip to content

feat(cli): teams, regions, ips and operating-systems commands + SDK v1.15.0 (PD-6080)#86

Merged
LanusseMorais merged 4 commits into
mainfrom
feature/PD-6080-cli-teams-regions-ips-os
Jun 10, 2026
Merged

feat(cli): teams, regions, ips and operating-systems commands + SDK v1.15.0 (PD-6080)#86
LanusseMorais merged 4 commits into
mainfrom
feature/PD-6080-cli-teams-regions-ips-os

Conversation

@LanusseMorais

@LanusseMorais LanusseMorais commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extends CLI API coverage with admin and metadata commands (PD-6080): team & member
management plus the regions / IPs / operating-systems catalogs — with interactive
fallbacks for required input and an enter-to-details view on IP listings. Bumps the
Go SDK to v1.15.1, which exposes these endpoints and consumes the fixed JSON:API
envelope for GET /ips/{id}.

Commands added

Group Subcommands
lsh teams list, create, update
lsh teams members list, add, remove
lsh regions list
lsh ips list, get <ip-id>
lsh operating-systems list (alias os)
  • teams members add --role <name> takes the human role name (owner /
    administrator / collaborator / billing) and resolves it to the SDK enum
    internally, with a clear error on an invalid value.
  • ips list is project-scoped (--project, or --all-projects) with --family,
    --type, --location, --server filters (case-insensitive enums);
    ips get <ip-id> is the single-record drill-down.
  • All list commands paginate to exhaustion via the SDK's Next() using
    page[size]=100, and show a stderr spinner while fetching (TTY only).

Interactive UX (TTY only — scripts fail fast with actionable errors)

  • teams create, teams update and teams members add open a form when required
    flags are omitted; teams members remove without an argument lists the team's
    members for selection and asks for confirmation before deleting.
  • ips list renders an interactive table where enter opens a details view of
    the selected IP (same pattern as servers), via new reusable
    ResourceTable/ResourceDetails TUI components.
  • With --no-input or non-TTY stdin (pipes, CI), every interactive fallback is
    replaced by a fail-fast error naming the missing flag.

Behavior notes

  • teams update operates on the team the token belongs to (API tokens are
    team-scoped). Passing another team's id fails fast with the shortest fix:
    lsh profile use <name> when a profile for it exists, lsh login otherwise,
    or a typo warning when the id is not one of your teams.
  • A successful teams update refreshes the active profile's stored team
    name/slug, keeping profile list / auth status in sync.
  • --currency is not available on teams update: the API only allows writing
    currency on create. The published spec still advertises it with a default, which
    makes the generated SDK inject currency into every PATCH — the CLI strips it
    from the wire until the spec is fixed (see workaround comment in cli/teams.go).
  • mfa_enabled is always present in members JSON output (no omitempty).
  • TTY detection now uses isatty instead of char-device sniffing, so piped
    commands get actionable errors instead of bubbletea TTY crashes.

Acceptance criteria

  • lsh teams members add --email new@example.com --role administrator invites a member
  • lsh teams members remove <id> removes a member
  • lsh regions list lists every available region
  • lsh ips list lists IPs allocated to the project

SDK / toolchain

  • latitudesh-go-sdk v1.9.0v1.15.1 (exposes teams members, regions, IPs and
    OS endpoints; v1.15.1 consumes the corrected ip_address JSON:API envelope, so
    ips get returns data).
  • go.mod now requires go 1.25.x; .github/workflows/release.yml switched from a
    hardcoded go-version: \'1.22.0\' to go-version-file: go.mod.
  • Adapted the existing volume_* operations to the renamed SDK client
    (client.Storageclient.BlockStorage) — mechanical rename, no logic changes.

Test plan

Unit tests (no credentials needed):

go test ./...

Manual validation — build, authenticate once with lsh login, then run the
commands against the live API:

go build -o ./lsh-dev .
./lsh-dev login   # opens the browser flow and stores the profile/token

# Metadata catalogs (read-only, safe)
./lsh-dev regions list
./lsh-dev operating-systems list
./lsh-dev ips list --project=<id>
./lsh-dev ips list --all-projects --family=IPv4   # enter on a row opens details
./lsh-dev ips get <ip-id>

# Teams
./lsh-dev teams list
./lsh-dev teams members list

# Interactive forms (run in a TTY, omit the flags)
./lsh-dev teams create
./lsh-dev teams update            # uses the profile\'s team; prints which one
./lsh-dev teams members add
./lsh-dev teams members remove    # member picker + confirmation

# Flags still work for scripting (mutating — use a disposable address)
./lsh-dev teams members add --email new@example.com --role administrator
./lsh-dev teams members remove <user-id>

# Fail-fast paths
./lsh-dev teams members add --email x@y.com --role superuser   # invalid role error
echo | ./lsh-dev teams create                                  # non-TTY → --name required
./lsh-dev teams members add --email x@y.com --role billing --dry-run

Notes

Greptile Summary

Adds teams, regions, ips, and operating-systems CLI commands backed by the bumped Go SDK v1.15.1, with interactive TTY fallbacks for required input and an enter-to-details view on IP listings.

  • New commands: lsh teams {list,create,update}, lsh teams members {list,add,remove}, lsh regions list, lsh ips {list,get}, lsh operating-systems list — all wired into the root command, paginated to exhaustion via Next(), guarded by dry-run, and covered by unit tests.
  • stripTeamPatchCurrency transport: a custom http.RoundTripper strips the spec-injected currency field from team PATCH bodies to work around an API spec bug; scoped to the single team-update client so other commands are unaffected.
  • TTY detection fix: IsTTY() now uses term.IsTerminal instead of ModeCharDevice, preventing bubbletea crashes when stdin is piped to /dev/null.

Confidence Score: 4/5

Safe to merge with one targeted fix: parseIPFamily rejects IPV4 and IPV6 while the PR documents case-insensitive enum handling for all IP filters.

The --family filter silently produces a user-facing error for fully-uppercased input (IPV4, IPV6) because parseIPFamily uses explicit case matching rather than strings.ToLower, inconsistent with parseIPType and the documented behavior. Every other new command and the stripTeamPatchCurrency workaround look correct and well-tested.

cli/ips.go — parseIPFamily case normalization

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[CLI command invoked] --> B{DryRun?}
    B -- yes --> Z[Log dry-run, return]

    B -- no --> C{Interactive form needed?}
    C -- "flags provided" --> D[Build request struct]
    C -- "flags missing + TTY" --> E[Run TUI prompts]
    C -- "flags missing + no TTY" --> F[requiredFlagError, return]

    E --> D
    D --> G[lsh.NewClient + API call]

    G -- error --> H[PrintError, return]
    G -- empty --> I[renderer.Render nil]
    G -- data --> J{Paginated?}

    J -- "Next() available" --> K[Append page, call Next]
    K --> J
    J -- "Next() == nil" --> L[stopSpinner]
    L --> M{Output type?}

    M -- "IP data\nisIPData" --> N[tui.RunResourceTable\nenter-details loop]
    M -- "Server data\nisServerData" --> O[RunServersTable]
    M -- other --> P[Standard table/JSON render]
Loading
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
cli/ips.go:198-206
**`parseIPFamily` is not case-insensitive for fully-uppercase input**

The PR description states that `--family` is a "case-insensitive enum," and `parseIPType` backs that up with `strings.ToLower`. But `parseIPFamily` only handles `"IPv4"`, `"ipv4"`, and `"v4"` — so `lsh ips list --family=IPV4` returns `invalid value for --family: 'IPV4' (allowed: IPv4, IPv6)` rather than filtering successfully. The test suite confirms the gap: it covers `Public` / `PRIVATE` for type, but never `IPV4` / `IPV6` for family.

### Issue 2 of 2
internal/renderer/bubbletea.go:54-64
**`isIPData` heuristic could misfire on future resources**

The function identifies IP data by checking for `address` and `family` keys in the first row. Any resource that happens to expose both fields (e.g., a network-interface or BGP session type added later) would be silently routed into the IP interactive table view. Naming the column `ip_address` / `ip_family`, or using a dedicated type tag passed through from the command layer, would make this discrimination unambiguous.

```suggestion
// isIPData checks if the data is IP address data by looking for the
// ip-specific combination of "address" + "family" table columns.
// NOTE: if a future resource type also exposes both columns, consider
// switching to an explicit marker (e.g. a dedicated ResponseDataKind
// interface) rather than this heuristic.
func isIPData(data []ResponseData) bool {
	if len(data) == 0 {
		return false
	}

	firstRow := data[0].TableRow()
	_, hasAddress := firstRow["address"]
	_, hasFamily := firstRow["family"]
	return hasAddress && hasFamily
}
```

Reviews (3): Last reviewed commit: "feat(cli): interactive forms, details vi..." | Re-trigger Greptile

Comment thread cli/ips.go
Comment thread cli/teams_members.go Outdated
@LanusseMorais

Copy link
Copy Markdown
Collaborator Author

@greptile review

@LanusseMorais

Copy link
Copy Markdown
Collaborator Author

@greptile review

@promptless

promptless Bot commented Jun 10, 2026

Copy link
Copy Markdown

Promptless prepared a documentation update related to this change.

Triggered by PR #86

Added a changelog entry documenting the new CLI commands: lsh teams (list/create/update), lsh teams members (list/add/remove), lsh regions list, lsh ips (list/get), and lsh operating-systems list. Highlights interactive forms with --no-input fallback, IP filtering options, and team member role management.

Review: CLI: Teams, Regions, IPs, and Operating Systems Commands

@LanusseMorais LanusseMorais merged commit cda5535 into main Jun 10, 2026
1 check passed
@LanusseMorais LanusseMorais deleted the feature/PD-6080-cli-teams-regions-ips-os branch June 10, 2026 21:16
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.

2 participants