UNPKG

@adinsure-ops/ops-cli

Version:

Operations CLI for working with AdInsure

200 lines (199 loc) 8.75 kB
import { __asyncValues, __awaiter } from "tslib"; import { Flags, ux } from '@oclif/core'; import chalk from 'chalk'; import { spawn } from 'child_process'; import CommandBase from '../../command.base.js'; import NpmContext from '../../lib/npm.js'; class NpmPublish extends CommandBase { publishPackage(pkg_1) { return __awaiter(this, arguments, void 0, function* (pkg, cmd = ['yarn', 'publish']) { var _a, e_1, _b, _c, _d, e_2, _e, _f; let sh; let args; // cross platform compatibility if (process.platform === 'win32') { sh = 'cmd'; args = ['/c', ...cmd]; } else { [sh, ...args] = cmd; } try { this.cp = spawn(sh, args, { cwd: pkg.path, env: Object.assign(Object.assign({}, process.env), process.stdout.isTTY ? { FORCE_COLOR: process.env.FORCE_COLOR || '1' } : {}), stdio: 'pipe', }); let data = ''; try { for (var _g = true, _h = __asyncValues(this.cp.stdout), _j; _j = yield _h.next(), _a = _j.done, !_a; _g = true) { _c = _j.value; _g = false; const chunk = _c; data += chunk; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (!_g && !_a && (_b = _h.return)) yield _b.call(_h); } finally { if (e_1) throw e_1.error; } } let error = ''; try { for (var _k = true, _l = __asyncValues(this.cp.stderr), _m; _m = yield _l.next(), _d = _m.done, !_d; _k = true) { _f = _m.value; _k = false; const chunk = _f; error += chunk; } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (!_k && !_d && (_e = _l.return)) yield _e.call(_l); } finally { if (e_2) throw e_2.error; } } const exitCode = yield new Promise((resolve) => { this.cp.on('close', resolve); }); if (exitCode) { throw new Error(`subprocess error exit ${exitCode}, ${error}`); } return { data, error }; // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error) { throw new Error(error.message); } }); } checkPackageCanPublish(pkg, allPackages, version, retries) { return __awaiter(this, void 0, void 0, function* () { this.log(''); ux.action.start(`${pkg.name}@${pkg.version}`, undefined, { stdout: true }); const matchedPackage = allPackages.value.find(azurePackage => azurePackage.name === pkg.name); if (pkg.version !== version) { this.warn(`${pkg.name}@${pkg.version} doesn't match desired publish version!`); ux.action.stop(chalk.red(`version doesn't match version ${version}`)); throw new Error(`Version in package.json doesn't match desired published version`); } if (!matchedPackage) { ux.action.stop(`${chalk.green('new package')}`); ux.action.start(`publish new package ${pkg.name}@${pkg.version} from ${pkg.jsonPath}`, undefined, { stdout: true }); try { yield this.publishPackage(pkg); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error) { if (error instanceof Error && error.message.includes('subprocess error exit')) { // Check if the error message contains 'subprocess error exit' // Extract the HTTP status code from the error message const statusCodeMatch = /\d{3}/.exec(error.message); const statusCode = statusCodeMatch ? Number.parseInt(statusCodeMatch[0], 10) : null; if (statusCode && (statusCode >= 400 && statusCode < 600)) { for (let i = 0; i < retries - 1; i++) { yield this.publishPackage(pkg); } } } } ux.action.stop(`${chalk.green('done')}`); return true; } const matchVersion = matchedPackage.versions.find(azurePackageVersion => azurePackageVersion.version === pkg.version); if (!matchVersion) { ux.action.stop(`${chalk.yellow('version missing')}`); ux.action.start(`publish new version ${pkg.name}@${pkg.version} from ${pkg.jsonPath}`, undefined, { stdout: true }); yield this.publishPackage(pkg); ux.action.stop(`${chalk.green('done')}`); return true; } this.warn(`${pkg.name}@${pkg.version} already exists`); ux.action.stop(`${chalk.blue('skipping')}`); return false; }); } publishPackages(packages, allPackages, version, retries) { return __awaiter(this, void 0, void 0, function* () { let errorCount = 0; this.log(`publishing ${packages.length} packages:`); this.log(packages.map(pkg => pkg.name).toString()); for (const pkg of packages) { try { yield this.checkPackageCanPublish(pkg, allPackages, version, retries); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error) { this.warn(error.message); errorCount++; continue; } } if (errorCount > 0) { throw new Error(`${errorCount} with Errors!`); } }); } run() { const _super = Object.create(null, { run: { get: () => super.run } }); return __awaiter(this, void 0, void 0, function* () { _super.run.call(this); try { const { flags } = yield this.parse(NpmPublish); const npmContext = new NpmContext(); ux.action.start('Parsing packages to check', undefined, { stdout: true }); const packages = yield npmContext.packageList(this, flags.package, flags.exclude); ux.action.stop(`${chalk.green('done')}`); ux.action.start('Getting list of published packages', undefined, { stdout: true }); const allPackages = (yield npmContext.getAllNpmPackages(flags.pat)).data; ux.action.stop(`${chalk.green('done')}`); yield this.publishPackages(packages, allPackages, flags.version, flags.retry); ux.action.stop('success'); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error) { ux.action.stop('error'); this.error(`${error.message}`); } }); } } NpmPublish.description = 'Publish npm packages'; NpmPublish.usage = 'npm:publish [options]'; NpmPublish.examples = [ '$ ops npm:publish -v 15.0.0', '$ ops npm:publish -v 15.0.0', '$ ops npm:publish -p @adinsure-tooling/* -v 15.0.0', '$ ops npm:publish -p @adinsure-tooling/* -x @adisure-tooling/studio-services -v 6.0.0', ]; NpmPublish.flags = { package: Flags.string({ char: 'p', description: 'package name filter you want to check', multiple: true, }), exclude: Flags.string({ char: 'x', description: 'exclude packages from filter', multiple: true, }), version: Flags.string({ char: 'v', description: 'version we want to check if published', required: true, }), pat: Flags.string({ description: 'PAT token or AZURE_DEVOPS_EXT_PAT environment variable', env: 'AZURE_DEVOPS_EXT_PAT', }), retry: Flags.integer({ description: 'Number of npm publishing retries in case of 4xx or 5xx http errors', default: 3, }), }; export default NpmPublish;