mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-15 01:54:04 +08:00
Currently, the version of a release is determined by the git tag. This PR changes release script to determine the release version from the `version` property in the root `package.json`. Release docs have also been updated.
248 lines
7.1 KiB
TypeScript
248 lines
7.1 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
// tslint:disable-next-line: no-global-tslint-disable
|
|
// tslint:disable: no-implicit-dependencies
|
|
import { JsonObject } from '@angular-devkit/core';
|
|
import { execSync } from 'child_process';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
|
|
const distRoot = path.join(__dirname, '../dist');
|
|
const { packages: monorepoPackages } = require('../.monorepo.json');
|
|
|
|
|
|
export interface PackageInfo {
|
|
name: string;
|
|
root: string;
|
|
bin: { [name: string]: string};
|
|
relative: string;
|
|
main: string;
|
|
dist: string;
|
|
build: string;
|
|
tar: string;
|
|
private: boolean;
|
|
experimental: boolean;
|
|
packageJson: JsonObject;
|
|
dependencies: string[];
|
|
reverseDependencies: string[];
|
|
|
|
snapshot: boolean;
|
|
snapshotRepo: string;
|
|
snapshotHash: string;
|
|
|
|
version: string;
|
|
}
|
|
export type PackageMap = { [name: string]: PackageInfo };
|
|
|
|
|
|
export function loadRootPackageJson() {
|
|
return require('../package.json');
|
|
}
|
|
|
|
function loadPackageJson(p: string) {
|
|
const root = loadRootPackageJson();
|
|
const pkg = require(p);
|
|
|
|
for (const key of Object.keys(root)) {
|
|
switch (key) {
|
|
// Keep the following keys from the package.json of the package itself.
|
|
case 'bin':
|
|
case 'description':
|
|
case 'dependencies':
|
|
case 'name':
|
|
case 'main':
|
|
case 'peerDependencies':
|
|
case 'optionalDependencies':
|
|
case 'typings':
|
|
case 'version':
|
|
case 'private':
|
|
case 'workspaces':
|
|
case 'resolutions':
|
|
case 'scripts':
|
|
continue;
|
|
|
|
// Remove the following keys from the package.json.
|
|
case 'devDependencies':
|
|
delete pkg[key];
|
|
continue;
|
|
|
|
// Merge the following keys with the root package.json.
|
|
case 'keywords':
|
|
const a = pkg[key] || [];
|
|
const b = Object.keys(
|
|
root[key].concat(a).reduce((acc: {[k: string]: boolean}, curr: string) => {
|
|
acc[curr] = true;
|
|
|
|
return acc;
|
|
}, {}));
|
|
pkg[key] = b;
|
|
break;
|
|
|
|
// Overwrite engines to a common default.
|
|
case 'engines':
|
|
pkg['engines'] = {
|
|
'node': '>= 12.13.0',
|
|
'npm': '^6.11.0 || ^7.5.6',
|
|
'yarn': '>= 1.13.0',
|
|
};
|
|
break;
|
|
|
|
// Overwrite the package's key with to root one.
|
|
default:
|
|
pkg[key] = root[key];
|
|
}
|
|
}
|
|
|
|
return pkg;
|
|
}
|
|
|
|
|
|
function _findAllPackageJson(dir: string, exclude: RegExp): string[] {
|
|
const result: string[] = [];
|
|
fs.readdirSync(dir)
|
|
.forEach(fileName => {
|
|
const p = path.join(dir, fileName);
|
|
|
|
if (exclude.test(p)) {
|
|
return;
|
|
} else if (/[\/\\]node_modules[\/\\]/.test(p)) {
|
|
return;
|
|
} else if (fileName == 'package.json') {
|
|
result.push(p);
|
|
} else if (fs.statSync(p).isDirectory() && fileName != 'node_modules') {
|
|
result.push(..._findAllPackageJson(p, exclude));
|
|
}
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
const tsConfigPath = path.join(__dirname, '../tsconfig.json');
|
|
const tsConfig = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
|
|
const pattern = '^('
|
|
+ (tsConfig.config.exclude as string[])
|
|
.map(ex => path.join(path.dirname(tsConfigPath), ex))
|
|
.map(ex => '('
|
|
+ ex
|
|
.replace(/[\-\[\]{}()+?./\\^$|]/g, '\\$&')
|
|
.replace(/(\\\\|\\\/)\*\*/g, '((\/|\\\\).+?)?')
|
|
.replace(/\*/g, '[^/\\\\]*')
|
|
+ ')')
|
|
.join('|')
|
|
+ ')($|/|\\\\)';
|
|
const excludeRe = new RegExp(pattern);
|
|
|
|
// Find all the package.json that aren't excluded from tsconfig.
|
|
const packageJsonPaths = _findAllPackageJson(path.join(__dirname, '..'), excludeRe)
|
|
// Remove the root package.json.
|
|
.filter(p => p != path.join(__dirname, '../package.json'));
|
|
|
|
|
|
function _exec(cmd: string) {
|
|
return execSync(cmd).toString().trim();
|
|
}
|
|
|
|
|
|
let gitShaCache: string;
|
|
function _getSnapshotHash(_pkg: PackageInfo): string {
|
|
if (!gitShaCache) {
|
|
gitShaCache = _exec('git log --format=%h -n1');
|
|
}
|
|
|
|
return gitShaCache;
|
|
}
|
|
|
|
|
|
const stableVersion = loadRootPackageJson().version;
|
|
const experimentalVersion = stableToExperimentalVersion(stableVersion);
|
|
|
|
/**
|
|
* Convert a stable version to its experimental equivalent. For example,
|
|
* stable = 10.2.3, experimental = 0.1002.3
|
|
* @param stable Must begin with d+.d+ where d is a 0-9 digit.
|
|
*/
|
|
export function stableToExperimentalVersion(stable: string): string {
|
|
return `0.${stable.replace(/^(\d+)\.(\d+)/, (_, major, minor) => {
|
|
return '' + (parseInt(major, 10) * 100 + parseInt(minor, 10));
|
|
})}`;
|
|
}
|
|
|
|
// All the supported packages. Go through the packages directory and create a map of
|
|
// name => PackageInfo. This map is partial as it lacks some information that requires the
|
|
// map itself to finish building.
|
|
export const packages: PackageMap =
|
|
packageJsonPaths
|
|
.map(pkgPath => ({ root: path.dirname(pkgPath) }))
|
|
.reduce((packages: PackageMap, pkg) => {
|
|
const pkgRoot = pkg.root;
|
|
const packageJson = loadPackageJson(path.join(pkgRoot, 'package.json'));
|
|
const name = packageJson['name'];
|
|
if (!name) {
|
|
// Only build the entry if there's a package name.
|
|
return packages;
|
|
}
|
|
if (!(name in monorepoPackages)) {
|
|
throw new Error(
|
|
`Package ${name} found in ${JSON.stringify(pkg.root)}, not found in .monorepo.json.`,
|
|
);
|
|
}
|
|
|
|
const bin: {[name: string]: string} = {};
|
|
Object.keys(packageJson['bin'] || {}).forEach(binName => {
|
|
let p = path.resolve(pkg.root, packageJson['bin'][binName]);
|
|
if (!fs.existsSync(p)) {
|
|
p = p.replace(/\.js$/, '.ts');
|
|
}
|
|
bin[binName] = p;
|
|
});
|
|
|
|
const experimental = !!packageJson.private || !!packageJson.experimental;
|
|
|
|
packages[name] = {
|
|
build: path.join(distRoot, pkgRoot.substr(path.dirname(__dirname).length)),
|
|
dist: path.join(distRoot, name),
|
|
root: pkgRoot,
|
|
relative: path.relative(path.dirname(__dirname), pkgRoot),
|
|
main: path.resolve(pkgRoot, 'src/index.ts'),
|
|
private: !!packageJson.private,
|
|
experimental,
|
|
// yarn doesn't take kindly to @ in tgz filenames
|
|
// https://github.com/yarnpkg/yarn/issues/6339
|
|
tar: path.join(distRoot, name.replace(/\/|@/g, '_') + '.tgz'),
|
|
bin,
|
|
name,
|
|
packageJson,
|
|
|
|
snapshot: !!monorepoPackages[name].snapshotRepo,
|
|
snapshotRepo: monorepoPackages[name].snapshotRepo,
|
|
get snapshotHash() {
|
|
return _getSnapshotHash(this);
|
|
},
|
|
|
|
dependencies: [],
|
|
reverseDependencies: [],
|
|
version: experimental ? experimentalVersion : stableVersion,
|
|
};
|
|
|
|
return packages;
|
|
}, {});
|
|
|
|
|
|
// Update with dependencies.
|
|
for (const pkgName of Object.keys(packages)) {
|
|
const pkg = packages[pkgName];
|
|
const pkgJson = require(path.join(pkg.root, 'package.json'));
|
|
pkg.dependencies = Object.keys(packages).filter(name => {
|
|
return name in (pkgJson.dependencies || {})
|
|
|| name in (pkgJson.devDependencies || {});
|
|
});
|
|
pkg.dependencies.forEach(depName => packages[depName].reverseDependencies.push(pkgName));
|
|
}
|