diff options
author | Fabio Berger <me@fabioberger.com> | 2018-06-02 08:13:02 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-06-02 08:13:02 +0800 |
commit | d3c64bd5b493dc1779a24c7c051c255106a4292a (patch) | |
tree | d1c818e64b75c1f4fed1c7d797892fb0d35dd779 | |
parent | 7024a7468a549a96cf120e6b7e287e79d7ad2d61 (diff) | |
parent | 62e60e2ba6d07b9b892b4f2e92a5421c54f5fa20 (diff) | |
download | dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.tar dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.tar.gz dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.tar.bz2 dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.tar.lz dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.tar.xz dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.tar.zst dexon-sol-tools-d3c64bd5b493dc1779a24c7c051c255106a4292a.zip |
Merge branch 'v2-prototype' into refactor/order-utils/for-v2
* v2-prototype:
Set contract expiration time to a constant 10 minutes
Remove unused promises array
Make erc20_wrapper and erc721_wrapper serial
Rename changelogs to changelog
Add CHANGELOG entry
Check that git branch is up to date before publishing
Move prepublish checks before building packages for publishing
Refactor changelog utils to a separate module
-rw-r--r-- | package.json | 6 | ||||
-rw-r--r-- | packages/contracts/src/utils/erc20_wrapper.ts | 48 | ||||
-rw-r--r-- | packages/contracts/src/utils/erc721_wrapper.ts | 56 | ||||
-rw-r--r-- | packages/contracts/src/utils/order_factory.ts | 3 | ||||
-rw-r--r-- | packages/monorepo-scripts/CHANGELOG.json | 9 | ||||
-rw-r--r-- | packages/monorepo-scripts/package.json | 1 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/deps_versions.ts | 2 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/find_unused_dependencies.ts | 2 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/postpublish_utils.ts | 2 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/prepublish_checks.ts | 71 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/publish.ts | 123 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/remove_tags.ts | 4 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/test_installation.ts | 2 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/types.ts | 8 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/utils/changelog_utils.ts | 55 | ||||
-rw-r--r-- | packages/monorepo-scripts/src/utils/utils.ts (renamed from packages/monorepo-scripts/src/utils.ts) | 4 |
16 files changed, 219 insertions, 177 deletions
diff --git a/package.json b/package.json index 177087f88..2ddde3484 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,9 @@ "prettier:ci": "prettier --list-different '**/*.{ts,tsx,json,md}' --config .prettierrc", "report_coverage": "lcov-result-merger 'packages/*/coverage/lcov.info' | coveralls", "test:installation": "node ./packages/monorepo-scripts/lib/test_installation.js", - "run:publish": "run-s install:all rebuild script:publish", - "run:publish:dry": "run-s install:all rebuild script:publish:dry", + "run:publish": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish", + "run:publish:dry": "run-s install:all build:monorepo_scripts script:prepublish_checks rebuild script:publish:dry", + "script:prepublish_checks": "node ./packages/monorepo-scripts/lib/prepublish_checks.js", "script:publish": "node ./packages/monorepo-scripts/lib/publish.js", "script:publish:dry": "IS_DRY_RUN=true yarn script:publish", "install:all": "yarn install", @@ -22,6 +23,7 @@ "lerna:run": "lerna run", "watch": "wsrun watch $PKG --fast-exit -r --stages --done-criteria='complete|successfully'", "build": "wsrun build $PKG --fast-exit -r --stages", + "build:monorepo_scripts": "PKG=@0xproject/monorepo-scripts yarn build", "clean": "wsrun clean $PKG --fast-exit -r --parallel", "rebuild": "run-s clean build", "test": "wsrun test $PKG --fast-exit --serial --exclude-missing", diff --git a/packages/contracts/src/utils/erc20_wrapper.ts b/packages/contracts/src/utils/erc20_wrapper.ts index 0f45fb1e6..dceeceeea 100644 --- a/packages/contracts/src/utils/erc20_wrapper.ts +++ b/packages/contracts/src/utils/erc20_wrapper.ts @@ -16,18 +16,19 @@ export class ERC20Wrapper { private _contractOwnerAddress: string; private _web3Wrapper: Web3Wrapper; private _provider: Provider; - private _dummyTokenContracts?: DummyERC20TokenContract[]; + private _dummyTokenContracts: DummyERC20TokenContract[]; private _proxyContract?: ERC20ProxyContract; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { + this._dummyTokenContracts = []; this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; this._tokenOwnerAddresses = tokenOwnerAddresses; this._contractOwnerAddress = contractOwnerAddress; } public async deployDummyTokensAsync(): Promise<DummyERC20TokenContract[]> { - this._dummyTokenContracts = await Promise.all( - _.times(constants.NUM_DUMMY_ERC20_TO_DEPLOY, async () => - DummyERC20TokenContract.deployFrom0xArtifactAsync( + for (let i = 0; i < constants.NUM_DUMMY_ERC20_TO_DEPLOY; i++) { + this._dummyTokenContracts.push( + await DummyERC20TokenContract.deployFrom0xArtifactAsync( artifacts.DummyERC20Token, this._provider, txDefaults, @@ -36,8 +37,8 @@ export class ERC20Wrapper { constants.DUMMY_TOKEN_DECIMALS, constants.DUMMY_TOKEN_TOTAL_SUPPLY, ), - ), - ); + ); + } return this._dummyTokenContracts; } public async deployProxyAsync(): Promise<ERC20ProxyContract> { @@ -51,44 +52,41 @@ export class ERC20Wrapper { public async setBalancesAndAllowancesAsync(): Promise<void> { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); - const setBalancePromises: Array<Promise<string>> = []; - const setAllowancePromises: Array<Promise<string>> = []; - _.forEach(this._dummyTokenContracts, dummyTokenContract => { - _.forEach(this._tokenOwnerAddresses, tokenOwnerAddress => { - setBalancePromises.push( - dummyTokenContract.setBalance.sendTransactionAsync( + for (const dummyTokenContract of this._dummyTokenContracts) { + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + await this._web3Wrapper.awaitTransactionSuccessAsync( + await dummyTokenContract.setBalance.sendTransactionAsync( tokenOwnerAddress, constants.INITIAL_ERC20_BALANCE, { from: this._contractOwnerAddress }, ), + constants.AWAIT_TRANSACTION_MINED_MS, ); - setAllowancePromises.push( - dummyTokenContract.approve.sendTransactionAsync( + await this._web3Wrapper.awaitTransactionSuccessAsync( + await dummyTokenContract.approve.sendTransactionAsync( (this._proxyContract as ERC20ProxyContract).address, constants.INITIAL_ERC20_ALLOWANCE, { from: tokenOwnerAddress }, ), + constants.AWAIT_TRANSACTION_MINED_MS, ); - }); - }); - const txHashes = await Promise.all([...setBalancePromises, ...setAllowancePromises]); - await Promise.all(_.map(txHashes, async txHash => this._web3Wrapper.awaitTransactionSuccessAsync(txHash))); + } + } } public async getBalancesAsync(): Promise<ERC20BalancesByOwner> { this._validateDummyTokenContractsExistOrThrow(); const balancesByOwner: ERC20BalancesByOwner = {}; - const balancePromises: Array<Promise<BigNumber>> = []; + const balances: BigNumber[] = []; const balanceInfo: Array<{ tokenOwnerAddress: string; tokenAddress: string }> = []; - _.forEach(this._dummyTokenContracts, dummyTokenContract => { - _.forEach(this._tokenOwnerAddresses, tokenOwnerAddress => { - balancePromises.push(dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress)); + for (const dummyTokenContract of this._dummyTokenContracts) { + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + balances.push(await dummyTokenContract.balanceOf.callAsync(tokenOwnerAddress)); balanceInfo.push({ tokenOwnerAddress, tokenAddress: dummyTokenContract.address, }); - }); - }); - const balances = await Promise.all(balancePromises); + } + } _.forEach(balances, (balance, balanceIndex) => { const tokenAddress = balanceInfo[balanceIndex].tokenAddress; const tokenOwnerAddress = balanceInfo[balanceIndex].tokenOwnerAddress; diff --git a/packages/contracts/src/utils/erc721_wrapper.ts b/packages/contracts/src/utils/erc721_wrapper.ts index 11a012602..13fdf630e 100644 --- a/packages/contracts/src/utils/erc721_wrapper.ts +++ b/packages/contracts/src/utils/erc721_wrapper.ts @@ -17,27 +17,28 @@ export class ERC721Wrapper { private _contractOwnerAddress: string; private _web3Wrapper: Web3Wrapper; private _provider: Provider; - private _dummyTokenContracts?: DummyERC721TokenContract[]; + private _dummyTokenContracts: DummyERC721TokenContract[]; private _proxyContract?: ERC721ProxyContract; private _initialTokenIdsByOwner: ERC721TokenIdsByOwner = {}; constructor(provider: Provider, tokenOwnerAddresses: string[], contractOwnerAddress: string) { this._web3Wrapper = new Web3Wrapper(provider); this._provider = provider; + this._dummyTokenContracts = []; this._tokenOwnerAddresses = tokenOwnerAddresses; this._contractOwnerAddress = contractOwnerAddress; } public async deployDummyTokensAsync(): Promise<DummyERC721TokenContract[]> { - this._dummyTokenContracts = await Promise.all( - _.times(constants.NUM_DUMMY_ERC721_TO_DEPLOY, async () => - DummyERC721TokenContract.deployFrom0xArtifactAsync( + for (let i = 0; i < constants.NUM_DUMMY_ERC721_TO_DEPLOY; i++) { + this._dummyTokenContracts.push( + await DummyERC721TokenContract.deployFrom0xArtifactAsync( artifacts.DummyERC721Token, this._provider, txDefaults, constants.DUMMY_TOKEN_NAME, constants.DUMMY_TOKEN_SYMBOL, ), - ), - ); + ); + } return this._dummyTokenContracts; } public async deployProxyAsync(): Promise<ERC721ProxyContract> { @@ -51,17 +52,16 @@ export class ERC721Wrapper { public async setBalancesAndAllowancesAsync(): Promise<void> { this._validateDummyTokenContractsExistOrThrow(); this._validateProxyContractExistsOrThrow(); - const setBalancePromises: Array<Promise<string>> = []; - const setAllowancePromises: Array<Promise<string>> = []; this._initialTokenIdsByOwner = {}; - _.forEach(this._dummyTokenContracts, dummyTokenContract => { - _.forEach(this._tokenOwnerAddresses, tokenOwnerAddress => { - _.forEach(_.range(constants.NUM_ERC721_TOKENS_TO_MINT), () => { + for (const dummyTokenContract of this._dummyTokenContracts) { + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { + for (let i = 0; i < constants.NUM_ERC721_TOKENS_TO_MINT; i++) { const tokenId = generatePseudoRandomSalt(); - setBalancePromises.push( - dummyTokenContract.mint.sendTransactionAsync(tokenOwnerAddress, tokenId, { + await this._web3Wrapper.awaitTransactionSuccessAsync( + await dummyTokenContract.mint.sendTransactionAsync(tokenOwnerAddress, tokenId, { from: this._contractOwnerAddress, }), + constants.AWAIT_TRANSACTION_MINED_MS, ); if (_.isUndefined(this._initialTokenIdsByOwner[tokenOwnerAddress])) { this._initialTokenIdsByOwner[tokenOwnerAddress] = { @@ -72,41 +72,39 @@ export class ERC721Wrapper { this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address] = []; } this._initialTokenIdsByOwner[tokenOwnerAddress][dummyTokenContract.address].push(tokenId); - }); + } const shouldApprove = true; - setAllowancePromises.push( - dummyTokenContract.setApprovalForAll.sendTransactionAsync( + await this._web3Wrapper.awaitTransactionSuccessAsync( + await dummyTokenContract.setApprovalForAll.sendTransactionAsync( (this._proxyContract as ERC721ProxyContract).address, shouldApprove, { from: tokenOwnerAddress }, ), + constants.AWAIT_TRANSACTION_MINED_MS, ); - }); - }); - const txHashes = await Promise.all([...setBalancePromises, ...setAllowancePromises]); - await Promise.all(_.map(txHashes, async txHash => this._web3Wrapper.awaitTransactionSuccessAsync(txHash))); + } + } } public async getBalancesAsync(): Promise<ERC721TokenIdsByOwner> { this._validateDummyTokenContractsExistOrThrow(); this._validateBalancesAndAllowancesSetOrThrow(); const tokenIdsByOwner: ERC721TokenIdsByOwner = {}; - const tokenOwnerPromises: Array<Promise<string>> = []; + const tokenOwnerAddresses: string[] = []; const tokenInfo: Array<{ tokenId: BigNumber; tokenAddress: string }> = []; - _.forEach(this._dummyTokenContracts, dummyTokenContract => { - _.forEach(this._tokenOwnerAddresses, tokenOwnerAddress => { + for (const dummyTokenContract of this._dummyTokenContracts) { + for (const tokenOwnerAddress of this._tokenOwnerAddresses) { const initialTokenOwnerIds = this._initialTokenIdsByOwner[tokenOwnerAddress][ dummyTokenContract.address ]; - _.forEach(initialTokenOwnerIds, tokenId => { - tokenOwnerPromises.push(dummyTokenContract.ownerOf.callAsync(tokenId)); + for (const tokenId of initialTokenOwnerIds) { + tokenOwnerAddresses.push(await dummyTokenContract.ownerOf.callAsync(tokenId)); tokenInfo.push({ tokenId, tokenAddress: dummyTokenContract.address, }); - }); - }); - }); - const tokenOwnerAddresses = await Promise.all(tokenOwnerPromises); + } + } + } _.forEach(tokenOwnerAddresses, (tokenOwnerAddress, ownerIndex) => { const tokenAddress = tokenInfo[ownerIndex].tokenAddress; const tokenId = tokenInfo[ownerIndex].tokenId; diff --git a/packages/contracts/src/utils/order_factory.ts b/packages/contracts/src/utils/order_factory.ts index ef11e4341..af411c01f 100644 --- a/packages/contracts/src/utils/order_factory.ts +++ b/packages/contracts/src/utils/order_factory.ts @@ -17,7 +17,8 @@ export class OrderFactory { customOrderParams: Partial<Order> = {}, signatureType: SignatureType = SignatureType.EthSign, ): SignedOrder { - const randomExpiration = new BigNumber(Math.floor((Date.now() + Math.random() * 100000000000) / 1000)); + const tenMinutes = 10 * 60 * 1000; + const randomExpiration = new BigNumber(Date.now() + tenMinutes); const order = ({ senderAddress: constants.NULL_ADDRESS, expirationTimeSeconds: randomExpiration, diff --git a/packages/monorepo-scripts/CHANGELOG.json b/packages/monorepo-scripts/CHANGELOG.json index 58d946cd6..a41262ed2 100644 --- a/packages/monorepo-scripts/CHANGELOG.json +++ b/packages/monorepo-scripts/CHANGELOG.json @@ -1,5 +1,14 @@ [ { + "version": "0.2.0", + "changes": [ + { + "note": "Add `prepublish_checks` script", + "pr": 650 + } + ] + }, + { "timestamp": 1527008794, "version": "0.1.20", "changes": [ diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index 02a8e4a42..2bbf4df11 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -16,6 +16,7 @@ "find_unused_deps": "run-s build script:find_unused_deps", "remove_tags": "run-s build script:remove_tags", "script:deps_versions": "node ./lib/deps_versions.js", + "script:prepublish_checks": "node ./lib/prepublish_checks.js", "script:publish": "IS_DRY_RUN=true node ./lib/publish.js", "script:find_unused_deps": "node ./lib/find_unused_dependencies.js", "script:remove_tags": "node ./lib/remove_tags.js" diff --git a/packages/monorepo-scripts/src/deps_versions.ts b/packages/monorepo-scripts/src/deps_versions.ts index 07292a160..f090d12e9 100644 --- a/packages/monorepo-scripts/src/deps_versions.ts +++ b/packages/monorepo-scripts/src/deps_versions.ts @@ -5,7 +5,7 @@ import * as fs from 'fs'; import { sync as globSync } from 'glob'; import * as _ from 'lodash'; -import { utils } from './utils'; +import { utils } from './utils/utils'; interface Dependencies { [depName: string]: string; diff --git a/packages/monorepo-scripts/src/find_unused_dependencies.ts b/packages/monorepo-scripts/src/find_unused_dependencies.ts index df303f6ce..71e707224 100644 --- a/packages/monorepo-scripts/src/find_unused_dependencies.ts +++ b/packages/monorepo-scripts/src/find_unused_dependencies.ts @@ -7,7 +7,7 @@ import * as _ from 'lodash'; import { exec as execAsync } from 'promisify-child-process'; import { constants } from './constants'; -import { utils } from './utils'; +import { utils } from './utils/utils'; // For some reason, `depcheck` hangs on some packages. Add them here. const IGNORE_PACKAGES = ['@0xproject/sol-compiler']; diff --git a/packages/monorepo-scripts/src/postpublish_utils.ts b/packages/monorepo-scripts/src/postpublish_utils.ts index f5785343d..dbbde894d 100644 --- a/packages/monorepo-scripts/src/postpublish_utils.ts +++ b/packages/monorepo-scripts/src/postpublish_utils.ts @@ -7,7 +7,7 @@ import * as publishRelease from 'publish-release'; import semverSort = require('semver-sort'); import { constants } from './constants'; -import { utils } from './utils'; +import { utils } from './utils/utils'; const publishReleaseAsync = promisify(publishRelease); const generatedDocsDirectoryName = 'generated_docs'; diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts new file mode 100644 index 000000000..2c096d8f6 --- /dev/null +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -0,0 +1,71 @@ +import * as _ from 'lodash'; +import { exec as execAsync } from 'promisify-child-process'; + +import { constants } from './constants'; +import { utils } from './utils/utils'; + +async function checkPublishRequiredSetupAsync(): Promise<void> { + // check to see if logged into npm before publishing + try { + // HACK: for some reason on some setups, the `npm whoami` will not recognize a logged-in user + // unless run with `sudo` (i.e Fabio's NVM setup) but is fine for others (Jacob's NVM setup). + utils.log('Checking that the user is logged in on npm...'); + await execAsync(`sudo npm whoami`); + } catch (err) { + throw new Error('You must be logged into npm in the commandline to publish. Run `npm login` and try again.'); + } + + // Check to see if Git personal token setup + if (_.isUndefined(constants.githubPersonalAccessToken)) { + throw new Error( + 'You must have a Github personal access token set to an envVar named `GITHUB_PERSONAL_ACCESS_TOKEN_0X_JS`. Add it then try again.', + ); + } + + // Check Yarn version is 1.X + utils.log('Checking the yarn version...'); + const result = await execAsync(`yarn --version`); + const version = result.stdout; + const versionSegments = version.split('.'); + const majorVersion = _.parseInt(versionSegments[0]); + if (majorVersion < 1) { + throw new Error('Your yarn version must be v1.x or higher. Upgrade yarn and try again.'); + } + + // Check that `aws` commandline tool is installed + try { + utils.log('Checking that aws CLI tool is installed...'); + await execAsync(`aws help`); + } catch (err) { + throw new Error('You must have `awscli` commandline tool installed. Install it and try again.'); + } + + // Check that `aws` credentials are setup + try { + utils.log('Checking that aws credentials are configured...'); + await execAsync(`aws sts get-caller-identity`); + } catch (err) { + throw new Error('You must setup your AWS credentials by running `aws configure`. Do this and try again.'); + } + + utils.log('Checking that git branch is up to date with upstream...'); + await execAsync('git fetch'); + const res = await execAsync('git status -bs'); // s - short format, b - branch info + /** + * Possible outcomes + * ## branch_name...origin/branch_name [behind n] + * ## branch_name...origin/branch_name [ahead n] + * ## branch_name...origin/branch_name + */ + const gitShortStatusHeader = res.stdout.split('\n')[0]; + if (gitShortStatusHeader.includes('behind')) { + throw new Error('Your branch is behind upstream. Please pull before publishing.'); + } else if (gitShortStatusHeader.includes('ahead')) { + throw new Error('Your branch is ahead of upstream. Please push before publishing.'); + } +} + +checkPublishRequiredSetupAsync().catch(err => { + utils.log(err.message); + process.exit(1); +}); diff --git a/packages/monorepo-scripts/src/publish.ts b/packages/monorepo-scripts/src/publish.ts index 73106821a..36970f85b 100644 --- a/packages/monorepo-scripts/src/publish.ts +++ b/packages/monorepo-scripts/src/publish.ts @@ -13,14 +13,14 @@ import semverDiff = require('semver-diff'); import semverSort = require('semver-sort'); import { constants } from './constants'; -import { Changelog, Changes, PackageToVersionChange, SemVerIndex, UpdatedPackage } from './types'; -import { utils } from './utils'; +import { Changelog, PackageToVersionChange, SemVerIndex, VersionChangelog } from './types'; +import { changelogUtils } from './utils/changelog_utils'; +import { utils } from './utils/utils'; const DOC_GEN_COMMAND = 'docs:json'; const NPM_NAMESPACE = '@0xproject/'; const IS_DRY_RUN = process.env.IS_DRY_RUN === 'true'; const TODAYS_TIMESTAMP = moment().unix(); -const LERNA_EXECUTABLE = './node_modules/lerna/bin/lerna.js'; const semverNameToIndex: { [semver: string]: number } = { patch: SemVerIndex.Patch, minor: SemVerIndex.Minor, @@ -39,11 +39,6 @@ const packageNameToWebsitePath: { [name: string]: string } = { }; (async () => { - const hasRequiredSetup = await checkPublishRequiredSetupAsync(); - if (!hasRequiredSetup) { - return; // abort - } - // Fetch public, updated Lerna packages const shouldIncludePrivate = false; const updatedPublicLernaPackages = await utils.getUpdatedLernaPackagesAsync(shouldIncludePrivate); @@ -114,54 +109,6 @@ package.ts. Please add an entry for it and try again.`, } } -async function checkPublishRequiredSetupAsync(): Promise<boolean> { - // check to see if logged into npm before publishing - try { - // HACK: for some reason on some setups, the `npm whoami` will not recognize a logged-in user - // unless run with `sudo` (i.e Fabio's NVM setup) but is fine for others (Jacob's N setup). - await execAsync(`sudo npm whoami`); - } catch (err) { - utils.log('You must be logged into npm in the commandline to publish. Run `npm login` and try again.'); - return false; - } - - // Check to see if Git personal token setup - if (_.isUndefined(constants.githubPersonalAccessToken)) { - utils.log( - 'You must have a Github personal access token set to an envVar named `GITHUB_PERSONAL_ACCESS_TOKEN_0X_JS`. Add it then try again.', - ); - return false; - } - - // Check Yarn version is 1.X - const result = await execAsync(`yarn --version`); - const version = result.stdout; - const versionSegments = version.split('.'); - const majorVersion = _.parseInt(versionSegments[0]); - if (majorVersion < 1) { - utils.log('Your yarn version must be v1.x or higher. Upgrade yarn and try again.'); - return false; - } - - // Check that `aws` commandline tool is installed - try { - await execAsync(`aws help`); - } catch (err) { - utils.log('You must have `awscli` commandline tool installed. Install it and try again.'); - return false; - } - - // Check that `aws` credentials are setup - try { - await execAsync(`aws sts get-caller-identity`); - } catch (err) { - utils.log('You must setup your AWS credentials by running `aws configure`. Do this and try again.'); - return false; - } - - return true; -} - async function pushChangelogsToGithubAsync(): Promise<void> { await execAsync(`git add . --all`, { cwd: constants.monorepoRootPath }); await execAsync(`git commit -m "Updated CHANGELOGS"`, { cwd: constants.monorepoRootPath }); @@ -175,9 +122,9 @@ async function updateChangeLogsAsync(updatedPublicLernaPackages: LernaPackage[]) const packageName = lernaPackage.package.name; const changelogJSONPath = path.join(lernaPackage.location, 'CHANGELOG.json'); const changelogJSON = utils.getChangelogJSONOrCreateIfMissing(changelogJSONPath); - let changelogs: Changelog[]; + let changelog: Changelog; try { - changelogs = JSON.parse(changelogJSON); + changelog = JSON.parse(changelogJSON); } catch (err) { throw new Error( `${lernaPackage.package.name}'s CHANGELOG.json contains invalid JSON. Please fix and try again.`, @@ -185,11 +132,11 @@ async function updateChangeLogsAsync(updatedPublicLernaPackages: LernaPackage[]) } const currentVersion = lernaPackage.package.version; - const shouldAddNewEntry = shouldAddNewChangelogEntry(currentVersion, changelogs); + const shouldAddNewEntry = changelogUtils.shouldAddNewChangelogEntry(currentVersion, changelog); if (shouldAddNewEntry) { // Create a new entry for a patch version with generic changelog entry. const nextPatchVersion = utils.getNextPatchVersion(currentVersion); - const newChangelogEntry: Changelog = { + const newChangelogEntry: VersionChangelog = { timestamp: TODAYS_TIMESTAMP, version: nextPatchVersion, changes: [ @@ -198,27 +145,27 @@ async function updateChangeLogsAsync(updatedPublicLernaPackages: LernaPackage[]) }, ], }; - changelogs = [newChangelogEntry, ...changelogs]; + changelog = [newChangelogEntry, ...changelog]; packageToVersionChange[packageName] = semverDiff(currentVersion, nextPatchVersion); } else { // Update existing entry with timestamp - const lastEntry = changelogs[0]; + const lastEntry = changelog[0]; if (_.isUndefined(lastEntry.timestamp)) { lastEntry.timestamp = TODAYS_TIMESTAMP; } // Check version number is correct. const proposedNextVersion = lastEntry.version; lastEntry.version = updateVersionNumberIfNeeded(currentVersion, proposedNextVersion); - changelogs[0] = lastEntry; + changelog[0] = lastEntry; packageToVersionChange[packageName] = semverDiff(currentVersion, lastEntry.version); } // Save updated CHANGELOG.json - fs.writeFileSync(changelogJSONPath, JSON.stringify(changelogs, null, '\t')); + fs.writeFileSync(changelogJSONPath, JSON.stringify(changelog, null, '\t')); await utils.prettifyAsync(changelogJSONPath, constants.monorepoRootPath); utils.log(`${packageName}: Updated CHANGELOG.json`); // Generate updated CHANGELOG.md - const changelogMd = generateChangelogMd(changelogs); + const changelogMd = changelogUtils.generateChangelogMd(changelog); const changelogMdPath = path.join(lernaPackage.location, 'CHANGELOG.md'); fs.writeFileSync(changelogMdPath, changelogMd); await utils.prettifyAsync(changelogMdPath, constants.monorepoRootPath); @@ -231,7 +178,8 @@ async function updateChangeLogsAsync(updatedPublicLernaPackages: LernaPackage[]) async function lernaPublishAsync(packageToVersionChange: { [name: string]: string }): Promise<void> { // HACK: Lerna publish does not provide a way to specify multiple package versions via // flags so instead we need to interact with their interactive prompt interface. - const child = spawn('lerna', ['publish', '--registry=https://registry.npmjs.org/'], { + const PACKAGE_REGISTRY = 'https://registry.npmjs.org/'; + const child = spawn('lerna', ['publish', `--registry=${PACKAGE_REGISTRY}`], { cwd: constants.monorepoRootPath, }); let shouldPrintOutput = false; @@ -279,46 +227,3 @@ function updateVersionNumberIfNeeded(currentVersion: string, proposedNextVersion } return proposedNextVersion; } - -function shouldAddNewChangelogEntry(currentVersion: string, changelogs: Changelog[]): boolean { - if (_.isEmpty(changelogs)) { - return true; - } - const lastEntry = changelogs[0]; - const isLastEntryCurrentVersion = lastEntry.version === currentVersion; - return isLastEntryCurrentVersion; -} - -function generateChangelogMd(changelogs: Changelog[]): string { - let changelogMd = `<!-- -This file is auto-generated using the monorepo-scripts package. Don't edit directly. -Edit the package's CHANGELOG.json file only. ---> - -CHANGELOG - `; - - _.each(changelogs, changelog => { - if (_.isUndefined(changelog.timestamp)) { - throw new Error( - 'All CHANGELOG.json entries must be updated to include a timestamp before generating their MD version', - ); - } - const date = moment(`${changelog.timestamp}`, 'X').format('MMMM D, YYYY'); - const title = `\n## v${changelog.version} - _${date}_\n\n`; - changelogMd += title; - - let changes = ''; - _.each(changelog.changes, change => { - let line = ` * ${change.note}`; - if (!_.isUndefined(change.pr)) { - line += ` (#${change.pr})`; - } - line += '\n'; - changes += line; - }); - changelogMd += `${changes}`; - }); - - return changelogMd; -} diff --git a/packages/monorepo-scripts/src/remove_tags.ts b/packages/monorepo-scripts/src/remove_tags.ts index 6d09729c7..affdf2751 100644 --- a/packages/monorepo-scripts/src/remove_tags.ts +++ b/packages/monorepo-scripts/src/remove_tags.ts @@ -8,7 +8,7 @@ import semverSort = require('semver-sort'); import { constants } from './constants'; import { Changelog } from './types'; -import { utils } from './utils'; +import { utils } from './utils/utils'; (async () => { const shouldIncludePrivate = true; @@ -24,7 +24,7 @@ import { utils } from './utils'; let latestChangelogVersion: string; if (!_.isUndefined(changelogJSONIfExists)) { - let changelogs: Changelog[]; + let changelogs: Changelog; try { changelogs = JSON.parse(changelogJSONIfExists); } catch (err) { diff --git a/packages/monorepo-scripts/src/test_installation.ts b/packages/monorepo-scripts/src/test_installation.ts index e84221f9d..b67154667 100644 --- a/packages/monorepo-scripts/src/test_installation.ts +++ b/packages/monorepo-scripts/src/test_installation.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import { exec as execAsync } from 'promisify-child-process'; import * as rimraf from 'rimraf'; -import { utils } from './utils'; +import { utils } from './utils/utils'; (async () => { const monorepoRootPath = path.join(__dirname, '../../..'); diff --git a/packages/monorepo-scripts/src/types.ts b/packages/monorepo-scripts/src/types.ts index 28d00d710..36fb923b3 100644 --- a/packages/monorepo-scripts/src/types.ts +++ b/packages/monorepo-scripts/src/types.ts @@ -4,15 +4,17 @@ export interface UpdatedPackage { private: boolean; } -export interface Changes { +export interface Change { note: string; pr?: number; } -export interface Changelog { +export type Changelog = VersionChangelog[]; + +export interface VersionChangelog { timestamp?: number; version: string; - changes: Changes[]; + changes: Change[]; } export enum SemVerIndex { diff --git a/packages/monorepo-scripts/src/utils/changelog_utils.ts b/packages/monorepo-scripts/src/utils/changelog_utils.ts new file mode 100644 index 000000000..edfe65a80 --- /dev/null +++ b/packages/monorepo-scripts/src/utils/changelog_utils.ts @@ -0,0 +1,55 @@ +import * as _ from 'lodash'; +import * as moment from 'moment'; + +import { Change, Changelog, VersionChangelog } from '../types'; + +const CHANGELOG_MD_HEADER = ` +<!-- +This file is auto-generated using the monorepo-scripts package. Don't edit directly. +Edit the package's CHANGELOG.json file only. +--> + +CHANGELOG +`; + +export const changelogUtils = { + getChangelogMdTitle(versionChangelog: VersionChangelog): string { + if (_.isUndefined(versionChangelog.timestamp)) { + throw new Error( + 'All CHANGELOG.json entries must be updated to include a timestamp before generating their MD version', + ); + } + const date = moment(`${versionChangelog.timestamp}`, 'X').format('MMMM D, YYYY'); + const title = `\n## v${versionChangelog.version} - _${date}_\n\n`; + return title; + }, + getChangelogMdChange(change: Change): string { + let line = ` * ${change.note}`; + if (!_.isUndefined(change.pr)) { + line += ` (#${change.pr})`; + } + return line; + }, + generateChangelogMd(changelog: Changelog): string { + let changelogMd = CHANGELOG_MD_HEADER; + _.each(changelog, versionChangelog => { + const title = changelogUtils.getChangelogMdTitle(versionChangelog); + changelogMd += title; + const changelogVersionLines = _.map( + versionChangelog.changes, + changelogUtils.getChangelogMdChange.bind(changelogUtils), + ); + changelogMd += `${_.join(changelogVersionLines, '\n')}`; + }); + + return changelogMd; + }, + shouldAddNewChangelogEntry(currentVersion: string, changelog: Changelog): boolean { + if (_.isEmpty(changelog)) { + return true; + } + const lastEntry = changelog[0]; + const isLastEntryCurrentVersion = lastEntry.version === currentVersion; + return isLastEntryCurrentVersion; + }, +}; diff --git a/packages/monorepo-scripts/src/utils.ts b/packages/monorepo-scripts/src/utils/utils.ts index c2d92c86a..8f2a0bbaa 100644 --- a/packages/monorepo-scripts/src/utils.ts +++ b/packages/monorepo-scripts/src/utils/utils.ts @@ -3,8 +3,8 @@ import lernaGetPackages = require('lerna-get-packages'); import * as _ from 'lodash'; import { exec as execAsync, spawn } from 'promisify-child-process'; -import { constants } from './constants'; -import { UpdatedPackage } from './types'; +import { constants } from '../constants'; +import { UpdatedPackage } from '../types'; export const utils = { log(...args: any[]): void { |