UNPKG

3.27 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, opts) => {
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, ...opts};
30 if (options.ci === false) {
31 options.noCi = true;
32 }
33
34 const pluginsPath = {};
35 let extendPaths;
36 ({extends: extendPaths, ...options} = options);
37 if (extendPaths) {
38 // If `extends` is defined, load and merge each shareable config with `options`
39 options = {
40 ...castArray(extendPaths).reduce((result, extendPath) => {
41 const extendsOpts = require(resolveFrom.silent(__dirname, extendPath) || resolveFrom(cwd, extendPath));
42
43 // For each plugin defined in a shareable config, save in `pluginsPath` the extendable config path,
44 // so those plugin will be loaded relatively to the config file
45 Object.entries(extendsOpts)
46 .filter(([, value]) => Boolean(value))
47 .reduce((pluginsPath, [option, value]) => {
48 castArray(value).forEach(plugin => {
49 if (option === 'plugins' && validatePlugin(plugin)) {
50 pluginsPath[parseConfig(plugin)[0]] = extendPath;
51 } else if (
52 PLUGINS_DEFINITIONS[option] &&
53 (isString(plugin) || (isPlainObject(plugin) && isString(plugin.path)))
54 ) {
55 pluginsPath[isString(plugin) ? plugin : plugin.path] = extendPath;
56 }
57 });
58 return pluginsPath;
59 }, pluginsPath);
60
61 return {...result, ...extendsOpts};
62 }, {}),
63 ...options,
64 };
65 }
66
67 // Set default options values if not defined yet
68 options = {
69 branch: 'master',
70 repositoryUrl: (await pkgRepoUrl({normalize: false, cwd})) || (await repoUrl({cwd, env})),
71 tagFormat: `v\${version}`,
72 plugins: [
73 '@semantic-release/commit-analyzer',
74 '@semantic-release/release-notes-generator',
75 '@semantic-release/npm',
76 '@semantic-release/github',
77 ],
78 // Remove `null` and `undefined` options so they can be replaced with default ones
79 ...pickBy(options, option => !isNil(option)),
80 };
81
82 debug('options values: %O', options);
83
84 return {options, plugins: await plugins({...context, options}, pluginsPath)};
85};
86
87async function pkgRepoUrl(opts) {
88 const {package: pkg} = (await readPkgUp(opts)) || {};
89 return pkg && (isPlainObject(pkg.repository) ? pkg.repository.url : pkg.repository);
90}