Skip to content
Merged
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
16 changes: 16 additions & 0 deletions .chronus/changes/pnpm-catalogs-2026-2-24-19-47-57.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@azure-tools/azure-http-specs"
- "@azure-tools/typespec-autorest-canonical"
- "@azure-tools/typespec-autorest"
- "@azure-tools/typespec-azure-core"
- "@azure-tools/typespec-azure-portal-core"
- "@azure-tools/typespec-azure-resource-manager"
- "@azure-tools/typespec-azure-rulesets"
- "@azure-tools/typespec-client-generator-core"
- "@azure-tools/typespec-metadata"
---

migrate to catalogs
4 changes: 2 additions & 2 deletions .github/workflows/consistency.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ jobs:
- run: pnpm run lint
name: Lint

# Check version mismatch
# Check catalog is in sync with core
version-consistency:
name: Versions consistency
runs-on: ubuntu-latest
Expand All @@ -113,7 +113,7 @@ jobs:
name: Install dependencies

- run: pnpm run check-version-mismatch
name: Check version mismatch
name: Check catalog is in sync

# Verify Arm OpenAPI common types are up to date
common-types-up-to-date:
Expand Down
2 changes: 1 addition & 1 deletion core
Submodule core updated 138 files
1 change: 1 addition & 0 deletions cspell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ignorePaths:
- common/scripts/*
- packages/website/build/*
- pnpm-lock.yaml
- pnpm-workspace.yaml
- eng/feeds/**/examples/**
- packages/samples/test/output/**
- eng/scripts/doc-updater/knowledge/**
Expand Down
2 changes: 1 addition & 1 deletion eng/feeds/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"description": "",
"devDependencies": {
"@typespec/compiler": "workspace:^",
"vitest": "^4.1.0"
"vitest": "catalog:"
}
}
179 changes: 179 additions & 0 deletions eng/scripts/sync-catalog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { readFileSync, writeFileSync } from "fs";
import { resolve } from "path";
import pc from "picocolors";
import { coreRepoRoot, repoRoot } from "./helpers.js";

const WorkspaceYamlFile = "pnpm-workspace.yaml";

/** Parses the `catalog:` section from a pnpm-workspace.yaml file. */
function parseCatalog(filePath: string): Record<string, string> {
let content: string;
try {
content = readFileSync(filePath, "utf8");
} catch {
return {};
}

const catalog: Record<string, string> = {};
const lines = content.split("\n");
let inCatalog = false;

for (const line of lines) {
if (/^catalog:\s*$/.test(line)) {
inCatalog = true;
continue;
}
// A non-indented, non-empty, non-comment line ends the catalog section
if (inCatalog && line.length > 0 && !line.startsWith(" ") && !line.startsWith("#")) {
break;
}
if (!inCatalog) continue;

const match = line.match(/^\s+"?([^":]+)"?\s*:\s*"?([^"]+)"?\s*$/);
if (match) {
catalog[match[1].trim()] = match[2].trim();
}
}

return catalog;
}

/** Serializes a catalog object into YAML. */
function serializeCatalog(catalog: Record<string, string>): string {
const lines = ["catalog:"];
const sorted = Object.entries(catalog).sort(([a], [b]) => a.localeCompare(b));
for (const [dep, version] of sorted) {
const key = dep.startsWith("@") ? `"${dep}"` : dep;
// Quote versions that start with a digit so YAML doesn't parse them as numbers
const val = /^\d/.test(version) ? `"${version}"` : version;
lines.push(` ${key}: ${val}`);
}
return lines.join("\n") + "\n";
}

/** Replaces the catalog section in a pnpm-workspace.yaml file. */
function replaceCatalogSection(content: string, catalog: Record<string, string>): string {
const lines = content.split("\n");
const beforeCatalog: string[] = [];
const afterCatalog: string[] = [];

let state: "before" | "in" | "after" = "before";
for (const line of lines) {
if (state === "before") {
if (/^catalog:\s*$/.test(line)) {
state = "in";
} else {
beforeCatalog.push(line);
}
} else if (state === "in") {
if (line.length > 0 && !line.startsWith(" ") && !line.startsWith("#")) {
state = "after";
afterCatalog.push(line);
}
} else {
afterCatalog.push(line);
}
}

const before = beforeCatalog.join("\n").replace(/\n+$/, "\n");
const catalogStr = "\n" + serializeCatalog(catalog);
const after = afterCatalog.length > 0 ? "\n" + afterCatalog.join("\n") : "";

return before + catalogStr + after;
}

interface Mismatch {
dep: string;
repoVersion: string;
coreVersion: string;
}

interface Missing {
dep: string;
coreVersion: string;
}

function main() {
const mode = process.argv[2];

if (mode !== "check" && mode !== "fix") {
console.error("Usage: sync-catalog <check|fix>");
console.error(
" check - Report mismatches between core and this repo's catalog (exits non-zero if any)",
);
console.error(" fix - Update this repo's catalog with versions from core");
process.exit(1);
}

const repoWorkspaceYaml = resolve(repoRoot, WorkspaceYamlFile);
const coreWorkspaceYaml = resolve(coreRepoRoot, WorkspaceYamlFile);

const repoCatalog = parseCatalog(repoWorkspaceYaml);
const coreCatalog = parseCatalog(coreWorkspaceYaml);

if (Object.keys(repoCatalog).length === 0) {
console.error(`No catalog found in ${repoWorkspaceYaml}`);
process.exit(1);
}

if (Object.keys(coreCatalog).length === 0) {
console.log("No catalog found in core workspace yaml. Nothing to sync.");
process.exit(0);
}

const mismatches: Mismatch[] = [];
const missing: Missing[] = [];

for (const [dep, coreVersion] of Object.entries(coreCatalog)) {
if (dep in repoCatalog) {
if (repoCatalog[dep] !== coreVersion) {
mismatches.push({ dep, repoVersion: repoCatalog[dep], coreVersion });
}
} else {
missing.push({ dep, coreVersion });
}
}

if (mismatches.length === 0 && missing.length === 0) {
console.log(pc.green("✓") + " Catalog is in sync with core.");
process.exit(0);
}

if (mismatches.length > 0) {
console.log(`Found ${pc.yellow(String(mismatches.length))} version mismatch(es) with core:\n`);
for (const { dep, repoVersion, coreVersion } of mismatches) {
console.log(` ${pc.cyan(dep)}: ${pc.red(repoVersion)} → ${pc.green(coreVersion)}`);
}
}

if (missing.length > 0) {
console.log(
`\nFound ${pc.yellow(String(missing.length))} dep(s) in core catalog missing from this repo:\n`,
);
for (const { dep, coreVersion } of missing) {
console.log(` ${pc.cyan(dep)}: ${pc.green(coreVersion)}`);
}
}

if (mode === "check") {
console.log(`\nRun with ${pc.cyan("fix")} to apply these changes.`);
process.exit(1);
}

// Fix mode: apply changes
const updatedCatalog = { ...repoCatalog };
for (const { dep, coreVersion } of mismatches) {
updatedCatalog[dep] = coreVersion;
}
for (const { dep, coreVersion } of missing) {
updatedCatalog[dep] = coreVersion;
}

const content = readFileSync(repoWorkspaceYaml, "utf8");
const updated = replaceCatalogSection(content, updatedCatalog);
writeFileSync(repoWorkspaceYaml, updated);

console.log(`\n${pc.green("✓")} Updated ${repoWorkspaceYaml}`);
}

main();
61 changes: 25 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"run-all": "pnpm -r --filter=!./core/",
"run-azure-only": "pnpm -r --filter=\"!./core/**\"",
"build": "pnpm run-all --workspace-concurrency=Infinity --aggregate-output --reporter=append-only build && pnpm check:eng",
"check-version-mismatch": "syncpack list-mismatches",
"check-version-mismatch": "tsx eng/scripts/sync-catalog.ts check",
"check:eng": "tsc -p ./tsconfig.eng.json --noEmit",
"change": "chronus",
"clean": "pnpm run-all run clean",
"cspell": "cspell --no-progress .",
"dogfood": "pnpm install && pnpm build && pnpm run-all dogfood",
"fix-version-mismatch": "syncpack fix-mismatches",
"fix-version-mismatch": "tsx eng/scripts/sync-catalog.ts fix",
"format": "prettier --write .",
"format:check": "prettier . --check",
"format:dir": "prettier --write",
Expand All @@ -40,42 +40,31 @@
"tsp-integration": "node core/packages/tsp-integration/cmd/tsp-integration.js"
},
"devDependencies": {
"@chronus/chronus": "^1.3.1",
"@chronus/github": "^1.0.6",
"@eslint/js": "^10.0.1",
"@pnpm/workspace.find-packages": "^1000.0.64",
"@types/node": "~25.5.0",
"@vitest/coverage-v8": "^4.1.0",
"c8": "^11.0.0",
"cspell": "^9.7.0",
"eslint": "^10.0.3",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-unicorn": "^63.0.0",
"@vitest/eslint-plugin": "^1.6.12",
"playwright": "^1.58.2",
"prettier": "~3.8.1",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-organize-imports": "~4.3.0",
"prettier-plugin-sh": "^0.18.0",
"rimraf": "~6.1.3",
"syncpack": "^13.0.3",
"tsx": "^4.21.0",
"typescript": "~5.9.3",
"typescript-eslint": "^8.57.0",
"vitest": "^4.1.0"
},
"syncpack": {
"dependencyTypes": [
"dev",
"overrides",
"peer",
"pnpmOverrides",
"prod",
"resolutions"
]
"@chronus/chronus": "catalog:",
"@chronus/github": "catalog:",
"@eslint/js": "catalog:",
"@pnpm/workspace.find-packages": "catalog:",
"@types/node": "catalog:",
"@vitest/coverage-v8": "catalog:",
"c8": "catalog:",
"cspell": "catalog:",
"eslint": "catalog:",
"eslint-plugin-import": "catalog:",
"eslint-plugin-unicorn": "catalog:",
"@vitest/eslint-plugin": "catalog:",
"playwright": "catalog:",
"prettier": "catalog:",
"prettier-plugin-astro": "catalog:",
"prettier-plugin-organize-imports": "catalog:",
"prettier-plugin-sh": "catalog:",
"rimraf": "catalog:",
"tsx": "catalog:",
"typescript": "catalog:",
"typescript-eslint": "catalog:",
"vitest": "catalog:"
},
"dependencies": {
"picocolors": "~1.1.1"
"picocolors": "catalog:"
},
"pnpm": {
"onlyBuiltDependencies": [
Expand Down
10 changes: 5 additions & 5 deletions packages/azure-http-specs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@
"@azure-tools/typespec-autorest": "workspace:^",
"@azure-tools/typespec-azure-resource-manager": "workspace:^",
"@azure-tools/typespec-client-generator-core": "workspace:^",
"@types/multer": "^2.1.0",
"@types/node": "~25.5.0",
"@types/multer": "catalog:",
"@types/node": "catalog:",
"@typespec/openapi": "workspace:^",
"@typespec/openapi3": "workspace:^",
"concurrently": "^9.2.1",
"rimraf": "~6.1.3",
"typescript": "~5.9.3"
"concurrently": "catalog:",
"rimraf": "catalog:",
"typescript": "catalog:"
},
"peerDependencies": {
"@azure-tools/typespec-azure-core": "workspace:^",
Expand Down
4 changes: 2 additions & 2 deletions packages/e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"devDependencies": {
"@typespec/compiler": "workspace:^",
"dotenv": "^17.2.3",
"typescript": "~5.9.3"
"dotenv": "catalog:",
"typescript": "catalog:"
}
}
16 changes: 8 additions & 8 deletions packages/samples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@
"@typespec/xml": "workspace:^"
},
"devDependencies": {
"@types/node": "~25.5.0",
"@types/node": "catalog:",
"@typespec/internal-build-utils": "workspace:^",
"@typespec/samples": "workspace:^",
"@vitest/coverage-v8": "^4.1.0",
"@vitest/ui": "^4.1.0",
"autorest": "~3.7.1",
"cross-env": "~10.1.0",
"rimraf": "~6.1.3",
"typescript": "~5.9.3",
"vitest": "^4.1.0"
"@vitest/coverage-v8": "catalog:",
"@vitest/ui": "catalog:",
"autorest": "catalog:",
"cross-env": "catalog:",
"rimraf": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:"
}
}
14 changes: 7 additions & 7 deletions packages/typespec-autorest-canonical/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,19 +64,19 @@
"@azure-tools/typespec-azure-core": "workspace:^",
"@azure-tools/typespec-azure-resource-manager": "workspace:^",
"@azure-tools/typespec-client-generator-core": "workspace:^",
"@types/node": "~25.5.0",
"@types/node": "catalog:",
"@typespec/compiler": "workspace:^",
"@typespec/http": "workspace:^",
"@typespec/library-linter": "workspace:^",
"@typespec/openapi": "workspace:^",
"@typespec/rest": "workspace:^",
"@typespec/tspd": "workspace:^",
"@typespec/versioning": "workspace:^",
"@vitest/coverage-v8": "^4.1.0",
"@vitest/ui": "^4.1.0",
"c8": "^11.0.0",
"rimraf": "~6.1.3",
"typescript": "~5.9.3",
"vitest": "^4.1.0"
"@vitest/coverage-v8": "catalog:",
"@vitest/ui": "catalog:",
"c8": "catalog:",
"rimraf": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:"
}
}
Loading
Loading