Skip to content

Commit

Permalink
[et] Move UpdateVersions from xdl to expotools (#9336)
Browse files Browse the repository at this point in the history
# Why

Part of expo/expo-cli#2282

# How

Moved some functionality of xdl's UpdateVersions to expotools and refactored `et client-build` command a little bit.

# Test Plan

Tested with `et client-build -p ios --release --skip-upload`, will test Android soon
  • Loading branch information
tsapeta committed Jul 29, 2020
1 parent b5532de commit d56ff1c
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 103 deletions.
4 changes: 2 additions & 2 deletions ios/Exponent/Supporting/Info.plist
Expand Up @@ -16,8 +16,6 @@
<string>$(EX_BUNDLE_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleVersion</key>
<string>2.16.0</string>
<key>CFBundleShortVersionString</key>
<string>2.16.0</string>
<key>CFBundleSignature</key>
Expand Down Expand Up @@ -55,6 +53,8 @@
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>2.16.0</string>
<key>FacebookAdvertiserIDCollectionEnabled</key>
<false/>
<key>FacebookAppID</key>
Expand Down
74 changes: 74 additions & 0 deletions tools/expotools/src/Versions.ts
@@ -0,0 +1,74 @@
import { Config, Versions } from '@expo/xdl';

export enum VersionsApiHost {
PRODUCTION = 'exp.host',
STAGING = 'staging.exp.host',
}

export type VersionsSchema = {
sdkVersions: Record<string, VersionsSdkSchema>;
turtleSdkVersions: {
android: string;
ios: string;
};
};

export type VersionsSdkSchema = Partial<{
androidClientUrl: string;
androidClientVersion: string;
androidExpoViewUrl: string;
expokitNpmPackage: string;
expoReactNativeTag: string;
facebookReactNativeVersion: string;
facebookReactVersion: string;
iosClientUrl: string;
iosClientVersion: string;
iosExpoViewUrl: string;
packagesToInstallWhenEjecting: Record<string, string>;
relatedPackages: Record<string, string>;
releaseNoteUrl: string;
}>;

export async function getVersionsAsync(
apiHost: VersionsApiHost = VersionsApiHost.STAGING
): Promise<VersionsSchema> {
return await runWithApiHost(apiHost, () => Versions.versionsAsync() as Promise<VersionsSchema>);
}

export async function getSdkVersionsAsync(
sdkVersion: string,
apiHost: VersionsApiHost = VersionsApiHost.STAGING
): Promise<VersionsSdkSchema | null> {
const versions = await getVersionsAsync(apiHost);
return versions?.sdkVersions?.[sdkVersion] ?? null;
}

export async function setVersionsAsync(
versions: VersionsSchema,
apiHost: VersionsApiHost = VersionsApiHost.STAGING
): Promise<void> {
return await runWithApiHost(apiHost, () => Versions.setVersionsAsync(versions));
}

export async function modifySdkVersionsAsync(
sdkVersion: string,
modifier: (sdkVersions: VersionsSdkSchema) => VersionsSdkSchema | Promise<VersionsSdkSchema>
): Promise<VersionsSdkSchema> {
const versions = await getVersionsAsync();
const sdkVersions = await modifier(versions.sdkVersions[sdkVersion] ?? {});

versions.sdkVersions[sdkVersion] = sdkVersions;
await setVersionsAsync(versions);
return sdkVersions;
}

async function runWithApiHost<T = any>(
apiHost: VersionsApiHost,
lambda: () => T | Promise<T>
): Promise<T> {
const originalHost = Config.api.host;
Config.api.host = apiHost;
const result = await lambda();
Config.api.host = originalHost;
return result;
}
40 changes: 40 additions & 0 deletions tools/expotools/src/client-build/AndroidClientBuilder.ts
@@ -0,0 +1,40 @@
import fs from 'fs-extra';
import path from 'path';

import { ANDROID_DIR } from '../Constants';
import { androidAppVersionAsync } from '../ProjectVersions';
import { spawnAsync } from '../Utils';
import { ClientBuilder, Platform, S3Client } from './types';

export default class AndroidClientBuilder implements ClientBuilder {
platform: Platform = 'android';

getAppPath(): string {
return path.join(ANDROID_DIR, 'app', 'build', 'outputs', 'apk', 'release', 'app-release.apk');
}

getClientUrl(appVersion: string): string {
return `https://d1ahtucjixef4r.cloudfront.net/Exponent-${appVersion}.apk`;
}

async getAppVersionAsync(): Promise<string> {
return androidAppVersionAsync();
}

async buildAsync() {
await spawnAsync('fastlane', ['android', 'build', 'build_type:Release'], { stdio: 'inherit' });
}

async uploadBuildAsync(s3Client: S3Client, appVersion: string) {
const file = fs.createReadStream(this.getAppPath());

await s3Client
.putObject({
Bucket: 'exp-android-apks',
Key: `Exponent-${appVersion}.apk`,
Body: file,
ACL: 'public-read',
})
.promise();
}
}
55 changes: 55 additions & 0 deletions tools/expotools/src/client-build/IosClientBuilder.ts
@@ -0,0 +1,55 @@
import fs from 'fs-extra';
import path from 'path';

import { EXPO_DIR, IOS_DIR } from '../Constants';
import { iosAppVersionAsync } from '../ProjectVersions';
import { spawnAsync } from '../Utils';
import { ClientBuilder, Platform } from './types';

export default class IosClientBuilder implements ClientBuilder {
platform: Platform = 'ios';

getAppPath(): string {
return path.join(
IOS_DIR,
'simulator-build',
'Build',
'Products',
'Release-iphonesimulator',
'Exponent.app'
);
}

getClientUrl(appVersion: string): string {
return `https://dpq5q02fu5f55.cloudfront.net/Exponent-${appVersion}.tar.gz`;
}

async getAppVersionAsync(): Promise<string> {
return await iosAppVersionAsync();
}

async buildAsync() {
await spawnAsync('fastlane', ['ios', 'create_simulator_build'], { stdio: 'inherit' });
}

async uploadBuildAsync(s3Client, appVersion: string) {
const tempAppPath = path.join(EXPO_DIR, 'temp-app.tar.gz');

await spawnAsync('tar', ['-zcvf', tempAppPath, '-C', this.getAppPath(), '.'], {
stdio: ['ignore', 'ignore', 'inherit'], // only stderr
});

const file = fs.createReadStream(tempAppPath);

await s3Client
.putObject({
Bucket: 'exp-ios-simulator-apps',
Key: `Exponent-${appVersion}.tar.gz`,
Body: file,
ACL: 'public-read',
})
.promise();

await fs.remove(tempAppPath);
}
}
15 changes: 15 additions & 0 deletions tools/expotools/src/client-build/types.ts
@@ -0,0 +1,15 @@
import aws from 'aws-sdk';
import { Platform } from '../ProjectVersions';

export { Platform };

export type S3Client = aws.S3;

export interface ClientBuilder {
platform: Platform;
getAppPath: () => string;
getClientUrl: (appVersion: string) => string;
getAppVersionAsync: () => Promise<string>;
buildAsync: () => Promise<void>;
uploadBuildAsync: (s3Client: S3Client, appVersion: string) => Promise<void>;
}

0 comments on commit d56ff1c

Please sign in to comment.