-
Notifications
You must be signed in to change notification settings - Fork 54
Add Rpaas_ResourceProvisioningState, improve TopLevelResourcesListByResourceGroup #234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
7245d5c
1f7a753
6fc5ac4
27fcac8
96c6b4f
5780a5a
b82c1fa
b609e9d
2ce4bbc
bf753e5
7360ff3
f4ffd27
b72475c
83cf34e
242c163
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| # Ignore compiled files | ||
| src/**/*.js | ||
| regression/**/*.js | ||
| src/**/*.map | ||
| src/**/*.d.ts | ||
| node_modules/ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /*--------------------------------------------------------------------------------------------- | ||
| * Copyright (c) Microsoft Corporation. All rights reserved. | ||
| * Licensed under the MIT License. See License.txt in the project root for license information. | ||
| *--------------------------------------------------------------------------------------------*/ | ||
| import { MergeStates, OpenApiTypes, rules } from "../rule" | ||
| import { ResourceUtils } from "./utilities/resourceUtils" | ||
| import { JsonPath } from "../../jsonrpc/types" | ||
| export const Rpaas_ResourceProvisioningState: string = "Rpaas_ResourceProvisioningState" | ||
|
|
||
| rules.push({ | ||
| id: "R4031", | ||
| name: Rpaas_ResourceProvisioningState, | ||
| severity: "error", | ||
| category: "RPaaSViolation", | ||
| mergeState: MergeStates.individual, | ||
| openapiType: OpenApiTypes.rpaas, | ||
| appliesTo_JsonQuery: "$", | ||
| *run(doc, node, path) { | ||
| const msg = `The resource {0} is defined without 'provisioningState' in properties bag, consider adding the provisioningState for it.` | ||
| const utils = new ResourceUtils(doc) | ||
| const allResources = utils.getAllResource() | ||
| for (const resource of allResources) { | ||
| const model = utils.getResourceByName(resource) | ||
| const properties = utils.getPropertyOfModel(model,"properties") | ||
| let hasProvisioningState = false | ||
| if (properties && (!properties.type || properties.type === "object")) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If type undefined, is it valid?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, undefined type equals to "object" |
||
| if (utils.getPropertyOfModel(properties,"provisioningState")) { | ||
| hasProvisioningState = true | ||
| } | ||
|
|
||
| } | ||
| if (!hasProvisioningState) { | ||
| yield { message: msg.replace("{0}", resource), | ||
| location: ["$", "definitions", resource] as JsonPath} | ||
| } | ||
| } | ||
| } | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -82,7 +82,7 @@ export class ResourceUtils { | |
| } | ||
| } | ||
|
|
||
| private getResourceByName(modelName: string) { | ||
| public getResourceByName(modelName: string) { | ||
| if (!modelName) { | ||
| return undefined | ||
| } | ||
|
|
@@ -132,6 +132,10 @@ export class ResourceUtils { | |
| } | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Get all resources which allOf a x-ms-resource | ||
| */ | ||
| public getAllOfResources() { | ||
| const keys = Object.keys(this.innerDoc.definitions as object) | ||
| const AllOfResources = keys.reduce((pre, cur) => { | ||
|
|
@@ -195,6 +199,42 @@ export class ResourceUtils { | |
| } | ||
| return topLevelModels | ||
| } | ||
|
|
||
| public getTopLevelResourcesByRG() { | ||
| const fullModels = this.getOperationGetResponseResources() | ||
| const topLevelModels = new Set<string>() | ||
| for (const entry of fullModels.entries()) { | ||
| const paths = entry[1] | ||
|
jianyexi marked this conversation as resolved.
|
||
| paths | ||
| .filter(p => this.isPathByResourceGroup(p)) | ||
| .some(p => { | ||
| const hierarchy = this.getResourcesTypeHierarchy(p) | ||
| if (hierarchy.length === 1) { | ||
| topLevelModels.add(entry[0]) | ||
| return true | ||
| } | ||
| }) | ||
| } | ||
| return topLevelModels | ||
| } | ||
|
|
||
| public getAllResource() { | ||
| const fullModels = this.getOperationGetResponseResources() | ||
| const resources = new Set<string>() | ||
| for (const entry of fullModels.entries()) { | ||
| const paths = entry[1] | ||
| paths | ||
| .some(p => { | ||
| const hierarchy = this.getResourcesTypeHierarchy(p) | ||
| if (hierarchy.length > 0) { | ||
| resources.add(entry[0]) | ||
| return true | ||
| } | ||
| }) | ||
| } | ||
| return resources.values() | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @param path | ||
|
|
@@ -249,8 +289,25 @@ export class ResourceUtils { | |
| return hierarchy | ||
| } | ||
|
|
||
| private dereference(ref: string) { | ||
| return this.getResourceByName(this.stripDefinitionPath(ref)) | ||
| private dereference(ref: string, visited:Set<string>) { | ||
| if (visited.has(ref)) { | ||
| return undefined | ||
| } | ||
| visited.add(ref) | ||
| const model = this.getResourceByName(this.stripDefinitionPath(ref)) | ||
| if (model && model.$ref) { | ||
| return this.dereference(model.$ref, visited) | ||
| } | ||
| else { | ||
| return model | ||
| } | ||
| } | ||
|
|
||
| private getUnwrappedModel(property:any) { | ||
| if (property) { | ||
| const ref = property.$ref | ||
| return ref ? this.dereference(ref, new Set<string>()) : property | ||
| } | ||
| } | ||
|
|
||
| public containsDiscriminator(modelName: string) { | ||
|
|
@@ -432,21 +489,7 @@ export class ResourceUtils { | |
| if (!model) { | ||
| return undefined | ||
| } | ||
| if (model.properties) { | ||
| if (model.properties[propertyName]) { | ||
| const ref = model.properties[propertyName].$ref | ||
| return ref ? this.dereference(ref) : model.properties[propertyName] | ||
| } | ||
| } | ||
| if (model.allOf) { | ||
| for (const element of model.allOf) { | ||
| const property = this.getPropertyOfModelName(this.stripDefinitionPath(element.$ref), propertyName) | ||
| if (property) { | ||
| const ref = property.$ref | ||
| return ref ? this.dereference(ref) : property | ||
| } | ||
| } | ||
| } | ||
| return this.getPropertyOfModel(model,propertyName) | ||
| } | ||
|
|
||
| public getPropertyOfModel(sourceModel, propertyName: string) { | ||
|
|
@@ -455,20 +498,29 @@ export class ResourceUtils { | |
| } | ||
| let model = sourceModel | ||
| if (sourceModel.$ref) { | ||
| model = this.getResourceByName(this.stripDefinitionPath(sourceModel)) | ||
| model = this.getUnwrappedModel(sourceModel.$ref) | ||
| } | ||
| if (!model) { | ||
| return undefined | ||
| } | ||
| if (model.properties) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. model.properties?.propertyName
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, 'propertyName' is variable |
||
| if (model.properties[propertyName]) { | ||
| const ref = model.properties[propertyName].$ref | ||
| return ref ? this.dereference(ref) : model.properties[propertyName] | ||
| return this.getUnwrappedModel(model.properties[propertyName]) | ||
| } | ||
| } | ||
| if (model.allOf) { | ||
| for (const element of model.allOf) { | ||
| const property = this.getPropertyOfModelName(this.stripDefinitionPath(element.$ref), propertyName) | ||
| if (property) { | ||
| const ref = property.$ref | ||
| return ref ? this.dereference(ref) : property | ||
| if (element.$ref) { | ||
| const property = this.getPropertyOfModelName(this.stripDefinitionPath(element.$ref), propertyName) | ||
| if (property) { | ||
| return this.getUnwrappedModel(property) | ||
| } | ||
| } | ||
| else { | ||
| const property = this.getPropertyOfModel(element,propertyName) | ||
| if (property) { | ||
|
jianyexi marked this conversation as resolved.
Outdated
|
||
| return property | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| { | ||
| "swagger": "2.0", | ||
| "info": { | ||
| "title": "Network interfaces have unallowed types", | ||
| "description": "Some documentation.", | ||
| "version": "2014-04-01-preview" | ||
| }, | ||
| "host": "management.azure.com", | ||
| "schemes": [ | ||
| "https" | ||
| ], | ||
| "basePath": "/", | ||
| "produces": [ | ||
| "application/json" | ||
| ], | ||
| "consumes": [ | ||
| "application/json" | ||
| ], | ||
| "paths": { | ||
| "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/applicationGateways/{applicationGatewayName}": { | ||
| "get": { | ||
| "operationId": "getTestResource", | ||
| "summary": "Foo path", | ||
| "description": "Foo operation", | ||
| "parameters": [ | ||
| { | ||
| "$ref": "#/parameters/SubscriptionIdParameter" | ||
| }, | ||
| { | ||
| "$ref": "#/parameters/ApiVersion" | ||
| } | ||
| ], | ||
| "responses": { | ||
| "200": { | ||
| "description": "Created", | ||
| "schema":{ | ||
| "$ref": "#/definitions/TestResource" | ||
| } | ||
| }, | ||
| "default": { | ||
| "description": "Unexpected error" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "parameters": { | ||
| "SubscriptionIdParameter": { | ||
| "name": "subscriptionId", | ||
| "in": "path", | ||
| "required": true, | ||
| "type": "string", | ||
| "description": "test subscription id" | ||
| }, | ||
| "ApiVersion": { | ||
| "name": "api-version", | ||
| "in": "path", | ||
| "required": true, | ||
| "type": "string", | ||
| "description": "test api version" | ||
| } | ||
| }, | ||
| "definitions": { | ||
| "Resource": { | ||
| "properties": { | ||
| "id": { | ||
| "type": "string", | ||
| "description": "Resource ID." | ||
| }, | ||
| "name": { | ||
| "readOnly": true, | ||
| "type": "string", | ||
| "description": "Resource name." | ||
| }, | ||
| "type": { | ||
| "readOnly": true, | ||
| "type": "string", | ||
| "description": "Resource type." | ||
| } | ||
| }, | ||
| "description": "Common resource representation.", | ||
| "x-ms-azure-resource": true | ||
| }, | ||
| "TestResource": { | ||
| "description": "test", | ||
| "allOf": [ | ||
| {"$ref": "#/definitions/Resource"} | ||
| ], | ||
| "properties": { | ||
| "properties":{ | ||
| "type":"object", | ||
| "description": "properties" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.