beachball
Advanced tools
Comparing version
# Changelog - beachball | ||
This log was last generated on Thu, 27 Jun 2019 17:50:27 GMT and should not be manually modified. | ||
This log was last generated on Thu, 27 Jun 2019 21:10:09 GMT and should not be manually modified. | ||
## 1.8.1 | ||
Thu, 27 Jun 2019 21:10:09 GMT | ||
### Patches | ||
- use object.values (kchau@microsoft.com) | ||
## 1.8.0 | ||
Thu, 27 Jun 2019 17:50:27 GMT | ||
Thu, 27 Jun 2019 17:50:36 GMT | ||
@@ -8,0 +15,0 @@ ### Minor |
@@ -18,8 +18,5 @@ export interface PackageInfo { | ||
packageInfos: { | ||
[pkgName: string]: PackageInfo; | ||
[pkgName: string]: import("./monorepo").PackageInfo; | ||
}; | ||
}; | ||
export declare function getPackageInfos(cwd: string): { | ||
[pkgName: string]: PackageInfo; | ||
}; | ||
//# sourceMappingURL=bump.d.ts.map |
@@ -11,3 +11,2 @@ "use strict"; | ||
const fs_1 = __importDefault(require("fs")); | ||
const glob_1 = __importDefault(require("glob")); | ||
const path_1 = __importDefault(require("path")); | ||
@@ -20,3 +19,3 @@ const semver_1 = __importDefault(require("semver")); | ||
// Gather all package info from package.json | ||
const packageInfos = getPackageInfos(cwd); | ||
const packageInfos = monorepo_1.getPackageInfos(cwd); | ||
// Apply package.json version updates | ||
@@ -76,40 +75,1 @@ Object.keys(packageChangeTypes).forEach(pkgName => { | ||
} | ||
function getPackageInfos(cwd) { | ||
const gitRoot = paths_1.findGitRoot(cwd) || cwd; | ||
const packagePatterns = monorepo_1.getPackagePatterns(cwd); | ||
const packageInfos = {}; | ||
if (packagePatterns && packagePatterns.length > 0) { | ||
packagePatterns.forEach(pattern => { | ||
const packageJsonPattern = path_1.default.join(pattern, 'package.json'); | ||
const packageJsonFiles = glob_1.default.sync(packageJsonPattern, { cwd: gitRoot }); | ||
packageJsonFiles.forEach(packageJsonPath => { | ||
try { | ||
const packageJson = require(path_1.default.join(gitRoot, packageJsonPath)); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath, | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} | ||
catch (e) { | ||
// Pass, the package.json is invalid | ||
} | ||
}); | ||
}); | ||
} | ||
else { | ||
const packageJsonPath = path_1.default.join(paths_1.findPackageRoot(cwd), 'package.json'); | ||
const packageJson = require(packageJsonPath); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath: 'package.json', | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} | ||
return packageInfos; | ||
} | ||
exports.getPackageInfos = getPackageInfos; |
@@ -6,5 +6,5 @@ import { ChangeInfo } from './ChangeInfo'; | ||
*/ | ||
export declare function promptForChange(branch: string, cwd: string): Promise<{ | ||
export declare function promptForChange(branch: string, specificPackage: string, cwd: string): Promise<{ | ||
[pkgname: string]: ChangeInfo; | ||
}>; | ||
} | undefined>; | ||
/** | ||
@@ -11,0 +11,0 @@ * Loops through the `changes` and writes out a list of change files |
@@ -24,9 +24,8 @@ "use strict"; | ||
*/ | ||
function promptForChange(branch, cwd) { | ||
function promptForChange(branch, specificPackage, cwd) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const changedPackages = getChangedPackages_1.getChangedPackages(branch, cwd); | ||
const changedPackages = specificPackage ? [specificPackage] : getChangedPackages_1.getChangedPackages(branch, cwd); | ||
const recentMessages = git_1.getRecentCommitMessages(branch, cwd) || []; | ||
const packageChangeInfo = {}; | ||
yield changedPackages.reduce((currentPromise, pkg) => __awaiter(this, void 0, void 0, function* () { | ||
yield currentPromise; | ||
for (let pkg of changedPackages) { | ||
console.log(''); | ||
@@ -60,3 +59,3 @@ console.log(`Please describe the changes for: ${pkg}`); | ||
packageChangeInfo[pkg] = Object.assign({}, response, { packageName: pkg, email: git_1.getUserEmail(cwd) || 'email not defined', commit: git_1.getCurrentHash(cwd) || 'hash not available', date: new Date() }); | ||
}), Promise.resolve()); | ||
} | ||
return packageChangeInfo; | ||
@@ -63,0 +62,0 @@ }); |
@@ -45,3 +45,3 @@ "use strict"; | ||
catch (e) { | ||
console.warn("The CHANGELOG.json file is invalid, skipping writing to it"); | ||
console.warn('The CHANGELOG.json file is invalid, skipping writing to it'); | ||
} | ||
@@ -53,3 +53,2 @@ }); | ||
function renderJsonChangelog(previous, changelog) { | ||
console.log('previous\n', previous.entries); | ||
const result = { | ||
@@ -56,0 +55,0 @@ name: changelog.name, |
@@ -20,3 +20,2 @@ "use strict"; | ||
const publish_1 = require("./publish"); | ||
const changelog_1 = require("./changelog"); | ||
const yargs_parser_1 = __importDefault(require("yargs-parser")); | ||
@@ -32,3 +31,4 @@ let argv = process.argv.splice(2); | ||
help: ['h', '?'], | ||
yes: ['y'] | ||
yes: ['y'], | ||
package: ['p'] | ||
} | ||
@@ -57,7 +57,9 @@ }); | ||
yes: args.yes === true || false, | ||
access: args.access || 'restricted' | ||
access: args.access || 'restricted', | ||
package: args.package || '' | ||
}; | ||
(() => __awaiter(this, void 0, void 0, function* () { | ||
// Validation Steps | ||
if (!validation_1.isGitAvailable(options.path)) { | ||
console.error('Please make sure git is installed and initialize the repository with "git init".'); | ||
console.error('ERROR: Please make sure git is installed and initialize the repository with "git init".'); | ||
process.exit(1); | ||
@@ -67,4 +69,4 @@ } | ||
if (uncommitted && uncommitted.length > 0) { | ||
console.warn('There are uncommitted changes in your repository. Please commit these files first:'); | ||
console.warn('- ' + uncommitted.join('\n- ')); | ||
console.error('ERROR: There are uncommitted changes in your repository. Please commit these files first:'); | ||
console.error('- ' + uncommitted.join('\n- ')); | ||
process.exit(1); | ||
@@ -74,5 +76,9 @@ } | ||
if (isChangeNeeded && options.command !== 'change') { | ||
console.log('Change files are needed! Run "beachball" to generate change files.'); | ||
console.error('ERROR: Change files are needed! Run "beachball" to generate change files.'); | ||
process.exit(1); | ||
} | ||
if (options.package && !validation_1.isValidPackageName(options.package, options.path)) { | ||
console.error('ERROR: Specified package name is not valid'); | ||
process.exit(1); | ||
} | ||
switch (options.command) { | ||
@@ -82,5 +88,2 @@ case 'check': | ||
break; | ||
case 'changelog': | ||
const packageInfos = bump_1.getPackageInfos(options.path); | ||
changelog_1.writeChangelog(packageInfos, options.path); | ||
case 'publish': | ||
@@ -93,7 +96,7 @@ publish_1.publish(options); | ||
default: | ||
if (!isChangeNeeded) { | ||
if (!isChangeNeeded && !options.package) { | ||
console.log('No change files are needed'); | ||
return; | ||
} | ||
const changes = yield changefile_1.promptForChange(options.branch, options.path); | ||
const changes = yield changefile_1.promptForChange(options.branch, options.package, options.path); | ||
if (changes) { | ||
@@ -135,2 +138,3 @@ changefile_1.writeChangeFiles(changes, options.path); | ||
--yes, -y - skips the prompts for publish | ||
--package, -p - manually specify a package to create a change file; creates a change file regardless of diffs | ||
@@ -137,0 +141,0 @@ Examples: |
@@ -13,3 +13,4 @@ export interface CliOptions { | ||
access: 'public' | 'restricted'; | ||
package: string; | ||
} | ||
//# sourceMappingURL=CliOptions.d.ts.map |
@@ -6,7 +6,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const monorepo_1 = require("./monorepo"); | ||
const paths_1 = require("./paths"); | ||
const git_1 = require("./git"); | ||
const fs_1 = __importDefault(require("fs")); | ||
const minimatch_1 = __importDefault(require("minimatch")); | ||
const path_1 = __importDefault(require("path")); | ||
@@ -18,3 +16,2 @@ /** | ||
function getAllChangedPackages(branch, cwd) { | ||
const gitRoot = paths_1.findGitRoot(cwd) || cwd; | ||
const changes = git_1.getChanges(branch, cwd); | ||
@@ -40,21 +37,3 @@ const packageRoots = {}; | ||
} | ||
if (monorepo_1.findLernaConfig(cwd)) { | ||
const packagePatterns = monorepo_1.getPackagePatterns(cwd); | ||
return Object.keys(packageRoots) | ||
.filter(pkgPath => { | ||
for (let pattern of packagePatterns) { | ||
const relativePath = path_1.default.relative(gitRoot, pkgPath); | ||
if (minimatch_1.default(relativePath, pattern)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}) | ||
.map(pkgPath => { | ||
return packageRoots[pkgPath]; | ||
}); | ||
} | ||
else { | ||
return Object.values(packageRoots); | ||
} | ||
return Object.values(packageRoots); | ||
} | ||
@@ -61,0 +40,0 @@ /** |
@@ -25,2 +25,3 @@ export declare function git(args: string[], options?: { | ||
export declare function getDefaultRemoteMaster(cwd: string): string; | ||
export declare function listAllTrackedFiles(cwd: string): string[]; | ||
//# sourceMappingURL=git.d.ts.map |
@@ -10,3 +10,3 @@ "use strict"; | ||
const paths_1 = require("./paths"); | ||
const url_1 = __importDefault(require("url")); | ||
const git_url_parse_1 = __importDefault(require("git-url-parse")); | ||
function git(args, options) { | ||
@@ -207,2 +207,9 @@ const results = child_process_1.spawnSync('git', args, options); | ||
exports.parseRemoteBranch = parseRemoteBranch; | ||
function normalizeRepoUrl(repositoryUrl) { | ||
const parsed = git_url_parse_1.default(repositoryUrl); | ||
return parsed | ||
.toString('https') | ||
.replace(/\.git$/, '') | ||
.toLowerCase(); | ||
} | ||
function getDefaultRemoteMaster(cwd) { | ||
@@ -225,3 +232,3 @@ let packageJson; | ||
} | ||
const normalizedUrl = url_1.default.format(url_1.default.parse(repositoryUrl)).toLowerCase(); | ||
const normalizedUrl = normalizeRepoUrl(repositoryUrl); | ||
const remotesResult = git(['remote', '-v'], { cwd }); | ||
@@ -232,3 +239,3 @@ if (remotesResult.success) { | ||
const parts = line.split(/\s+/); | ||
allRemotes[parts[1]] = url_1.default.format(url_1.default.parse(parts[0])).toLowerCase(); | ||
allRemotes[normalizeRepoUrl(parts[1])] = parts[0]; | ||
}); | ||
@@ -247,1 +254,9 @@ if (Object.keys(allRemotes).length > 0) { | ||
exports.getDefaultRemoteMaster = getDefaultRemoteMaster; | ||
function listAllTrackedFiles(cwd) { | ||
const results = git(['ls-tree', '-r', '--name-only', '--full-tree', 'HEAD'], { cwd }); | ||
if (results.success) { | ||
return results.stdout.split(/\n/); | ||
} | ||
return []; | ||
} | ||
exports.listAllTrackedFiles = listAllTrackedFiles; |
@@ -1,3 +0,16 @@ | ||
export declare function findLernaConfig(cwd: string): string | null; | ||
export declare function getPackagePatterns(cwd: string): string[]; | ||
export interface PackageInfo { | ||
name: string; | ||
packageJsonPath: string; | ||
version: string; | ||
dependencies: { | ||
[dep: string]: string; | ||
}; | ||
devDependencies: { | ||
[dep: string]: string; | ||
}; | ||
} | ||
export declare function getAllPackages(cwd: string): string[]; | ||
export declare function getPackageInfos(cwd: string): { | ||
[pkgName: string]: PackageInfo; | ||
}; | ||
//# sourceMappingURL=monorepo.d.ts.map |
@@ -9,19 +9,43 @@ "use strict"; | ||
const path_1 = __importDefault(require("path")); | ||
function findLernaConfig(cwd) { | ||
return paths_1.searchUp('lerna.json', cwd); | ||
const git_1 = require("./git"); | ||
function getAllPackages(cwd) { | ||
const infos = getPackageInfos(cwd); | ||
return Object.keys(infos); | ||
} | ||
exports.findLernaConfig = findLernaConfig; | ||
function getPackagePatterns(cwd) { | ||
const config = findLernaConfig(cwd); | ||
if (config) { | ||
try { | ||
const lernaConfig = JSON.parse(fs_1.default.readFileSync(path_1.default.join(config, 'lerna.json')).toString()); | ||
return lernaConfig.packages || ['packages/*']; | ||
} | ||
catch (e) { | ||
throw new Error('Cannot parse the lerna.json configuration file!'); | ||
} | ||
exports.getAllPackages = getAllPackages; | ||
function getPackageInfos(cwd) { | ||
const trackedFiles = git_1.listAllTrackedFiles(cwd); | ||
const packageJsonFiles = trackedFiles.filter(file => path_1.default.basename(file) === 'package.json'); | ||
const packageInfos = {}; | ||
if (packageJsonFiles && packageJsonFiles.length > 0) { | ||
packageJsonFiles.forEach(packageJsonPath => { | ||
try { | ||
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8')); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath, | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} | ||
catch (e) { | ||
// Pass, the package.json is invalid | ||
console.warn(`Invalid package.json file detected ${packageJsonPath}`); | ||
} | ||
}); | ||
} | ||
return []; | ||
else { | ||
const packageJsonPath = path_1.default.join(paths_1.findPackageRoot(cwd), 'package.json'); | ||
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8')); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath, | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} | ||
return packageInfos; | ||
} | ||
exports.getPackagePatterns = getPackagePatterns; | ||
exports.getPackageInfos = getPackageInfos; |
@@ -22,8 +22,13 @@ "use strict"; | ||
const currentBranch = git_1.getBranchName(cwd); | ||
console.log(`Publishing from beachball | ||
console.log(`Publishing with the following configuration: | ||
registry: ${registry} | ||
current branch: ${currentBranch} | ||
target branch: ${branch} | ||
tag: ${tag} | ||
publishes to npm registry: ${options.publish ? 'yes' : 'no'} | ||
pushes to remote git repo: ${options.push && options.branch ? 'yes' : 'no'} | ||
`); | ||
@@ -69,14 +74,9 @@ if (!options.yes) { | ||
} | ||
else { | ||
console.log('Skipping publish'); | ||
} | ||
// Step 2. | ||
// - For repos with no remotes: just commit and move on! | ||
// - For repos with remotes: reset, fetch latest from origin/master (to ensure less chance of conflict), then bump again + commit | ||
// - reset, fetch latest from origin/master (to ensure less chance of conflict), then bump again + commit | ||
if (!branch || !options.push) { | ||
console.log('Committing changes locally.'); | ||
const mergePublishBranchResult = mergePublishBranch(publishBranch, branch, message, cwd); | ||
if (!mergePublishBranchResult.success) { | ||
console.error('CRITICAL ERROR: merging to target has failed!'); | ||
displayManualRecovery(bumpInfo); | ||
process.exit(1); | ||
} | ||
tagPackages(bumpInfo, tag, cwd); | ||
console.log('Skipping git push and tagging'); | ||
} | ||
@@ -83,0 +83,0 @@ else { |
export declare function isChangeFileNeeded(branch: string, cwd: string): boolean; | ||
export declare function isGitAvailable(cwd: string): string | false | null; | ||
export declare function isValidTargetBranch(branch?: string): boolean; | ||
export declare function isValidPackageName(pkg: string, cwd: string): boolean; | ||
//# sourceMappingURL=validation.d.ts.map |
@@ -6,2 +6,3 @@ "use strict"; | ||
const git_1 = require("./git"); | ||
const monorepo_1 = require("./monorepo"); | ||
function isChangeFileNeeded(branch, cwd) { | ||
@@ -26,1 +27,6 @@ console.log(`Checking for changes against "${branch}"`); | ||
exports.isValidTargetBranch = isValidTargetBranch; | ||
function isValidPackageName(pkg, cwd) { | ||
const packages = monorepo_1.getAllPackages(cwd); | ||
return packages.includes(pkg); | ||
} | ||
exports.isValidPackageName = isValidPackageName; |
{ | ||
"name": "beachball", | ||
"version": "1.8.0", | ||
"version": "1.8.1", | ||
"main": "index.js", | ||
@@ -19,5 +19,5 @@ "license": "MIT", | ||
"fs-extra": "^8.0.1", | ||
"git-url-parse": "^11.1.2", | ||
"glob": "^7.1.4", | ||
"prompts": "~2.1.0", | ||
"minimatch": "^3.0.4", | ||
"semver": "^6.1.1", | ||
@@ -28,2 +28,3 @@ "yargs-parser": "^13.1.0" | ||
"@types/fs-extra": "^7.0.0", | ||
"@types/git-url-parse": "^9.0.0", | ||
"@types/glob": "^7.1.1", | ||
@@ -30,0 +31,0 @@ "@types/minimatch": "^3.0.3", |
import { findPackageRoot, findGitRoot } from './paths'; | ||
import { getPackageChangeTypes } from './changefile'; | ||
import { getPackagePatterns } from './monorepo'; | ||
import { getPackageInfos } from './monorepo'; | ||
import { writeChangelog } from './changelog'; | ||
@@ -90,42 +90,1 @@ import fs from 'fs'; | ||
} | ||
export function getPackageInfos(cwd: string) { | ||
const gitRoot = findGitRoot(cwd) || cwd; | ||
const packagePatterns = getPackagePatterns(cwd); | ||
const packageInfos: { [pkgName: string]: PackageInfo } = {}; | ||
if (packagePatterns && packagePatterns.length > 0) { | ||
packagePatterns.forEach(pattern => { | ||
const packageJsonPattern = path.join(pattern, 'package.json'); | ||
const packageJsonFiles = glob.sync(packageJsonPattern, { cwd: gitRoot }); | ||
packageJsonFiles.forEach(packageJsonPath => { | ||
try { | ||
const packageJson = require(path.join(gitRoot, packageJsonPath)); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath, | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} catch (e) { | ||
// Pass, the package.json is invalid | ||
} | ||
}); | ||
}); | ||
} else { | ||
const packageJsonPath = path.join(findPackageRoot(cwd)!, 'package.json'); | ||
const packageJson = require(packageJsonPath); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath: 'package.json', | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} | ||
return packageInfos; | ||
} |
@@ -13,10 +13,8 @@ import { ChangeInfo } from './ChangeInfo'; | ||
*/ | ||
export async function promptForChange(branch: string, cwd: string) { | ||
const changedPackages = getChangedPackages(branch, cwd); | ||
export async function promptForChange(branch: string, specificPackage: string, cwd: string) { | ||
const changedPackages = specificPackage ? [specificPackage] : getChangedPackages(branch, cwd); | ||
const recentMessages = getRecentCommitMessages(branch, cwd) || []; | ||
const packageChangeInfo: { [pkgname: string]: ChangeInfo } = {}; | ||
await changedPackages.reduce(async (currentPromise, pkg) => { | ||
await currentPromise; | ||
for (let pkg of changedPackages) { | ||
console.log(''); | ||
@@ -59,3 +57,3 @@ console.log(`Please describe the changes for: ${pkg}`); | ||
}; | ||
}, Promise.resolve()); | ||
} | ||
@@ -62,0 +60,0 @@ return packageChangeInfo; |
@@ -26,4 +26,4 @@ import { readChangeFiles, unlinkChangeFiles } from './changefile'; | ||
interface ChangelogJsonEntry { | ||
date: string, | ||
version: string, | ||
date: string; | ||
version: string; | ||
changes: { | ||
@@ -34,3 +34,3 @@ patch?: ChangelogEntry[]; | ||
none?: ChangelogEntry[]; | ||
} | ||
}; | ||
} | ||
@@ -84,3 +84,3 @@ | ||
} catch (e) { | ||
console.warn("The CHANGELOG.json file is invalid, skipping writing to it") | ||
console.warn('The CHANGELOG.json file is invalid, skipping writing to it'); | ||
} | ||
@@ -93,4 +93,2 @@ }); | ||
function renderJsonChangelog(previous: ChangelogJson, changelog: PackageChangelog) { | ||
console.log('previous\n', previous.entries); | ||
const result: ChangelogJson = { | ||
@@ -105,3 +103,3 @@ name: changelog.name, | ||
changes: changelog.changes | ||
} | ||
}; | ||
@@ -120,5 +118,5 @@ result.entries.unshift(newEntry); | ||
? previous | ||
.split(/\n/g) | ||
.slice(3) | ||
.join('\n') | ||
.split(/\n/g) | ||
.slice(3) | ||
.join('\n') | ||
: '') | ||
@@ -125,0 +123,0 @@ ); |
@@ -1,9 +0,8 @@ | ||
import { bump, getPackageInfos } from './bump'; | ||
import { bump } from './bump'; | ||
import { CliOptions } from './CliOptions'; | ||
import { findPackageRoot } from './paths'; | ||
import { getUncommittedChanges, getParentBranch, getDefaultRemoteMaster, getRemoteBranch } from './git'; | ||
import { isChangeFileNeeded as checkChangeFileNeeded, isGitAvailable, isValidTargetBranch } from './validation'; | ||
import { getUncommittedChanges, getDefaultRemoteMaster } from './git'; | ||
import { isChangeFileNeeded as checkChangeFileNeeded, isGitAvailable, isValidTargetBranch, isValidPackageName } from './validation'; | ||
import { promptForChange, writeChangeFiles } from './changefile'; | ||
import { publish } from './publish'; | ||
import { writeChangelog } from './changelog'; | ||
import parser from 'yargs-parser'; | ||
@@ -20,3 +19,4 @@ | ||
help: ['h', '?'], | ||
yes: ['y'] | ||
yes: ['y'], | ||
package: ['p'] | ||
} | ||
@@ -48,8 +48,11 @@ }); | ||
yes: args.yes === true || false, | ||
access: args.access || 'restricted' | ||
access: args.access || 'restricted', | ||
package: args.package || '' | ||
}; | ||
(async () => { | ||
// Validation Steps | ||
if (!isGitAvailable(options.path)) { | ||
console.error('Please make sure git is installed and initialize the repository with "git init".'); | ||
console.error('ERROR: Please make sure git is installed and initialize the repository with "git init".'); | ||
process.exit(1); | ||
@@ -61,4 +64,4 @@ } | ||
if (uncommitted && uncommitted.length > 0) { | ||
console.warn('There are uncommitted changes in your repository. Please commit these files first:'); | ||
console.warn('- ' + uncommitted.join('\n- ')); | ||
console.error('ERROR: There are uncommitted changes in your repository. Please commit these files first:'); | ||
console.error('- ' + uncommitted.join('\n- ')); | ||
process.exit(1); | ||
@@ -70,6 +73,11 @@ } | ||
if (isChangeNeeded && options.command !== 'change') { | ||
console.log('Change files are needed! Run "beachball" to generate change files.'); | ||
console.error('ERROR: Change files are needed! Run "beachball" to generate change files.'); | ||
process.exit(1); | ||
} | ||
if (options.package && !isValidPackageName(options.package, options.path)) { | ||
console.error('ERROR: Specified package name is not valid'); | ||
process.exit(1); | ||
} | ||
switch (options.command) { | ||
@@ -80,6 +88,2 @@ case 'check': | ||
case 'changelog': | ||
const packageInfos = getPackageInfos(options.path); | ||
writeChangelog(packageInfos, options.path); | ||
case 'publish': | ||
@@ -94,3 +98,3 @@ publish(options); | ||
default: | ||
if (!isChangeNeeded) { | ||
if (!isChangeNeeded && !options.package) { | ||
console.log('No change files are needed'); | ||
@@ -100,3 +104,3 @@ return; | ||
const changes = await promptForChange(options.branch, options.path); | ||
const changes = await promptForChange(options.branch, options.package, options.path); | ||
@@ -141,2 +145,3 @@ if (changes) { | ||
--yes, -y - skips the prompts for publish | ||
--package, -p - manually specify a package to create a change file; creates a change file regardless of diffs | ||
@@ -143,0 +148,0 @@ Examples: |
@@ -13,2 +13,3 @@ export interface CliOptions { | ||
access: 'public' | 'restricted'; | ||
package: string; | ||
} |
import { ChangeInfo } from './ChangeInfo'; | ||
import { findLernaConfig, getPackagePatterns } from './monorepo'; | ||
import { findPackageRoot, findGitRoot, getChangePath } from './paths'; | ||
import { findPackageRoot, getChangePath } from './paths'; | ||
import { getChanges, git } from './git'; | ||
import fs from 'fs'; | ||
import minimatch from 'minimatch'; | ||
import path from 'path'; | ||
@@ -14,3 +12,2 @@ | ||
function getAllChangedPackages(branch: string, cwd: string) { | ||
const gitRoot = findGitRoot(cwd) || cwd; | ||
const changes = getChanges(branch, cwd); | ||
@@ -39,22 +36,3 @@ | ||
if (findLernaConfig(cwd)) { | ||
const packagePatterns = getPackagePatterns(cwd); | ||
return Object.keys(packageRoots) | ||
.filter(pkgPath => { | ||
for (let pattern of packagePatterns) { | ||
const relativePath = path.relative(gitRoot, pkgPath); | ||
if (minimatch(relativePath, pattern)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}) | ||
.map(pkgPath => { | ||
return packageRoots[pkgPath]; | ||
}); | ||
} else { | ||
return Object.values(packageRoots); | ||
} | ||
return Object.values(packageRoots); | ||
} | ||
@@ -61,0 +39,0 @@ |
@@ -6,2 +6,3 @@ import { spawnSync } from 'child_process'; | ||
import url from 'url'; | ||
import gitUrlParse from 'git-url-parse'; | ||
@@ -231,2 +232,10 @@ export function git(args: string[], options?: { cwd: string }) { | ||
function normalizeRepoUrl(repositoryUrl: string) { | ||
const parsed = gitUrlParse(repositoryUrl); | ||
return parsed | ||
.toString('https') | ||
.replace(/\.git$/, '') | ||
.toLowerCase(); | ||
} | ||
export function getDefaultRemoteMaster(cwd: string) { | ||
@@ -252,3 +261,3 @@ let packageJson: any; | ||
const normalizedUrl = url.format(url.parse(repositoryUrl)).toLowerCase(); | ||
const normalizedUrl = normalizeRepoUrl(repositoryUrl); | ||
const remotesResult = git(['remote', '-v'], { cwd }); | ||
@@ -260,3 +269,3 @@ | ||
const parts = line.split(/\s+/); | ||
allRemotes[parts[1]] = url.format(url.parse(parts[0])).toLowerCase(); | ||
allRemotes[normalizeRepoUrl(parts[1])] = parts[0]; | ||
}); | ||
@@ -277,1 +286,11 @@ | ||
} | ||
export function listAllTrackedFiles(cwd: string) { | ||
const results = git(['ls-tree', '-r', '--name-only', '--full-tree', 'HEAD'], { cwd }); | ||
if (results.success) { | ||
return results.stdout.split(/\n/); | ||
} | ||
return []; | ||
} |
@@ -1,22 +0,56 @@ | ||
import { searchUp } from './paths'; | ||
import { searchUp, findPackageRoot } from './paths'; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import { listAllTrackedFiles } from './git'; | ||
import { fileURLToPath } from 'url'; | ||
export function findLernaConfig(cwd: string) { | ||
return searchUp('lerna.json', cwd); | ||
export interface PackageInfo { | ||
name: string; | ||
packageJsonPath: string; | ||
version: string; | ||
dependencies: { [dep: string]: string }; | ||
devDependencies: { [dep: string]: string }; | ||
} | ||
export function getPackagePatterns(cwd: string): string[] { | ||
const config = findLernaConfig(cwd); | ||
export function getAllPackages(cwd: string): string[] { | ||
const infos = getPackageInfos(cwd); | ||
return Object.keys(infos); | ||
} | ||
if (config) { | ||
try { | ||
const lernaConfig = JSON.parse(fs.readFileSync(path.join(config, 'lerna.json')).toString()); | ||
return lernaConfig.packages || ['packages/*']; | ||
} catch (e) { | ||
throw new Error('Cannot parse the lerna.json configuration file!'); | ||
} | ||
export function getPackageInfos(cwd: string) { | ||
const trackedFiles = listAllTrackedFiles(cwd); | ||
const packageJsonFiles = trackedFiles.filter(file => path.basename(file) === 'package.json'); | ||
const packageInfos: { [pkgName: string]: PackageInfo } = {}; | ||
if (packageJsonFiles && packageJsonFiles.length > 0) { | ||
packageJsonFiles.forEach(packageJsonPath => { | ||
try { | ||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath, | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} catch (e) { | ||
// Pass, the package.json is invalid | ||
console.warn(`Invalid package.json file detected ${packageJsonPath}`); | ||
} | ||
}); | ||
} else { | ||
const packageJsonPath = path.join(findPackageRoot(cwd)!, 'package.json'); | ||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); | ||
packageInfos[packageJson.name] = { | ||
name: packageJson.name, | ||
version: packageJson.version, | ||
packageJsonPath, | ||
dependencies: packageJson.dependencies, | ||
devDependencies: packageJson.devDependencies | ||
}; | ||
} | ||
return []; | ||
return packageInfos; | ||
} |
@@ -12,8 +12,13 @@ import { bump, BumpInfo } from './bump'; | ||
console.log(`Publishing from beachball | ||
console.log(`Publishing with the following configuration: | ||
registry: ${registry} | ||
current branch: ${currentBranch} | ||
target branch: ${branch} | ||
tag: ${tag} | ||
publishes to npm registry: ${options.publish ? 'yes' : 'no'} | ||
pushes to remote git repo: ${options.push && options.branch ? 'yes' : 'no'} | ||
`); | ||
@@ -63,21 +68,12 @@ | ||
}); | ||
} else { | ||
console.log('Skipping publish'); | ||
} | ||
// Step 2. | ||
// - For repos with no remotes: just commit and move on! | ||
// - For repos with remotes: reset, fetch latest from origin/master (to ensure less chance of conflict), then bump again + commit | ||
// - reset, fetch latest from origin/master (to ensure less chance of conflict), then bump again + commit | ||
if (!branch || !options.push) { | ||
console.log('Committing changes locally.'); | ||
const mergePublishBranchResult = mergePublishBranch(publishBranch, branch, message, cwd); | ||
if (!mergePublishBranchResult.success) { | ||
console.error('CRITICAL ERROR: merging to target has failed!'); | ||
displayManualRecovery(bumpInfo); | ||
process.exit(1); | ||
} | ||
tagPackages(bumpInfo, tag, cwd); | ||
console.log('Skipping git push and tagging'); | ||
} else { | ||
const { remote, remoteBranch } = parseRemoteBranch(branch); | ||
console.log('Reverting and fetching from remote'); | ||
@@ -84,0 +80,0 @@ |
import { findGitRoot } from './paths'; | ||
import { getChangedPackages } from './getChangedPackages'; | ||
import { git } from './git'; | ||
import { getAllPackages } from './monorepo'; | ||
@@ -25,1 +26,6 @@ export function isChangeFileNeeded(branch: string, cwd: string) { | ||
} | ||
export function isValidPackageName(pkg: string, cwd: string) { | ||
const packages = getAllPackages(cwd); | ||
return packages.includes(pkg); | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
7
-22.22%96072
-0.14%9
12.5%2319
-0.43%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed