eng/scripts/prerelease.mjs (128 lines of code) (raw):

/* eslint-disable no-console */ import { execSync } from "child_process"; import { readFile, writeFile } from "fs/promises"; import { join } from "path"; async function getPackages(workspaceRoot) { const rushJson = await readJsonFile(join(workspaceRoot, "rush.json")); const paths = {}; for (const project of rushJson.projects) { const packagePath = join(workspaceRoot, project.projectFolder); const pkg = await readJsonFile(join(packagePath, "package.json")); paths[project.packageName] = { path: packagePath, version: pkg.version, }; } return paths; } /** * Update the package dependencies to match the newly updated version. * @param {*} packageManifest * @param {*} updatedPackages */ function updateDependencyVersions(packageManifest, updatedPackages) { const clone = { ...packageManifest, }; for (const depType of ["dependencies", "devDependencies", "peerDependencies"]) { const dependencies = {}; const currentDeps = packageManifest[depType]; if (currentDeps) { for (const [name, currentVersion] of Object.entries(currentDeps)) { const updatedPackage = updatedPackages[name]; if (updatedPackage) { dependencies[name] = `~${updatedPackage.newVersion}`; } else { dependencies[name] = currentVersion; } } } clone[depType] = dependencies; } return clone; } async function appendPrereleaseSemverSuffix(packages) { var _a; const updatedManifests = {}; const timestamp = getIsoLikeTimestamp(); for (const [packageName, packageInfo] of Object.entries(packages)) { const packageJsonPath = join(packageInfo.path, "package.json"); const packageJsonContent = await readJsonFile(packageJsonPath); // As of [1] we no longer require running `rush change`. // As a side-effect of this, there is no concept of `changeCount` anymore. // To work around the fact we don't know the change count, we append a timestamp to the version. // This is temporary solution until the work item [2] is completed. // Note that if we would not append anything to packageInfo.version, we would end up // inadvertently pushing prerelease bits to production packages as soon as LintDiff PR is merged. // Details on that in [2]. // // The "-beta." infix is here to simulate the behavior of `rush publish --apply --partial-prerelease --prerelease-name="beta"` // called upstream in this script. It does no-op when changeCount is zero, hence we mimic that behavior here. // // [1] https://github.com/Azure/azure-openapi-validator/pull/659 // [2] https://github.com/Azure/azure-sdk-tools/issues/7619 const newVersion = `${packageInfo.version}-beta.${timestamp}` console.log(`Setting version for ${packageName} to '${newVersion}'`); updatedManifests[packageName] = { packageJsonPath, oldVersion: packageJsonContent.version, newVersion: newVersion, manifest: { ...packageJsonContent, version: newVersion, }, }; } for (const { packageJsonPath, manifest } of Object.values(updatedManifests)) { const newManifest = updateDependencyVersions(manifest, updatedManifests); await writeFile(packageJsonPath, JSON.stringify(newManifest, null, 2)); } } /** * @returns Date in format "YYYY-MM-DD-hh-mm-ss" */ function getIsoLikeTimestamp() { const date = new Date(); const year = date.getFullYear().toString(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); // +1 because getMonth() returns 0-11 const day = date.getDate().toString().padStart(2, '0'); const hours = date.getHours().toString().padStart(2, '0'); const minutes = date.getMinutes().toString().padStart(2, '0'); const seconds = date.getSeconds().toString().padStart(2, '0'); const formattedDate = `${year}-${month}-${day}-${hours}-${minutes}-${seconds}`; return formattedDate; } export async function bumpVersionsForPrerelease(workspaceRoots) { let packages = {}; const prerelease_type = process.env.PRERELEASE_TYPE || 'beta' for (const workspaceRoot of workspaceRoots) { packages = { ...packages, ...(await getPackages(workspaceRoot)) }; } console.log("Packages", packages); // Bumping with rush publish so rush computes from the changes what will be the next non prerelease version. console.log("Bumping versions with rush publish"); for (const workspaceRoot of workspaceRoots) { // https://rushjs.io/pages/commands/rush_publish/ const stdout = execSync(`npx @microsoft/rush publish --apply --partial-prerelease --prerelease-name="${prerelease_type}"`, { cwd: workspaceRoot, }); console.log(`npx @microsoft/rush publish --apply --partial-prerelease --prerelease-name="${prerelease_type} ` + `cwd: "${workspaceRoot}" stdout: "${stdout.toString()}"`) } await appendPrereleaseSemverSuffix(packages); updateOpenapiValidatorPck() } // update rulesets and core version in the package.json of openapi-validator to the latest beta version. async function updateOpenapiValidatorPck() { const packagePath = `packages/azure-openapi-validator/autorest/package.json` const pkg = await readJsonFile(packagePath) pkg.dependencies["@microsoft.azure/openapi-validator-core"] = "beta" pkg.dependencies["@microsoft.azure/openapi-validator-rulesets"] = "beta" await writeFile(packagePath,JSON.stringify(pkg,null,2)) } async function readJsonFile(filename) { const content = await readFile(filename); return JSON.parse(content.toString()); } bumpVersionsForPrerelease(["."])