Unify managed identity practice across modules (#1289)
* wip * wip * wip * wip * wip * get+put * fix * add preprocess method * remove mi by setting identitytype as none * move handler to a sperate method * add directive * remove mapping from new-object cmdlet * remove patch for mi-suppported update cmdlet * skip preprocess mi parameter if identitytype doesn't exist * bug fix * skip using getput to replace patch if no identity type exists * bug fix * remove hardcode for UserAssignedIdentityTypeDeclaration * rush lint --fix * rush lint --fix * remove extra space * support system assigned identity only scenario * polish * fix internal cmdlets * get+put update identity type only * add fallback logic if replacement is failed * add tranform in last layer * allow skip renaming identityuserassignedidentity to userassignedidentity * wip * Update powershell/cmdlets/class.ts * handle identitytype case * revert changes for psproxyoutput * fix typo * handle userassignedid case * fix rush lint * fix the case that variant is removed by directive so that operation contains identity type but variant doesn't contain identity type * Calculate UserAssignedIdentity from string array * if UserAssignedIdentity is a string array, use Length instead of Count to obtain amount * calculate UserAssignedIdentity if contains UserAssignedIdentity in CommandType.Atomic case * rush lint fix * Fix UserAssignedIdentity is empty hashtable * Fixed UserAssignedIdentity is renamed * Fixed UserAssignedIdentity is renamed, read name from virtual property * add get+put as OperationType.Update * consider set command as operationType.create * Should be required if getput for managedidentityupdate
This commit is contained in:
Родитель
882e8e2a42
Коммит
cc041291be
|
@ -12,10 +12,10 @@ import { escapeString, docComment, serialize, pascalCase, DeepPartial, camelCase
|
|||
import { items, values, Dictionary, length } from '@azure-tools/linq';
|
||||
import {
|
||||
Access, Attribute, BackedProperty, Catch, Class, ClassType, Constructor, dotnet, Else, Expression, Finally, ForEach, If, LambdaProperty, LiteralExpression, LocalVariable, Method, Modifier, Namespace, OneOrMoreStatements, Parameter, Property, Return, Statements, BlockStatement, StringExpression,
|
||||
Switch, System, TerminalCase, toExpression, Try, Using, valueOf, Field, IsNull, Or, ExpressionOrLiteral, TerminalDefaultCase, xmlize, TypeDeclaration, And, IsNotNull, PartialMethod, Case, While, LiteralStatement
|
||||
Switch, System, TerminalCase, toExpression, Try, Using, valueOf, Field, IsNull, Or, ExpressionOrLiteral, TerminalDefaultCase, xmlize, TypeDeclaration, And, IsNotNull, PartialMethod, Case, While, LiteralStatement, Not, ElseIf
|
||||
} from '@azure-tools/codegen-csharp';
|
||||
import { ClientRuntime, EventListener, Schema, ArrayOf, EnumImplementation } from '../llcsharp/exports';
|
||||
import { Alias, ArgumentCompleterAttribute, PSArgumentCompleterAttribute, AsyncCommandRuntime, AsyncJob, CmdletAttribute, ErrorCategory, ErrorRecord, Events, InvocationInfo, OutputTypeAttribute, ParameterAttribute, PSCmdlet, PSCredential, SwitchParameter, ValidateNotNull, verbEnum, GeneratedAttribute, DescriptionAttribute, ExternalDocsAttribute, CategoryAttribute, ParameterCategory, ProfileAttribute, PSObject, InternalExportAttribute, ExportAsAttribute, DefaultRunspace, RunspaceFactory, AllowEmptyCollectionAttribute, DoNotExportAttribute, HttpPathAttribute, NotSuggestDefaultParameterSetAttribute } from '../internal/powershell-declarations';
|
||||
import { NullableBoolean, Alias, ArgumentCompleterAttribute, PSArgumentCompleterAttribute, AsyncCommandRuntime, AsyncJob, CmdletAttribute, ErrorCategory, ErrorRecord, Events, InvocationInfo, OutputTypeAttribute, ParameterAttribute, PSCmdlet, PSCredential, SwitchParameter, ValidateNotNull, verbEnum, GeneratedAttribute, DescriptionAttribute, ExternalDocsAttribute, CategoryAttribute, ParameterCategory, ProfileAttribute, PSObject, InternalExportAttribute, ExportAsAttribute, DefaultRunspace, RunspaceFactory, AllowEmptyCollectionAttribute, DoNotExportAttribute, HttpPathAttribute, NotSuggestDefaultParameterSetAttribute } from '../internal/powershell-declarations';
|
||||
import { State } from '../internal/state';
|
||||
import { Channel } from '@autorest/extension-base';
|
||||
import { IParameter } from '@azure-tools/codemodel-v3/dist/code-model/components';
|
||||
|
@ -358,7 +358,7 @@ type operationParameter = {
|
|||
};
|
||||
|
||||
type PreProcess = ((cmdlet: CmdletClass, pathParameters: Array<Expression>, nonPathParameters: Array<Expression | Property>, viaIdentity: boolean) => Statements) | undefined;
|
||||
|
||||
type ProcessGetResponse = ((cmdlet: CmdletClass) => Statements) | undefined;
|
||||
export class CmdletClass extends Class {
|
||||
private cancellationToken!: Expression;
|
||||
public state: State;
|
||||
|
@ -385,6 +385,8 @@ export class CmdletClass extends Class {
|
|||
private responses: Array<Response>;
|
||||
private callbackMethods: Array<LiteralExpression>;
|
||||
private serializationMode: LiteralExpression | undefined;
|
||||
private disableTransformIdentityType?: boolean;
|
||||
private flattenUserAssignedIdentity?: boolean;
|
||||
|
||||
constructor(namespace: Namespace, operation: CommandOperation, state: State, objectInitializer?: DeepPartial<CmdletClass>) {
|
||||
// generate the 'variant' part of the name
|
||||
|
@ -422,6 +424,8 @@ export class CmdletClass extends Class {
|
|||
this.addCommonStuff();
|
||||
this.description = escapeString(this.operation.details.csharp.description);
|
||||
const $this = this;
|
||||
this.disableTransformIdentityType = await $this.state.getValue('disable-transform-identity-type', false);
|
||||
this.flattenUserAssignedIdentity = await $this.state.getValue('flatten-userassignedidentity', true);
|
||||
|
||||
this.add(new Method('BeginProcessing', dotnet.Void, {
|
||||
override: Modifier.Override,
|
||||
|
@ -856,12 +860,18 @@ export class CmdletClass extends Class {
|
|||
// make the call.
|
||||
let preProcess: PreProcess;
|
||||
switch ($this.operation.commandType) {
|
||||
case CommandType.ManagedIdentityUpdate:
|
||||
preProcess = $this.ContainsIdentityTypeParameter() ? $this.ManagedIdentityUpdateCmdletPreProcess : undefined;
|
||||
break;
|
||||
case CommandType.GetPut:
|
||||
preProcess = $this.GetPutPreProcess;
|
||||
break;
|
||||
case CommandType.ManagedIdentityNew:
|
||||
preProcess = $this.ContainsIdentityTypeParameter() && $this.ContainsUserAssignedIdentityParameter() ? $this.ManagedIdentityPreProcessForNewVerbCmdlet : undefined;
|
||||
break;
|
||||
case CommandType.Atomic:
|
||||
default:
|
||||
preProcess = undefined;
|
||||
preProcess = $this.ContainsUserAssignedIdentityParameter() ? $this.ManagedUserAssignedIdentityPreProcess : undefined;
|
||||
break;
|
||||
}
|
||||
const actualCall = function* () {
|
||||
|
@ -1038,6 +1048,7 @@ export class CmdletClass extends Class {
|
|||
if (serializationMode) {
|
||||
parameters.push(serializationMode);
|
||||
}
|
||||
|
||||
if (preProcess) {
|
||||
yield preProcess($this, pathParameters, [...otherParams.map(each => toExpression(each.value)), dotnet.This, pipeline], true);
|
||||
}
|
||||
|
@ -1069,7 +1080,116 @@ export class CmdletClass extends Class {
|
|||
}
|
||||
}
|
||||
|
||||
private GetPutPreProcess(cmdlet: CmdletClass, pathParams: Array<Expression>, nonPathParams: Array<Expression>, viaIdentity: boolean): Statements {
|
||||
private ContainsSpecifiedParameter(parameterName: string): boolean {
|
||||
return this.operation.details.csharp.virtualParameters?.body?.map(p => p.name)?.includes(parameterName) ?? false;
|
||||
}
|
||||
|
||||
private ContainsIdentityTypeParameter(): boolean {
|
||||
return this.ContainsSpecifiedParameter('IdentityType');
|
||||
}
|
||||
|
||||
private ContainsUserAssignedIdentityParameter(): boolean {
|
||||
return this.ContainsSpecifiedParameter('IdentityUserAssignedIdentity') || this.ContainsSpecifiedParameter('UserAssignedIdentity');
|
||||
}
|
||||
|
||||
private GetUserAssignedIdentityParameterElementType(): string | undefined {
|
||||
return (<DictionarySchema>this.operation.details.csharp.virtualParameters?.body?.filter(p => p.name === 'UserAssignedIdentity' || p.name === 'IdentityUserAssignedIdentity')?.[0]?.schema)?.elementType?.language?.csharp?.fullname;
|
||||
}
|
||||
|
||||
private GetUserAssignedIdentityPropertyTypeDeclaration(): string {
|
||||
const userAssignedIdentityParameter = this.properties.filter(p => p.name === 'UserAssignedIdentity' || p.name === 'IdentityUserAssignedIdentity');
|
||||
return userAssignedIdentityParameter?.[0]?.type?.declaration ?? undefined;
|
||||
}
|
||||
|
||||
private GetUserAssignedIdentityPropertyName(): string {
|
||||
const response = this.responses.filter(re => (<SchemaResponse>re)?.schema?.extensions?.['is-return-object'])?.[0];
|
||||
const props = NewGetAllPublicVirtualProperties((<SchemaResponse>response).schema.language.csharp?.virtualProperties);
|
||||
const userAssignedIdentityParameter = props?.filter(p => p.name === 'UserAssignedIdentity' || p.name === 'IdentityUserAssignedIdentity');
|
||||
return userAssignedIdentityParameter?.[0]?.name ?? undefined;
|
||||
}
|
||||
|
||||
private ManagedUserAssignedIdentityPreProcess(cmdlet: CmdletClass, pathParams: Array<Expression> = [], nonPathParams: Array<Expression> = [], viaIdentity = false): Statements {
|
||||
const $this = cmdlet;
|
||||
if ($this.ContainsUserAssignedIdentityParameter() && $this.flattenUserAssignedIdentity) {
|
||||
return If('this.UserAssignedIdentity?.Length > 0',
|
||||
function* () {
|
||||
yield '// calculate UserAssignedIdentity';
|
||||
yield ForEach('id', 'this.UserAssignedIdentity', `${$this.bodyParameter?.value}.${$this.GetUserAssignedIdentityPropertyName()}.Add(id, new ${$this.GetUserAssignedIdentityParameterElementType()}());`);
|
||||
yield '';
|
||||
}
|
||||
);
|
||||
}
|
||||
return new Statements();
|
||||
}
|
||||
|
||||
private ManagedIdentityPreProcessForNewVerbCmdlet(cmdlet: CmdletClass, pathParams: Array<Expression>, nonPathParams: Array<Expression>, viaIdentity: boolean): Statements {
|
||||
const $this = cmdlet;
|
||||
const preProcessManagedIdentityParametersMethod = new Method('PreProcessManagedIdentityParameters', dotnet.Void, {
|
||||
access: Access.Private
|
||||
});
|
||||
|
||||
const preProcessManagedIdentityParameters = function* () {
|
||||
yield $this.ManagedUserAssignedIdentityPreProcess($this);
|
||||
// if UserAssignedIdentity is a string array, use Length. Otherwise, use Count
|
||||
yield If(`this.UserAssignedIdentity?.${$this.flattenUserAssignedIdentity ? 'Length' : 'Count'} > 0`,
|
||||
function* () {
|
||||
yield '// calculate IdentityType';
|
||||
yield If(`"SystemAssigned".Equals(${$this.bodyParameter?.value}.IdentityType, StringComparison.InvariantCultureIgnoreCase)`, `${$this.bodyParameter?.value}.IdentityType = "SystemAssigned,UserAssigned";`);
|
||||
yield Else(`${$this.bodyParameter?.value}.IdentityType = "UserAssigned";`);
|
||||
});
|
||||
};
|
||||
|
||||
if (!$this.hasMethodWithSameDeclaration(preProcessManagedIdentityParametersMethod)) {
|
||||
preProcessManagedIdentityParametersMethod.add(preProcessManagedIdentityParameters);
|
||||
$this.add(preProcessManagedIdentityParametersMethod);
|
||||
}
|
||||
|
||||
return new Statements(function* () {
|
||||
yield `this.${preProcessManagedIdentityParametersMethod.name}();`;
|
||||
});
|
||||
}
|
||||
|
||||
private ProcessGetResponseForManagedIdentityUpdateCmdlet(cmdlet: CmdletClass): Statements {
|
||||
const $this = cmdlet;
|
||||
const containsUserAssignedIdentity = $this.ContainsUserAssignedIdentityParameter();
|
||||
const preProcessManagedIdentity = function* () {
|
||||
yield new LocalVariable('supportsSystemAssignedIdentity', dotnet.Bool, { initializer: Or('true == this.EnableSystemAssignedIdentity', `null == this.EnableSystemAssignedIdentity && true == ${$this.bodyParameter?.value}?.IdentityType?.Contains("SystemAssigned")`) });
|
||||
yield new LocalVariable('supportsUserAssignedIdentity', dotnet.Bool, { initializer: `${dotnet.False}` });
|
||||
if (containsUserAssignedIdentity) {
|
||||
yield $this.ManagedUserAssignedIdentityPreProcess($this);
|
||||
yield `supportsUserAssignedIdentity = true == this.MyInvocation?.BoundParameters?.ContainsKey("UserAssignedIdentity") && ${$this.flattenUserAssignedIdentity ? 'this.UserAssignedIdentity?.Length' : `((${$this.GetUserAssignedIdentityPropertyTypeDeclaration()})this.MyInvocation?.BoundParameters["UserAssignedIdentity"])?.Count`} > 0 ||
|
||||
true != this.MyInvocation?.BoundParameters?.ContainsKey("UserAssignedIdentity") && true == ${$this.bodyParameter?.value}.IdentityType?.Contains("UserAssigned");`;
|
||||
yield If('!supportsUserAssignedIdentity', function* () {
|
||||
yield `${$this.bodyParameter?.value}.${$this.GetUserAssignedIdentityPropertyName()} = null;`;
|
||||
});
|
||||
yield '';
|
||||
}
|
||||
|
||||
yield '// calculate IdentityType';
|
||||
yield If(And('supportsUserAssignedIdentity', 'supportsSystemAssignedIdentity'), `${$this.bodyParameter?.value}.IdentityType = "SystemAssigned,UserAssigned";`);
|
||||
yield ElseIf(And('supportsUserAssignedIdentity', '!supportsSystemAssignedIdentity'), `${$this.bodyParameter?.value}.IdentityType = "UserAssigned";`);
|
||||
yield ElseIf(And('!supportsUserAssignedIdentity', 'supportsSystemAssignedIdentity'), `${$this.bodyParameter?.value}.IdentityType = "SystemAssigned";`);
|
||||
yield Else(`${$this.bodyParameter?.value}.IdentityType = "None";`);
|
||||
};
|
||||
|
||||
const preProcessManagedIdentityMethod = new Method('PreProcessManagedIdentityParametersWithGetResult', dotnet.Void, {
|
||||
access: Access.Private
|
||||
});
|
||||
|
||||
if (!$this.hasMethodWithSameDeclaration(preProcessManagedIdentityMethod)) {
|
||||
preProcessManagedIdentityMethod.add(preProcessManagedIdentity);
|
||||
$this.add(preProcessManagedIdentityMethod);
|
||||
}
|
||||
return new Statements(function* () {
|
||||
yield `this.${preProcessManagedIdentityMethod.name}();`;
|
||||
});
|
||||
}
|
||||
|
||||
private ManagedIdentityUpdateCmdletPreProcess(cmdlet: CmdletClass, pathParams: Array<Expression>, nonPathParams: Array<Expression>, viaIdentity: boolean): Statements {
|
||||
return cmdlet.GetPutPreProcess(cmdlet, pathParams, nonPathParams, viaIdentity, cmdlet.ProcessGetResponseForManagedIdentityUpdateCmdlet);
|
||||
}
|
||||
|
||||
private GetPutPreProcess(cmdlet: CmdletClass, pathParams: Array<Expression>, nonPathParams: Array<Expression>, viaIdentity: boolean, processGetResponse: ProcessGetResponse = undefined): Statements {
|
||||
const $this = cmdlet;
|
||||
const updateBodyMethod = new Method(`Update${$this.bodyParameter?.value}`, dotnet.Void, {
|
||||
access: Access.Private
|
||||
|
@ -1093,9 +1213,19 @@ export class CmdletClass extends Class {
|
|||
});
|
||||
$this.add(updateBodyMethod);
|
||||
}
|
||||
|
||||
const getPut = function* () {
|
||||
yield `${$this.bodyParameter?.value} = await this.${$this.$<Property>('Client').invokeMethod(httpOperationName, ...[...pathParams, ...nonPathParams]).implementation}`;
|
||||
yield `${$this.bodyParameter?.value} = await this.${$this.$<Property>('Client').invokeMethod(httpOperationName, ...[...pathParams, ...nonPathParams]).implementation} `;
|
||||
// PreProcess body parameter
|
||||
if (processGetResponse) {
|
||||
yield processGetResponse($this);
|
||||
}
|
||||
yield `this.${updateBodyMethod.name}();`;
|
||||
/** Instance:
|
||||
* _requestBodyParametersBody = await this.Client.GrafanaGetWithResult(SubscriptionId, ResourceGroupName, Name, this, Pipeline);
|
||||
* this.Update_requestBodyParametersBody();
|
||||
* */
|
||||
|
||||
};
|
||||
return new Statements(getPut);
|
||||
}
|
||||
|
@ -1650,6 +1780,34 @@ export class CmdletClass extends Class {
|
|||
const nullable = this.state.project.schemaDefinitionResolver.resolveTypeDeclaration(vSchema, !!(<NewVirtualProperty>vParam.origin).required, this.state).isNullable;
|
||||
let cmdletParameter: Property;
|
||||
if (propertyType.schema.type !== SchemaType.Array) {
|
||||
if (vParam.name === 'IdentityType' && !this.disableTransformIdentityType) {
|
||||
const enableSystemAssignedIdentity = new Property('EnableSystemAssignedIdentity', operation.details.csharp.verb.toLowerCase() === 'new' ? SwitchParameter : NullableBoolean, {
|
||||
set: operation.details.csharp.verb.toLowerCase() === 'new' ? toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name} = value.IsPresent ? "SystemAssigned": null `) : undefined
|
||||
});
|
||||
enableSystemAssignedIdentity.description = 'Decides if enable a system assigned identity for the resource.';
|
||||
enableSystemAssignedIdentity.add(new Attribute(ParameterAttribute, { parameters: [new LiteralExpression(`Mandatory = ${vParam.required ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "${escapeString(enableSystemAssignedIdentity.description || '.')}"`)] }));
|
||||
if (length(vParam.alias) > 0) {
|
||||
enableSystemAssignedIdentity.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
|
||||
}
|
||||
this.add(enableSystemAssignedIdentity);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vParam.name === 'IdentityUserAssignedIdentity' || vParam.name === 'UserAssignedIdentity') {
|
||||
if (this.flattenUserAssignedIdentity) {
|
||||
const userAssignedIdentity = new Property('UserAssignedIdentity', dotnet.StringArray);
|
||||
userAssignedIdentity.description = 'The array of user assigned identities associated with the resource. The elements in array will be ARM resource ids in the form: \'/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName}.\'';
|
||||
userAssignedIdentity.add(new Attribute(ParameterAttribute, { parameters: [new LiteralExpression(`Mandatory = ${vParam.required ? 'true' : 'false'}`), new LiteralExpression(`HelpMessage = "${escapeString(userAssignedIdentity.description || '.')}"`)] }));
|
||||
userAssignedIdentity.add(new Attribute(AllowEmptyCollectionAttribute));
|
||||
if (length(vParam.alias) > 0) {
|
||||
userAssignedIdentity.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
|
||||
}
|
||||
this.add(userAssignedIdentity);
|
||||
continue;
|
||||
} else {
|
||||
vParam.name = 'UserAssignedIdentity';
|
||||
}
|
||||
}
|
||||
cmdletParameter = new Property(vParam.name, propertyType, {
|
||||
get: toExpression(`${expandedBodyParameter.value}.${getVirtualPropertyName((<any>vParam.origin)) || vParam.origin.name}${!nullable ? '' : ` ?? ${propertyType.defaultOfType}`}`), // /* ${inspect(vParam.origin)} */
|
||||
// get: toExpression(`null == ${expandedBodyParameter.value}.${vParam.origin.name} ? ${propertyType.defaultOfType} : (${propertyType.declaration}) ${expandedBodyParameter.value}.${vParam.origin.name}`),
|
||||
|
@ -1747,7 +1905,6 @@ export class CmdletClass extends Class {
|
|||
if (length(vParam.alias) > 0) {
|
||||
cmdletParameter.add(new Attribute(Alias, { parameters: vParam.alias.map(x => '"' + x + '"') }));
|
||||
}
|
||||
|
||||
this.add(cmdletParameter);
|
||||
}
|
||||
const paramDictSchema = parameter.schema.type === SchemaType.Dictionary ? parameter.schema :
|
||||
|
@ -2110,7 +2267,7 @@ export class CmdletClass extends Class {
|
|||
if (operation.details.default.externalDocs) {
|
||||
this.add(new Attribute(ExternalDocsAttribute, {
|
||||
parameters: [`${new StringExpression(this.operation.details.default.externalDocs?.url ?? '')}`,
|
||||
`${new StringExpression(this.operation.details.default.externalDocs?.description ?? '')}`]
|
||||
`${new StringExpression(this.operation.details.default.externalDocs?.description ?? '')}`]
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ export const ResourceGroupCompleter: TypeDeclaration = new ClassType(sma, 'Resou
|
|||
export const OutputTypeAttribute: TypeDeclaration = new ClassType(sma, 'OutputType');
|
||||
export const ErrorRecord: TypeDeclaration = new ClassType(sma, 'ErrorRecord');
|
||||
export const SwitchParameter: TypeDeclaration = new ClassType(sma, 'SwitchParameter');
|
||||
export const NullableBoolean: TypeDeclaration = new ClassType(new Namespace('System'), 'Boolean?');
|
||||
export const IArgumentCompleter: IInterface = { allProperties: [], declaration: 'System.Management.Automation.IArgumentCompleter' };
|
||||
export const CompletionResult: TypeDeclaration = new ClassType(sma, 'CompletionResult');
|
||||
export const CommandAst: TypeDeclaration = new ClassType(`${sma}.Language`, 'CommandAst');
|
||||
|
|
|
@ -168,47 +168,60 @@ export /* @internal */ class Inferrer {
|
|||
parameters: new Dictionary<any>(),
|
||||
};
|
||||
const disableGetPut = await this.state.getValue('disable-getput', false);
|
||||
|
||||
const disableTransformIdentityType = await this.state.getValue('disable-transform-identity-type', false);
|
||||
this.state.message({ Channel: Channel.Debug, Text: 'detecting high level commands...' });
|
||||
for (const operationGroup of values(model.operationGroups)) {
|
||||
let hasPatch = false;
|
||||
let commandType!: CommandType;
|
||||
const getOperations: Array<Operation> = [];
|
||||
let putOperation: Operation | undefined;
|
||||
let patchOperation: Operation | undefined;
|
||||
for (const operation of values(operationGroup.operations)) {
|
||||
if (operation.requests?.[0]?.protocol?.http?.method.toLowerCase() === 'patch') {
|
||||
hasPatch = true;
|
||||
patchOperation = operation;
|
||||
// bez: remove patch operation to avoid conflicts with replacements
|
||||
if (!disableTransformIdentityType && this.IsManagedIdentityOperation(operation)) {
|
||||
continue;
|
||||
}
|
||||
} else if (operation.requests?.[0]?.protocol?.http?.method.toLowerCase() === 'get') {
|
||||
getOperations.push(operation);
|
||||
} else if (operation.requests?.[0]?.protocol?.http?.method.toLowerCase() === 'put') {
|
||||
putOperation = operation;
|
||||
if (!disableTransformIdentityType && this.IsManagedIdentityOperation(operation)) {
|
||||
commandType = CommandType.ManagedIdentityNew;
|
||||
}
|
||||
}
|
||||
for (const variant of await this.inferCommandNames(operation, operationGroup.$key, this.state)) {
|
||||
await this.addVariants(operation.parameters, operation, variant, '', this.state);
|
||||
await this.addVariants(operation.parameters, operation, variant, '', this.state, undefined, commandType);
|
||||
}
|
||||
}
|
||||
/*
|
||||
generate variants for Update(Get+Put) for subjects only if:
|
||||
- there is no patch operation
|
||||
- there is a get operation
|
||||
- there is a put operation
|
||||
- get operation path is the same as put operation path
|
||||
- there is only one put reqeust schema
|
||||
- get operation response schema type is the same as put operation request schema type
|
||||
*/
|
||||
if (this.isAzure
|
||||
&& !disableGetPut
|
||||
&& !hasPatch
|
||||
&& getOperations
|
||||
&& putOperation
|
||||
&& putOperation.requests?.length == 1) {
|
||||
|
||||
if (this.isAzure && getOperations && putOperation && putOperation.requests?.length == 1) {
|
||||
const getOperation = getOperations.find(getOperation => getOperation.requests?.[0]?.protocol?.http?.path === putOperation?.requests?.[0]?.protocol?.http?.path);
|
||||
const hasQueryParameter = getOperation?.parameters?.find(p => p.protocol.http?.in === 'query' && p.language.default.name !== 'apiVersion');
|
||||
//parameter.protocal.http.in === 'body' probably only applies to open api 2.0
|
||||
const schema = putOperation?.requests?.[0]?.parameters?.find(p => p.protocol.http?.in === 'body')?.schema;
|
||||
if (getOperation && !hasQueryParameter && schema && [...values(getOperation?.responses)].filter(each => (<SchemaResponse>each).schema !== schema).length === 0) {
|
||||
const supportsCombineGetPutOperation = getOperation && this.supportsGetPut(getOperation, putOperation);
|
||||
if (!disableTransformIdentityType && supportsCombineGetPutOperation &&
|
||||
(hasPatch && patchOperation && this.IsManagedIdentityOperation(patchOperation)
|
||||
|| !hasPatch && putOperation && this.IsManagedIdentityOperation(putOperation))) {
|
||||
await this.addVariants(putOperation.parameters, putOperation, this.createCommandVariant('create', [operationGroup.$key], [], this.state.model), '', this.state, [getOperation], CommandType.ManagedIdentityUpdate);
|
||||
} else if (!disableTransformIdentityType && !supportsCombineGetPutOperation && hasPatch && patchOperation && this.IsManagedIdentityOperation(patchOperation)) {
|
||||
// bez: add patch operation back and disable transforming identity type
|
||||
for (const variant of await this.inferCommandNames(patchOperation, operationGroup.$key, this.state)) {
|
||||
await this.addVariants(patchOperation.parameters, patchOperation, variant, '', this.state);
|
||||
}
|
||||
await this.state.setValue('disable-transform-identity-type', true);
|
||||
} else if (!disableGetPut && !hasPatch && supportsCombineGetPutOperation) {
|
||||
/* generate variants for Update(Get+Put) for subjects only if:
|
||||
- there is a get operation
|
||||
- there is a put operation
|
||||
- get operation path is the same as put operation path
|
||||
- there is only one put request schema
|
||||
- get operation response schema type is the same as put operation request schema type
|
||||
*/
|
||||
await this.addVariants(putOperation.parameters, putOperation, this.createCommandVariant('create', [operationGroup.$key], [], this.state.model), '', this.state, [getOperation], CommandType.GetPut);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// for (const operation of values(model.http.operations)) {
|
||||
// for (const variant of await this.inferCommandNames(operation, this.state)) {
|
||||
|
@ -219,6 +232,30 @@ export /* @internal */ class Inferrer {
|
|||
return model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Judge if the response of get operation can be piped as the input of put operation
|
||||
* 1. there is only one put request schema
|
||||
* 2. get operation response schema type is the same as put operation request schema type
|
||||
*/
|
||||
private supportsGetPut(getOperation: Operation, putOperation: Operation): boolean {
|
||||
const hasQueryParameter = getOperation?.parameters?.find(p => p.protocol.http?.in === 'query' && p.language.default.name !== 'apiVersion');
|
||||
//parameter.protocal.http.in === 'body' probably only applies to open api 2.0
|
||||
const schema = putOperation?.requests?.[0]?.parameters?.find(p => p.protocol.http?.in === 'body')?.schema;
|
||||
return (getOperation && !hasQueryParameter && schema && [...values(getOperation?.responses)].filter(each => (<SchemaResponse>each).schema !== schema).length === 0) ?? false;
|
||||
}
|
||||
|
||||
private containsIdentityType(op: Operation): boolean {
|
||||
const body = op.requests?.[0].parameters?.find((p) => !p.origin || p.origin.indexOf('modelerfour:synthesized') < 0) || null;
|
||||
// property identity in the body parameter
|
||||
const identityProperty = (body && body.schema && isObjectSchema(body.schema)) ? values(getAllProperties(body.schema)).where(property => !property.language.default.readOnly && isObjectSchema(property.schema) && property.language.default.name === 'identity')?.toArray()?.[0] : null;
|
||||
const identityTypeProperty = (identityProperty && identityProperty.schema && isObjectSchema(identityProperty.schema)) ? values(getAllProperties(identityProperty.schema)).where(property => !property.language.default.readOnly && property.language.default.name === 'type')?.toArray()?.[0] : null;
|
||||
return identityTypeProperty !== null && identityTypeProperty !== undefined;
|
||||
}
|
||||
|
||||
private IsManagedIdentityOperation(op: Operation): boolean {
|
||||
return this.containsIdentityType(op);
|
||||
}
|
||||
|
||||
inferCommand(operation: Array<string>, group: string, suffix: Array<string> = []): Array<CommandVariant> {
|
||||
operation = operation.filter(each => each !== 'all');
|
||||
// no instant match
|
||||
|
@ -441,9 +478,11 @@ export /* @internal */ class Inferrer {
|
|||
// Add operation type to support x-ms-mutability
|
||||
let operationType = OperationType.Other;
|
||||
if (operation.requests) {
|
||||
if (operation.requests[0].protocol.http?.method === 'put' && variant.action.toLowerCase() === 'create') {
|
||||
if (operation.requests[0].protocol.http?.method === 'put' && (variant.action.toLowerCase() === 'create' || variant.action.toLowerCase() === 'update' && variant.verb.toLowerCase() === 'set')) {
|
||||
// put create and put set
|
||||
operationType = OperationType.Create;
|
||||
} else if (operation.requests[0].protocol.http?.method === 'patch' && variant.action.toLowerCase() === 'update') {
|
||||
} else if ((operation.requests[0].protocol.http?.method === 'patch' || operation.requests[0].protocol.http?.method === 'put') && variant.action.toLowerCase() === 'update') {
|
||||
// patch update, get+put update and exclude set update
|
||||
operationType = OperationType.Update;
|
||||
}
|
||||
}
|
||||
|
@ -569,7 +608,8 @@ export /* @internal */ class Inferrer {
|
|||
await this.addVariant(pascalCase([variant.action, vname, `via-identity${resourceName}`]), body, bodyParameterName, [...constants, ...otherParams, ...pathParams.slice(i + 1)], operation, variant, state, preOperations, commandType);
|
||||
}
|
||||
|
||||
if (this.supportJsonInput && hasValidBodyParameters(operation) && !commandType) {
|
||||
if (this.supportJsonInput && hasValidBodyParameters(operation) &&
|
||||
commandType != CommandType.GetPut && commandType != CommandType.ManagedIdentityUpdate) {
|
||||
const createStringParameter = (name: string, description: string, serializedName: string): IParameter => {
|
||||
const schema = new SchemaModel(name, description, SchemaType.String);
|
||||
const language = {
|
||||
|
|
|
@ -213,7 +213,6 @@ function createVirtualProperties(schema: ObjectSchema, stack: Array<string>, thr
|
|||
required: property.required || property.language.default.required,
|
||||
};
|
||||
virtualProperties.owned.push(privateProperty);
|
||||
|
||||
for (const inlinedProperty of [...virtualChildProperties.inherited, ...virtualChildProperties.owned]) {
|
||||
// child properties are be inlined without prefixing the name with the property name
|
||||
// unless there is a collision, in which case, we have to resolve
|
||||
|
@ -376,7 +375,6 @@ function createVirtualParameters(operation: CommandOperation) {
|
|||
} else if (operation.operationType === OperationType.Update && !(<VirtualProperty>virtualProperty).update) {
|
||||
continue;
|
||||
}
|
||||
|
||||
virtualParameters.body.push({
|
||||
name: virtualProperty.name,
|
||||
description: virtualProperty.property.language.default.description,
|
||||
|
@ -411,7 +409,6 @@ function createVirtualParameters(operation: CommandOperation) {
|
|||
operation.details.default.virtualParameters = virtualParameters;
|
||||
}
|
||||
|
||||
|
||||
async function createVirtuals(state: State): Promise<PwshModel> {
|
||||
/*
|
||||
A model class should provide inlined properties for anything in a property called properties
|
||||
|
@ -422,7 +419,6 @@ async function createVirtuals(state: State): Promise<PwshModel> {
|
|||
*/
|
||||
const threshold = await state.getValue('inlining-threshold', 24);
|
||||
const conflicts = new Array<string>();
|
||||
|
||||
for (const schema of values(state.model.schemas.objects)) {
|
||||
// did we already inline this objecct
|
||||
if (schema.language.default.inlined) {
|
||||
|
@ -450,7 +446,7 @@ async function createVirtuals(state: State): Promise<PwshModel> {
|
|||
}
|
||||
|
||||
function shouldBeRequired(operation: CommandOperation, virtualProperty: VirtualProperty): boolean {
|
||||
const shouldBeOptional = operation.commandType === CommandType.GetPut;
|
||||
const shouldBeOptional = operation.commandType === CommandType.GetPut || operation.commandType === CommandType.ManagedIdentityUpdate;
|
||||
if (!shouldBeOptional) {
|
||||
return virtualProperty.required;
|
||||
}
|
||||
|
|
|
@ -70,9 +70,8 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
var variantGroups = profileGroups.SelectMany(pg => pg.Variants
|
||||
.GroupBy(v => new { v.CmdletName, v.IsInternal })
|
||||
.Select(vg => new VariantGroup(ModuleName, vg.Key.CmdletName, vg.Select(v => v).ToArray(),
|
||||
Path.Combine(vg.Key.IsInternal ? InternalFolder : ExportsFolder, pg.ProfileFolder), pg.ProfileName, isInternal: vg.Key.IsInternal)))
|
||||
Path.Combine(vg.Key.IsInternal ? InternalFolder : ExportsFolder, pg.ProfileFolder), pg.ProfileName, isInternal: vg.Key.IsInternal)))
|
||||
.ToArray();
|
||||
|
||||
var license = new StringBuilder();
|
||||
license.Append(@"
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
@ -103,6 +102,7 @@ ${$project.pwshCommentHeaderForCsharp}
|
|||
|
||||
sb.Append("param(");
|
||||
sb.Append($"{(parameterGroups.Any() ? Environment.NewLine : String.Empty)}");
|
||||
|
||||
foreach (var parameterGroup in parameterGroups)
|
||||
{
|
||||
var parameters = parameterGroup.HasAllVariants ? parameterGroup.Parameters.Take(1) : parameterGroup.Parameters;
|
||||
|
|
|
@ -188,6 +188,7 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
public VariantGroup VariantGroup { get; }
|
||||
|
||||
protected static readonly bool IsAzure = Convert.ToBoolean(@"${$project.azure}");
|
||||
|
||||
public BaseOutput(VariantGroup variantGroup)
|
||||
{
|
||||
VariantGroup = variantGroup;
|
||||
|
@ -295,6 +296,7 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class ProcessOutput : BaseOutput
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
{
|
||||
public string ModuleName { get; }
|
||||
|
||||
public string RootModuleName {get => @"${$project.rootModuleName}";}
|
||||
public string RootModuleName { get => @"${$project.rootModuleName}"; }
|
||||
public string CmdletName { get; }
|
||||
public string CmdletVerb { get; }
|
||||
public string CmdletNoun { get; }
|
||||
|
@ -49,7 +49,6 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
public PsHelpInfo HelpInfo { get; }
|
||||
public bool IsGenerated { get; }
|
||||
public bool IsInternal { get; }
|
||||
|
||||
public string OutputFolder { get; }
|
||||
public string FileName { get; }
|
||||
public string FilePath { get; }
|
||||
|
@ -84,7 +83,6 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
HelpInfo = Variants.Select(v => v.HelpInfo).FirstOrDefault() ?? new PsHelpInfo();
|
||||
IsGenerated = Variants.All(v => v.Attributes.OfType<GeneratedAttribute>().Any());
|
||||
IsInternal = isInternal;
|
||||
|
||||
OutputFolder = outputFolder;
|
||||
FileName = $"{CmdletName}{(isTest ? ".Tests" : String.Empty)}.ps1";
|
||||
FilePath = Path.Combine(OutputFolder, FileName);
|
||||
|
@ -258,7 +256,6 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
public ParameterMetadata Metadata { get; }
|
||||
public PsParameterHelpInfo HelpInfo { get; }
|
||||
public Type ParameterType { get; }
|
||||
|
||||
public Attribute[] Attributes { get; }
|
||||
public ParameterCategory[] Categories { get; }
|
||||
public ParameterCategory OrderCategory { get; }
|
||||
|
@ -334,7 +331,7 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
public bool Required { get; }
|
||||
public bool ReadOnly { get; }
|
||||
public string Description { get; }
|
||||
|
||||
|
||||
public ComplexInterfaceInfo[] NestedInfos { get; }
|
||||
public bool IsComplexInterface { get; }
|
||||
|
||||
|
@ -351,7 +348,7 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
var unwrappedType = Type.Unwrap();
|
||||
var hasBeenSeen = seenTypes?.Contains(unwrappedType) ?? false;
|
||||
(seenTypes ?? (seenTypes = new List<Type>())).Add(unwrappedType);
|
||||
NestedInfos = hasBeenSeen ? new ComplexInterfaceInfo[]{} :
|
||||
NestedInfos = hasBeenSeen ? new ComplexInterfaceInfo[] { } :
|
||||
unwrappedType.GetInterfaces()
|
||||
.Concat(InfoAttribute.PossibleTypes)
|
||||
.SelectMany(pt => pt.GetProperties()
|
||||
|
@ -440,7 +437,7 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
}
|
||||
}
|
||||
|
||||
internal class PSArgumentCompleterInfo: CompleterInfo
|
||||
internal class PSArgumentCompleterInfo : CompleterInfo
|
||||
{
|
||||
public string[] ResourceTypes { get; }
|
||||
|
||||
|
@ -511,7 +508,8 @@ namespace Microsoft.Rest.ClientRuntime.PowerShell
|
|||
parameterHelp = parameterHelp.Where(ph => (!ph.ParameterSetNames.Any() || ph.ParameterSetNames.Any(psn => psn == variant.VariantName || psn == AllParameterSets)) && ph.Name != "IncludeTotalCount");
|
||||
}
|
||||
var result = parameters.Select(p => new Parameter(variant.VariantName, p.Key, p.Value, parameterHelp.FirstOrDefault(ph => ph.Name == p.Key)));
|
||||
if (variant.SupportsPaging) {
|
||||
if (variant.SupportsPaging)
|
||||
{
|
||||
// If supportsPaging is set, we will need to add First and Skip parameters since they are treated as common parameters which as not contained on Metadata>parameters
|
||||
variant.Info.Parameters["First"].Attributes.OfType<ParameterAttribute>().FirstOrDefault(pa => pa.ParameterSetName == variant.VariantName || pa.ParameterSetName == AllParameterSets).HelpMessage = "Gets only the first 'n' objects.";
|
||||
variant.Info.Parameters["Skip"].Attributes.OfType<ParameterAttribute>().FirstOrDefault(pa => pa.ParameterSetName == variant.VariantName || pa.ParameterSetName == AllParameterSets).HelpMessage = "Ignores the first 'n' objects and then gets the remaining objects.";
|
||||
|
|
|
@ -62,7 +62,9 @@ export interface VirtualParameter {
|
|||
|
||||
export enum CommandType {
|
||||
Atomic,
|
||||
GetPut
|
||||
GetPut,
|
||||
ManagedIdentityUpdate,
|
||||
ManagedIdentityNew
|
||||
}
|
||||
|
||||
export class CommandOperation extends Extensions implements CommandOperation {
|
||||
|
|
Загрузка…
Ссылка в новой задаче