Skip to content

Commit 95e389a

Browse files
authored
Merge pull request #165 from Azure/remove-spec-format-option
Remove unimplemented --spec-format and --otel options
2 parents 18bc2be + 24d5edd commit 95e389a

12 files changed

Lines changed: 11 additions & 113 deletions

File tree

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ Extract APIM service configuration to local artifact files.
4747
| `--output <dir>` | `./apim-artifacts` | Output directory |
4848
| `--filter <path>` | | Extract only matching resources |
4949
| `--no-transitive` | | Skip transitive dependencies |
50-
| `--spec-format <format>` | | Override API spec format |
5150

5251
```bash
5352
apiops extract --help
@@ -58,12 +57,11 @@ apiops extract \
5857
--service-name <name> \
5958
--output ./apim-artifacts
6059

61-
# Extract a filtered subset of resources and override the API spec format
60+
# Extract a filtered subset of resources
6261
apiops extract \
6362
--resource-group <rg> \
6463
--service-name <name> \
65-
--filter ./filter.yaml \
66-
--spec-format openapi-v3-yaml
64+
--filter ./filter.yaml
6765

6866
# Authenticate explicitly with a service principal
6967
apiops extract \

docs/commands/extract.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ apiops extract \
6666
| `--output <dir>` | string | `./apim-artifacts` | No | Output directory path |
6767
| `--filter <path>` | string || No | Filter configuration YAML file |
6868
| `--no-transitive` | boolean | false (transitive ON) | No | Disable transitive dependency inclusion |
69-
| `--spec-format <format>` | string || No | API spec format: `openapi-v2-json`, `openapi-v3-json`, `openapi-v3-yaml` |
7069

7170
### Global flags
7271

specs/contracts/cli-commands.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ These flags are available on **all** commands (`extract`, `publish`, `init`).
1515
| `--api-version <version>` | string | no | `2024-05-01` | APIM REST API version |
1616
| `--format <mode>` | string | no | `text` | Output format: `text` (human-readable) or `json` (machine-readable) |
1717
| `--verbose` | boolean | no | `false` | Enable debug-level output |
18-
| `--otel <path>` | string | no || OpenTelemetry configuration YAML file |
1918
| `--client-id <id>` | string | no || Service principal client ID (sets `AZURE_CLIENT_ID` for DefaultAzureCredential) |
2019
| `--client-secret <secret>` | string | no || Service principal client secret (sets `AZURE_CLIENT_SECRET`) |
2120
| `--tenant-id <id>` | string | no || Azure AD tenant ID (sets `AZURE_TENANT_ID`) |
@@ -35,7 +34,6 @@ Extract APIM configuration to local artifact files.
3534
| `--output <dir>` | string | no | `./apim-artifacts` | Output directory path |
3635
| `--filter <path>` | string | no || Filter configuration YAML file |
3736
| `--no-transitive` | boolean | no | `false` | Disable transitive dependency inclusion |
38-
| `--spec-format <format>` | string | no || API specification format (`openapi-v2-json`, `openapi-v3-json`, `openapi-v3-yaml`); native format used when omitted or conversion not possible |
3937

4038
**stdout**: Per-resource status lines (one per extracted resource)
4139
**stderr**: Structured log messages (JSON when `--verbose`)
@@ -109,8 +107,6 @@ Initialize repository structure and CI/CD pipeline configuration.
109107
| `AZURE_SUBSCRIPTION_ID` | Azure subscription (fallback for `--subscription-id`) | extract, publish |
110108
| `AZURE_API_VERSION` | Override APIM REST API version (default: `2024-05-01`) | extract, publish |
111109
| `COMMIT_ID` | Git SHA for incremental publish | publish |
112-
| `OTEL_EXPORTER_OTLP_ENDPOINT` | OTel exporter endpoint (used by OTel SDK) | extract, publish |
113-
| `APPLICATIONINSIGHTS_CONNECTION_STRING` | Azure Monitor connection string | extract, publish |
114110

115111
---
116112

specs/data-model.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,7 @@ interface ExtractConfig {
150150
outputDir: string;
151151
filter?: FilterConfig;
152152
includeTransitive: boolean; // Default: true; false when --no-transitive
153-
specFormat?: string; // From --spec-format; undefined = native format
154153
verbose: boolean;
155-
otelConfigPath?: string;
156154
}
157155
```
158156

@@ -204,7 +202,6 @@ interface PublishConfig {
204202
deleteUnmatched: boolean; // Default: false; true when --delete-unmatched
205203
commitId?: string; // From COMMIT_ID env var; triggers incremental publish
206204
verbose: boolean;
207-
otelConfigPath?: string;
208205
}
209206
```
210207

specs/research.md

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ program
242242
.option('--api-version <version>', 'APIM REST API version', '2024-05-01')
243243
.option('--format <mode>', 'Output format (text|json)', 'text')
244244
.option('--verbose', 'Enable verbose output')
245-
.option('--otel <path>', 'OpenTelemetry configuration file')
246245
.option('--client-id <id>', 'Service principal client ID')
247246
.option('--client-secret <secret>', 'Service principal client secret')
248247
.option('--tenant-id <id>', 'Azure AD tenant ID')
@@ -254,7 +253,6 @@ program.command('extract')
254253
.option('--output <dir>', 'Output directory', './apim-artifacts')
255254
.option('--filter <path>', 'Filter configuration YAML file')
256255
.option('--no-transitive', 'Disable transitive dependency inclusion')
257-
.option('--spec-format <format>', 'API specification format')
258256
.action(extractAction)
259257

260258
program.command('publish')
@@ -295,25 +293,6 @@ program.command('init')
295293

296294
---
297295

298-
## R9: OpenTelemetry Integration
299-
300-
**Decision**: `@opentelemetry/sdk-node` with auto-instrumentation for HTTP; `--otel <path>` accepts standard OTel config YAML file.
301-
302-
**Rationale**:
303-
- spec requires structured logging to stderr + optional OTel export (clarification C5)
304-
- Standard OTel env vars (`OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS`) for server config
305-
- Config file can set resource attributes, exporter endpoint, and custom headers
306-
- `--otel <path>` flag consistent with `--filter <path>` and `--overrides <path>` pattern
307-
308-
**Implementation**:
309-
- When `--otel` not specified: No OTel SDK initialized, no overhead
310-
- When `--otel <path>` specified: Read YAML config, initialize `NodeSDK` with OTLP exporter
311-
- Traces: One span per resource type extraction/publish, child spans per individual resource
312-
- Metrics: Resource count, duration, error count
313-
- Azure Monitor: Users set `APPLICATIONINSIGHTS_CONNECTION_STRING` env var + use Azure Monitor OTel exporter in config
314-
315-
---
316-
317296
## R10: Testing Strategy
318297

319298
**Decision**: Vitest with three test tiers — unit, integration, contract.

specs/spec.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
- Q: What progress feedback should the tool provide during long-running operations? → A: Per-resource status lines by default (e.g., `✓ apis/orders-api`). A `--log-level debug` option adds additional diagnostic output (HTTP requests, timing, retry details) useful for debugging.
1616
- Q: How should the tool handle API revisions during extract and publish? → A: Extract all revisions, stored as sub-folders under each API. Publish recreates all revisions in the correct order (root API first, then revisions with forced revision numbers).
1717
- Q: How should the tool parallelize extraction? → A: Cross-type parallel where safe (independent resource types extracted concurrently; resources within each type also concurrent). Publish remains dependency-ordered.
18-
- Q: Should the CLI emit structured telemetry/logging? → A: Structured logging to stderr by default. An `--otel <path>` flag accepts a standard OpenTelemetry configuration YAML file to enable trace and metric export. Credentials (API keys, connection strings) live in the OTel config file or environment variables, never as CLI flags.
1918

2019
### User Story 1 — Extract APIM Configuration (Priority: P1)
2120

@@ -35,8 +34,6 @@ A platform engineer wants to capture the current state of an Azure API Managemen
3534

3635
3. **Given** the user only wants a subset of resources, **When** the user provides a filter configuration file via `--filter filter.yaml`, **Then** only the resources matching the allowlist in the configuration file are extracted, along with any resources those filtered resources transitively depend on (e.g., backends, named values, loggers referenced in policies). The user can suppress transitive inclusion with `--no-transitive`.
3736

38-
4. **Given** an APIM instance with APIs using different specification formats (OpenAPI v2/v3, GraphQL, SOAP/WSDL), **When** the user runs extract with a `--spec-format` option, **Then** API specifications are exported in the requested format where format conversion is possible, and in their native format otherwise.
39-
4037
5. **Given** an APIM instance, **When** the user runs `apiops extract --format json`, **Then** machine-readable JSON progress output is written to stdout (resource counts, file paths written) suitable for CI/CD pipeline consumption.
4138

4239
7. **Given** an APIM instance with APIs that have multiple revisions (e.g., `orders-api;rev=1`, `orders-api;rev=2`), **When** the user runs `apiops extract`, **Then** all revisions are extracted as sub-folders under the API directory, preserving revision numbers and metadata.
@@ -163,7 +160,7 @@ The development team wants the CLI to support adding new top-level commands (e.g
163160
- **FR-012**: System MUST support configuring the APIM REST API version per invocation via a CLI flag or configuration file.
164161
- **FR-024**: System MUST extract all API revisions as sub-folders under each API directory, preserving revision numbers. During publish, the tool MUST create the root API first, then apply revisions in order with forced revision numbers to prevent APIM from auto-assigning.
165162
- **FR-025**: During extraction, the system MUST parallelize across independent resource types (e.g., backends and loggers concurrently) and across resources within each type. Dependencies between types (e.g., APIs depend on version sets) MUST be respected. During publish, resource types MUST be processed in dependency order.
166-
- **FR-026**: All commands MUST emit structured log output to stderr by default (timestamps, log levels, resource context). An `--otel <path>` flag MUST accept a standard OpenTelemetry configuration YAML file to enable trace and metric export. The tool MUST pass this file to the OTel SDK (equivalent to setting `OTEL_CONFIG_FILE`). If `--otel` is not provided, no telemetry is exported. Credentials (API keys, connection strings) MUST NOT be accepted as separate CLI flags — they MUST reside in the OTel config file or environment variables.
163+
- **FR-026**: All commands MUST emit structured log output to stderr by default (timestamps, log levels, resource context).
167164
- **FR-013**: System MUST provide `--format json|text` on all commands for machine-readable output suitable for CI/CD pipeline consumption. The default format is `text` (human-readable). `--format json` writes structured JSON to stdout. This flag is independent of `--output` (extract directory) and `--source` (publish directory).
168165
- **FR-014**: System MUST handle paginated Azure REST API responses by following `nextLink` continuation tokens.
169166
- **FR-015**: System MUST implement retry logic with exponential backoff for transient HTTP failures and 429 rate-limit responses.
@@ -211,4 +208,5 @@ The development team wants the CLI to support adding new top-level commands (e.g
211208
- The tool is distributed as an npm package and/or standalone binary; distribution mechanism details are deferred to implementation planning.
212209
- APIM API secrets (named value values marked as secrets, subscription keys) are NOT extracted in plaintext — they must be handled via override configuration or key vault references.
213210
- GraphQL and SOAP/WSDL APIs are supported for extraction in their native formats; format conversion between these and OpenAPI is out of scope.
211+
- For REST APIs, specifications are extracted in OpenAPI v3 YAML only. The APIOps Toolkit's `API_SPECIFICATION_FORMAT` / `--spec-format` option (which allowed selecting `OpenAPIV2Json`, `OpenAPIV2Yaml`, `OpenAPIV3Json`, or `OpenAPIV3Yaml`) is intentionally not carried forward. This is a known breaking change from the APIOps Toolkit: users who relied on OpenAPI v2 output or JSON output will need to migrate to OpenAPI v3 YAML. SC-006 (toolkit artifact compatibility) covers directory layout, not spec format variants.
214212
- Instance-specific resources (authorization servers, OpenID Connect providers, certificates, caches, identity providers, portal configuration, content types/items, notifications, users, tenant settings) are intentionally excluded — they do not belong in environment-promotion pipelines.

specs/tasks.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@
4242
- [x] T012 Implement resource descriptor ↔ ARM URI mapping in src/lib/resource-uri.ts (builds full ARM URL from ApimServiceContext + ResourceDescriptor, including workspace prefix)
4343
- [x] T013 Implement resource descriptor ↔ artifact file path mapping in src/lib/resource-path.ts (maps descriptor to directory/file paths per data-model.md artifact conventions)
4444
- [x] T014 [P] Implement structured logger in src/lib/logger.ts (stderr output, timestamps, log levels, --verbose support per FR-023/FR-026)
45-
- [x] T015 [P] Implement YAML config loader in src/lib/config-loader.ts (parse filter YAML, override YAML, OTel config with js-yaml; validate against FilterConfig/OverrideConfig schemas)
45+
- [x] T015 [P] Implement YAML config loader in src/lib/config-loader.ts (parse filter YAML, override YAML with js-yaml; validate against FilterConfig/OverrideConfig schemas)
4646
- [x] T016 Implement Azure REST HTTP client in src/clients/apim-client.ts (implements IApimClient: DefaultAzureCredential auth, nextLink pagination, Retry-After/429 handling, exponential backoff, provisioningState polling per research.md R1)
4747
- [x] T017 Implement filesystem artifact store in src/clients/artifact-store.ts (implements IArtifactStore: read/write resource JSON, policy XML, API specs, association files, wiki markdown; UTF-8 encoding; directory creation per contracts/iartifact-store.md)
4848
- [x] T018 [P] Implement parallel execution runner in src/lib/parallel-runner.ts (p-limit based concurrency control, Promise.allSettled, configurable concurrency per research.md R8)
49-
- [x] T019 Set up Commander program entry point in src/cli/index.ts (program name, version, global options --verbose/--otel/--format/--subscription-id/--cloud, subcommand registration pattern per FR-018)
49+
- [x] T019 Set up Commander program entry point in src/cli/index.ts (program name, version, global options --verbose/--format/--subscription-id/--cloud, subcommand registration pattern per FR-018)
5050

5151
**Checkpoint**: Foundation ready — user story implementation can now begin
5252

@@ -68,7 +68,7 @@
6868
- [ ] T025 [US1] Implement transitive dependency resolver in src/services/transitive-resolver.ts (scan policies for named value refs \{\{name\}\}, backend refs set-backend-service, policy fragment refs include-fragment; scan apiInformation.json for apiVersionSetId; fixed-point expansion; --no-transitive bypass per research.md R4)
6969
- [ ] T026 [US1] Implement secret redaction in src/services/secret-redactor.ts (detect properties.secret === true on named values, replace properties.value with redaction marker per research.md R5)
7070
- [ ] T027 [US1] Implement workspace-scoped extraction in src/services/workspace-extractor.ts (list workspaces, extract workspace-scoped resources under workspaces/{name}/ using same resource-extractor with workspace context prefix per FR-010)
71-
- [ ] T028 [US1] Register extract command in src/cli/extract-command.ts (Commander subcommand with --resource-group, --service-name, --output, --filter, --no-transitive, --spec-format flags; wire to extract-service per contracts/cli-commands.md)
71+
- [ ] T028 [US1] Register extract command in src/cli/extract-command.ts (Commander subcommand with --resource-group, --service-name, --output, --filter, --no-transitive flags; wire to extract-service per contracts/cli-commands.md)
7272
- [ ] T029 [US1] Implement JSON output mode for extract in src/cli/extract-command.ts (--format json: machine-readable JSON to stdout with resource counts and file paths per FR-013)
7373

7474
**Checkpoint**: `apiops extract` works end-to-end for all 33 resource types with filtering, parallelism, and secret redaction
@@ -145,7 +145,7 @@
145145
### Implementation for User Story 5
146146

147147
- [ ] T052 [US5] Implement command auto-discovery in src/cli/index.ts (scan src/cli/*-command.ts files or use explicit registration array; new commands appear in --help automatically per FR-018/SC-007)
148-
- [ ] T053 [US5] Extract shared command infrastructure in src/cli/shared.ts (common option builders for --resource-group/--service-name/--subscription-id/--verbose/--otel; shared APIM client factory; shared artifact store factory)
148+
- [ ] T053 [US5] Extract shared command infrastructure in src/cli/shared.ts (common option builders for --resource-group/--service-name/--subscription-id/--verbose; shared APIM client factory; shared artifact store factory)
149149
- [ ] T054 [US5] Create command developer guide in src/cli/README.md (document how to add a new command: file naming, interface shape, option reuse, testing pattern)
150150

151151
**Checkpoint**: Adding a new command requires only creating one file in src/cli/
@@ -156,9 +156,7 @@
156156

157157
**Purpose**: Improvements that affect multiple user stories
158158

159-
- [ ] T055 [P] Implement OTel integration in src/lib/otel-setup.ts (load --otel config YAML, initialize NodeSDK with OTLP exporter, create spans per resource type/resource, metrics for counts/duration per research.md R9)
160159
- [ ] T056 [P] Add --api-version global flag support in src/cli/index.ts and src/clients/apim-client.ts (override default 2024-05-01 per FR-012)
161-
- [ ] T057 [P] Implement --spec-format option for extract in src/services/api-extractor.ts (request specific format from APIM export API where conversion supported; fallback to native with warning per FR-011)
162160
- [ ] T058 Run quickstart.md validation (execute each quickstart command against a test APIM instance, verify expected outputs)
163161
- [ ] T059 Add bin entry to package.json and shebang to src/cli/index.ts for global npm install (`npx apiops` / `npm install -g`)
164162

@@ -248,4 +246,4 @@ T029: JSON output mode → src/cli/extract-command.ts
248246
4. Add US3 (CI/CD) → Test in GitHub Actions pipeline
249247
5. Add US4 (Init) → Test scaffold generation in empty repo
250248
6. Add US5 (Extensibility) → Verify new command pattern
251-
7. Polish → OTel, spec-format, quickstart validation
249+
7. Polish → quickstart validation

src/cli/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ program
3232
.choices(['debug', 'info', 'warn', 'error'])
3333
.default('info'),
3434
)
35-
.option('--otel <path>', 'Path to OpenTelemetry config YAML')
3635
.option('--format <type>', 'Output format: text or json', 'text')
3736
.option('--subscription-id <id>', 'Azure subscription ID')
3837
.option('--cloud <name>', 'Sovereign cloud: public, china, usgov, germany', 'public')

src/lib/config-loader.ts

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT license.
33
/**
44
* YAML config loader with validation
5-
* Parse filter YAML, override YAML, and OTel config files
5+
* Parse filter YAML and override YAML config files
66
*/
77

88
import * as fs from 'node:fs/promises';
@@ -428,23 +428,3 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
428428
Object.prototype.toString.call(value) === '[object Object]'
429429
);
430430
}
431-
432-
/**
433-
* Load and parse an OpenTelemetry configuration YAML file.
434-
* Returns undefined if file doesn't exist.
435-
*/
436-
export async function loadOTelConfig(filePath: string): Promise<Record<string, unknown> | undefined> {
437-
try {
438-
const content = await fs.readFile(filePath, 'utf-8');
439-
const parsed = (yaml.load(content) ?? {}) as Record<string, unknown>;
440-
441-
logger.debug(`Loaded OTel config from ${filePath}`);
442-
return parsed;
443-
} catch (error) {
444-
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
445-
logger.debug(`OTel config file not found: ${filePath}`);
446-
return undefined;
447-
}
448-
throw new Error(`Failed to load OTel config from ${filePath}: ${(error as Error).message}`, { cause: error });
449-
}
450-
}

src/models/config.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export interface ExtractConfig {
1414
filter?: FilterConfig;
1515
includeTransitive: boolean;
1616
logLevel: LogLevel;
17-
otelConfigPath?: string;
1817
}
1918

2019
/**
@@ -81,7 +80,6 @@ export interface PublishConfig {
8180
deleteUnmatched: boolean;
8281
commitId?: string;
8382
logLevel: LogLevel;
84-
otelConfigPath?: string;
8583
}
8684

8785
/**

0 commit comments

Comments
 (0)