text: const {readFile} = require('fs').promises;
  const {castArray, pickBy, isNil, isString, isPlainObject} = require('lodash');
  const findPkgUp = require('pkg-up');
  const {cosmiconfig} = require('cosmiconfig');
  const resolveFrom = require('resolve-from');
  const findDuplicatedPropertyKeys = require('find-duplicated-property-keys');
  const debug = require('debug')('semantic-release:config');
  const {repoUrl} = require('./git');
  const PLUGINS_DEFINITIONS = require('./definitions/plugins');
  const plugins = require('./plugins');
  const {validatePlugin, parseConfig} = require('./plugins/utils');
  const getError = require('./get-error');
  
  const CONFIG_NAME = 'release';
  const CONFIG_FILES = [
    'package.json',
    `.${CONFIG_NAME}rc`,
    `.${CONFIG_NAME}rc.json`,
    `.${CONFIG_NAME}rc.yaml`,
    `.${CONFIG_NAME}rc.yml`,
    `.${CONFIG_NAME}rc.js`,
    `${CONFIG_NAME}.config.js`,
  ];
  
  module.exports = async (context, cliOptions) => {
    const {cwd, env} = context;
    const {config, filepath} = (await cosmiconfig(CONFIG_NAME, {searchPlaces: CONFIG_FILES}).search(cwd)) || {};
  
    debug('load config from: %s', filepath);
  
    // Merge config file options and CLI/API options
    let options = {...config, ...cliOptions};
    if (options.ci === false) {
      options.noCi = true;
    }
  
    const pluginsPath = {};
    let extendPaths;
    ({extends: extendPaths, ...options} = options);
    if (extendPaths) {
      // If `extends` is defined, load and merge each shareable config with `options`
      options = {
        ...castArray(extendPaths).reduce((result, extendPath) => {
          const extendsOptions = require(resolveFrom.silent(__dirname, extendPath) || resolveFrom(cwd, extendPath));
  
          // For each plugin defined in a shareable config, save in `pluginsPath` the extendable config path,
          // so those plugin will be loaded relatively to the config file
          Object.entries(extendsOptions)
            .filter(([, value]) => Boolean(value))
            .reduce((pluginsPath, [option, value]) => {
              castArray(value).forEach((plugin) => {
                if (option === 'plugins' && validatePlugin(plugin)) {
                  pluginsPath[parseConfig(plugin)[0]] = extendPath;
                } else if (
                  PLUGINS_DEFINITIONS[option] &&
                  (isString(plugin) || (isPlainObject(plugin) && isString(plugin.path)))
                ) {
                  pluginsPath[isString(plugin) ? plugin : plugin.path] = extendPath;
                }
              });
              return pluginsPath;
            }, pluginsPath);
  
          return {...result, ...extendsOptions};
        }, {}),
        ...options,
      };
    }
  
    // Set default options values if not defined yet
    options = {
      branches: [
        '+([0-9])?(.{+([0-9]),x}).x',
        'master',
        'next',
        'next-major',
        {name: 'beta', prerelease: true},
        {name: 'alpha', prerelease: true},
      ],
      repositoryUrl: (await pkgRepoUrl({cwd})) || (await repoUrl({cwd, env})),
      tagFormat: `v\${version}`,
      plugins: [
        '@semantic-release/commit-analyzer',
        '@semantic-release/release-notes-generator',
        '@semantic-release/npm',
        '@semantic-release/github',
      ],
      // Remove `null` and `undefined` options so they can be replaced with default ones
      ...pickBy(options, (option) => !isNil(option)),
      ...(options.branches ? {branches: castArray(options.branches)} : {}),
    };
  
    debug('options values: %O', options);
  
    return {options, plugins: await plugins({...context, options}, pluginsPath)};
  };
  
  async function pkgRepoUrl(options) {
    const packageJsonPath = await findPkgUp(options);
    if (!packageJsonPath) return;
  
    const packageJsonString = await readFile(packageJsonPath, 'utf-8');
    const result = findDuplicatedPropertyKeys(packageJsonString);
  
    if (result.length > 0) {
      throw getError('EDUPLICATEREPOSITORYKEY', {packageJsonPath});
    }
  
    const {repository} = require(packageJsonPath);
    if (!repository) return;
  
    return isPlainObject(repository) ? repository.url : repository;
  }
  