feat: implement apiops compare command#74
Draft
EMaher wants to merge 6 commits into
Draft
Conversation
Closes #21 Adds full implementation of `apiops compare` command for comparing two Azure API Management instances via the ARM REST API. Files added: - src/lib/compare-normalizer.ts — normalization engine (string replacement, auto-ID keying, resource map building) - src/lib/compare-differ.ts — diff engine (deep JSON diff, resource map comparison, secret/credential skip) - src/services/compare-service.ts — orchestrator (hierarchical comparison: top-level, API children, product/gateway/workspace children) - src/cli/compare-command.ts — CLI registration + text/JSON output - tests/unit/lib/compare-normalizer.test.ts - tests/unit/lib/compare-differ.test.ts - tests/unit/services/compare-service.test.ts - tests/unit/cli/compare-command.test.ts Files modified: - src/models/config.ts — adds CompareConfig - src/cli/index.ts — registers compare command - specs/contracts/cli-commands.md — documents compare command - specs/tasks.md — Phase 9 with all compare tasks marked done Agent-Logs-Url: https://github.com/Azure/apiops-cli/sessions/a77d8d45-6ce6-4ca7-a7ea-9191c35edc17 Co-authored-by: EMaher <9244742+EMaher@users.noreply.github.com>
…re-service Agent-Logs-Url: https://github.com/Azure/apiops-cli/sessions/a77d8d45-6ce6-4ca7-a7ea-9191c35edc17 Co-authored-by: EMaher <9244742+EMaher@users.noreply.github.com>
…izer Previously, normalizeString built the full APIM ARM path by assembling subscriptionId + resourceGroup + serviceName with a hardcoded 'Microsoft.ApiManagement/service' provider string. Now it uses getArmPathFromBaseUrl(context.baseUrl) to extract the path component from the already-constructed base URL (built by buildArmBaseUrl in cloud-config.ts), and splitAtProviders() to derive the subscription+RG prefix. This removes the hardcoded provider type from the normalizer. Added tests for the two new exported helpers. Agent-Logs-Url: https://github.com/Azure/apiops-cli/sessions/60174382-313e-441b-b12f-562cf1f89617 Co-authored-by: EMaher <9244742+EMaher@users.noreply.github.com>
…ally exclusive in compare --subscription-id (global) is for when both APIM instances are in the same subscription. --source-subscription-id + --target-subscription-id are for the cross-subscription case. Using both groups simultaneously is now rejected with exit code 2. Extracted resolveSubscriptionIds() pure helper for testability. Added 9 unit tests covering: shared sub, env-var fallback, per-side pair, mutual-exclusion violation, single per-side flag, and missing sub ID. Updated specs/contracts/cli-commands.md with a subscription note table. Agent-Logs-Url: https://github.com/Azure/apiops-cli/sessions/7bdc7855-c1c2-4087-a9f8-a5ca471577ab Co-authored-by: EMaher <9244742+EMaher@users.noreply.github.com>
… and resource-path libs Replace hardcoded resource type lists with derivations from the same model used by extract and publish: - TOP_LEVEL_TYPES = TIER_1 + TIER_2 + non-child TIER_3 (mirrors extract-service) - getChildTypesOf(parent) uses getDependencies() from dependency-graph.ts so newly added resource types are automatically included - TYPE_OPTIONS map centralises per-type skip/exclude flags - RESOURCE_TYPE_LABEL map centralises display labels with enum-name fallback - McpServer now automatically included as an API child (was previously missing) Agent-Logs-Url: https://github.com/Azure/apiops-cli/sessions/685cf23c-6c2a-4672-b8f8-8f7331c04b88 Co-authored-by: EMaher <9244742+EMaher@users.noreply.github.com>
… no emojis
- Remove --subscription-id from global CLI options; add it as a
per-command required option (with AZURE_SUBSCRIPTION_ID env var
support) to extract and publish commands
- Make --source-subscription-id and --target-subscription-id required
options on compare (no global subscription-id fallback)
- Remove resolveSubscriptionIds() helper (no longer needed)
- Add --format text|table|json to compare command; table shows
Resource / Status / Notes columns per resource; json mirrors the
same row structure
- Remove all emojis from compare text output
- Add status field ('missing' | 'extra' | 'different') to ResourceDiff
to make categorization explicit
- Update spec doc, all affected tests
Agent-Logs-Url: https://github.com/Azure/apiops-cli/sessions/5742ddd2-d902-42cb-bc38-c94c3ffe182d
Co-authored-by: EMaher <9244742+EMaher@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
apiops compare— a new subcommand that compares two APIM instances via the ARM REST API and reports resource-level differences. Designed for deployment verification and environment drift investigation.Normalization logic is ported from
tests/integration/all-resource-types/Compare-ApimInstance.ps1.New modules
src/lib/compare-normalizer.ts— Strips ARM envelope fields, read-only/timestamp properties, and replaces instance-specific values with stable placeholders before comparison:{{sub}},{{rg}},{{apim-name}}{{auto-id}}/{{guid}}{{auto-id-0}},{{auto-id-1}}, … for stable cross-instance matchingcontext.baseUrl(viagetArmPathFromBaseUrl/splitAtProviders) — no hardcoded provider type stringssrc/lib/compare-differ.ts— Deep recursive JSON diff with dot-notation paths; skips.properties.valueon secret named values and.properties.credentialson EventHub/AppInsights loggers. EachResourceDiffcarries an explicitstatusfield (missing|extra|different) for structured output.src/services/compare-service.ts— Hierarchical orchestrator using the same dependency graph and resource-path libraries as extract and publish:TIER_1_RESOURCES,TIER_2_RESOURCES, and non-childTIER_3_RESOURCES(viaisChildType()) — same pattern asextract-service.tsgetDependencies()viagetChildTypesOf()— new resource types added to the dependency graph are automatically includedTYPE_OPTIONSmapecho-api,administrators/developers/guests,starter/unlimited,mastersrc/cli/compare-command.ts— Commander subcommand with--format text|table|jsonoutput modes and plain-text (emoji-free) console output:text(default): per-type summary with field-level diff detailstable: ASCII table with Resource (by resource ID), Status (missing,extra,different,skipped), and Notes columnsjson: same row structure astable, machine-readableCLI interface
All six resource-identity flags are required.
--source-subscription-idand--target-subscription-idare independent — use them when the instances are in different subscriptions or the same one.Exit codes:
0= identical,1= differences found,2= fatal errorSupporting changes
src/cli/index.ts—--subscription-idremoved from global options; it is now a per-command required option onextractandpublish(withAZURE_SUBSCRIPTION_IDenv var fallback)src/cli/extract-command.ts/src/cli/publish-command.ts—--subscription-idadded as a mandatory per-command optionsrc/models/config.ts— addsCompareConfigspecs/contracts/cli-commands.md— updated global options table, extract/publish option tables, and compare command documentationspecs/tasks.md— Phase 9 added with all compare tasks