@peterhauge/apiops-cli 0.1.3-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +135 -0
- package/dist/cli/extract-command.d.ts +12 -0
- package/dist/cli/extract-command.d.ts.map +1 -0
- package/dist/cli/extract-command.js +157 -0
- package/dist/cli/extract-command.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +74 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-command.d.ts +11 -0
- package/dist/cli/init-command.d.ts.map +1 -0
- package/dist/cli/init-command.js +87 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/publish-command.d.ts +12 -0
- package/dist/cli/publish-command.d.ts.map +1 -0
- package/dist/cli/publish-command.js +159 -0
- package/dist/cli/publish-command.js.map +1 -0
- package/dist/clients/apim-client.d.ts +110 -0
- package/dist/clients/apim-client.d.ts.map +1 -0
- package/dist/clients/apim-client.js +586 -0
- package/dist/clients/apim-client.js.map +1 -0
- package/dist/clients/artifact-store.d.ts +23 -0
- package/dist/clients/artifact-store.d.ts.map +1 -0
- package/dist/clients/artifact-store.js +188 -0
- package/dist/clients/artifact-store.js.map +1 -0
- package/dist/clients/iapim-client.d.ts +52 -0
- package/dist/clients/iapim-client.d.ts.map +1 -0
- package/dist/clients/iapim-client.js +6 -0
- package/dist/clients/iapim-client.js.map +1 -0
- package/dist/clients/iartifact-store.d.ts +50 -0
- package/dist/clients/iartifact-store.d.ts.map +1 -0
- package/dist/clients/iartifact-store.js +6 -0
- package/dist/clients/iartifact-store.js.map +1 -0
- package/dist/lib/auto-generated.d.ts +27 -0
- package/dist/lib/auto-generated.d.ts.map +1 -0
- package/dist/lib/auto-generated.js +34 -0
- package/dist/lib/auto-generated.js.map +1 -0
- package/dist/lib/cloud-config.d.ts +29 -0
- package/dist/lib/cloud-config.d.ts.map +1 -0
- package/dist/lib/cloud-config.js +60 -0
- package/dist/lib/cloud-config.js.map +1 -0
- package/dist/lib/config-loader.d.ts +21 -0
- package/dist/lib/config-loader.d.ts.map +1 -0
- package/dist/lib/config-loader.js +131 -0
- package/dist/lib/config-loader.js.map +1 -0
- package/dist/lib/dependency-graph.d.ts +43 -0
- package/dist/lib/dependency-graph.d.ts.map +1 -0
- package/dist/lib/dependency-graph.js +163 -0
- package/dist/lib/dependency-graph.js.map +1 -0
- package/dist/lib/exit-codes.d.ts +27 -0
- package/dist/lib/exit-codes.d.ts.map +1 -0
- package/dist/lib/exit-codes.js +33 -0
- package/dist/lib/exit-codes.js.map +1 -0
- package/dist/lib/logger.d.ts +39 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +128 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/parallel-runner.d.ts +38 -0
- package/dist/lib/parallel-runner.d.ts.map +1 -0
- package/dist/lib/parallel-runner.js +70 -0
- package/dist/lib/parallel-runner.js.map +1 -0
- package/dist/lib/resource-path.d.ts +205 -0
- package/dist/lib/resource-path.d.ts.map +1 -0
- package/dist/lib/resource-path.js +401 -0
- package/dist/lib/resource-path.js.map +1 -0
- package/dist/lib/resource-uri.d.ts +40 -0
- package/dist/lib/resource-uri.d.ts.map +1 -0
- package/dist/lib/resource-uri.js +86 -0
- package/dist/lib/resource-uri.js.map +1 -0
- package/dist/lib/user-agent.d.ts +2 -0
- package/dist/lib/user-agent.d.ts.map +1 -0
- package/dist/lib/user-agent.js +5 -0
- package/dist/lib/user-agent.js.map +1 -0
- package/dist/models/config.d.ts +83 -0
- package/dist/models/config.d.ts.map +1 -0
- package/dist/models/config.js +6 -0
- package/dist/models/config.js.map +1 -0
- package/dist/models/resource-types.d.ts +66 -0
- package/dist/models/resource-types.d.ts.map +1 -0
- package/dist/models/resource-types.js +243 -0
- package/dist/models/resource-types.js.map +1 -0
- package/dist/models/types.d.ts +47 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +6 -0
- package/dist/models/types.js.map +1 -0
- package/dist/services/api-extractor.d.ts +36 -0
- package/dist/services/api-extractor.d.ts.map +1 -0
- package/dist/services/api-extractor.js +319 -0
- package/dist/services/api-extractor.js.map +1 -0
- package/dist/services/api-publisher.d.ts +18 -0
- package/dist/services/api-publisher.d.ts.map +1 -0
- package/dist/services/api-publisher.js +290 -0
- package/dist/services/api-publisher.js.map +1 -0
- package/dist/services/delete-unmatched-service.d.ts +17 -0
- package/dist/services/delete-unmatched-service.d.ts.map +1 -0
- package/dist/services/delete-unmatched-service.js +143 -0
- package/dist/services/delete-unmatched-service.js.map +1 -0
- package/dist/services/dry-run-reporter.d.ts +30 -0
- package/dist/services/dry-run-reporter.d.ts.map +1 -0
- package/dist/services/dry-run-reporter.js +111 -0
- package/dist/services/dry-run-reporter.js.map +1 -0
- package/dist/services/extract-service.d.ts +47 -0
- package/dist/services/extract-service.d.ts.map +1 -0
- package/dist/services/extract-service.js +374 -0
- package/dist/services/extract-service.js.map +1 -0
- package/dist/services/filter-service.d.ts +29 -0
- package/dist/services/filter-service.d.ts.map +1 -0
- package/dist/services/filter-service.js +143 -0
- package/dist/services/filter-service.js.map +1 -0
- package/dist/services/git-diff-service.d.ts +23 -0
- package/dist/services/git-diff-service.d.ts.map +1 -0
- package/dist/services/git-diff-service.js +135 -0
- package/dist/services/git-diff-service.js.map +1 -0
- package/dist/services/identity-guide-service.d.ts +11 -0
- package/dist/services/identity-guide-service.d.ts.map +1 -0
- package/dist/services/identity-guide-service.js +227 -0
- package/dist/services/identity-guide-service.js.map +1 -0
- package/dist/services/init-service.d.ts +16 -0
- package/dist/services/init-service.d.ts.map +1 -0
- package/dist/services/init-service.js +304 -0
- package/dist/services/init-service.js.map +1 -0
- package/dist/services/keyvault-checker.d.ts +58 -0
- package/dist/services/keyvault-checker.d.ts.map +1 -0
- package/dist/services/keyvault-checker.js +390 -0
- package/dist/services/keyvault-checker.js.map +1 -0
- package/dist/services/override-merger.d.ts +20 -0
- package/dist/services/override-merger.d.ts.map +1 -0
- package/dist/services/override-merger.js +102 -0
- package/dist/services/override-merger.js.map +1 -0
- package/dist/services/product-extractor.d.ts +26 -0
- package/dist/services/product-extractor.d.ts.map +1 -0
- package/dist/services/product-extractor.js +141 -0
- package/dist/services/product-extractor.js.map +1 -0
- package/dist/services/product-publisher.d.ts +15 -0
- package/dist/services/product-publisher.d.ts.map +1 -0
- package/dist/services/product-publisher.js +113 -0
- package/dist/services/product-publisher.js.map +1 -0
- package/dist/services/prompt-service.d.ts +13 -0
- package/dist/services/prompt-service.d.ts.map +1 -0
- package/dist/services/prompt-service.js +69 -0
- package/dist/services/prompt-service.js.map +1 -0
- package/dist/services/publish-service.d.ts +31 -0
- package/dist/services/publish-service.d.ts.map +1 -0
- package/dist/services/publish-service.js +445 -0
- package/dist/services/publish-service.js.map +1 -0
- package/dist/services/resource-extractor.d.ts +52 -0
- package/dist/services/resource-extractor.d.ts.map +1 -0
- package/dist/services/resource-extractor.js +168 -0
- package/dist/services/resource-extractor.js.map +1 -0
- package/dist/services/resource-publisher.d.ts +23 -0
- package/dist/services/resource-publisher.d.ts.map +1 -0
- package/dist/services/resource-publisher.js +349 -0
- package/dist/services/resource-publisher.js.map +1 -0
- package/dist/services/secret-redactor.d.ts +20 -0
- package/dist/services/secret-redactor.d.ts.map +1 -0
- package/dist/services/secret-redactor.js +45 -0
- package/dist/services/secret-redactor.js.map +1 -0
- package/dist/services/transitive-resolver.d.ts +45 -0
- package/dist/services/transitive-resolver.d.ts.map +1 -0
- package/dist/services/transitive-resolver.js +177 -0
- package/dist/services/transitive-resolver.js.map +1 -0
- package/dist/services/workspace-extractor.d.ts +34 -0
- package/dist/services/workspace-extractor.d.ts.map +1 -0
- package/dist/services/workspace-extractor.js +120 -0
- package/dist/services/workspace-extractor.js.map +1 -0
- package/dist/templates/azure-devops/extract-pipeline.d.ts +9 -0
- package/dist/templates/azure-devops/extract-pipeline.d.ts.map +1 -0
- package/dist/templates/azure-devops/extract-pipeline.js +95 -0
- package/dist/templates/azure-devops/extract-pipeline.js.map +1 -0
- package/dist/templates/azure-devops/publish-pipeline.d.ts +10 -0
- package/dist/templates/azure-devops/publish-pipeline.d.ts.map +1 -0
- package/dist/templates/azure-devops/publish-pipeline.js +100 -0
- package/dist/templates/azure-devops/publish-pipeline.js.map +1 -0
- package/dist/templates/configs/filter-config.d.ts +6 -0
- package/dist/templates/configs/filter-config.d.ts.map +1 -0
- package/dist/templates/configs/filter-config.js +51 -0
- package/dist/templates/configs/filter-config.js.map +1 -0
- package/dist/templates/configs/override-config.d.ts +6 -0
- package/dist/templates/configs/override-config.d.ts.map +1 -0
- package/dist/templates/configs/override-config.js +45 -0
- package/dist/templates/configs/override-config.js.map +1 -0
- package/dist/templates/configs/package-json.d.ts +10 -0
- package/dist/templates/configs/package-json.d.ts.map +1 -0
- package/dist/templates/configs/package-json.js +19 -0
- package/dist/templates/configs/package-json.js.map +1 -0
- package/dist/templates/copilot/identity-setup-prompt.d.ts +13 -0
- package/dist/templates/copilot/identity-setup-prompt.d.ts.map +1 -0
- package/dist/templates/copilot/identity-setup-prompt.js +279 -0
- package/dist/templates/copilot/identity-setup-prompt.js.map +1 -0
- package/dist/templates/github-actions/extract-workflow.d.ts +9 -0
- package/dist/templates/github-actions/extract-workflow.d.ts.map +1 -0
- package/dist/templates/github-actions/extract-workflow.js +126 -0
- package/dist/templates/github-actions/extract-workflow.js.map +1 -0
- package/dist/templates/github-actions/publish-workflow.d.ts +10 -0
- package/dist/templates/github-actions/publish-workflow.d.ts.map +1 -0
- package/dist/templates/github-actions/publish-workflow.js +105 -0
- package/dist/templates/github-actions/publish-workflow.js.map +1 -0
- package/package.json +65 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Microsoft Corporation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# apiops
|
|
2
|
+
|
|
3
|
+
`apiops` is a CLI tool for Azure API Management (APIM) configuration-as-code. Extract your APIM service configuration to local artifact files, publish those artifacts back to Azure, and scaffold CI/CD pipelines — all from the command line.
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **Source code** | [github.com/Azure/apiops-cli](https://github.com/Azure/apiops-cli) |
|
|
8
|
+
| **Issues** | [GitHub Issues](https://github.com/Azure/apiops-cli/issues) |
|
|
9
|
+
|
|
10
|
+
## Getting started
|
|
11
|
+
|
|
12
|
+
**Prerequisites:** An Azure subscription with an existing APIM resource, and Node.js ≥ 22.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g @peterhauge/apiops-cli
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Authentication
|
|
19
|
+
|
|
20
|
+
`apiops` uses [`@azure/identity`](https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity) `DefaultAzureCredential` for authentication:
|
|
21
|
+
|
|
22
|
+
- To use environment variables, set the following variables: `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID`
|
|
23
|
+
- To specify authentication in command, use the following flags: `--client-id`, `--client-secret`, `--tenant-id`, and `--subscription-id`
|
|
24
|
+
- **CI/CD:** A service principal with the **API Management Service Contributor** role is recommended.
|
|
25
|
+
- **Azure-hosted environments:** Managed Identity and Workload Identity are also supported.
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
### `apiops extract`
|
|
30
|
+
|
|
31
|
+
Extract APIM service configuration to local artifact files.
|
|
32
|
+
|
|
33
|
+
| Flag | Default | Description |
|
|
34
|
+
|------|---------|-------------|
|
|
35
|
+
| `--resource-group <rg>` | *(required)* | Azure resource group |
|
|
36
|
+
| `--service-name <name>` | *(required)* | APIM service name |
|
|
37
|
+
| `--output <dir>` | `./apim-artifacts` | Output directory |
|
|
38
|
+
| `--filter <path>` | | Extract only matching resources |
|
|
39
|
+
| `--no-transitive` | | Skip transitive dependencies |
|
|
40
|
+
| `--spec-format <format>` | | Override API spec format |
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
apiops extract --help
|
|
44
|
+
|
|
45
|
+
# Basic extraction to the default output directory
|
|
46
|
+
apiops extract \
|
|
47
|
+
--resource-group <rg> \
|
|
48
|
+
--service-name <name> \
|
|
49
|
+
--output ./apim-artifacts
|
|
50
|
+
|
|
51
|
+
# Extract a filtered subset of resources and override the API spec format
|
|
52
|
+
apiops extract \
|
|
53
|
+
--resource-group <rg> \
|
|
54
|
+
--service-name <name> \
|
|
55
|
+
--filter ./filter.yaml \
|
|
56
|
+
--spec-format openapi-v3-yaml
|
|
57
|
+
|
|
58
|
+
# Authenticate explicitly with a service principal
|
|
59
|
+
apiops extract \
|
|
60
|
+
--resource-group <rg> \
|
|
61
|
+
--service-name <name> \
|
|
62
|
+
--client-id $AZURE_CLIENT_ID \
|
|
63
|
+
--client-secret $AZURE_CLIENT_SECRET \
|
|
64
|
+
--tenant-id $AZURE_TENANT_ID \
|
|
65
|
+
--subscription-id $AZURE_SUBSCRIPTION_ID
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### `apiops publish`
|
|
69
|
+
|
|
70
|
+
Publish local artifact files to an Azure APIM service.
|
|
71
|
+
|
|
72
|
+
| Flag | Default | Description |
|
|
73
|
+
|------|---------|-------------|
|
|
74
|
+
| `--resource-group <rg>` | *(required)* | Azure resource group |
|
|
75
|
+
| `--service-name <name>` | *(required)* | APIM service name |
|
|
76
|
+
| `--source <dir>` | `./apim-artifacts` | Source artifacts directory |
|
|
77
|
+
| `--overrides <path>` | | Path to overrides file |
|
|
78
|
+
| `--dry-run` | | Preview changes without applying |
|
|
79
|
+
| `--delete-unmatched` | | Delete resources not in artifacts |
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
apiops publish --help
|
|
83
|
+
|
|
84
|
+
# Preview changes without applying them
|
|
85
|
+
apiops publish \
|
|
86
|
+
--resource-group <rg> \
|
|
87
|
+
--service-name <name> \
|
|
88
|
+
--dry-run
|
|
89
|
+
|
|
90
|
+
# Publish and remove resources not present in the local artifacts
|
|
91
|
+
apiops publish \
|
|
92
|
+
--resource-group <rg> \
|
|
93
|
+
--service-name <name> \
|
|
94
|
+
--delete-unmatched
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `apiops init`
|
|
98
|
+
|
|
99
|
+
Scaffold a new APIM artifacts repository with CI/CD pipelines.
|
|
100
|
+
|
|
101
|
+
| Flag | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `--cli-package <path>` | Path to a local `.tgz` tarball |
|
|
104
|
+
| `--ci <platform>` | `github-actions` or `azure-devops` |
|
|
105
|
+
| `--environments <list>` | Comma-separated environments (e.g. `dev,prod`) |
|
|
106
|
+
| `--non-interactive` | Skip all prompts |
|
|
107
|
+
| `--force` | Overwrite existing files |
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
apiops init --help
|
|
111
|
+
|
|
112
|
+
apiops init \
|
|
113
|
+
--ci github-actions \
|
|
114
|
+
--environments dev,prod
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Global options
|
|
118
|
+
|
|
119
|
+
| Option | Default | Description |
|
|
120
|
+
|--------|---------|-------------|
|
|
121
|
+
| `--subscription-id <id>` | `AZURE_SUBSCRIPTION_ID` env var | Azure subscription ID |
|
|
122
|
+
| `--cloud <name>` | `public` | `public`, `china`, `usgov`, `germany` |
|
|
123
|
+
| `--log-level <level>` | `info` | `debug`, `info`, `warn`, `error` |
|
|
124
|
+
| `--format <type>` | `text` | `text` or `json` |
|
|
125
|
+
| `--client-id <id>` | `AZURE_CLIENT_ID` env var | Service principal client ID |
|
|
126
|
+
| `--client-secret <secret>` | `AZURE_CLIENT_SECRET` env var | Service principal secret |
|
|
127
|
+
| `--tenant-id <id>` | `AZURE_TENANT_ID` env var | Azure AD tenant ID |
|
|
128
|
+
|
|
129
|
+
## Contributing
|
|
130
|
+
|
|
131
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for how to build, test, debug, and submit changes.
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T028 & T029: Extract command CLI registration
|
|
3
|
+
* Commander subcommand with --resource-group, --service-name, --output,
|
|
4
|
+
* --filter, --no-transitive, --spec-format flags.
|
|
5
|
+
* Includes --format json: machine-readable JSON output mode.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
/**
|
|
9
|
+
* Create and return the extract command for Commander.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createExtractCommand(): Command;
|
|
12
|
+
//# sourceMappingURL=extract-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-command.d.ts","sourceRoot":"","sources":["../../src/cli/extract-command.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAsB9C"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T028 & T029: Extract command CLI registration
|
|
3
|
+
* Commander subcommand with --resource-group, --service-name, --output,
|
|
4
|
+
* --filter, --no-transitive, --spec-format flags.
|
|
5
|
+
* Includes --format json: machine-readable JSON output mode.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { runExtraction } from '../services/extract-service.js';
|
|
9
|
+
import { loadFilterConfig } from '../lib/config-loader.js';
|
|
10
|
+
import { logger, parseLogLevel } from '../lib/logger.js';
|
|
11
|
+
import { ApimClient } from '../clients/apim-client.js';
|
|
12
|
+
import { ArtifactStore } from '../clients/artifact-store.js';
|
|
13
|
+
import { getCloudConfig, buildArmBaseUrl } from '../lib/cloud-config.js';
|
|
14
|
+
/**
|
|
15
|
+
* Create and return the extract command for Commander.
|
|
16
|
+
*/
|
|
17
|
+
export function createExtractCommand() {
|
|
18
|
+
const extract = new Command('extract')
|
|
19
|
+
.description('Extract APIM configuration to local artifact files')
|
|
20
|
+
.requiredOption('--resource-group <rg>', 'Azure resource group name')
|
|
21
|
+
.requiredOption('--service-name <name>', 'APIM service instance name')
|
|
22
|
+
.option('--output <dir>', 'Output directory path', './apim-artifacts')
|
|
23
|
+
.option('--filter <path>', 'Filter configuration YAML file')
|
|
24
|
+
.option('--no-transitive', 'Disable transitive dependency inclusion')
|
|
25
|
+
.option('--spec-format <format>', 'API specification format (openapi-v2-json, openapi-v3-json, openapi-v3-yaml)')
|
|
26
|
+
.action(async (options, command) => {
|
|
27
|
+
const globalOpts = command.optsWithGlobals();
|
|
28
|
+
await executeExtract(options, globalOpts);
|
|
29
|
+
});
|
|
30
|
+
return extract;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Execute the extract command.
|
|
34
|
+
*/
|
|
35
|
+
async function executeExtract(options, globalOpts) {
|
|
36
|
+
const subscriptionId = globalOpts.subscriptionId ?? process.env.AZURE_SUBSCRIPTION_ID;
|
|
37
|
+
if (!subscriptionId) {
|
|
38
|
+
logger.error('Subscription ID required: use --subscription-id or set AZURE_SUBSCRIPTION_ID');
|
|
39
|
+
process.exit(2);
|
|
40
|
+
}
|
|
41
|
+
// Build service context
|
|
42
|
+
const apiVersion = globalOpts.apiVersion ?? process.env.AZURE_API_VERSION ?? '2024-05-01';
|
|
43
|
+
const cloudName = globalOpts.cloud ?? 'public';
|
|
44
|
+
const cloudConfig = getCloudConfig(cloudName);
|
|
45
|
+
const baseUrl = buildArmBaseUrl(cloudName, subscriptionId, options.resourceGroup, options.serviceName);
|
|
46
|
+
const context = {
|
|
47
|
+
subscriptionId,
|
|
48
|
+
resourceGroup: options.resourceGroup,
|
|
49
|
+
serviceName: options.serviceName,
|
|
50
|
+
apiVersion,
|
|
51
|
+
baseUrl,
|
|
52
|
+
};
|
|
53
|
+
// Load filter config if specified
|
|
54
|
+
let filterConfig;
|
|
55
|
+
if (options.filter) {
|
|
56
|
+
filterConfig = await loadFilterConfig(options.filter);
|
|
57
|
+
if (!filterConfig) {
|
|
58
|
+
logger.error(`Filter file not found: ${options.filter}`);
|
|
59
|
+
process.exit(2);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Build extract config
|
|
63
|
+
const extractConfig = {
|
|
64
|
+
service: context,
|
|
65
|
+
outputDir: options.output,
|
|
66
|
+
filter: filterConfig,
|
|
67
|
+
includeTransitive: options.transitive,
|
|
68
|
+
specFormat: options.specFormat,
|
|
69
|
+
logLevel: parseLogLevel(globalOpts.logLevel ?? 'info'),
|
|
70
|
+
};
|
|
71
|
+
// Create client and store
|
|
72
|
+
const client = new ApimClient(cloudConfig.authScope);
|
|
73
|
+
const store = new ArtifactStore();
|
|
74
|
+
// Run extraction
|
|
75
|
+
const result = await runExtraction(client, store, extractConfig);
|
|
76
|
+
// Output results
|
|
77
|
+
if (globalOpts.format === 'json') {
|
|
78
|
+
outputJson(result);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
outputText(result);
|
|
82
|
+
}
|
|
83
|
+
process.exit(result.exitCode);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* T029: JSON output mode for extract.
|
|
87
|
+
* Machine-readable JSON to stdout with resource counts and file paths.
|
|
88
|
+
*/
|
|
89
|
+
function outputJson(result) {
|
|
90
|
+
const output = {
|
|
91
|
+
status: result.exitCode === 0 ? 'success' : result.exitCode === 1 ? 'partial' : 'error',
|
|
92
|
+
exitCode: result.exitCode,
|
|
93
|
+
summary: {
|
|
94
|
+
totalExtracted: result.totalExtracted,
|
|
95
|
+
totalErrors: result.totalErrors,
|
|
96
|
+
typeBreakdown: result.typeResults.map((tr) => ({
|
|
97
|
+
type: tr.type,
|
|
98
|
+
extracted: tr.extracted.filter((r) => r.status === 'success').length,
|
|
99
|
+
errors: tr.errorCount,
|
|
100
|
+
})),
|
|
101
|
+
},
|
|
102
|
+
resources: result.extractedDescriptors.map((d) => ({
|
|
103
|
+
type: d.type,
|
|
104
|
+
nameParts: d.nameParts,
|
|
105
|
+
workspace: d.workspace,
|
|
106
|
+
})),
|
|
107
|
+
apis: result.apiResults.map((ar) => ({
|
|
108
|
+
name: ar.apiName,
|
|
109
|
+
revisions: ar.revisions.filter((r) => r.status === 'success').length,
|
|
110
|
+
specification: ar.specification,
|
|
111
|
+
operations: ar.operations.filter((r) => r.status === 'success').length,
|
|
112
|
+
tags: ar.tags.filter((r) => r.status === 'success').length,
|
|
113
|
+
})),
|
|
114
|
+
workspaces: result.workspaceResults.map((wr) => ({
|
|
115
|
+
name: wr.workspaceName,
|
|
116
|
+
resources: wr.resourceCount,
|
|
117
|
+
errors: wr.errorCount,
|
|
118
|
+
})),
|
|
119
|
+
};
|
|
120
|
+
// JSON output goes to stdout (not stderr)
|
|
121
|
+
process.stdout.write(JSON.stringify(output, null, 2) + '\n');
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Text output mode (default) — per-resource status lines.
|
|
125
|
+
*/
|
|
126
|
+
function outputText(result) {
|
|
127
|
+
// Per-type summary
|
|
128
|
+
for (const tr of result.typeResults) {
|
|
129
|
+
const successCount = tr.extracted.filter((r) => r.status === 'success').length;
|
|
130
|
+
if (successCount > 0) {
|
|
131
|
+
process.stdout.write(`Extracted ${successCount} ${tr.type}(s)\n`);
|
|
132
|
+
}
|
|
133
|
+
if (tr.errorCount > 0) {
|
|
134
|
+
process.stdout.write(`Failed ${tr.errorCount} ${tr.type}(s)\n`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// API details
|
|
138
|
+
for (const ar of result.apiResults) {
|
|
139
|
+
const details = [];
|
|
140
|
+
if (ar.specification)
|
|
141
|
+
details.push('spec');
|
|
142
|
+
if (ar.operations.length > 0)
|
|
143
|
+
details.push(`${ar.operations.length} ops`);
|
|
144
|
+
if (ar.revisions.length > 0)
|
|
145
|
+
details.push(`${ar.revisions.length} revisions`);
|
|
146
|
+
if (details.length > 0) {
|
|
147
|
+
process.stdout.write(` API "${ar.apiName}": ${details.join(', ')}\n`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Workspace details
|
|
151
|
+
for (const wr of result.workspaceResults) {
|
|
152
|
+
process.stdout.write(`Workspace "${wr.workspaceName}": ${wr.resourceCount} resources\n`);
|
|
153
|
+
}
|
|
154
|
+
// Summary
|
|
155
|
+
process.stdout.write(`\nTotal: ${result.totalExtracted} resources extracted, ${result.totalErrors} errors\n`);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=extract-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-command.js","sourceRoot":"","sources":["../../src/cli/extract-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* T019: Commander program entry point
|
|
4
|
+
* Sets up global options and subcommand registration pattern
|
|
5
|
+
*/
|
|
6
|
+
import { Command, Option } from 'commander';
|
|
7
|
+
import { logger, parseLogLevel } from '../lib/logger.js';
|
|
8
|
+
import { createExtractCommand } from './extract-command.js';
|
|
9
|
+
import { createPublishCommand } from './publish-command.js';
|
|
10
|
+
import { createInitCommand } from './init-command.js';
|
|
11
|
+
const program = new Command();
|
|
12
|
+
// Configure program metadata
|
|
13
|
+
program
|
|
14
|
+
.name('apiops')
|
|
15
|
+
.version('0.1.0')
|
|
16
|
+
.description('CLI tool for Azure API Management configuration-as-code');
|
|
17
|
+
// Show global options in subcommand help (e.g. apiops extract --help)
|
|
18
|
+
program.configureHelp({ showGlobalOptions: true });
|
|
19
|
+
// Global options inherited by all subcommands
|
|
20
|
+
program
|
|
21
|
+
.addOption(new Option('--log-level <level>', 'Log level: debug, info, warn, or error')
|
|
22
|
+
.choices(['debug', 'info', 'warn', 'error'])
|
|
23
|
+
.default('info'))
|
|
24
|
+
.option('--otel <path>', 'Path to OpenTelemetry config YAML')
|
|
25
|
+
.option('--format <type>', 'Output format: text or json', 'text')
|
|
26
|
+
.option('--subscription-id <id>', 'Azure subscription ID')
|
|
27
|
+
.option('--cloud <name>', 'Sovereign cloud: public, china, usgov, germany', 'public')
|
|
28
|
+
.option('--client-id <id>', 'Service principal client ID')
|
|
29
|
+
.option('--client-secret <secret>', 'Service principal client secret')
|
|
30
|
+
.option('--tenant-id <id>', 'Azure AD tenant ID');
|
|
31
|
+
// Configure logger and set auth environment variables before each command
|
|
32
|
+
program.hook('preAction', (thisCommand) => {
|
|
33
|
+
const opts = thisCommand.optsWithGlobals();
|
|
34
|
+
logger.configure({ level: parseLogLevel(opts.logLevel ?? 'info') });
|
|
35
|
+
// T040: Set DefaultAzureCredential env vars from explicit auth flags.
|
|
36
|
+
// This ensures the ServicePrincipal credential is tried first,
|
|
37
|
+
// avoiding interactive browser prompts in CI/CD pipelines.
|
|
38
|
+
if (opts.clientId) {
|
|
39
|
+
process.env.AZURE_CLIENT_ID = opts.clientId;
|
|
40
|
+
}
|
|
41
|
+
if (opts.clientSecret) {
|
|
42
|
+
process.env.AZURE_CLIENT_SECRET = opts.clientSecret;
|
|
43
|
+
}
|
|
44
|
+
if (opts.tenantId) {
|
|
45
|
+
process.env.AZURE_TENANT_ID = opts.tenantId;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
// Subcommand registration section
|
|
49
|
+
program.addCommand(createExtractCommand());
|
|
50
|
+
program.addCommand(createPublishCommand());
|
|
51
|
+
program.addCommand(createInitCommand());
|
|
52
|
+
// Apply help configuration to all subcommands so global options are visible
|
|
53
|
+
program.commands.forEach((cmd) => cmd.configureHelp({ showGlobalOptions: true }));
|
|
54
|
+
// Handle unknown commands gracefully
|
|
55
|
+
program.on('command:*', (operands) => {
|
|
56
|
+
const unknownCommand = operands[0] ?? 'unknown';
|
|
57
|
+
logger.error(`Unknown command: ${unknownCommand}`);
|
|
58
|
+
logger.info('Run "apiops --help" to see available commands');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
});
|
|
61
|
+
// Parse arguments and handle errors
|
|
62
|
+
try {
|
|
63
|
+
await program.parseAsync(process.argv);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error instanceof Error) {
|
|
67
|
+
logger.error('Command failed:', error.message);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
logger.error('Command failed with unknown error');
|
|
71
|
+
}
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T050: Register init command
|
|
3
|
+
* Commander subcommand with --ci, --non-interactive, --artifact-dir, --environments flags
|
|
4
|
+
* Wire to init-service
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
/**
|
|
8
|
+
* Create and return the init command for Commander
|
|
9
|
+
*/
|
|
10
|
+
export declare function createInitCommand(): Command;
|
|
11
|
+
//# sourceMappingURL=init-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-command.d.ts","sourceRoot":"","sources":["../../src/cli/init-command.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAiF3C"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T050: Register init command
|
|
3
|
+
* Commander subcommand with --ci, --non-interactive, --artifact-dir, --environments flags
|
|
4
|
+
* Wire to init-service
|
|
5
|
+
*/
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { initService } from '../services/init-service.js';
|
|
8
|
+
import { logger } from '../lib/logger.js';
|
|
9
|
+
/**
|
|
10
|
+
* Create and return the init command for Commander
|
|
11
|
+
*/
|
|
12
|
+
export function createInitCommand() {
|
|
13
|
+
const init = new Command('init')
|
|
14
|
+
.description('Initialize APIM repository with CI/CD pipelines and configuration templates')
|
|
15
|
+
.option('--ci <provider>', 'CI/CD provider: github-actions or azure-devops')
|
|
16
|
+
.option('--non-interactive', 'Skip interactive prompts (requires --ci)', false)
|
|
17
|
+
.option('--artifact-dir <dir>', 'Artifact directory path', './apim-artifacts')
|
|
18
|
+
.option('--environments <list>', 'Comma-separated environment names', 'dev,prod')
|
|
19
|
+
.requiredOption('--cli-package <path>', 'Path to apiops npm tarball (from npm pack)')
|
|
20
|
+
.option('--force', 'Overwrite existing files without prompting', false)
|
|
21
|
+
.action(async (options) => {
|
|
22
|
+
try {
|
|
23
|
+
// Use pretty log format for init (human-facing command)
|
|
24
|
+
logger.setFormat('pretty');
|
|
25
|
+
// Validate CI provider if specified
|
|
26
|
+
if (options.ci && options.ci !== 'github-actions' && options.ci !== 'azure-devops') {
|
|
27
|
+
logger.error('Invalid CI provider. Must be "github-actions" or "azure-devops"');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
// Parse environments
|
|
31
|
+
const environments = options.environments
|
|
32
|
+
.split(',')
|
|
33
|
+
.map((env) => env.trim())
|
|
34
|
+
.filter((env) => env.length > 0);
|
|
35
|
+
if (environments.length === 0) {
|
|
36
|
+
logger.error('At least one environment must be specified');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
// Build config
|
|
40
|
+
const config = {
|
|
41
|
+
ciProvider: options.ci,
|
|
42
|
+
nonInteractive: options.nonInteractive,
|
|
43
|
+
artifactDir: options.artifactDir,
|
|
44
|
+
environments,
|
|
45
|
+
outputDir: process.cwd(),
|
|
46
|
+
cliPackage: options.cliPackage,
|
|
47
|
+
force: options.force,
|
|
48
|
+
};
|
|
49
|
+
// Run init service
|
|
50
|
+
const generatedFiles = await initService.run(config);
|
|
51
|
+
// Output file listing
|
|
52
|
+
const allFiles = [
|
|
53
|
+
...generatedFiles.pipelines,
|
|
54
|
+
...generatedFiles.configs,
|
|
55
|
+
];
|
|
56
|
+
logger.info(`\nGenerated ${allFiles.length} file(s):`);
|
|
57
|
+
allFiles.forEach((file) => logger.info(` - ${file.startsWith('./') ? file : './' + file}`));
|
|
58
|
+
logger.info(`\nCreated ${generatedFiles.directories.length} directory/directories:`);
|
|
59
|
+
generatedFiles.directories.forEach((dir) => logger.info(` - ${dir.startsWith('./') ? dir : './' + dir}`));
|
|
60
|
+
// Determine which CI provider was actually used by checking generated files
|
|
61
|
+
const isGitHub = allFiles.some((f) => f.includes('IDENTITY-SETUP-GITHUB.md'));
|
|
62
|
+
logger.info('\nNext steps:');
|
|
63
|
+
logger.info(' 1. Review and customize the generated configuration files');
|
|
64
|
+
logger.info(' 2. Commit the generated files to your repository');
|
|
65
|
+
logger.info(' 3. Set up CI/CD identity authentication:');
|
|
66
|
+
if (isGitHub) {
|
|
67
|
+
logger.info(' - Follow ./IDENTITY-SETUP-GITHUB.md for manual setup, OR');
|
|
68
|
+
logger.info(' - Open ./.github/prompts/apiops-setup-identity.prompt.md with GitHub Copilot for guided setup');
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
logger.info(' - Follow ./IDENTITY-SETUP-AZDO.md for manual setup');
|
|
72
|
+
}
|
|
73
|
+
logger.info('');
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error instanceof Error) {
|
|
77
|
+
logger.error('Init failed:', error.message);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
logger.error('Init failed with unknown error');
|
|
81
|
+
}
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return init;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=init-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-command.js","sourceRoot":"","sources":["../../src/cli/init-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T037 & T038: Publish command CLI registration
|
|
3
|
+
* Commander subcommand with --resource-group, --service-name, --source,
|
|
4
|
+
* --overrides, --dry-run, --delete-unmatched flags.
|
|
5
|
+
* Includes --format json: machine-readable JSON output mode (T038).
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
/**
|
|
9
|
+
* Create and return the publish command for Commander.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createPublishCommand(): Command;
|
|
12
|
+
//# sourceMappingURL=publish-command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish-command.d.ts","sourceRoot":"","sources":["../../src/cli/publish-command.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CA0B9C"}
|