@expo/eas-json 0.55.0 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,7 +16,7 @@ function resolveBuildProfile({ easJson, platform, profileName, }) {
16
16
  exports.resolveBuildProfile = resolveBuildProfile;
17
17
  function resolveProfile({ easJson, profileName, depth = 0, }) {
18
18
  var _a;
19
- if (depth >= 2) {
19
+ if (depth >= 5) {
20
20
  throw new Error('Too long chain of profile extensions, make sure "extends" keys do not make a cycle');
21
21
  }
22
22
  const profile = (_a = easJson.build) === null || _a === void 0 ? void 0 : _a[profileName];
package/build/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { AndroidReleaseStatus, AndroidReleaseTrack, SubmitProfile } from './submit/types';
2
2
  export { getDefaultProfile as getDefaultSubmitProfile } from './submit/resolver';
3
- export { EasJson, ProfileType } from './types';
3
+ export { EasJson, ProfileType, AppVersionSource } from './types';
4
4
  export { AndroidVersionAutoIncrement, BuildProfile, CredentialsSource, DistributionType, IosEnterpriseProvisioning, IosVersionAutoIncrement, } from './build/types';
5
5
  export { EasJsonReader } from './reader';
6
6
  export * as errors from './errors';
package/build/index.js CHANGED
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.errors = exports.EasJsonReader = exports.CredentialsSource = exports.getDefaultSubmitProfile = exports.AndroidReleaseTrack = exports.AndroidReleaseStatus = void 0;
3
+ exports.errors = exports.EasJsonReader = exports.CredentialsSource = exports.AppVersionSource = exports.getDefaultSubmitProfile = exports.AndroidReleaseTrack = exports.AndroidReleaseStatus = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  var types_1 = require("./submit/types");
6
6
  Object.defineProperty(exports, "AndroidReleaseStatus", { enumerable: true, get: function () { return types_1.AndroidReleaseStatus; } });
7
7
  Object.defineProperty(exports, "AndroidReleaseTrack", { enumerable: true, get: function () { return types_1.AndroidReleaseTrack; } });
8
8
  var resolver_1 = require("./submit/resolver");
9
9
  Object.defineProperty(exports, "getDefaultSubmitProfile", { enumerable: true, get: function () { return resolver_1.getDefaultProfile; } });
10
- var types_2 = require("./build/types");
11
- Object.defineProperty(exports, "CredentialsSource", { enumerable: true, get: function () { return types_2.CredentialsSource; } });
10
+ var types_2 = require("./types");
11
+ Object.defineProperty(exports, "AppVersionSource", { enumerable: true, get: function () { return types_2.AppVersionSource; } });
12
+ var types_3 = require("./build/types");
13
+ Object.defineProperty(exports, "CredentialsSource", { enumerable: true, get: function () { return types_3.CredentialsSource; } });
12
14
  var reader_1 = require("./reader");
13
15
  Object.defineProperty(exports, "EasJsonReader", { enumerable: true, get: function () { return reader_1.EasJsonReader; } });
14
16
  exports.errors = tslib_1.__importStar(require("./errors"));
package/build/schema.js CHANGED
@@ -5,10 +5,12 @@ const tslib_1 = require("tslib");
5
5
  const joi_1 = tslib_1.__importDefault(require("joi"));
6
6
  const schema_1 = require("./build/schema");
7
7
  const schema_2 = require("./submit/schema");
8
+ const types_1 = require("./types");
8
9
  exports.EasJsonSchema = joi_1.default.object({
9
10
  cli: joi_1.default.object({
10
11
  version: joi_1.default.string(),
11
12
  requireCommit: joi_1.default.boolean(),
13
+ appVersionSource: joi_1.default.string().valid(...Object.values(types_1.AppVersionSource)),
12
14
  }),
13
15
  build: joi_1.default.object().pattern(joi_1.default.string(), schema_1.BuildProfileSchema),
14
16
  submit: joi_1.default.object().pattern(joi_1.default.string(), schema_2.SubmitProfileSchema),
package/build/types.d.ts CHANGED
@@ -6,10 +6,15 @@ export declare enum CredentialsSource {
6
6
  LOCAL = "local",
7
7
  REMOTE = "remote"
8
8
  }
9
+ export declare enum AppVersionSource {
10
+ LOCAL = "local",
11
+ REMOTE = "remote"
12
+ }
9
13
  export interface EasJson {
10
14
  cli?: {
11
15
  version?: string;
12
16
  requireCommit?: boolean;
17
+ appVersionSource?: AppVersionSource;
13
18
  };
14
19
  build?: {
15
20
  [profileName: string]: EasJsonBuildProfile;
package/build/types.js CHANGED
@@ -1,8 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CredentialsSource = void 0;
3
+ exports.AppVersionSource = exports.CredentialsSource = void 0;
4
4
  var CredentialsSource;
5
5
  (function (CredentialsSource) {
6
6
  CredentialsSource["LOCAL"] = "local";
7
7
  CredentialsSource["REMOTE"] = "remote";
8
8
  })(CredentialsSource = exports.CredentialsSource || (exports.CredentialsSource = {}));
9
+ var AppVersionSource;
10
+ (function (AppVersionSource) {
11
+ AppVersionSource["LOCAL"] = "local";
12
+ AppVersionSource["REMOTE"] = "remote";
13
+ })(AppVersionSource = exports.AppVersionSource || (exports.AppVersionSource = {}));
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@expo/eas-json",
3
3
  "description": "A library for interacting with eas.json",
4
- "version": "0.55.0",
4
+ "version": "0.58.0",
5
5
  "author": "Expo <support@expo.dev>",
6
6
  "bugs": "https://github.com/expo/eas-cli/issues",
7
7
  "dependencies": {
8
- "@expo/eas-build-job": "0.2.77",
8
+ "@expo/eas-build-job": "0.2.85",
9
9
  "@expo/json-file": "8.2.36",
10
10
  "chalk": "4.1.2",
11
11
  "env-string": "1.0.1",
@@ -36,8 +36,15 @@
36
36
  "test": "jest",
37
37
  "clean": "rm -rf build node_modules yarn-error.log"
38
38
  },
39
+ "files": [
40
+ "/build"
41
+ ],
39
42
  "publishConfig": {
40
43
  "access": "public"
41
44
  },
42
- "gitHead": "be38117012a25011044440d48b6125cfed8aac2a"
45
+ "volta": {
46
+ "node": "18.6.0",
47
+ "yarn": "1.22.19"
48
+ },
49
+ "gitHead": "bb249345a77f7d4a179301cf1260ac56e1809083"
43
50
  }
package/__mocks__/fs.ts DELETED
@@ -1,6 +0,0 @@
1
- import { fs } from 'memfs';
2
-
3
- // fs-extra@10 is not compatible with memfs, the following line fixes tests
4
- (fs.realpath as any).native = jest.fn();
5
-
6
- module.exports = fs;
package/jest.config.js DELETED
@@ -1,5 +0,0 @@
1
- module.exports = {
2
- ...require('../../jest/jest.config.js'),
3
- rootDir: __dirname,
4
- roots: ['src', '__mocks__'],
5
- };
@@ -1,290 +0,0 @@
1
- import { Platform } from '@expo/eas-build-job';
2
- import fs from 'fs-extra';
3
- import { vol } from 'memfs';
4
-
5
- import { EasJsonReader } from '../reader';
6
-
7
- jest.mock('fs');
8
-
9
- beforeEach(async () => {
10
- vol.reset();
11
- await fs.mkdirp('/project');
12
- });
13
-
14
- test('minimal valid eas.json for both platforms', async () => {
15
- await fs.writeJson('/project/eas.json', {
16
- build: {
17
- production: {},
18
- },
19
- });
20
-
21
- const reader = new EasJsonReader('/project');
22
- const iosProfile = await reader.getBuildProfileAsync(Platform.IOS, 'production');
23
- const androidProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'production');
24
-
25
- expect(androidProfile).toEqual({
26
- distribution: 'store',
27
- credentialsSource: 'remote',
28
- });
29
-
30
- expect(iosProfile).toEqual({
31
- distribution: 'store',
32
- credentialsSource: 'remote',
33
- });
34
- });
35
-
36
- test('valid eas.json for development client builds', async () => {
37
- await fs.writeJson('/project/eas.json', {
38
- build: {
39
- production: {},
40
- debug: {
41
- developmentClient: true,
42
- android: {
43
- withoutCredentials: true,
44
- },
45
- },
46
- },
47
- });
48
-
49
- const reader = new EasJsonReader('/project');
50
- const iosProfile = await reader.getBuildProfileAsync(Platform.IOS, 'debug');
51
- const androidProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'debug');
52
- expect(androidProfile).toEqual({
53
- credentialsSource: 'remote',
54
- distribution: 'store',
55
- developmentClient: true,
56
- withoutCredentials: true,
57
- });
58
-
59
- expect(iosProfile).toEqual({
60
- credentialsSource: 'remote',
61
- distribution: 'store',
62
- developmentClient: true,
63
- });
64
- });
65
-
66
- test('valid profile for internal distribution on Android', async () => {
67
- await fs.writeJson('/project/eas.json', {
68
- build: {
69
- internal: {
70
- distribution: 'internal',
71
- },
72
- },
73
- });
74
-
75
- const reader = new EasJsonReader('/project');
76
- const profile = await reader.getBuildProfileAsync(Platform.ANDROID, 'internal');
77
- expect(profile).toEqual({
78
- distribution: 'internal',
79
- credentialsSource: 'remote',
80
- });
81
- });
82
-
83
- test('valid profile extending other profile', async () => {
84
- await fs.writeJson('/project/eas.json', {
85
- build: {
86
- base: {
87
- node: '12.0.0',
88
- },
89
- extension: {
90
- extends: 'base',
91
- distribution: 'internal',
92
- node: '13.0.0',
93
- },
94
- },
95
- });
96
-
97
- const reader = new EasJsonReader('/project');
98
- const baseProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'base');
99
- const extendedProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'extension');
100
- expect(baseProfile).toEqual({
101
- distribution: 'store',
102
- credentialsSource: 'remote',
103
- node: '12.0.0',
104
- });
105
- expect(extendedProfile).toEqual({
106
- distribution: 'internal',
107
- credentialsSource: 'remote',
108
- node: '13.0.0',
109
- });
110
- });
111
-
112
- test('valid profile extending other profile with platform specific envs', async () => {
113
- await fs.writeJson('/project/eas.json', {
114
- build: {
115
- base: {
116
- env: {
117
- BASE_ENV: '1',
118
- PROFILE: 'base',
119
- },
120
- },
121
- extension: {
122
- extends: 'base',
123
- distribution: 'internal',
124
- env: {
125
- PROFILE: 'extension',
126
- },
127
- android: {
128
- env: {
129
- PROFILE: 'extension:android',
130
- },
131
- },
132
- },
133
- },
134
- });
135
-
136
- const reader = new EasJsonReader('/project');
137
- const baseProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'base');
138
- const extendedAndroidProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'extension');
139
- const extendedIosProfile = await reader.getBuildProfileAsync(Platform.IOS, 'extension');
140
- expect(baseProfile).toEqual({
141
- distribution: 'store',
142
- credentialsSource: 'remote',
143
- env: {
144
- BASE_ENV: '1',
145
- PROFILE: 'base',
146
- },
147
- });
148
- expect(extendedAndroidProfile).toEqual({
149
- distribution: 'internal',
150
- credentialsSource: 'remote',
151
- env: {
152
- BASE_ENV: '1',
153
- PROFILE: 'extension:android',
154
- },
155
- });
156
- expect(extendedIosProfile).toEqual({
157
- distribution: 'internal',
158
- credentialsSource: 'remote',
159
- env: {
160
- BASE_ENV: '1',
161
- PROFILE: 'extension',
162
- },
163
- });
164
- });
165
-
166
- test('valid profile extending other profile with platform specific caching', async () => {
167
- await fs.writeJson('/project/eas.json', {
168
- build: {
169
- base: {
170
- cache: {
171
- disabled: true,
172
- },
173
- },
174
- extension: {
175
- extends: 'base',
176
- distribution: 'internal',
177
- cache: {
178
- key: 'extend-key',
179
- },
180
- android: {
181
- cache: {
182
- cacheDefaultPaths: false,
183
- customPaths: ['somefakepath'],
184
- },
185
- },
186
- },
187
- },
188
- });
189
-
190
- const reader = new EasJsonReader('/project');
191
- const baseProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'base');
192
- const extendedAndroidProfile = await reader.getBuildProfileAsync(Platform.ANDROID, 'extension');
193
- const extendedIosProfile = await reader.getBuildProfileAsync(Platform.IOS, 'extension');
194
- expect(baseProfile).toEqual({
195
- distribution: 'store',
196
- credentialsSource: 'remote',
197
- cache: {
198
- disabled: true,
199
- },
200
- });
201
- expect(extendedAndroidProfile).toEqual({
202
- distribution: 'internal',
203
- credentialsSource: 'remote',
204
- cache: {
205
- cacheDefaultPaths: false,
206
- customPaths: ['somefakepath'],
207
- },
208
- });
209
- expect(extendedIosProfile).toEqual({
210
- distribution: 'internal',
211
- credentialsSource: 'remote',
212
-
213
- cache: {
214
- key: 'extend-key',
215
- },
216
- });
217
- });
218
-
219
- test('valid eas.json with missing profile', async () => {
220
- await fs.writeJson('/project/eas.json', {
221
- build: {
222
- production: {},
223
- },
224
- });
225
-
226
- const reader = new EasJsonReader('/project');
227
- const promise = reader.getBuildProfileAsync(Platform.ANDROID, 'debug');
228
- await expect(promise).rejects.toThrowError('Missing build profile in eas.json: debug');
229
- });
230
-
231
- test('invalid eas.json when using wrong buildType', async () => {
232
- await fs.writeJson('/project/eas.json', {
233
- build: {
234
- production: { android: { buildType: 'archive' } },
235
- },
236
- });
237
-
238
- const reader = new EasJsonReader('/project');
239
- const promise = reader.getBuildProfileAsync(Platform.ANDROID, 'production');
240
- await expect(promise).rejects.toThrowError(
241
- 'eas.json is not valid [ValidationError: "build.production.android.buildType" must be one of [apk, app-bundle]]'
242
- );
243
- });
244
-
245
- test('empty json', async () => {
246
- await fs.writeJson('/project/eas.json', {});
247
-
248
- const reader = new EasJsonReader('/project');
249
- const promise = reader.getBuildProfileAsync(Platform.ANDROID, 'production');
250
- await expect(promise).rejects.toThrowError('Missing build profile in eas.json: production');
251
- });
252
-
253
- test('invalid semver value', async () => {
254
- await fs.writeJson('/project/eas.json', {
255
- build: {
256
- production: { node: 'alpha' },
257
- },
258
- });
259
-
260
- const reader = new EasJsonReader('/project');
261
- const promise = reader.getBuildProfileAsync(Platform.ANDROID, 'production');
262
- await expect(promise).rejects.toThrowError(
263
- 'eas.json is not valid [ValidationError: "build.production.node" failed custom validation because alpha is not a valid version]'
264
- );
265
- });
266
-
267
- test('invalid release channel', async () => {
268
- await fs.writeJson('/project/eas.json', {
269
- build: {
270
- production: { releaseChannel: 'feature/myfeature' },
271
- },
272
- });
273
-
274
- const reader = new EasJsonReader('/project');
275
- const promise = reader.getBuildProfileAsync(Platform.ANDROID, 'production');
276
- await expect(promise).rejects.toThrowError(/fails to match the required pattern/);
277
- });
278
-
279
- test('get profile names', async () => {
280
- await fs.writeJson('/project/eas.json', {
281
- build: {
282
- production: { node: '12.0.0-alpha' },
283
- blah: { node: '12.0.0' },
284
- },
285
- });
286
-
287
- const reader = new EasJsonReader('/project');
288
- const allProfileNames = await reader.getBuildProfileNamesAsync();
289
- expect(allProfileNames.sort()).toEqual(['blah', 'production'].sort());
290
- });
@@ -1,222 +0,0 @@
1
- import { Platform } from '@expo/eas-build-job';
2
- import fs from 'fs-extra';
3
- import { vol } from 'memfs';
4
-
5
- import { EasJsonReader } from '../reader';
6
-
7
- jest.mock('fs');
8
-
9
- beforeEach(async () => {
10
- vol.reset();
11
- await fs.mkdirp('/project');
12
- });
13
-
14
- test('minimal allowed eas.json for both platforms', async () => {
15
- await fs.writeJson('/project/eas.json', {
16
- submit: {
17
- production: {},
18
- },
19
- });
20
-
21
- const reader = new EasJsonReader('/project');
22
- const iosProfile = await reader.getSubmitProfileAsync(Platform.IOS, 'production');
23
- const androidProfile = await reader.getSubmitProfileAsync(Platform.ANDROID, 'production');
24
-
25
- expect(androidProfile).toEqual({
26
- changesNotSentForReview: false,
27
- releaseStatus: 'completed',
28
- track: 'internal',
29
- });
30
- expect(iosProfile).toEqual({
31
- language: 'en-US',
32
- });
33
- });
34
-
35
- test('android config with all required values', async () => {
36
- await fs.writeJson('/project/eas.json', {
37
- submit: {
38
- production: {
39
- android: {
40
- serviceAccountKeyPath: './path.json',
41
- track: 'beta',
42
- releaseStatus: 'completed',
43
- },
44
- },
45
- },
46
- });
47
-
48
- const reader = new EasJsonReader('/project');
49
- const androidProfile = await reader.getSubmitProfileAsync(Platform.ANDROID, 'production');
50
-
51
- expect(androidProfile).toEqual({
52
- serviceAccountKeyPath: './path.json',
53
- track: 'beta',
54
- releaseStatus: 'completed',
55
- changesNotSentForReview: false,
56
- });
57
- });
58
-
59
- test('android config with serviceAccountKeyPath set to env var', async () => {
60
- await fs.writeJson('/project/eas.json', {
61
- submit: {
62
- production: {
63
- android: {
64
- serviceAccountKeyPath: '$GOOGLE_SERVICE_ACCOUNT',
65
- track: 'beta',
66
- releaseStatus: 'completed',
67
- },
68
- },
69
- },
70
- });
71
-
72
- try {
73
- process.env.GOOGLE_SERVICE_ACCOUNT = './path.json';
74
- const reader = new EasJsonReader('/project');
75
- const androidProfile = await reader.getSubmitProfileAsync(Platform.ANDROID, 'production');
76
-
77
- expect(androidProfile).toEqual({
78
- serviceAccountKeyPath: './path.json',
79
- track: 'beta',
80
- releaseStatus: 'completed',
81
- changesNotSentForReview: false,
82
- });
83
- } finally {
84
- process.env.GOOGLE_SERVICE_ACCOUNT = undefined;
85
- }
86
- });
87
-
88
- test('ios config with all required values', async () => {
89
- await fs.writeJson('/project/eas.json', {
90
- submit: {
91
- production: {
92
- ios: {
93
- appleId: 'some@email.com',
94
- ascAppId: '1223423523',
95
- appleTeamId: 'QWERTY',
96
- ascApiKeyPath: './path-ABCD.p8',
97
- ascApiKeyIssuerId: 'abc-123-def-456',
98
- ascApiKeyId: 'ABCD',
99
- },
100
- },
101
- },
102
- });
103
-
104
- const reader = new EasJsonReader('/project');
105
- const iosProfile = await reader.getSubmitProfileAsync(Platform.IOS, 'production');
106
-
107
- expect(iosProfile).toEqual({
108
- appleId: 'some@email.com',
109
- appleTeamId: 'QWERTY',
110
- ascAppId: '1223423523',
111
- ascApiKeyPath: './path-ABCD.p8',
112
- ascApiKeyIssuerId: 'abc-123-def-456',
113
- ascApiKeyId: 'ABCD',
114
- language: 'en-US',
115
- });
116
- });
117
-
118
- test('ios config with ascApiKey fields set to env var', async () => {
119
- await fs.writeJson('/project/eas.json', {
120
- submit: {
121
- release: {
122
- ios: {
123
- appleId: 'some@email.com',
124
- ascAppId: '1223423523',
125
- appleTeamId: 'QWERTY',
126
- ascApiKeyPath: '$ASC_API_KEY_PATH',
127
- ascApiKeyIssuerId: '$ASC_API_KEY_ISSUER_ID',
128
- ascApiKeyId: '$ASC_API_KEY_ID',
129
- },
130
- },
131
- },
132
- });
133
-
134
- try {
135
- process.env.ASC_API_KEY_PATH = './path-ABCD.p8';
136
- process.env.ASC_API_KEY_ISSUER_ID = 'abc-123-def-456';
137
- process.env.ASC_API_KEY_ID = 'ABCD';
138
- const reader = new EasJsonReader('/project');
139
- const iosProfile = await reader.getSubmitProfileAsync(Platform.IOS, 'release');
140
-
141
- expect(iosProfile).toEqual({
142
- appleId: 'some@email.com',
143
- ascAppId: '1223423523',
144
- appleTeamId: 'QWERTY',
145
- ascApiKeyPath: './path-ABCD.p8',
146
- ascApiKeyIssuerId: 'abc-123-def-456',
147
- ascApiKeyId: 'ABCD',
148
- language: 'en-US',
149
- });
150
- } finally {
151
- process.env.ASC_API_KEY_PATH = undefined;
152
- process.env.ASC_API_KEY_ISSUER_ID = undefined;
153
- process.env.ASC_API_KEY_ID = undefined;
154
- }
155
- });
156
-
157
- test('valid profile extending other profile', async () => {
158
- await fs.writeJson('/project/eas.json', {
159
- submit: {
160
- base: {
161
- ios: {
162
- appleId: 'some@email.com',
163
- ascAppId: '1223423523',
164
- appleTeamId: 'QWERTY',
165
- },
166
- },
167
- extension: {
168
- extends: 'base',
169
- ios: {
170
- appleTeamId: 'ABCDEF',
171
- ascApiKeyPath: './path-ABCD.p8',
172
- ascApiKeyIssuerId: 'abc-123-def-456',
173
- ascApiKeyId: 'ABCD',
174
- },
175
- },
176
- },
177
- });
178
-
179
- const reader = new EasJsonReader('/project');
180
- const baseProfile = await reader.getSubmitProfileAsync(Platform.IOS, 'base');
181
- const extendedProfile = await reader.getSubmitProfileAsync(Platform.IOS, 'extension');
182
- expect(baseProfile).toEqual({
183
- language: 'en-US',
184
- appleId: 'some@email.com',
185
- ascAppId: '1223423523',
186
- appleTeamId: 'QWERTY',
187
- });
188
- expect(extendedProfile).toEqual({
189
- language: 'en-US',
190
- appleId: 'some@email.com',
191
- ascAppId: '1223423523',
192
- appleTeamId: 'ABCDEF',
193
- ascApiKeyPath: './path-ABCD.p8',
194
- ascApiKeyIssuerId: 'abc-123-def-456',
195
- ascApiKeyId: 'ABCD',
196
- });
197
- });
198
-
199
- test('get profile names', async () => {
200
- await fs.writeJson('/project/eas.json', {
201
- submit: {
202
- production: {
203
- android: {
204
- serviceAccountKeyPath: './path.json',
205
- track: 'beta',
206
- releaseStatus: 'completed',
207
- },
208
- },
209
- blah: {
210
- android: {
211
- serviceAccountKeyPath: './path.json',
212
- track: 'internal',
213
- releaseStatus: 'completed',
214
- },
215
- },
216
- },
217
- });
218
-
219
- const reader = new EasJsonReader('/project');
220
- const allProfileNames = await reader.getSubmitProfileNamesAsync();
221
- expect(allProfileNames.sort()).toEqual(['production', 'blah'].sort());
222
- });
@@ -1,97 +0,0 @@
1
- import { Platform } from '@expo/eas-build-job';
2
-
3
- import { MissingParentProfileError, MissingProfileError } from '../errors';
4
- import { EasJson } from '../types';
5
- import { BuildProfileSchema } from './schema';
6
- import { BuildProfile, EasJsonBuildProfile } from './types';
7
-
8
- type EasJsonBuildProfileResolved = Omit<EasJsonBuildProfile, 'extends'>;
9
-
10
- export function resolveBuildProfile<T extends Platform>({
11
- easJson,
12
- platform,
13
- profileName,
14
- }: {
15
- easJson: EasJson;
16
- platform: T;
17
- profileName?: string;
18
- }): BuildProfile<T> {
19
- const easJsonProfile = resolveProfile({
20
- easJson,
21
- profileName: profileName ?? 'production',
22
- });
23
- const { android, ios, ...base } = easJsonProfile;
24
- const withoutDefaults = mergeProfiles(base, easJsonProfile[platform] ?? {});
25
- return mergeProfiles(getDefaultProfile(platform), withoutDefaults) as BuildProfile<T>;
26
- }
27
-
28
- function resolveProfile({
29
- easJson,
30
- profileName,
31
- depth = 0,
32
- }: {
33
- easJson: EasJson;
34
- profileName: string;
35
- depth?: number;
36
- }): EasJsonBuildProfileResolved {
37
- if (depth >= 2) {
38
- throw new Error(
39
- 'Too long chain of profile extensions, make sure "extends" keys do not make a cycle'
40
- );
41
- }
42
-
43
- const profile = easJson.build?.[profileName];
44
- if (!profile) {
45
- if (depth === 0) {
46
- throw new MissingProfileError(`Missing build profile in eas.json: ${profileName}`);
47
- } else {
48
- throw new MissingParentProfileError(
49
- `Extending non-existent build profile in eas.json: ${profileName}`
50
- );
51
- }
52
- }
53
-
54
- const { extends: baseProfileName, ...rest } = profile;
55
- if (baseProfileName) {
56
- const baseProfile = resolveProfile({
57
- easJson,
58
- profileName: baseProfileName,
59
- depth: depth + 1,
60
- });
61
- return mergeProfiles(baseProfile, rest);
62
- } else {
63
- return rest;
64
- }
65
- }
66
-
67
- function mergeProfiles(
68
- base: EasJsonBuildProfileResolved,
69
- update: EasJsonBuildProfileResolved
70
- ): EasJsonBuildProfileResolved {
71
- const result = {
72
- ...base,
73
- ...update,
74
- };
75
- if (base.env && update.env) {
76
- result.env = {
77
- ...base.env,
78
- ...update.env,
79
- };
80
- }
81
- if (base.android && update.android) {
82
- result.android = mergeProfiles(base.android, update.android);
83
- }
84
- if (base.ios && update.ios) {
85
- result.ios = mergeProfiles(base.ios, update.ios);
86
- }
87
- return result;
88
- }
89
-
90
- function getDefaultProfile<T extends Platform>(platform: T): EasJsonBuildProfile {
91
- const defaultProfile = BuildProfileSchema.validate(
92
- {},
93
- { allowUnknown: false, abortEarly: false, convert: true }
94
- ).value;
95
- const { android, ios, ...base } = defaultProfile;
96
- return mergeProfiles(base, defaultProfile[platform]);
97
- }
@@ -1,83 +0,0 @@
1
- import { Android, Ios } from '@expo/eas-build-job';
2
- import Joi from 'joi';
3
- import semver from 'semver';
4
-
5
- const CacheSchema = Joi.object({
6
- disabled: Joi.boolean(),
7
- key: Joi.string().max(128),
8
- cacheDefaultPaths: Joi.boolean(),
9
- customPaths: Joi.array().items(Joi.string()),
10
- });
11
-
12
- const CommonBuildProfileSchema = Joi.object({
13
- credentialsSource: Joi.string().valid('local', 'remote').default('remote'),
14
- distribution: Joi.string().valid('store', 'internal').default('store'),
15
- cache: CacheSchema,
16
- releaseChannel: Joi.string().regex(/^[a-z\d][a-z\d._-]*$/),
17
- channel: Joi.string().regex(/^[a-z\d][a-z\d._-]*$/),
18
- developmentClient: Joi.boolean(),
19
- prebuildCommand: Joi.string(),
20
-
21
- node: Joi.string().empty(null).custom(semverCheck),
22
- yarn: Joi.string().empty(null).custom(semverCheck),
23
- expoCli: Joi.string().empty(null).custom(semverCheck),
24
- env: Joi.object().pattern(Joi.string(), Joi.string().empty(null)),
25
- });
26
-
27
- const AndroidBuildProfileSchema = CommonBuildProfileSchema.concat(
28
- Joi.object({
29
- credentialsSource: Joi.string().valid('local', 'remote'),
30
- distribution: Joi.string().valid('store', 'internal'),
31
- withoutCredentials: Joi.boolean(),
32
-
33
- image: Joi.string().valid(...Android.builderBaseImages),
34
- ndk: Joi.string().empty(null).custom(semverCheck),
35
- autoIncrement: Joi.alternatives().try(
36
- Joi.boolean(),
37
- Joi.string().valid('version', 'versionCode')
38
- ),
39
-
40
- artifactPath: Joi.string(),
41
- gradleCommand: Joi.string(),
42
-
43
- buildType: Joi.string().valid('apk', 'app-bundle'),
44
- })
45
- );
46
-
47
- const IosBuildProfileSchema = CommonBuildProfileSchema.concat(
48
- Joi.object({
49
- credentialsSource: Joi.string().valid('local', 'remote'),
50
- distribution: Joi.string().valid('store', 'internal'),
51
- enterpriseProvisioning: Joi.string().valid('adhoc', 'universal'),
52
- autoIncrement: Joi.alternatives().try(
53
- Joi.boolean(),
54
- Joi.string().valid('version', 'buildNumber')
55
- ),
56
- simulator: Joi.boolean(),
57
-
58
- image: Joi.string().valid(...Ios.builderBaseImages),
59
- bundler: Joi.string().empty(null).custom(semverCheck),
60
- fastlane: Joi.string().empty(null).custom(semverCheck),
61
- cocoapods: Joi.string().empty(null).custom(semverCheck),
62
-
63
- artifactPath: Joi.string(),
64
- scheme: Joi.string(),
65
- buildConfiguration: Joi.string(),
66
- })
67
- );
68
-
69
- export const BuildProfileSchema = CommonBuildProfileSchema.concat(
70
- Joi.object({
71
- extends: Joi.string(),
72
- android: AndroidBuildProfileSchema,
73
- ios: IosBuildProfileSchema,
74
- })
75
- );
76
-
77
- function semverCheck(value: any): any {
78
- if (semver.valid(value)) {
79
- return value;
80
- } else {
81
- throw new Error(`${value} is not a valid version`);
82
- }
83
- }
@@ -1,65 +0,0 @@
1
- import { Android, Cache, Ios, Platform } from '@expo/eas-build-job';
2
-
3
- export enum CredentialsSource {
4
- LOCAL = 'local',
5
- REMOTE = 'remote',
6
- }
7
-
8
- export type DistributionType = 'store' | 'internal';
9
-
10
- export type IosEnterpriseProvisioning = 'adhoc' | 'universal';
11
-
12
- export type VersionAutoIncrement = boolean | 'version';
13
- export type IosVersionAutoIncrement = VersionAutoIncrement | 'buildNumber';
14
- export type AndroidVersionAutoIncrement = VersionAutoIncrement | 'versionCode';
15
-
16
- export interface CommonBuildProfile {
17
- credentialsSource: CredentialsSource;
18
- distribution: DistributionType;
19
- cache?: Omit<Cache, 'clear'>;
20
- releaseChannel?: string;
21
- channel?: string;
22
- developmentClient?: boolean;
23
- prebuildCommand?: string;
24
-
25
- node?: string;
26
- yarn?: string;
27
- expoCli?: string;
28
- env?: Record<string, string>;
29
- }
30
-
31
- export interface AndroidBuildProfile extends CommonBuildProfile {
32
- withoutCredentials?: boolean;
33
- image?: Android.BuilderEnvironment['image'];
34
- ndk?: string;
35
- autoIncrement?: AndroidVersionAutoIncrement;
36
-
37
- buildType?: Android.BuildType.APK | Android.BuildType.APP_BUNDLE;
38
-
39
- gradleCommand?: string;
40
- artifactPath?: string;
41
- }
42
-
43
- export interface IosBuildProfile extends CommonBuildProfile {
44
- enterpriseProvisioning?: IosEnterpriseProvisioning;
45
- autoIncrement?: IosVersionAutoIncrement;
46
- simulator?: boolean;
47
- image?: Ios.BuilderEnvironment['image'];
48
- bundler?: string;
49
- fastlane?: string;
50
- cocoapods?: string;
51
-
52
- artifactPath?: string;
53
- scheme?: string;
54
- buildConfiguration?: string;
55
- }
56
-
57
- export type BuildProfile<TPlatform extends Platform = Platform> = TPlatform extends Platform.ANDROID
58
- ? AndroidBuildProfile
59
- : IosBuildProfile;
60
-
61
- export interface EasJsonBuildProfile extends Partial<CommonBuildProfile> {
62
- extends?: string;
63
- [Platform.ANDROID]?: Partial<AndroidBuildProfile>;
64
- [Platform.IOS]?: Partial<IosBuildProfile>;
65
- }
package/src/errors.ts DELETED
@@ -1,7 +0,0 @@
1
- export class InvalidEasJsonError extends Error {}
2
-
3
- export class MissingEasJsonError extends Error {}
4
-
5
- export class MissingProfileError extends Error {}
6
-
7
- export class MissingParentProfileError extends Error {}
package/src/index.ts DELETED
@@ -1,13 +0,0 @@
1
- export { AndroidReleaseStatus, AndroidReleaseTrack, SubmitProfile } from './submit/types';
2
- export { getDefaultProfile as getDefaultSubmitProfile } from './submit/resolver';
3
- export { EasJson, ProfileType } from './types';
4
- export {
5
- AndroidVersionAutoIncrement,
6
- BuildProfile,
7
- CredentialsSource,
8
- DistributionType,
9
- IosEnterpriseProvisioning,
10
- IosVersionAutoIncrement,
11
- } from './build/types';
12
- export { EasJsonReader } from './reader';
13
- export * as errors from './errors';
package/src/reader.ts DELETED
@@ -1,92 +0,0 @@
1
- import { Platform } from '@expo/eas-build-job';
2
- import JsonFile from '@expo/json-file';
3
- import fs from 'fs-extra';
4
- import path from 'path';
5
-
6
- import { resolveBuildProfile } from './build/resolver';
7
- import { BuildProfile } from './build/types';
8
- import { InvalidEasJsonError, MissingEasJsonError } from './errors';
9
- import { EasJsonSchema } from './schema';
10
- import { resolveSubmitProfile } from './submit/resolver';
11
- import { SubmitProfile } from './submit/types';
12
- import { EasJson } from './types';
13
-
14
- export class EasJsonReader {
15
- private easJson: EasJson | undefined;
16
-
17
- constructor(private projectDir: string) {}
18
-
19
- public static formatEasJsonPath(projectDir: string): string {
20
- return path.join(projectDir, 'eas.json');
21
- }
22
-
23
- public async readAsync(): Promise<EasJson> {
24
- if (this.easJson) {
25
- return this.easJson;
26
- }
27
-
28
- try {
29
- const easJsonPath = EasJsonReader.formatEasJsonPath(this.projectDir);
30
- if (!(await fs.pathExists(easJsonPath))) {
31
- throw new MissingEasJsonError(
32
- `eas.json could not be found at ${easJsonPath}. Learn more at https://expo.fyi/eas-json`
33
- );
34
- }
35
- const contents = JsonFile.read(easJsonPath);
36
- const { value, error } = EasJsonSchema.validate(contents, {
37
- allowUnknown: false,
38
- abortEarly: false,
39
- convert: true,
40
- noDefaults: true,
41
- });
42
- if (error) {
43
- throw new InvalidEasJsonError(`eas.json is not valid [${error.toString()}]`);
44
- }
45
- this.easJson = value;
46
- return value;
47
- } catch (err: any) {
48
- if (err.code === 'EJSONPARSE') {
49
- err.message = `Found invalid JSON in eas.json. ${err.message}`;
50
- }
51
- throw err;
52
- }
53
- }
54
-
55
- public async getBuildProfileNamesAsync(): Promise<string[]> {
56
- const easJson = await this.readAsync();
57
- return Object.keys(easJson?.build ?? {});
58
- }
59
-
60
- public async getBuildProfileAsync<T extends Platform>(
61
- platform: T,
62
- profileName?: string
63
- ): Promise<BuildProfile<T>> {
64
- const easJson = await this.readAsync();
65
- return resolveBuildProfile({ easJson, platform, profileName });
66
- }
67
-
68
- public async getCliConfigAsync(): Promise<EasJson['cli'] | null> {
69
- try {
70
- const easJson = await this.readAsync();
71
- return easJson.cli ?? null;
72
- } catch (err: any) {
73
- if (err instanceof MissingEasJsonError) {
74
- return null;
75
- }
76
- throw err;
77
- }
78
- }
79
-
80
- public async getSubmitProfileNamesAsync(): Promise<string[]> {
81
- const easJson = await this.readAsync();
82
- return Object.keys(easJson?.submit ?? {});
83
- }
84
-
85
- public async getSubmitProfileAsync<T extends Platform>(
86
- platform: T,
87
- profileName?: string
88
- ): Promise<SubmitProfile<T>> {
89
- const easJson = await this.readAsync();
90
- return resolveSubmitProfile({ easJson, platform, profileName });
91
- }
92
- }
package/src/schema.ts DELETED
@@ -1,13 +0,0 @@
1
- import Joi from 'joi';
2
-
3
- import { BuildProfileSchema } from './build/schema';
4
- import { SubmitProfileSchema } from './submit/schema';
5
-
6
- export const EasJsonSchema = Joi.object({
7
- cli: Joi.object({
8
- version: Joi.string(),
9
- requireCommit: Joi.boolean(),
10
- }),
11
- build: Joi.object().pattern(Joi.string(), BuildProfileSchema),
12
- submit: Joi.object().pattern(Joi.string(), SubmitProfileSchema),
13
- });
@@ -1,122 +0,0 @@
1
- import { Platform } from '@expo/eas-build-job';
2
- import envString from 'env-string';
3
-
4
- import { MissingParentProfileError, MissingProfileError } from '../errors';
5
- import { EasJson } from '../types';
6
- import { AndroidSubmitProfileSchema, IosSubmitProfileSchema } from './schema';
7
- import {
8
- AndroidSubmitProfileFieldsToEvaluate,
9
- IosSubmitProfileFieldsToEvaluate,
10
- SubmitProfile,
11
- } from './types';
12
-
13
- export function resolveSubmitProfile<T extends Platform>({
14
- easJson,
15
- platform,
16
- profileName,
17
- }: {
18
- easJson: EasJson;
19
- platform: T;
20
- profileName?: string;
21
- }): SubmitProfile<T> {
22
- try {
23
- const submitProfile = resolveProfile({
24
- easJson,
25
- platform,
26
- profileName: profileName ?? 'production',
27
- });
28
- const unevaluatedProfile = mergeProfiles(getDefaultProfile(platform), submitProfile);
29
- return evaluateFields(platform, unevaluatedProfile);
30
- } catch (err: any) {
31
- if (err instanceof MissingProfileError && !profileName) {
32
- return getDefaultProfile(platform);
33
- } else {
34
- throw err;
35
- }
36
- }
37
- }
38
-
39
- function resolveProfile<T extends Platform>({
40
- easJson,
41
- profileName,
42
- depth = 0,
43
- platform,
44
- }: {
45
- platform: T;
46
- easJson: EasJson;
47
- profileName: string;
48
- depth?: number;
49
- }): SubmitProfile<T> | undefined {
50
- if (depth >= 2) {
51
- throw new Error(
52
- 'Too long chain of profile extensions, make sure "extends" keys do not make a cycle'
53
- );
54
- }
55
-
56
- const profile = easJson.submit?.[profileName];
57
- if (!profile) {
58
- if (depth === 0) {
59
- throw new MissingProfileError(`Missing submit profile in eas.json: ${profileName}`);
60
- } else {
61
- throw new MissingParentProfileError(
62
- `Extending non-existent submit profile in eas.json: ${profileName}`
63
- );
64
- }
65
- }
66
-
67
- const { extends: baseProfileName, ...rest } = profile;
68
- const platformProfile = rest[platform] as SubmitProfile<T> | undefined;
69
- if (baseProfileName) {
70
- const baseProfile = resolveProfile({
71
- easJson,
72
- platform,
73
- profileName: baseProfileName,
74
- depth: depth + 1,
75
- });
76
- return mergeProfiles(baseProfile, platformProfile);
77
- } else {
78
- return platformProfile;
79
- }
80
- }
81
-
82
- function mergeProfiles<T extends Platform>(
83
- base: SubmitProfile<T>,
84
- update?: SubmitProfile<T>
85
- ): SubmitProfile<T>;
86
- function mergeProfiles<T extends Platform>(
87
- base?: SubmitProfile<T>,
88
- update?: SubmitProfile<T>
89
- ): SubmitProfile<T> | undefined;
90
- function mergeProfiles<T extends Platform>(
91
- base?: SubmitProfile<T>,
92
- update?: SubmitProfile<T>
93
- ): SubmitProfile<T> | undefined {
94
- if (!update) {
95
- return base;
96
- }
97
- return { ...base, ...update };
98
- }
99
-
100
- export function getDefaultProfile<T extends Platform>(platform: T): SubmitProfile<T> {
101
- const Schema =
102
- platform === Platform.ANDROID ? AndroidSubmitProfileSchema : IosSubmitProfileSchema;
103
- return Schema.validate({}, { allowUnknown: false, abortEarly: false, convert: true }).value;
104
- }
105
-
106
- function evaluateFields<T extends Platform>(
107
- platform: T,
108
- profile: SubmitProfile<T>
109
- ): SubmitProfile<T> {
110
- const fields =
111
- platform === Platform.ANDROID
112
- ? AndroidSubmitProfileFieldsToEvaluate
113
- : IosSubmitProfileFieldsToEvaluate;
114
- const evaluatedProfile = { ...profile };
115
- for (const field of fields) {
116
- if (field in evaluatedProfile) {
117
- // @ts-ignore
118
- evaluatedProfile[field] = envString(evaluatedProfile[field], process.env);
119
- }
120
- }
121
- return evaluatedProfile;
122
- }
@@ -1,36 +0,0 @@
1
- import Joi from 'joi';
2
-
3
- import { AndroidReleaseStatus, AndroidReleaseTrack } from './types';
4
-
5
- export const AndroidSubmitProfileSchema = Joi.object({
6
- serviceAccountKeyPath: Joi.string(),
7
- track: Joi.string()
8
- .valid(...Object.values(AndroidReleaseTrack))
9
- .default(AndroidReleaseTrack.internal),
10
- releaseStatus: Joi.string()
11
- .valid(...Object.values(AndroidReleaseStatus))
12
- .default(AndroidReleaseStatus.completed),
13
- changesNotSentForReview: Joi.boolean().default(false),
14
- applicationId: Joi.string(),
15
- });
16
-
17
- export const IosSubmitProfileSchema = Joi.object({
18
- ascApiKeyPath: Joi.string(),
19
- ascApiKeyId: Joi.string(),
20
- ascApiKeyIssuerId: Joi.string(),
21
- appleId: Joi.string(),
22
- ascAppId: Joi.string(),
23
- appleTeamId: Joi.string(),
24
- sku: Joi.string(),
25
- language: Joi.string().default('en-US'),
26
- companyName: Joi.string(),
27
- appName: Joi.string(),
28
- bundleIdentifier: Joi.string(),
29
- metadataPath: Joi.string(),
30
- });
31
-
32
- export const SubmitProfileSchema = Joi.object({
33
- extends: Joi.string(),
34
- android: AndroidSubmitProfileSchema,
35
- ios: IosSubmitProfileSchema,
36
- });
@@ -1,57 +0,0 @@
1
- import { Platform } from '@expo/eas-build-job';
2
-
3
- export enum AndroidReleaseStatus {
4
- completed = 'completed',
5
- draft = 'draft',
6
- halted = 'halted',
7
- inProgress = 'inProgress',
8
- }
9
-
10
- export enum AndroidReleaseTrack {
11
- production = 'production',
12
- beta = 'beta',
13
- alpha = 'alpha',
14
- internal = 'internal',
15
- }
16
-
17
- export interface AndroidSubmitProfile {
18
- serviceAccountKeyPath?: string;
19
- track: AndroidReleaseTrack;
20
- releaseStatus: AndroidReleaseStatus;
21
- changesNotSentForReview: boolean;
22
- applicationId?: string;
23
- }
24
-
25
- export const AndroidSubmitProfileFieldsToEvaluate: (keyof AndroidSubmitProfile)[] = [
26
- 'serviceAccountKeyPath',
27
- ];
28
-
29
- export interface IosSubmitProfile {
30
- ascApiKeyPath?: string;
31
- ascApiKeyIssuerId?: string;
32
- ascApiKeyId?: string;
33
- appleId?: string;
34
- ascAppId?: string;
35
- appleTeamId?: string;
36
- sku?: string;
37
- language: string;
38
- companyName?: string;
39
- appName?: string;
40
- bundleIdentifier?: string;
41
- metadataPath?: string;
42
- }
43
-
44
- export const IosSubmitProfileFieldsToEvaluate: (keyof IosSubmitProfile)[] = [
45
- 'ascApiKeyPath',
46
- 'ascApiKeyIssuerId',
47
- 'ascApiKeyId',
48
- ];
49
-
50
- export type SubmitProfile<TPlatform extends Platform = Platform> =
51
- TPlatform extends Platform.ANDROID ? AndroidSubmitProfile : IosSubmitProfile;
52
-
53
- export interface EasJsonSubmitProfile {
54
- extends?: string;
55
- [Platform.ANDROID]?: AndroidSubmitProfile;
56
- [Platform.IOS]?: IosSubmitProfile;
57
- }
package/src/types.ts DELETED
@@ -1,21 +0,0 @@
1
- import { EasJsonBuildProfile } from './build/types';
2
- import { EasJsonSubmitProfile } from './submit/types';
3
-
4
- export type ProfileType = 'build' | 'submit';
5
- export type EasJsonProfile<T extends ProfileType> = T extends 'build'
6
- ? EasJsonBuildProfile
7
- : EasJsonSubmitProfile;
8
-
9
- export enum CredentialsSource {
10
- LOCAL = 'local',
11
- REMOTE = 'remote',
12
- }
13
-
14
- export interface EasJson {
15
- cli?: {
16
- version?: string;
17
- requireCommit?: boolean;
18
- };
19
- build?: { [profileName: string]: EasJsonBuildProfile };
20
- submit?: { [profileName: string]: EasJsonSubmitProfile };
21
- }
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "./tsconfig",
3
- "exclude": ["**/__mocks__/*", "**/__tests__/*"]
4
- }
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "declaration": true,
4
- "importHelpers": true,
5
- "module": "commonjs",
6
- "esModuleInterop": true,
7
- "noImplicitReturns": true,
8
- "strict": true,
9
- "target": "ES2019",
10
- "outDir": "build",
11
- "rootDir": "src",
12
- "typeRoots": [
13
- "../../node_modules/@types",
14
- "../../ts-declarations",
15
- "./node_modules/@types"
16
- ]
17
- },
18
- "include": ["src/**/*"]
19
- }