Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[eas-build-job] add channel to Job #24

Merged
merged 28 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions packages/build-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@
"fs-extra": "^9.0.0",
"node-forge": "^0.9.1",
"nullthrows": "^1.1.1",
"plist": "^3.0.1",
"uuid": "^3.3.3",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uuid wasn't being used.

"xml2js": "^0.4.23"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced the manual xml2js usage in packages/build-tools/src/android/releaseChannel.ts with calls to methods in @expo/config-plugins.AndroidConfig.Manifest.* in packages/build-tools/src/android/expoUpdates.ts

"plist": "^3.0.1"
},
"devDependencies": {
"@types/fs-extra": "^9.0.1",
Expand Down
3 changes: 3 additions & 0 deletions packages/build-tools/src/__mocks__/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@ import { fs } from 'memfs';
// `temp-dir` dependency of `tempy` is using `fs.realpathSync('/tmp')`
// on import to verify existence of tmp directory
fs.mkdirSync('/tmp');
if (process.env.TMPDIR) {
fs.mkdirSync(process.env.TMPDIR, { recursive: true });
}
dsokal marked this conversation as resolved.
Show resolved Hide resolved

module.exports = fs;
156 changes: 156 additions & 0 deletions packages/build-tools/src/android/__tests__/expoUpdates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import path from 'path';

import fs from 'fs-extra';
import { AndroidConfig } from '@expo/config-plugins';

import {
AndroidMetadataName,
androidGetNativelyDefinedClassicReleaseChannelAsync,
androidSetChannelNativelyAsync,
androidSetClassicReleaseChannelNativelyAsync,
} from '../expoUpdates';

jest.mock('fs');

const channel = 'main';
const noMetadataAndroidManifest = `
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.expo.mycoolapp">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>

</manifest>
`;
describe(androidSetClassicReleaseChannelNativelyAsync, () => {
test('sets the release channel', async () => {
const reactNativeProjectDirectory = fs.mkdtempSync('/expo-project-');
fs.ensureDirSync(reactNativeProjectDirectory);
const releaseChannel = 'default';
const ctx = {
reactNativeProjectDirectory,
job: { releaseChannel },
logger: { info: () => {} },
};

fs.ensureDirSync(path.join(reactNativeProjectDirectory, 'android'));
const manifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(
reactNativeProjectDirectory
);
const manifestDirectory = path.dirname(manifestPath);

fs.ensureDirSync(manifestDirectory);
fs.writeFileSync(manifestPath, Buffer.from(noMetadataAndroidManifest));
const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
expect(
AndroidConfig.Manifest.getMainApplicationMetaDataValue(androidManifest, 'releaseChannel')
).toBe(null);

await androidSetClassicReleaseChannelNativelyAsync(ctx as any);

const newAndroidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
expect(
AndroidConfig.Manifest.getMainApplicationMetaDataValue(
newAndroidManifest,
AndroidMetadataName.RELEASE_CHANNEL
)
).toBe(releaseChannel);
});
});
describe(androidSetChannelNativelyAsync, () => {
it('sets the channel', async () => {
const reactNativeProjectDirectory = fs.mkdtempSync('/expo-project-');
fs.ensureDirSync(reactNativeProjectDirectory);
const ctx = {
reactNativeProjectDirectory,
job: { updates: { channel } },
logger: { info: () => {} },
};

fs.ensureDirSync(path.join(reactNativeProjectDirectory, 'android'));
const manifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(
reactNativeProjectDirectory
);
const manifestDirectory = path.dirname(manifestPath);

fs.ensureDirSync(manifestDirectory);
fs.writeFileSync(manifestPath, noMetadataAndroidManifest);

const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
expect(
AndroidConfig.Manifest.getMainApplicationMetaDataValue(
androidManifest,
AndroidMetadataName.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY
)
).toBe(null);

await androidSetChannelNativelyAsync(ctx as any);

const newAndroidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
const newValue = AndroidConfig.Manifest.getMainApplicationMetaDataValue(
newAndroidManifest,
AndroidMetadataName.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY
);
expect(newValue).toBeDefined();
expect(JSON.parse(newValue!)).toEqual({ 'expo-channel-name': channel });
});
});
describe(androidGetNativelyDefinedClassicReleaseChannelAsync, () => {
it('gets the natively defined release channel', async () => {
const reactNativeProjectDirectory = fs.mkdtempSync('/expo-project-');
fs.ensureDirSync(reactNativeProjectDirectory);
const releaseChannel = 'default';
const ctx = {
reactNativeProjectDirectory,
logger: { info: () => {} },
};

const releaseChannelInAndroidManifest = `
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.expo.mycoolapp">
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme">
<activity android:name=".MainActivity" android:launchMode="singleTask" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity"/>
<meta-data android:name="expo.modules.updates.EXPO_RELEASE_CHANNEL" android:value="default"/>
</application>
</manifest>`;
fs.ensureDirSync(path.join(reactNativeProjectDirectory, 'android'));
const manifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(
reactNativeProjectDirectory
);
const manifestDirectory = path.dirname(manifestPath);

fs.ensureDirSync(manifestDirectory);
fs.writeFileSync(manifestPath, releaseChannelInAndroidManifest);

const nativelyDefinedReleaseChannel = await androidGetNativelyDefinedClassicReleaseChannelAsync(
ctx as any
);
expect(nativelyDefinedReleaseChannel).toBe(releaseChannel);
});
});
81 changes: 81 additions & 0 deletions packages/build-tools/src/android/expoUpdates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import assert from 'assert';

import fs from 'fs-extra';
import { AndroidConfig } from '@expo/config-plugins';
import { Job } from '@expo/eas-build-job';

import { BuildContext } from '../context';

export enum AndroidMetadataName {
jkhales marked this conversation as resolved.
Show resolved Hide resolved
UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY = 'expo.modules.updates.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY',
RELEASE_CHANNEL = 'expo.modules.updates.EXPO_RELEASE_CHANNEL',
}

export async function androidSetChannelNativelyAsync(ctx: BuildContext<Job>): Promise<void> {
assert(ctx.job.updates?.channel, 'updates.channel must be defined');

const manifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(
ctx.reactNativeProjectDirectory
);

if (!(await fs.pathExists(manifestPath))) {
throw new Error(`Couldn't find Android manifest at ${manifestPath}`);
}

const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
const mainApp = AndroidConfig.Manifest.getMainApplicationOrThrow(androidManifest);
const stringifiedUpdatesRequestHeaders = AndroidConfig.Manifest.getMainApplicationMetaDataValue(
androidManifest,
AndroidMetadataName.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY
);
AndroidConfig.Manifest.addMetaDataItemToMainApplication(
mainApp,
AndroidMetadataName.UPDATES_CONFIGURATION_REQUEST_HEADERS_KEY,
JSON.stringify({
...JSON.parse(stringifiedUpdatesRequestHeaders ?? '{}'),
'expo-channel-name': ctx.job.updates.channel,
}),
'value'
);
await AndroidConfig.Manifest.writeAndroidManifestAsync(manifestPath, androidManifest);
}

export async function androidSetClassicReleaseChannelNativelyAsync(
ctx: BuildContext<Job>
): Promise<void> {
assert(ctx.job.releaseChannel, 'releaseChannel must be defined');

const manifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(
ctx.reactNativeProjectDirectory
);
if (!(await fs.pathExists(manifestPath))) {
throw new Error(`Couldn't find Android manifest at ${manifestPath}`);
}

const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
const mainApp = AndroidConfig.Manifest.getMainApplicationOrThrow(androidManifest);
AndroidConfig.Manifest.addMetaDataItemToMainApplication(
mainApp,
AndroidMetadataName.RELEASE_CHANNEL,
ctx.job.releaseChannel,
'value'
);
await AndroidConfig.Manifest.writeAndroidManifestAsync(manifestPath, androidManifest);
}

export async function androidGetNativelyDefinedClassicReleaseChannelAsync(
ctx: BuildContext<Job>
): Promise<string | null> {
const manifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(
ctx.reactNativeProjectDirectory
);
if (!(await fs.pathExists(manifestPath))) {
return null;
}

const androidManifest = await AndroidConfig.Manifest.readAndroidManifestAsync(manifestPath);
return AndroidConfig.Manifest.getMainApplicationMetaDataValue(
androidManifest,
AndroidMetadataName.RELEASE_CHANNEL
);
}
91 changes: 0 additions & 91 deletions packages/build-tools/src/android/releaseChannel.ts

This file was deleted.

5 changes: 2 additions & 3 deletions packages/build-tools/src/builders/androidGeneric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { BuildContext } from '../context';
import { setup } from '../utils/project';
import { findBuildArtifacts } from '../utils/buildArtifacts';
import { Hook, runHookIfPresent } from '../utils/hooks';
import { getReleaseChannel, updateReleaseChannel } from '../android/releaseChannel';
import { restoreCredentials } from '../android/credentials';
import { runGradleCommand, ensureLFLineEndingsInGradlewScript } from '../android/gradle';
import { configureExpoUpdatesIfInstalled } from '../generic/expoUpdates';
import { configureExpoUpdatesIfInstalledAsync } from '../utils/expoUpdates';

export default async function androidGenericBuilder(
ctx: BuildContext<Android.GenericJob>
Expand All @@ -33,7 +32,7 @@ export default async function androidGenericBuilder(
}

await ctx.runBuildPhase(BuildPhase.CONFIGURE_EXPO_UPDATES, async () => {
await configureExpoUpdatesIfInstalled(ctx, { getReleaseChannel, updateReleaseChannel });
await configureExpoUpdatesIfInstalledAsync(ctx);
});

await ctx.runBuildPhase(BuildPhase.RUN_GRADLEW, async () => {
Expand Down
5 changes: 2 additions & 3 deletions packages/build-tools/src/builders/androidManaged.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import { AndroidConfig } from '@expo/config-plugins';
import { Android, BuildPhase } from '@expo/eas-build-job';

import { ManagedBuildContext } from '../managed/context';
import { configureExpoUpdatesIfInstalled } from '../managed/expoUpdates';
import { configureExpoUpdatesIfInstalledAsync } from '../utils/expoUpdates';
import { setup } from '../utils/project';
import { findSingleBuildArtifact } from '../utils/buildArtifacts';
import { Hook, runHookIfPresent } from '../utils/hooks';
import { updateReleaseChannel } from '../android/releaseChannel';
import { restoreCredentials } from '../android/credentials';
import { runGradleCommand } from '../android/gradle';

Expand All @@ -33,7 +32,7 @@ export default async function androidManagedBuilder(
});
}
await ctx.runBuildPhase(BuildPhase.CONFIGURE_EXPO_UPDATES, async () => {
await configureExpoUpdatesIfInstalled(ctx, updateReleaseChannel);
await configureExpoUpdatesIfInstalledAsync(ctx);
});

await ctx.runBuildPhase(BuildPhase.RUN_GRADLEW, async () => {
Expand Down
Loading