diff --git a/GUIDE.md b/GUIDE.md index 03fe1afa..c31c481b 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -3,6 +3,7 @@ - [Installation](#installation) + - [Install `hub`](#install-hub) - [Dry Mode](#dry-mode) - [Integrate with Circle CI](#integrate-with-circle-ci) - [NPM Token](#npm-token) @@ -212,27 +213,27 @@ By default, `publishCommand` returns `yarn publish` or `npm publish`. You can ov ### Release your monorepo project -Ship.js currently supports monorepo project unless you want independent versioning in your packages. - -Let's say you have the following package.json files: - -- package.json -- packages/first-package/package.json -- packages/second-package/package.json -- example/package.json +Ship.js currently supports monorepo project(Independent versioning is not supported at the moment). ```js module.exports = { - filesToBump: [ - "package.json", - "packages/first-package/package.json", - "packages/second-package/package.json", - "example/package.json" - ] + monorepo: { + readVersionFrom: 'package.json', + packagesToBump: ['packages/*', 'examples/*'], + packagesToPublish: ['packages/*'], + } }; ``` -With the config above, Ship.js will read the current version from the first entry from the array, which is `package.json`. After figuring out the next version, the next version will be updated to the all package.json files. +With the config above, `prepare` command will + +1. Read the current version from `package.json` file at the project root directory. +2. Calculate the next version based on commit messages. +3. Update the next version over `package.json` files in `['packages/*', 'examples/*']`. + +And `release` command will publish packages in `['packages/*']`. + +When Ship.js handles `packagesToBump` and `packagesToPublish`, it will only list directories with `package.json` inside them. ### Schedule your release diff --git a/package.json b/package.json index 15e42cab..a39ed346 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "tw2": "yarn workspace shipjs test:watch", "bootstrap": "./packages/shipjs-lib/tests/bootstrap.sh", "release:prepare": "npx shipjs prepare", - "release:trigger": "npx shipjs release" + "release:trigger": "npx shipjs release", + "toc": "npx markdown-toc -i --bullets=\"-\" GUIDE.md" }, "author": "Algolia ", "license": "MIT", diff --git a/packages/shipjs-lib/src/index.js b/packages/shipjs-lib/src/index.js index 801eaea0..3f09d106 100644 --- a/packages/shipjs-lib/src/index.js +++ b/packages/shipjs-lib/src/index.js @@ -1,8 +1,5 @@ /* version */ export { default as getCurrentVersion } from './lib/util/getCurrentVersion'; -export { - default as hasTagForCurrentVersion, -} from './lib/util/hasTagForCurrentVersion'; export { default as getNextVersion } from './lib/util/getNextVersion'; export { default as updateVersion } from './lib/util/updateVersion'; export { default as isValidVersion } from './lib/util/isValidVersion'; @@ -19,6 +16,7 @@ export { default as getRepoURL } from './lib/git/getRepoURL'; export { default as getLatestCommitHash } from './lib/git/getLatestCommitHash'; export { default as getCommitUrl } from './lib/git/getCommitUrl'; export { default as isWorkingTreeClean } from './lib/git/isWorkingTreeClean'; +export { default as hasTag } from './lib/git/hasTag'; /* shell */ export { default as exec } from './lib/shell/exec'; @@ -29,3 +27,4 @@ export { default as loadConfig } from './lib/config/loadConfig'; /* etc */ export { default as getAppName } from './lib/util/getAppName'; +export { default as expandPackageList } from './lib/util/expandPackageList'; diff --git a/packages/shipjs-lib/src/lib/config/defaultConfig.js b/packages/shipjs-lib/src/lib/config/defaultConfig.js index 260c6893..3affa4e8 100644 --- a/packages/shipjs-lib/src/lib/config/defaultConfig.js +++ b/packages/shipjs-lib/src/lib/config/defaultConfig.js @@ -1,6 +1,10 @@ export default { remote: 'origin', - filesToBump: ['package.json'], + // monorepo: { + // readVersionFrom: 'package.json', + // packagesToBump: ['packages/*', 'examples/*'], + // packagesToPublish: ['packages/*'], + // }, updateChangelog: true, conventionalChangelogArgs: '-p angular -i CHANGELOG.md -s', installCommand: ({ isYarn }) => (isYarn ? 'yarn install' : 'npm install'), @@ -70,8 +74,8 @@ export default { ].join(', ')}]`; }, buildCommand: ({ isYarn }) => (isYarn ? 'yarn build' : 'npm run build'), - publishCommand: ({ isYarn, defaultCommand }) => defaultCommand, - getTagName: ({ currentVersion }) => `v${currentVersion}`, + publishCommand: ({ isYarn, tag, defaultCommand, dir }) => defaultCommand, + getTagName: ({ version }) => `v${version}`, testCommandBeforeRelease: ({ isYarn }) => isYarn ? 'yarn test' : 'npm run test', appName: undefined, diff --git a/packages/shipjs-lib/src/lib/util/__tests__/expandPackageList.spec.js b/packages/shipjs-lib/src/lib/util/__tests__/expandPackageList.spec.js new file mode 100644 index 00000000..156c6d4a --- /dev/null +++ b/packages/shipjs-lib/src/lib/util/__tests__/expandPackageList.spec.js @@ -0,0 +1,31 @@ +import silentExec from '../../shell/silentExec'; +import expandPackageList from '../expandPackageList'; + +describe('expandPackageList', () => { + it('expands package list', () => { + silentExec('./tests/bootstrap-examples/simple-monorepo.sh'); + expect(expandPackageList(['.'], 'sandbox/simple-monorepo')).toEqual([ + `${process.cwd()}/sandbox/simple-monorepo`, + ]); + + expect( + expandPackageList(['.', 'packages/*'], 'sandbox/simple-monorepo') + ).toEqual([ + `${process.cwd()}/sandbox/simple-monorepo`, + `${process.cwd()}/sandbox/simple-monorepo/packages/package_a`, + `${process.cwd()}/sandbox/simple-monorepo/packages/package_b`, + ]); + }); + + it('gets only directories with package.json', () => { + silentExec('./tests/bootstrap-examples/monorepo-with-nonpkg-directory.sh'); + const projectName = 'monorepo-with-nonpkg-directory'; + expect( + expandPackageList(['.', 'packages/*'], `sandbox/${projectName}`) + ).toEqual([ + `${process.cwd()}/sandbox/${projectName}`, + `${process.cwd()}/sandbox/${projectName}/packages/package_a`, + `${process.cwd()}/sandbox/${projectName}/packages/package_b`, + ]); + }); +}); diff --git a/packages/shipjs-lib/src/lib/util/__tests__/getCurrentVersion.spec.js b/packages/shipjs-lib/src/lib/util/__tests__/getCurrentVersion.spec.js deleted file mode 100644 index 8582bbf9..00000000 --- a/packages/shipjs-lib/src/lib/util/__tests__/getCurrentVersion.spec.js +++ /dev/null @@ -1,9 +0,0 @@ -import getCurrentVersion from '../getCurrentVersion'; -import silentExec from '../../shell/silentExec'; - -describe('getCurrentVersion', () => { - it('gets current version', () => { - silentExec('./tests/bootstrap-examples/empty.sh nothing'); - expect(getCurrentVersion('sandbox/nothing')).toBe('0.0.1'); - }); -}); diff --git a/packages/shipjs-lib/src/lib/util/__tests__/getNextVersion.spec.js b/packages/shipjs-lib/src/lib/util/__tests__/getNextVersion.spec.js index bcc8b8f1..39771ebd 100644 --- a/packages/shipjs-lib/src/lib/util/__tests__/getNextVersion.spec.js +++ b/packages/shipjs-lib/src/lib/util/__tests__/getNextVersion.spec.js @@ -148,31 +148,46 @@ describe('getNextVersionFromCommitMessages', () => { describe('getNextVersion', () => { it('gets next version with patch updated', () => { silentExec('./tests/bootstrap-examples/patch-version-up.sh'); - const { version: actual } = getNextVersion('sandbox/patch-version-up'); + const { version: actual } = getNextVersion( + '0.0.1', + 'sandbox/patch-version-up' + ); expect(actual).toBe('0.0.2'); }); it('gets next version with minor updated', () => { silentExec('./tests/bootstrap-examples/minor-version-up.sh'); - const { version: actual } = getNextVersion('sandbox/minor-version-up'); + const { version: actual } = getNextVersion( + '0.0.1', + 'sandbox/minor-version-up' + ); expect(actual).toBe('0.1.0'); }); it('gets next version with major updated', () => { silentExec('./tests/bootstrap-examples/major-version-up.sh'); - const { version: actual } = getNextVersion('sandbox/major-version-up'); + const { version: actual } = getNextVersion( + '0.0.1', + 'sandbox/major-version-up' + ); expect(actual).toBe('1.0.0'); }); it('gets a null with no commit messages', () => { silentExec('./tests/bootstrap-examples/empty.sh no-commit-log'); - const { version: actual } = getNextVersion('sandbox/no-commit-log'); + const { version: actual } = getNextVersion( + '0.0.1', + 'sandbox/no-commit-log' + ); expect(actual).toBe(null); }); it('throws when there is a commit message out of convention', () => { silentExec('./tests/bootstrap-examples/out-of-convention.sh'); - const { ignoredMessages } = getNextVersion('sandbox/out-of-convention'); + const { ignoredMessages } = getNextVersion( + '0.0.1', + 'sandbox/out-of-convention' + ); expect(ignoredMessages).toEqual(['hello: add a']); }); }); diff --git a/packages/shipjs-lib/src/lib/util/__tests__/updateVersion.spec.js b/packages/shipjs-lib/src/lib/util/__tests__/updateVersion.spec.js index 2e9d0dde..10ec2649 100644 --- a/packages/shipjs-lib/src/lib/util/__tests__/updateVersion.spec.js +++ b/packages/shipjs-lib/src/lib/util/__tests__/updateVersion.spec.js @@ -6,8 +6,8 @@ import { resolve } from 'path'; describe('updateVersion', () => { it('update version correctly', () => { silentExec('./tests/bootstrap-examples/empty.sh version-updating'); - const filePath = resolve('sandbox/version-updating', 'package.json'); - updateVersion([filePath], '0.9.9'); + const dir = resolve('sandbox/version-updating'); + updateVersion('0.9.9', dir); expect(getCurrentVersion('sandbox/version-updating')).toBe('0.9.9'); }); }); diff --git a/packages/shipjs-lib/src/lib/util/expandPackageList.js b/packages/shipjs-lib/src/lib/util/expandPackageList.js new file mode 100644 index 00000000..db75ff37 --- /dev/null +++ b/packages/shipjs-lib/src/lib/util/expandPackageList.js @@ -0,0 +1,23 @@ +import { resolve, join } from 'path'; +import { statSync, readdirSync, existsSync } from 'fs'; + +const isDirectory = dir => statSync(dir).isDirectory(); +const getDirectories = dir => + readdirSync(dir) + .map(name => join(dir, name)) + .filter(isDirectory); +const hasPackageJson = dir => existsSync(`${dir}/package.json`); +const flatten = arr => arr.reduce((acc, item) => acc.concat(item), []); + +export default function expandPackageList(list, dir = '.') { + return flatten( + list.map(item => { + if (item.endsWith('/*')) { + const basePath = resolve(dir, item.slice(0, item.length - 2)); + return getDirectories(basePath).filter(hasPackageJson); + } else { + return resolve(dir, item); + } + }) + ); +} diff --git a/packages/shipjs-lib/src/lib/util/getAppName.js b/packages/shipjs-lib/src/lib/util/getAppName.js index 8458cd5a..85abf94d 100644 --- a/packages/shipjs-lib/src/lib/util/getAppName.js +++ b/packages/shipjs-lib/src/lib/util/getAppName.js @@ -3,10 +3,10 @@ import { resolve } from 'path'; import loadConfig from '../config/loadConfig'; export default function getAppName(dir = '.') { - const { appName, filesToBump } = loadConfig(dir); + const { appName } = loadConfig(dir); if (appName) { return appName; } - const { name } = JSON.parse(readFileSync(resolve(dir, filesToBump[0]))); + const { name } = JSON.parse(readFileSync(resolve(dir, 'package.json'))); return name; } diff --git a/packages/shipjs-lib/src/lib/util/getCurrentVersion.js b/packages/shipjs-lib/src/lib/util/getCurrentVersion.js index 1f56a45f..463d9d58 100644 --- a/packages/shipjs-lib/src/lib/util/getCurrentVersion.js +++ b/packages/shipjs-lib/src/lib/util/getCurrentVersion.js @@ -1,9 +1,10 @@ import { readFileSync } from 'fs'; import { resolve } from 'path'; -import loadConfig from '../config/loadConfig'; -export default function getCurrentVersion(dir = '.') { - const { filesToBump } = loadConfig(dir); - const { version } = JSON.parse(readFileSync(resolve(dir, filesToBump[0]))); +export default function getCurrentVersion( + dir = '.', + filename = 'package.json' +) { + const { version } = JSON.parse(readFileSync(resolve(dir, filename))); return version; } diff --git a/packages/shipjs-lib/src/lib/util/getNextVersion.js b/packages/shipjs-lib/src/lib/util/getNextVersion.js index 6f2210a7..ea76fe2c 100644 --- a/packages/shipjs-lib/src/lib/util/getNextVersion.js +++ b/packages/shipjs-lib/src/lib/util/getNextVersion.js @@ -4,7 +4,6 @@ import { GIT_COMMIT_BREAKING_CHANGE, } from '../const'; import { inc, prerelease } from 'semver'; -import getCurrentVersion from './getCurrentVersion'; import silentExec from '../shell/silentExec'; export function getNextVersionFromCommitMessages(version, titles, bodies) { @@ -63,9 +62,8 @@ function getBodies(version, dir) { .trim(); } -export default function getNextVersion(dir = '.') { - const version = getCurrentVersion(dir); - const titles = getTitles(version, dir); - const bodies = getBodies(version, dir); - return getNextVersionFromCommitMessages(version, titles, bodies); +export default function getNextVersion(currentVersion, dir = '.') { + const titles = getTitles(currentVersion, dir); + const bodies = getBodies(currentVersion, dir); + return getNextVersionFromCommitMessages(currentVersion, titles, bodies); } diff --git a/packages/shipjs-lib/src/lib/util/hasTagForCurrentVersion.js b/packages/shipjs-lib/src/lib/util/hasTagForCurrentVersion.js deleted file mode 100644 index 776b409c..00000000 --- a/packages/shipjs-lib/src/lib/util/hasTagForCurrentVersion.js +++ /dev/null @@ -1,7 +0,0 @@ -import hasTag from '../git/hasTag'; -import getCurrentVersion from './getCurrentVersion'; - -export default function hasTagForCurrentVersion(dir = '.') { - const tag = `v${getCurrentVersion(dir)}`; - return hasTag(tag, dir); -} diff --git a/packages/shipjs-lib/src/lib/util/updateVersion.js b/packages/shipjs-lib/src/lib/util/updateVersion.js index 0a245baa..554d621c 100644 --- a/packages/shipjs-lib/src/lib/util/updateVersion.js +++ b/packages/shipjs-lib/src/lib/util/updateVersion.js @@ -1,11 +1,9 @@ import { readFileSync, writeFileSync } from 'fs'; import { resolve } from 'path'; -export default function updateVersion(filesToBump, nextVersion, dir = '.') { - filesToBump.forEach(file => { - const filePath = resolve(dir, file); - const json = JSON.parse(readFileSync(filePath).toString()); - json.version = nextVersion; - writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`); - }); +export default function updateVersion(nextVersion, dir = '.') { + const filePath = resolve(dir, 'package.json'); + const json = JSON.parse(readFileSync(filePath).toString()); + json.version = nextVersion; + writeFileSync(filePath, `${JSON.stringify(json, null, 2)}\n`); } diff --git a/packages/shipjs-lib/tests/bootstrap-examples/monorepo-with-nonpkg-directory.sh b/packages/shipjs-lib/tests/bootstrap-examples/monorepo-with-nonpkg-directory.sh new file mode 100755 index 00000000..7f4548dc --- /dev/null +++ b/packages/shipjs-lib/tests/bootstrap-examples/monorepo-with-nonpkg-directory.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +./tests/bootstrap-examples/empty.sh monorepo-with-nonpkg-directory/ && \ +./tests/bootstrap-examples/empty.sh monorepo-with-nonpkg-directory/packages/package_a && \ +./tests/bootstrap-examples/empty.sh monorepo-with-nonpkg-directory/packages/package_b && \ +mkdir sandbox/monorepo-with-nonpkg-directory/packages/not_a_package \ No newline at end of file diff --git a/packages/shipjs-lib/tests/bootstrap-examples/simple-monorepo.sh b/packages/shipjs-lib/tests/bootstrap-examples/simple-monorepo.sh new file mode 100755 index 00000000..348f5ec6 --- /dev/null +++ b/packages/shipjs-lib/tests/bootstrap-examples/simple-monorepo.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +./tests/bootstrap-examples/empty.sh simple-monorepo/ && \ +./tests/bootstrap-examples/empty.sh simple-monorepo/packages/package_a && \ +./tests/bootstrap-examples/empty.sh simple-monorepo/packages/package_b \ No newline at end of file diff --git a/packages/shipjs/src/flow/prepare.js b/packages/shipjs/src/flow/prepare.js index d3f871d8..57a46877 100644 --- a/packages/shipjs/src/flow/prepare.js +++ b/packages/shipjs/src/flow/prepare.js @@ -11,7 +11,8 @@ import getNextVersion from '../step/prepare/getNextVersion'; import confirmNextVersion from '../step/prepare/confirmNextVersion'; import prepareStagingBranch from '../step/prepare/prepareStagingBranch'; import checkoutToStagingBranch from '../step/prepare/checkoutToStagingBranch'; -import updateVersions from '../step/prepare/updateVersions'; +import updateVersion from '../step/prepare/updateVersion'; +import updateVersionMonorepo from '../step/prepare/updateVersionMonorepo'; import installDependencies from '../step/prepare/installDependencies'; import updateChangelog from '../step/prepare/updateChangelog'; import commitChanges from '../step/prepare/commitChanges'; @@ -41,7 +42,7 @@ async function prepare({ validateMergeStrategy({ config }); pull({ dir, dryRun }); push({ config, currentBranch: baseBranch, dir, dryRun }); - let { nextVersion } = getNextVersion({ dir }); + let { nextVersion } = getNextVersion({ currentVersion, dir }); nextVersion = await confirmNextVersion({ yes, currentVersion, @@ -54,7 +55,10 @@ async function prepare({ dir, }); checkoutToStagingBranch({ stagingBranch, dir, dryRun }); - await updateVersions({ config, nextVersion, dir, dryRun }); + const updateVersionFn = config.monorepo + ? updateVersionMonorepo + : updateVersion; + await updateVersionFn({ config, nextVersion, dir, dryRun }); installDependencies({ config, dir, dryRun }); updateChangelog({ config, firstRelease, releaseCount, dir, dryRun }); await commitChanges({ nextVersion, dir, config, dryRun }); diff --git a/packages/shipjs/src/flow/release.js b/packages/shipjs/src/flow/release.js index 6f5ce5f7..a1efc2ec 100644 --- a/packages/shipjs/src/flow/release.js +++ b/packages/shipjs/src/flow/release.js @@ -23,15 +23,14 @@ async function release({ help = false, dir = '.', dryRun = false }) { printDryRunBanner(); } const config = loadConfig(dir); - validate({ config, dir }); + const { currentVersion: version } = validate({ config, dir }); const { appName, - version, latestCommitHash, latestCommitUrl, repoURL, releaseTag, - } = gatherRepoInfo({ dir }); + } = gatherRepoInfo({ version, dir }); await notifyReleaseStart({ config, appName, @@ -43,7 +42,7 @@ async function release({ help = false, dir = '.', dryRun = false }) { runTest({ isYarn, config, dir, dryRun }); runBuild({ isYarn, config, dir, dryRun }); runPublish({ isYarn, config, releaseTag, dir, dryRun }); - const { tagName } = createGitTag({ config, dir, dryRun }); + const { tagName } = createGitTag({ version, config, dir, dryRun }); gitPush({ tagName, config, dir, dryRun }); await notifyReleaseSuccess({ config, diff --git a/packages/shipjs/src/helper/__tests__/validateBeforePrepare.spec.js b/packages/shipjs/src/helper/__tests__/validateBeforePrepare.spec.js index ef3abfd8..d7758cd9 100644 --- a/packages/shipjs/src/helper/__tests__/validateBeforePrepare.spec.js +++ b/packages/shipjs/src/helper/__tests__/validateBeforePrepare.spec.js @@ -1,9 +1,5 @@ import validate from '../validateBeforePrepare'; -import { - isWorkingTreeClean, - getCurrentBranch, - hasTagForCurrentVersion, -} from 'shipjs-lib'; // eslint-disable-line import/no-unresolved +import { isWorkingTreeClean, getCurrentBranch, hasTag } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved jest.mock('shipjs-lib'); const defaultOpts = { @@ -14,7 +10,7 @@ describe('Validate', () => { beforeEach(() => { isWorkingTreeClean.mockImplementation(() => true); getCurrentBranch.mockImplementation(() => 'master'); - hasTagForCurrentVersion.mockImplementation(() => true); + hasTag.mockImplementation(() => true); }); it('returns error if working tree is not clean', () => { @@ -46,7 +42,7 @@ describe('Validate', () => { }); it('returns error if there is no git tag for current version', () => { - hasTagForCurrentVersion.mockImplementation(() => false); + hasTag.mockImplementation(() => false); const result = validate(defaultOpts); expect(result).not.toBe(true); expect(result.length).toBe(1); @@ -54,7 +50,7 @@ describe('Validate', () => { }); it('does not return error if there is git tag for current version', () => { - hasTagForCurrentVersion.mockImplementation(() => true); + hasTag.mockImplementation(() => true); const result = validate(defaultOpts); expect(result).toBe(true); }); @@ -62,7 +58,7 @@ describe('Validate', () => { it('returns more than one error', () => { isWorkingTreeClean.mockImplementation(() => false); getCurrentBranch.mockImplementation(() => 'aaa'); - hasTagForCurrentVersion.mockImplementation(() => false); + hasTag.mockImplementation(() => false); const result = validate(defaultOpts); expect(result).not.toBe(true); expect(result.length).toBe(3); diff --git a/packages/shipjs/src/helper/validateBeforePrepare.js b/packages/shipjs/src/helper/validateBeforePrepare.js index 0a97d4ac..ebee5cf6 100644 --- a/packages/shipjs/src/helper/validateBeforePrepare.js +++ b/packages/shipjs/src/helper/validateBeforePrepare.js @@ -1,14 +1,14 @@ -import { - isWorkingTreeClean, - getCurrentBranch, - hasTagForCurrentVersion, -} from 'shipjs-lib'; // eslint-disable-line import/no-unresolved +import { isWorkingTreeClean, getCurrentBranch, hasTag } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved const WORKING_TREE_NOT_CLEAN = 'workingTreeNotClean'; const CURRENT_BRANCH_INCORRECT = 'currentBranchIncorrect'; const NO_TAG_FOR_CURRENT_VERSION = 'noTagForCurrentVersion'; -export default function validateBeforePrepare({ dir, baseBranches } = {}) { +export default function validateBeforePrepare({ + dir, + currentTagName, + baseBranches, +} = {}) { const result = []; if (!isWorkingTreeClean(dir)) { result.push(WORKING_TREE_NOT_CLEAN); @@ -16,7 +16,7 @@ export default function validateBeforePrepare({ dir, baseBranches } = {}) { if (baseBranches.indexOf(getCurrentBranch(dir)) === -1) { result.push(CURRENT_BRANCH_INCORRECT); } - if (!hasTagForCurrentVersion(dir)) { + if (!hasTag(currentTagName)) { result.push(NO_TAG_FOR_CURRENT_VERSION); } return result.length === 0 ? true : result; diff --git a/packages/shipjs/src/step/prepare/getNextVersion.js b/packages/shipjs/src/step/prepare/getNextVersion.js index 5e69b4b9..3604112e 100644 --- a/packages/shipjs/src/step/prepare/getNextVersion.js +++ b/packages/shipjs/src/step/prepare/getNextVersion.js @@ -1,11 +1,12 @@ import { getNextVersion } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved import runStep from '../runStep'; -export default ({ dir }) => +export default ({ currentVersion, dir }) => runStep( { title: 'Calculating the next version.' }, ({ print, warning, error, exitProcess }) => { const { version: nextVersion, ignoredMessages = [] } = getNextVersion( + currentVersion, dir ); if (ignoredMessages.length > 0) { diff --git a/packages/shipjs/src/step/prepare/updateVersions.js b/packages/shipjs/src/step/prepare/updateVersion.js similarity index 74% rename from packages/shipjs/src/step/prepare/updateVersions.js rename to packages/shipjs/src/step/prepare/updateVersion.js index 6c6617bb..86a40cce 100644 --- a/packages/shipjs/src/step/prepare/updateVersions.js +++ b/packages/shipjs/src/step/prepare/updateVersion.js @@ -4,15 +4,13 @@ import wrapExecWithDir from '../../util/wrapExecWithDir'; export default async ({ config, nextVersion, dir, dryRun }) => await runStep({ title: 'Updating the version.' }, async ({ print, info }) => { - const { filesToBump, versionUpdated } = config; + const { versionUpdated } = config; if (dryRun) { - filesToBump.forEach(file => { - print(`-> ${info(file)}`); - }); + print(`-> ${info('package.json')}`); print(`-> execute ${info('versionUpdated()')} callback.`); return; } - updateVersion(filesToBump, nextVersion, dir); + updateVersion(nextVersion, dir); await versionUpdated({ version: nextVersion, dir, diff --git a/packages/shipjs/src/step/prepare/updateVersionMonorepo.js b/packages/shipjs/src/step/prepare/updateVersionMonorepo.js new file mode 100644 index 00000000..63b09a22 --- /dev/null +++ b/packages/shipjs/src/step/prepare/updateVersionMonorepo.js @@ -0,0 +1,33 @@ +import { expandPackageList, updateVersion } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved +import runStep from '../runStep'; +import wrapExecWithDir from '../../util/wrapExecWithDir'; + +export default async ({ config, nextVersion, dir, dryRun }) => + await runStep( + { title: 'Updating the versions on the monorepo.' }, + async ({ print, info }) => { + const { + versionUpdated, + monorepo: { packagesToBump }, + } = config; + const packageList = expandPackageList(packagesToBump, dir); + if (dryRun) { + print(`Your configuration: ${JSON.stringify(packagesToBump)}`); + print(`Actual packages to bump:`); + packageList.forEach(packageDir => + print(`-> ${info(`${packageDir}/package.json`)}`) + ); + print(`-> execute ${info('versionUpdated()')} callback.`); + return; + } + packageList.forEach(packageDir => { + print(`-> ${info(`${packageDir}/package.json`)}`); + updateVersion(nextVersion, packageDir); + }); + await versionUpdated({ + version: nextVersion, + dir, + exec: wrapExecWithDir(dir), + }); + } + ); diff --git a/packages/shipjs/src/step/prepare/validate.js b/packages/shipjs/src/step/prepare/validate.js index c75a6107..ab1e2957 100644 --- a/packages/shipjs/src/step/prepare/validate.js +++ b/packages/shipjs/src/step/prepare/validate.js @@ -35,13 +35,18 @@ export default ({ config, dir }) => title: 'Checking the current status.', }, ({ print, info, error, exitProcess }) => { - const { mergeStrategy } = config; + const { mergeStrategy, monorepo, getTagName } = config; const baseBranches = getBaseBranches({ mergeStrategy }); + const currentVersion = + monorepo && monorepo.readVersionFrom + ? getCurrentVersion(dir, monorepo.readVersionFrom) + : getCurrentVersion(dir); + const currentTagName = getTagName({ version: currentVersion }); const result = validateBeforePrepare({ dir, + currentTagName, baseBranches, }); - const currentVersion = getCurrentVersion(dir); const baseBranch = getCurrentBranch(dir); if (result !== true) { printValidationError({ diff --git a/packages/shipjs/src/step/release/createGitTag.js b/packages/shipjs/src/step/release/createGitTag.js index 4eec88c2..3525cc1c 100644 --- a/packages/shipjs/src/step/release/createGitTag.js +++ b/packages/shipjs/src/step/release/createGitTag.js @@ -1,11 +1,9 @@ -import { getCurrentVersion } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved import runStep from '../runStep'; -export default ({ config, dir, dryRun }) => +export default ({ version, config, dir, dryRun }) => runStep({ title: 'Creating a git tag.' }, ({ run }) => { const { getTagName } = config; - const currentVersion = getCurrentVersion(dir); - const tagName = getTagName({ currentVersion }); + const tagName = getTagName({ version }); const command = `git tag ${tagName}`; run(command, dir, dryRun); return { tagName }; diff --git a/packages/shipjs/src/step/release/gatherRepoInfo.js b/packages/shipjs/src/step/release/gatherRepoInfo.js index d1bf2cde..79d6f161 100644 --- a/packages/shipjs/src/step/release/gatherRepoInfo.js +++ b/packages/shipjs/src/step/release/gatherRepoInfo.js @@ -1,5 +1,4 @@ import { - getCurrentVersion, getLatestCommitHash, getCommitUrl, getAppName, @@ -8,10 +7,9 @@ import { } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved import runStep from '../runStep'; -export default ({ dir }) => +export default ({ version, dir }) => runStep({ title: 'Gathering repository information.' }, () => { const appName = getAppName(dir); - const version = getCurrentVersion(dir); const latestCommitHash = getLatestCommitHash(dir); const latestCommitUrl = getCommitUrl(latestCommitHash, dir); const repoURL = getRepoURL(dir); diff --git a/packages/shipjs/src/step/release/runPublish.js b/packages/shipjs/src/step/release/runPublish.js index debcf5bb..a3d0fd3f 100644 --- a/packages/shipjs/src/step/release/runPublish.js +++ b/packages/shipjs/src/step/release/runPublish.js @@ -1,10 +1,27 @@ +import { expandPackageList } from 'shipjs-lib'; // eslint-disable-line import/no-unresolved import runStep from '../runStep'; export default ({ isYarn, config, releaseTag: tag, dir, dryRun }) => - runStep({ title: 'Publishing.' }, ({ run }) => { - const { publishCommand } = config; + runStep({ title: 'Publishing.' }, ({ run, print, info }) => { + const { publishCommand, monorepo } = config; const defaultCommand = isYarn ? `yarn publish --no-git-tag-version --non-interactive --tag ${tag}` : `npm publish --tag ${tag}`; - run(publishCommand({ isYarn, tag, defaultCommand }), dir, dryRun); + if (monorepo) { + const { packagesToPublish } = monorepo; + const packageList = expandPackageList(packagesToPublish, dir); + packageList.forEach(packageDir => { + const command = publishCommand({ + isYarn, + tag, + defaultCommand, + dir: packageDir, + }); + print(`Running the following at ${info(packageDir)}`); + run(command, packageDir, dryRun); + }); + } else { + const command = publishCommand({ isYarn, tag, defaultCommand, dir }); + run(command, dir, dryRun); + } }); diff --git a/packages/shipjs/src/step/release/validate.js b/packages/shipjs/src/step/release/validate.js index 621a10db..21e4f13f 100644 --- a/packages/shipjs/src/step/release/validate.js +++ b/packages/shipjs/src/step/release/validate.js @@ -9,9 +9,12 @@ export default ({ config, dir }) => runStep( { title: 'Checking the current status.' }, ({ print, info, warning, exitProcess }) => { - const { mergeStrategy, shouldRelease } = config; + const { mergeStrategy, shouldRelease, monorepo } = config; const commitMessage = getLatestCommitMessage(dir); - const currentVersion = getCurrentVersion(dir); + const currentVersion = + monorepo && monorepo.readVersionFrom + ? getCurrentVersion(dir, monorepo.readVersionFrom) + : getCurrentVersion(dir); const currentBranch = getCurrentBranch(dir); const validationResult = shouldRelease({ commitMessage, @@ -24,5 +27,8 @@ export default ({ config, dir }) => print(info(` > ${validationResult}`)); exitProcess(0); } + return { + currentVersion, + }; } ); diff --git a/packages/shipjs/src/step/runStep.js b/packages/shipjs/src/step/runStep.js index 34a224ff..3e3c6f26 100644 --- a/packages/shipjs/src/step/runStep.js +++ b/packages/shipjs/src/step/runStep.js @@ -12,7 +12,7 @@ export default function runStep({ title }, stepFn) { print(bold(slateblue(`› ${title}`))); } return stepFn({ - run: wrapRun({ exec, print, info, error }), + run: wrapRun({ exec, print, error }), print: indentPrint(2), info, warning, diff --git a/ship.config.js b/ship.config.js index 2bb0abc2..e3aa94ff 100644 --- a/ship.config.js +++ b/ship.config.js @@ -1,9 +1,4 @@ module.exports = { - filesToBump: [ - "package.json", - "packages/shipjs-lib/package.json", - "packages/shipjs/package.json" - ], versionUpdated: ({ version, dir, exec }) => { exec(`npx json -I -f lerna.json -e 'this.version = "${version}"'`); exec( @@ -14,7 +9,7 @@ module.exports = { ); }, beforeCommitChanges: ({ exec }) => { - exec(`npx markdown-toc -i --bullets="-" GUIDE.md`); + exec("yarn toc"); }, publishCommand: () => `lerna exec -- yarn publish --no-git-tag-version --non-interactive`