Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Update arm APIVersionPattern rule for canonical swagger #732

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft.azure/openapi-validator-rulesets",
"comment": "update APIVersionPattern rule",
"type": "patch"
}
],
"packageName": "@microsoft.azure/openapi-validator-rulesets"
}
5 changes: 3 additions & 2 deletions docs/api-version-pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ ARM OpenAPI(swagger) specs

## Output Message

API Version must be in the format: yyyy-MM-dd, optionally followed by -preview.
API Version must be in the format: yyyy-MM-dd, optionally followed by -preview, or 'canonical' for canonical swagger.

## Description

The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) NOTE that this is the en-US ordering of month and date.
The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) or 'canonical' for canonical swagger. NOTE that this is the en-US ordering of month and date.

The date MAY optionally be followed by one of:
* -preview - Indicates the API version is in (public) preview
Expand All @@ -36,6 +36,7 @@ The API version specified wil be used by the generated client.
Examples of valid version patterns include:
* 2016-07-04
* 2016-07-04-preview
* canonical (for canonical swagger)

## Bad Examples

Expand Down
2 changes: 1 addition & 1 deletion docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Please refer to [api-version-parameter-required.md](./api-version-parameter-requ

### APIVersionPattern

The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) NOTE that this is the en-US ordering of month and date.
The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) or 'canonical' for canonical swagger. NOTE that this is the en-US ordering of month and date.
The date MAY optionally be followed by one of:
* -preview - Indicates the API version is in (public) preview

Expand Down
39 changes: 33 additions & 6 deletions packages/rulesets/generated/spectral/az-arm.js
Original file line number Diff line number Diff line change
Expand Up @@ -1278,6 +1278,36 @@ const ruleset$1 = {
},
};

const apiVersionPatternValidation = (info, opts, paths) => {
if (info === null || typeof info !== "object") {
return [];
}
const path = paths.path || [];
const canonicalEmitter = "@azure-tools/typespec-autorest-canonical";
if (info["x-typespec-generated"] && info["x-typespec-generated"][0].emitter == canonicalEmitter) {
if (info.version != "canonical") {
return [
{
message: `Canonical swagger version should be 'canonical.`,
path: [...path, "version"],
},
];
}
}
else {
const apiVersionPattern = /^(20\d{2})-(0[1-9]|1[0-2])-((0[1-9])|[12][0-9]|3[01])(-preview)?$/gi;
if (!apiVersionPattern.test(info.version)) {
return [
{
message: `The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.). NOTE that this is the en-US ordering of month and date.`,
path: [...path, "version"],
},
];
}
}
return [];
};

function matchAnyPatterns$2(patterns, path) {
return patterns.some((p) => p.test(path));
}
Expand Down Expand Up @@ -4001,17 +4031,14 @@ const ruleset = {
},
},
APIVersionPattern: {
description: "The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) NOTE that this is the en-US ordering of month and date.",
description: "The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) or 'canonical'. NOTE that this is the en-US ordering of month and date.",
severity: "error",
message: "{{description}}",
resolved: true,
formats: [oas2],
given: "$.info.version",
given: "$.info",
then: {
function: pattern,
functionOptions: {
match: "^(20\\d{2})-(0[1-9]|1[0-2])-((0[1-9])|[12][0-9]|3[01])(-(preview))?$",
},
function: apiVersionPatternValidation,
},
},
ParameterNotDefinedInGlobalParameters: {
Expand Down
10 changes: 4 additions & 6 deletions packages/rulesets/src/spectral/az-arm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { oas2 } from "@stoplight/spectral-formats"
import { falsy, pattern, truthy } from "@stoplight/spectral-functions"
import common from "./az-common"
import apiVersionPatternValidation from "./functions/api-version-pattern-validation"
import verifyArmPath from "./functions/arm-path-validation"
import bodyParamRepeatedInfo from "./functions/body-param-repeated-info"
import { camelCase } from "./functions/camel-case"
Expand Down Expand Up @@ -1104,17 +1105,14 @@ const ruleset: any = {
},
APIVersionPattern: {
description:
"The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) NOTE that this is the en-US ordering of month and date.",
"The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.) or 'canonical'. NOTE that this is the en-US ordering of month and date.",
severity: "error",
message: "{{description}}",
resolved: true,
formats: [oas2],
given: "$.info.version",
given: "$.info",
then: {
function: pattern,
functionOptions: {
match: "^(20\\d{2})-(0[1-9]|1[0-2])-((0[1-9])|[12][0-9]|3[01])(-(preview))?$",
},
function: apiVersionPatternValidation,
},
},
ParameterNotDefinedInGlobalParameters: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const apiVersionPatternValidation = (info: any, opts: any, paths: any) => {
if (info === null || typeof info !== "object") {
return []
}

const path = paths.path || []
const canonicalEmitter = "@azure-tools/typespec-autorest-canonical"

if (info["x-typespec-generated"] && info["x-typespec-generated"][0].emitter == canonicalEmitter) {
if (info.version != "canonical") {
return [
{
message: `Canonical swagger version should be 'canonical.`,
path: [...path, "version"],
},
]
}
} else {
const apiVersionPattern = /^(20\d{2})-(0[1-9]|1[0-2])-((0[1-9])|[12][0-9]|3[01])(-preview)?$/gi

if (!apiVersionPattern.test(info.version)) {
return [
{
message: `The API Version parameter MUST be in the Year-Month-Date format (i.e. 2016-07-04.). NOTE that this is the en-US ordering of month and date.`,
path: [...path, "version"],
},
]
}
}

return []
}

export default apiVersionPatternValidation
182 changes: 182 additions & 0 deletions packages/rulesets/src/spectral/test/api-version-pattern.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { Spectral } from "@stoplight/spectral-core"
import linterForRule from "./utils"

let linter: Spectral

beforeAll(async () => {
linter = await linterForRule("APIVersionPattern")
return linter
})

test("APIVersionPattern should find no errors", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "2021-07-01",
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(0)
})
})

test("APIVersionPattern should find errors", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "3.0.1",
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(1)
expect(results[0].path.join(".")).toBe("info.version")
})
})

test("APIVersionPattern should find errors 2", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "canonical",
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(1)
expect(results[0].path.join(".")).toBe("info.version")
})
})

test("APIVersionPattern should find no errors for autorest generated swagger", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "2021-07-01",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(0)
})
})

test("APIVersionPattern should find errors for autorest generated swagger", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "3.0.1",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(1)
expect(results[0].path.join(".")).toBe("info.version")
})
})

test("APIVersionPattern should find errors for autorest-canonical generated swagger", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "3.0.1",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest-canonical",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(1)
expect(results[0].path.join(".")).toBe("info.version")
})
})

test("APIVersionPattern should find errors for autorest-canonical generated swagger 2", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "2021-07-01",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest-canonical",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(1)
expect(results[0].path.join(".")).toBe("info.version")
})
})

test("APIVersionPattern should find no errors for autorest-canonical generated swagger", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "canonical",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest-canonical",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(0)
})
})

test("APIVersionPattern should find no errors with -preview", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "2021-07-01-preview",
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(0)
})
})

test("APIVersionPattern should find no errors for autorest generated swagger with -preview", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "2021-07-01-preview",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(0)
})
})

test("APIVersionPattern should find errors for autorest-canonical generated swagger with -preview 2", () => {
const myOpenApiDocument = {
swagger: "2.0",
info: {
version: "2021-07-01-preview",
"x-typespec-generated": [
{
emitter: "@azure-tools/typespec-autorest-canonical",
},
],
},
}
return linter.run(myOpenApiDocument).then((results) => {
expect(results.length).toBe(1)
expect(results[0].path.join(".")).toBe("info.version")
})
})
Loading