Skip to content

fix(platform): add --device-type flag to platform-device-groups name lookup#210

Merged
neilmartin83 merged 3 commits into
mainfrom
fix/pdg-device-type-flag
May 15, 2026
Merged

fix(platform): add --device-type flag to platform-device-groups name lookup#210
neilmartin83 merged 3 commits into
mainfrom
fix/pdg-device-type-flag

Conversation

@neilmartin83
Copy link
Copy Markdown
Member

@neilmartin83 neilmartin83 commented May 15, 2026

Summary

  • Adds --device-type COMPUTER|MOBILE flag (case-insensitive) to all --name-based platform-device-groups operations: get, delete, patch, members, patch-members, add-members, remove-members
  • apply auto-derives device type from the input JSON's deviceType field — no extra flag needed
  • ResolveIDByNameFiltered added to internal/platform for narrowed name walks with an RSQL filter expression
  • ResolveIDByName now errors on ambiguous matches (two items with the same name on the same page) instead of silently returning the first result
  • Bundles unrelated go fix modernisations: range-over-int, strings.SplitSeq, scope JSON tag

Fixes #209

Test plan

  • go test ./... passes
  • get --name "X" --device-type mobile returns the MOBILE group (live, platform-nmartin)
  • get --name "X" --device-type COMPUTER — not-found when no COMPUTER group by that name (live, platform-nmartin)
  • get --name "X" --device-type computer (lowercase) normalises to COMPUTER and works (live)
  • --device-type invalid returns a clear validation error (live)
  • get --name "X" when COMPUTER and MOBILE group share name → ambiguous error (unit-tested only; no duplicate-name groups in test tenant)
  • apply with "deviceType": "COMPUTER" in input JSON resolves against COMPUTER groups only

🤖 Generated with Claude Code

neilmartin83 and others added 2 commits May 15, 2026 15:08
…me lookup

When a COMPUTER and MOBILE group share the same name, `get --name` (and
all other --name-based ops) previously silently returned the wrong group.

- Override generated get/delete/patch/members/patch-members with handwritten
  versions that accept --device-type COMPUTER|MOBILE (case-insensitive)
- apply auto-derives device type from input JSON's deviceType field
- add-members / remove-members gain --device-type
- ResolveIDByNameFiltered added to internal/platform for filtered name walks
- ResolveIDByName now errors on ambiguous matches (same name twice per page)

Fixes #209

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@ktn-jamf ktn-jamf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Verdict: Needs minor changes. The core fix is correct and addresses #209, CI passes, and tests cover the new ambiguity behavior. Four cleanup items worth addressing before merge — none block, but one ships a misleading error to consumers of a shared helper.

Risk: medium / single-module — bug fix for platform-device-groups name resolution. One file accounts for ~300 lines of new CLI code; the resolver helper change is the load-bearing piece.


Findings

⚠️ (1) (correctness/usability) — Ambiguity error in the shared resolver hints at a flag that doesn't exist for most callers.

firstMatch in internal/platform/resolve_generic.go returns:

```
ambiguous match: %d items named %q; use a positional ID or add --type to narrow
```

Two problems:

  • The actual flag is `--device-type`, not `--type`. Anyone hitting this on a `platform-device-groups` command will hunt for `--type` and find nothing.
  • `ResolveIDByName` is shared by `baselines`, `benchmark-reports`, `device-actions`, `device-reports`, and `device-groups` (8+ callers in generated commands). Most of those resources have no `--device-type` flag at all — so the hint is wrong everywhere except this PR's commands.

A generic resolver should not name caller-specific flags in its errors. Either drop the flag suggestion ("disambiguate by passing the positional ID") or thread an optional `hint string` parameter into `ResolveIDByNameFiltered` so each caller supplies its own narrowing flag.

Suggested fix: change the message to e.g. `ambiguous match: %d items named %q; pass the positional ID instead, or narrow the list before resolution`, or thread a hint string from the caller.

Acceptance: error message no longer references `--type`, and `platform-device-groups get --name "X"` produces guidance that matches its actual flags.


⚠️ (2) (code quality) — Dead-code import guards at the bottom of `pro_platform_device_groups.go`.

```go
// guards against unused-import errors
var (
_ = strings.Replace
_ = strconv.Itoa
)
```

  • `strconv` isn't used anywhere else in the file. Remove the import and the dummy reference.
  • `strings.ToUpper` (used in `normalizeDeviceTypeFlag`) already keeps the `strings` import alive, so `_ = strings.Replace` is redundant.

Reads like cruft from a refactor that removed callers without removing the imports. It will also confuse anyone grepping for `strings.Replace` usage in this package.

Suggested fix: delete the `var (...)` block and remove `"strconv"` from the import list.

Acceptance: file compiles with no `_ = ...` placeholders and `strconv` not imported.


⚠️ (3) (consistency) — `patch` and `patch-members` scaffolds bypass the project's scaffold helper.

The handwritten `apply` command uses `printScaffold(deviceGroupScaffold())`. The new `newPDGPatchCmd` and `newPDGPatchMembersCmd` instead hardcode:

```go
fmt.Println("{\n \"criteria\": [],\n \"description\": \"\",\n \"name\": \"\"\n}")
```

`printScaffold` exists in `pro_platform_helpers.go` precisely so scaffold output flows through `cliCtx.Output` and honours `--no-color`, `--out-file`, etc. `fmt.Println` skips all of that.

Suggested fix: define scaffold structs (or `map[string]any`) for patch and patch-members and route them through `printScaffold`.

Acceptance: `pdg patch --scaffold --out-file foo.json` writes to `foo.json`, and global output flags are respected.


💡 (4) (simplification) — Five new commands repeat the same ~15-line name-or-ID resolution and path-building block.

`newPDGGetCmd`, `newPDGDeleteCmd`, `newPDGPatchCmd`, `newPDGMembersCmd`, `newPDGPatchMembersCmd` each contain:

```go
dt, err := normalizeDeviceTypeFlag(deviceTypeFlag)
if err != nil { return err }
var resolvedID string
if nameFlag != "" {
id, err := pdgResolveID(...)
...
} else if len(args) == 1 {
resolvedID = args[0]
} else {
return fmt.Errorf("provide a positional ID or --name")
}
path := "/api/device-groups/v1/tenant/" + url.PathEscape(...) + "/device-groups/" + url.PathEscape(resolvedID)
```

~75 lines of duplicate logic. A `resolvePDGTarget(ctx, cliCtx, args, nameFlag, deviceTypeFlag)` helper plus a `pdgItemPath(c, id)` helper would collapse each command body to its API-method-specific lines. Not blocking — worth doing while the file is small enough to refactor cheaply.

Suggested fix: extract `resolvePDGTarget` and `pdgItemPath` helpers; each command becomes `id, err := resolvePDGTarget(...)` + the unique HTTP call.

Acceptance: no per-command repetition of the name/positional/path-build pattern.


This covers all findings — addressing the above gets this PR to merge-ready.

- Fix ambiguous-match error to not reference --type (shared helper used
  by resources without that flag); now says "pass the positional ID"
- Remove strconv import and dead _ = ... import guards left from refactor
- Route patch/patch-members --scaffold through printScaffold so --out-file
  and -o flags are honoured
- Extract resolvePDGTarget + pdgItemPath helpers; collapse repeated
  ~15-line name/positional/path-build block in all 5 commands

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@neilmartin83
Copy link
Copy Markdown
Member Author

All four findings addressed in f0dd80a:

  1. Ambiguous-match error no longer references --type — generic message now
  2. Dead strconv import and _ = ... guards removed
  3. patch/patch-members --scaffold routes through printScaffold — honours --out-file and -o
  4. Extracted resolvePDGTarget + pdgItemPath helpers — repeated block gone from all 5 commands

@ktn-jamf ktn-jamf self-requested a review May 15, 2026 15:40
@neilmartin83 neilmartin83 merged commit 60c3f82 into main May 15, 2026
1 check passed
@neilmartin83 neilmartin83 deleted the fix/pdg-device-type-flag branch May 15, 2026 15:40
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.

Handling platform-device-groups when the same name exists for a Computer and Mobile group

2 participants