-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
version.ts
140 lines (116 loc) Β· 5.02 KB
/
version.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import {BaseCommand, WorkspaceRequiredError} from '@yarnpkg/cli';
import {Configuration, Project} from '@yarnpkg/core';
import {Command, UsageError} from 'clipanion';
import semver from 'semver';
import * as yup from 'yup';
// This is a special strategy; Yarn won't change the semver version,
// but will change the nonce. This will cause `yarn version check` to
// stop reporting the package as having no explicit bump strategy.
const DECLINE = `decline`;
const STRATEGIES = new Set([
`major`,
`minor`,
`patch`,
`premajor`,
`preminor`,
`prepatch`,
`prerelease`,
DECLINE,
]);
// eslint-disable-next-line arca/no-default-export
export default class VersionCommand extends BaseCommand {
@Command.String()
strategy!: string;
@Command.Boolean(`-d,--deferred`)
deferred?: boolean;
@Command.Boolean(`-i,--immediate`)
immediate?: boolean;
@Command.Boolean(`-f,--force`)
force: boolean = false;
static schema = yup.object().shape({
strategy: yup.string().test({
name: `strategy`,
message: '${path} must be a semver range or one of ${strategies}',
params: {strategies: Array.from(STRATEGIES).join(`, `)},
test: (range: string) => {
return semver.valid(range) !== null || STRATEGIES.has(range);
},
}),
});
static usage = Command.Usage({
category: `Release-related commands`,
description: `apply a new version to the current package`,
details: `
This command will bump the version number for the given package, following the specified strategy:
- If \`major\`, the first number from the semver range will be increased (\`X.0.0\`).
- If \`minor\`, the second number from the semver range will be increased (\`0.X.0\`).
- If \`patch\`, the third number from the semver range will be increased (\`0.0.X\`).
- If prefixed by \`pre\` (\`premajor\`, ...), a \`-0\` suffix will be set (\`0.0.0-0\`).
- If \`prerelease\`, the suffix will be increased (\`0.0.0-X\`); the third number from the semver range will also be increased if there was no suffix in the previous version.
- If \`decline\`, the nonce will be increased for \`yarn version check\` to pass without version bump.
- If a valid semver range, it will be used as new version.
- If unspecified, Yarn will ask you for guidance.
For more information about the \`--deferred\` flag, consult our documentation ("Managing Releases").
`,
examples: [[
`Immediatly bump the version to the next major`,
`yarn version major`,
], [
`Prepare the version to be bumped to the next major`,
`yarn version major --deferred`,
]],
});
@Command.Path(`version`)
async execute() {
const configuration = await Configuration.find(this.context.cwd, this.context.plugins);
const {workspace} = await Project.find(configuration, this.context.cwd);
if (!workspace)
throw new WorkspaceRequiredError(this.context.cwd);
let deferred = configuration.get(`preferDeferredVersions`);
if (this.deferred)
deferred = true;
if (this.immediate)
deferred = false;
const isSemver = semver.valid(this.strategy);
const isDeclined = this.strategy === DECLINE;
let nextVersion: string | null;
if (isSemver) {
nextVersion = this.strategy;
} else {
let currentVersion = workspace.manifest.version;
if (!isDeclined) {
if (currentVersion === null)
throw new UsageError(`Can't bump the version if there wasn't a version to begin with - use 0.0.0 as initial version then run the command again.`);
if (typeof currentVersion !== `string` || !semver.valid(currentVersion)) {
throw new UsageError(`Can't bump the version (${currentVersion}) if it's not valid semver`);
}
}
const bumpedVersion = !isDeclined
? semver.inc(currentVersion!, this.strategy as any)
: currentVersion;
if (!isDeclined && bumpedVersion === null)
throw new Error(`Assertion failed: Failed to increment the version number (${currentVersion})`);
nextVersion = bumpedVersion;
}
if (workspace.manifest.raw.nextVersion) {
const deferredVersion = workspace.manifest.raw.nextVersion.semver as string | undefined;
if (typeof deferredVersion !== `undefined`) {
if (!isDeclined) {
if (semver.gt(deferredVersion, nextVersion!) && !this.force) {
throw new UsageError(`The target version (${nextVersion}) is smaller than the one currently registered (${deferredVersion}); use -f,--force to overwrite.`);
}
} else {
nextVersion = deferredVersion;
}
}
}
workspace.manifest.setRawField(`nextVersion`, {
semver: nextVersion !== workspace.manifest.version ? nextVersion : undefined,
nonce: String(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER)),
}, {after: [`version`]});
await workspace.persistManifest();
if (!deferred) {
await this.cli.run([`version`, `apply`]);
}
}
}