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

Commit

Permalink
[expo-cli] Add a eas:build:init command
Browse files Browse the repository at this point in the history
We want to add a separate command to configure the project for eas builds without having to actually start a build.
  • Loading branch information
satya164 committed Aug 25, 2020
1 parent ffaf58e commit 10fca19
Show file tree
Hide file tree
Showing 12 changed files with 382 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jest.mock('../../../../projects', () => {
ensureProjectExistsAsync: () => 'fakeProjectId',
};
});
jest.mock('../utils/git');
jest.mock('../../utils/git');
jest.mock('../../../../git');
jest.mock('../../../../uploads', () => ({
UploadType: {},
Expand Down Expand Up @@ -132,7 +132,8 @@ function setupProjectConfig(overrideConfig: any) {
'package.json': JSON.stringify(packageJson),
'node_modules/expo/package.json': '{ "version": "38.0.0" }',
'cert.p12': cert.content,
'android/app/build.gradle': '',
'android/app/build.gradle': 'apply from: "./eas-build.gradle"',
'android/app/eas-build.gradle': '',
},
'/projectdir'
);
Expand All @@ -159,6 +160,24 @@ jest.setTimeout(30000);

describe('build command', () => {
describe('android generic job', () => {
it('should throw if project is not configured', async () => {
expect.assertions(1);

setupProjectConfig({});
vol.unlinkSync('/projectdir/android/app/eas-build.gradle');

try {
await buildAction('/projectdir', {
platform: BuildCommandPlatform.ANDROID,
wait: false,
profile: 'release',
});
} catch (e) {
expect(e.message).toMatch(
'Project is not configured. Please run "expo eas:build:init" first to configure the project'
);
}
});
it('should go through build process', async () => {
const postArguments: any = {};
mockPostAsync.mockImplementationOnce((url, body) => {
Expand Down Expand Up @@ -189,10 +208,6 @@ describe('build command', () => {
},
},
});
expect(vol.existsSync('/projectdir/android/app/eas-build.gradle')).toBe(true);
expect(vol.readFileSync('/projectdir/android/app/build.gradle', 'utf-8')).toContain(
'apply from: "./eas-build.gradle"'
);
});
});
describe('ios generic job', () => {
Expand Down
58 changes: 15 additions & 43 deletions packages/expo-cli/src/commands/eas-build/build/action.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getConfig } from '@expo/config';
import { ApiV2, User, UserManager } from '@expo/xdl';
import { ApiV2 } from '@expo/xdl';
import chalk from 'chalk';
import delayAsync from 'delay-async';
import fs from 'fs-extra';
Expand All @@ -8,22 +7,23 @@ import os from 'os';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';

import CommandError from '../../../CommandError';
import { EasConfig, EasJsonReader } from '../../../easJson';
import log from '../../../log';
import { ensureProjectExistsAsync } from '../../../projects';
import { UploadType, uploadAsync } from '../../../uploads';
import { createProgressTracker } from '../../utils/progress';
import { platformDisplayNames } from '../constants';
import { Build, BuildCommandPlatform, BuildStatus } from '../types';
import AndroidBuilder from './builders/AndroidBuilder';
import iOSBuilder from './builders/iOSBuilder';
import { Builder, BuilderContext } from './types';
import { Build, BuildCommandPlatform, BuildStatus, Builder, BuilderContext } from '../types';
import createBuilderContextAsync from '../utils/createBuilderContextAsync';
import {
ensureGitRepoExistsAsync,
ensureGitStatusIsCleanAsync,
makeProjectTarballAsync,
} from './utils/git';
import { printBuildResults, printLogsUrls } from './utils/misc';
} from '../utils/git';
import { printBuildResults, printLogsUrls } from '../utils/misc';
import AndroidBuilder from './builders/AndroidBuilder';
import iOSBuilder from './builders/iOSBuilder';

interface BuildOptions {
platform: BuildCommandPlatform;
Expand Down Expand Up @@ -77,40 +77,6 @@ async function buildAction(projectDir: string, options: BuildOptions): Promise<v
}
}

async function createBuilderContextAsync(
projectDir: string,
eas: EasConfig,
{
platform = BuildCommandPlatform.ALL,
nonInteractive = false,
skipCredentialsCheck = false,
skipProjectConfiguration = false,
}: {
platform?: BuildCommandPlatform;
nonInteractive?: boolean;
skipCredentialsCheck?: boolean;
skipProjectConfiguration?: boolean;
}
): Promise<BuilderContext> {
const user: User = await UserManager.ensureLoggedInAsync();
const { exp } = getConfig(projectDir, { skipSDKVersionRequirement: true });
const accountName = exp.owner || user.username;
const projectName = exp.slug;

return {
eas,
projectDir,
user,
accountName,
projectName,
exp,
platform,
nonInteractive,
skipCredentialsCheck,
skipProjectConfiguration,
};
}

async function startBuildsAsync(
ctx: BuilderContext,
projectId: string
Expand Down Expand Up @@ -145,7 +111,13 @@ async function startBuildAsync(
await builder.ensureCredentialsAsync();

if (!builder.ctx.skipProjectConfiguration) {
await builder.configureProjectAsync();
if (builder instanceof iOSBuilder) {
await builder.configureProjectAsync();
} else if (!(await builder.isProjectConfiguredAsync())) {
throw new CommandError(
'Project is not configured. Please run "expo eas:build:init" first to configure the project'
);
}
}

const fileSize = await makeProjectTarballAsync(tarPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ import {
} from '../../../../easJson';
import { gitAddAsync } from '../../../../git';
import log from '../../../../log';
import { Builder, BuilderContext } from '../../types';
import * as gitUtils from '../../utils/git';
import { ensureCredentialsAsync } from '../credentials';
import gradleContent from '../templates/gradleContent';
import { Builder, BuilderContext } from '../types';
import * as gitUtils from '../utils/git';

interface CommonJobProperties {
platform: Platform.Android;
Expand Down Expand Up @@ -60,9 +60,32 @@ class AndroidBuilder implements Builder {
this.credentials = await provider.getCredentialsAsync(credentialsSource);
}

public async isProjectConfiguredAsync(): Promise<boolean> {
const androidAppDir = path.join(this.ctx.projectDir, 'android', 'app');
const buildGradlePath = path.join(androidAppDir, 'build.gradle');
const easGradlePath = path.join(androidAppDir, 'eas-build.gradle');

const hasEasGradleFile = await fs.pathExists(easGradlePath);

const buildGradleContent = await fs.readFile(path.join(buildGradlePath), 'utf-8');
const applyEasGradle = 'apply from: "./eas-build.gradle"';

const hasEasGradleApply = buildGradleContent
.split('\n')
// Check for both single and double quotes
.some(line => line === applyEasGradle || line === applyEasGradle.replace(/"/g, "'"));

return hasEasGradleApply && hasEasGradleFile;
}

public async configureProjectAsync(): Promise<void> {
const spinner = ora('Making sure your Android project is set up properly');

if (await this.isProjectConfiguredAsync()) {
spinner.succeed('Android project is already configured');
return;
}

const { projectDir } = this.ctx;

const androidAppDir = path.join(projectDir, 'android', 'app');
Expand All @@ -75,14 +98,7 @@ class AndroidBuilder implements Builder {
const buildGradleContent = await fs.readFile(path.join(buildGradlePath), 'utf-8');
const applyEasGradle = 'apply from: "./eas-build.gradle"';

const isAlreadyConfigured = buildGradleContent
.split('\n')
// Check for both single and double quotes
.some(line => line === applyEasGradle || line === applyEasGradle.replace(/"/g, "'"));

if (!isAlreadyConfigured) {
await fs.writeFile(buildGradlePath, `${buildGradleContent.trim()}\n${applyEasGradle}\n`);
}
await fs.writeFile(buildGradlePath, `${buildGradleContent.trim()}\n${applyEasGradle}\n`);

try {
await gitUtils.ensureGitStatusIsCleanAsync();
Expand All @@ -100,7 +116,7 @@ class AndroidBuilder implements Builder {
log(`${chalk.green(figures.tick)} Successfully committed the configuration changes.`);
} catch (e) {
throw new Error(
"Aborting, run the build command once you're ready. Make sure to commit any changes you've made."
"Aborting, run the command again once you're ready. Make sure to commit any changes you've made."
);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import {
iOSManagedBuildProfile,
} from '../../../../easJson';
import log from '../../../../log';
import { Builder, BuilderContext } from '../../types';
import * as gitUtils from '../../utils/git';
import { ensureCredentialsAsync } from '../credentials';
import { Builder, BuilderContext } from '../types';
import * as gitUtils from '../utils/git';
import { getBundleIdentifier } from '../utils/ios';

interface CommonJobProperties {
Expand Down Expand Up @@ -73,16 +73,22 @@ class iOSBuilder implements Builder {
this.credentials = await provider.getCredentialsAsync(credentialsSource);
}

public async isProjectConfiguredAsync(): Promise<boolean> {
// TODO: implement this later
throw new Error('Not implemented.');
}

public async configureProjectAsync(): Promise<void> {
// TODO: add simulator flow
// assuming we're building for app store
if (!this.credentials) {
throw new Error('Call ensureCredentialsAsync first!');
}
const bundleIdentifier = await getBundleIdentifier(this.ctx.projectDir, this.ctx.exp);

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

const bundleIdentifier = await getBundleIdentifier(this.ctx.projectDir, this.ctx.exp);

const profileName = ProvisioningProfileUtils.readProfileName(
this.credentials.provisioningProfile
);
Expand Down Expand Up @@ -111,7 +117,7 @@ class iOSBuilder implements Builder {
log(`${chalk.green(figures.tick)} Successfully committed the configuration changes.`);
} catch (e) {
throw new Error(
"Aborting, run the build command once you're ready. Make sure to commit any changes you've made."
"Aborting, run the command again once you're ready. Make sure to commit any changes you've made."
);
}
} else {
Expand Down
26 changes: 0 additions & 26 deletions packages/expo-cli/src/commands/eas-build/build/types.ts

This file was deleted.

16 changes: 14 additions & 2 deletions packages/expo-cli/src/commands/eas-build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ import path from 'path';

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

export default function (program: Command) {
// don't register `expo eas:build:*` commands if eas.json doesn't exist
const easJsonPath = path.join(process.cwd(), 'eas.json');
if (!fs.pathExistsSync(easJsonPath)) {
const hasEasJson = fs.pathExistsSync(easJsonPath);

if (hasEasJson || process.argv[2] !== '--help') {
// We don't want to show this in the help output for now
program
.command('eas:build:init [project-dir]')
.description('Initialize build configuration for your project.')
.option('--skip-credentials-check', 'Skip checking credentials', false)
.asyncActionProjectDir(initAction, { checkConfig: true });
}

if (!hasEasJson) {
return;
}

Expand All @@ -26,7 +38,7 @@ export default function (program: Command) {
.description('Build an app binary for your project.')
.option(
'-p --platform <platform>',
'Build for specified platform: ios, android, all',
'Build for the specified platform: ios, android, all',
/^(all|android|ios)$/i
)
.option('--skip-credentials-check', 'Skip checking credentials', false)
Expand Down
Loading

0 comments on commit 10fca19

Please sign in to comment.