CI validation bundle
Inherits hard rules from SKILL.md §Hard rules.
Use this bundle for package hygiene, validation, and pipeline snippets.
Required validation commands
npm ci
npx tsp compile . --warn-as-error
npx tsp format "**/*.tsp"
npx tsp infoOptional, if configured:
npx spectral lint tsp-output/openapi3/openapi.yamlDo not rely on tsp lint . for new work. Configure linting in tspconfig.yaml and make compilation fail with --warn-as-error.
package.json scripts
The recommended scripts block in package.json:
"scripts": {
"build": "tsp compile . --warn-as-error",
"watch": "tsp compile . --watch",
"format": "tsp format \"**/*.tsp\"",
"format:check": "tsp format \"**/*.tsp\" --check",
"validate:openapi": "redocly lint tsp-output/@typespec/openapi3/openapi.yaml"
}format:checkis the non-mutating variant intended for CI; it fails the build if any.tspfile is unformatted instead of rewriting files in place.validate:openapiis optional but catches emitter regressions early by linting the generated OpenAPI document. Swapredoclyforspectralif that is the repository's chosen linter.
Per SKILL.md hard rule #15, pin TypeSpec packages to exact patch versions - no ^ or ~ ranges. Example devDependencies block:
"devDependencies": {
"@typespec/compiler": "1.15.0",
"@typespec/http": "1.15.0",
"@typespec/rest": "0.85.0",
"@typespec/openapi3": "1.15.0"
}Use "1.15.0", not "^1.15.0" - exact pins keep CI reproducible and surface package drift in a single dependency-bump PR. Note the split version tracks: @typespec/compiler/http/openapi3 are on the 1.x line while @typespec/rest/versioning are on the 0.8x line, and any @azure-tools/typespec-* packages sit on their own independent family (see bundles/emitter-gotchas/guide.md). Resolve each pin with npm view <package> version against current releases before committing - do not copy a number from the typespec-azure@X.Y.Z GitHub monorepo tag.
CI matrix should pin Node 22 LTS or 24 LTS; TypeSpec 1.x requires Node 22+ (Azure TypeSpec recommends Node 24 LTS).
CI gates
A PR is not mergeable until every required gate passes:
npm cisucceeds (lockfile in sync, no install drift).npm run buildsucceeds with--warn-as-error(no TypeSpec diagnostics).npm run format:checkshows no diffs.- Optional:
redocly lintorspectral linton the generated OpenAPI passes. - Optional:
oasdiff breaking previous-openapi.yaml tsp-output/@typespec/openapi3/openapi.yamlruns on PRs to flag breaking changes against the last released contract.
Caching
Cache ~/.npm and node_modules keyed on the package-lock.json hash in both GitHub Actions and Azure DevOps to keep CI fast:
- GitHub Actions:
actions/setup-node@v4withcache: npmhandles~/.npm; add anactions/cache@v4step keyed onhashFiles('**/package-lock.json')to also cachenode_modules. - Azure DevOps: use the
Cache@2task withkey: 'npm | "$(Agent.OS)" | package-lock.json'covering both~/.npmandnode_modules.
GitHub Actions example
name: typespec
on:
pull_request:
push:
branches: [main]
jobs:
validate-typespec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Compile TypeSpec
run: npx tsp compile . --warn-as-error
- name: Format check
run: npx tsp format "**/*.tsp" --check
- name: Publish generated API artifacts
uses: actions/upload-artifact@v4
with:
name: tsp-output
path: tsp-outputVerify tsp format --check against the pinned compiler. If unsupported, replace with repository-approved formatting validation.
Azure DevOps example
trigger:
branches:
include:
- main
pool:
vmImage: ubuntu-latest
steps:
- task: NodeTool@0
inputs:
versionSpec: '22.x'
- script: npm ci
displayName: Install dependencies
- script: npx tsp compile . --warn-as-error
displayName: Compile TypeSpec
- script: npx tsp format "**/*.tsp" --check
displayName: Check TypeSpec formatting
- task: PublishPipelineArtifact@1
displayName: Publish TypeSpec output
inputs:
targetPath: tsp-output
artifact: tsp-output
publishLocation: pipelinePackage hygiene
- Pin compatible package families; avoid mixing arbitrary TypeSpec package versions.
- Commit lockfiles for reproducible CI.
- Use
npm ciin CI, notnpm install. - Use
tspconfig.yaml, nottspconfig.yml. - Keep generated output out of source unless required by an external API review process.
- Publish generated output as build artifacts for downstream jobs.
CI quality gate
A PR is not ready until:
- TypeSpec compilation succeeds with warnings as errors.
- Azure linter rules pass when Azure packages are used.
- Generated OpenAPI/Swagger exists at the documented path.
- Examples compile or validate against the emitted schema where tooling exists.
- Contract changes are summarized for reviewers.
- Breaking-change risk is explicitly called out.