Skip to content
Draft
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
28 changes: 28 additions & 0 deletions src/api-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

// apiVersion may be date-based ("2025-07-01") or non-date-based ("7.0", "v7.0", etc). All recent versions should be
// date-based, so sort all date-based versions later than all non-date-based versions.
export const compareApiVersion = (a: string, b: string): number => {
const dateA = containsDate(a)
const dateB = containsDate(b)
if (dateA && !dateB) {
return 1
} else if (!dateA && dateB) {
return -1
} else {
// Both "a" and "b" are either date-based or non-date-based, so perform an invariant string comparison
return invariantCompare(a, b)
}
}

// Returns true if a string contains a substring that looks like a date "YYYY-MM-DD"
const containsDate = (s: string): boolean => {
const dateRegex = /\d{4}-\d{2}-\d{2}/
return dateRegex.test(s)
}

const invariantCompare = (a: string, b: string): number => {
// JS doesn't provide a built-in invariantCompare(), and recommends this
return a.localeCompare(b, /* locales */ 'und', { sensitivity: 'variant' })
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as commonmark from 'commonmark'
import * as fs from 'fs'
import { JSONPath } from 'jsonpath-plus'
import * as path from 'path'
import { compareApiVersion } from './api-version'
import * as childProcess from './child-process'
import * as cli from './cli'
import * as devOps from './dev-ops'
Expand Down Expand Up @@ -469,7 +470,7 @@ export const validateRPMustContainAllLatestApiVersionSwagger = (dir: string): it
export const mergePathTable = (pathTable: PathTable, newPathTable: PathTable): PathTable => {
for (const [key, value] of newPathTable) {
if (pathTable.has(key)) {
if (pathTable.get(key)!.apiVersion < value.apiVersion) {
if (compareApiVersion(pathTable.get(key)!.apiVersion, value.apiVersion) < 0) {
pathTable.set(key, value)
}
} else {
Expand Down
25 changes: 25 additions & 0 deletions src/test/api-version-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

import * as assert from 'assert'
import { compareApiVersion } from '../api-version'

describe('api-version', () => {
it.each([
// date-based versions
['2025-01-01', '2025-01-01', 0],
['2025-01-01', '2025-01-02', -1],
['2025-01-03', '2025-01-02', 1],
// non-date-based versions
['7.0', '7.0', 0],
['7.0', '7.1', -1],
['7.2', '7.1', 1],
// mixed versions, date-based should always sort later
['7.0', '2025-01-01', -1],
['2025-01-01', '7.0', 1],
])('compares API version strings(%s, %s, %d)', (a: string, b: string, result: number) => {
// Compare both ways, ensure results are inverted
assert.equal(compareApiVersion(a, b), result)
assert.equal(compareApiVersion(b, a), result * -1)
})
})
11 changes: 11 additions & 0 deletions src/test/avocado-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,17 @@ describe('avocado', () => {
)
})

it('avocado check date-based version is latest', async () => {
// Spec contains two versions "7.0" and "2025-07-01", and default version "2025-07-01". If the versions are only
// sorted alphabetically, "7.0" sorts later than "2025-07-01", which results in error
// "NOT_LATEST_API_VERSION_IN_DEFAULT_TAG". Thus, our runtime code must special-case this, and ensure date-based
// versions always sort "later" than non-date-based-versions.

const r = await avocado.avocado({ cwd: 'src/test/latest_api_version', env: {} }).toArray()
const errorCodes = r.map((e) => e.code)
assert.deepStrictEqual(errorCodes, [])
})

it('avocado check illegal file, like cadl', async () => {
const r = await avocado.avocado({ cwd: 'src/test/contain_cadl_folder', env: {} }).toArray()
assert.deepStrictEqual(r.length > 0, true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# latest-api-version

> see https://aka.ms/autorest

## Configuration

### Basic Information

```yaml
tag: package-2025-07-01
```

### Tag: package-2025-07-01

```yaml $(tag) == 'package-2025-07-01'
input-file:
- stable/2025-07-01/spec.json
```

### Tag: package-7.0

```yaml $(tag) == 'package-7.0'
input-file:
- stable/7.0/spec.json
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"swagger": "2.0",
"info": {
"version": "2025-07-01"
},
"paths": {
"/path1": {},
"/path2": {},
"/path3": {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"swagger": "2.0",
"info": {
"version": "7.0"
},
"paths": {
"/path1": {},
"/path2": {},
"/path3": {}
}
}
Loading