1/** 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * 4 * This source code is licensed under the MIT license found in the 5 * LICENSE file in the root directory of this source tree. 6 * 7 * @format 8 */ 9 10const { 11 parseVersion, 12 isReleaseBranch, 13 validateBuildType, 14} = require('../version-utils'); 15 16let execResult = null; 17jest.mock('shelljs', () => ({ 18 exec: () => { 19 return { 20 stdout: execResult, 21 }; 22 }, 23 echo: message => { 24 console.log(message); 25 }, 26 exit: exitCode => { 27 exit(exitCode); 28 }, 29})); 30 31describe('version-utils', () => { 32 describe('isReleaseBranch', () => { 33 it('should identify as release branch', () => { 34 expect(isReleaseBranch('v0.66-stable')).toBe(true); 35 expect(isReleaseBranch('0.66-stable')).toBe(true); 36 expect(isReleaseBranch('made-up-stuff-stable')).toBe(true); 37 }); 38 it('should not identify as release branch', () => { 39 expect(isReleaseBranch('main')).toBe(false); 40 expect(isReleaseBranch('pull/32659')).toBe(false); 41 }); 42 }); 43 44 describe('parseVersion', () => { 45 it('should throw error if buildType is undefined', () => { 46 function testInvalidVersion() { 47 parseVersion('v0.10.5'); 48 } 49 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 50 `"Unsupported build type: undefined"`, 51 ); 52 }); 53 54 it('should throw error if buildType is not `release`, `dry-run` or `nightly`', () => { 55 function testInvalidVersion() { 56 parseVersion('v0.10.5', 'invalid_build_type'); 57 } 58 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 59 `"Unsupported build type: invalid_build_type"`, 60 ); 61 }); 62 it('should throw error if invalid match with release', () => { 63 function testInvalidVersion() { 64 parseVersion('<invalid version>', 'release'); 65 } 66 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 67 `"You must pass a correctly formatted version; couldn't parse <invalid version>"`, 68 ); 69 }); 70 it('should throw error if invalid match with dry-run', () => { 71 function testInvalidVersion() { 72 parseVersion('<invalid version>', 'dry-run'); 73 } 74 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 75 `"You must pass a correctly formatted version; couldn't parse <invalid version>"`, 76 ); 77 }); 78 it('should throw error if invalid match with nightly', () => { 79 function testInvalidVersion() { 80 parseVersion('<invalid version>', 'nightly'); 81 } 82 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 83 `"You must pass a correctly formatted version; couldn't parse <invalid version>"`, 84 ); 85 }); 86 87 it('should parse pre-release version with release and `.`', () => { 88 const {version, major, minor, patch, prerelease} = parseVersion( 89 '0.66.0-rc.4', 90 'release', 91 ); 92 expect(version).toBe('0.66.0-rc.4'); 93 expect(major).toBe('0'); 94 expect(minor).toBe('66'); 95 expect(patch).toBe('0'); 96 expect(prerelease).toBe('rc.4'); 97 }); 98 99 it('should parse pre-release version with release and `-`', () => { 100 const {version, major, minor, patch, prerelease} = parseVersion( 101 '0.66.0-rc-4', 102 'release', 103 ); 104 expect(version).toBe('0.66.0-rc-4'); 105 expect(major).toBe('0'); 106 expect(minor).toBe('66'); 107 expect(patch).toBe('0'); 108 expect(prerelease).toBe('rc-4'); 109 }); 110 111 it('should reject pre-release version with random prerelease pattern', () => { 112 function testInvalidVersion() { 113 parseVersion('0.66.0-something_invalid', 'release'); 114 } 115 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 116 `"Version 0.66.0-something_invalid is not valid for Release"`, 117 ); 118 }); 119 120 it('should parse stable version', () => { 121 const {version, major, minor, patch, prerelease} = parseVersion( 122 '0.66.0', 123 'release', 124 ); 125 expect(version).toBe('0.66.0'); 126 expect(major).toBe('0'); 127 expect(minor).toBe('66'); 128 expect(patch).toBe('0'); 129 expect(prerelease).toBeUndefined(); 130 }); 131 132 it('should parse pre-release version from tag', () => { 133 const {version, major, minor, patch, prerelease} = parseVersion( 134 'v0.66.0-rc.4', 135 'release', 136 ); 137 expect(version).toBe('0.66.0-rc.4'); 138 expect(major).toBe('0'); 139 expect(minor).toBe('66'); 140 expect(patch).toBe('0'); 141 expect(prerelease).toBe('rc.4'); 142 }); 143 144 it('should reject pre-release version from tag with random prerelease pattern', () => { 145 function testInvalidVersion() { 146 parseVersion('v0.66.0-something_invalid', 'release'); 147 } 148 expect(testInvalidVersion).toThrowErrorMatchingInlineSnapshot( 149 `"Version 0.66.0-something_invalid is not valid for Release"`, 150 ); 151 }); 152 153 it('should parse stable version from tag', () => { 154 const {version, major, minor, patch, prerelease} = parseVersion( 155 'v0.66.0', 156 'release', 157 ); 158 expect(version).toBe('0.66.0'); 159 expect(major).toBe('0'); 160 expect(minor).toBe('66'); 161 expect(patch).toBe('0'); 162 expect(prerelease).toBeUndefined(); 163 }); 164 165 it('should reject nightly with no prerelease', () => { 166 // this should fail 167 function testInvalidFunction() { 168 parseVersion('0.0.0', 'nightly'); 169 } 170 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 171 `"Version 0.0.0 is not valid for nightlies"`, 172 ); 173 }); 174 175 it('should reject nightly with prerelease but wrong version numbers', () => { 176 // this should fail 177 function testInvalidFunction() { 178 parseVersion('1.2.3-pre-release', 'nightly'); 179 } 180 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 181 `"Version 1.2.3-pre-release is not valid for nightlies"`, 182 ); 183 }); 184 185 it('should parse nightly with 0.0.0 and a prerelease part', () => { 186 // this should fail 187 const {version, major, minor, patch, prerelease} = parseVersion( 188 '0.0.0-pre-release', 189 'nightly', 190 ); 191 192 expect(version).toBe('0.0.0-pre-release'); 193 expect(major).toBe('0'); 194 expect(minor).toBe('0'); 195 expect(patch).toBe('0'); 196 expect(prerelease).toBe('pre-release'); 197 }); 198 it('should parse dryrun with release version', () => { 199 const {version, major, minor, patch, prerelease} = parseVersion( 200 '0.7.3', 201 'dry-run', 202 ); 203 expect(version).toBe('0.7.3'); 204 expect(major).toBe('0'); 205 expect(minor).toBe('7'); 206 expect(patch).toBe('3'); 207 expect(prerelease).toBeUndefined(); 208 }); 209 210 it('should parse dryrun with prerelease . version', () => { 211 const {version, major, minor, patch, prerelease} = parseVersion( 212 '0.20.0-rc.0', 213 'dry-run', 214 ); 215 expect(version).toBe('0.20.0-rc.0'); 216 expect(major).toBe('0'); 217 expect(minor).toBe('20'); 218 expect(patch).toBe('0'); 219 expect(prerelease).toBe('rc.0'); 220 }); 221 222 it('should parse dryrun with prerelease - version', () => { 223 const {version, major, minor, patch, prerelease} = parseVersion( 224 '0.20.0-rc-0', 225 'dry-run', 226 ); 227 expect(version).toBe('0.20.0-rc-0'); 228 expect(major).toBe('0'); 229 expect(minor).toBe('20'); 230 expect(patch).toBe('0'); 231 expect(prerelease).toBe('rc-0'); 232 }); 233 234 it('should parse dryrun with main version', () => { 235 const {version, major, minor, patch, prerelease} = parseVersion( 236 '1000.0.0', 237 'dry-run', 238 ); 239 expect(version).toBe('1000.0.0'); 240 expect(major).toBe('1000'); 241 expect(minor).toBe('0'); 242 expect(patch).toBe('0'); 243 expect(prerelease).toBeUndefined(); 244 }); 245 246 it('should fail for dryrun with v1000.0.1 version', () => { 247 function testInvalidFunction() { 248 parseVersion('v1000.0.1', 'dry-run'); 249 } 250 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 251 `"Version 1000.0.1 is not valid for dry-runs"`, 252 ); 253 }); 254 it('should parse dryrun with nightly version', () => { 255 const {version, major, minor, patch, prerelease} = parseVersion( 256 '0.0.0-something-else', 257 'dry-run', 258 ); 259 expect(version).toBe('0.0.0-something-else'); 260 expect(major).toBe('0'); 261 expect(minor).toBe('0'); 262 expect(patch).toBe('0'); 263 expect(prerelease).toBe('something-else'); 264 }); 265 266 it('should reject dryrun invalid values', () => { 267 function testInvalidFunction() { 268 parseVersion('1000.0.4', 'dry-run'); 269 } 270 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 271 `"Version 1000.0.4 is not valid for dry-runs"`, 272 ); 273 }); 274 275 it('should reject dryrun for invalid prerelease', () => { 276 function testInvalidFunction() { 277 parseVersion('0.6.4-something-else', 'dry-run'); 278 } 279 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 280 `"Version 0.6.4-something-else is not valid for dry-runs"`, 281 ); 282 }); 283 284 it('should reject dryrun for nightlies with invalid prerelease', () => { 285 function testInvalidFunction() { 286 parseVersion('0.0.0', 'dry-run'); 287 } 288 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 289 `"Version 0.0.0 is not valid for dry-runs"`, 290 ); 291 }); 292 }); 293 294 describe('Validate version', () => { 295 it('Throw error if the buildType is unknown', () => { 296 function testInvalidFunction() { 297 validateBuildType('wrong_build'); 298 } 299 expect(testInvalidFunction).toThrowErrorMatchingInlineSnapshot( 300 `"Unsupported build type: wrong_build"`, 301 ); 302 }); 303 it('Does not throw if the buildType is release', () => { 304 function testValidCall() { 305 validateBuildType('release'); 306 } 307 expect(testValidCall).not.toThrowError(); 308 }); 309 it('Does not throw if the buildType is nightly', () => { 310 function testValidCall() { 311 validateBuildType('nightly'); 312 } 313 expect(testValidCall).not.toThrowError(); 314 }); 315 it('Does not throw if the buildType is dry-run', () => { 316 function testValidCall() { 317 validateBuildType('dry-run'); 318 } 319 expect(testValidCall).not.toThrowError(); 320 }); 321 }); 322}); 323