Skip to content

feat: setup uses cache by default; replace stale field mappings on re-run#29

Merged
robbiet480 merged 4 commits into
mainfrom
feat/setup-use-cache
Mar 7, 2026
Merged

feat: setup uses cache by default; replace stale field mappings on re-run#29
robbiet480 merged 4 commits into
mainfrom
feat/setup-use-cache

Conversation

@robbiet480

@robbiet480 robbiet480 commented Mar 7, 2026

Copy link
Copy Markdown
Member

Summary

  • setup now has --use-cache (default true) and --cache-dir flags. Purchase sources are read from devices.json instead of fetching all ABM devices on every run. ABM client is skipped entirely when using cache (no credentials needed for purchase source discovery).
  • MergeFieldMapping now accepts a replaceValues set — existing field_mapping entries whose ABM attribute value is in that set are removed before writing fresh ones. This prevents stale _snipeit_*_N field IDs from accumulating when setup is re-run after fields are recreated.
  • Added GetPurchaseSourcesFromCache to abmclient for reading purchase sources from devices.json.
  • Added TestMergeFieldMapping_ReplaceStaleIDs test.

Test plan

  • go test ./... passes
  • axm2snipe setup -v (with existing cache) — completes without ABM call, updates field mappings, removes old IDs
  • axm2snipe setup -v --use-cache=false — fetches from ABM as before

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Setup gains offline cache support: --use-cache and cache-dir let setup load MDM servers and purchase sources from local cache, skip remote fetching, and adjust prompts.
    • Setup can replace stale ABM-backed field mappings when instructed.
  • Bug Fixes

    • Dry-run mode now short-circuits earlier to avoid unintended operations.
  • Tests

    • Added tests covering field-mapping replacement behavior.

…-run

- Add --use-cache (default true) and --cache-dir to setup command.
  Purchase sources are read from devices.json instead of fetching all
  ABM devices. ABM client is skipped entirely when --use-cache is set.
- MergeFieldMapping now accepts replaceValues: existing entries whose
  ABM attribute value is in that set are removed before writing fresh
  ones, preventing stale field IDs from accumulating across setup runs.
- Add GetPurchaseSourcesFromCache to abmclient for cache-based lookup.
- Add TestMergeFieldMapping_ReplaceStaleIDs test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 7, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 098bd54d-ae75-45c0-8fe5-ec4aabc44084

📥 Commits

Reviewing files that changed from the base of the PR and between 448d75c and 2217c13.

📒 Files selected for processing (2)
  • abmclient/cache.go
  • abmclient/client.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • abmclient/client.go

Walkthrough

Adds cache-aware setup flow: new cache reader for purchase sources; refactors ABM purchase-source extraction into a helper; setup gains a --use-cache flag to skip ABM and load cached devices; MergeFieldMapping gains replaceValues to remove stale mappings; SetupFields short-circuits on dry-run.

Changes

Cohort / File(s) Summary
ABM client — refactor & cache reader
abmclient/client.go, abmclient/cache.go
Extracts purchase-source extraction into collectPurchaseSources(...); refactors GetAllPurchaseSources to use it. Adds GetPurchaseSourcesFromCache(cacheDir string) to read devices.json, parse devices and return deduplicated purchase sources.
Setup command — cache integration
cmd/setup.go
Adds --use-cache flag; conditionally skips ABM initialization and validation when using cache; loads MDM servers and purchase sources from cache when enabled; tracks replaceValues and passes it to MergeFieldMapping; adapts messaging and scaffolding flow.
CLI flag wiring
cmd/root.go
Includes setupCmd in the loop that registers the --cache-dir flag alongside downloadCmd and syncCmd.
Field mapping API & tests
config/config.go, config/config_test.go
Changes signature to MergeFieldMapping(path, newMappings, replaceValues); when replaceValues provided, removes existing field_mapping entries matching those ABM attribute values before merging. Tests updated and a new test added for replacement behavior.
Dry-run behavior
snipe/client.go
Adds an early return of ErrDryRun in SetupFields when client is in dry-run mode to avoid further processing.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Setup as Setup Cmd
    participant Cache as Cache Dir
    participant ABM as ABM Client
    participant Config as Config Manager

    alt use-cache flag enabled
        User->>Setup: run setup --use-cache
        Setup->>Cache: read devices.json
        Cache-->>Setup: cached device list
        Setup->>Setup: collectPurchaseSources(cached devices)
        Setup->>Config: MergeFieldMapping(..., replaceValues)
        Config-->>User: setup complete (cache)
    else use-cache flag disabled
        User->>Setup: run setup
        Setup->>ABM: init client
        ABM-->>Setup: client ready
        Setup->>ABM: fetch MDM servers & purchase sources
        ABM-->>Setup: ABM data
        Setup->>Config: MergeFieldMapping(..., nil)
        Config-->>User: setup complete (ABM)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I found a cached JSON snug and sweet,
Skipped the ABM to save a hop in feat,
I swept stale IDs with a twitchy paw,
Dry-run stops — no changes to the law,
Setup hums, burrow warm, carrot treat! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: cache-by-default behavior in setup and stale field mapping replacement on re-runs.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/setup-use-cache

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
abmclient/client.go (1)

241-269: Use filepath.Join for cross-platform path handling.

Line 244 uses string concatenation (cacheDir + "/devices.json") which may cause issues on Windows where the path separator is \. Consider using filepath.Join for portability.

♻️ Proposed fix
 import (
 	"context"
 	"encoding/json"
 	"fmt"
 	"io"
 	"os"
+	"path/filepath"
 	"time"

 ...

 func GetPurchaseSourcesFromCache(cacheDir string) ([]PurchaseSource, error) {
-	data, err := os.ReadFile(cacheDir + "/devices.json")
+	data, err := os.ReadFile(filepath.Join(cacheDir, "devices.json"))
 	if err != nil {
 		return nil, fmt.Errorf("reading devices cache: %w", err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@abmclient/client.go` around lines 241 - 269, GetPurchaseSourcesFromCache
currently builds the devices.json path with string concatenation (cacheDir +
"/devices.json") which breaks on Windows; replace that with
filepath.Join(cacheDir, "devices.json") where os.ReadFile is called and add the
"path/filepath" import to the file (or ensure it's present) so path construction
is cross-platform compatible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/setup.go`:
- Around line 127-139: SetupFields currently calls the upstream library
unconditionally and ignores the client's dry-run flag; add an early guard at the
top of SetupFields to return nil, ErrDryRun when c.DryRun is true (matching
other write helpers in snipe/client.go) so no Create/Update/Associate API calls
are executed in dry-run mode, keeping behavior consistent with supplier_mapping
and other write methods.

---

Nitpick comments:
In `@abmclient/client.go`:
- Around line 241-269: GetPurchaseSourcesFromCache currently builds the
devices.json path with string concatenation (cacheDir + "/devices.json") which
breaks on Windows; replace that with filepath.Join(cacheDir, "devices.json")
where os.ReadFile is called and add the "path/filepath" import to the file (or
ensure it's present) so path construction is cross-platform compatible.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cc79b576-82a4-405f-8550-f452dbd39c9b

📥 Commits

Reviewing files that changed from the base of the PR and between 38d54b4 and 8f25db2.

📒 Files selected for processing (5)
  • abmclient/client.go
  • cmd/root.go
  • cmd/setup.go
  • config/config.go
  • config/config_test.go

Comment thread cmd/setup.go
…ard to SetupFields

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
abmclient/client.go (1)

253-269: Extract the purchase-source collection loop into one helper.

This block now duplicates the filtering/deduplication logic in Client.GetAllPurchaseSources. Since setup can now source purchase sources from either live ABM data or devices.json, keeping the two paths separate makes it easy for future normalization fixes to land in only one branch and produce different scaffolding.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@abmclient/client.go` around lines 253 - 269, Extract the duplicated
filtering/deduplication loop into a single helper function (e.g.,
collectPurchaseSourcesFromDevices) that accepts the devices slice and returns
([]PurchaseSource, error) or ([]PurchaseSource) matching the current behavior;
replace the duplicated loop in Client.GetAllPurchaseSources and in setup to call
this helper instead of repeating the logic, ensuring it handles nil Attributes,
empty PurchaseSourceType, constructs PurchaseSource{Type:
string(d.Attributes.PurchaseSourceType), ID: d.Attributes.PurchaseSourceID}, and
deduplicates using a seen map keyed by PurchaseSource so behavior of
PurchaseSource, Client.GetAllPurchaseSources, and setup remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@abmclient/client.go`:
- Around line 253-269: Extract the duplicated filtering/deduplication loop into
a single helper function (e.g., collectPurchaseSourcesFromDevices) that accepts
the devices slice and returns ([]PurchaseSource, error) or ([]PurchaseSource)
matching the current behavior; replace the duplicated loop in
Client.GetAllPurchaseSources and in setup to call this helper instead of
repeating the logic, ensuring it handles nil Attributes, empty
PurchaseSourceType, constructs PurchaseSource{Type:
string(d.Attributes.PurchaseSourceType), ID: d.Attributes.PurchaseSourceID}, and
deduplicates using a seen map keyed by PurchaseSource so behavior of
PurchaseSource, Client.GetAllPurchaseSources, and setup remains unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9e58a1e-4a3f-4d4c-a678-1edd3fa2b524

📥 Commits

Reviewing files that changed from the base of the PR and between 8f25db2 and e86cd72.

📒 Files selected for processing (2)
  • abmclient/client.go
  • snipe/client.go

coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 7, 2026
Deduplicate the purchase source iteration logic into a shared
helper that accepts []abm.OrgDevice. GetPurchaseSourcesFromCache
unwraps []Device to []abm.OrgDevice before calling it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
abmclient/client.go (1)

246-262: Move the cache reader out of client.go.

GetPurchaseSourcesFromCache adds filesystem/JSON cache handling to the ABM client wrapper file. A small abmclient/cache.go-style home would keep client.go focused on upstream-client behavior and make the cache path easier to evolve independently.

As per coding guidelines, "Organize API client wrappers in dedicated files that wrap upstream libraries with project-specific logic (e.g., dry-run enforcement) in abmclient/client.go and snipe/client.go."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@abmclient/client.go` around lines 246 - 262, GetPurchaseSourcesFromCache
contains filesystem/JSON cache handling that should be relocated out of
client.go; create a new abmclient/cache.go in package abmclient and move the
GetPurchaseSourcesFromCache implementation there (preserving its signature and
behavior: reading devices.json, unmarshalling into []Device, converting to
[]abm.OrgDevice and calling collectPurchaseSources), update imports if needed,
and ensure any callers of GetPurchaseSourcesFromCache or references to
Device/collectPurchaseSources continue to compile; keep client.go focused on
upstream-client behavior and run tests to confirm no API/behavior changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@abmclient/client.go`:
- Around line 246-262: GetPurchaseSourcesFromCache contains filesystem/JSON
cache handling that should be relocated out of client.go; create a new
abmclient/cache.go in package abmclient and move the GetPurchaseSourcesFromCache
implementation there (preserving its signature and behavior: reading
devices.json, unmarshalling into []Device, converting to []abm.OrgDevice and
calling collectPurchaseSources), update imports if needed, and ensure any
callers of GetPurchaseSourcesFromCache or references to
Device/collectPurchaseSources continue to compile; keep client.go focused on
upstream-client behavior and run tests to confirm no API/behavior changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 283ae06b-fcad-4237-8803-b1a4a8aa1fb4

📥 Commits

Reviewing files that changed from the base of the PR and between e86cd72 and 448d75c.

📒 Files selected for processing (1)
  • abmclient/client.go

coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 7, 2026
Separate filesystem/JSON cache concerns from upstream-client behavior
by relocating GetPurchaseSourcesFromCache into a dedicated cache.go file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@robbiet480 robbiet480 merged commit 90ac6a5 into main Mar 7, 2026
2 checks passed
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