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

[expo-cli] detect git changes on credentials.json update #2482

Merged
merged 2 commits into from
Aug 21, 2020
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
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: warn user when credentials are not git ignored ([#2482](https://github.com/expo/expo-cli/pull/2482)) by [@wkozyra95](https://github.com/wkozyra95)

### 🐛 Bug fixes

### 📦 Packages updated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jest.mock('../../../../projects', () => {
};
});
jest.mock('../utils/git');
jest.mock('../../../../git');
jest.mock('../../../../uploads', () => ({
UploadType: {},
uploadAsync: () => mockProjectUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
AndroidManagedBuildProfile,
Workflow,
} from '../../../../easJson';
import { gitAddAsync } from '../../../../git';
import log from '../../../../log';
import { ensureCredentialsAsync } from '../credentials';
import gradleContent from '../templates/gradleContent';
Expand Down Expand Up @@ -69,7 +70,7 @@ class AndroidBuilder implements Builder {
const easGradlePath = path.join(androidAppDir, 'eas-build.gradle');

await fs.writeFile(easGradlePath, gradleContent);
await gitUtils.addFileAsync(easGradlePath, { intentToAdd: true });
await gitAddAsync(easGradlePath, { intentToAdd: true });

const buildGradleContent = await fs.readFile(path.join(buildGradlePath), 'utf-8');
const applyEasGradle = 'apply from: "./eas-build.gradle"';
Expand Down
19 changes: 3 additions & 16 deletions packages/expo-cli/src/commands/eas-build/build/utils/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import fs from 'fs-extra';
import ora from 'ora';

import CommandError from '../../../../CommandError';
import { gitDiffAsync, gitStatusAsync } from '../../../../git';
import log from '../../../../log';
import prompts from '../../../../prompts';

async function ensureGitStatusIsCleanAsync(): Promise<void> {
const changes = (await spawnAsync('git', ['status', '-s', '-uno'])).stdout;
const changes = await gitStatusAsync();
if (changes.length > 0) {
throw new DirtyGitTreeError(
'Please commit all changes before building your project. Aborting...'
Expand All @@ -34,18 +35,6 @@ async function makeProjectTarballAsync(tarPath: string): Promise<number> {
return size;
}

async function showDiffAsync(): Promise<void> {
await spawnAsync('git', ['--no-pager', 'diff'], { stdio: ['ignore', 'inherit', 'inherit'] });
}

async function addFileAsync(file: string, options?: { intentToAdd?: boolean }): Promise<void> {
if (options?.intentToAdd) {
await spawnAsync('git', ['add', '--intent-to-add', file]);
} else {
await spawnAsync('git', ['add', file]);
}
}

async function reviewAndCommitChangesAsync(
commitMessage: string,
{ nonInteractive }: { nonInteractive: boolean }
Expand All @@ -58,7 +47,7 @@ async function reviewAndCommitChangesAsync(

log('Please review the following changes and pass the message to make the commit.');
log.newLine();
await showDiffAsync();
await gitDiffAsync();
log.newLine();

const { confirm } = await prompts({
Expand Down Expand Up @@ -89,6 +78,4 @@ export {
ensureGitStatusIsCleanAsync,
makeProjectTarballAsync,
reviewAndCommitChangesAsync,
showDiffAsync,
addFileAsync,
};
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('update credentials.json', () => {
expect(credJson).toEqual({
android: {
keystore: {
keystorePath: './android/keystores/keystore.jks',
keystorePath: 'android/keystores/keystore.jks',
keystorePassword: testKeystore.keystorePassword,
keyAlias: testKeystore.keyAlias,
keyPassword: testKeystore.keyPassword,
Expand Down Expand Up @@ -120,7 +120,7 @@ describe('update credentials.json', () => {
expect(credJson).toEqual({
android: {
keystore: {
keystorePath: './android/keystores/keystore.jks',
keystorePath: 'android/keystores/keystore.jks',
keystorePassword: testKeystore.keystorePassword,
keyAlias: testKeystore.keyAlias,
keyPassword: testKeystore.keyPassword,
Expand Down Expand Up @@ -208,9 +208,9 @@ describe('update credentials.json', () => {
expect(pprofile).toEqual(testAllCredentialsForApp.credentials.provisioningProfile);
expect(credJson).toEqual({
ios: {
provisioningProfilePath: './ios/certs/profile.mobileprovision',
provisioningProfilePath: 'ios/certs/profile.mobileprovision',
distributionCertificate: {
path: './ios/certs/dist-cert.p12',
path: 'ios/certs/dist-cert.p12',
password: testAllCredentialsForApp.distCredentials.certPassword,
},
},
Expand Down
58 changes: 55 additions & 3 deletions packages/expo-cli/src/credentials/credentialsJson/update.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs-extra';
import path from 'path';

import { gitStatusAsync } from '../../git';
import log from '../../log';
import prompts from '../../prompts';
import { Context } from '../context';
Expand Down Expand Up @@ -42,9 +43,10 @@ export async function updateAndroidCredentialsAsync(ctx: Context) {
}

const keystorePath =
rawCredentialsJsonObject?.android?.keystore?.keystorePath ?? './android/keystores/keystore.jks';
rawCredentialsJsonObject?.android?.keystore?.keystorePath ?? 'android/keystores/keystore.jks';
log(`Writing Keystore to ${keystorePath}`);
await updateFileAsync(ctx.projectDir, keystorePath, keystore.keystore);
const shouldWarnKeystore = await isFileUntrackedAsync(keystorePath);

rawCredentialsJsonObject.android = {
keystore: {
Expand All @@ -57,6 +59,16 @@ export async function updateAndroidCredentialsAsync(ctx: Context) {
await fs.writeJson(credentialsJsonFilePath, rawCredentialsJsonObject, {
spaces: 2,
});
const shouldWarnCredentialsJson = await isFileUntrackedAsync('credentials.json');

const newFilePaths = [];
if (shouldWarnKeystore) {
newFilePaths.push(keystorePath);
}
if (shouldWarnCredentialsJson) {
newFilePaths.push('credentials.json');
}
displayUntrackedFilesWarning(newFilePaths);
}

export async function updateIosCredentialsAsync(ctx: Context, bundleIdentifier: string) {
Expand All @@ -79,9 +91,9 @@ export async function updateIosCredentialsAsync(ctx: Context, bundleIdentifier:
bundleIdentifier,
};
const pprofilePath =
rawCredentialsJsonObject?.ios?.provisioningProfilePath ?? './ios/certs/profile.mobileprovision';
rawCredentialsJsonObject?.ios?.provisioningProfilePath ?? 'ios/certs/profile.mobileprovision';
const distCertPath =
rawCredentialsJsonObject?.ios?.distributionCertificate?.path ?? './ios/certs/dist-cert.p12';
rawCredentialsJsonObject?.ios?.distributionCertificate?.path ?? 'ios/certs/dist-cert.p12';
const appCredentials = await ctx.ios.getAppCredentials(appLookupParams);
const distCredentials = await ctx.ios.getDistCert(appLookupParams);
if (!appCredentials?.credentials?.provisioningProfile && !distCredentials) {
Expand Down Expand Up @@ -113,8 +125,11 @@ export async function updateIosCredentialsAsync(ctx: Context, bundleIdentifier:
pprofilePath,
appCredentials?.credentials?.provisioningProfile
);
const shouldWarnPProfile = await isFileUntrackedAsync(pprofilePath);

log(`Writing Distribution Certificate to ${distCertPath}`);
await updateFileAsync(ctx.projectDir, distCertPath, distCredentials?.certP12);
const shouldWarnDistCert = await isFileUntrackedAsync(distCertPath);

rawCredentialsJsonObject.ios = {
...(appCredentials?.credentials?.provisioningProfile
Expand All @@ -132,6 +147,19 @@ export async function updateIosCredentialsAsync(ctx: Context, bundleIdentifier:
await fs.writeJson(credentialsJsonFilePath, rawCredentialsJsonObject, {
spaces: 2,
});
const shouldWarnCredentialsJson = await isFileUntrackedAsync('credentials.json');

const newFilePaths = [];
if (shouldWarnPProfile) {
newFilePaths.push(pprofilePath);
}
if (shouldWarnDistCert) {
newFilePaths.push(distCertPath);
}
if (shouldWarnCredentialsJson) {
newFilePaths.push('credentials.json');
}
displayUntrackedFilesWarning(newFilePaths);
}

async function updateFileAsync(projectDir: string, filePath: string, base64Data?: string) {
Expand All @@ -144,3 +172,27 @@ async function updateFileAsync(projectDir: string, filePath: string, base64Data?
await fs.writeFile(filePath, Buffer.from(base64Data, 'base64'));
}
}

async function isFileUntrackedAsync(path: string): Promise<boolean> {
const withUntrackedFiles = await gitStatusAsync({ showUntracked: true });
const trackedFiles = await gitStatusAsync({ showUntracked: false });
const pathWithoutLeadingDot = path.replace(/^\.\//, ''); // remove leading './' from path
return (
withUntrackedFiles.includes(pathWithoutLeadingDot) &&
!trackedFiles.includes(pathWithoutLeadingDot)
);
}

function displayUntrackedFilesWarning(newFilePaths: string[]) {
if (newFilePaths.length === 1) {
log.warn(
`File ${newFilePaths[0]} is currently untracked, remember to add it to .gitignore or to encrypt it. (e.g. with git-crypt)`
);
} else if (newFilePaths.length > 1) {
log.warn(
`Files ${newFilePaths.join(
', '
)} are currently untracked, remember to add them to .gitignore or to encrypt them. (e.g. with git-crypt)`
);
}
}
24 changes: 24 additions & 0 deletions packages/expo-cli/src/git.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import spawnAsync from '@expo/spawn-async';

interface GitStatusOptions {
showUntracked?: boolean;
}

export async function gitStatusAsync({ showUntracked }: GitStatusOptions = {}): Promise<string> {
return (await spawnAsync('git', ['status', '-s', showUntracked ? '-uall' : '-uno'])).stdout;
}

export async function gitDiffAsync(): Promise<void> {
await spawnAsync('git', ['--no-pager', 'diff'], { stdio: ['ignore', 'inherit', 'inherit'] });
}

export async function gitAddAsync(
file: string,
options?: { intentToAdd?: boolean }
): Promise<void> {
if (options?.intentToAdd) {
await spawnAsync('git', ['add', '--intent-to-add', file]);
} else {
await spawnAsync('git', ['add', file]);
}
}