diff --git a/.js/branch.txt b/.js/branch.txt new file mode 100644 index 000000000000..8de1c3245328 --- /dev/null +++ b/.js/branch.txt @@ -0,0 +1 @@ +origin/wanl/fix-migration-sdk-type-detection diff --git a/eng/tools/typespec-validation/package.json b/eng/tools/typespec-validation/package.json index c4cdbafaa805..b8fcfa146932 100644 --- a/eng/tools/typespec-validation/package.json +++ b/eng/tools/typespec-validation/package.json @@ -10,13 +10,16 @@ "globby": "^14.0.1", "simple-git": "^3.24.0", "suppressions": "file:../suppressions", - "yaml": "^2.4.2" + "yaml": "^2.4.2", + "ajv": "^8.17.1", + "yaml-eslint-parser": "^1.2.3" }, "devDependencies": { "@types/node": "^18.19.31", "@vitest/coverage-v8": "^3.0.2", "typescript": "~5.6.2", - "vitest": "^3.0.2" + "vitest": "^3.0.2", + "eslint": "^9.17.0" }, "scripts": { "build": "tsc --build", diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/config/config-schema.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/config/config-schema.ts new file mode 100644 index 000000000000..e92b473ebf20 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/config/config-schema.ts @@ -0,0 +1,117 @@ +// Copied from https://github.com/microsoft/typespec/blob/main/packages/compiler/src/config/config-schema.ts + +import type { JSONSchemaType } from "ajv"; +import { EmitterOptions, TypeSpecRawConfig } from "./types.js"; + +export const emitterOptionsSchema: JSONSchemaType = { + type: "object", + additionalProperties: true, + required: [], + properties: { + "emitter-output-dir": { type: "string", nullable: true } as any, + }, +}; + +export const TypeSpecConfigJsonSchema: JSONSchemaType = { + type: "object", + additionalProperties: false, + properties: { + extends: { + type: "string", + nullable: true, + }, + "environment-variables": { + type: "object", + nullable: true, + required: [], + additionalProperties: { + type: "object", + properties: { + default: { type: "string" }, + }, + required: ["default"], + }, + }, + parameters: { + type: "object", + nullable: true, + required: [], + additionalProperties: { + type: "object", + properties: { + default: { type: "string" }, + }, + required: ["default"], + }, + }, + + "output-dir": { + type: "string", + nullable: true, + }, + "warn-as-error": { + type: "boolean", + nullable: true, + }, + trace: { + oneOf: [ + { type: "string" }, + { + type: "array", + items: { type: "string" }, + }, + ], + } as any, // Issue with AJV optional property typing https://github.com/ajv-validator/ajv/issues/1664 + imports: { + type: "array", + nullable: true, + items: { type: "string" }, + }, + emit: { + type: "array", + nullable: true, + items: { type: "string" }, + }, + options: { + type: "object", + nullable: true, + required: [], + additionalProperties: emitterOptionsSchema, + }, + emitters: { + type: "object", + nullable: true, + deprecated: true, + required: [], + additionalProperties: { + oneOf: [{ type: "boolean" }, emitterOptionsSchema], + }, + }, + + linter: { + type: "object", + nullable: true, + required: [], + additionalProperties: false, + properties: { + extends: { + type: "array", + nullable: true, + items: { type: "string" }, + }, + enable: { + type: "object", + required: [], + nullable: true, + additionalProperties: { type: "boolean" }, + }, + disable: { + type: "object", + required: [], + nullable: true, + additionalProperties: { type: "string" }, + }, + }, + } as any, // ajv type system doesn't like the string templates + }, +}; diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/config/types.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/config/types.ts new file mode 100644 index 000000000000..575e3b6df553 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/config/types.ts @@ -0,0 +1,112 @@ +// Copied from https://github.com/microsoft/typespec/blob/main/packages/compiler/src/config/types.ts + +import type { Diagnostic, RuleRef } from "@typespec/compiler"; +import type { YamlScript } from "../yaml/types.js"; + +/** + * Represent the normalized user configuration. + */ +export interface TypeSpecConfig { + /** + * Project root. + */ + projectRoot: string; + + /** Yaml file used in this configuration. */ + file?: YamlScript; + + /** + * Path to the config file used to create this configuration. + */ + filename?: string; + + /** + * Diagnostics reported while loading the configuration + */ + diagnostics: Diagnostic[]; + + /** + * Path to another TypeSpec config to extend. + */ + extends?: string; + + /** + * Environment variables configuration + */ + environmentVariables?: Record; + + /** + * Parameters that can be used + */ + parameters?: Record; + + /** + * Treat warning as error. + */ + warnAsError?: boolean; + + /** + * Output directory + */ + outputDir: string; + + /** + * Trace options. + */ + trace?: string[]; + + /** + * Additional imports. + */ + imports?: string[]; + + /** + * Name of emitters or path to emitters that should be used. + */ + emit?: string[]; + + /** + * Name of emitters or path to emitters that should be used. + */ + options?: Record; + + linter?: LinterConfig; +} + +/** + * Represent the configuration that can be provided in a config file. + */ +export interface TypeSpecRawConfig { + extends?: string; + "environment-variables"?: Record; + parameters?: Record; + + "warn-as-error"?: boolean; + "output-dir"?: string; + trace?: string | string[]; + imports?: string[]; + + emit?: string[]; + options?: Record; + emitters?: Record; + + linter?: LinterConfig; +} + +export interface ConfigEnvironmentVariable { + default: string; +} + +export interface ConfigParameter { + default: string; +} + +export type EmitterOptions = Record & { + "emitter-output-dir"?: string; +}; + +export interface LinterConfig { + extends?: RuleRef[]; + enable?: Record; + disable?: Record; +} diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/eslint-plugin-tsv.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/eslint-plugin-tsv.ts new file mode 100644 index 000000000000..581472b85320 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/eslint-plugin-tsv.ts @@ -0,0 +1,27 @@ +import parser from "yaml-eslint-parser"; +import { NamedESLint } from "./interfaces/named-eslint.js"; +import tspconfigValidationRules from "./rules/tspconfig-validation-rules.js"; + +const plugin: NamedESLint.Plugin = { + configs: { recommended: {} }, + name: "tsv", + rules: {}, +}; + +plugin.configs.recommended = { + plugins: { + [plugin.name]: plugin, + }, + files: ["*.yaml", "**/*.yaml"], + rules: {}, + languageOptions: { + parser: parser, + }, +}; + +tspconfigValidationRules.forEach((rule) => { + plugin.rules![rule.name] = rule; + plugin.configs.recommended.rules![`${plugin.name}/${rule.name}`] = "error"; +}); + +export default plugin; diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/interfaces/named-eslint.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/interfaces/named-eslint.ts new file mode 100644 index 000000000000..a09d8d27f150 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/interfaces/named-eslint.ts @@ -0,0 +1,17 @@ +import { ESLint, Linter, Rule } from "eslint"; + +// ESLint with names for convenience + +export namespace NamedRule { + export interface RuleModule extends Rule.RuleModule { + name: string; + } +} + +export namespace NamedESLint { + export interface Plugin extends ESLint.Plugin { + configs: { recommended: Linter.Config }; + name: string; + rules?: Record; + } +} diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/interfaces/rule-interfaces.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/interfaces/rule-interfaces.ts new file mode 100644 index 000000000000..d45d6ab20597 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/interfaces/rule-interfaces.ts @@ -0,0 +1,34 @@ +import { Rule } from "eslint"; +import { TypeSpecConfig } from "../config/types.js"; + +export enum KeyType { + EmitterOption, + Parameter, +} + +export interface RuleDocument { + description: string; + error: string; + action: string; + example: string; +} + +export interface RuleInfo { + name: string; + documentation: RuleDocument; + functions: { + messages: () => { [messageId: string]: string } | undefined; + condition: (tspconfig: TypeSpecConfig, context: Rule.RuleContext) => boolean; + validation: (tspconfig: TypeSpecConfig, context: Rule.RuleContext, node: Rule.Node) => void; + }; +} + +export interface CreateCodeGenSDKRuleArgs { + rule: string; + type: KeyType; + key: string; + expectedValue: string | boolean | RegExp; + exampleValue: string | boolean; + extraExplanation?: string; + condition?: (tspconfig: TypeSpecConfig, context: Rule.RuleContext) => boolean; +} \ No newline at end of file diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/rules/tspconfig-validation-rules.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/rules/tspconfig-validation-rules.ts new file mode 100644 index 000000000000..9eae374011e1 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/rules/tspconfig-validation-rules.ts @@ -0,0 +1,233 @@ +import { Rule } from "eslint"; +import { TypeSpecConfig } from "../config/types.js"; +import { createCodeGenSDKRule, isManagementSDK } from "../utils/rule-creator.js"; +import { emitters } from "../utils/constants.js"; +import { CreateCodeGenSDKRuleArgs, KeyType } from "../interfaces/rule-interfaces.js"; + +const tsIsManagementCondition = (tspconfig: TypeSpecConfig, context: Rule.RuleContext) => { + const emitterName = emitters.ts; + const isModularLibrary = tspconfig.options?.[emitterName]?.isModularLibrary as + | boolean + | undefined; + return isManagementSDK(context) && isModularLibrary !== false; +}; + +const args: CreateCodeGenSDKRuleArgs[] = [ + // common + { + rule: "tspconfig-common-az-service-dir-match-pattern", + key: "service-dir", + type: KeyType.Parameter, + expectedValue: /^sdk\/[^\/]*$/, + exampleValue: "sdk/placeholder", + extraExplanation: + "The 'service-dir' should be a string that starts with 'sdk/', followed by zero or more characters that are not a '/', and ends there", + condition: (_: TypeSpecConfig, _1: Rule.RuleContext) => true, + }, + // ts + { + rule: "tspconfig-ts-mgmt-modular-generate-metadata-true", + key: "generateMetadata", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: tsIsManagementCondition, + }, + { + rule: "tspconfig-ts-mgmt-modular-hierarchy-client-false", + key: "hierarchyClient", + type: KeyType.EmitterOption, + expectedValue: false, + exampleValue: false, + condition: tsIsManagementCondition, + }, + { + rule: "tspconfig-ts-mgmt-modular-experimental-extensible-enums-true", + key: "experimentalExtensibleEnums", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: tsIsManagementCondition, + }, + { + rule: "tspconfig-ts-mgmt-modular-enable-operation-group-true", + key: "enableOperationGroup", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: tsIsManagementCondition, + }, + { + rule: "tspconfig-ts-mgmt-modular-package-dir-match-pattern", + key: "package-dir", + type: KeyType.EmitterOption, + expectedValue: /^arm(?:-[a-z]+)+$/, + exampleValue: "arm-placeholder-placeholder", + extraExplanation: + "The 'package-dir' should be a string that starts with 'arm' and is followed by one or more groups of a hyphen (-) and lowercase letters", + condition: tsIsManagementCondition, + }, + { + rule: "tspconfig-ts-mgmt-modular-package-name-match-pattern", + key: "packageDetails.name", + type: KeyType.EmitterOption, + expectedValue: /^\@azure\/arm(?:-[a-z]+)+$/, + exampleValue: "@azure/arm-placeholder-placeholder", + extraExplanation: + "The package name should be a string that starts with '@azure/arm' and is followed by one or more groups of a hyphen (-) and lowercase letters", + condition: tsIsManagementCondition, + }, + // go + { + rule: "tspconfig-go-mgmt-service-dir-match-pattern", + key: "service-dir", + type: KeyType.EmitterOption, + expectedValue: /^sdk\/resourcemanager\/[^\/]*$/, + exampleValue: "sdk/resourcemanager/placeholder", + extraExplanation: + "The 'service-dir' should be a string that starts with 'sdk/resourcemanager/', followed by zero or more characters that are not a '/', and ends there", + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-package-dir-match-pattern", + key: "package-dir", + type: KeyType.EmitterOption, + expectedValue: /^arm[^\/]*$/, + exampleValue: "armplaceholder", + extraExplanation: + "The 'package-dir' should be a string that starts with 'arm' and do not contain a forward slash (/) after it", + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-module-equal-string", + key: "module", + type: KeyType.EmitterOption, + expectedValue: "github.com/Azure/azure-sdk-for-go/{service-dir}/{package-dir}", + exampleValue: "github.com/Azure/azure-sdk-for-go/{service-dir}/{package-dir}", + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-fix-const-stuttering-true", + key: "fix-const-stuttering", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-generate-examples-true", + key: "generate-examples", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-generate-fakes-true", + key: "generate-fakes", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-head-as-boolean-true", + key: "head-as-boolean", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-go-mgmt-inject-spans-true", + key: "inject-spans", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + // java + { + rule: "tspconfig-java-az-package-dir-match-pattern", + key: "package-dir", + type: KeyType.EmitterOption, + expectedValue: /^azure(-\w+)+$/, + exampleValue: "azure-placeholder", + extraExplanation: + "The 'package-dir' should be a string that starts with 'azure', followed by one or more '-' segments. Each segment can contains letters, digits, or underscores", + condition: (_: TypeSpecConfig, _1: Rule.RuleContext) => true, + }, + // python + { + rule: "tspconfig-python-mgmt-package-dir-match-pattern", + key: "package-dir", + type: KeyType.EmitterOption, + expectedValue: /^azure-mgmt(-[a-z]+){1,2}$/, + exampleValue: "azure-mgmt-placeholder", + extraExplanation: + "The 'package-dir' should be a string that starts with 'azure-mgmt', followed by 1 or 2 hyphen-separated lowercase alphabetic segments", + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-python-mgmt-package-name-equal-string", + key: "package-name", + type: KeyType.EmitterOption, + expectedValue: "{package-dir}", + exampleValue: "{package-dir}", + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-python-mgmt-generate-test-true", + key: "generate-test", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + { + rule: "tspconfig-python-mgmt-generate-sample-true", + key: "generate-sample", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, + // csharp + { + rule: "tspconfig-csharp-az-package-dir-match-pattern", + key: "package-dir", + type: KeyType.EmitterOption, + expectedValue: /^Azure\./, + exampleValue: "Azure.placeholder", + extraExplanation: "The 'package-dir' should be a string that starts with 'Azure.'", + condition: (_: TypeSpecConfig, _1: Rule.RuleContext) => true, + }, + { + rule: "tspconfig-csharp-az-namespace-equal-string", + key: "namespace", + type: KeyType.EmitterOption, + expectedValue: "{package-dir}", + exampleValue: "{package-dir}", + condition: (_: TypeSpecConfig, _1: Rule.RuleContext) => true, + }, + { + rule: "tspconfig-csharp-az-clear-output-folder-true", + key: "clear-output-folder", + type: KeyType.EmitterOption, + expectedValue: true, + exampleValue: true, + condition: (_: TypeSpecConfig, _1: Rule.RuleContext) => true, + }, + { + rule: "tspconfig-csharp-mgmt-package-dir-match-pattern", + key: "package-dir", + type: KeyType.EmitterOption, + expectedValue: /^Azure\.ResourceManager\./, + exampleValue: "Azure.ResourceManager.Placeholder", + extraExplanation: + "The 'package-dir' should be a string that starts with 'Azure.ResourceManager.'", + condition: (_: TypeSpecConfig, context: Rule.RuleContext) => isManagementSDK(context), + }, +]; + +export default args.map((a) => createCodeGenSDKRule(a)); diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/constants.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/constants.ts new file mode 100644 index 000000000000..aff4758de554 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/constants.ts @@ -0,0 +1,13 @@ +export const emitters = { + ts: "@azure-tools/typespec-ts", + java: "@azure-tools/typespec-java", + csharp: "@azure-tools/typespec-csharp", + python: "@azure-tools/typespec-python", + go: "@azure-tools/typespec-go", + autorest: "@azure-tools/typespec-autorest", + common: "", +}; + +export const defaultMessageId = "problem"; + +export const defaultRuleType = "problem"; diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/rule-creator.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/rule-creator.ts new file mode 100644 index 000000000000..889c4efbbd0e --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/rule-creator.ts @@ -0,0 +1,131 @@ +import { Rule } from "eslint"; +import { TypeSpecConfig } from "../config/types.js"; +import { + CreateCodeGenSDKRuleArgs, + KeyType, + RuleDocument, + RuleInfo, +} from "../interfaces/rule-interfaces.js"; +import { defaultMessageId, defaultRuleType, emitters } from "./constants.js"; +import { NamedRule } from "../interfaces/named-eslint.js"; +import { AST, getStaticYAMLValue } from "yaml-eslint-parser"; +import { createRuleDocument } from "./rule-doc.js"; + +export function createRule(ruleContext: RuleInfo): NamedRule.RuleModule { + const rule: NamedRule.RuleModule = { + name: ruleContext.name, + meta: { + type: defaultRuleType, + docs: { + description: ruleContext.documentation.description, + }, + schema: [], + messages: ruleContext.functions.messages(), + }, + create(context) { + return { + YAMLDocument(node: Rule.Node) { + // TODO: remove try-catch block when ESLint based TSV is ready, and have confidence for this + try { + const yamlDocument = node as unknown as AST.YAMLDocument; + const rawConfig = getStaticYAMLValue(yamlDocument) || {}; + const config = rawConfig as unknown as TypeSpecConfig; + if (!ruleContext.functions.condition(config, context)) return; + ruleContext.functions.validation(config, context, node); + } catch (error) { + console.error(`Failed to validate rule '${ruleContext.name}' due to error: ${error}`); + } + }, + }; + }, + }; + return rule; +} + +export function createRuleMessages(messageId: string, docs: RuleDocument) { + return { + [messageId]: `Error: ${docs.error}.\nAction: ${docs.action}.\nExample:\n\`\`\`\n${docs.example}\n\`\`\``, + }; +} + +export function isManagementSDK(context: Rule.RuleContext) { + const filename = context.filename; + return filename.includes(".Management"); +} + +function validateValue( + context: Rule.RuleContext, + node: Rule.Node, + actual: string | boolean | undefined, + expected: boolean | string | RegExp, +) { + switch (typeof expected) { + case "boolean": + case "string": + if (actual !== expected) context.report({ node, messageId: defaultMessageId }); + break; + case "object": + if (typeof actual !== "string" || !expected.test(actual)) + context.report({ node, messageId: defaultMessageId }); + break; + case "undefined": + context.report({ node, messageId: defaultMessageId }); + break; + default: + console.warn("Unsupported expected-value-type for tspconfig.yaml"); + break; + } +} + +// TODO: add logs +export function createCodeGenSDKRule(args: CreateCodeGenSDKRuleArgs): NamedRule.RuleModule { + const language = args.rule.split("-")[1]! as keyof typeof emitters; + const emitterName = emitters[language]; + const documentation = createRuleDocument( + emitterName, + args.type, + args.key, + args.expectedValue, + args.exampleValue, + args.extraExplanation ?? "", + ); + + const ruleInfo: RuleInfo = { + name: args.rule, + documentation: documentation!, + functions: { + messages: () => createRuleMessages(defaultMessageId, documentation), + condition: (tspconfig, context) => { + if (args.condition) return args.condition(tspconfig, context); + return true; + }, + validation: (tspconfig, context, node) => { + switch (args.type) { + case KeyType.EmitterOption: { + let option: Record | undefined = tspconfig.options?.[emitterName]; + for (const segment of args.key.split(".")) { + if (option && segment in option) option = option![segment]; + } + validateValue( + context, + node, + option as undefined | string | boolean, + args.expectedValue, + ); + break; + } + case KeyType.Parameter: { + const parameter = tspconfig.parameters?.[args.key].default; + validateValue(context, node, parameter, args.expectedValue); + break; + } + default: + console.warn("Unsupported key type in tspconfig.yaml"); + break; + } + }, + }, + }; + + return createRule(ruleInfo); +} diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/rule-doc.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/rule-doc.ts new file mode 100644 index 000000000000..1ffef72bee77 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/utils/rule-doc.ts @@ -0,0 +1,113 @@ +import { KeyType, RuleDocument } from "../interfaces/rule-interfaces.js"; +import { stringify } from "yaml"; + +function createDescriptionDocumentBlock( + displayName: string, + expectedValue: string | boolean | RegExp, + extraExplanation: string, +): string { + switch (typeof expectedValue) { + case "object": + return `Validate whether '${displayName}' matches regex pattern '${expectedValue}' in tspconfig.yaml. ${extraExplanation}`; + default: + case "string": + case "boolean": + return `Validate whether '${displayName}' is set to '${expectedValue}' in tspconfig.yaml`; + } +} + +function createErrorDocumentBlock( + displayName: string, + expectedValue: string | boolean | RegExp, +): string { + switch (typeof expectedValue) { + case "object": + return `'${displayName}' does NOT match regex pattern '${expectedValue}' in tspconfig.yaml`; + default: + case "string": + case "boolean": + return `'${displayName}' is NOT set to '${expectedValue}' in tspconfig.yaml`; + } +} + +function createActionDocumentBlock( + displayName: string, + expectedValue: string | boolean | RegExp, +): string { + switch (typeof expectedValue) { + case "object": + return `Set '${displayName}' to a value that matches regex pattern '${expectedValue}' in tspconfig.yaml`; + default: + case "string": + case "boolean": + return `Set '${displayName}' to '${expectedValue}' in tspconfig.yaml`; + } +} + +export function createRuleDocument( + emitterName: string, + keyType: KeyType, + key: string, + expectedValue: string | boolean | RegExp, + exampleValue: string | boolean, + extraExplanation: string, +): RuleDocument { + let displayName = key; + let example = ""; + switch (keyType) { + case KeyType.EmitterOption: + displayName = `options.${emitterName}.${key}`; + example = createEmitterOptionExample(emitterName, { key: key, value: exampleValue }); + break; + case KeyType.Parameter: + displayName = `parameters.${key}`; + example = createParameterExample({ key: key, value: exampleValue }); + break; + default: + // TODO: log not supported + displayName = key; + } + const description = createDescriptionDocumentBlock(displayName, expectedValue, extraExplanation); + const error = createErrorDocumentBlock(displayName, expectedValue); + const action = createActionDocumentBlock(displayName, expectedValue); + + const document: RuleDocument = { + description, + error, + action, + example, + }; + return document; +} + +export function createParameterExample(...pairs: { key: string; value: string | boolean | {} }[]) { + const obj: Record = { parameters: {} }; + for (const pair of pairs) { + obj.parameters[pair.key] = { default: pair.value }; + } + const content = stringify(obj); + return content; +} + +export function createEmitterOptionExample( + emitter: string, + ...pairs: { key: string; value: string | boolean | {} }[] +) { + const obj = { options: { [emitter]: {} } }; + for (const pair of pairs) { + const segments = pair.key.split("."); + let cur: Record = obj.options[emitter]; + for (const [i, segment] of segments.entries()) { + if (i === segments.length - 1) { + cur[segment] = pair.value; + break; + } + if (!(segment in cur)) { + cur[segment] = {}; + } + cur = cur[segment]; + } + } + const content = stringify(obj); + return content; +} diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/yaml/types.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/yaml/types.ts new file mode 100644 index 000000000000..2c73c7c0da1e --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/src/yaml/types.ts @@ -0,0 +1,24 @@ +// Copied from https://github.com/microsoft/typespec/blob/main/packages/compiler/src/yaml/types.ts + +import { SourceFile } from "@typespec/compiler"; +import { Document } from "yaml"; + +export interface YamlScript { + readonly kind: "yaml-script"; + readonly file: SourceFile; + /** Value of the yaml script. */ + readonly value: unknown; + + /** @internal yaml library document. We do not expose this as the "yaml" library is not part of the contract. */ + readonly doc: Document.Parsed; +} + +/** + * Represent the location of a value in a yaml script. + */ +export interface YamlPathTarget { + kind: "path-target"; + script: YamlScript; + path: string[]; +} +export type YamlDiagnosticTargetType = "value" | "key"; diff --git a/eng/tools/typespec-validation/src/eslint-plugin-tsv/test/rules/tspconfig-options-validation.test.ts b/eng/tools/typespec-validation/src/eslint-plugin-tsv/test/rules/tspconfig-options-validation.test.ts new file mode 100644 index 000000000000..9e0bb1ea2228 --- /dev/null +++ b/eng/tools/typespec-validation/src/eslint-plugin-tsv/test/rules/tspconfig-options-validation.test.ts @@ -0,0 +1,397 @@ +import { Rule, RuleTester } from "eslint"; +import { describe, it } from "vitest"; +import parser from "yaml-eslint-parser"; +import { defaultMessageId, emitters } from "../../src/utils/constants.js"; +import { NamedRule } from "../../src/interfaces/named-eslint.js"; +import { createEmitterOptionExample, createParameterExample } from "../../src/utils/rule-doc.js"; + +interface Case { + description: string; + rulePath: string; + ruleName: string; + fileName?: string; + yamlContent: string; + shouldReportError: boolean; +} + +const managementTspconfigPath = "contosowidgetmanager/Contoso.Management/tspconfig.yaml"; +const rulePath = "../../src/rules/tspconfig-validation-rules.js"; + +const commonAzureServiceDirTestCases = createParameterTestCases( + rulePath, + "tspconfig-common-az-service-dir-match-pattern", + "", + "service-dir", + "sdk/aaa", + "sdka/aaa", +); + +const tsManagementGenerateMetadataTestCases = createEmitterOptionTestCases( + emitters.ts, + rulePath, + "tspconfig-ts-mgmt-modular-generate-metadata-true", + managementTspconfigPath, + "generateMetadata", + true, + false, +); + +const tsManagementHierarchyClientTestCases = createEmitterOptionTestCases( + emitters.ts, + rulePath, + "tspconfig-ts-mgmt-modular-hierarchy-client-false", + managementTspconfigPath, + "hierarchyClient", + false, + true, +); + +const tsManagementExperimentalExtensibleEnumsTestCases = createEmitterOptionTestCases( + emitters.ts, + rulePath, + "tspconfig-ts-mgmt-modular-experimental-extensible-enums-true", + managementTspconfigPath, + "experimentalExtensibleEnums", + true, + false, +); + +const tsManagementEnableOperationGroupTestCases = createEmitterOptionTestCases( + emitters.ts, + rulePath, + "tspconfig-ts-mgmt-modular-enable-operation-group-true", + managementTspconfigPath, + "enableOperationGroup", + true, + false, +); + +const tsManagementPackageDirTestCases = createEmitterOptionTestCases( + emitters.ts, + rulePath, + "tspconfig-ts-mgmt-modular-package-dir-match-pattern", + managementTspconfigPath, + "package-dir", + "arm-aaa-bbb", + "aaa-bbb", +); + +const tsManagementPackageNameTestCases = createEmitterOptionTestCases( + emitters.ts, + rulePath, + "tspconfig-ts-mgmt-modular-package-name-match-pattern", + managementTspconfigPath, + "packageDetails.name", + "@azure/arm-aaa-bbb", + "@azure/aaa-bbb", +); + +const goManagementServiceDirTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-service-dir-match-pattern", + managementTspconfigPath, + "service-dir", + "sdk/resourcemanager/aaa", + "sdk/manager/aaa", +); + +const goManagementPackageDirTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-package-dir-match-pattern", + managementTspconfigPath, + "package-dir", + "armaaa", + "aaa", +); + +const goManagementModuleTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-module-equal-string", + managementTspconfigPath, + "module", + "github.com/Azure/azure-sdk-for-go/{service-dir}/{package-dir}", + "github.com/Azure/azure-sdk-for-java/{service-dir}/{package-dir}", +); + +const goManagementFixConstStutteringTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-fix-const-stuttering-true", + managementTspconfigPath, + "fix-const-stuttering", + true, + false, +); + +const goManagementGenerateExamplesTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-generate-examples-true", + managementTspconfigPath, + "generate-examples", + true, + false, +); + +const goManagementGenerateFakesTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-generate-fakes-true", + managementTspconfigPath, + "generate-fakes", + true, + false, +); + +const goManagementHeadAsBooleanTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-head-as-boolean-true", + managementTspconfigPath, + "head-as-boolean", + true, + false, +); + +const goManagementInjectSpansTestCases = createEmitterOptionTestCases( + emitters.go, + rulePath, + "tspconfig-go-mgmt-inject-spans-true", + managementTspconfigPath, + "inject-spans", + true, + false, +); + +const javaManagementPackageDirTestCases = createEmitterOptionTestCases( + emitters.java, + rulePath, + "tspconfig-java-az-package-dir-match-pattern", + "", + "package-dir", + "azure-aaa", + "aaa", +); + +const pythonManagementPackageDirTestCases = createEmitterOptionTestCases( + emitters.python, + rulePath, + "tspconfig-python-mgmt-package-dir-match-pattern", + managementTspconfigPath, + "package-dir", + "azure-mgmt-aaa", + "azure-aaa", +); + +const pythonManagementPackageNameTestCases = createEmitterOptionTestCases( + emitters.python, + rulePath, + "tspconfig-python-mgmt-package-name-equal-string", + managementTspconfigPath, + "package-name", + "{package-dir}", + "aaa", +); + +const pythonManagementGenerateTestTestCases = createEmitterOptionTestCases( + emitters.python, + rulePath, + "tspconfig-python-mgmt-generate-test-true", + managementTspconfigPath, + "generate-test", + true, + false, +); + +const pythonManagementGenerateSampleTestCases = createEmitterOptionTestCases( + emitters.python, + rulePath, + "tspconfig-python-mgmt-generate-sample-true", + managementTspconfigPath, + "generate-sample", + true, + false, +); + +const csharpAzPackageDirTestCases = createEmitterOptionTestCases( + emitters.csharp, + rulePath, + "tspconfig-csharp-az-package-dir-match-pattern", + "", + "package-dir", + "Azure.AAA", + "AAA", +); + +const csharpAzNamespaceTestCases = createEmitterOptionTestCases( + emitters.csharp, + rulePath, + "tspconfig-csharp-az-namespace-equal-string", + "", + "namespace", + "{package-dir}", + "AAA", +); + +const csharpAzClearOutputFolderTestCases = createEmitterOptionTestCases( + emitters.csharp, + rulePath, + "tspconfig-csharp-az-clear-output-folder-true", + "", + "clear-output-folder", + true, + false, +); + +const csharpMgmtPackageDirTestCases = createEmitterOptionTestCases( + emitters.csharp, + rulePath, + "tspconfig-csharp-mgmt-package-dir-match-pattern", + managementTspconfigPath, + "package-dir", + "Azure.ResourceManager.AAA", + "Azure.Management.AAA", +); + +describe("Tspconfig emitter options validation", () => { + it.each([ + // common + ...commonAzureServiceDirTestCases, + // ts + ...tsManagementGenerateMetadataTestCases, + ...tsManagementHierarchyClientTestCases, + ...tsManagementExperimentalExtensibleEnumsTestCases, + ...tsManagementEnableOperationGroupTestCases, + ...tsManagementPackageDirTestCases, + ...tsManagementPackageNameTestCases, + // go + ...goManagementServiceDirTestCases, + ...goManagementPackageDirTestCases, + ...goManagementModuleTestCases, + ...goManagementFixConstStutteringTestCases, + ...goManagementGenerateExamplesTestCases, + ...goManagementGenerateFakesTestCases, + ...goManagementHeadAsBooleanTestCases, + ...goManagementInjectSpansTestCases, + // java + ...javaManagementPackageDirTestCases, + // python + ...pythonManagementPackageDirTestCases, + ...pythonManagementPackageNameTestCases, + ...pythonManagementGenerateTestTestCases, + ...pythonManagementGenerateSampleTestCases, + // csharp + ...csharpAzPackageDirTestCases, + ...csharpAzNamespaceTestCases, + ...csharpAzClearOutputFolderTestCases, + ...csharpMgmtPackageDirTestCases, + ])("$ruleName - $description", async (c: Case) => { + const ruleTester = new RuleTester({ + languageOptions: { + parser: parser, + }, + }); + + const ruleModule = await import(c.rulePath); + const rule = ruleModule.default.find((r: NamedRule.RuleModule) => r.name === c.ruleName); + const tests = c.shouldReportError + ? { + valid: [], + invalid: [ + { + filename: c.fileName, + code: c.yamlContent, + errors: [{ messageId: defaultMessageId }], + }, + ], + } + : { + valid: [ + { + filename: c.fileName, + code: c.yamlContent, + }, + ], + invalid: [], + }; + ruleTester.run(rule.name, rule as Rule.RuleModule, tests); + }); +}); + +function createEmitterOptionTestCases( + emitterName: string, + rulePath: string, + ruleName: string, + fileName: string, + key: string, + validValue: boolean | string, + invalidValue: boolean | string, +): Case[] { + const managementGenerateMetadataTestCases: Case[] = [ + { + description: `valid: ${key} is ${validValue}`, + rulePath, + ruleName, + fileName, + yamlContent: createEmitterOptionExample(emitterName, { key: key, value: validValue }), + shouldReportError: false, + }, + { + description: `invalid: ${key} is ${invalidValue}`, + rulePath, + ruleName, + fileName, + yamlContent: createEmitterOptionExample(emitterName, { key: key, value: invalidValue }), + shouldReportError: true, + }, + { + description: `invalid: ${key} is undefined`, + rulePath, + ruleName, + fileName, + yamlContent: createEmitterOptionExample(emitterName), + shouldReportError: true, + }, + ]; + return managementGenerateMetadataTestCases; +} + +function createParameterTestCases( + rulePath: string, + ruleName: string, + fileName: string, + key: string, + validValue: boolean | string, + invalidValue: boolean | string, +): Case[] { + const managementGenerateMetadataTestCases: Case[] = [ + { + description: `valid: ${key} is ${validValue}`, + rulePath, + ruleName, + fileName, + yamlContent: createParameterExample({ key: key, value: validValue }), + shouldReportError: false, + }, + { + description: `invalid: ${key} is ${invalidValue}`, + rulePath, + ruleName, + fileName, + yamlContent: createParameterExample({ key: key, value: invalidValue }), + shouldReportError: true, + }, + { + description: `invalid: ${key} is undefined`, + rulePath, + ruleName, + fileName, + yamlContent: "", + shouldReportError: true, + }, + ]; + return managementGenerateMetadataTestCases; +} diff --git a/eng/tools/typespec-validation/src/index.ts b/eng/tools/typespec-validation/src/index.ts index b72ea7616531..b1ac12500eb7 100755 --- a/eng/tools/typespec-validation/src/index.ts +++ b/eng/tools/typespec-validation/src/index.ts @@ -1,13 +1,14 @@ import { parseArgs, ParseArgsConfig } from "node:util"; import { CompileRule } from "./rules/compile.js"; import { EmitAutorestRule } from "./rules/emit-autorest.js"; -import { FlavorAzureRule } from "./rules/flavor-azure.js"; import { FolderStructureRule } from "./rules/folder-structure.js"; import { FormatRule } from "./rules/format.js"; import { LinterRulesetRule } from "./rules/linter-ruleset.js"; import { NpmPrefixRule } from "./rules/npm-prefix.js"; import { TsvRunnerHost } from "./tsv-runner-host.js"; import { getSuppressions, Suppression } from "suppressions"; +import tspconfigRules from "./rules/tspconfig-validation-rules.js"; +import { Rule } from "./rule.js"; export async function main() { const host = new TsvRunnerHost(); @@ -39,15 +40,16 @@ export async function main() { return; } - const rules = [ + let rules: Rule[] = [ new FolderStructureRule(), new NpmPrefixRule(), new EmitAutorestRule(), - new FlavorAzureRule(), new LinterRulesetRule(), new CompileRule(), new FormatRule(), ]; + rules.push(...tspconfigRules); + let success = true; for (let i = 0; i < rules.length; i++) { const rule = rules[i]; diff --git a/eng/tools/typespec-validation/src/rules/flavor-azure.ts b/eng/tools/typespec-validation/src/rules/flavor-azure.ts deleted file mode 100644 index 1c01955448b3..000000000000 --- a/eng/tools/typespec-validation/src/rules/flavor-azure.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { parse as yamlParse } from "yaml"; -import { Rule } from "../rule.js"; -import { RuleResult } from "../rule-result.js"; -import { TsvHost } from "../tsv-host.js"; - -export class FlavorAzureRule implements Rule { - readonly name = "FlavorAzure"; - - readonly description = "Client emitters must set 'flavor:azure'"; - - async execute(host: TsvHost, folder: string): Promise { - let success = true; - let stdOutput = ""; - let errorOutput = ""; - - const configText = await host.readTspConfig(folder); - const config = yamlParse(configText); - - const options = config?.options; - for (const emitter in options) { - if (this.isClientEmitter(emitter)) { - const flavor = options[emitter]?.flavor; - - stdOutput += `"${emitter}":\n`; - stdOutput += ` flavor: ${flavor}\n`; - - if (flavor !== "azure") { - success = false; - errorOutput += - "tspconfig.yaml must define the following property:\n" + - "\n" + - "options:\n" + - ` "${emitter}":\n` + - " flavor: azure\n\n"; - } - } - } - - return { - success: success, - stdOutput: stdOutput, - errorOutput: errorOutput, - }; - } - - isClientEmitter(name: string): boolean { - const regex = new RegExp( - "^(@azure-tools/typespec-(csharp|java|python|ts)|@typespec/http-client-.+)$", - ); - - return regex.test(name); - } -} diff --git a/eng/tools/typespec-validation/src/rules/tspconfig-java-package-dir.ts b/eng/tools/typespec-validation/src/rules/tspconfig-java-package-dir.ts deleted file mode 100644 index 28c8d544f13b..000000000000 --- a/eng/tools/typespec-validation/src/rules/tspconfig-java-package-dir.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { join } from "path"; -import { parse as yamlParse } from "yaml"; -import { Rule } from "../rule.js"; -import { RuleResult } from "../rule-result.js"; -import { TsvHost } from "../tsv-host.js"; - -export class TspConfigJavaPackageDirectoryRule implements Rule { - pattern = new RegExp(/^azure(-\w+)+$/); - - readonly name = "tspconfig-java-package-dir"; - readonly description = `"options.@azure-tools/typespec-java.package-dir" must match ${this.pattern}.`; - readonly action = `Please update "options.@azure-tools/typespec-java.package-dir" to start with "azure", followed by one or more "-" segments. Each segment can contains letters, digits, or underscores. For example: "azure-test".`; - // TODO: provide link to the rule details and full sample - readonly link = ""; - async execute(host: TsvHost, folder: string): Promise { - const tspconfigExists = await host.checkFileExists(join(folder, "tspconfig.yaml")); - if (!tspconfigExists) - return this.createFailedResult(`Failed to find ${join(folder, "tspconfig.yaml")}`); - - let config = undefined; - try { - const configText = await host.readTspConfig(folder); - config = yamlParse(configText); - } catch (error) { - // TODO: append content " Check tpsconfig-file-exists rule for more details." when it's ready - return this.createFailedResult(`Failed to parse ${join(folder, "tspconfig.yaml")}`); - } - - const javaEmitterOptions = config?.options?.["@azure-tools/typespec-java"]; - - if (!javaEmitterOptions) - return this.createFailedResult(`Failed to find "options.@azure-tools/typespec-java"`); - - const packageDir = javaEmitterOptions?.["package-dir"]; - if (!packageDir) - return this.createFailedResult( - `Failed to find "options.@azure-tools/typespec-java.package-dir"`, - ); - - if (!this.pattern.test(packageDir)) { - return this.createFailedResult( - `package-dir "${packageDir}" does not match "${this.pattern}"`, - ); - } - return { success: true, stdOutput: `[${this.name}]: validation passed.` }; - } - - createFailedResult(errorMessage: string): RuleResult { - return { - success: false, - errorOutput: `[${this.name}]: ${errorMessage}. ${this.description} ${this.action} For more information and full samples, see ${this.link}.`, - }; - } -} diff --git a/eng/tools/typespec-validation/src/rules/tspconfig-validation-rules.ts b/eng/tools/typespec-validation/src/rules/tspconfig-validation-rules.ts new file mode 100644 index 000000000000..0929c2699065 --- /dev/null +++ b/eng/tools/typespec-validation/src/rules/tspconfig-validation-rules.ts @@ -0,0 +1,59 @@ +// Note: temporary workaround to convert new rules to old rules to provides suggestion to correct tspconfig + +import { join } from "path"; +import { Rule } from "../rule.js"; +import { RuleResult } from "../rule-result.js"; +import { TsvHost } from "../tsv-host.js"; +import { ESLint } from "eslint"; +import tsvPlugin from "../eslint-plugin-tsv/src/eslint-plugin-tsv.js"; + +async function runESLint(content: string, folder: string, ruleName: string) { + const cwd = process.cwd(); + const eslint = new ESLint({ + cwd, + overrideConfig: { + ...tsvPlugin.configs.recommended, + rules: { + [`${tsvPlugin.name}/${ruleName}`]: "error", + } + }, + overrideConfigFile: true, + }); + const results = await eslint.lintText(content, { filePath: join(folder, "tspconfig.yaml") }); + return results; +} + +// NOTE: This is a workaround to convert the new rules to old rules +// To be removed when the new TSV framework is ready +function convertToOldRules() { + let oldRules = []; + for (const [_, rule] of Object.entries(tsvPlugin.rules ?? {})) { + if (!rule.name.startsWith("tspconfig-")) continue; + const oldRule: Rule = { + name: rule.name, + description: rule.meta?.docs?.description ?? "", + async execute(host: TsvHost, folder: string): Promise { + const configText = await host.readTspConfig(folder); + const results = await runESLint(configText, folder, rule.name); + if (results.length > 0 && results[0].messages.length > 0) { + return { + stdOutput: 'Validation failed.\n' + results[0].messages[0].message, + // Only used to provide suggestion to correct tspconfig + success: true, + }; + } + + return { + stdOutput: `[${rule.name}]: validation passed.`, + success: true, + }; + }, + }; + oldRules.push(oldRule); + } + return oldRules; +} + +const rules = convertToOldRules(); + +export default rules; diff --git a/eng/tools/typespec-validation/test/flavor-azure.test.ts b/eng/tools/typespec-validation/test/flavor-azure.test.ts deleted file mode 100644 index e282d9364989..000000000000 --- a/eng/tools/typespec-validation/test/flavor-azure.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { describe, it } from "vitest"; -import { FlavorAzureRule } from "../src/rules/flavor-azure.js"; -import { TsvTestHost } from "./tsv-test-host.js"; -import { strict as assert } from "node:assert"; - -describe("flavor-azure", function () { - const clientEmitterNames = [ - "@azure-tools/typespec-csharp", - "@azure-tools/typespec-java", - "@azure-tools/typespec-python", - "@azure-tools/typespec-ts", - "@typespec/http-client-foo", - ]; - - const nonClientEmitterNames = ["@azure-tools/typespec-autorest", "@typespec/openapi3"]; - - clientEmitterNames.forEach(function (emitter) { - it(`should fail if "${emitter}" is missing flavor`, async function () { - let host = new TsvTestHost(); - - host.readTspConfig = async (_folder: string) => ` - options: - "${emitter}": - package-dir: "foo" - `; - const result = await new FlavorAzureRule().execute(host, TsvTestHost.folder); - assert(!result.success); - }); - - it(`should fail if "${emitter}" flavor is not "azure"`, async function () { - let host = new TsvTestHost(); - host.readTspConfig = async (_folder: string) => ` - options: - "${emitter}": - package-dir: "foo" - flavor: not-azure - `; - const result = await new FlavorAzureRule().execute(host, TsvTestHost.folder); - assert(!result.success); - }); - - it(`should succeed if ${emitter} flavor is "azure"`, async function () { - let host = new TsvTestHost(); - host.readTspConfig = async (_folder: string) => ` - options: - "${emitter}": - package-dir: "foo" - flavor: azure - `; - const result = await new FlavorAzureRule().execute(host, TsvTestHost.folder); - assert(result.success); - }); - }); - - nonClientEmitterNames.forEach(function (emitter) { - it(`should succeed if ${emitter} is missing flavor`, async function () { - let host = new TsvTestHost(); - host.readTspConfig = async (_folder: string) => ` - options: - "${emitter}": - azure-resource-provider-folder: "data-plane" - `; - const result = await new FlavorAzureRule().execute(host, TsvTestHost.folder); - assert(result.success); - }); - }); - - it("should succeed if config is empty", async function () { - let host = new TsvTestHost(); - host.readTspConfig = async (_folder: string) => ""; - const result = await new FlavorAzureRule().execute(host, TsvTestHost.folder); - assert(result.success); - }); - - it("should succeed if config has no options", async function () { - let host = new TsvTestHost(); - host.readTspConfig = async (_folder: string) => ` -emit: - - "@azure-tools/typespec-autorest" -`; - const result = await new FlavorAzureRule().execute(host, TsvTestHost.folder); - assert(result.success); - }); -}); diff --git a/eng/tools/typespec-validation/test/tspconfig.test.ts b/eng/tools/typespec-validation/test/tspconfig.test.ts index 3be4e4f1deb3..9f34671e4f1b 100644 --- a/eng/tools/typespec-validation/test/tspconfig.test.ts +++ b/eng/tools/typespec-validation/test/tspconfig.test.ts @@ -1,6 +1,6 @@ import { describe, it } from "vitest"; import { join } from "path"; -import { TspConfigJavaPackageDirectoryRule } from "../src/rules/tspconfig-java-package-dir.js"; +import tspconfigRules from "../src/rules/tspconfig-validation-rules.js"; import { TsvTestHost } from "./tsv-test-host.js"; import { strict as assert, strictEqual } from "node:assert"; import { Rule } from "../src/rule.js"; @@ -13,88 +13,44 @@ interface TestCase { folder: string; } -const testCases: TestCase[] = [ - { - rule: new TspConfigJavaPackageDirectoryRule(), - folder: TsvTestHost.folder, - when: "package-dir \"azure-abc\" is valid", - tspconfig: ` -options: - "@azure-tools/typespec-java": - package-dir: azure-abc -`, - expectedResult: true, - }, - { - rule: new TspConfigJavaPackageDirectoryRule(), - folder: TsvTestHost.folder, - when: "tspconfig.yaml is not a valid yaml", - tspconfig: `aaa`, - expectedResult: false, - }, - { - rule: new TspConfigJavaPackageDirectoryRule(), - folder: TsvTestHost.folder, - when: "java emitter has no options", - tspconfig: ` -options: - "@azure-tools/typespec-ts": - package-dir: com.azure.test -`, - expectedResult: false, - }, - { - rule: new TspConfigJavaPackageDirectoryRule(), - folder: TsvTestHost.folder, - when: "java emitter options have no package-dir", - tspconfig: ` -options: - "@azure-tools/typespec-java": - x: com.azure.test -`, - expectedResult: false, - }, - { - rule: new TspConfigJavaPackageDirectoryRule(), - folder: TsvTestHost.folder, - when: "package-dir \"azure.test\" is invalid", - tspconfig: ` -options: - "@azure-tools/typespec-java": - package-dir: azure.test -`, - expectedResult: false, - }, - { - rule: new TspConfigJavaPackageDirectoryRule(), - folder: TsvTestHost.folder, - when: "package-dir \"azure-\" is invalid", - tspconfig: ` -options: - "@azure-tools/typespec-java": - package-dir: azure- -`, - expectedResult: false, - }, -]; - -describe("tspconfig", function () { - it.each(testCases)( - `should be $expectedResult for rule $rule.name when $when`, - async (c: TestCase) => { - let host = new TsvTestHost(); - host.checkFileExists = async (file: string) => { - return file === join(TsvTestHost.folder, "tspconfig.yaml"); - }; - host.readTspConfig = async (_folder: string) => c.tspconfig; - const result = await c.rule.execute(host, TsvTestHost.folder); - strictEqual(result.success, c.expectedResult); - if (!c.expectedResult) { - // TODO: assert link when ready - assert(result.errorOutput?.includes(c.rule.name)); - assert(result.errorOutput?.includes(c.rule.description)); - assert(result.errorOutput?.includes(c.rule.action!)); - } +describe("tspconfig rules", () => { + it.each([ + { + rule: tspconfigRules.find((r) => r.name === "tspconfig-java-az-package-dir-match-pattern")!, + folder: "aaa/bbb/", + when: 'package-dir "azure-" is invalid', + tspconfig: ` + options: + "@azure-tools/typespec-java": + package-dir: xxxxx + flavor: azure + `, + expectedResult: false, + }, + { + rule: tspconfigRules.find((r) => r.name === "tspconfig-java-az-package-dir-match-pattern")!, + folder: "aaa/aaa.Management/", + when: 'package-dir "azure-" is invalid', + tspconfig: ` + options: + "@azure-tools/typespec-java": + package-dir: azure-test + flavor: azure + `, + expectedResult: true, }, - ); + ])(`should be $expectedResult for new rule $rule.name when $when`, async (c: TestCase) => { + let host = new TsvTestHost(); + host.checkFileExists = async (file: string) => { + return file === join(TsvTestHost.folder, "tspconfig.yaml"); + }; + host.readTspConfig = async (_folder: string) => c.tspconfig; + const result = await c.rule.execute(host, c.folder); + strictEqual(result.success, true); + assert(result.stdOutput && result.stdOutput.length > 0 && result.errorOutput === undefined); + assert( + (c.expectedResult && result.stdOutput.includes("validation passed")) || + (!c.expectedResult && result.stdOutput.includes("Validation failed.")) + ); + }); }); diff --git a/package-lock.json b/package-lock.json index adaa8f5bc243..7379bd58641e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "dev": true, "hasInstallScript": true, "devDependencies": { + "@azure-tools/eslint-plugin-tsv": "file:eslint-plugin-tsv", "@azure-tools/sdk-suppressions": "file:sdk-suppressions", "@azure-tools/specs-model": "file:specs-model", "@azure-tools/suppressions": "file:suppressions", @@ -48,6 +49,799 @@ "@azure-tools/typespec-validation": "file:typespec-validation" } }, + "eng/tools/eslint-plugin-tsv": { + "name": "@azure-tools/eslint-plugin-tsv", + "dev": true, + "dependencies": { + "ajv": "^8.17.1", + "yaml-eslint-parser": "^1.2.3" + }, + "devDependencies": { + "@types/node": "^18.19.31", + "@vitest/coverage-v8": "^2.0.4", + "eslint": "^9.17.0", + "memfs": "^4.15.0", + "rimraf": "^5.0.10", + "typescript": "~5.6.2", + "vitest": "^2.0.4" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "eslint": ">=9.0.0" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/coverage-v8": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.8.tgz", + "integrity": "sha512-2Y7BPlKH18mAZYAW1tYByudlCYrQyl5RGvnnDYJKW5tCiO5qg3KSAy3XAxcxKz900a0ZXxWtKrMuZLe3lKBpJw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^0.2.3", + "debug": "^4.3.7", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.12", + "magicast": "^0.3.5", + "std-env": "^3.8.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "2.1.8", + "vitest": "2.1.8" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/expect": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.8.tgz", + "integrity": "sha512-8ytZ/fFHq2g4PJVAtDX57mayemKgDR6X3Oa2Foro+EygiOJHUXhCqBAAKQYYajZpFoIfvBCF1j6R6IYRSIUFuw==", + "dev": true, + "dependencies": { + "@vitest/spy": "2.1.8", + "@vitest/utils": "2.1.8", + "chai": "^5.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/pretty-format": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.8.tgz", + "integrity": "sha512-9HiSZ9zpqNLKlbIDRWOnAWqgcA7xu+8YxXSekhr0Ykab7PAYFkhkwoqVArPOtJhPmYeE2YHgKZlj3CP36z2AJQ==", + "dev": true, + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/runner": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.8.tgz", + "integrity": "sha512-17ub8vQstRnRlIU5k50bG+QOMLHRhYPAna5tw8tYbj+jzjcspnwnwtPtiOlkuKC4+ixDPTuLZiqiWWQ2PSXHVg==", + "dev": true, + "dependencies": { + "@vitest/utils": "2.1.8", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/snapshot": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.8.tgz", + "integrity": "sha512-20T7xRFbmnkfcmgVEz+z3AU/3b0cEzZOt/zmnvZEctg64/QZbSDJEVm9fLnnlSi74KibmRsO9/Qabi+t0vCRPg==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.8", + "magic-string": "^0.30.12", + "pathe": "^1.1.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/spy": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.8.tgz", + "integrity": "sha512-5swjf2q95gXeYPevtW0BLk6H8+bPlMb4Vw/9Em4hFxDcaOxS+e0LOX4yqNxoHzMR2akEB2xfpnWUzkZokmgWDg==", + "dev": true, + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/@vitest/utils": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.8.tgz", + "integrity": "sha512-dwSoui6djdwbfFmIgbIjX2ZhIoG7Ex/+xpxyiEgIGzjliY8xGkcpITKTlp6B4MgtGkF2ilvm97cPM96XZaAgcA==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "2.1.8", + "loupe": "^3.1.2", + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true + }, + "eng/tools/eslint-plugin-tsv/node_modules/tinyrainbow": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-1.2.0.tgz", + "integrity": "sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/vite-node": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.8.tgz", + "integrity": "sha512-uPAwSr57kYjAUux+8E2j0q0Fxpn8M9VoyfGiRI8Kfktz9NcYMCenwY5RnZxnF1WTu3TGiYipirIzacLL3VVGFg==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.7", + "es-module-lexer": "^1.5.4", + "pathe": "^1.1.2", + "vite": "^5.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/vite-node/node_modules/vite": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/vitest": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.8.tgz", + "integrity": "sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "2.1.8", + "@vitest/mocker": "2.1.8", + "@vitest/pretty-format": "^2.1.8", + "@vitest/runner": "2.1.8", + "@vitest/snapshot": "2.1.8", + "@vitest/spy": "2.1.8", + "@vitest/utils": "2.1.8", + "chai": "^5.1.2", + "debug": "^4.3.7", + "expect-type": "^1.1.0", + "magic-string": "^0.30.12", + "pathe": "^1.1.2", + "std-env": "^3.8.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.1", + "tinypool": "^1.0.1", + "tinyrainbow": "^1.2.0", + "vite": "^5.0.0", + "vite-node": "2.1.8", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/node": "^18.0.0 || >=20.0.0", + "@vitest/browser": "2.1.8", + "@vitest/ui": "2.1.8", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/vitest/node_modules/@vitest/mocker": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.8.tgz", + "integrity": "sha512-7guJ/47I6uqfttp33mgo6ga5Gr1VnL58rcqYKyShoRK9ebu8T5Rs6HN3s1NABiBeVTdWNrwUMcHH54uXZBN4zA==", + "dev": true, + "dependencies": { + "@vitest/spy": "2.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "eng/tools/eslint-plugin-tsv/node_modules/vitest/node_modules/vite": { + "version": "5.4.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.14.tgz", + "integrity": "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "eng/tools/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "eng/tools/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "eng/tools/node_modules/@types/node": { "version": "18.19.71", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.71.tgz", @@ -386,6 +1180,7 @@ "name": "@azure-tools/typespec-validation", "dev": true, "dependencies": { + "eslint-plugin-tsv": "file:../eslint-plugin-tsv", "globby": "^14.0.1", "simple-git": "^3.24.0", "suppressions": "file:../suppressions", @@ -587,6 +1382,10 @@ "node": ">=12.0.0" } }, + "node_modules/@azure-tools/eslint-plugin-tsv": { + "resolved": "eng/tools/eslint-plugin-tsv", + "link": true + }, "node_modules/@azure-tools/openapi-tools-common": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@azure-tools/openapi-tools-common/-/openapi-tools-common-1.2.2.tgz", @@ -2361,6 +3160,60 @@ "jsep": "^0.4.0||^1.0.0" } }, + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.1.tgz", + "integrity": "sha512-osjeBqMJ2lb/j/M8NCPjs1ylqWIcTRTycIhVB5pt6LgzgeRSb0YRZ7j9RfA8wIUrsr/medIuhVyonXRZWLyfdw==", + "dev": true, + "dependencies": { + "@jsonjoy.com/base64": "^1.1.1", + "@jsonjoy.com/util": "^1.1.2", + "hyperdyperid": "^1.2.0", + "thingies": "^1.20.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", + "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/@kwsites/file-exists": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", @@ -4854,6 +5707,10 @@ } } }, + "node_modules/eslint-plugin-tsv": { + "resolved": "eng/tools/eslint-plugin-tsv", + "link": true + }, "node_modules/eslint-plugin-unicorn": { "version": "56.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-56.0.1.tgz", @@ -6007,6 +6864,15 @@ "dev": true, "license": "Unlicense" }, + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "engines": { + "node": ">=10.18" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -6836,6 +7702,25 @@ "dev": true, "license": "MIT" }, + "node_modules/memfs": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.17.0.tgz", + "integrity": "sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==", + "dev": true, + "dependencies": { + "@jsonjoy.com/json-pack": "^1.0.3", + "@jsonjoy.com/util": "^1.3.0", + "tree-dump": "^1.0.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">= 4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -8387,6 +9272,65 @@ "node": ">=0.10.0" } }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "4.31.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.31.0.tgz", @@ -9062,6 +10006,18 @@ "dev": true, "license": "MIT" }, + "node_modules/thingies": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", + "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", + "dev": true, + "engines": { + "node": ">=10.18" + }, + "peerDependencies": { + "tslib": "^2" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -9143,6 +10099,22 @@ "dev": true, "license": "MIT" }, + "node_modules/tree-dump": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", + "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", + "dev": true, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/triple-beam": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", @@ -9887,6 +10859,35 @@ "node": ">= 14" } }, + "node_modules/yaml-eslint-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.3.tgz", + "integrity": "sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, + "node_modules/yaml-eslint-parser/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/specification/compute/cspell.yaml b/specification/compute/cspell.yaml index ccaf4546626a..1ebdb93297a0 100644 --- a/specification/compute/cspell.yaml +++ b/specification/compute/cspell.yaml @@ -21,6 +21,7 @@ words: - osdisk - osdiskforlinuxsimple - osdiskforwindowssimple + - rdma - reimage - reimageall - reimaged diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/diagnostic.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/diagnostic.json new file mode 100644 index 000000000000..7077da709f3b --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/diagnostic.json @@ -0,0 +1,1488 @@ +{ + "swagger": "2.0", + "info": { + "title": "ComputeDiagnosticResourceProviderClient", + "description": "The Compute Diagnostic Resource Provider Client", + "version": "2025-02-01-preview" + }, + "host": "management.azure.com", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "security": [ + { + "azure_auth": [ + "user_impersonation" + ] + } + ], + "securityDefinitions": { + "azure_auth": { + "type": "oauth2", + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize", + "flow": "implicit", + "description": "Azure Active Directory OAuth2 Flow", + "scopes": { + "user_impersonation": "impersonate your user account" + } + } + }, + "paths": { + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnosticOperations/{operationId}": { + "get": { + "tags": [ + "diagnosticOperations" + ], + "operationId": "DiagnosticOperations_Read", + "description": "Gets status of a Diagnostic operation issued for Disk Inspection.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/OperationIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ComputeDiagnosticsOperationResult" + } + }, + "202": { + "description": "Accepted", + "headers": { + "Location": { + "type": "string" + } + } + }, + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Gets the status of a scheduled disk inspection request.": { + "$ref": "./examples/GetDiagnosticOperation.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics/diskInspection/run": { + "post": { + "tags": [ + "diagnostics" + ], + "operationId": "DiskInspection_Create", + "x-ms-long-running-operation": true, + "x-ms-long-running-operation-options": { + "final-state-via": "location" + }, + "description": "Creates a request for executing disk Inspection.", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "runDiskInspectionInput", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/RunDiskInspectionInput" + }, + "description": "RunDiskInspection object supplied in the body of the Post run disk inspection operation." + } + ], + "responses": { + "202": { + "description": "Accepted", + "headers": { + "Location": { + "type": "string" + } + } + }, + "default": { + "description": "Error response describing why the diagnostic run failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Create a request for disk inspection.": { + "$ref": "./examples/RunDiskInspection.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics": { + "get": { + "tags": [ + "diagnostics" + ], + "operationId": "Diagnostics_List", + "description": "Lists all available Compute diagnostics for a subscription in a location.", + "x-ms-pageable": { + "nextLinkName": "nextLink", + "itemName": "value" + }, + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ComputeDiagnosticsList" + } + }, + "default": { + "description": "Error response describing why the listing call failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Gets the status of a scheduled disk inspection request.": { + "$ref": "./examples/ListDiagnostics.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics/diskInspection": { + "get": { + "tags": [ + "diagnostics_DiskInspection" + ], + "operationId": "DiskInspection_Get", + "description": "Gets a specific Compute diagnostic for a subscription in a location.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ComputeDiagnosticBase" + } + }, + "default": { + "description": "Error response describing why the get call failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Gets the status of a scheduled disk inspection request.": { + "$ref": "./examples/GetDiskInspection.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics/diskInspection/registerStorageConfiguration": { + "post": { + "tags": [ + "registerStorageConfiguration" + ], + "operationId": "DiskInspectionStorageConfiguration_Register", + "x-ms-long-running-operation": false, + "description": "Register a storageAccount for a subscription used for DiskInspection", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "storageConfigurationInput", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/StorageConfigurationInput" + }, + "description": "Storage Configuration object supplied in the body of the Post to cache storageAccount for a given subscription." + } + ], + "responses": { + "200": { + "description": "Succeeded" + }, + "default": { + "description": "Error response describing why the register operation failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Create a request for registering a storageAccount information.": { + "$ref": "./examples/RegisterStorageConfiguration.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics/diskInspection/validateStorageConfiguration": { + "post": { + "tags": [ + "validateStorageConfiguration" + ], + "operationId": "DiskInspectionStorageConfiguration_Validate", + "x-ms-long-running-operation": false, + "description": "Validate if a storageAccount configuration exists for a subscription used for DiskInspection.", + "consumes": [ + "application/json" + ], + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/StorageConfigurationResponse" + } + }, + "default": { + "description": "Error response describing why the get call failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Returns storageAccount value for an existing configuration entry": { + "$ref": "./examples/ValidateStorageConfiguration.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics/spotPlacementRecommender": { + "get": { + "tags": [ + "diagnostics_SpotPlacementRecommender" + ], + "operationId": "SpotPlacementRecommender_Get", + "description": "[SOON TO BE DEPRECATED] Gets Spot Placement Recommender diagnostic metadata.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ComputeDiagnosticBase" + } + }, + "default": { + "description": "Error response describing why the get call failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Gets the metadata of Spot Placement Recommender diagnostic.": { + "$ref": "./examples/GetSpotPlacementRecommender.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/diagnostics/spotPlacementRecommender/generate": { + "post": { + "tags": [ + "spotPlacementRecommender" + ], + "operationId": "SpotPlacementRecommender_Post", + "description": "[SOON TO BE DEPRECATED] Generates placement scores for Spot VM skus.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "spotPlacementRecommenderInput", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SpotPlacementRecommenderInput" + }, + "description": "SpotPlacementRecommender object supplied in the body of the Post spot placement recommender operation." + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/SpotPlacementRecommenderResponse" + } + }, + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Returns spot VM placement scores for given configurations.": { + "$ref": "./examples/SpotPlacementRecommender.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/placementScores/spot": { + "get": { + "tags": [ + "placementScores_spot" + ], + "operationId": "SpotPlacementScores_Get", + "description": "Gets Spot Placement Scores metadata.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ComputeDiagnosticBase" + } + }, + "default": { + "description": "Error response describing why the get call failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Gets the metadata of Spot Placement Scores.": { + "$ref": "./examples/GetSpotPlacementScores.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/placementScores/spot/generate": { + "post": { + "tags": [ + "spotPlacementScores" + ], + "operationId": "SpotPlacementScores_Post", + "description": "Generates placement scores for Spot VM skus.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "spotPlacementScoresInput", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/SpotPlacementScoresInput" + }, + "description": "SpotPlacementScores object supplied in the body of the Post spot placement scores operation." + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/SpotPlacementScoresResponse" + } + }, + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Returns spot VM placement scores for given configurations.": { + "$ref": "./examples/GenerateSpotPlacementScores.json" + } + } + } + }, + "/subscriptions/{subscriptionId}/providers/Microsoft.Compute/locations/{location}/vmSizeRecommendations/vmAttributeBased/generate": { + "post": { + "tags": [ + "attributeBasedVMSizeRecommender" + ], + "operationId": "AttributeBasedVMSizeRecommender_Post", + "description": "Generates attribute based VM Size Recommendations.", + "parameters": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/SubscriptionIdParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/LocationParameter" + }, + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/parameters/ApiVersionParameter" + }, + { + "name": "attributeBasedVMSizeRecommenderInput", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/AttributeBasedVMSizeRecommenderInput" + }, + "description": "AttributeBasedVMSizeRecommender object supplied in the body of the Post attribute based VMSize recommender operation." + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/AttributeBasedVMSizeRecommenderResponse" + } + }, + "default": { + "description": "Error response describing why the operation failed.", + "schema": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorResponse" + } + } + }, + "x-ms-examples": { + "Returns VMSize recommendations for given configurations.": { + "$ref": "./examples/GenerateAttributeBasedVMSizeRecommender.json" + } + } + } + } + }, + "definitions": { + "ComputeDiagnosticsList": { + "description": "Lists all available Compute diagnostics for a subscription in a location.", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/ComputeDiagnosticBase" + }, + "description": "The collection of available Compute diagnostics returned by the listing operation." + }, + "nextLink": { + "type": "string", + "description": "The continuation token." + } + } + }, + "ComputeDiagnosticBase": { + "description": "Contains metadata of a diagnostic type", + "type": "object", + "properties": { + "properties": { + "$ref": "#/definitions/DiagnosticProperties" + } + }, + "allOf": [ + { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ProxyResource" + } + ] + }, + "DiagnosticProperties": { + "description": "Contains additional properties of a diagnostic", + "type": "object", + "properties": { + "supportedResourceTypes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Describes what are the supported resource types for a diagnostic." + } + } + }, + "RunDiskInspectionInput": { + "type": "object", + "properties": { + "resourceId": { + "description": "Qualified ID of the resource.", + "type": "string" + }, + "manifest": { + "description": "Name of manifest in order to trigger Disk Inspection.", + "type": "string" + }, + "uploadSasUri": { + "description": "SAS uri to the blob where results will be uploaded.", + "type": "string", + "x-ms-secret": true + } + }, + "required": [ + "resourceId", + "manifest", + "uploadSasUri" + ], + "description": "Data used for requesting a Disk Inspection execution." + }, + "ComputeDiagnosticsOperationResult": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The result of the disk inspection operation." + }, + "responseFields": { + "type": "string", + "description": "The response fields of the disk inspection operation." + }, + "resultStatus": { + "type": "string", + "enum": [ + "Success", + "Failed" + ], + "x-ms-enum": { + "name": "resultStatus", + "modelAsString": true + }, + "description": "Result status of the async operation." + }, + "errorDetail": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorDetail", + "description": "The API error details." + }, + "createdUTC": { + "type": "string", + "format": "date-time", + "description": "The time when the disk inspection was completed." + } + }, + "description": "Api output result when Compute Diagnostic operation is completed." + }, + "StorageConfigurationInput": { + "type": "object", + "properties": { + "storageAccountId": { + "description": "Fully qualified storage account Id. Example: \"/subscriptions/{subId}/resourceGroups/{rgName}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}\"", + "type": "string" + } + }, + "required": [ + "storageAccountId" + ], + "description": "Data used for registering a Storage Account for a Subscription." + }, + "StorageConfigurationResponse": { + "type": "object", + "properties": { + "storageAccountId": { + "type": "string", + "description": "Fully qualified storage account Id. Example: \"/subscriptions/{subId}/resourceGroups/{rgName}/providers/Microsoft.Storage/storageAccounts/{storageAccountName}\"" + } + }, + "description": "Api output result when there is an existing storage configuration entry." + }, + "ErrorResponse": { + "type": "object", + "properties": { + "error": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorDetail" + } + }, + "description": "An error response from the Compute Diagnostic Resource Provider service." + }, + "ErrorDetail": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "The error code." + }, + "target": { + "type": "string", + "description": "The target of the particular error." + }, + "message": { + "type": "string", + "description": "User friendly error message." + }, + "details": { + "type": "array", + "items": { + "$ref": "../../../../../../common-types/resource-management/v5/types.json#/definitions/ErrorDetail" + }, + "description": "The Api error details" + }, + "innerError": { + "$ref": "#/definitions/InnerError", + "description": "The Api inner error" + } + }, + "description": "Error Detail message." + }, + "InnerError": { + "type": "object", + "properties": { + "exceptiontype": { + "type": "string", + "description": "The exception type." + }, + "errordetail": { + "type": "string", + "description": "The internal error message or exception dump." + } + }, + "description": "Inner error details." + }, + "SpotPlacementRecommenderInput": { + "type": "object", + "properties": { + "desiredLocations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The desired regions" + }, + "desiredSizes": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceSize" + }, + "description": "The desired resource SKUs." + }, + "desiredCount": { + "type": "integer", + "format": "int32", + "description": "Desired instance count per region/zone based on the scope." + }, + "availabilityZones": { + "type": "boolean", + "description": "Defines if the scope is zonal or regional." + } + }, + "description": "SpotPlacementRecommender API Input." + }, + "SpotPlacementRecommenderResponse": { + "type": "object", + "properties": { + "desiredLocations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The desired regions" + }, + "desiredSizes": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceSize" + }, + "description": "The desired resource SKUs." + }, + "desiredCount": { + "type": "integer", + "format": "int32", + "description": "Desired instance count per region/zone based on the scope." + }, + "availabilityZones": { + "type": "boolean", + "description": "Defines if the scope is zonal or regional." + }, + "placementScores": { + "type": "array", + "items": { + "$ref": "#/definitions/PlacementScore" + }, + "description": "The spot placement scores." + } + }, + "description": "SpotPlacementRecommender API response." + }, + "SpotPlacementScoresInput": { + "type": "object", + "properties": { + "desiredLocations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The desired regions" + }, + "desiredSizes": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceSize" + }, + "description": "The desired resource SKUs." + }, + "desiredCount": { + "type": "integer", + "format": "int32", + "description": "Desired instance count per region/zone based on the scope." + }, + "availabilityZones": { + "type": "boolean", + "description": "Defines if the scope is zonal or regional." + } + }, + "description": "SpotPlacementScores API Input." + }, + "SpotPlacementScoresResponse": { + "type": "object", + "properties": { + "desiredLocations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The desired regions" + }, + "desiredSizes": { + "type": "array", + "items": { + "$ref": "#/definitions/ResourceSize" + }, + "description": "The desired resource SKUs." + }, + "desiredCount": { + "type": "integer", + "format": "int32", + "description": "Desired instance count per region/zone based on the scope." + }, + "availabilityZones": { + "type": "boolean", + "description": "Defines if the scope is zonal or regional." + }, + "placementScores": { + "type": "array", + "items": { + "$ref": "#/definitions/PlacementScore" + }, + "description": "The spot placement scores." + } + }, + "description": "SpotPlacementScores API response." + }, + "ResourceSize": { + "type": "object", + "properties": { + "sku": { + "type": "string", + "description": "The resource's CRP virtual machine SKU size." + } + }, + "description": "SpotPlacementRecommender API response." + }, + "PlacementScore": { + "type": "object", + "properties": { + "sku": { + "type": "string", + "description": "The resource's CRP virtual machine SKU size." + }, + "region": { + "type": "string", + "description": "The region." + }, + "availabilityZone": { + "type": "string", + "description": "The availability region." + }, + "score": { + "type": "string", + "description": "The placement score." + }, + "isQuotaAvailable": { + "type": "boolean", + "description": "Whether the desired quota is available." + } + }, + "description": "The spot placement score for sku/region/zone combination." + }, + "AttributeBasedVMSizeRecommenderInput": { + "type": "object", + "properties": { + "regularPriorityProfile": { + "type": "object", + "items": { + "$ref": "#/definitions/RegularPriorityProfile" + }, + "description": "The regular priority VM profile." + }, + "spotPriorityProfile": { + "type": "object", + "items": { + "$ref": "#/definitions/SpotPriorityProfile" + }, + "description": "The spot priority VM profile." + }, + "recommendationProperties": { + "type": "object", + "items": { + "$ref": "#/definitions/RecommendationProperties" + }, + "description": "The recommendation properties." + }, + "resourceProperties": { + "type": "object", + "items": { + "$ref": "#/definitions/ResourceProperties" + }, + "description": "The resource properties." + } + }, + "description": "AttributeBasedVMSizeRecommender API Input." + }, + "AttributeBasedVMSizeRecommenderResponse": { + "type": "object", + "properties": { + "recommendedVMSizes": { + "type": "object", + "items": { + "$ref": "#/definitions/RecommendedVMSizes" + }, + "description": "The recommended VMSizes." + } + }, + "description": "AttributeBasedVMSizeRecommender API response." + }, + "RegularPriorityProfile": { + "type": "object", + "properties": { + "targetCapacity": { + "type": "integer", + "format": "int32", + "description": "The target capacity." + }, + "capacityUnitType": { + "type": "string", + "description": "The capacity unit type." + } + }, + "description": "Regular Priority Profile for AttributeBasedVmSizeRecommender." + }, + "SpotPriorityProfile": { + "type": "object", + "properties": { + "targetCapacity": { + "type": "integer", + "format": "int32", + "description": "The target capacity." + }, + "capacityUnitType": { + "type": "string", + "description": "The capacity unit type." + }, + "maxPricePerVM": { + "type": "number", + "format": "double", + "description": "The maximum price per spot vm instance." + } + }, + "description": "Spot Priority Profile for AttributeBasedVmSizeRecommender." + }, + "RecommendationProperties": { + "type": "object", + "properties": { + "restrictionsFilter": { + "type": "string", + "description": "The restrictions filters to apply on VMSize recommendations.", + "enum": [ + "QuotaAndOfferRestrictions", + "QuotaRestrictions", + "OfferRestrictions", + "None" + ], + "x-ms-enum": { + "name": "RestrictionsFilterType", + "modelAsString": false + } + } + }, + "description": "Recommendations Properties for AttributeBasedVmSizeRecommender." + }, + "ResourceProperties": { + "type": "object", + "properties": { + "vmAttributes": { + "type": "object", + "items": { + "$ref": "#/definitions/VmAttributes" + }, + "description": "The VM attributes." + } + }, + "description": "Resource Properties for AttributeBasedVmSizeRecommender." + }, + "VmAttributes": { + "type": "object", + "properties": { + "vCpuCount": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxInteger" + }, + "description": "The vCPU count." + }, + "memoryInGiB": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxDouble" + }, + "description": "The memory in GiB." + }, + "memoryInGiBPerVCpu": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxDouble" + }, + "description": "The memory in GiB per vCPU." + }, + "vmCategories": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The vm categories." + }, + "architectureTypes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The cpu architecture types." + }, + "cpuManufacturers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The cpu manufacturers." + }, + "localStorageSupport": { + "type": "string", + "description": "The local storage support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "localStorageDiskTypes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The local storage disk types." + }, + "localStorageInGiB": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxDouble" + }, + "description": "The local storage in GiB." + }, + "dataDiskCount": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxInteger" + }, + "description": "The data disk count." + }, + "ultraSSDSupport": { + "type": "string", + "description": "The ultra ssd support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "hibernationSupport": { + "type": "string", + "description": "The hibernation support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "hyperVGenerations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The Hyper-V Generations." + }, + "networkInterfaceCount": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxInteger" + }, + "description": "The network interface count." + }, + "networkBandwidthInMbps": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxDouble" + }, + "description": "The network bandwidth in Mbps." + }, + "burstableSupport": { + "type": "string", + "description": "The burstable support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "acceleratorSupport": { + "type": "string", + "description": "The accelerator support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "acceleratorTypes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The accelerator types." + }, + "acceleratorManufacturers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The accelerator manufacturers." + }, + "acceleratorCount": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxInteger" + }, + "description": "The accelerator count." + }, + "rdmaSupport": { + "type": "string", + "description": "The rdma support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "rdmaNetworkInterfaceCount": { + "type": "object", + "items": { + "$ref": "#/definitions/VMAttributeMinMaxInteger" + }, + "description": "The rdma network interface count." + }, + "acceleratedNetworkingSupport": { + "type": "string", + "description": "The accelerated networking support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "confidentialVMSupport": { + "type": "string", + "description": "The confidential VM support filter.", + "enum": [ + "Included", + "Required", + "Excluded" + ], + "x-ms-enum": { + "name": "FilterType", + "modelAsString": false + } + }, + "osTypes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of Operation Systems." + }, + "allowedVMSizes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of allowed VMSizes." + }, + "excludedVMSizes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of excluded VMSizes." + } + }, + "description": "VM attributes for AttributeBasedVmSizeRecommender." + }, + "VMAttributeMinMaxInteger": { + "type": "object", + "properties": { + "min": { + "type": "integer", + "format": "int32", + "description": "The minimum value for vm attribute in integer." + }, + "max": { + "type": "integer", + "format": "int32", + "description": "The maximum value for vm attribute in integer." + } + }, + "description": "MinMax values in integer for AttributeBasedVmSizeRecommender." + }, + "VMAttributeMinMaxDouble": { + "type": "object", + "properties": { + "min": { + "type": "number", + "format": "double", + "description": "The minimum value for vm attribute in double." + }, + "max": { + "type": "number", + "format": "double", + "description": "The maximum value for vm attribute in double." + } + }, + "description": "Priority Profile for AttributeBasedVmSizeRecommender." + }, + "RecommendedVMSizes": { + "type": "object", + "properties": { + "regularVMSizes": { + "type": "array", + "items": { + "$ref": "#/definitions/RecommendedVMSizeProperties" + }, + "description": "The regular priority VMSizes." + }, + "spotVMSizes": { + "type": "array", + "items": { + "$ref": "#/definitions/RecommendedVMSizeProperties" + }, + "description": "The spot priority VMSizes." + } + }, + "description": "The regular and spot priority recommended VMSizes." + }, + "RecommendedVMSizeProperties": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of the VMSize." + }, + "size": { + "type": "string", + "description": "The vm size." + }, + "family": { + "type": "string", + "description": "The family of VMSize." + }, + "attributes": { + "type": "object", + "items": { + "$ref": "#/definitions/RecommendedVMSizeAttributes" + }, + "description": "The recommended VMSize attributes." + }, + "restrictions": { + "type": "array", + "items": { + "$ref": "#/definitions/RecommendedVMSizeRestrictions" + }, + "description": "The recommended VMSize restrictions." + } + }, + "description": "The recommended VMSize properties." + }, + "RecommendedVMSizeAttributes": { + "type": "object", + "properties": { + "vCpu": { + "type": "integer", + "format": "int32", + "description": "The vCPU count." + }, + "memoryInGiB": { + "type": "number", + "format": "double", + "description": "The memory in GiB." + }, + "cpuArchitecture": { + "type": "string", + "description": "The cpu architecture of VMSize." + }, + "cpuManufacturer": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The cpu manufacturers." + }, + "networkBandwidthInMbps": { + "type": "number", + "format": "double", + "description": "The network bandwidth in Mbps." + }, + "localStorageSupport": { + "type": "boolean", + "description": "The local storage support flag." + }, + "localStorageType": { + "type": "string", + "description": "The local storage type of VMSize." + }, + "localStorageInGiB": { + "type": "number", + "format": "double", + "description": "The local storage in GiB." + }, + "dataDiskCount": { + "type": "integer", + "format": "int32", + "description": "The data disk count." + }, + "networkInterfaceCount": { + "type": "integer", + "format": "int32", + "description": "The network interface count." + } + }, + "description": "The recommended VMSize attributes." + }, + "RecommendedVMSizeRestrictions": { + "type": "object", + "properties": { + "offerRestrictions": { + "type": "array", + "items": { + "$ref": "#/definitions/VMSizeOfferRestriction" + }, + "description": "The offer restrictions on VMSize." + }, + "quotaRestrictions": { + "type": "array", + "items": { + "$ref": "#/definitions/VMSizeQuotaRestriction" + }, + "description": "The quota restrictions on VMSize." + } + }, + "description": "The restrictions recommended VMSizes." + }, + "VMSizeOfferRestriction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of offer restriction on VMSize.", + "enum": [ + "NotSpecified", + "Location", + "Zone" + ], + "x-ms-enum": { + "name": "ResourceSkuRestrictionType", + "modelAsString": false + } + }, + "values": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of restriction values." + }, + "restrictionInfo": { + "type": "object", + "items": { + "$ref": "#/definitions/VMSizeOfferRestrictionInfo" + }, + "description": "The offer restrictions on VMSize." + }, + "reasonCode": { + "type": "string", + "description": "The offer restriction reason code.", + "enum": [ + "NotSpecified", + "QuotaId", + "NotAvailableForSubscription" + ], + "x-ms-enum": { + "name": "ResourceSkuRestrictionReasonCode", + "modelAsString": false + } + } + }, + "description": "The offer restrictions on recommended VMSize." + }, + "VMSizeOfferRestrictionInfo": { + "type": "object", + "properties": { + "locations": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of restriction locations." + }, + "zones": { + "type": "array", + "items": { + "type": "string" + }, + "description": "The list of restriction zones." + } + }, + "description": "The offer restriction info on recommended VMSize." + }, + "VMSizeQuotaRestriction": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of quota restriction on VMSize.", + "enum": [ + "RegionalVCpu", + "VMFamilyVCpu" + ], + "x-ms-enum": { + "name": "QuotaRestrictionsType", + "modelAsString": false + } + } + }, + "description": "The quota restrictions on recommended VMSize." + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GenerateAttributeBasedVMSizeRecommender.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GenerateAttributeBasedVMSizeRecommender.json new file mode 100644 index 000000000000..d4c7a3211d30 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GenerateAttributeBasedVMSizeRecommender.json @@ -0,0 +1,201 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "api-version": "2025-02-01-preview", + "attributeBasedVMSizeRecommenderInput": { + "regularPriorityProfile": { + "targetCapacity": 1, + "capacityUnitType": "VMInstanceCount" + }, + "spotPriorityProfile": { + "targetCapacity": 1, + "capacityUnitType": "VMInstanceCount", + "maxPricePerVM": 0.200 + }, + "recommendationProperties": { + "restrictionsFilter": "QuotaAndOfferRestrictions" + }, + "resourceProperties": { + "vmAttributes": { + "vCpuCount": { + "Min": 0, + "Max": 0 + }, + "memoryInMiB": { + "Min": 0, + "Max": 0 + }, + "vmCategories": [ + "General Purpose" + ], + "architectureTypes": [ + "x86", + "arm64" + ], + "cpuManufacturers": [ + "Intel", + "AMD" + ], + "localStorageSupport": "included", + "ultraSSDSupport": "included", + "localStorageTypes": [ + "SSD", + "HDD" + ], + "localStorageInMiB": { + "Min": 0, + "Max": 0 + }, + "dataDiskCount": { + "Min": 0, + "Max": 4 + }, + "hibernationSupport": "included", + "hyperVGenerations": [ + "Gen1", + "Gen2" + ], + "networkInterfaceCount": { + "Min": 0, + "Max": 4 + }, + "networkBandwidthInMbps": { + "Min": 0, + "Max": 0 + }, + "confidentialVMSupport": "included", + "burstableSupport": "included", + "acceleratorSupport": "included", + "acceleratorTypes": [ + "FPGA", + "GPU" + ], + "acceleratorManufacturers": [ + "Intel", + "AMD", + "NVidia" + ], + "acceleratorCount": { + "Min": 0, + "Max": 0 + }, + "acceleratedNetworkingSupport": "included", + "rdmaSupport": "included", + "rdmaNetworkInterfaceCount": { + "Min": 0, + "Max": 0 + }, + "osType": [ + "Windows", + "Linux" + ], + "allowedVMSizes": [], + "excludeVMSizes": [] + } + } + } + }, + "responses": { + "200": { + "body": { + "recommendedVMSizes": { + "regularVMSizes": [ + { + "name": "Standard_D4ds_v5", + "size": "D4ds_v5", + "family": "standardDDSv5Family", + "attributes": { + "vCPUs": 4, + "memoryGB": 16, + "cpuArchitecture": "x86", + "cpuManufacturer": "Intel", + "networkBandwidthInMbps": "12500", + "localStorageSupport": "Included", + "localStorageType": "SSD", + "localStorageInGb": 150, + "dataDiskCount": 4, + "networkInterfaceCount": 4 + }, + "restrictions": { + "offerRestrictions": [ + { + "type": "Location", + "values": [ + "westus" + ], + "restrictionInfo": { + "location": [ + "westus" + ], + "zones": [ + "1", + "2", + "3" + ] + }, + "reasonCode": "NotAvailableForSubscription" + } + ], + "quotaRestrictions": [ + { + "type": "RegionalVCpu" + } + ] + } + } + ], + "spotVMSizes": [ + { + "name": "Standard_D4ds_v6", + "size": "D4ds_v5", + "family": "standardDDSv6Family", + "attributes": { + "vCPUs": 4, + "memoryGB": 16, + "cpuArchitecture": "x86", + "cpuManufacturer": "Intel", + "networkBandwidthInMbps": "12500", + "localStorageSupport": "Included", + "localStorageType": "SSD", + "localStorageInGb": 150, + "dataDiskCount": 4, + "networkInterfaceCount": 4 + }, + "restrictions": { + "offerRestrictions": [ + { + "type": "Location", + "values": [ + "westus" + ], + "restrictionInfo": { + "location": [ + "westus" + ], + "zones": [ + "1", + "2", + "3" + ] + }, + "reasonCode": "NotAvailableForSubscription" + } + ], + "quotaRestrictions": [ + { + "type": "RegionalVCpu" + } + ] + } + } + ] + } + }, + "headers": { + "x-ms-request-id": "57b891ab-1fb7-4f5a-b002-71eb6854961f", + "location": "https://management.azure.com/subscriptions/be23ca13-8eb4-4d0e-be10-b00451817956/providers/Microsoft.Compute/locations/eastus/vmSizeRecommendations/vmAttributeBased/generate?api-version=2025-02-01-preview" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GenerateSpotPlacementScores.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GenerateSpotPlacementScores.json new file mode 100644 index 000000000000..a74a41cf2459 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GenerateSpotPlacementScores.json @@ -0,0 +1,85 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "api-version": "2025-02-01-preview", + "spotPlacementScoresInput": { + "desiredLocations": [ + "eastus", + "eastus2" + ], + "desiredSizes": [ + { + "sku": "Standard_D2_v2" + } + ], + "desiredCount": 1, + "availabilityZones": true + } + }, + "responses": { + "200": { + "body": { + "desiredLocations": [ + "eastus", + "eastus2" + ], + "desiredSizes": [ + { + "sku": "Standard_D2_v2" + } + ], + "desiredCount": 1, + "availabilityZones": true, + "placementScores": [ + { + "sku": "Standard_D2_v2", + "region": "eastus", + "availabilityZone": "1", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus", + "availabilityZone": "2", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus", + "availabilityZone": "3", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus2", + "availabilityZone": "1", + "score": "DataNotFoundOrStale", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus2", + "availabilityZone": "2", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus2", + "availabilityZone": "3", + "score": "High", + "isQuotaAvailable": true + } + ] + }, + "headers": { + "x-ms-request-id": "57b891ab-1fb7-4f5a-b002-71eb6854961f", + "location": "https://management.azure.com/subscriptions/be23ca13-8eb4-4d0e-be10-b00451817956/providers/Microsoft.Compute/locations/eastus/placementScores/spot/generate?api-version=2025-02-01-preview" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetDiagnosticOperation.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetDiagnosticOperation.json new file mode 100644 index 000000000000..d16a6301fe62 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetDiagnosticOperation.json @@ -0,0 +1,29 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "operationId": "{operation-id}", + "api-version": "2025-02-01-preview" + }, + "responses": { + "200": { + "body": { + "message": "DiskInspection for selected resource succeeded.", + "createdUTC": "2024-03-05T22:15:44.2986354Z", + "resultStatus": "Success", + "errorDetail": null + }, + "headers": { + "x-ms-request-id": "57b891ab-1fb7-4f5a-b002-71eb6854961f", + "location": "https://westcentralus.diagnostic.compute.azure.com/subscriptions/88fd8cb2-8248-499e-9a2d-4929a4b0133c/providers/Microsoft.Compute/locations/southcentralus/diagnosticOperations/57b891ab-1fb7-4f5a-b002-71eb6854961f" + } + }, + "202": { + "headers": { + "Retry-After": "120000", + "x-ms-request-id": "57b891ab-1fb7-4f5a-b002-71eb6854961f", + "location": "https://westcentralus.diagnostic.compute.azure.com/subscriptions/88fd8cb2-8248-499e-9a2d-4929a4b0133c/providers/Microsoft.Compute/locations/southcentralus/diagnosticOperations/57b891ab-1fb7-4f5a-b002-71eb6854961f" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetDiskInspection.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetDiskInspection.json new file mode 100644 index 000000000000..0556ca00e927 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetDiskInspection.json @@ -0,0 +1,23 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus" + }, + "responses": { + "200": { + "headers": { + "x-ms-request-id": "27b7c568-16ec-46f3-bcf1-5bea3f2529b1" + }, + "body": { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/eastus/diagnostics/diskInspection", + "name": "diskInspection", + "type": "Microsoft.Compute/locations/diagnostics", + "properties": { + "supportedResourceTypes": [ + "Microsoft.Compute/virtualMachines" + ] + } + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetSpotPlacementRecommender.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetSpotPlacementRecommender.json new file mode 100644 index 000000000000..c62e24870102 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetSpotPlacementRecommender.json @@ -0,0 +1,23 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus" + }, + "responses": { + "200": { + "headers": { + "x-ms-request-id": "27b7c568-16ec-46f3-bcf1-5bea3f2529b1" + }, + "body": { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/eastus/diagnostics/spotPlacementRecommender", + "name": "spotPlacementRecommender", + "type": "Microsoft.Compute/locations/diagnostics", + "properties": { + "supportedResourceTypes": [ + "Microsoft.Compute/virtualMachines" + ] + } + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetSpotPlacementScores.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetSpotPlacementScores.json new file mode 100644 index 000000000000..b7ab7d0e7bbd --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/GetSpotPlacementScores.json @@ -0,0 +1,23 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus" + }, + "responses": { + "200": { + "headers": { + "x-ms-request-id": "27b7c568-16ec-46f3-bcf1-5bea3f2529b1" + }, + "body": { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/placementScores/spot", + "name": "spotPlacementScores", + "type": "Microsoft.Compute/placementScores", + "properties": { + "supportedResourceTypes": [ + "Microsoft.Compute/virtualMachines" + ] + } + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/ListDiagnostics.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/ListDiagnostics.json new file mode 100644 index 000000000000..e81b89d721e5 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/ListDiagnostics.json @@ -0,0 +1,47 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus" + }, + "responses": { + "200": { + "headers": { + "x-ms-request-id": "27b7c568-16ec-46f3-bcf1-5bea3f2529b1" + }, + "body": { + "value": [ + { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/eastus/diagnostics/diskInspection", + "name": "diskInspection", + "type": "Microsoft.Compute/locations/diagnostics", + "properties": { + "supportedResourceTypes": [ + "Microsoft.Compute/virtualMachines" + ] + } + }, + { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/{location}/diagnostics/spotPlacementRecommender", + "name": "spotPlacementRecommender", + "type": "Microsoft.Compute/locations/diagnostics", + "properties": { + "supportedResourceTypes": [ + "Microsoft.Compute/virtualMachines" + ] + } + }, + { + "id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Compute/locations/{location}/placementScores/spot", + "name": "spotPlacementRecommender", + "type": "Microsoft.Compute/placementScores", + "properties": { + "supportedResourceTypes": [ + "Microsoft.Compute/virtualMachines" + ] + } + } + ] + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/RegisterStorageConfiguration.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/RegisterStorageConfiguration.json new file mode 100644 index 000000000000..c53b212af6b3 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/RegisterStorageConfiguration.json @@ -0,0 +1,17 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "api-version": "2025-02-01-preview", + "storageConfigurationInput": { + "storageAccountId": "/subscriptions/88fd8cb2-8248-499e-9a2d-4929a4b0133c/resourceGroups/az-iid-blobtest/providers/Microsoft.Storage/storageAccounts/aziidblobtest" + } + }, + "responses": { + "200": { + "headers": { + "x-ms-request-id": "fa55b700-8218-42b1-a3e3-1794cfd37629" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/RunDiskInspection.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/RunDiskInspection.json new file mode 100644 index 000000000000..6374d356fba2 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/RunDiskInspection.json @@ -0,0 +1,20 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "api-version": "2025-02-01-preview", + "runDiskInspectionInput": { + "resourceId": "/subscriptions/88fd8cb2-8248-499e-9a2d-4929a4b0133c/resourceGroups/cladtest1/providers/Microsoft.Compute/virtualMachines/adVM", + "manifest": "diagnostic", + "uploadSasUri": "testSasUri" + } + }, + "responses": { + "202": { + "headers": { + "x-ms-request-id": "57b891ab-1fb7-4f5a-b002-71eb6854961f", + "location": "https://westcentralus.diagnostic.compute.azure.com/subscriptions/88fd8cb2-8248-499e-9a2d-4929a4b0133c/providers/Microsoft.Compute/locations/southcentralus/diagnosticOperations/57b891ab-1fb7-4f5a-b002-71eb6854961f" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/SpotPlacementRecommender.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/SpotPlacementRecommender.json new file mode 100644 index 000000000000..ae5e81e1bcb1 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/SpotPlacementRecommender.json @@ -0,0 +1,85 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "api-version": "2025-02-01-preview", + "spotPlacementRecommenderInput": { + "desiredLocations": [ + "eastus", + "eastus2" + ], + "desiredSizes": [ + { + "sku": "Standard_D2_v2" + } + ], + "desiredCount": 1, + "availabilityZones": true + } + }, + "responses": { + "200": { + "body": { + "desiredLocations": [ + "eastus", + "eastus2" + ], + "desiredSizes": [ + { + "sku": "Standard_D2_v2" + } + ], + "desiredCount": 1, + "availabilityZones": true, + "placementScores": [ + { + "sku": "Standard_D2_v2", + "region": "eastus", + "availabilityZone": "1", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus", + "availabilityZone": "2", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus", + "availabilityZone": "3", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus2", + "availabilityZone": "1", + "score": "DataNotFoundOrStale", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus2", + "availabilityZone": "2", + "score": "High", + "isQuotaAvailable": true + }, + { + "sku": "Standard_D2_v2", + "region": "eastus2", + "availabilityZone": "3", + "score": "High", + "isQuotaAvailable": true + } + ] + }, + "headers": { + "x-ms-request-id": "57b891ab-1fb7-4f5a-b002-71eb6854961f", + "location": "https://management.azure.com/subscriptions/be23ca13-8eb4-4d0e-be10-b00451817956/providers/Microsoft.Compute/locations/eastus/diagnostics/spotplacementrecommender/generate?api-version=2025-02-01-preview" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/ValidateStorageConfiguration.json b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/ValidateStorageConfiguration.json new file mode 100644 index 000000000000..39066f0063f4 --- /dev/null +++ b/specification/compute/resource-manager/Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/examples/ValidateStorageConfiguration.json @@ -0,0 +1,17 @@ +{ + "parameters": { + "subscriptionId": "00000000-0000-0000-0000-000000000000", + "location": "eastus", + "api-version": "2025-02-01-preview" + }, + "responses": { + "200": { + "headers": { + "x-ms-request-id": "27b7c568-16ec-46f3-bcf1-5bea3f2529b1" + }, + "body": { + "storageAccountId": "/subscriptions/88fd8cb2-8248-499e-9a2d-4929a4b0133c/resourceGroups/az-iid-blobtest/providers/Microsoft.Storage/storageAccounts/aziidblobtest" + } + } + } +} diff --git a/specification/compute/resource-manager/Microsoft.Compute/suppressions.yaml b/specification/compute/resource-manager/Microsoft.Compute/suppressions.yaml index a801dff0e896..ee80746fcc21 100644 --- a/specification/compute/resource-manager/Microsoft.Compute/suppressions.yaml +++ b/specification/compute/resource-manager/Microsoft.Compute/suppressions.yaml @@ -1,3 +1,6 @@ - tool: TypeSpecRequirement path: DiagnosticRP/preview/2024-06-01-preview/**/*.json reason: CDRP service not yet ready to migrate to typespec +- tool: TypeSpecRequirement + path: DiagnosticRP/preview/2025-02-01-preview/**/*.json + reason: CDRP service not yet ready to migrate to typespec diff --git a/specification/compute/resource-manager/readme.md b/specification/compute/resource-manager/readme.md index 5cd125cb6f5b..432f4df488f8 100644 --- a/specification/compute/resource-manager/readme.md +++ b/specification/compute/resource-manager/readme.md @@ -2,7 +2,7 @@ > see https://aka.ms/autorest -This is the AutoRest configuration file for Compute. +This is the AutoRest configuration file for Compute.. The compute RP comprises of small services where each service has its own tag. Hence, each sub-service has its own swagger spec. @@ -34,7 +34,7 @@ These are the global settings for the Compute API. title: ComputeManagementClient description: Compute Client openapi-type: arm -tag: package-2024-11-04 +tag: package-2025-02-01-preview directive: - where: @@ -269,6 +269,12 @@ suppressions: from: diagnostic.json - code: XmsPageableForListCalls reason: False positive error as API Path does not match ARM Lint check formatting, requesting to suppress due to approval from reviewer. + from: diagnostic.json + - code: DefinitionsPropertiesNamesCamelCase + reason: The property name contains abbreviations and need to keep it as upper case. + from: diagnostic.json + - code: BodyTopLevelProperties + reason: The is the additional property bag to introduce new nonbreaking properties. from: diagnostic.json - code: PatchResponseCodes reason: PATCH and PUT follow the same behavior and response codes in Compute. Keeping it for legacy reasons. @@ -288,6 +294,42 @@ suppressions: reason: Existing issue from last version. ``` +### Tag: package-2025-02-01-preview + +These settings apply only when `--tag=package-2025-02-01-preview` is specified on the command line. + +```yaml $(tag) == 'package-2025-02-01-preview' +input-file: + - Microsoft.Compute/DiagnosticRP/preview/2025-02-01-preview/diagnostic.json + - Microsoft.Compute/common-types/v1/common.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/computeRPCommon.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/virtualMachineScaleSet.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/virtualMachine.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/virtualMachineImage.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/virtualMachineExtensionImage.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/availabilitySet.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/proximityPlacementGroup.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/dedicatedHost.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/sshPublicKey.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/image.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/restorePoint.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/capacityReservation.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/logAnalytic.json + - Microsoft.Compute/ComputeRP/stable/2024-07-01/runCommand.json + - Microsoft.Compute/DiskRP/stable/2024-03-02/diskRPCommon.json + - Microsoft.Compute/DiskRP/stable/2024-03-02/disk.json + - Microsoft.Compute/DiskRP/stable/2024-03-02/diskAccess.json + - Microsoft.Compute/DiskRP/stable/2024-03-02/diskEncryptionSet.json + - Microsoft.Compute/DiskRP/stable/2024-03-02/diskRestorePoint.json + - Microsoft.Compute/DiskRP/stable/2024-03-02/snapshot.json + - Microsoft.Compute/Skus/stable/2021-07-01/skus.json + - Microsoft.Compute/GalleryRP/stable/2024-03-03/galleryRPCommon.json + - Microsoft.Compute/GalleryRP/stable/2024-03-03/gallery.json + - Microsoft.Compute/GalleryRP/stable/2024-03-03/sharedGallery.json + - Microsoft.Compute/GalleryRP/stable/2024-03-03/communityGallery.json + - Microsoft.Compute/CloudserviceRP/stable/2024-11-04/cloudService.json +``` + ### Tag: package-2024-11-04 These settings apply only when `--tag=package-2024-11-04` is specified on the command line. diff --git a/specificationRepositoryConfiguration.json b/specificationRepositoryConfiguration.json index 0b2c1930d549..7a0e48278243 100644 --- a/specificationRepositoryConfiguration.json +++ b/specificationRepositoryConfiguration.json @@ -13,12 +13,14 @@ "configFilePath": "eng/automation/swagger_to_sdk_config.json" }, "azure-sdk-for-js": { - "integrationRepository": "azure-sdk/azure-sdk-for-js", - "mainRepository": "Azure/azure-sdk-for-js" + "integrationRepository": "test-repo-billy/azure-sdk-for-js", + "mainBranch": "test_repo_breaking_change_mlc", + "mainRepository": "test-repo-billy/azure-sdk-for-js" }, "azure-sdk-for-net": { "integrationRepository": "azure-sdk/azure-sdk-for-net", - "mainRepository": "Azure/azure-sdk-for-net", + "mainRepository": "pshao25/azure-sdk-for-net", + "mainBranch": "computeMigrationReadmeUpdate", "configFilePath": "eng/swagger_to_sdk_config.json" }, "azure-sdk-for-python": { @@ -44,8 +46,9 @@ "configFilePath": "eng/automation/swagger_to_sdk_config.json" }, "azure-sdk-for-js": { - "integrationRepository": "azure-sdk/azure-sdk-for-js-pr", - "mainRepository": "Azure/azure-sdk-for-js-pr" + "integrationRepository": "test-repo-billy/azure-sdk-for-js", + "mainBranch": "test_repo_breaking_change_mlc", + "mainRepository": "test-repo-billy/azure-sdk-for-js" }, "azure-sdk-for-net": { "integrationRepository": "azure-sdk/azure-sdk-for-net-pr",