UNPKG

3.57 kBJavaScriptView Raw
1const {castArray, pickBy, isNil, isString, isPlainObject} = require('lodash');
2const readPkgUp = require('read-pkg-up');
3const {cosmiconfig} = require('cosmiconfig');
4const resolveFrom = require('resolve-from');
5const debug = require('debug')('semantic-release:config');
6const {repoUrl} = require('./git');
7const PLUGINS_DEFINITIONS = require('./definitions/plugins');
8const plugins = require('./plugins');
9const {validatePlugin, parseConfig} = require('./plugins/utils');
10
11const CONFIG_NAME = 'release';
12const CONFIG_FILES = [
13 'package.json',
14 `.${CONFIG_NAME}rc`,
15 `.${CONFIG_NAME}rc.json`,
16 `.${CONFIG_NAME}rc.yaml`,
17 `.${CONFIG_NAME}rc.yml`,
18 `.${CONFIG_NAME}rc.js`,
19 `${CONFIG_NAME}.config.js`,
20];
21
22module.exports = async (context, cliOptions) => {
23 const {cwd, env} = context;
24 const {config, filepath} = (await cosmiconfig(CONFIG_NAME, {searchPlaces: CONFIG_FILES}).search(cwd)) || {};
25
26 debug('load config from: %s', filepath);
27
28 // Merge config file options and CLI/API options
29 let options = {...config, ...cliOptions};
30
31 const pluginsPath = {};
32 let extendPaths;
33 ({extends: extendPaths, ...options} = options);
34 if (extendPaths) {
35 // If `extends` is defined, load and merge each shareable config with `options`
36 options = {
37 ...castArray(extendPaths).reduce((result, extendPath) => {
38 const extendsOptions = require(resolveFrom.silent(__dirname, extendPath) || resolveFrom(cwd, extendPath));
39
40 // For each plugin defined in a shareable config, save in `pluginsPath` the extendable config path,
41 // so those plugin will be loaded relatively to the config file
42 Object.entries(extendsOptions)
43 .filter(([, value]) => Boolean(value))
44 .reduce((pluginsPath, [option, value]) => {
45 castArray(value).forEach((plugin) => {
46 if (option === 'plugins' && validatePlugin(plugin)) {
47 pluginsPath[parseConfig(plugin)[0]] = extendPath;
48 } else if (
49 PLUGINS_DEFINITIONS[option] &&
50 (isString(plugin) || (isPlainObject(plugin) && isString(plugin.path)))
51 ) {
52 pluginsPath[isString(plugin) ? plugin : plugin.path] = extendPath;
53 }
54 });
55 return pluginsPath;
56 }, pluginsPath);
57
58 return {...result, ...extendsOptions};
59 }, {}),
60 ...options,
61 };
62 }
63
64 // Set default options values if not defined yet
65 options = {
66 branches: [
67 '+([0-9])?(.{+([0-9]),x}).x',
68 'master',
69 'next',
70 'next-major',
71 {name: 'beta', prerelease: true},
72 {name: 'alpha', prerelease: true},
73 ],
74 repositoryUrl: (await pkgRepoUrl({normalize: false, cwd})) || (await repoUrl({cwd, env})),
75 tagFormat: `v\${version}`,
76 plugins: [
77 '@semantic-release/commit-analyzer',
78 '@semantic-release/release-notes-generator',
79 '@semantic-release/npm',
80 '@semantic-release/github',
81 ],
82 // Remove `null` and `undefined` options so they can be replaced with default ones
83 ...pickBy(options, (option) => !isNil(option)),
84 ...(options.branches ? {branches: castArray(options.branches)} : {}),
85 };
86
87 if (options.ci === false) {
88 options.noCi = true;
89 }
90
91 debug('options values: %O', options);
92
93 return {options, plugins: await plugins({...context, options}, pluginsPath)};
94};
95
96async function pkgRepoUrl(options) {
97 const {packageJson} = (await readPkgUp(options)) || {};
98 return packageJson && (isPlainObject(packageJson.repository) ? packageJson.repository.url : packageJson.repository);
99}