Skip to content

Commit a4b178e

Browse files
[tsp-client] Add support for arm swagger->tsp conversion (#7881)
* add support for arm swagger->tsp * update docs * feedback
1 parent 3008573 commit a4b178e

5 files changed

Lines changed: 50 additions & 23 deletions

File tree

tools/tsp-client/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Convert an existing swagger specification to a TypeSpec project. This command sh
4545

4646
## Options
4747
```
48+
--arm Convert ARM swagger specification to TypeSpec [boolean]
4849
-c, --tsp-config The tspconfig.yaml file to use [string]
4950
--commit Commit to be used for project init or update [string]
5051
-d, --debug Enable debug logging [boolean]
@@ -55,7 +56,7 @@ Convert an existing swagger specification to a TypeSpec project. This command sh
5556
--skip-sync-and-generate Skip sync and generate during project init [boolean]
5657
--swagger-readme Path or url to swagger readme file [string]
5758
-o, --output-dir Specify an alternate output directory for the
58-
generated files. Default is your local directory. [string]
59+
generated files. Default is your current directory [string]
5960
--repo Repository where the project is defined for init
6061
or update [string]
6162
-v, --version Show version number [boolean]

tools/tsp-client/src/index.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
import { npmCommand } from "./npm.js";
1+
import { npmCommand, npxCommand } from "./npm.js";
22
import { createTempDirectory, removeDirectory, readTspLocation, getEmitterFromRepoConfig } from "./fs.js";
33
import { Logger, printBanner, enableDebug, printVersion } from "./log.js";
44
import { TspLocation, compileTsp, discoverMainFile, resolveTspConfigUrl } from "./typespec.js";
55
import { getOptions } from "./options.js";
6-
import { mkdir, writeFile, cp, readFile, access, stat } from "node:fs/promises";
6+
import { mkdir, writeFile, cp, readFile, access, stat, rename } from "node:fs/promises";
77
import { addSpecFiles, checkoutCommit, cloneRepo, getRepoRoot, sparseCheckout } from "./git.js";
88
import { doesFileExist } from "./network.js";
99
import { parse as parseYaml } from "yaml";
1010
import { joinPaths, normalizePath, resolvePath } from "@typespec/compiler";
1111
import { formatAdditionalDirectories, getAdditionalDirectoryName } from "./utils.js";
1212
import { resolve } from "node:path";
13-
import { spawn } from "node:child_process";
1413
import { config as dotenvConfig } from "dotenv";
1514

1615

@@ -240,24 +239,25 @@ async function generate({
240239
}
241240

242241

243-
async function convert(readme: string, outputDir: string): Promise<void> {
244-
return new Promise((resolve, reject) => {
245-
const autorest = spawn("npx", ["autorest", readme, "--openapi-to-typespec", "--use=@autorest/openapi-to-typespec", `--output-folder=${outputDir}`], {
246-
cwd: outputDir,
247-
stdio: "inherit",
248-
shell: true,
249-
});
250-
autorest.once("exit", (code) => {
251-
if (code === 0) {
252-
resolve();
253-
} else {
254-
reject(new Error(`openapi to typespec conversion failed exited with code ${code}`));
255-
}
256-
});
257-
autorest.once("error", (err) => {
258-
reject(new Error(`openapi to typespec conversion failed with error: ${err}`));
259-
});
260-
});
242+
async function convert(readme: string, outputDir: string, arm?: boolean): Promise<void> {
243+
const args = ["autorest", "--openapi-to-typespec", "--csharp=false", `--output-folder="${outputDir}"`, "--use=@autorest/openapi-to-typespec", `"${readme}"`];
244+
if (arm) {
245+
const generateMetadataCmd = ["autorest", "--csharp", "--max-memory-size=8192", '--use="https://aka.ms/azsdk/openapi-to-typespec-csharp"', `--output-folder="${outputDir}"`, "--mgmt-debug.only-generate-metadata", "--azure-arm", "--skip-csproj", `"${readme}"`];
246+
try {
247+
await npxCommand(outputDir, generateMetadataCmd);
248+
} catch (err) {
249+
Logger.error(`Error occurred while attempting to generate ARM metadata: ${err}`);
250+
process.exit(1);
251+
}
252+
try {
253+
await rename(joinPaths(outputDir, "metadata.json"), joinPaths(outputDir, "resources.json"));
254+
} catch (err) {
255+
Logger.error(`Error occurred while attempting to rename metadata.json to resources.json: ${err}`);
256+
process.exit(1);
257+
}
258+
args.push("--isArm");
259+
}
260+
return await npxCommand(outputDir, args);
261261
}
262262

263263

@@ -330,7 +330,7 @@ async function main() {
330330
if (await doesFileExist(readme)) {
331331
readme = normalizePath(resolve(readme));
332332
}
333-
await convert(readme, rootUrl);
333+
await convert(readme, rootUrl, options.arm);
334334
break;
335335
default:
336336
throw new Error(`Unknown command: ${options.command}`);

tools/tsp-client/src/log.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Commands:
7070
convert Convert a swagger specification to TypeSpec [string]
7171
7272
Options:
73+
--arm Convert ARM swagger specification to TypeSpec [boolean]
7374
-c, --tsp-config The tspconfig.yaml file to use [string]
7475
--commit Commit to be used for project init or update [string]
7576
-d, --debug Enable debug logging [boolean]

tools/tsp-client/src/npm.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@ export async function npmCommand(workingDir: string, args: string[]): Promise<vo
3939
});
4040
}
4141

42+
export async function npxCommand(workingDir: string, args: string[]): Promise<void> {
43+
return new Promise((resolve, reject) => {
44+
const npm = spawn("npx", args, {
45+
cwd: workingDir,
46+
stdio: "inherit",
47+
shell: true,
48+
});
49+
npm.once("exit", (code) => {
50+
if (code === 0) {
51+
resolve();
52+
} else {
53+
reject(new Error(`npx ${args[0]} failed exited with code ${code}`));
54+
}
55+
});
56+
npm.once("error", (err) => {
57+
reject(new Error(`npx ${args[0]} failed with error: ${err}`));
58+
});
59+
});
60+
}
61+
4262
let packageVersion: string;
4363
export async function getPackageVersion(): Promise<string> {
4464
if (!packageVersion) {

tools/tsp-client/src/options.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface Options {
1818
localSpecRepo?: string;
1919
emitterOptions?: string;
2020
swaggerReadme?: string;
21+
arm: boolean;
2122
}
2223

2324
export async function getOptions(): Promise<Options> {
@@ -64,6 +65,9 @@ export async function getOptions(): Promise<Options> {
6465
},
6566
["swagger-readme"]: {
6667
type: "string",
68+
},
69+
arm: {
70+
type: "boolean",
6771
}
6872
},
6973
});
@@ -165,5 +169,6 @@ export async function getOptions(): Promise<Options> {
165169
localSpecRepo: values["local-spec-repo"],
166170
emitterOptions: values["emitter-options"],
167171
swaggerReadme: values["swagger-readme"],
172+
arm: values.arm ?? false,
168173
};
169174
}

0 commit comments

Comments
 (0)