Skip to content

Commit 779fc55

Browse files
ckairenharryli0108
authored andcommitted
[TypeSpec] Add @azure-tools/typespec-validation tool
- Replaces bash script used in "specs - typespec - validation" pipeline - Also intended for spec authors to run on their dev machines
1 parent ec1bf6c commit 779fc55

File tree

8 files changed

+213
-52
lines changed

8 files changed

+213
-52
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,7 @@ warnings.txt
119119
*.js.map
120120
*.d.ts.map
121121
*.bak
122+
123+
# Eng Tools
124+
eng/tools/TypeSpecValidation/dist
125+
!eng/tools/TypeSpecValidation/cmd/*.js

eng/pipelines/templates/steps/typespec-ci.yml

Lines changed: 1 addition & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,6 @@ parameters:
55
type: string
66

77
steps:
8-
- script: |
9-
RED='\033[0;31m'
10-
exit_code=0
11-
expected_npm_prefix=$(pwd)
12-
13-
# Log commands before running
14-
set -x
15-
16-
pushd ${{parameters.Folder}} || exit_code=1
17-
18-
actual_npm_prefix=$(npm prefix)
19-
20-
if [ "$expected_npm_prefix" != "$actual_npm_prefix" ]; then
21-
echo -e "\n${RED}ERROR: TypeSpec folders MUST NOT contain a package.json, and instead MUST rely on the package.json at repo root."
22-
echo -e "${RED}Expected npm prefix: $expected_npm_prefix\n${RED}Actual npm prefix: $actual_npm_prefix\n"
23-
exit_code=1
24-
fi
25-
26-
# Pass "--no" to ensure npx does not install anything (TypeSpec compiler should already be installed)
27-
28-
if test -f main.tsp; then
29-
npx --no tsp compile . --warn-as-error || exit_code=1
30-
fi
31-
if test -f client.tsp; then
32-
npx --no tsp compile client.tsp --no-emit --warn-as-error || exit_code=1
33-
fi
34-
35-
# Format parent folder to include shared files
36-
npx tsp format ../**/*.tsp
37-
38-
popd
39-
40-
# If any files are added, changed, or deleted, print diff and return error
41-
if [ -n "$(git status --porcelain)" ]; then
42-
git status
43-
git diff
44-
exit_code=1
45-
fi
46-
47-
# Revert any changes
48-
git restore .
49-
git clean -df
50-
51-
exit $exit_code
8+
- script: npx --no tsv ${{parameters.Folder}}
529
displayName: ${{parameters.DisplayName}}
5310
condition: succeededOrFailed()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env node
2+
3+
import { main } from "../dist/TypeSpecValidation.js"
4+
5+
await main();
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "@azure-tools/typespec-validation",
3+
"private": true,
4+
"version": "0.0.1",
5+
"type": "module",
6+
"main": "dist/TypeSpecValidation.js",
7+
"bin": {
8+
"tsv": "cmd/tsv.js"
9+
},
10+
"dependencies": {
11+
"simple-git": "^3.16.0"
12+
},
13+
"devDependencies": {
14+
"@types/node": "^18.16.18"
15+
}
16+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import {exec} from "child_process";
2+
import {access} from "fs/promises"
3+
import {parseArgs, ParseArgsConfig} from 'node:util';
4+
import path from "path";
5+
import {simpleGit} from 'simple-git';
6+
7+
async function runCmd(cmd:string, cwd:string) {
8+
console.log(`run command:${cmd}`)
9+
const { err, stdout, stderr } = await new Promise((res) =>
10+
exec(
11+
cmd,
12+
{ encoding: "utf8", maxBuffer: 1024 * 1024 * 64, cwd: cwd},
13+
(err: unknown, stdout: unknown, stderr: unknown) =>
14+
res({ err: err, stdout: stdout, stderr: stderr })
15+
)
16+
) as any;
17+
let resultString = stderr + stdout;
18+
console.log("Stdout output:")
19+
console.log(stdout)
20+
if (stderr) {
21+
console.log("Stderr output:")
22+
console.log(stderr)
23+
}
24+
if (stderr || err) {
25+
throw new Error(err);
26+
}
27+
return resultString as string;
28+
}
29+
30+
async function checkFileExists(file:string) {
31+
return access(file)
32+
.then(() => true)
33+
.catch(() => false)
34+
}
35+
36+
export async function main() {
37+
const args = process.argv.slice(2);
38+
const options = {
39+
folder: {
40+
type: 'string',
41+
short: 'f',
42+
},
43+
};
44+
const parsedArgs = parseArgs({ args, options, allowPositionals: true} as ParseArgsConfig);
45+
const folder = parsedArgs.positionals[0];
46+
console.log("Running TypeSpecValidation on folder:", folder);
47+
48+
// Verify all specs are using root level pacakge.json
49+
let expected_npm_prefix = process.cwd()
50+
const actual_npm_prefix = (await runCmd(`npm prefix`, folder)).trim()
51+
if (expected_npm_prefix !== actual_npm_prefix) {
52+
console.log("ERROR: TypeSpec folders MUST NOT contain a package.json, and instead MUST rely on the package.json at repo root.")
53+
throw new Error ("Expected npm prefix: " + expected_npm_prefix +"\nActual npm prefix: " + actual_npm_prefix)
54+
}
55+
56+
// Spec compilation check
57+
if (await checkFileExists(path.join(folder, "main.tsp"))) {
58+
await runCmd(
59+
`npx --no tsp compile . --warn-as-error`,
60+
folder
61+
);
62+
}
63+
if (await checkFileExists(path.join(folder, "client.tsp"))) {
64+
await runCmd(
65+
`npx --no tsp compile client.tsp --no-emit --warn-as-error`,
66+
folder
67+
);
68+
}
69+
70+
// Format parent folder to include shared files
71+
await runCmd(
72+
`npx tsp format ../**/*.tsp`,
73+
folder
74+
);
75+
76+
// Verify generated swagger file is in sync with one on disk
77+
const git = simpleGit();
78+
let gitStatusIsClean = await (await git.status(['--porcelain'])).isClean()
79+
if (!gitStatusIsClean) {
80+
let gitStatus = await git.status()
81+
let gitDiff = await git.diff()
82+
console.log("git status")
83+
console.log(gitStatus)
84+
console.log("git diff")
85+
console.log(gitDiff)
86+
throw new Error("Generated swagger file does not match swagger file on disk")
87+
}
88+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../../tsconfig.json",
3+
"compilerOptions": {
4+
"target": "ES6",
5+
"module": "Node16",
6+
"outDir": "./dist"
7+
}
8+
}

package-lock.json

Lines changed: 86 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@
2020
"@azure/avocado": "^0.8.4",
2121
"@types/prettier": "^2.7.2",
2222
"prettier": "^2.8.8",
23-
"typescript": "~5.0.4"
23+
"typescript": "~5.0.4",
24+
"typespec-validation": "file:eng/tools/TypeSpecValidation"
25+
},
26+
"scripts": {
27+
"postinstall": "npx --no tsc -- -p eng/tools/TypeSpecValidation"
2428
},
2529
"private": true
2630
}

0 commit comments

Comments
 (0)