UNPKG

2.69 kBJavaScriptView Raw
1const { identity, memoizeWith, pipeP } = require('ramda');
2const pkgUp = require('pkg-up');
3const readPkg = require('read-pkg');
4const path = require('path');
5const pLimit = require('p-limit');
6const debug = require('debug')('semantic-release:monorepo');
7const { getCommitFiles, getRoot } = require('./git-utils');
8const { mapCommits } = require('./options-transforms');
9
10const memoizedGetCommitFiles = memoizeWith(identity, getCommitFiles);
11
12/**
13 * Get the normalized PACKAGE root path, relative to the git PROJECT root.
14 */
15const getPackagePath = async () => {
16 const packagePath = await pkgUp();
17 const gitRoot = await getRoot();
18
19 return path.relative(gitRoot, path.resolve(packagePath, '..'));
20};
21
22const withFiles = async commits => {
23 const limit = pLimit(Number(process.env.SRM_MAX_THREADS) || 500);
24 return Promise.all(
25 commits.map(commit =>
26 limit(async () => {
27 const files = await memoizedGetCommitFiles(commit.hash);
28 return { ...commit, files };
29 })
30 )
31 );
32};
33
34const onlyPackageCommits = async commits => {
35 const packagePath = await getPackagePath();
36 debug('Filter commits by package path: "%s"', packagePath);
37 const commitsWithFiles = await withFiles(commits);
38 // Convert package root path into segments - one for each folder
39 const packageSegments = packagePath.split(path.sep);
40
41 return commitsWithFiles.filter(({ files, subject }) => {
42 // Normalise paths and check if any changed files' path segments start
43 // with that of the package root.
44 const packageFile = files.find(file => {
45 const fileSegments = path.normalize(file).split(path.sep);
46 // Check the file is a *direct* descendent of the package folder (or the folder itself)
47 return packageSegments.every(
48 (packageSegment, i) => packageSegment === fileSegments[i]
49 );
50 });
51
52 if (packageFile) {
53 debug(
54 'Including commit "%s" because it modified package file "%s".',
55 subject,
56 packageFile
57 );
58 }
59
60 return !!packageFile;
61 });
62};
63
64// Async version of Ramda's `tap`
65const tapA = fn => async x => {
66 await fn(x);
67 return x;
68};
69
70const logFilteredCommitCount = logger => async ({ commits }) => {
71 const { name } = await readPkg();
72
73 logger.log(
74 'Found %s commits for package %s since last release',
75 commits.length,
76 name
77 );
78};
79
80const withOnlyPackageCommits = plugin => async (pluginConfig, config) => {
81 const { logger } = config;
82
83 return plugin(
84 pluginConfig,
85 await pipeP(
86 mapCommits(onlyPackageCommits),
87 tapA(logFilteredCommitCount(logger))
88 )(config)
89 );
90};
91
92module.exports = {
93 withOnlyPackageCommits,
94 onlyPackageCommits,
95 withFiles,
96};