release-it 15.0.0-esm.0 → 15.0.0-esm.4
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/README.md +13 -13
- package/bin/release-it.js +1 -1
- package/config/release-it.json +4 -1
- package/lib/cli.js +13 -1
- package/lib/config.js +2 -3
- package/lib/index.js +136 -10
- package/lib/plugin/GitBase.js +17 -16
- package/lib/plugin/factory.js +11 -5
- package/lib/plugin/git/Git.js +13 -6
- package/lib/plugin/git/prompts.js +1 -1
- package/lib/plugin/github/GitHub.js +60 -17
- package/lib/plugin/github/prompts.js +3 -3
- package/lib/plugin/gitlab/GitLab.js +3 -2
- package/lib/plugin/npm/npm.js +1 -1
- package/lib/plugin/version/Version.js +5 -5
- package/lib/shell.js +1 -1
- package/lib/spinner.js +3 -3
- package/package.json +34 -30
- package/test/config.js +2 -2
- package/test/git.init.js +26 -6
- package/test/git.js +2 -2
- package/test/github.js +127 -23
- package/test/plugins.js +27 -52
- package/test/prompt.js +1 -1
- package/test/spinner.js +7 -9
- package/test/stub/github.js +26 -10
- package/test/tasks.interactive.js +1 -1
- package/test/tasks.js +53 -10
- package/test/util/index.js +13 -18
- package/test/version.js +14 -9
- package/lib/tasks.js +0 -139
package/README.md
CHANGED
|
@@ -156,19 +156,18 @@ remote.
|
|
|
156
156
|
|
|
157
157
|
## GitHub Releases
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
GitHub projects can have releases attached to Git tags, containing release notes and assets. There are two ways to add
|
|
160
160
|
[GitHub releases](https://help.github.com/articles/creating-releases) in your release-it flow:
|
|
161
161
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
(release-it only needs "repo" access; no "admin" or other scopes).
|
|
165
|
-
- Make sure the token is [available as an environment variable](./docs/environment-variables.md).
|
|
162
|
+
1. Automated (requires a `GITHUB_TOKEN`)
|
|
163
|
+
2. Manual (using the GitHub web interface with pre-populated fields)
|
|
166
164
|
|
|
167
165
|
→ See [GitHub Releases](./docs/github-releases.md) for more details.
|
|
168
166
|
|
|
169
167
|
## GitLab Releases
|
|
170
168
|
|
|
171
|
-
|
|
169
|
+
GitLab projects can have releases attached to Git tags, containing release notes and assets. To automate
|
|
170
|
+
[GitLab releases](https://docs.gitlab.com/ce/user/project/releases/):
|
|
172
171
|
|
|
173
172
|
- Configure `gitlab.release: true`
|
|
174
173
|
- Obtain a [personal access token](https://gitlab.com/profile/personal_access_tokens) (release-it only needs the "api"
|
|
@@ -210,11 +209,11 @@ pre-releases. An example pre-release version is `2.0.0-beta.0`.
|
|
|
210
209
|
|
|
211
210
|
## Update or re-run existing releases
|
|
212
211
|
|
|
213
|
-
Use `--no-increment` to not increment the
|
|
212
|
+
Use `--no-increment` to not increment the last version, but update the last existing tag/version.
|
|
214
213
|
|
|
215
|
-
This may be helpful in
|
|
214
|
+
This may be helpful in cases where the version was already incremented. Here's a few example scenarios:
|
|
216
215
|
|
|
217
|
-
- To update or publish a draft GitHub Release for an existing Git tag.
|
|
216
|
+
- To update or publish a (draft) GitHub Release for an existing Git tag.
|
|
218
217
|
- Publishing to npm succeeded, but pushing the Git tag to the remote failed. Then use
|
|
219
218
|
`release-it --no-increment --no-npm` to skip the `npm publish` and try pushing the same Git tag again.
|
|
220
219
|
|
|
@@ -322,17 +321,18 @@ While mostly used as a CLI tool, release-it can be used as a dependency to integ
|
|
|
322
321
|
- [blockchain/blockchain-wallet-v4-frontend](https://github.com/blockchain/blockchain-wallet-v4-frontend)
|
|
323
322
|
- [callstack/linaria](https://github.com/callstack/linaria)
|
|
324
323
|
- [ember-cli/ember-cli](https://github.com/ember-cli/ember-cli)
|
|
325
|
-
|
|
324
|
+
- [metalsmith/metalsmith](https://github.com/metalsmith/metalsmith)
|
|
325
|
+
- [react-native-paper](https://github.com/callstack/react-native-paper)
|
|
326
326
|
- [js-cookie/js-cookie](https://github.com/js-cookie/js-cookie)
|
|
327
327
|
- [mirumee/saleor](https://github.com/mirumee/saleor)
|
|
328
328
|
- [mozilla/readability](https://github.com/mozilla/readability)
|
|
329
|
-
- [
|
|
329
|
+
- [redis/node-redis](https://github.com/redis/node-redis)
|
|
330
330
|
- [shipshapecode/shepherd](https://github.com/shipshapecode/shepherd)
|
|
331
331
|
- [swagger-api/swagger-ui](https://github.com/swagger-api/swagger-ui) +
|
|
332
332
|
[swagger-editor](https://github.com/swagger-api/swagger-editor)
|
|
333
333
|
- [StevenBlack/hosts](https://github.com/StevenBlack/hosts)
|
|
334
|
-
- [tabler](https://github.com/tabler/tabler) + [tabler-icons](https://github.com/tabler/tabler-icons)
|
|
335
|
-
- [youzan/vant](https://github.com/youzan/vant
|
|
334
|
+
- [tabler/tabler](https://github.com/tabler/tabler) + [tabler-icons](https://github.com/tabler/tabler-icons)
|
|
335
|
+
- [youzan/vant](https://github.com/youzan/vant)
|
|
336
336
|
- [Repositories that depend on release-it](https://github.com/release-it/release-it/network/dependents)
|
|
337
337
|
- GitHub search for [filename:.release-it.json](https://github.com/search?q=filename%3A.release-it.json)
|
|
338
338
|
|
package/bin/release-it.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import updater from 'update-notifier';
|
|
4
4
|
import parseArgs from 'yargs-parser';
|
|
5
|
-
import release from '../lib/
|
|
5
|
+
import release from '../lib/cli.js';
|
|
6
6
|
import { readJSON } from '../lib/util.js';
|
|
7
7
|
|
|
8
8
|
const pkg = readJSON(new URL('../package.json', import.meta.url));
|
package/config/release-it.json
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"commitArgs": [],
|
|
13
13
|
"tag": true,
|
|
14
14
|
"tagName": null,
|
|
15
|
+
"tagMatch": null,
|
|
15
16
|
"tagAnnotation": "Release ${version}",
|
|
16
17
|
"tagArgs": [],
|
|
17
18
|
"push": true,
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
"release": false,
|
|
33
34
|
"releaseName": "Release ${version}",
|
|
34
35
|
"releaseNotes": null,
|
|
36
|
+
"autoGenerate": false,
|
|
35
37
|
"preRelease": false,
|
|
36
38
|
"draft": false,
|
|
37
39
|
"tokenRef": "GITHUB_TOKEN",
|
|
@@ -39,7 +41,8 @@
|
|
|
39
41
|
"host": null,
|
|
40
42
|
"timeout": 0,
|
|
41
43
|
"proxy": null,
|
|
42
|
-
"skipChecks": false
|
|
44
|
+
"skipChecks": false,
|
|
45
|
+
"web": false
|
|
43
46
|
},
|
|
44
47
|
"gitlab": {
|
|
45
48
|
"release": false,
|
package/lib/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { readJSON } from '
|
|
1
|
+
import { readJSON } from './util.js';
|
|
2
2
|
import Log from './log.js';
|
|
3
|
+
import runTasks from './index.js';
|
|
3
4
|
|
|
4
5
|
const pkg = readJSON(new URL('../package.json', import.meta.url));
|
|
5
6
|
|
|
@@ -27,3 +28,14 @@ For more details, please see https://github.com/release-it/release-it`;
|
|
|
27
28
|
export let version = () => log.log(`v${pkg.version}`);
|
|
28
29
|
|
|
29
30
|
export let help = () => log.log(helpText);
|
|
31
|
+
|
|
32
|
+
export default async options => {
|
|
33
|
+
if (options.version) {
|
|
34
|
+
version();
|
|
35
|
+
} else if (options.help) {
|
|
36
|
+
help();
|
|
37
|
+
} else {
|
|
38
|
+
return runTasks(options);
|
|
39
|
+
}
|
|
40
|
+
return Promise.resolve();
|
|
41
|
+
};
|
package/lib/config.js
CHANGED
|
@@ -54,7 +54,6 @@ class Config {
|
|
|
54
54
|
|
|
55
55
|
expandPreReleaseShorthand(options) {
|
|
56
56
|
const { increment, preRelease, preReleaseId } = options;
|
|
57
|
-
options.isUpdate = increment === false;
|
|
58
57
|
options.version = {
|
|
59
58
|
increment,
|
|
60
59
|
isPreRelease: Boolean(preRelease),
|
|
@@ -97,8 +96,8 @@ class Config {
|
|
|
97
96
|
return Boolean(this.options['dry-run']);
|
|
98
97
|
}
|
|
99
98
|
|
|
100
|
-
get
|
|
101
|
-
return this.options.increment
|
|
99
|
+
get isIncrement() {
|
|
100
|
+
return this.options.increment !== false;
|
|
102
101
|
}
|
|
103
102
|
|
|
104
103
|
get isVerbose() {
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,142 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import { getPlugins } from './plugin/factory.js';
|
|
3
|
+
import Logger from './log.js';
|
|
4
|
+
import Config from './config.js';
|
|
5
|
+
import Shell from './shell.js';
|
|
6
|
+
import Prompt from './prompt.js';
|
|
7
|
+
import Spinner from './spinner.js';
|
|
8
|
+
import Metrics from './metrics.js';
|
|
9
|
+
import { reduceUntil, parseVersion } from './util.js';
|
|
10
|
+
import handleDeprecated from './deprecated.js';
|
|
3
11
|
import Plugin from './plugin/Plugin.js';
|
|
4
12
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
const runTasks = async (opts, di) => {
|
|
14
|
+
let container = {};
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
Object.assign(container, di);
|
|
18
|
+
container.config = container.config || new Config(opts);
|
|
19
|
+
|
|
20
|
+
const { config } = container;
|
|
21
|
+
const { isCI, isVerbose, verbosityLevel, isDryRun } = config;
|
|
22
|
+
|
|
23
|
+
container.log = container.log || new Logger({ isCI, isVerbose, verbosityLevel, isDryRun });
|
|
24
|
+
container.spinner = container.spinner || new Spinner({ container, config });
|
|
25
|
+
container.prompt = container.prompt || new Prompt({ container: { config } });
|
|
26
|
+
container.metrics = new Metrics({ isEnabled: config.isCollectMetrics });
|
|
27
|
+
container.shell = container.shell || new Shell({ container });
|
|
28
|
+
|
|
29
|
+
const { log, metrics, shell, spinner } = container;
|
|
30
|
+
|
|
31
|
+
const options = handleDeprecated(config.getContext(), log);
|
|
32
|
+
|
|
33
|
+
metrics.trackEvent('start', options);
|
|
34
|
+
|
|
35
|
+
const { hooks } = options;
|
|
36
|
+
|
|
37
|
+
const runHook = async (...name) => {
|
|
38
|
+
const scripts = hooks[name.join(':')];
|
|
39
|
+
if (!scripts || !scripts.length) return;
|
|
40
|
+
const context = config.getContext();
|
|
41
|
+
const external = true;
|
|
42
|
+
for (const script of _.castArray(scripts)) {
|
|
43
|
+
const task = () => shell.exec(script, { external }, context);
|
|
44
|
+
await spinner.show({ task, label: script, context, external });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const runLifeCycleHook = async (plugin, name, ...args) => {
|
|
49
|
+
if (plugin === _.first(plugins)) await runHook('before', name);
|
|
50
|
+
await runHook('before', plugin.namespace, name);
|
|
51
|
+
const willHookRun = (await plugin[name](...args)) !== false;
|
|
52
|
+
if (willHookRun) {
|
|
53
|
+
await runHook('after', plugin.namespace, name);
|
|
54
|
+
}
|
|
55
|
+
if (plugin === _.last(plugins)) await runHook('after', name);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const [internal, external] = await getPlugins(config, container);
|
|
59
|
+
let plugins = [...external, ...internal];
|
|
60
|
+
|
|
61
|
+
for (const plugin of plugins) {
|
|
62
|
+
await runLifeCycleHook(plugin, 'init');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const { increment, isPreRelease, preReleaseId } = options.version;
|
|
66
|
+
|
|
67
|
+
const name = await reduceUntil(plugins, plugin => plugin.getName());
|
|
68
|
+
const latestVersion = (await reduceUntil(plugins, plugin => plugin.getLatestVersion())) || '0.0.0';
|
|
69
|
+
const changelog = await reduceUntil(plugins, plugin => plugin.getChangelog(latestVersion));
|
|
70
|
+
|
|
71
|
+
const incrementBase = { latestVersion, increment, isPreRelease, preReleaseId };
|
|
72
|
+
|
|
73
|
+
let version;
|
|
74
|
+
if (config.isIncrement) {
|
|
75
|
+
incrementBase.increment = await reduceUntil(plugins, plugin => plugin.getIncrement(incrementBase));
|
|
76
|
+
version = await reduceUntil(plugins, plugin => plugin.getIncrementedVersionCI(incrementBase));
|
|
77
|
+
} else {
|
|
78
|
+
version = latestVersion;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (config.isReleaseVersion) {
|
|
82
|
+
log.log(version);
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
config.setContext({ name, latestVersion, version, changelog });
|
|
87
|
+
|
|
88
|
+
const action = config.isIncrement ? 'release' : 'update';
|
|
89
|
+
const suffix = version && config.isIncrement ? `${latestVersion}...${version}` : `currently at ${latestVersion}`;
|
|
90
|
+
|
|
91
|
+
log.obtrusive(`🚀 Let's ${action} ${name} (${suffix})`);
|
|
92
|
+
|
|
93
|
+
log.preview({ title: 'changelog', text: changelog });
|
|
94
|
+
|
|
95
|
+
if (config.isIncrement) {
|
|
96
|
+
version = version || (await reduceUntil(plugins, plugin => plugin.getIncrementedVersion(incrementBase)));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
config.setContext(parseVersion(version));
|
|
100
|
+
|
|
101
|
+
if (config.isPromptOnlyVersion) {
|
|
102
|
+
config.setCI(true);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const hook of ['beforeBump', 'bump', 'beforeRelease']) {
|
|
106
|
+
for (const plugin of plugins) {
|
|
107
|
+
const args = hook === 'bump' ? [version] : [];
|
|
108
|
+
await runLifeCycleHook(plugin, hook, ...args);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
plugins = [...internal, ...external];
|
|
113
|
+
|
|
114
|
+
for (const hook of ['release', 'afterRelease']) {
|
|
115
|
+
for (const plugin of plugins) {
|
|
116
|
+
await runLifeCycleHook(plugin, hook);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await metrics.trackEvent('end');
|
|
121
|
+
|
|
122
|
+
log.log(`🏁 Done (in ${Math.floor(process.uptime())}s.)`);
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
name,
|
|
126
|
+
changelog,
|
|
127
|
+
latestVersion,
|
|
128
|
+
version
|
|
129
|
+
};
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const { log, metrics } = container;
|
|
132
|
+
if (metrics) {
|
|
133
|
+
await metrics.trackException(err);
|
|
134
|
+
}
|
|
135
|
+
log ? log.error(err.message || err) : console.error(err); // eslint-disable-line no-console
|
|
136
|
+
throw err;
|
|
12
137
|
}
|
|
13
|
-
return Promise.resolve();
|
|
14
138
|
};
|
|
15
139
|
|
|
140
|
+
export default runTasks;
|
|
141
|
+
|
|
16
142
|
export { Plugin };
|
package/lib/plugin/GitBase.js
CHANGED
|
@@ -10,11 +10,11 @@ class GitBase extends Plugin {
|
|
|
10
10
|
this.remoteUrl = await this.getRemoteUrl();
|
|
11
11
|
await this.fetch();
|
|
12
12
|
const repo = parseGitUrl(this.remoteUrl);
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const tagTemplate = this.options.tagName || ((
|
|
16
|
-
this.setContext({ repo
|
|
17
|
-
this.config.setContext({ latestTag
|
|
13
|
+
const latestTag = await this.getLatestTagName(repo);
|
|
14
|
+
const secondLatestTag = !this.config.isIncrement ? await this.getSecondLatestTagName(latestTag) : null;
|
|
15
|
+
const tagTemplate = this.options.tagName || ((latestTag || '').match(/^v/) ? 'v${version}' : '${version}');
|
|
16
|
+
this.setContext({ repo });
|
|
17
|
+
this.config.setContext({ tagTemplate, latestTag, secondLatestTag });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
getName() {
|
|
@@ -22,19 +22,20 @@ class GitBase extends Plugin {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
getLatestVersion() {
|
|
25
|
-
const
|
|
26
|
-
|
|
25
|
+
const { tagTemplate, latestTag } = this.config.getContext();
|
|
26
|
+
const prefix = tagTemplate.replace(/\$\{version\}/, '');
|
|
27
|
+
return latestTag ? latestTag.replace(prefix, '').replace(/^v/, '') : null;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
async getChangelog() {
|
|
30
|
-
const {
|
|
31
|
-
const context = { latestTag
|
|
31
|
+
const { latestTag, secondLatestTag } = this.config.getContext();
|
|
32
|
+
const context = { latestTag, from: latestTag, to: 'HEAD' };
|
|
32
33
|
const { changelog } = this.options;
|
|
33
34
|
if (!changelog) return null;
|
|
34
35
|
|
|
35
|
-
if (
|
|
36
|
-
context.from =
|
|
37
|
-
context.to = `${
|
|
36
|
+
if (latestTag && !this.config.isIncrement) {
|
|
37
|
+
context.from = secondLatestTag;
|
|
38
|
+
context.to = `${latestTag}^1`;
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
if (!context.from && changelog.includes('${from}')) {
|
|
@@ -45,10 +46,10 @@ class GitBase extends Plugin {
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
bump(version) {
|
|
48
|
-
const { tagTemplate } = this.getContext();
|
|
49
|
+
const { tagTemplate } = this.config.getContext();
|
|
49
50
|
const context = Object.assign(this.config.getContext(), { version });
|
|
50
51
|
const tagName = format(tagTemplate, context) || version;
|
|
51
|
-
this.setContext({ version
|
|
52
|
+
this.setContext({ version });
|
|
52
53
|
this.config.setContext({ tagName });
|
|
53
54
|
}
|
|
54
55
|
|
|
@@ -87,7 +88,7 @@ class GitBase extends Plugin {
|
|
|
87
88
|
|
|
88
89
|
getLatestTagName(repo) {
|
|
89
90
|
const context = Object.assign({ repo }, this.getContext(), { version: '*' });
|
|
90
|
-
const match = format(this.options.tagName || '${version}', context);
|
|
91
|
+
const match = format(this.options.tagMatch || this.options.tagName || '${version}', context);
|
|
91
92
|
return this.exec(`git describe --tags --match=${match} --abbrev=0`, { options }).then(
|
|
92
93
|
stdout => stdout || null,
|
|
93
94
|
() => null
|
|
@@ -98,7 +99,7 @@ class GitBase extends Plugin {
|
|
|
98
99
|
const sha = await this.exec(`git rev-list ${latestTag || '--skip=1'} --tags --max-count=1`, {
|
|
99
100
|
options
|
|
100
101
|
});
|
|
101
|
-
return this.exec(`git describe --tags --abbrev=0 ${sha}`, { options }).catch(() => null);
|
|
102
|
+
return this.exec(`git describe --tags --abbrev=0 "${sha}^"`, { options }).catch(() => null);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
|
package/lib/plugin/factory.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import url from 'url';
|
|
1
2
|
import path from 'path';
|
|
2
3
|
import { createRequire } from 'module';
|
|
3
4
|
import _ from 'lodash';
|
|
@@ -8,8 +9,6 @@ import GitLab from './gitlab/GitLab.js';
|
|
|
8
9
|
import GitHub from './github/GitHub.js';
|
|
9
10
|
import npm from './npm/npm.js';
|
|
10
11
|
|
|
11
|
-
const require = createRequire(import.meta.url);
|
|
12
|
-
|
|
13
12
|
const debug = _debug('release-it:plugins');
|
|
14
13
|
|
|
15
14
|
const pluginNames = ['npm', 'git', 'github', 'gitlab', 'version'];
|
|
@@ -25,11 +24,18 @@ const plugins = {
|
|
|
25
24
|
const load = async pluginName => {
|
|
26
25
|
let plugin = null;
|
|
27
26
|
try {
|
|
28
|
-
const module = await import(
|
|
27
|
+
const module = await import(pluginName);
|
|
29
28
|
plugin = module.default;
|
|
30
29
|
} catch (err) {
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
try {
|
|
31
|
+
const module = await import(path.join(process.cwd(), pluginName));
|
|
32
|
+
plugin = module.default;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
// In some cases or tests we might need to support legacy `require.resolve`
|
|
35
|
+
const require = createRequire(process.cwd());
|
|
36
|
+
const module = await import(url.pathToFileURL(require.resolve(pluginName, { paths: [process.cwd()] })));
|
|
37
|
+
plugin = module.default;
|
|
38
|
+
}
|
|
33
39
|
}
|
|
34
40
|
return [path.parse(pluginName).name, plugin];
|
|
35
41
|
};
|
package/lib/plugin/git/Git.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EOL } from 'os';
|
|
2
2
|
import _ from 'lodash';
|
|
3
|
-
import
|
|
3
|
+
import { execa } from 'execa';
|
|
4
4
|
import { format, e } from '../../util.js';
|
|
5
5
|
import GitBase from '../GitBase.js';
|
|
6
6
|
import prompts from './prompts.js';
|
|
@@ -12,6 +12,12 @@ const fixArgs = args => (args ? (typeof args === 'string' ? args.split(' ') : ar
|
|
|
12
12
|
|
|
13
13
|
const docs = 'https://git.io/release-it-git';
|
|
14
14
|
|
|
15
|
+
const isGitRepo = () =>
|
|
16
|
+
execa('git', ['rev-parse', '--git-dir']).then(
|
|
17
|
+
() => true,
|
|
18
|
+
() => false
|
|
19
|
+
);
|
|
20
|
+
|
|
15
21
|
class Git extends GitBase {
|
|
16
22
|
constructor(...args) {
|
|
17
23
|
super(...args);
|
|
@@ -19,7 +25,7 @@ class Git extends GitBase {
|
|
|
19
25
|
}
|
|
20
26
|
|
|
21
27
|
static async isEnabled(options) {
|
|
22
|
-
return options !== false && (await
|
|
28
|
+
return options !== false && (await isGitRepo());
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
async init() {
|
|
@@ -46,7 +52,8 @@ class Git extends GitBase {
|
|
|
46
52
|
|
|
47
53
|
rollback() {
|
|
48
54
|
this.log.info('Rolling back changes...');
|
|
49
|
-
const {
|
|
55
|
+
const { tagName } = this.config.getContext();
|
|
56
|
+
const { isCommitted, isTagged } = this.getContext();
|
|
50
57
|
if (isTagged) {
|
|
51
58
|
this.exec(`git tag --delete ${tagName}`);
|
|
52
59
|
}
|
|
@@ -175,12 +182,12 @@ class Git extends GitBase {
|
|
|
175
182
|
|
|
176
183
|
tag({ name, annotation = this.options.tagAnnotation, args = this.options.tagArgs } = {}) {
|
|
177
184
|
const message = format(annotation, this.config.getContext());
|
|
178
|
-
const tagName = name || this.getContext('tagName');
|
|
185
|
+
const tagName = name || this.config.getContext('tagName');
|
|
179
186
|
return this.exec(['git', 'tag', '--annotate', '--message', message, ...fixArgs(args), tagName])
|
|
180
187
|
.then(() => this.setContext({ isTagged: true }))
|
|
181
188
|
.catch(err => {
|
|
182
|
-
const {
|
|
183
|
-
if (/tag '.+' already exists/.test(err) &&
|
|
189
|
+
const { latestTag, tagName } = this.config.getContext();
|
|
190
|
+
if (/tag '.+' already exists/.test(err) && latestTag === tagName) {
|
|
184
191
|
this.log.warn(`Tag "${tagName}" already exists`);
|
|
185
192
|
} else {
|
|
186
193
|
throw err;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import open from 'open';
|
|
3
4
|
import { Octokit } from '@octokit/rest';
|
|
4
|
-
import globby from 'globby';
|
|
5
|
+
import { globby } from 'globby';
|
|
5
6
|
import mime from 'mime-types';
|
|
6
7
|
import _ from 'lodash';
|
|
7
8
|
import retry from 'async-retry';
|
|
9
|
+
import newGithubReleaseUrl from 'new-github-release-url';
|
|
8
10
|
import { format, parseVersion, readJSON, e } from '../../util.js';
|
|
9
11
|
import Release from '../GitRelease.js';
|
|
10
12
|
import prompts from './prompts.js';
|
|
@@ -21,7 +23,7 @@ const parseErrormsg = err => {
|
|
|
21
23
|
let msg = err;
|
|
22
24
|
if (err instanceof Error) {
|
|
23
25
|
const { status, message } = err;
|
|
24
|
-
const
|
|
26
|
+
const headers = err.response ? err.response.headers : {};
|
|
25
27
|
msg = `${_.get(headers, 'status', status)} (${message})`;
|
|
26
28
|
}
|
|
27
29
|
return msg;
|
|
@@ -36,14 +38,22 @@ class GitHub extends Release {
|
|
|
36
38
|
async init() {
|
|
37
39
|
await super.init();
|
|
38
40
|
|
|
39
|
-
const { skipChecks, tokenRef } = this.options;
|
|
40
|
-
const { isUpdate } = this.config;
|
|
41
|
+
const { skipChecks, tokenRef, web, update, assets } = this.options;
|
|
41
42
|
|
|
42
|
-
if (!
|
|
43
|
-
if (!
|
|
44
|
-
|
|
43
|
+
if (!this.token || web) {
|
|
44
|
+
if (!web) {
|
|
45
|
+
this.log.warn(`Environment variable "${tokenRef}" is required for automated GitHub Releases.`);
|
|
46
|
+
this.log.warn('Falling back to web-based GitHub Release.');
|
|
45
47
|
}
|
|
48
|
+
this.setContext({ isWeb: true });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
46
51
|
|
|
52
|
+
if (web && assets) {
|
|
53
|
+
this.log.warn('Assets are not included in web-based releases.');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!skipChecks) {
|
|
47
57
|
// If we're running on GitHub Actions, we can skip the authentication and
|
|
48
58
|
// collaborator checks. Ref: https://bit.ly/2vsyRzu
|
|
49
59
|
if (process.env.GITHUB_ACTIONS) {
|
|
@@ -61,11 +71,11 @@ class GitHub extends Release {
|
|
|
61
71
|
}
|
|
62
72
|
}
|
|
63
73
|
|
|
64
|
-
if (
|
|
65
|
-
const {
|
|
74
|
+
if (update) {
|
|
75
|
+
const { latestTag } = this.config.getContext();
|
|
66
76
|
try {
|
|
67
77
|
const { id, upload_url, tag_name } = await this.getLatestRelease();
|
|
68
|
-
if (
|
|
78
|
+
if (latestTag === tag_name) {
|
|
69
79
|
this.setContext({ isUpdate: true, isReleased: true, releaseId: id, upload_url });
|
|
70
80
|
} else {
|
|
71
81
|
this.setContext({ isUpdate: false });
|
|
@@ -74,7 +84,7 @@ class GitHub extends Release {
|
|
|
74
84
|
this.setContext({ isUpdate: false });
|
|
75
85
|
}
|
|
76
86
|
if (!this.getContext('isUpdate')) {
|
|
77
|
-
this.log.warn(`GitHub release for tag ${
|
|
87
|
+
this.log.warn(`GitHub release for tag ${latestTag} was not found. Creating new release.`);
|
|
78
88
|
}
|
|
79
89
|
}
|
|
80
90
|
}
|
|
@@ -109,13 +119,16 @@ class GitHub extends Release {
|
|
|
109
119
|
|
|
110
120
|
async release() {
|
|
111
121
|
const { assets } = this.options;
|
|
112
|
-
const { isUpdate } = this.getContext();
|
|
122
|
+
const { isWeb, isUpdate } = this.getContext();
|
|
113
123
|
const { isCI } = this.config;
|
|
114
124
|
|
|
115
125
|
const type = isUpdate ? 'update' : 'create';
|
|
116
126
|
const publishMethod = `${type}Release`;
|
|
117
127
|
|
|
118
|
-
if (
|
|
128
|
+
if (isWeb) {
|
|
129
|
+
const task = () => this.createWebRelease();
|
|
130
|
+
return this.step({ task, label: 'Generating link to GitHub Release web interface', prompt: 'release' });
|
|
131
|
+
} else if (isCI) {
|
|
119
132
|
await this.step({ task: () => this[publishMethod](), label: `GitHub ${type} release` });
|
|
120
133
|
return this.step({ enabled: assets, task: () => this.uploadAssets(), label: 'GitHub upload assets' });
|
|
121
134
|
} else {
|
|
@@ -179,11 +192,12 @@ class GitHub extends Release {
|
|
|
179
192
|
|
|
180
193
|
getOctokitReleaseOptions(options = {}) {
|
|
181
194
|
const { owner, project: repo } = this.getContext('repo');
|
|
182
|
-
const { releaseName, draft = false, preRelease = false } = this.options;
|
|
183
|
-
const {
|
|
195
|
+
const { releaseName, draft = false, preRelease = false, autoGenerate = false } = this.options;
|
|
196
|
+
const { tagName } = this.config.getContext();
|
|
197
|
+
const { version, releaseNotes } = this.getContext();
|
|
184
198
|
const { isPreRelease } = parseVersion(version);
|
|
185
199
|
const name = format(releaseName, this.config.getContext());
|
|
186
|
-
const body = releaseNotes;
|
|
200
|
+
const body = autoGenerate ? '' : releaseNotes || '';
|
|
187
201
|
|
|
188
202
|
return Object.assign(options, {
|
|
189
203
|
owner,
|
|
@@ -192,7 +206,8 @@ class GitHub extends Release {
|
|
|
192
206
|
name,
|
|
193
207
|
body,
|
|
194
208
|
draft,
|
|
195
|
-
prerelease: isPreRelease || preRelease
|
|
209
|
+
prerelease: isPreRelease || preRelease,
|
|
210
|
+
generate_release_notes: autoGenerate
|
|
196
211
|
});
|
|
197
212
|
}
|
|
198
213
|
|
|
@@ -285,6 +300,34 @@ class GitHub extends Release {
|
|
|
285
300
|
return `https://${host}/${repository}/releases/tag/${tagName}`;
|
|
286
301
|
}
|
|
287
302
|
|
|
303
|
+
generateWebUrl() {
|
|
304
|
+
const host = this.options.host || this.getContext('repo.host');
|
|
305
|
+
const isGitHub = host === 'github.com';
|
|
306
|
+
|
|
307
|
+
const options = this.getOctokitReleaseOptions();
|
|
308
|
+
const url = newGithubReleaseUrl({
|
|
309
|
+
user: options.owner,
|
|
310
|
+
repo: options.repo,
|
|
311
|
+
tag: options.tag_name,
|
|
312
|
+
isPrerelease: options.prerelease,
|
|
313
|
+
title: options.name,
|
|
314
|
+
body: options.body
|
|
315
|
+
});
|
|
316
|
+
return isGitHub ? url : url.replace('github.com', host);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async createWebRelease() {
|
|
320
|
+
const { isCI } = this.config;
|
|
321
|
+
const { tagName } = this.config.getContext();
|
|
322
|
+
const url = this.generateWebUrl();
|
|
323
|
+
if (isCI) {
|
|
324
|
+
this.setContext({ isReleased: true, releaseUrl: url });
|
|
325
|
+
} else {
|
|
326
|
+
await open(url);
|
|
327
|
+
this.setContext({ isReleased: true, releaseUrl: this.getReleaseUrlFallback(tagName) });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
288
331
|
updateRelease() {
|
|
289
332
|
const { isDryRun } = this.config;
|
|
290
333
|
const release_id = this.getContext('releaseId');
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { format } from '../../util.js';
|
|
2
2
|
|
|
3
3
|
const message = context => {
|
|
4
|
-
const { isPreRelease,
|
|
5
|
-
const { releaseName } = github;
|
|
4
|
+
const { isPreRelease, github } = context;
|
|
5
|
+
const { releaseName, update } = github;
|
|
6
6
|
const name = format(releaseName, context);
|
|
7
|
-
return `${
|
|
7
|
+
return `${update ? 'Update' : 'Create a'} ${isPreRelease ? 'pre-' : ''}release on GitHub (${name})?`;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
export default {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import got from 'got';
|
|
4
|
-
import globby from 'globby';
|
|
4
|
+
import { globby } from 'globby';
|
|
5
5
|
import FormData from 'form-data';
|
|
6
6
|
import _ from 'lodash';
|
|
7
7
|
import Release from '../GitRelease.js';
|
|
@@ -132,7 +132,8 @@ class GitLab extends Release {
|
|
|
132
132
|
|
|
133
133
|
async createRelease() {
|
|
134
134
|
const { releaseName } = this.options;
|
|
135
|
-
const {
|
|
135
|
+
const { tagName } = this.config.getContext();
|
|
136
|
+
const { id, releaseNotes, repo, origin } = this.getContext();
|
|
136
137
|
const { isDryRun } = this.config;
|
|
137
138
|
const name = format(releaseName, this.config.getContext());
|
|
138
139
|
const description = releaseNotes || '-';
|
package/lib/plugin/npm/npm.js
CHANGED
|
@@ -80,7 +80,7 @@ class npm extends Plugin {
|
|
|
80
80
|
const tag = this.options.tag || (await this.resolveTag(version));
|
|
81
81
|
this.setContext({ version, tag });
|
|
82
82
|
|
|
83
|
-
if (this.config.
|
|
83
|
+
if (!this.config.isIncrement) return false;
|
|
84
84
|
|
|
85
85
|
const task = () => this.exec(`npm version ${version} --no-git-tag-version`);
|
|
86
86
|
return this.spinner.show({ task, label: 'npm version' });
|