xref: /expo/tools/src/ProjectVersions.ts (revision eeffdb10)
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