From ff3a1f53aa70e1eae0b3f5e619be36710f824c09 Mon Sep 17 00:00:00 2001 From: Patrick Mowrer Date: Mon, 8 Jan 2018 17:59:23 -0500 Subject: [PATCH 1/3] fix: typo in `debug` namespace for in `git-utils` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The typo was causing debug statements to be swallowed (since they didn’t match the preconfigured `semantic-release:` namespace). --- src/git-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/git-utils.js b/src/git-utils.js index 07c7a37..67745be 100644 --- a/src/git-utils.js +++ b/src/git-utils.js @@ -1,6 +1,6 @@ const { pipeP, split } = require('ramda'); const execa = require('execa'); -const debug = require('debug')('semantic-release-monorepo'); +const debug = require('debug')('semantic-release:monorepo'); const git = async (args, options = {}) => { const { stdout } = await execa('git', args, options); From 9d497703164a1d742b263183d2cdb42a98daf8d6 Mon Sep 17 00:00:00 2001 From: Patrick Mowrer Date: Mon, 8 Jan 2018 19:32:36 -0500 Subject: [PATCH 2/3] refactor: bring some consistency to `git-utils` functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Using “git” in the function name is redundant. * Use arrow functions throughout. --- src/git-utils.js | 10 +++++----- src/only-package-commits.js | 4 ++-- src/with-version-head.js | 10 +++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/git-utils.js b/src/git-utils.js index 67745be..0f1ebc8 100644 --- a/src/git-utils.js +++ b/src/git-utils.js @@ -23,7 +23,7 @@ const getCommitFiles = pipeP( * @async * @return {Promise} System path of the git repository. */ -const getGitRoot = () => git(['rev-parse', '--show-toplevel']); +const getRoot = () => git(['rev-parse', '--show-toplevel']); /** * Get the commit sha for a given tag. @@ -32,14 +32,14 @@ const getGitRoot = () => git(['rev-parse', '--show-toplevel']); * @param {string} tagName Tag name for which to retrieve the commit sha. * @return {string} The commit sha of the tag in parameter or `null`. */ -async function gitTagHead(tagName) { +const getTagHead = async tagName => { try { return await git(['rev-list', '-1', tagName]); } catch (err) { debug(err); return null; } -} +}; /** * Unshallow the git repository (retrieving every commit and tags). @@ -50,7 +50,7 @@ const unshallow = () => module.exports = { getCommitFiles, - getGitRoot, - gitTagHead, + getRoot, + getTagHead, unshallow, }; diff --git a/src/only-package-commits.js b/src/only-package-commits.js index 38350d3..4df4c19 100644 --- a/src/only-package-commits.js +++ b/src/only-package-commits.js @@ -2,14 +2,14 @@ const { identity, memoizeWith, pipeP } = require('ramda'); const pkgUp = require('pkg-up'); const readPkg = require('read-pkg'); const debug = require('debug')('semantic-release:monorepo'); -const { getCommitFiles, getGitRoot } = require('./git-utils'); +const { getCommitFiles, getRoot } = require('./git-utils'); const { mapCommits } = require('./options-transforms'); const memoizedGetCommitFiles = memoizeWith(identity, getCommitFiles); const getPackagePath = async () => { const path = await pkgUp(); - const gitRoot = await getGitRoot(); + const gitRoot = await getRoot(); return path.replace('package.json', '').replace(`${gitRoot}/`, ''); }; diff --git a/src/with-version-head.js b/src/with-version-head.js index 2ddf4ba..7c6480f 100644 --- a/src/with-version-head.js +++ b/src/with-version-head.js @@ -11,18 +11,18 @@ const { const debug = require('debug')('semantic-release:monorepo'); const gitTag = require('./version-to-git-tag'); -const { gitTagHead, unshallow } = require('./git-utils'); +const { getTagHead, unshallow } = require('./git-utils'); /** * Attempt to find the git tag for the given tag name. * Will "unshallow" the repo and try again if not successful. * Adapted from: https://github.com/semantic-release/npm/blob/cf039fdafda1a5ce43c2a5f033160cd46487f102/lib/get-version-head.js */ -const getTagHead = tagName => +const findTagHead = tagName => pipeP( - gitTagHead, + getTagHead, when(isNil, pipeP(unshallow, always(tagName))), - when(equals(tagName), gitTagHead), + when(equals(tagName), getTagHead), unless(isNil, tap(curryN(2, debug)('Use tagHead: %s'))) )(tagName); @@ -42,7 +42,7 @@ const withVersionHead = plugin => async (pluginConfig, options) => { if (release) { return { ...release, - gitHead: await getTagHead(await gitTag(release.version)), + gitHead: await findTagHead(await gitTag(release.version)), }; } }; From d0f0ab844bc54853fca685348be8d08642fdfc14 Mon Sep 17 00:00:00 2001 From: Patrick Mowrer Date: Mon, 8 Jan 2018 20:32:10 -0500 Subject: [PATCH 3/3] feat(withVersionHead): fetch git tags prior to trying to unshallow Fetching tags is likely pointless when running on CI since it's assumed that the repo has just been cloned (implying up-to-date tags). However, when running locally (e.g. `--dry-run`), it's not uncommon that tags are out of sync with origin, which is why we include this step. --- src/git-utils.js | 16 +++++++------- src/with-version-head.js | 47 +++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/git-utils.js b/src/git-utils.js index 0f1ebc8..26450f7 100644 --- a/src/git-utils.js +++ b/src/git-utils.js @@ -32,14 +32,13 @@ const getRoot = () => git(['rev-parse', '--show-toplevel']); * @param {string} tagName Tag name for which to retrieve the commit sha. * @return {string} The commit sha of the tag in parameter or `null`. */ -const getTagHead = async tagName => { - try { - return await git(['rev-list', '-1', tagName]); - } catch (err) { - debug(err); - return null; - } -}; +const getTagHead = tagName => + git(['rev-list', '-1', tagName], { reject: false }); + +/** + * Fetch tags from the repository's origin. + */ +const fetchTags = () => git(['fetch', '--tags']); /** * Unshallow the git repository (retrieving every commit and tags). @@ -52,5 +51,6 @@ module.exports = { getCommitFiles, getRoot, getTagHead, + fetchTags, unshallow, }; diff --git a/src/with-version-head.js b/src/with-version-head.js index 7c6480f..841bbc1 100644 --- a/src/with-version-head.js +++ b/src/with-version-head.js @@ -1,29 +1,42 @@ -const { - always, - curryN, - equals, - isNil, - pipeP, - tap, - unless, - when, -} = require('ramda'); +const { curryN, isEmpty, pipeP, tap, unless, when } = require('ramda'); const debug = require('debug')('semantic-release:monorepo'); const gitTag = require('./version-to-git-tag'); -const { getTagHead, unshallow } = require('./git-utils'); +const { getTagHead, fetchTags, unshallow } = require('./git-utils'); + +const debugTap = message => tap(curryN(2, debug)(message)); +const whenIsEmpty = when(isEmpty); +const unlessIsEmpty = unless(isEmpty); /** * Attempt to find the git tag for the given tag name. - * Will "unshallow" the repo and try again if not successful. + * If necessary, will fetch git tags and "unshallow". * Adapted from: https://github.com/semantic-release/npm/blob/cf039fdafda1a5ce43c2a5f033160cd46487f102/lib/get-version-head.js */ const findTagHead = tagName => pipeP( getTagHead, - when(isNil, pipeP(unshallow, always(tagName))), - when(equals(tagName), getTagHead), - unless(isNil, tap(curryN(2, debug)('Use tagHead: %s'))) + whenIsEmpty( + // Fetching tags is likely pointless when running on CI since it's assumed + // that the repo has just been cloned (implying up-to-date tags). + // However, when running locally (e.g. `--dry-run`), it's not uncommon that + // tags are out of sync with origin, which is why we include this step. + pipeP( + fetchTags, + debugTap('Unable to find tagHead. Fetching tags and re-trying.'), + () => getTagHead(tagName) + ) + ), + whenIsEmpty( + // Unshallowing is likely only relevant on CI, where using a shallow clone + // is more performant than downloading the entire repo. + pipeP( + unshallow, + debugTap('Unable to find tagHead. Unshallowing and re-trying.'), + () => getTagHead(tagName) + ) + ), + unlessIsEmpty(debugTap('Use tagHead: %o')) )(tagName); /** @@ -36,8 +49,8 @@ const findTagHead = tagName => * 2. We can use `semantic-release`'s fallback strategy, searching for a matching git tag, * but we must update the git tag format to be compatible with the monorepo workflow. **/ -const withVersionHead = plugin => async (pluginConfig, options) => { - const release = await plugin(pluginConfig, options); +const withVersionHead = plugin => async (pluginConfig, config) => { + const release = await plugin(pluginConfig, config); if (release) { return {