release-it 19.0.0-next.0 → 19.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cli.js CHANGED
@@ -1,11 +1,8 @@
1
1
  import { readJSON } from './util.js';
2
- import Log from './log.js';
3
2
  import runTasks from './index.js';
4
3
 
5
4
  const pkg = readJSON(new URL('../package.json', import.meta.url));
6
5
 
7
- const log = new Log();
8
-
9
6
  const helpText = `Release It! v${pkg.version}
10
7
 
11
8
  Usage: release-it <increment> [options]
@@ -27,10 +24,10 @@ const helpText = `Release It! v${pkg.version}
27
24
  For more details, please see https://github.com/release-it/release-it`;
28
25
 
29
26
  /** @internal */
30
- export const version = () => log.log(`v${pkg.version}`);
27
+ export const version = () => console.log(`v${pkg.version}`);
31
28
 
32
29
  /** @internal */
33
- export const help = () => log.log(helpText);
30
+ export const help = () => console.log(helpText);
34
31
 
35
32
  export default async options => {
36
33
  if (options.version) {
package/lib/config.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import util from 'node:util';
2
2
  import { cosmiconfigSync } from 'cosmiconfig';
3
3
  import parseToml from '@iarna/toml/parse-string.js';
4
- import _ from 'lodash';
5
4
  import { isCI } from 'ci-info';
6
- import { readJSON, getSystemInfo } from './util.js';
5
+ import defaultsDeep from '@nodeutils/defaults-deep';
6
+ import { isObjectStrict } from '@phun-ky/typeof';
7
+ import merge from 'lodash.merge';
8
+ import get from 'lodash.get';
9
+ import { e, getSystemInfo, readJSON } from './util.js';
7
10
 
8
11
  const debug = util.debug('release-it:config');
9
12
  const defaultConfig = readJSON(new URL('../config/release-it.json', import.meta.url));
@@ -35,7 +38,34 @@ const getLocalConfig = ({ file, dir = process.cwd() }) => {
35
38
  throw new Error(`Invalid configuration file at ${result.filepath}`);
36
39
  }
37
40
  debug({ cosmiconfig: result });
38
- return result && _.isPlainObject(result.config) ? result.config : localConfig;
41
+ return result && isObjectStrict(result.config) ? result.config : localConfig;
42
+ };
43
+
44
+ const fetchConfigurationFromGitHub = async configuration => {
45
+ const docs = 'https://github.com/release-it/release-it/blob/main/docs/configuration.md';
46
+
47
+ const regex = /^github:([^/]+)\/([^#:]+)(?::([^#]+))?(?:#(.+))?$/;
48
+ const match = configuration.match(regex);
49
+
50
+ if (!match) {
51
+ throw e(`Invalid Extended Configuration from GitHub: ${configuration}`, docs);
52
+ }
53
+
54
+ const [, owner, repo, file = '.release-it.json', tag] = match;
55
+ const ref = tag ? `refs/tags/${tag}` : 'HEAD';
56
+ const url = new URL(`https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${file}`);
57
+
58
+ const response = await fetch(url);
59
+
60
+ if (!response.ok) {
61
+ throw e(`Failed to fetch ${url}: ${response.statusText}`, docs);
62
+ }
63
+
64
+ return response.json();
65
+ };
66
+
67
+ const getRemoteConfiguration = async configuration => {
68
+ return fetchConfigurationFromGitHub(configuration);
39
69
  };
40
70
 
41
71
  class Config {
@@ -72,7 +102,7 @@ class Config {
72
102
  }
73
103
 
74
104
  mergeOptions() {
75
- return _.defaultsDeep(
105
+ return defaultsDeep(
76
106
  {},
77
107
  this.constructorConfig,
78
108
  {
@@ -83,14 +113,17 @@ class Config {
83
113
  );
84
114
  }
85
115
 
116
+ mergeRemoteOptions(remoteConfiguration) {
117
+ return merge({}, this.options, remoteConfiguration);
118
+ }
86
119
  getContext(path) {
87
- const context = _.merge({}, this.options, this.contextOptions);
88
- return path ? _.get(context, path) : context;
120
+ const context = merge({}, this.options, this.contextOptions);
121
+ return path ? get(context, path) : context;
89
122
  }
90
123
 
91
124
  setContext(options) {
92
125
  debug(options);
93
- _.merge(this.contextOptions, options);
126
+ merge(this.contextOptions, options);
94
127
  }
95
128
 
96
129
  setCI(value = true) {
@@ -138,4 +171,6 @@ class Config {
138
171
  }
139
172
  }
140
173
 
174
+ export { getRemoteConfiguration };
175
+
141
176
  export default Config;
package/lib/index.js CHANGED
@@ -1,11 +1,10 @@
1
- import _ from 'lodash';
2
1
  import { getPlugins } from './plugin/factory.js';
3
2
  import Logger from './log.js';
4
- import Config from './config.js';
3
+ import Config, { getRemoteConfiguration } from './config.js';
5
4
  import Shell from './shell.js';
6
5
  import Prompt from './prompt.js';
7
6
  import Spinner from './spinner.js';
8
- import { reduceUntil, parseVersion } from './util.js';
7
+ import { reduceUntil, parseVersion, castArray } from './util.js';
9
8
 
10
9
  const runTasks = async (opts, di) => {
11
10
  let container = {};
@@ -14,6 +13,15 @@ const runTasks = async (opts, di) => {
14
13
  Object.assign(container, di);
15
14
  container.config = container.config || new Config(opts);
16
15
 
16
+ if (typeof container.config.options?.extends === 'string') {
17
+ /**
18
+ * If the configuration has an 'extends' property, fetch the remote configuration
19
+ * and merge it into the local configuration options.
20
+ */
21
+ const remoteConfiguration = await getRemoteConfiguration(container.config.options.extends);
22
+ container.config.options = container.config.mergeRemoteOptions(remoteConfiguration);
23
+ }
24
+
17
25
  const { config } = container;
18
26
  const { isCI, isVerbose, verbosityLevel, isDryRun, isChangelog, isReleaseVersion } = config;
19
27
 
@@ -33,20 +41,20 @@ const runTasks = async (opts, di) => {
33
41
  if (!scripts || !scripts.length) return;
34
42
  const context = config.getContext();
35
43
  const external = true;
36
- for (const script of _.castArray(scripts)) {
44
+ for (const script of castArray(scripts)) {
37
45
  const task = () => shell.exec(script, { external }, context);
38
46
  await spinner.show({ task, label: script, context, external });
39
47
  }
40
48
  };
41
49
 
42
50
  const runLifeCycleHook = async (plugin, name, ...args) => {
43
- if (plugin === _.first(plugins)) await runHook('before', name);
51
+ if (plugin === plugins.at(0)) await runHook('before', name);
44
52
  await runHook('before', plugin.namespace, name);
45
53
  const willHookRun = (await plugin[name](...args)) !== false;
46
54
  if (willHookRun) {
47
55
  await runHook('after', plugin.namespace, name);
48
56
  }
49
- if (plugin === _.last(plugins)) await runHook('after', name);
57
+ if (plugin === plugins.at(-1)) await runHook('after', name);
50
58
  };
51
59
 
52
60
  const [internal, external] = await getPlugins(config, container);
@@ -63,8 +71,13 @@ const runTasks = async (opts, di) => {
63
71
  const changelog = await reduceUntil(plugins, plugin => plugin.getChangelog(latestVersion));
64
72
 
65
73
  if (isChangelog) {
66
- console.log(changelog);
67
- process.exit(0);
74
+ if (changelog) {
75
+ console.log(changelog);
76
+ process.exit(0);
77
+ } else {
78
+ log.warn('No changelog found');
79
+ process.exit(1);
80
+ }
68
81
  }
69
82
 
70
83
  const incrementBase = { latestVersion, increment, isPreRelease, preReleaseId, preReleaseBase };
@@ -96,13 +109,14 @@ const runTasks = async (opts, di) => {
96
109
  version = version || (await reduceUntil(plugins, plugin => plugin.getIncrementedVersion(incrementBase)));
97
110
  }
98
111
 
99
- if (!version) {
100
- log.obtrusive(`No new version to release`);
101
- }
102
-
103
112
  if (isReleaseVersion) {
104
- console.log(version);
105
- process.exit(0);
113
+ if (version) {
114
+ console.log(version);
115
+ process.exit(0);
116
+ } else {
117
+ log.warn(`No new version to release`);
118
+ process.exit(1);
119
+ }
106
120
  }
107
121
 
108
122
  if (version) {
@@ -126,6 +140,8 @@ const runTasks = async (opts, di) => {
126
140
  await runLifeCycleHook(plugin, hook);
127
141
  }
128
142
  }
143
+ } else {
144
+ log.obtrusive(`No new version to release`);
129
145
  }
130
146
 
131
147
  log.log(`🏁 Done (in ${Math.floor(process.uptime())}s.)`);
package/lib/log.js CHANGED
@@ -1,8 +1,7 @@
1
1
  import { EOL } from 'node:os';
2
2
  import chalk from 'chalk';
3
- import _ from 'lodash';
4
-
5
- const { isObject, last, filter, isString, lowerCase, upperFirst, isArray } = _;
3
+ import { isObjectLoose } from '@phun-ky/typeof';
4
+ import { upperFirst } from './util.js';
6
5
 
7
6
  class Logger {
8
7
  constructor({ isCI = true, isVerbose = false, verbosityLevel = 0, isDryRun = false } = {}) {
@@ -25,27 +24,29 @@ class Logger {
25
24
  }
26
25
 
27
26
  info(...args) {
28
- this.log(chalk.grey(...args));
27
+ console.error(chalk.grey(...args));
29
28
  }
30
29
 
31
30
  warn(...args) {
32
- this.log(chalk.yellow('WARNING'), ...args);
31
+ console.error(chalk.yellow('WARNING'), ...args);
33
32
  }
34
33
 
35
34
  verbose(...args) {
36
- const { isExternal } = isObject(last(args)) ? last(args) : {};
35
+ const { isExternal } = isObjectLoose(args.at(-1)) ? args.at(-1) : {};
37
36
  if (this.shouldLog(isExternal)) {
38
- this.log(...filter(args, isString));
37
+ console.error(...args.filter(str => typeof str === 'string'));
39
38
  }
40
39
  }
41
40
 
42
41
  exec(...args) {
43
- const { isDryRun: isExecutedInDryRun, isExternal, isCached } = isObject(last(args)) ? last(args) : {};
42
+ const { isDryRun: isExecutedInDryRun, isExternal, isCached } = isObjectLoose(args.at(-1)) ? args.at(-1) : {};
44
43
  if (this.shouldLog(isExternal) || this.isDryRun) {
45
44
  const prefix = isExecutedInDryRun == null ? '$' : '!';
46
- const command = args.map(cmd => (isString(cmd) ? cmd : isArray(cmd) ? cmd.join(' ') : '')).join(' ');
45
+ const command = args
46
+ .map(cmd => (typeof cmd === 'string' ? cmd : Array.isArray(cmd) ? cmd.join(' ') : ''))
47
+ .join(' ');
47
48
  const message = [prefix, command, isCached ? '[cached]' : ''].join(' ').trim();
48
- this.log(message);
49
+ console.error(message);
49
50
  }
50
51
  }
51
52
 
@@ -61,7 +62,7 @@ class Logger {
61
62
  const body = text.replace(new RegExp(EOL + EOL, 'g'), EOL);
62
63
  this.obtrusive(`${header}:${EOL}${body}`);
63
64
  } else {
64
- this.obtrusive(`Empty ${lowerCase(title)}`);
65
+ this.obtrusive(`Empty ${title.toLowerCase()}`);
65
66
  }
66
67
  }
67
68
  }
@@ -22,7 +22,8 @@ class GitBase extends Plugin {
22
22
  }
23
23
 
24
24
  getName() {
25
- return this.getContext('repo.project');
25
+ const repo = this.getContext('repo');
26
+ return repo.project;
26
27
  }
27
28
 
28
29
  getLatestVersion() {
@@ -1,5 +1,4 @@
1
- import _ from 'lodash';
2
- import { readJSON } from '../util.js';
1
+ import { pick, readJSON } from '../util.js';
3
2
  import GitBase from './GitBase.js';
4
3
 
5
4
  const defaultConfig = readJSON(new URL('../../config/release-it.json', import.meta.url));
@@ -12,7 +11,7 @@ class GitRelease extends GitBase {
12
11
  getInitialOptions(options) {
13
12
  const baseOptions = super.getInitialOptions(...arguments);
14
13
  const git = options.git || defaultConfig.git;
15
- const gitOptions = _.pick(git, [
14
+ const gitOptions = pick(git, [
16
15
  'tagExclude',
17
16
  'tagName',
18
17
  'tagMatch',
@@ -21,12 +20,13 @@ class GitRelease extends GitBase {
21
20
  'changelog',
22
21
  'commit'
23
22
  ]);
24
- return _.defaults(baseOptions, gitOptions);
23
+
24
+ return Object.assign({}, gitOptions, baseOptions);
25
25
  }
26
26
 
27
27
  get token() {
28
28
  const { tokenRef } = this.options;
29
- return _.get(process.env, tokenRef, null);
29
+ return process.env[tokenRef] || null;
30
30
  }
31
31
 
32
32
  async beforeRelease() {
@@ -1,5 +1,6 @@
1
1
  import { debug } from 'node:util';
2
- import _ from 'lodash';
2
+ import merge from 'lodash.merge';
3
+ import get from 'lodash.get';
3
4
 
4
5
  class Plugin {
5
6
  static isEnabled() {
@@ -40,12 +41,13 @@ class Plugin {
40
41
  afterRelease() {}
41
42
 
42
43
  getContext(path) {
43
- const context = _.merge({}, this.options, this.context);
44
- return path ? _.get(context, path) : context;
44
+ const context = merge({}, this.options, this.context);
45
+
46
+ return path ? get(context, path) : context;
45
47
  }
46
48
 
47
49
  setContext(context) {
48
- _.merge(this.context, context);
50
+ merge(this.context, context);
49
51
  }
50
52
 
51
53
  exec(command, { options, context = {} } = {}) {
@@ -2,7 +2,7 @@ import url from 'node:url';
2
2
  import path from 'node:path';
3
3
  import util from 'node:util';
4
4
  import { createRequire } from 'node:module';
5
- import _ from 'lodash';
5
+ import { castArray } from '../util.js';
6
6
  import Version from './version/Version.js';
7
7
  import Git from './git/Git.js';
8
8
  import GitLab from './gitlab/GitLab.js';
@@ -54,23 +54,23 @@ export const getPluginName = pluginName => {
54
54
  export let getPlugins = async (config, container) => {
55
55
  const context = config.getContext();
56
56
  const disabledPlugins = [];
57
-
58
- const enabledExternalPlugins = await _.reduce(
59
- context.plugins,
60
- async (result, pluginConfig, pluginName) => {
57
+ const enabledExternalPlugins = [];
58
+ if (context.plugins) {
59
+ for (const [pluginName, pluginConfig] of Object.entries(context.plugins)) {
61
60
  const [name, Plugin] = await load(pluginName);
62
61
  const [namespace, options] = pluginConfig.length === 2 ? pluginConfig : [name, pluginConfig];
62
+
63
63
  config.setContext({ [namespace]: options });
64
+
64
65
  if (await Plugin.isEnabled(options)) {
65
66
  const instance = new Plugin({ namespace, options: config.getContext(), container });
66
67
  debug({ namespace, options: instance.options });
67
- (await result).push(instance);
68
- disabledPlugins.push(..._.intersection(pluginNames, _.castArray(Plugin.disablePlugin(options))));
68
+ enabledExternalPlugins.push(instance);
69
+
70
+ disabledPlugins.push(...pluginNames.filter(p => castArray(Plugin.disablePlugin(options)).includes(p)));
69
71
  }
70
- return result;
71
- },
72
- []
73
- );
72
+ }
73
+ }
74
74
 
75
75
  const enabledPlugins = await pluginNames.reduce(async (result, plugin) => {
76
76
  if (plugin in plugins && !disabledPlugins.includes(plugin)) {
@@ -1,8 +1,7 @@
1
1
  import { EOL } from 'node:os';
2
- import _ from 'lodash';
3
2
  import { execa } from 'execa';
4
3
  import matcher from 'wildcard-match';
5
- import { format, e, fixArgs } from '../../util.js';
4
+ import { format, e, fixArgs, once, castArray } from '../../util.js';
6
5
  import GitBase from '../GitBase.js';
7
6
  import prompts from './prompts.js';
8
7
 
@@ -64,7 +63,7 @@ class Git extends GitBase {
64
63
  }
65
64
 
66
65
  enableRollback() {
67
- this.rollbackOnce = _.once(this.rollback.bind(this));
66
+ this.rollbackOnce = once(this.rollback.bind(this));
68
67
  process.on('SIGINT', this.rollbackOnce);
69
68
  process.on('exit', this.rollbackOnce);
70
69
  }
@@ -96,7 +95,7 @@ class Git extends GitBase {
96
95
 
97
96
  async isRequiredBranch() {
98
97
  const branch = await this.getBranchName();
99
- const requiredBranches = _.castArray(this.options.requireBranch);
98
+ const requiredBranches = castArray(this.options.requireBranch);
100
99
  const [branches, negated] = requiredBranches.reduce(
101
100
  ([p, n], b) => (b.startsWith('!') ? [p, [...n, b.slice(1)]] : [[...p, b], n]),
102
101
  [[], []]
@@ -151,7 +150,7 @@ class Git extends GitBase {
151
150
 
152
151
  stage(file) {
153
152
  if (!file || !file.length) return noop;
154
- const files = _.castArray(file);
153
+ const files = castArray(file);
155
154
  return this.exec(['git', 'add', ...files]).catch(err => {
156
155
  this.log.warn(`Could not stage ${files}`);
157
156
  this.debug(err);
@@ -164,7 +163,7 @@ class Git extends GitBase {
164
163
  }
165
164
 
166
165
  reset(file) {
167
- const files = _.castArray(file);
166
+ const files = castArray(file);
168
167
  return this.exec(['git', 'checkout', 'HEAD', '--', ...files]).catch(err => {
169
168
  this.log.warn(`Could not reset ${files}`);
170
169
  this.debug(err);
@@ -4,19 +4,14 @@ import open from 'open';
4
4
  import { Octokit } from '@octokit/rest';
5
5
  import { globby } from 'globby';
6
6
  import mime from 'mime-types';
7
- import _ from 'lodash';
8
7
  import retry from 'async-retry';
9
8
  import newGithubReleaseUrl from 'new-github-release-url';
10
9
  import { ProxyAgent } from 'proxy-agent';
11
- import { format, parseVersion, readJSON, e } from '../../util.js';
10
+ import { format, parseVersion, readJSON, e, castArray } from '../../util.js';
12
11
  import Release from '../GitRelease.js';
13
12
  import prompts from './prompts.js';
14
13
  import { getCommitsFromChangelog, getResolvedIssuesFromChangelog, searchQueries } from './util.js';
15
14
 
16
- /**
17
- * @typedef {import('@octokit/rest').RestEndpointMethodTypes['repos']['createRelease']['parameters']} CreateReleaseOptions
18
- */
19
-
20
15
  /**
21
16
  * @typedef {import('@octokit/rest').RestEndpointMethodTypes['repos']['createRelease']['parameters']} CreateReleaseOptions
22
17
  */
@@ -34,7 +29,7 @@ const parseErrormsg = err => {
34
29
  if (err instanceof Error) {
35
30
  const { status, message } = err;
36
31
  const headers = err.response ? err.response.headers : {};
37
- msg = `${_.get(headers, 'status', status)} (${message})`;
32
+ msg = `${headers?.status || status} (${message})`;
38
33
  }
39
34
  return msg;
40
35
  };
@@ -166,7 +161,7 @@ class GitHub extends Release {
166
161
  const githubError = new Error(message);
167
162
  this.log.verbose(err.errors);
168
163
  this.debug(err);
169
- if (!_.includes(RETRY_CODES, err.status)) {
164
+ if (!RETRY_CODES.includes(err.status)) {
170
165
  return bail(githubError);
171
166
  }
172
167
  throw githubError;
@@ -175,7 +170,8 @@ class GitHub extends Release {
175
170
  get client() {
176
171
  if (this._client) return this._client;
177
172
  const { proxy, timeout } = this.options;
178
- const host = this.options.host || this.getContext('repo.host');
173
+ const repo = this.getContext('repo');
174
+ const host = this.options.host || repo.host;
179
175
  const isGitHub = host === 'github.com';
180
176
  const baseUrl = `https://${isGitHub ? 'api.github.com' : host}${isGitHub ? '' : '/api/v3'}`;
181
177
  const options = {
@@ -226,6 +222,7 @@ class GitHub extends Release {
226
222
  const { isPreRelease } = parseVersion(version);
227
223
  const name = format(releaseName, this.config.getContext());
228
224
  const releaseNotesObject = this.options.releaseNotes;
225
+
229
226
  const body = autoGenerate
230
227
  ? isUpdate
231
228
  ? null
@@ -331,7 +328,7 @@ class GitHub extends Release {
331
328
  const context = this.config.getContext();
332
329
  const { isDryRun } = this.config;
333
330
 
334
- const patterns = _.castArray(assets).map(pattern => format(pattern, context));
331
+ const patterns = castArray(assets).map(pattern => format(pattern, context));
335
332
 
336
333
  this.log.exec('octokit repos.uploadReleaseAssets', patterns, { isDryRun });
337
334
 
@@ -356,9 +353,9 @@ class GitHub extends Release {
356
353
  }
357
354
 
358
355
  async generateWebUrl() {
359
- const host = this.options.host || this.getContext('repo.host');
356
+ const repo = this.getContext('repo');
357
+ const host = this.options.host || repo.host;
360
358
  const isGitHub = host === 'github.com';
361
-
362
359
  const options = await this.getOctokitReleaseOptions();
363
360
  const url = newGithubReleaseUrl({
364
361
  user: options.owner,
@@ -410,7 +407,7 @@ class GitHub extends Release {
410
407
 
411
408
  async commentOnResolvedItems() {
412
409
  const { isDryRun } = this.config;
413
- const { owner, project: repo } = this.getContext('repo');
410
+ const { host, owner, project: repo } = this.getContext('repo');
414
411
  const changelog = await this.getChangelog();
415
412
  const { comments } = this.options;
416
413
  const { submit, issue, pr } = comments ?? {};
@@ -422,13 +419,13 @@ class GitHub extends Release {
422
419
  const searchResults = await Promise.all(searchQueries(this.client, owner, repo, shas));
423
420
  const mergedPullRequests = searchResults.flatMap(items => items.map(item => ({ type: 'pr', number: item.number })));
424
421
 
425
- const host = 'https://' + (this.options.host || this.getContext('repo.host'));
426
- const resolvedIssues = getResolvedIssuesFromChangelog(host, owner, repo, changelog);
422
+ const hostURL = 'https://' + (this.options.host || host);
423
+ const resolvedIssues = getResolvedIssuesFromChangelog(hostURL, owner, repo, changelog);
427
424
 
428
425
  for (const item of [...resolvedIssues, ...mergedPullRequests]) {
429
426
  const { type, number } = item;
430
427
  const comment = format(format(type === 'pr' ? pr : issue, context), context);
431
- const url = `${host}/${owner}/${repo}/${type === 'pr' ? 'pull' : 'issues'}/${number}`;
428
+ const url = `${hostURL}/${owner}/${repo}/${type === 'pr' ? 'pull' : 'issues'}/${number}`;
432
429
 
433
430
  if (isDryRun) {
434
431
  this.log.exec(`octokit issues.createComment (${url})`, { isDryRun });
@@ -18,7 +18,7 @@ export const getSearchQueries = (base, commits, separator = '+') => {
18
18
 
19
19
  export const searchQueries = (client, owner, repo, shas) =>
20
20
  getSearchQueries(`repo:${owner}/${repo}+type:pr+is:merged`, shas).map(
21
- async q => (await client.search.issuesAndPullRequests({ q })).data.items
21
+ async q => (await client.search.issuesAndPullRequests({ q, advanced_search: true })).data.items
22
22
  );
23
23
 
24
24
  export const getCommitsFromChangelog = changelog => {
@@ -1,10 +1,9 @@
1
1
  import path from 'node:path';
2
2
  import fs, { promises } from 'node:fs'; // import fs here so it can be stubbed in tests
3
3
  import { globby } from 'globby';
4
- import _ from 'lodash';
5
4
  import { Agent } from 'undici';
6
5
  import Release from '../GitRelease.js';
7
- import { format, e } from '../../util.js';
6
+ import { format, e, castArray } from '../../util.js';
8
7
  import prompts from './prompts.js';
9
8
 
10
9
  const docs = 'https://git.io/release-it-gitlab';
@@ -16,7 +15,10 @@ class GitLab extends Release {
16
15
  super(...args);
17
16
  this.registerPrompts(prompts);
18
17
  this.assets = [];
19
- const { certificateAuthorityFile, secure } = this.options;
18
+ const { secure } = this.options;
19
+ const certificateAuthorityFileRef = this.options.certificateAuthorityFileRef || 'CI_SERVER_TLS_CA_FILE';
20
+ const certificateAuthorityFile =
21
+ this.options.certificateAuthorityFile || process.env[certificateAuthorityFileRef] || null;
20
22
  this.certificateAuthorityOption = {};
21
23
 
22
24
  const needsCustomAgent = Boolean(secure === false || certificateAuthorityFile);
@@ -309,7 +311,7 @@ class GitLab extends Release {
309
311
  const { isDryRun } = this.config;
310
312
  const context = this.config.getContext();
311
313
 
312
- const patterns = _.castArray(assets).map(pattern => format(pattern, context));
314
+ const patterns = castArray(assets).map(pattern => format(pattern, context));
313
315
 
314
316
  this.log.exec('gitlab releases#uploadAssets', patterns, { isDryRun });
315
317
 
@@ -256,6 +256,10 @@ class npm extends Plugin {
256
256
  })
257
257
  .catch(err => {
258
258
  this.debug(err);
259
+ if (this.config.isDryRun && /publish over the previously published version/.test(err)) {
260
+ return Promise.resolve();
261
+ }
262
+
259
263
  if (/one-time pass/.test(err)) {
260
264
  if (otp != null) {
261
265
  this.log.warn('The provided OTP is incorrect or has expired.');