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

[expo-cli] EAS Build support experimental.npmToken in credentials.json #2603

Merged
merged 2 commits into from
Sep 9, 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
4 changes: 3 additions & 1 deletion 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 `experimental.npmToken` to `credentials.json` [#2603](https://github.com/expo/expo-cli/pull/2603)

### 🐛 Bug fixes

## [Thu, 8 Sep 2020 14:30:14 +0200](https://github.com/expo/expo-cli/commit/f0e24ee436806c109c19329c7e161fee0d2f0c81)
Expand All @@ -32,7 +34,7 @@ This is the log of notable changes to Expo CLI and related packages.

### 🐛 Bug fixes

- [expo-cli] fix Segment context format [#2560](https://github.com/expo/expo-cli/pull/2560))
- [expo-cli] fix Segment context format [#2560](https://github.com/expo/expo-cli/pull/2560)

### 📦 Packages updated

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,13 @@ describe('build command', () => {
artifactPath: 'android/app/build/outputs/**/*.{apk,aab}',
gradleCommand: ':app:bundleRelease',
secrets: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
buildCredentials: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
},
},
},
});
Expand Down Expand Up @@ -251,11 +253,13 @@ describe('build command', () => {
artifactPath: 'ios/build/App.ipa',
scheme: 'testapp',
secrets: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
buildCredentials: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
},
provisioningProfileBase64: pprofile.base64,
},
provisioningProfileBase64: pprofile.base64,
},
});
});
Expand Down Expand Up @@ -293,11 +297,13 @@ describe('build command', () => {
artifactPath: 'android/app/build/outputs/**/*.{apk,aab}',
gradleCommand: ':app:bundleRelease',
secrets: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
buildCredentials: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
},
},
},
});
Expand All @@ -314,11 +320,13 @@ describe('build command', () => {
artifactPath: 'ios/build/App.ipa',
scheme: 'testapp',
secrets: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
buildCredentials: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
},
provisioningProfileBase64: pprofile.base64,
},
provisioningProfileBase64: pprofile.base64,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ora from 'ora';
import path from 'path';

import CommandError from '../../../../CommandError';
import { readSecretEnvsAsync } from '../../../../credentials/credentialsJson/read';
import AndroidCredentialsProvider, {
AndroidCredentials,
} from '../../../../credentials/provider/AndroidCredentialsProvider';
Expand All @@ -25,13 +26,17 @@ import gradleContent from '../templates/gradleContent';
interface CommonJobProperties {
platform: Platform.Android;
projectUrl: string;
secrets?: {
keystore: Android.Keystore;
secrets: {
buildCredentials?: {
keystore: Android.Keystore;
};
secretEnvs?: Record<string, string>;
};
}

class AndroidBuilder implements Builder<Platform.Android> {
private credentials?: AndroidCredentials;
private secretEnvs?: Record<string, string>;
private credentialsPrepared: boolean = false;

constructor(public readonly ctx: BuilderContext<Platform.Android>) {}
Expand All @@ -42,6 +47,7 @@ class AndroidBuilder implements Builder<Platform.Android> {
CredentialsSource.LOCAL | CredentialsSource.REMOTE | undefined
> {
this.credentialsPrepared = true;
this.secretEnvs = await readSecretEnvsAsync(this.ctx.commandCtx.projectDir);
if (!this.shouldLoadCredentials()) {
return;
}
Expand Down Expand Up @@ -152,9 +158,9 @@ class AndroidBuilder implements Builder<Platform.Android> {
}

private async prepareJobCommonAsync(archiveUrl: string): Promise<Partial<CommonJobProperties>> {
const secrets = this.credentials
const buildCredentials = this.credentials
? {
secrets: {
buildCredentials: {
keystore: {
dataBase64: this.credentials.keystore.keystore,
keystorePassword: this.credentials.keystore.keystorePassword,
Expand All @@ -168,7 +174,10 @@ class AndroidBuilder implements Builder<Platform.Android> {
return {
platform: Platform.Android,
projectUrl: archiveUrl,
...secrets,
secrets: {
...(this.secretEnvs ? { secretEnvs: this.secretEnvs } : {}),
...buildCredentials,
},
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ describe('AndroidBuilder', () => {
artifactPath: 'android/app/build/outputs/**/*.{apk,aab}',
gradleCommand: ':app:bundleRelease',
secrets: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
buildCredentials: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
},
},
},
});
Expand Down Expand Up @@ -109,11 +111,13 @@ describe('AndroidBuilder', () => {
packageJson: { example: 'packageJson' },
manifest: { example: 'manifest' },
secrets: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
buildCredentials: {
keystore: {
dataBase64: keystore.base64,
keystorePassword: 'keystorePassword',
keyAlias: 'keyAlias',
keyPassword: 'keyPassword',
},
},
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,13 @@ describe('iOSBuilder', () => {
scheme: 'testapp',
artifactPath: 'ios/build/App.ipa',
secrets: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
buildCredentials: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
},
provisioningProfileBase64: pprofile.base64,
},
provisioningProfileBase64: pprofile.base64,
},
});
}, 10000);
Expand Down Expand Up @@ -123,11 +125,13 @@ describe('iOSBuilder', () => {
packageJson: { example: 'packageJson' },
manifest: { example: 'manifest' },
secrets: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
buildCredentials: {
distributionCertificate: {
dataBase64: cert.base64,
password: 'certPass',
},
provisioningProfileBase64: pprofile.base64,
},
provisioningProfileBase64: pprofile.base64,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import figures from 'figures';
import sortBy from 'lodash/sortBy';
import ora from 'ora';

import { readSecretEnvsAsync } from '../../../../credentials/credentialsJson/read';
import iOSCredentialsProvider, {
iOSCredentials,
} from '../../../../credentials/provider/iOSCredentialsProvider';
Expand All @@ -25,17 +26,21 @@ import { getBundleIdentifier } from '../utils/ios';
interface CommonJobProperties {
platform: Platform.iOS;
projectUrl: string;
secrets?: {
provisioningProfileBase64: string;
distributionCertificate: {
dataBase64: string;
password: string;
secrets: {
buildCredentials?: {
provisioningProfileBase64: string;
distributionCertificate: {
dataBase64: string;
password: string;
};
};
secretEnvs?: Record<string, string>;
};
}

class iOSBuilder implements Builder<Platform.iOS> {
private credentials?: iOSCredentials;
private secretEnvs?: Record<string, string>;
private scheme?: string;

constructor(public readonly ctx: BuilderContext<Platform.iOS>) {}
Expand All @@ -53,6 +58,7 @@ class iOSBuilder implements Builder<Platform.iOS> {
public async ensureCredentialsAsync(): Promise<
CredentialsSource.LOCAL | CredentialsSource.REMOTE | undefined
> {
this.secretEnvs = await readSecretEnvsAsync(this.ctx.commandCtx.projectDir);
if (!this.shouldLoadCredentials()) {
return;
}
Expand Down Expand Up @@ -150,9 +156,9 @@ class iOSBuilder implements Builder<Platform.iOS> {
}

private async prepareJobCommonAsync(archiveUrl: string): Promise<Partial<CommonJobProperties>> {
const secrets = this.credentials
const buildCredentials = this.credentials
? {
secrets: {
buildCredentials: {
provisioningProfileBase64: this.credentials.provisioningProfile,
distributionCertificate: {
dataBase64: this.credentials.distributionCertificate.certP12,
Expand All @@ -165,7 +171,10 @@ class iOSBuilder implements Builder<Platform.iOS> {
return {
platform: Platform.iOS,
projectUrl: archiveUrl,
...secrets,
secrets: {
...(this.secretEnvs ? { secretEnvs: this.secretEnvs } : {}),
...buildCredentials,
},
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,29 @@ describe('credentialsJson', () => {
await expect(promise).rejects.toThrow("ENOENT: no such file or directory, open 'pprofile'");
});
});

describe('readSecretEnvsAsync', () => {
it('should read secretEnvs field correctly', async () => {
vol.fromJSON({
'./credentials.json': JSON.stringify({
ios: {
provisioningProfilePath: 'pprofile',
distributionCertificate: {
path: 'cert.p12',
password: 'certPass',
},
},
experimental: {
npmToken: 'VALUE',
},
}),
'./pprofile': 'somebinarycontent',
'./cert.p12': 'somebinarycontent2',
});
const result = await credentialsJsonReader.readSecretEnvsAsync('.');
expect(result).toEqual({
NPM_TOKEN: 'VALUE',
});
});
});
});
14 changes: 14 additions & 0 deletions packages/expo-cli/src/credentials/credentialsJson/read.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ interface CredentialsJson {
password: string;
};
};
experimental?: {
npmToken?: string;
};
}

const CredentialsJsonSchema = Joi.object({
Expand All @@ -38,6 +41,9 @@ const CredentialsJsonSchema = Joi.object({
password: Joi.string().required(),
}).required(),
}),
experimental: Joi.object({
npmToken: Joi.string(),
}),
});

interface AndroidCredentials {
Expand Down Expand Up @@ -92,6 +98,14 @@ export async function readIosCredentialsAsync(projectDir: string): Promise<iOSCr
};
}

export async function readSecretEnvsAsync(
projectDir: string
): Promise<Record<string, string> | undefined> {
const credentialsJson = await readAsync(projectDir);
const npmToken = credentialsJson?.experimental?.npmToken;
return npmToken ? { NPM_TOKEN: npmToken } : undefined;
}

async function readAsync(projectDir: string): Promise<CredentialsJson> {
const credentialsJSONRaw = await readRawAsync(projectDir);

Expand Down