Skip to content

Commit

Permalink
Refactor the sample generation into rlc-common & Generate samples wit…
Browse files Browse the repository at this point in the history
…h mock content (#2002)

* Refactor the sample generation into rlc-common

* update the reference

* Build a generated fake content method

* update linter issue

* Update the js suffixes

* update the config

* adjust the position

* refresh with generatesample=true

* build the generation framework

* Can moke primitive data

* update the cases

* Update the samples in anomaly detector

* Support more types for sample type

* Update all samples in smoke testing

* update the sample codes

* Fix union bugs

* Update the normalization bug

* Remove debugging info

* temp

* update autorest samples for rlc

* Update the sample gen in autorest rlc

* Update the sample generation

* Fix union issues

* Fix the fixed enum issues

* Update the samples

* Update the samples

* Update the sample gen logic for smoke test

* Fix boolean issue

* Update the path

* Update the config to remove multi client settings

* Update the media types rlc samples

* Update the inherientance cases

* Update the test cases

* Update the smoke testings

* Update the samples in autorest side

* remove the debug tag

* Update the samples

* Disable some sample testing in integration testing

* Disable sample gen in smoke testing

* Update the smoke files

* Update the csv info

* Refactor the code for building import simpler

* Update to operation type

* Fix the key issues

* Regenerate the samples

* Refactor sample codes

* Update the test cases for type utils

* Update the test cases for typeUtil.ts

* Fix lint issue in rlc-common

* Add more test cases

* Regenerate the samples

* Update the UT for getSchemaFromType

* Revert format property

* Update the mock UT from typespec

* Update our UTs

* UPdate changes

* Update the samples

* Fix linter issues

* Fix extensible enum case

* Refresh the extensible enum value

* Refresh with fixes

* Update the UT for unions

* Refactor code to getallparents to getallproperties

* Fix the inheritance case issue

* Move generation logic to transform layer

* Update the ut issues

* Refactor the code

* Update the comments

* Update the generations

* Update the sample in swagger

* Update the file name

* Remove duplicated lisence header in sampleTemplate

* Update the csv info in swagger way

* Refresh the generation

* update the lisence header

* Generate the code again

* Regenerate the samples

* Update the sample in autorest smoke

* Update the more extension in eslint

* update ut

* update more ut in rlc-common

* remove the type info

* Update the ut

* Resolve comments
  • Loading branch information
MaryGao authored Oct 17, 2023
1 parent dcaaee9 commit a1b5026
Show file tree
Hide file tree
Showing 320 changed files with 7,171 additions and 959 deletions.
22 changes: 20 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@
"${workspaceFolder}/packages/*/dist-dev/**/*.js"
]
},
{
"name": "[Autorest] Run Debug Integration Test",
"request": "launch",
"cwd": "${workspaceFolder}/packages/autorest.typescript",
"runtimeArgs": [
"ts-node",
"./test/commands/test-swagger-gen.ts",
"--",
"rlc"
],
"runtimeExecutable": "npx",
"skipFiles": ["<node_internals>/**"],
"type": "pwa-node",
"outFiles": [
"${workspaceFolder}/packages/*/dist/**/*.js",
"${workspaceFolder}/packages/*/dist-dev/**/*.js"
]
},
{
"type": "node",
"request": "launch",
Expand Down Expand Up @@ -94,7 +112,7 @@
{
"name": "[TypeSpec] Smoke Test Debug",
"request": "launch",
"cwd": "${workspaceFolder}/packages/typespec-test/test/openai_modular",
"cwd": "${workspaceFolder}/packages/typespec-test/test/customWrapper",
"runtimeArgs": ["tsp", "compile", "./spec"],
"runtimeExecutable": "npx",
"skipFiles": ["<node_internals>/**"],
Expand All @@ -108,7 +126,7 @@
"runtimeArgs": [
"ts-node",
"./test/commands/gen-cadl-ranch.ts",
"--tag=modular",
"--tag=rlc",
"--debug"
],
"runtimeExecutable": "npx",
Expand Down
13 changes: 13 additions & 0 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,86 +2,69 @@ import {
ExampleParameter,
TestCodeModel
} from "@autorest/testmodeler/dist/src/core/model";
import { Project } from "ts-morph";
import { getAutorestOptions, getSession } from "../../autorestSession";
import * as fs from "fs";
import * as path from "path";
import * as hbs from "handlebars";
import { NameType, normalizeName } from "../../utils/nameUtils";
import { getLanguageMetadata } from "../../utils/languageHelpers";
import { transformBaseUrl } from "../../transforms/urlTransforms";
import {
RLCSampleDetail,
RLCSampleGroup,
SampleParameter,
SampleParameters,
TestSampleParameters,
OperationMethod
} from "../../restLevelClient/interfaces";
import { camelCase } from "@azure-tools/codegen";
import { Operation, ParameterLocation } from "@autorest/codemodel";
import { isLongRunningOperation } from "../../restLevelClient/helpers/hasPollingOperations";
import { isPagingOperation } from "../../utils/extractPaginationDetails";
import { getSecurityInfoFromModel } from "../../utils/schemaHelpers";
import { getParameterAssignment } from "../../utils/valueHelpers";
import { Paths, PathMetadata } from "@azure-tools/rlc-common";
import {
Paths,
PathMetadata,
RLCSampleGroup,
RLCSampleDetail,
SampleParameter,
SampleParameters,
OperationMethod,
SampleParameterPosition,
transformSampleGroups as transformSampleGroupsFromMockValue,
RLCModel
} from "@azure-tools/rlc-common";
import { transformPaths } from "../../restLevelClient/transforms/transformPaths";

const tokenCredentialPackage = "@azure/identity";
const apiKeyCredentialPackage = "@azure/core-auth";

export let hasRLCSamplesGenerated = false;
export function transformRLCSampleData(
model: TestCodeModel,
rlcModel: RLCModel
): RLCSampleGroup[] | undefined {
// We prefer to generate sample from swagger examples first
const sampleGroups = transformSampleGroupsFromSwaggerExamples(model);
if (sampleGroups && sampleGroups.length > 0) {
return sampleGroups;
}
const { generateSample, generateMetadata } = getAutorestOptions();
// If no swagger examples, we will generate mock sample
// Allow to generate mock sample when generateSample and generateMetadata are both true
const allowMockValue = generateSample === true && generateMetadata === true;
return transformSampleGroupsFromMockValue(rlcModel, allowMockValue);
}

export function generateRLCSamples(model: TestCodeModel, project: Project) {
function transformSampleGroupsFromSwaggerExamples(
model: TestCodeModel
): RLCSampleGroup[] | undefined {
const { generateSample, multiClient } = getAutorestOptions();
const session = getSession();
if (!generateSample || !model?.testModel?.mockTest?.exampleGroups) {
return;
}
const session = getSession();
// Currently only support single client
if (multiClient) {
session.info(
"Not support to generate samples for multi-clients and return directly"
);
return;
}
const sampleGroups: RLCSampleGroup[] = transformRLCSampleData(model);
if (sampleGroups.length > 0) {
hasRLCSamplesGenerated = true;
}
for (const sampleGroup of sampleGroups) {
try {
const file = fs.readFileSync(path.join(__dirname, "rlcSamples.ts.hbs"), {
encoding: "utf-8"
});
const sampleGroupFileContents = hbs.compile(file, { noEscape: true });
project.createSourceFile(
`samples-dev/${sampleGroup.filename}.ts`,
sampleGroupFileContents(sampleGroup),
{
overwrite: true
}
);
} catch (error) {
session.error(
"An error was encountered while handling sample generation",
[sampleGroup.filename]
);
session.error(
"Stop generating samples and please inform the developers of codegen the detailed errors",
[]
);
}
}
}

export function transformRLCSampleData(model: TestCodeModel): RLCSampleGroup[] {
const rlcSampleGroups: RLCSampleGroup[] = [];
if (!model?.testModel?.mockTest?.exampleGroups) {
return rlcSampleGroups;
}
// Get all paths
const session = getSession();
const paths: Paths = transformPaths(model);
const clientName = getLanguageMetadata(model.language).name;
const clientInterfaceName = clientName.endsWith("Client")
Expand Down Expand Up @@ -134,7 +117,10 @@ export function transformRLCSampleData(model: TestCodeModel): RLCSampleGroup[] {
useLegacyLro: false
};
// convert the parameters to the intermidate model - SampleParameters
const rawParamters: TestSampleParameters = {
const rawParamters: Record<
SampleParameterPosition,
ExampleParameter[]
> = {
client: rawSample.clientParameters,
path: (rawSample.methodParameters || []).filter(isPathLevelParam),
method: (rawSample.methodParameters || []).filter(isMethodLevelParam)
Expand All @@ -149,8 +135,7 @@ export function transformRLCSampleData(model: TestCodeModel): RLCSampleGroup[] {
path: convertPathLevelParameters(rawParamters.path, pathDetail, path),
method: convertMethodLevelParameters(
rawParamters.method,
pathDetail.methods[method],
importedDict
pathDetail.methods[method]
)
};
// enrich parameter details
Expand Down Expand Up @@ -310,8 +295,7 @@ function convertPathLevelParameters(

function convertMethodLevelParameters(
rawMethodParams: ExampleParameter[],
methods: OperationMethod[],
importedDict: Record<string, Set<string>>
methods: OperationMethod[]
): SampleParameter[] {
if (!methods || methods.length == 0) {
return [];
Expand Down Expand Up @@ -369,9 +353,9 @@ function convertMethodLevelParameters(
}
const optionParam: SampleParameter = {
name: "options",
assignment: `const options: ${method.optionsName} =` + value + `;`
assignment: `const options =` + value + `;`,
value
};
addValueInImportedDict(getPackageName(), method.optionsName, importedDict);
return [optionParam];
}

Expand All @@ -383,8 +367,8 @@ function enrichParameterInSample(
sample.clientParamNames = getContactParameterNames(parameters.client);
sample.pathParamAssignments = getAssignmentStrArray(parameters.path);
sample.pathParamNames = getContactParameterNames(parameters.path);
sample.methodParamAssignments = getAssignmentStrArray(parameters.method);
sample.methodParamNames = parameters.method.length > 0 ? "options" : "";
sample.methodParamNames =
parameters.method.length > 0 ? parameters.method[0].value ?? "" : "";
}

function getAssignmentStrArray(parameters: SampleParameter[]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ import { prettierJSONOptions, prettierTypeScriptOptions } from "./config";
import * as path from "path";
import * as fsextra from "fs-extra";
import { generateSampleEnv } from "../generators/samples/sampleEnvGenerator";
import {
generateRLCSamples,
hasRLCSamplesGenerated
} from "../generators/samples/rlcSampleGenerator";
import { transform } from "./transforms/transform";
import {
buildApiExtractorConfig,
Expand All @@ -36,7 +32,8 @@ import {
buildLicenseFile,
buildReadmeFile,
buildSerializeHelper,
buildLogger
buildLogger,
buildSamples
} from "@azure-tools/rlc-common";
import {
generateFileByBuilder,
Expand All @@ -53,7 +50,6 @@ export async function generateRestLevelClient() {
const {
outputPath,
srcPath,
generateSample,
generateTest,
generateMetadata
} = getAutorestOptions();
Expand All @@ -70,6 +66,7 @@ export async function generateRestLevelClient() {

// then transform CodeModel to RLCModel
const rlcModels = transform(model);
const hasSampleGenerated = (rlcModels.sampleGroups ?? []).length > 0;

if (generateMetadata) {
// buildReadmeFile
Expand Down Expand Up @@ -118,31 +115,18 @@ export async function generateRestLevelClient() {
generateFileByBuilder(project, buildSerializeHelper, rlcModels);
generateFileByBuilder(project, buildLogger, rlcModels);
generateTopLevelIndexFile(rlcModels, project);
if (generateSample && generateMetadata) {
generateRLCSamples(model, project);
if (hasSampleGenerated && generateMetadata) {
generateFileByBuilder(project, buildSamples, rlcModels);
}
if (
((generateSample && hasRLCSamplesGenerated) || generateTest) &&
generateMetadata
) {
if ((hasSampleGenerated || generateTest) && generateMetadata) {
generateSampleEnv(project);
}

if (generateMetadata) {
// buildPackageFile
generateFileByBuilder(
project,
buildPackageFile,
rlcModels,
hasRLCSamplesGenerated
);
generateFileByBuilder(project, buildPackageFile, rlcModels);
// buildTsConfig
generateFileByBuilder(
project,
buildTsConfig,
rlcModels,
hasRLCSamplesGenerated
);
generateFileByBuilder(project, buildTsConfig, rlcModels);
}

// Save the source files to the virtual filesystem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,13 @@ import { buildSchemaTypes } from "@azure-tools/rlc-common";
export function generateFileByBuilder(
project: Project,
buildFnOrList: ContentBuilder | ContentBuilder[],
rlcModels: RLCModel,
hasSampleGenerated?: boolean
rlcModels: RLCModel
) {
if (!Array.isArray(buildFnOrList)) {
buildFnOrList = [buildFnOrList];
}
for (const buildFn of buildFnOrList) {
const preparedFile: RLCFile | undefined = buildFn(
rlcModels,
hasSampleGenerated
);
generateFile(preparedFile, project);
generateFile(buildFn(rlcModels), project);
}
}

Expand All @@ -30,8 +25,17 @@ export function generateSchemaTypes(project: Project, rlcModels: RLCModel) {
generateFile(outputModelFile, project);
}

function generateFile(file: RLCFile | undefined, project: Project) {
if (file) {
function generateFile(
files: RLCFile[] | RLCFile | undefined,
project: Project
) {
if (!files) {
return;
}
if (!Array.isArray(files)) {
files = [files];
}
for (const file of files) {
project.createSourceFile(file.path, file.content, {
overwrite: true
});
Expand Down
Loading

0 comments on commit a1b5026

Please sign in to comment.