UNPKG

semantic-release-multi

Version:

Plugins for `semantic-release` allowing it to be used with a monorepo.

181 lines 7.78 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initGitRepo = exports.initBareRepo = exports.initGit = exports.gitCommitsWithFiles = exports.getRoot = exports.getCommitFiles = exports.gitResult = void 0; const execa_1 = require("execa"); const file_url_1 = __importDefault(require("file-url")); const fs_extra_1 = __importDefault(require("fs-extra")); const get_stream_1 = __importDefault(require("get-stream")); const git_log_parser_1 = __importDefault(require("git-log-parser")); const p_each_series_1 = __importDefault(require("p-each-series")); const path_1 = __importDefault(require("path")); const tempy_1 = require("tempy"); function gitResult(args, options = {}) { const { stdout } = (0, execa_1.execaSync)('git', args, options); return stdout; } exports.gitResult = gitResult; /** * // https://stackoverflow.com/questions/424071/how-to-list-all-the-files-in-a-commit * @async * @param hash Git commit hash. * @return {Promise<Array>} List of modified files in a commit. */ function getCommitFiles(hash) { const rs = gitResult(['diff-tree', '--root', '--no-commit-id', '--name-only', '-r', hash]); return rs.split('\n'); } exports.getCommitFiles = getCommitFiles; /** * https://stackoverflow.com/a/957978/89594 * @async * @return {Promise<String>} System path of the git repository. */ const getRoot = () => gitResult(['rev-parse', '--show-toplevel']); exports.getRoot = getRoot; /** * Create commits on the current git repository. * * @param {Array<string>} messages Commit messages. * @param {Object} [execaOpts] Options to pass to `execa`. * * @returns {Array<Commit>} The created commits, in reverse order (to match `git log` order). */ async function gitCommitsWithFiles(commits) { for (const commit of commits) { for (const file of commit.files) { let filePath = path_1.default.join(process.cwd(), file.name); fs_extra_1.default.outputFileSync(filePath, (file.body = !'undefined' ? file.body : commit.message)); (0, execa_1.execaSync)('git', ['add', filePath]); } (0, execa_1.execaSync)('git', ['commit', '-m', commit.message, '--allow-empty', '--no-gpg-sign']); } return (await gitGetCommits(undefined)).slice(0, commits === null || commits === void 0 ? void 0 : commits.length); } exports.gitCommitsWithFiles = gitCommitsWithFiles; /** * Initialize git repository * If `withRemote` is `true`, creates a bare repository and initialize it. * If `withRemote` is `false`, creates a regular repository and initialize it. * * @param {Boolean} withRemote `true` to create a shallow clone of a bare repository. * @return {{cwd: string, repositoryUrl: string}} The path of the repository */ async function initGit(withRemote) { const cwd = (0, tempy_1.temporaryDirectory)(); const args = withRemote ? ['--bare', '--initial-branch=master'] : ['--initial-branch=master']; try { (0, execa_1.execaSync)('git', ['init', ...args], { cwd }); } catch (e) { const args = withRemote ? ['--bare'] : []; (0, execa_1.execaSync)('git', ['init', ...args], { cwd }); } const repositoryUrl = (0, file_url_1.default)(cwd); return { cwd, repositoryUrl }; } exports.initGit = initGit; /** * Create commits on the current git repository. * * @param {Array<string>} messages Commit messages. * @param {Object} [execaOpts] Options to pass to `execa`. * * @returns {Array<Commit>} The created commits, in reverse order (to match `git log` order). */ const gitCommits = async (messages, execaOpts) => { await (0, p_each_series_1.default)(messages, async (message) => (0, execa_1.execaSync)('git', ['commit', '-m', message, '--allow-empty', '--no-gpg-sign'], execaOpts).stdout); return (await gitGetCommits(undefined, execaOpts)).slice(0, messages === null || messages === void 0 ? void 0 : messages.length); }; /** * Get the list of parsed commits since a git reference. * * @param {String} [from] Git reference from which to each commit. * @param {Object} [execaOpts] Options to pass to `execa`. * * @return {Array<Commit>} The list of parsed commits. */ const gitGetCommits = async (from, execaOpts = {}) => { Object.assign(git_log_parser_1.default.fields, { hash: 'H', message: 'B', gitTags: 'd', committerDate: { key: 'ci', type: Date }, }); return (await get_stream_1.default.array(git_log_parser_1.default.parse({ _: `${from ? from + '..' : ''}HEAD` }, { env: { ...process.env } }))).map((commit) => { commit.message = commit.message.trim(); commit.gitTags = commit.gitTags.trim(); return commit; }); }; /** * Initialize an existing bare repository: * - Clone the repository * - Change the current working directory to the clone root * - Create a default branch * - Create an initial commits * - Push to origin * * @param {String} repositoryUrl The URL of the bare repository. * @param {String} [branch='master'] the branch to initialize. */ async function initBareRepo(repositoryUrl, branch = 'master') { const cwd = (0, tempy_1.temporaryDirectory)(); (0, execa_1.execaSync)('git', ['clone', '--no-hardlinks', repositoryUrl, cwd], { cwd }); await gitCheckout(branch, true, { cwd }); await gitCommits(['Initial commit'], { cwd }); (0, execa_1.execaSync)('git', ['push', repositoryUrl, branch], { cwd }); } exports.initBareRepo = initBareRepo; /** * Create a temporary git repository. * If `withRemote` is `true`, creates a shallow clone. Change the current working directory to the clone root. * If `withRemote` is `false`, just change the current working directory to the repository root. * * * @param {Boolean} withRemote `true` to create a shallow clone of a bare repository. * @param {String} [branch='master'] The branch to initialize. * @return {String} The path of the clone if `withRemote` is `true`, the path of the repository otherwise. */ async function initGitRepo(withRemote, branch = 'master') { let { cwd, repositoryUrl } = await initGit(withRemote); if (withRemote) { await initBareRepo(repositoryUrl, branch); cwd = gitShallowClone(repositoryUrl, branch); } else { await gitCheckout(branch, true, { cwd }); } (0, execa_1.execaSync)('git', ['config', 'commit.gpgsign', 'false'], { cwd }); return { cwd, repositoryUrl }; } exports.initGitRepo = initGitRepo; /** * Create a shallow clone of a git repository and change the current working directory to the cloned repository root. * The shallow will contain a limited number of commit and no tags. * * @param {String} repositoryUrl The path of the repository to clone. * @param {String} [branch='master'] the branch to clone. * @param {Number} [depth=1] The number of commit to clone. * @return {String} The path of the cloned repository. */ const gitShallowClone = (repositoryUrl, branch = 'master', depth = 1) => { const cwd = (0, tempy_1.temporaryDirectory)(); (0, execa_1.execaSync)('git', ['clone', '--no-hardlinks', '--no-tags', '-b', branch, '--depth', depth, repositoryUrl, cwd], { cwd, }); return cwd; }; /** * Checkout a branch on the current git repository. * * @param {String} branch Branch name. * @param {Boolean} create to create the branch, `false` to check out an existing branch. * @param {Object} [execaOpts] Options to pass to `execa`. */ const gitCheckout = async (branch, create, execaOpts) => { (0, execa_1.execaSync)('git', create ? ['checkout', '-b', branch] : ['checkout', branch], execaOpts); }; //# sourceMappingURL=git-utils.js.map