Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

Commit

Permalink
[expo-cli] command for syncing credentials.json and credentials on www (
Browse files Browse the repository at this point in the history
#2460)

* [expo-cli] command for syncing credentials.json and credentials on www

* review feedback

* update CHANGELOG.md
  • Loading branch information
wkozyra95 authored Aug 18, 2020
1 parent d21717c commit 36dde71
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 98 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This is the log of notable changes to Expo CLI and related packages.

### 🎉 New features

- [expo-cli]: EAS Build: add command `eas:credentials:sync` ([#2460](https://github.com/expo/expo-cli/pull/2460)) by [@wkozyra95](https://github.com/wkozyra95)

### 🐛 Bug fixes

### 📦 Packages updated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ function setupCredentialsConfig() {
});
}

const originalWarn = console.warn;
const originalLog = console.log;
beforeAll(() => {
console.warn = jest.fn();
console.log = jest.fn();
});
afterAll(() => {
console.warn = originalWarn;
console.log = originalLog;
});
beforeEach(() => {
vol.reset();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ function setupCredentialsConfig() {
});
}

const originalWarn = console.warn;
const originalLog = console.log;
beforeAll(() => {
console.warn = jest.fn();
console.log = jest.fn();
});
afterAll(() => {
console.warn = originalWarn;
console.log = originalLog;
});
beforeEach(() => {
vol.reset();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { BuildType, Job, Platform, iOS, sanitizeJob } from '@expo/build-tools';
import { IOSConfig } from '@expo/config';
import chalk from 'chalk';
import figures from 'figures';
import once from 'lodash/once';
import ora from 'ora';

import iOSCredentialsProvider, {
Expand All @@ -16,10 +15,10 @@ import {
iOSManagedBuildProfile,
} from '../../../../easJson';
import log from '../../../../log';
import prompts from '../../../../prompts';
import { ensureCredentialsAsync } from '../credentials';
import { Builder, BuilderContext } from '../types';
import * as gitUtils from '../utils/git';
import { getBundleIdentifier } from '../utils/ios';

interface CommonJobProperties {
platform: Platform.iOS;
Expand Down Expand Up @@ -58,7 +57,7 @@ class iOSBuilder implements Builder {
if (!this.shouldLoadCredentials()) {
return;
}
const bundleIdentifier = await getBundleIdentifier(this.ctx);
const bundleIdentifier = await getBundleIdentifier(this.ctx.projectDir, this.ctx.exp);
const provider = new iOSCredentialsProvider(this.ctx.projectDir, {
projectName: this.ctx.projectName,
accountName: this.ctx.accountName,
Expand All @@ -80,7 +79,7 @@ class iOSBuilder implements Builder {
if (!this.credentials) {
throw new Error('Call ensureCredentialsAsync first!');
}
const bundleIdentifier = await getBundleIdentifier(this.ctx);
const bundleIdentifier = await getBundleIdentifier(this.ctx.projectDir, this.ctx.exp);

const spinner = ora('Making sure your iOS project is set up properly');

Expand Down Expand Up @@ -173,69 +172,5 @@ class iOSBuilder implements Builder {
);
}
}
const getBundleIdentifier = once(_getBundleIdentifier);

async function _getBundleIdentifier(ctx: BuilderContext): Promise<string> {
const bundleIdentifierFromPbxproj = IOSConfig.BundleIdenitifer.getBundleIdentifierFromPbxproj(
ctx.projectDir
);
const bundleIdentifierFromConfig = IOSConfig.BundleIdenitifer.getBundleIdentifier(ctx.exp);
if (bundleIdentifierFromPbxproj !== null && bundleIdentifierFromConfig !== null) {
if (bundleIdentifierFromPbxproj === bundleIdentifierFromConfig) {
return bundleIdentifierFromPbxproj;
} else {
log.newLine();
log(
log.chalk.yellow(
`We detected that your Xcode project is configured with a different bundle identifier than the one defined in app.json/app.config.js.
If you choose the one defined in app.json/app.config.js we'll automatically configure your Xcode project with it.
However, if you choose the one defined in the Xcode project you'll have to update app.json/app.config.js on your own.
Otherwise, you'll see this prompt again in the future.`
)
);
log.newLine();
const { bundleIdentifier } = await prompts({
type: 'select',
name: 'bundleIdentifier',
message: 'Which bundle identifier should we use?',
choices: [
{
title: `Defined in the Xcode project: ${log.chalk.bold(bundleIdentifierFromPbxproj)}`,
value: bundleIdentifierFromPbxproj,
},
{
title: `Defined in app.json/app.config.js: ${log.chalk.bold(
bundleIdentifierFromConfig
)}`,
value: bundleIdentifierFromConfig,
},
],
});
return bundleIdentifier;
}
} else if (bundleIdentifierFromPbxproj === null && bundleIdentifierFromConfig === null) {
throw new Error('Please define "expo.ios.bundleIdentifier" in app.json/app.config.js');
} else {
if (bundleIdentifierFromPbxproj !== null) {
log(
`Using ${log.chalk.bold(
bundleIdentifierFromPbxproj
)} as the bundle identifier (read from the Xcode project).`
);
return bundleIdentifierFromPbxproj;
} else {
// bundleIdentifierFromConfig is never null in this case
// the following line is to satisfy TS
const bundleIdentifier = bundleIdentifierFromConfig ?? '';
log(
`Using ${log.chalk.bold(
bundleIdentifier
)} as the bundle identifier (read from app.json/app.config.js).
We'll automatically configure your Xcode project using this value.`
);
return bundleIdentifier;
}
}
}

export default iOSBuilder;
70 changes: 70 additions & 0 deletions packages/expo-cli/src/commands/eas-build/build/utils/ios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ExpoConfig, IOSConfig } from '@expo/config';
import once from 'lodash/once';

import log from '../../../../log';
import prompts from '../../../../prompts';

export const getBundleIdentifier = once(_getBundleIdentifier);

async function _getBundleIdentifier(projectDir: string, manifest: ExpoConfig): Promise<string> {
const bundleIdentifierFromPbxproj = IOSConfig.BundleIdenitifer.getBundleIdentifierFromPbxproj(
projectDir
);
const bundleIdentifierFromConfig = IOSConfig.BundleIdenitifer.getBundleIdentifier(manifest);
if (bundleIdentifierFromPbxproj !== null && bundleIdentifierFromConfig !== null) {
if (bundleIdentifierFromPbxproj === bundleIdentifierFromConfig) {
return bundleIdentifierFromPbxproj;
} else {
log.newLine();
log(
log.chalk.yellow(
`We detected that your Xcode project is configured with a different bundle identifier than the one defined in app.json/app.config.js.
If you choose the one defined in app.json/app.config.js we'll automatically configure your Xcode project with it.
However, if you choose the one defined in the Xcode project you'll have to update app.json/app.config.js on your own.
Otherwise, you'll see this prompt again in the future.`
)
);
log.newLine();
const { bundleIdentifier } = await prompts({
type: 'select',
name: 'bundleIdentifier',
message: 'Which bundle identifier should we use?',
choices: [
{
title: `Defined in the Xcode project: ${log.chalk.bold(bundleIdentifierFromPbxproj)}`,
value: bundleIdentifierFromPbxproj,
},
{
title: `Defined in app.json/app.config.js: ${log.chalk.bold(
bundleIdentifierFromConfig
)}`,
value: bundleIdentifierFromConfig,
},
],
});
return bundleIdentifier;
}
} else if (bundleIdentifierFromPbxproj === null && bundleIdentifierFromConfig === null) {
throw new Error('Please define "expo.ios.bundleIdentifier" in app.json/app.config.js');
} else {
if (bundleIdentifierFromPbxproj !== null) {
log(
`Using ${log.chalk.bold(
bundleIdentifierFromPbxproj
)} as the bundle identifier (read from the Xcode project).`
);
return bundleIdentifierFromPbxproj;
} else {
// bundleIdentifierFromConfig is never null in this case
// the following line is to satisfy TS
const bundleIdentifier = bundleIdentifierFromConfig ?? '';
log(
`Using ${log.chalk.bold(
bundleIdentifier
)} as the bundle identifier (read from app.json/app.config.js).
We'll automatically configure your Xcode project using this value.`
);
return bundleIdentifier;
}
}
}
98 changes: 98 additions & 0 deletions packages/expo-cli/src/commands/eas-build/credentialsSync/action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import CommandError from '../../../CommandError';
import { Context } from '../../../credentials/context';
import * as credentialsJsonUpdateUtils from '../../../credentials/credentialsJson/update';
import { runCredentialsManager } from '../../../credentials/route';
import { SetupAndroidBuildCredentialsFromLocal } from '../../../credentials/views/SetupAndroidKeystore';
import { SetupIosBuildCredentialsFromLocal } from '../../../credentials/views/SetupIosBuildCredentials';
import log from '../../../log';
import prompts from '../../../prompts';
import { getBundleIdentifier } from '../build/utils/ios';
import { BuildCommandPlatform } from '../types';

interface Options {
parent: {
nonInteractive?: boolean;
};
}

export default async function credentialsSyncAction(projectDir: string, options: Options) {
if (options.parent.nonInteractive) {
throw new CommandError('This command is not supported in --non-interactive mode');
}
const { update, platform } = await prompts([
{
type: 'select',
name: 'update',
message: 'What do you want to do?',
choices: [
{
title: 'Update credentials on the Expo servers with the local credentials.json contents',
value: 'remote',
},
{
title: 'Update or create local credentials.json with credentials from the Expo servers',
value: 'local',
},
],
},
{
type: 'select',
name: 'platform',
message: 'Which platform would you like to update?',
choices: [
{ title: 'Android', value: BuildCommandPlatform.ANDROID },
{ title: 'iOS', value: BuildCommandPlatform.IOS },
{ title: 'both', value: BuildCommandPlatform.ALL },
],
},
]);
if (update === 'local') {
await updateLocalCredentialsAsync(projectDir, platform);
} else {
await updateRemoteCredentialsAsync(projectDir, platform);
}
}

async function updateRemoteCredentialsAsync(
projectDir: string,
platform: BuildCommandPlatform
): Promise<void> {
const ctx = new Context();
await ctx.init(projectDir);
if (!ctx.hasProjectContext) {
throw new Error('project context is required'); // should be checked earlier
}
if ([BuildCommandPlatform.ALL, BuildCommandPlatform.ANDROID].includes(platform)) {
const experienceName = `@${ctx.manifest.owner || ctx.user.username}/${ctx.manifest.slug}`;
await runCredentialsManager(ctx, new SetupAndroidBuildCredentialsFromLocal(experienceName));
}
if ([BuildCommandPlatform.ALL, BuildCommandPlatform.IOS].includes(platform)) {
const bundleIdentifier = await getBundleIdentifier(projectDir, ctx.manifest);
const appLookupParams = {
accountName: ctx.manifest.owner ?? ctx.user.username,
projectName: ctx.manifest.slug,
bundleIdentifier,
};
await runCredentialsManager(ctx, new SetupIosBuildCredentialsFromLocal(appLookupParams));
}
}

export async function updateLocalCredentialsAsync(
projectDir: string,
platform: BuildCommandPlatform
): Promise<void> {
const ctx = new Context();
await ctx.init(projectDir);
if (!ctx.hasProjectContext) {
throw new Error('project context is required'); // should be checked earlier
}
if ([BuildCommandPlatform.ALL, BuildCommandPlatform.ANDROID].includes(platform)) {
log('Updating Android credentials in credentials.json');
await credentialsJsonUpdateUtils.updateAndroidCredentialsAsync(ctx);
}
if ([BuildCommandPlatform.ALL, BuildCommandPlatform.IOS].includes(platform)) {
const bundleIdentifier = await getBundleIdentifier(projectDir, ctx.manifest);
log('Updating iOS credentials in credentials.json');
await credentialsJsonUpdateUtils.updateIosCredentialsAsync(ctx, bundleIdentifier);
}
}
6 changes: 6 additions & 0 deletions packages/expo-cli/src/commands/eas-build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fs from 'fs-extra';
import path from 'path';

import buildAction from './build/action';
import credentialsSyncAction from './credentialsSync/action';
import statusAction from './status/action';

export default function (program: Command) {
Expand All @@ -12,6 +13,11 @@ export default function (program: Command) {
return;
}

program
.command('eas:credentials:sync [project-dir]')
.description('Update credentials.json with credentials stored on Expo servers')
.asyncActionProjectDir(credentialsSyncAction, { checkConfig: true });

program
.command('eas:build [project-dir]')
.description('Build an app binary for your project.')
Expand Down
Loading

0 comments on commit 36dde71

Please sign in to comment.