-
Notifications
You must be signed in to change notification settings - Fork 535
/
version.ts
211 lines (181 loc) · 5.69 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/
import { Args, Command, Flags } from "@oclif/core";
import * as semver from "semver";
import { table } from "table";
import { isVersionBumpTypeExtended } from "../bumpTypes";
import {
MINIMUM_PUBLIC_VERSION,
bumpInternalVersion,
fromInternalScheme,
getVersionRange,
isInternalVersionScheme,
toInternalScheme,
} from "../internalVersionScheme";
interface VersionScheme {
internalSchemeVersion: string;
internalVersion: string;
publicVersion: string;
minorRange: string;
patchRange: string;
caretRange: string;
tildeRange: string;
}
interface VersionInfo {
input: string;
bumpType: string;
original: VersionScheme;
bumped: VersionScheme;
}
/**
* The root `version` command.
*/
// eslint-disable-next-line import/no-default-export
export default class VersionCommand extends Command {
static readonly description =
"Convert version strings between regular semver and the Fluid internal version scheme.";
static readonly enableJsonFlag = true;
static readonly flags = {
type: Flags.string({
char: "t",
description: "bump type",
options: ["major", "minor", "patch", "current"],
required: false,
}),
publicVersion: Flags.string({
default: MINIMUM_PUBLIC_VERSION,
description: "The public version to use in the Fluid internal version.",
}),
} as const;
static readonly args = {
version: Args.string({
description: "The version to convert.",
name: "version",
required: true,
}),
} as const;
static readonly examples = [
{
description: "The version can be a Fluid internal version.",
command: "<%= config.bin %> <%= command.id %> 2.0.0-internal.1.0.0 --type minor",
},
{
description: "The version can also be a semver with a bump type.",
command: "<%= config.bin %> <%= command.id %> 1.0.0 --type minor",
},
{
description: "If needed, you can provide a public version to override the default.",
command: "<%= config.bin %> <%= command.id %> 1.0.0 --type patch --publicVersion 3.1.0",
},
{
description: "You can use ^ and ~ as a shorthand.",
command: "<%= config.bin %> <%= command.id %> ^1.0.0",
},
{
description:
"You can use the 'current' bump type to calculate ranges without bumping the version.",
command: "<%= config.bin %> <%= command.id %> 2.0.0-internal.1.0.0 --type current",
},
];
async run(): Promise<VersionInfo> {
const { args, flags } = await this.parse(VersionCommand);
const versionArg = await this.parseVersionArgument(args.version);
const bumpType = flags.type ?? versionArg.bumpType ?? "";
if (!isVersionBumpTypeExtended(bumpType)) {
this.error(`Need a bump type`);
}
const { parsedVersion, isFluidInternalFormat } = versionArg;
const originalVersion = isFluidInternalFormat
? parsedVersion
: toInternalScheme(flags.publicVersion, parsedVersion);
let bumpedVersion: semver.SemVer;
switch (bumpType) {
case "patch":
case "minor":
case "major": {
bumpedVersion = bumpInternalVersion(originalVersion, bumpType);
break;
}
case "current": {
bumpedVersion = originalVersion;
break;
}
default: {
this.error(`Unsupported bump type: ${bumpType}`);
}
}
const makeScheme = (v: semver.SemVer): VersionScheme => {
const [publicVersion, internalVersion] = fromInternalScheme(v);
const patchRange = getVersionRange(v, "patch");
const minorRange = getVersionRange(v, "minor");
const scheme: VersionScheme = {
internalSchemeVersion: v.format(),
internalVersion: internalVersion.format(),
publicVersion: publicVersion.format(),
minorRange,
patchRange,
caretRange: minorRange,
tildeRange: patchRange,
};
return scheme;
};
const original = makeScheme(originalVersion);
const bumped = makeScheme(bumpedVersion);
const data: VersionInfo = {
input: args.version,
bumpType,
original,
bumped,
};
this.log(`Input string: ${data.input}`);
this.log(`Bump type: ${data.bumpType}`);
this.log(`\nORIGINAL (${data.original.internalVersion})`);
this.log(tablify(data.original));
if (bumpType !== "current") {
this.log(`\nBUMPED to ${data.bumped.internalSchemeVersion} (${data.bumpType})`);
this.log(tablify(data.bumped));
}
// When the --json flag is passed, the command will return the raw data as JSON.
return data;
}
/**
* Parses a CLI input string as a version. The st
*
* @param versionString - A version string in either standard semver or Fluid internal format. If the string begins
* with a "~" or "^", then the bump type will be set accordingly.
* @returns An object containing the parsed bump type, parsed version, and a boolean indicating whether the parsed
* version is in the Fluid internal format or not.
*/
async parseVersionArgument(versionString: string): Promise<ParsedVersion> {
const input = versionString;
let parsedInput = versionString;
let bumpType: string | undefined;
// Infer the bump type from the ^ and ~
if (input.startsWith("^") || input.startsWith("~")) {
bumpType = input.startsWith("^") ? "minor" : "patch";
parsedInput = input.slice(1);
}
const parsedVersion = semver.parse(parsedInput);
if (parsedVersion === null) {
this.error(`The version you provided isn't valid: "${parsedInput}"`);
}
return {
bumpType,
parsedVersion,
isFluidInternalFormat: isInternalVersionScheme(parsedVersion) === true,
};
}
}
function tablify(scheme: VersionScheme): string {
return table(Object.entries(scheme), {
columns: [{ alignment: "left" }, { alignment: "left" }, { alignment: "left" }],
singleLine: true,
});
}
interface ParsedVersion {
bumpType?: string;
parsedVersion: semver.SemVer;
isFluidInternalFormat: boolean;
}