@expo/eas-json 0.56.0 → 0.59.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.
- package/package.json +7 -4
- package/__mocks__/fs.ts +0 -6
- package/jest.config.js +0 -5
- package/src/__tests__/reader-build-test.ts +0 -290
- package/src/__tests__/reader-submit-test.ts +0 -222
- package/src/build/resolver.ts +0 -97
- package/src/build/schema.ts +0 -83
- package/src/build/types.ts +0 -65
- package/src/errors.ts +0 -7
- package/src/index.ts +0 -13
- package/src/reader.ts +0 -92
- package/src/schema.ts +0 -15
- package/src/submit/resolver.ts +0 -122
- package/src/submit/schema.ts +0 -36
- package/src/submit/types.ts +0 -57
- package/src/types.ts +0 -27
- package/tsconfig.build.json +0 -4
- package/tsconfig.json +0 -19
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.
|
|
4
|
+
"version": "0.59.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.
|
|
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",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@types/fs-extra": "9.0.13",
|
|
20
|
-
"memfs": "3.4.
|
|
20
|
+
"memfs": "3.4.7",
|
|
21
21
|
"typescript": "4.7.4"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
@@ -36,6 +36,9 @@
|
|
|
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
|
},
|
|
@@ -43,5 +46,5 @@
|
|
|
43
46
|
"node": "18.6.0",
|
|
44
47
|
"yarn": "1.22.19"
|
|
45
48
|
},
|
|
46
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "8281a68e2ed0a20896e1da94e6773c5fd15a6e9c"
|
|
47
50
|
}
|
package/__mocks__/fs.ts
DELETED
package/jest.config.js
DELETED
|
@@ -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
|
-
});
|
package/src/build/resolver.ts
DELETED
|
@@ -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 >= 5) {
|
|
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
|
-
}
|
package/src/build/schema.ts
DELETED
|
@@ -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
|
-
}
|
package/src/build/types.ts
DELETED
|
@@ -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
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, AppVersionSource } 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,15 +0,0 @@
|
|
|
1
|
-
import Joi from 'joi';
|
|
2
|
-
|
|
3
|
-
import { BuildProfileSchema } from './build/schema';
|
|
4
|
-
import { SubmitProfileSchema } from './submit/schema';
|
|
5
|
-
import { AppVersionSource } from './types';
|
|
6
|
-
|
|
7
|
-
export const EasJsonSchema = Joi.object({
|
|
8
|
-
cli: Joi.object({
|
|
9
|
-
version: Joi.string(),
|
|
10
|
-
requireCommit: Joi.boolean(),
|
|
11
|
-
appVersionSource: Joi.string().valid(...Object.values(AppVersionSource)),
|
|
12
|
-
}),
|
|
13
|
-
build: Joi.object().pattern(Joi.string(), BuildProfileSchema),
|
|
14
|
-
submit: Joi.object().pattern(Joi.string(), SubmitProfileSchema),
|
|
15
|
-
});
|
package/src/submit/resolver.ts
DELETED
|
@@ -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
|
-
}
|
package/src/submit/schema.ts
DELETED
|
@@ -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
|
-
});
|
package/src/submit/types.ts
DELETED
|
@@ -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,27 +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 enum AppVersionSource {
|
|
15
|
-
LOCAL = 'local',
|
|
16
|
-
REMOTE = 'remote',
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface EasJson {
|
|
20
|
-
cli?: {
|
|
21
|
-
version?: string;
|
|
22
|
-
requireCommit?: boolean;
|
|
23
|
-
appVersionSource?: AppVersionSource;
|
|
24
|
-
};
|
|
25
|
-
build?: { [profileName: string]: EasJsonBuildProfile };
|
|
26
|
-
submit?: { [profileName: string]: EasJsonSubmitProfile };
|
|
27
|
-
}
|
package/tsconfig.build.json
DELETED
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
|
-
}
|