1import path from 'path'; 2import fs from 'fs-extra'; 3import plist from 'plist'; 4import semver from 'semver'; 5import JsonFile from '@expo/json-file'; 6 7import { EXPO_DIR, ANDROID_DIR } from './Constants'; 8 9export type Platform = 'ios' | 'android'; 10 11export type SDKVersionsObject = { 12 sdkVersions: string[]; 13}; 14 15export async function sdkVersionAsync(): Promise<string> { 16 const packageJson = await JsonFile.readAsync(path.join(EXPO_DIR, 'packages/expo/package.json')); 17 return packageJson.version as string; 18} 19 20export async function iosAppVersionAsync(): Promise<string> { 21 const infoPlistPath = path.join(EXPO_DIR, 'ios', 'Exponent', 'Supporting', 'Info.plist'); 22 const infoPlist = plist.parse(fs.readFileSync(infoPlistPath, 'utf8')); 23 const bundleVersion = infoPlist.CFBundleShortVersionString; 24 25 if (!bundleVersion) { 26 throw new Error(`"CFBundleShortVersionString" not found in plist: ${infoPlistPath}`); 27 } 28 return bundleVersion; 29} 30 31export async function androidAppVersionAsync(): Promise<string> { 32 const buildGradlePath = path.join(ANDROID_DIR, 'app', 'build.gradle'); 33 const buildGradleContent = await fs.readFile(buildGradlePath, 'utf8'); 34 const match = buildGradleContent.match(/versionName ['"]([^'"]+?)['"]/); 35 36 if (!match) { 37 throw new Error("Can't obtain `versionName` from app's build.gradle"); 38 } 39 return match[1]; 40} 41 42export async function getHomeSDKVersionAsync(): Promise<string> { 43 const homeAppJsonPath = path.join(EXPO_DIR, 'home', 'app.json'); 44 const appJson = (await JsonFile.readAsync(homeAppJsonPath, { json5: true })) as any; 45 46 if (appJson?.expo?.sdkVersion) { 47 return appJson.expo.sdkVersion as string; 48 } 49 throw new Error(`Home's SDK version not found!`); 50} 51 52export async function getSDKVersionsAsync(platform: Platform): Promise<string[]> { 53 const sdkVersionsPath = path.join( 54 EXPO_DIR, 55 platform === 'ios' ? 'ios/Exponent/Supporting' : 'android', 56 'sdkVersions.json' 57 ); 58 59 if (!(await fs.pathExists(sdkVersionsPath))) { 60 throw new Error(`File at path "${sdkVersionsPath}" not found.`); 61 } 62 const { sdkVersions } = (await JsonFile.readAsync(sdkVersionsPath)) as SDKVersionsObject; 63 return sdkVersions; 64} 65 66export async function getOldestSDKVersionAsync(platform: Platform): Promise<string | undefined> { 67 const sdkVersions = await getSDKVersionsAsync(platform); 68 return sdkVersions.sort(semver.compare)[0]; 69} 70 71export async function getNewestSDKVersionAsync(platform: Platform): Promise<string | undefined> { 72 const sdkVersions = await getSDKVersionsAsync(platform); 73 return sdkVersions.sort(semver.rcompare)[0]; 74} 75 76export async function getNextSDKVersionAsync(platform: Platform): Promise<string | undefined> { 77 const newestVersion = await getNewestSDKVersionAsync(platform); 78 79 if (!newestVersion) { 80 return; 81 } 82 return `${semver.major(semver.inc(newestVersion, 'major')!)}.0.0`; 83} 84