semantic-release-multi
Version:
Plugins for `semantic-release` allowing it to be used with a monorepo.
181 lines • 7.78 kB
JavaScript
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
;