diff --git a/tools/js-sdk-release-tools/package-lock.json b/tools/js-sdk-release-tools/package-lock.json index c102ce90792..151110fd2de 100644 --- a/tools/js-sdk-release-tools/package-lock.json +++ b/tools/js-sdk-release-tools/package-lock.json @@ -14,6 +14,7 @@ "colors": "1.4.0", "command-line-args": "^5.1.1", "comment-json": "^4.1.0", + "fs-extra": "^11.2.0", "js-yaml": "^4.1.0", "parse-ts-to-ast": "^0.1.1", "semver": "^7.3.5", @@ -2088,6 +2089,19 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2465,6 +2479,17 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/lazystream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", @@ -3825,6 +3850,14 @@ "os-name": "^3.0.0" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/url-template": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz", diff --git a/tools/js-sdk-release-tools/package.json b/tools/js-sdk-release-tools/package.json index a0f6c6266bd..76703e59ea1 100644 --- a/tools/js-sdk-release-tools/package.json +++ b/tools/js-sdk-release-tools/package.json @@ -27,6 +27,7 @@ "colors": "1.4.0", "command-line-args": "^5.1.1", "comment-json": "^4.1.0", + "fs-extra": "^11.2.0", "js-yaml": "^4.1.0", "parse-ts-to-ast": "^0.1.1", "semver": "^7.3.5", diff --git a/tools/js-sdk-release-tools/src/common/utils.ts b/tools/js-sdk-release-tools/src/common/utils.ts index e9437249630..1a1851487ea 100644 --- a/tools/js-sdk-release-tools/src/common/utils.ts +++ b/tools/js-sdk-release-tools/src/common/utils.ts @@ -1,11 +1,31 @@ import shell from 'shelljs'; -import path from 'path'; +import path, { join, posix } from 'path'; import fs from 'fs'; import { SDKType } from './types' import { logger } from "../utils/logger"; import { Project, ScriptTarget, SourceFile } from 'ts-morph'; import { replaceAll } from '@ts-common/azure-js-dev-tools'; +import { readFile } from 'fs/promises'; +import { parse } from 'yaml'; + +// ./eng/common/scripts/TypeSpec-Project-Process.ps1 script forces to use emitter '@azure-tools/typespec-ts', +// so do NOT change the emitter +const emitterName = '@azure-tools/typespec-ts'; + +// TODO: remove it after we generate and use options by ourselves +const messageToTspConfigSample = + 'Please refer to https://github.com/Azure/azure-rest-api-specs/blob/main/specification/contosowidgetmanager/Contoso.WidgetManager/tspconfig.yaml for the right schema.'; + +async function loadTspConfig(typeSpecDirectory: string): Promise> { + const configPath = join(typeSpecDirectory, 'tspconfig.yaml'); + const content = await readFile(configPath, { encoding: 'utf-8' }); + const config = parse(content.toString()); + if (!config) { + throw new Error(`Failed to parse tspconfig.yaml in ${typeSpecDirectory}`); + } + return config; +} export function getClassicClientParametersPath(packageRoot: string): string { return path.join(packageRoot, 'src', 'models', 'parameters.ts'); @@ -73,4 +93,20 @@ export function tryReadNpmPackageChangelog(packageFolderPath: string): string { logger.logWarn(`Failed to read NPM package's changelog "${changelogPath}": ${(err as Error)?.stack ?? err}`); return ''; } -} \ No newline at end of file +} + +// generated path is in posix format +// e.g. sdk/mongocluster/arm-mongocluster +export async function getGeneratedPackageDirectory(typeSpecDirectory: string): Promise { + const tspConfig = await loadTspConfig(typeSpecDirectory); + const serviceDir = tspConfig.parameters?.['service-dir']?.default; + if (!serviceDir) { + throw new Error(`Misses service-dir in parameters section of tspconfig.yaml. ${messageToTspConfigSample}`); + } + const packageDir = tspConfig.options?.[emitterName]?.['package-dir']; + if (!packageDir) { + throw new Error(`Misses package-dir in ${emitterName} options of tspconfig.yaml. ${messageToTspConfigSample}`); + } + const packageDirFromRoot = posix.join(serviceDir, packageDir); + return packageDirFromRoot; +} diff --git a/tools/js-sdk-release-tools/src/llc/generateRLCInPipeline/generateRLCInPipeline.ts b/tools/js-sdk-release-tools/src/llc/generateRLCInPipeline/generateRLCInPipeline.ts index a869d4a6178..708ea0f5bc9 100644 --- a/tools/js-sdk-release-tools/src/llc/generateRLCInPipeline/generateRLCInPipeline.ts +++ b/tools/js-sdk-release-tools/src/llc/generateRLCInPipeline/generateRLCInPipeline.ts @@ -18,6 +18,8 @@ import { } from '../utils/generateSampleReadmeMd'; import { updateTypeSpecProjectYamlFile } from '../utils/updateTypeSpecProjectYamlFile'; import { getRelativePackagePath } from "../utils/utils"; +import { getGeneratedPackageDirectory } from "../../common/utils"; +import { remove } from 'fs-extra'; export async function generateRLCInPipeline(options: { sdkRepo: string; @@ -38,6 +40,10 @@ export async function generateRLCInPipeline(options: { let packagePath: string | undefined = undefined; let relativePackagePath: string | undefined = undefined; if (options.typespecProject) { + const typespecProject = path.join(options.swaggerRepo, options.typespecProject); + const generatedPackageDir = await getGeneratedPackageDirectory(typespecProject); + await remove(generatedPackageDir); + if (!options.skipGeneration) { logger.logGreen(`>>>>>>>>>>>>>>>>>>> Start: "${options.typespecProject}" >>>>>>>>>>>>>>>>>>>>>>>>>`); if(options.sdkGenerationType === "command") {