Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use reportDiagnostics rather than throwing for known errors #5854

Merged
merged 50 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
64e9095
Use reportDiagnostics rather than throwing for known errors
JoshLove-msft Feb 4, 2025
e87e395
Fix package.json
JoshLove-msft Feb 4, 2025
847a610
format
JoshLove-msft Feb 4, 2025
49bb95f
revert package-lock
JoshLove-msft Feb 4, 2025
d5e5f73
PR fb
JoshLove-msft Feb 4, 2025
340aebc
fix emitter
JoshLove-msft Feb 4, 2025
ce95be9
fix naming in test
JoshLove-msft Feb 4, 2025
dad9965
remove test
JoshLove-msft Feb 4, 2025
0d760b0
format
JoshLove-msft Feb 4, 2025
017b90b
PR fb
JoshLove-msft Feb 4, 2025
714e8a7
Merge branch 'main' of https://github.com/microsoft/typespec into use…
JoshLove-msft Feb 4, 2025
ea20ea9
Change to afterall
JoshLove-msft Feb 6, 2025
49d702a
Merge branch 'main' of https://github.com/microsoft/typespec into use…
JoshLove-msft Feb 6, 2025
d2d607c
resolve once
JoshLove-msft Feb 6, 2025
6d8e2f8
add logging
JoshLove-msft Feb 6, 2025
11a248c
move vi.mock up
JoshLove-msft Feb 6, 2025
260612f
add more logs
JoshLove-msft Feb 7, 2025
9c016bc
explicit mock
JoshLove-msft Feb 7, 2025
d87117a
explicit mock
JoshLove-msft Feb 7, 2025
112d7e9
fix
JoshLove-msft Feb 7, 2025
938a18f
reset
JoshLove-msft Feb 7, 2025
fd515a8
Merge branch 'main' of https://github.com/microsoft/typespec into use…
JoshLove-msft Feb 7, 2025
5157aae
try custom job
timotheeguerin Feb 7, 2025
bd4cf14
Merge branch 'use-report-diags' of https://github.com/joshlove-msft/t…
timotheeguerin Feb 7, 2025
3fca3a0
fix test ci job
timotheeguerin Feb 7, 2025
65ea8c5
on run emitter tests
timotheeguerin Feb 7, 2025
2a4f51e
Fix bad merge
JoshLove-msft Feb 7, 2025
26dcac6
missing wd
timotheeguerin Feb 7, 2025
885014e
Ensure sequential
JoshLove-msft Feb 7, 2025
eafa9f0
try upgrade vitest
timotheeguerin Feb 7, 2025
4fe26e2
Merge branch 'use-report-diags' of https://github.com/joshlove-msft/t…
timotheeguerin Feb 7, 2025
8f4d02a
mockResolvedValue
JoshLove-msft Feb 9, 2025
18ef34c
restore all mocks
JoshLove-msft Feb 9, 2025
a8e8833
mock logger
JoshLove-msft Feb 9, 2025
3ee3f31
reset module
JoshLove-msft Feb 10, 2025
c605de8
add logging to execasync
JoshLove-msft Feb 10, 2025
931af67
more logs
JoshLove-msft Feb 10, 2025
dee29e9
avoid index.js import
JoshLove-msft Feb 10, 2025
5d63e6a
remove resetmodules
JoshLove-msft Feb 10, 2025
ba2e2c8
move to top
JoshLove-msft Feb 10, 2025
7716660
Use explicit exports
JoshLove-msft Feb 10, 2025
f239e29
log-level
JoshLove-msft Feb 10, 2025
5fd9e92
fix build
JoshLove-msft Feb 10, 2025
5aaeebb
log
JoshLove-msft Feb 10, 2025
5dc86ca
remove test stage
JoshLove-msft Feb 10, 2025
34f0fa3
format
JoshLove-msft Feb 10, 2025
24605fb
remove console.log
JoshLove-msft Feb 10, 2025
79bbde3
clean up params
JoshLove-msft Feb 10, 2025
ce2cf3a
use context
JoshLove-msft Feb 10, 2025
4d043d5
format
JoshLove-msft Feb 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 33 additions & 23 deletions packages/http-client-csharp/emitter/src/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

import { createSdkContext, UsageFlags } from "@azure-tools/typespec-client-generator-core";
import {
createSdkContext,
SdkContext,
UsageFlags,
} from "@azure-tools/typespec-client-generator-core";
import {
EmitContext,
getDirectoryPath,
Expand Down Expand Up @@ -30,6 +34,10 @@ import { _resolveOutputFolder, NetEmitterOptions, resolveOptions } from "./optio
import { defaultSDKContextOptions } from "./sdk-context-options.js";
import { Configuration } from "./type/configuration.js";

export interface CSharpEmitterContext extends SdkContext<NetEmitterOptions> {
logger: Logger;
}

/**
* Look for the project root by looking up until a `package.json` is found.
* @param path Path to start looking
Expand Down Expand Up @@ -61,7 +69,7 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
const outputFolder = _resolveOutputFolder(context);

/* set the loglevel. */
Logger.initialize(program, options.logLevel ?? LoggerLevel.INFO);
const logger = new Logger(program, options.logLevel ?? LoggerLevel.INFO);

if (!program.compilerOptions.noEmit && !program.hasError()) {
// Write out the dotnet model to the output path
Expand All @@ -70,7 +78,8 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
"@typespec/http-client-csharp",
defaultSDKContextOptions,
);
const root = createModel(sdkContext);
const csharpEmitterContext = { ...sdkContext, logger: logger };
const root = createModel(csharpEmitterContext);
if (
context.program.diagnostics.length > 0 &&
context.program.diagnostics.filter((digs) => digs.severity === "error").length > 0
Expand Down Expand Up @@ -113,7 +122,7 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
"src",
`${configurations["library-name"]}.csproj`,
);
Logger.getInstance().info(`Checking if ${csProjFile} exists`);
logger.info(`Checking if ${csProjFile} exists`);
const newProjectOption =
options["new-project"] || !checkFile(csProjFile) ? "--new-project" : "";
const debugFlag = (options.debug ?? false) ? "--debug" : "";
Expand All @@ -125,7 +134,7 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
);

const command = `dotnet --roll-forward Major ${generatorPath} ${outputFolder} -p ${options["plugin-name"]}${constructCommandArg(newProjectOption)}${constructCommandArg(debugFlag)}`;
Logger.getInstance().info(command);
logger.info(command);

try {
const result = await execAsync(
Expand All @@ -144,28 +153,28 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {
);
if (result.exitCode !== 0) {
const isValid = await _validateDotNetSdk(
sdkContext.program,
csharpEmitterContext,
_minSupportedDotNetSdkVersion,
);
// if the dotnet sdk is valid, the error is not dependency issue, log it as normal
if (isValid) {
if (result.stderr) Logger.getInstance().error(result.stderr);
if (result.stdout) Logger.getInstance().verbose(result.stdout);
if (result.stderr) logger.error(result.stderr);
if (result.stdout) logger.verbose(result.stdout);
throw new Error(`Failed to generate the library. Exit code: ${result.exitCode}`);
}
}
} catch (error: any) {
const isValid = await _validateDotNetSdk(
sdkContext.program,
csharpEmitterContext,
_minSupportedDotNetSdkVersion,
);
// if the dotnet sdk is valid, the error is not dependency issue, log it as normal
if (isValid) throw new Error(error);
}
if (!options["save-inputs"]) {
// delete
deleteFile(resolvePath(outputFolder, tspOutputFileName));
deleteFile(resolvePath(outputFolder, configurationFileName));
deleteFile(resolvePath(outputFolder, tspOutputFileName), logger);
deleteFile(resolvePath(outputFolder, configurationFileName), logger);
}
}
}
Expand All @@ -174,20 +183,21 @@ export async function $onEmit(context: EmitContext<NetEmitterOptions>) {

/** check the dotnet sdk installation.
* Report diagnostic if dotnet sdk is not installed or its version does not meet prerequisite
* @param program - The typespec compiler program
* @param sdkContext - The SDK context
* @param minVersionRequisite - The minimum required major version
* @param logger - The logger
* @internal
*/
export async function _validateDotNetSdk(
program: Program,
sdkContext: CSharpEmitterContext,
minMajorVersion: number,
): Promise<boolean> {
try {
const result = await execAsync("dotnet", ["--version"], { stdio: "pipe" });
return validateDotNetSdkVersion(program, result.stdout, minMajorVersion);
return validateDotNetSdkVersionCore(sdkContext, result.stdout, minMajorVersion);
} catch (error: any) {
if (error && "code" in (error as {}) && error["code"] === "ENOENT") {
reportDiagnostic(program, {
reportDiagnostic(sdkContext.program, {
code: "invalid-dotnet-sdk-dependency",
messageId: "missing",
format: {
Expand All @@ -201,8 +211,8 @@ export async function _validateDotNetSdk(
}
}

function validateDotNetSdkVersion(
program: Program,
function validateDotNetSdkVersionCore(
sdkContext: CSharpEmitterContext,
version: string,
minMajorVersion: number,
): boolean {
Expand All @@ -212,11 +222,11 @@ function validateDotNetSdkVersion(
const major = Number(firstPart);

if (isNaN(major)) {
Logger.getInstance().error("Invalid .NET SDK version.");
sdkContext.logger.error("Invalid .NET SDK version.");
return false;
}
if (major < minMajorVersion) {
reportDiagnostic(program, {
reportDiagnostic(sdkContext.program, {
code: "invalid-dotnet-sdk-dependency",
messageId: "invalidVersion",
format: {
Expand All @@ -230,7 +240,7 @@ function validateDotNetSdkVersion(
}
return true;
} else {
Logger.getInstance().error("Cannot get the installed .NET SDK version.");
sdkContext.logger.error("Cannot get the installed .NET SDK version.");
return false;
}
}
Expand Down Expand Up @@ -266,12 +276,12 @@ function transformJSONProperties(this: any, key: string, value: any): any {
return value;
}

function deleteFile(filePath: string) {
function deleteFile(filePath: string, logger: Logger) {
fs.unlink(filePath, (err) => {
if (err) {
//logger.error(`stderr: ${err}`);
logger.error(`Failed to delete files: ${err}`);
} else {
Logger.getInstance().info(`File ${filePath} is deleted.`);
logger.info(`File ${filePath} is deleted.`);
}
});
}
Expand Down
2 changes: 1 addition & 1 deletion packages/http-client-csharp/emitter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

export { configurationFileName, tspOutputFileName } from "./constants.js";
export * from "./emitter.js";
export { $onEmit } from "./emitter.js";
export { createDiagnostic, getTracer, reportDiagnostic } from "./lib/lib.js";
export { LoggerLevel } from "./lib/log-level.js";
export { Logger } from "./lib/logger.js";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import {
SdkClientType,
SdkContext,
SdkEndpointParameter,
SdkEndpointType,
SdkHttpOperation,
Expand All @@ -12,7 +11,7 @@ import {
UsageFlags,
} from "@azure-tools/typespec-client-generator-core";
import { NoTarget } from "@typespec/compiler";
import { NetEmitterOptions } from "../options.js";
import { CSharpEmitterContext } from "../emitter.js";
import { CodeModel } from "../type/code-model.js";
import { InputClient } from "../type/input-client.js";
import { InputOperationParameterKind } from "../type/input-operation-parameter-kind.js";
Expand All @@ -26,7 +25,7 @@ import { fromSdkServiceMethod, getParameterDefaultValue } from "./operation-conv
import { processServiceAuthentication } from "./service-authentication.js";
import { fromSdkType } from "./type-converter.js";

export function createModel(sdkContext: SdkContext<NetEmitterOptions>): CodeModel {
export function createModel(sdkContext: CSharpEmitterContext): CodeModel {
const sdkPackage = sdkContext.sdkPackage;

const sdkTypeMap: SdkTypeMap = {
Expand Down Expand Up @@ -66,7 +65,7 @@ export function createModel(sdkContext: SdkContext<NetEmitterOptions>): CodeMode
return clientModel;

function fromSdkClients(
sdkContext: SdkContext<NetEmitterOptions>,
sdkContext: CSharpEmitterContext,
clients: SdkClientType<SdkHttpOperation>[],
inputClients: InputClient[],
parentClientNames: string[],
Expand All @@ -84,7 +83,7 @@ export function createModel(sdkContext: SdkContext<NetEmitterOptions>): CodeMode
}

function fromSdkClient(
sdkContext: SdkContext<NetEmitterOptions>,
sdkContext: CSharpEmitterContext,
client: SdkClientType<SdkHttpOperation>,
parentNames: string[],
): InputClient {
Expand Down Expand Up @@ -158,8 +157,14 @@ export function createModel(sdkContext: SdkContext<NetEmitterOptions>): CodeMode
.replace("https://", "")
.replace("http://", "")
.split("/")[0];
if (!/^\{\w+\}$/.test(endpointExpr))
throw new Error(`Unsupported server url "${type.serverUrl}"`);
if (!/^\{\w+\}$/.test(endpointExpr)) {
reportDiagnostic(sdkContext.program, {
code: "unsupported-endpoint-url",
format: { endpoint: type.serverUrl },
target: NoTarget,
});
return [];
}
const endpointVariableName = endpointExpr.substring(1, endpointExpr.length - 1);

const parameters: InputParameter[] = [];
Expand Down Expand Up @@ -188,7 +193,11 @@ export function createModel(sdkContext: SdkContext<NetEmitterOptions>): CodeMode
SkipUrlEncoding: false,
Explode: false,
Kind: InputOperationParameterKind.Client,
DefaultValue: getParameterDefaultValue(parameter.clientDefaultValue, parameterType),
DefaultValue: getParameterDefaultValue(
sdkContext,
parameter.clientDefaultValue,
parameterType,
),
});
}
return parameters;
Expand Down
24 changes: 24 additions & 0 deletions packages/http-client-csharp/emitter/src/lib/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,30 @@ const $lib = createTypeSpecLibrary({
default: paramMessage`namespace ${"clientNamespace"} conflicts with client ${"clientName"}, please use @clientName to specify a different name for the client.`,
},
},
"unsupported-endpoint-url": {
severity: "error",
messages: {
default: paramMessage`Unsupported server endpoint URL: ${"endpoint"}`,
},
},
"unsupported-sdk-type": {
severity: "error",
messages: {
default: paramMessage`Unsupported SDK type: ${"sdkType"}.`,
},
},
"unsupported-default-value-type": {
severity: "error",
messages: {
default: paramMessage`Unsupported default value type: ${"valueType"}.`,
},
},
"unsupported-cookie-parameter": {
severity: "error",
messages: {
default: paramMessage`Cookie parameter is not supported: ${"parameterName"}, found in operation ${"path"}`,
},
},
},
emitter: {
options: NetEmitterOptionsSchema,
Expand Down
27 changes: 1 addition & 26 deletions packages/http-client-csharp/emitter/src/lib/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,17 @@ import { LoggerLevel } from "./log-level.js";
* @beta
*/
export class Logger {
private static instance: Logger;
private initialized: boolean = false;
private tracer: Tracer;
private level: LoggerLevel;
private program: Program;

private constructor(program: Program, level: LoggerLevel) {
public constructor(program: Program, level: LoggerLevel) {
this.tracer = getTracer(program);
this.level = level;
this.program = program;
}

static initialize(program: Program, level: LoggerLevel): void {
if (!Logger.instance) {
Logger.instance = new Logger(program, level);
Logger.instance.initialized = true;
}
}

static getInstance(): Logger {
if (!Logger.instance) {
throw new Error("Logger is not initialized. Call initialize() first.");
}
return Logger.instance;
}

info(message: string): void {
if (!this.initialized) {
throw new Error("Logger is not initialized. Call initialize() first.");
}
if (
this.level === LoggerLevel.INFO ||
this.level === LoggerLevel.DEBUG ||
Expand All @@ -50,18 +31,12 @@ export class Logger {
}

debug(message: string): void {
if (!this.initialized) {
throw new Error("Logger is not initialized. Call initialize() first.");
}
if (this.level === LoggerLevel.DEBUG || this.level === LoggerLevel.VERBOSE) {
this.tracer.trace(LoggerLevel.DEBUG, message);
}
}

verbose(message: string): void {
if (!this.initialized) {
throw new Error("Logger is not initialized. Call initialize() first.");
}
if (this.level === LoggerLevel.VERBOSE) {
this.tracer.trace(LoggerLevel.VERBOSE, message);
}
Expand Down
6 changes: 3 additions & 3 deletions packages/http-client-csharp/emitter/src/lib/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import {
getQueryParamName,
isStatusCode,
} from "@typespec/http";
import { CSharpEmitterContext } from "../emitter.js";
import { NetEmitterOptions } from "../options.js";
import { InputType } from "../type/input-type.js";
import { LiteralTypeContext } from "../type/literal-type-context.js";
import { SdkTypeMap } from "../type/sdk-type-map.js";
import { Logger } from "./logger.js";
import { fromSdkEnumType, fromSdkModelType, fromSdkType } from "./type-converter.js";

/**
Expand Down Expand Up @@ -72,13 +72,13 @@ export function getDefaultValue(type: Type): any {
}

export function getInputType(
context: SdkContext<NetEmitterOptions>,
context: CSharpEmitterContext,
type: Type,
typeCache: SdkTypeMap,
operation?: Operation,
literalTypeContext?: LiteralTypeContext,
): InputType {
Logger.getInstance().debug(`getInputType for kind: ${type.kind}`);
context.logger.debug(`getInputType for kind: ${type.kind}`);

const sdkType = getClientType(context, type, operation);
return fromSdkType(sdkType, context, typeCache, literalTypeContext);
Expand Down
Loading
Loading