@bravemobile/react-native-code-push 13.1.0-beta.3 → 13.1.0-beta.4
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/README.md +9 -4
- package/cli/commands/releaseCommand/release.test.ts +52 -10
- package/cli/commands/releaseCommand/release.ts +39 -6
- package/cli/dist/commands/releaseCommand/release.js +23 -8
- package/cli/dist/commands/releaseCommand/release.test.js +34 -6
- package/cli/dist/functions/resolveAssetDiffBases.js +7 -2
- package/cli/dist/functions/resolveAssetDiffBases.test.js +26 -12
- package/cli/functions/resolveAssetDiffBases.test.ts +28 -14
- package/cli/functions/resolveAssetDiffBases.ts +8 -1
- package/package.json +1 -1
- package/typings/react-native-code-push.d.ts +42 -12
package/README.md
CHANGED
|
@@ -351,9 +351,10 @@ Diff archives are published only when all three of these hold:
|
|
|
351
351
|
- `--diff-base-count` is greater than `0` (it defaults to `3`).
|
|
352
352
|
|
|
353
353
|
```ts
|
|
354
|
-
bundleDownloader: async (
|
|
355
|
-
const downloadedFilePath = path.join(os.tmpdir(),
|
|
356
|
-
|
|
354
|
+
bundleDownloader: async (archive, platform, identifier = 'staging') => {
|
|
355
|
+
const downloadedFilePath = path.join(os.tmpdir(), archive.packageHash);
|
|
356
|
+
const storageKey = `bundles/${platform}/${identifier}/full-bundle/${archive.packageHash}`;
|
|
357
|
+
// fetch storageKey from your storage (S3, Supabase, ...) to downloadedFilePath
|
|
357
358
|
return { downloadedFilePath };
|
|
358
359
|
},
|
|
359
360
|
```
|
|
@@ -389,6 +390,7 @@ const Config: CliConfigInterface = {
|
|
|
389
390
|
source: string,
|
|
390
391
|
platform: "ios" | "android",
|
|
391
392
|
identifier,
|
|
393
|
+
artifact,
|
|
392
394
|
): Promise<{downloadUrl: string}> => {
|
|
393
395
|
// ...
|
|
394
396
|
},
|
|
@@ -413,7 +415,7 @@ const Config: CliConfigInterface = {
|
|
|
413
415
|
|
|
414
416
|
// Only needed to publish asset diff archives (see "4-2. Asset Diff Archives").
|
|
415
417
|
// bundleDownloader: async (
|
|
416
|
-
//
|
|
418
|
+
// archive,
|
|
417
419
|
// platform: "ios" | "android",
|
|
418
420
|
// identifier,
|
|
419
421
|
// ): Promise<{downloadedFilePath: string}> => {
|
|
@@ -427,6 +429,9 @@ module.exports = Config;
|
|
|
427
429
|
|
|
428
430
|
**`bundleUploader`**
|
|
429
431
|
- Implements a function to upload the bundle file.
|
|
432
|
+
- The optional `artifact` argument identifies the full bundle, binary patch, or asset diff
|
|
433
|
+
archive. The `release` command always provides it, including the target binary version and
|
|
434
|
+
the package hashes needed to construct a storage key without parsing a file name.
|
|
430
435
|
- The `downloadUrl` returned by this function is recorded in `ReleaseHistoryInterface` data
|
|
431
436
|
and is used by the library runtime to download the bundle file from this URL.
|
|
432
437
|
- Used in the following cases:
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { applyPatch } from "../../utils/binaryPatch.js";
|
|
18
18
|
import { generatePackageHashFromDirectory } from "../../utils/hash-utils.js";
|
|
19
19
|
import { unzip } from "../../utils/unzip.js";
|
|
20
|
-
import type { CliConfigInterface, ReleaseHistoryInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
20
|
+
import type { BundleUploadArtifact, CliConfigInterface, ReleaseHistoryInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Covers the release flow around the binary patch option with `--skip-bundle`, which is
|
|
@@ -92,15 +92,23 @@ class ProcessExitError extends Error {
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
type Uploads = {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
type Uploads = {
|
|
96
|
+
artifact: BundleUploadArtifact | undefined;
|
|
97
|
+
downloadUrl: string;
|
|
98
|
+
filePath: string;
|
|
99
|
+
logCountBeforeUpload: number;
|
|
100
|
+
}[];
|
|
101
|
+
|
|
102
|
+
function recordingUploader(
|
|
103
|
+
uploads: Uploads,
|
|
104
|
+
failOn?: (filePath: string) => boolean,
|
|
105
|
+
): CliConfigInterface['bundleUploader'] {
|
|
106
|
+
return async (filePath, _platform, _identifier, artifact) => {
|
|
99
107
|
if (failOn?.(filePath)) {
|
|
100
108
|
throw new Error(`upload rejected: ${path.basename(filePath)}`);
|
|
101
109
|
}
|
|
102
110
|
const downloadUrl = `https://cdn.example.com/${path.basename(filePath)}`;
|
|
103
|
-
uploads.push({ filePath, downloadUrl, logCountBeforeUpload: logs.length });
|
|
111
|
+
uploads.push({ artifact, filePath, downloadUrl, logCountBeforeUpload: logs.length });
|
|
104
112
|
return { downloadUrl };
|
|
105
113
|
};
|
|
106
114
|
}
|
|
@@ -204,6 +212,17 @@ afterEach(() => {
|
|
|
204
212
|
});
|
|
205
213
|
|
|
206
214
|
describe("release without --binary-bundle-path", () => {
|
|
215
|
+
it("keeps existing three-argument uploaders callable", async () => {
|
|
216
|
+
const legacyUploader = async (
|
|
217
|
+
source: string,
|
|
218
|
+
_platform: 'ios' | 'android',
|
|
219
|
+
_identifier?: string,
|
|
220
|
+
) => ({ downloadUrl: source });
|
|
221
|
+
const uploader: CliConfigInterface['bundleUploader'] = legacyUploader;
|
|
222
|
+
|
|
223
|
+
await expect(uploader('bundle.zip', 'ios')).resolves.toEqual({ downloadUrl: 'bundle.zip' });
|
|
224
|
+
});
|
|
225
|
+
|
|
207
226
|
it("uploads the full bundle only, exactly as before binary patches existed", async () => {
|
|
208
227
|
const staged = await stageBundleOutput("full-only");
|
|
209
228
|
|
|
@@ -211,6 +230,11 @@ describe("release without --binary-bundle-path", () => {
|
|
|
211
230
|
|
|
212
231
|
expect(uploads).toHaveLength(1);
|
|
213
232
|
expect(uploads[0].filePath).toBe(`${staged.bundleDirectory}/${staged.bundleFileName}`);
|
|
233
|
+
expect(uploads[0].artifact).toEqual({
|
|
234
|
+
type: 'full-bundle',
|
|
235
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
236
|
+
packageHash: staged.bundleFileName,
|
|
237
|
+
});
|
|
214
238
|
expect(fs.readdirSync(staged.bundleDirectory)).toEqual([staged.bundleFileName]);
|
|
215
239
|
expect(releaseHistories[0][APP_VERSION]).toEqual({
|
|
216
240
|
enabled: true,
|
|
@@ -658,11 +682,11 @@ describe("release with asset diff bases", () => {
|
|
|
658
682
|
|
|
659
683
|
/** Serves the staged base archives, and records which releases were asked for. */
|
|
660
684
|
function recordingDownloader(bases: StagedBaseRelease[], downloads: string[]): CliConfigInterface['bundleDownloader'] {
|
|
661
|
-
return async (
|
|
662
|
-
downloads.push(downloadUrl);
|
|
663
|
-
const base = bases.find((candidate) => candidate.downloadUrl === downloadUrl);
|
|
685
|
+
return async (archive) => {
|
|
686
|
+
downloads.push(archive.downloadUrl);
|
|
687
|
+
const base = bases.find((candidate) => candidate.downloadUrl === archive.downloadUrl);
|
|
664
688
|
if (!base) {
|
|
665
|
-
throw new Error(`the downloader was called with an unexpected url: ${downloadUrl}`);
|
|
689
|
+
throw new Error(`the downloader was called with an unexpected url: ${archive.downloadUrl}`);
|
|
666
690
|
}
|
|
667
691
|
return { downloadedFilePath: base.archivePath };
|
|
668
692
|
};
|
|
@@ -687,6 +711,24 @@ describe("release with asset diff bases", () => {
|
|
|
687
711
|
`${staged.bundleFileName}${BINARY_PATCH_ARCHIVE_SUFFIX}`,
|
|
688
712
|
diffFileName,
|
|
689
713
|
]);
|
|
714
|
+
expect(uploads.map(({ artifact }) => artifact)).toEqual([
|
|
715
|
+
{
|
|
716
|
+
type: 'full-bundle',
|
|
717
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
718
|
+
packageHash: staged.bundleFileName,
|
|
719
|
+
},
|
|
720
|
+
{
|
|
721
|
+
type: 'binary-patch',
|
|
722
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
723
|
+
packageHash: staged.bundleFileName,
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
type: 'asset-diff',
|
|
727
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
728
|
+
packageHash: staged.bundleFileName,
|
|
729
|
+
basePackageHash: base.packageHash,
|
|
730
|
+
},
|
|
731
|
+
]);
|
|
690
732
|
expect(downloads).toEqual([base.downloadUrl]);
|
|
691
733
|
// Every artifact is uploaded before the history points at any of them.
|
|
692
734
|
expect(uploadCountsWhenHistorySaved).toEqual([3]);
|
|
@@ -2,7 +2,7 @@ import fs from "fs";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { bundleCodePush, resolveJsBundleName } from "../bundleCommand/bundleCodePush.js";
|
|
4
4
|
import { addToReleaseHistory } from "./addToReleaseHistory.js";
|
|
5
|
-
import type { CliConfigInterface, ReleaseHistoryInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
5
|
+
import type { BundleUploadArtifact, CliConfigInterface, ReleaseHistoryInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
6
6
|
import { generatePackageHashFromDirectory } from "../../utils/hash-utils.js";
|
|
7
7
|
import { unzip } from "../../utils/unzip.js";
|
|
8
8
|
import { ASSET_DIFF_ARCHIVE_INFIX, makeAssetDiffBundle } from "../../functions/makeAssetDiffBundle.js";
|
|
@@ -95,6 +95,7 @@ export async function release(
|
|
|
95
95
|
bundleDownloader,
|
|
96
96
|
bundleDirectory,
|
|
97
97
|
packageHash,
|
|
98
|
+
targetBinaryVersion: binaryVersion,
|
|
98
99
|
platform,
|
|
99
100
|
identifier,
|
|
100
101
|
})
|
|
@@ -102,10 +103,32 @@ export async function release(
|
|
|
102
103
|
|
|
103
104
|
// Every artifact is uploaded before the release history is touched, so a failed
|
|
104
105
|
// upload leaves the history describing only updates that can actually be downloaded.
|
|
105
|
-
const downloadUrl = await uploadArtifact(
|
|
106
|
+
const downloadUrl = await uploadArtifact(
|
|
107
|
+
bundleUploader,
|
|
108
|
+
bundleFilePath,
|
|
109
|
+
platform,
|
|
110
|
+
identifier,
|
|
111
|
+
{
|
|
112
|
+
type: 'full-bundle',
|
|
113
|
+
targetBinaryVersion: binaryVersion,
|
|
114
|
+
packageHash,
|
|
115
|
+
},
|
|
116
|
+
'bundle',
|
|
117
|
+
);
|
|
106
118
|
let patchDownloadUrl: string | undefined;
|
|
107
119
|
if (binaryPatch) {
|
|
108
|
-
patchDownloadUrl = await uploadArtifact(
|
|
120
|
+
patchDownloadUrl = await uploadArtifact(
|
|
121
|
+
bundleUploader,
|
|
122
|
+
binaryPatch.patchBundleFilePath,
|
|
123
|
+
platform,
|
|
124
|
+
identifier,
|
|
125
|
+
{
|
|
126
|
+
type: 'binary-patch',
|
|
127
|
+
targetBinaryVersion: binaryVersion,
|
|
128
|
+
packageHash,
|
|
129
|
+
},
|
|
130
|
+
'binary patch bundle',
|
|
131
|
+
);
|
|
109
132
|
console.log(`log: Binary patch archive uploaded (download url: ${patchDownloadUrl})`);
|
|
110
133
|
}
|
|
111
134
|
const diffPackages: Record<string, string> = {};
|
|
@@ -114,7 +137,12 @@ export async function release(
|
|
|
114
137
|
// one that cannot be uploaded is left out of the history instead of failing the
|
|
115
138
|
// release the other two artifacts are ready for.
|
|
116
139
|
try {
|
|
117
|
-
const diffDownloadUrl = await uploadFile(bundleUploader, filePath, platform, identifier
|
|
140
|
+
const diffDownloadUrl = await uploadFile(bundleUploader, filePath, platform, identifier, {
|
|
141
|
+
type: 'asset-diff',
|
|
142
|
+
targetBinaryVersion: binaryVersion,
|
|
143
|
+
packageHash,
|
|
144
|
+
basePackageHash,
|
|
145
|
+
});
|
|
118
146
|
diffPackages[basePackageHash] = diffDownloadUrl;
|
|
119
147
|
console.log(`log: Asset diff archive against ${basePackageHash} uploaded (download url: ${diffDownloadUrl})`);
|
|
120
148
|
} catch (error) {
|
|
@@ -289,6 +317,7 @@ async function makeAssetDiffArtifacts({
|
|
|
289
317
|
bundleDownloader,
|
|
290
318
|
bundleDirectory,
|
|
291
319
|
packageHash,
|
|
320
|
+
targetBinaryVersion,
|
|
292
321
|
platform,
|
|
293
322
|
identifier,
|
|
294
323
|
}: {
|
|
@@ -298,6 +327,7 @@ async function makeAssetDiffArtifacts({
|
|
|
298
327
|
bundleDownloader: NonNullable<CliConfigInterface['bundleDownloader']>;
|
|
299
328
|
bundleDirectory: string;
|
|
300
329
|
packageHash: string;
|
|
330
|
+
targetBinaryVersion: string;
|
|
301
331
|
platform: 'ios' | 'android';
|
|
302
332
|
identifier: string | undefined;
|
|
303
333
|
}): Promise<AssetDiffArtifact[]> {
|
|
@@ -307,6 +337,7 @@ async function makeAssetDiffArtifacts({
|
|
|
307
337
|
bundleDownloader,
|
|
308
338
|
platform,
|
|
309
339
|
identifier,
|
|
340
|
+
targetBinaryVersion,
|
|
310
341
|
});
|
|
311
342
|
|
|
312
343
|
const artifacts: AssetDiffArtifact[] = [];
|
|
@@ -421,10 +452,11 @@ async function uploadArtifact(
|
|
|
421
452
|
filePath: string,
|
|
422
453
|
platform: 'ios' | 'android',
|
|
423
454
|
identifier: string | undefined,
|
|
455
|
+
artifact: BundleUploadArtifact,
|
|
424
456
|
artifactName: string,
|
|
425
457
|
): Promise<string> {
|
|
426
458
|
try {
|
|
427
|
-
return await uploadFile(bundleUploader, filePath, platform, identifier);
|
|
459
|
+
return await uploadFile(bundleUploader, filePath, platform, identifier, artifact);
|
|
428
460
|
} catch (error) {
|
|
429
461
|
console.error(`Failed to upload the ${artifactName} file. Exiting the program.\n`, error)
|
|
430
462
|
process.exit(1)
|
|
@@ -436,7 +468,8 @@ async function uploadFile(
|
|
|
436
468
|
filePath: string,
|
|
437
469
|
platform: 'ios' | 'android',
|
|
438
470
|
identifier: string | undefined,
|
|
471
|
+
artifact: BundleUploadArtifact,
|
|
439
472
|
): Promise<string> {
|
|
440
|
-
const { downloadUrl } = await bundleUploader(filePath, platform, identifier);
|
|
473
|
+
const { downloadUrl } = await bundleUploader(filePath, platform, identifier, artifact);
|
|
441
474
|
return downloadUrl
|
|
442
475
|
}
|
|
@@ -51,16 +51,25 @@ export async function release(bundleUploader, getReleaseHistory, setReleaseHisto
|
|
|
51
51
|
bundleDownloader,
|
|
52
52
|
bundleDirectory,
|
|
53
53
|
packageHash,
|
|
54
|
+
targetBinaryVersion: binaryVersion,
|
|
54
55
|
platform,
|
|
55
56
|
identifier,
|
|
56
57
|
})
|
|
57
58
|
: [];
|
|
58
59
|
// Every artifact is uploaded before the release history is touched, so a failed
|
|
59
60
|
// upload leaves the history describing only updates that can actually be downloaded.
|
|
60
|
-
const downloadUrl = await uploadArtifact(bundleUploader, bundleFilePath, platform, identifier,
|
|
61
|
+
const downloadUrl = await uploadArtifact(bundleUploader, bundleFilePath, platform, identifier, {
|
|
62
|
+
type: 'full-bundle',
|
|
63
|
+
targetBinaryVersion: binaryVersion,
|
|
64
|
+
packageHash,
|
|
65
|
+
}, 'bundle');
|
|
61
66
|
let patchDownloadUrl;
|
|
62
67
|
if (binaryPatch) {
|
|
63
|
-
patchDownloadUrl = await uploadArtifact(bundleUploader, binaryPatch.patchBundleFilePath, platform, identifier,
|
|
68
|
+
patchDownloadUrl = await uploadArtifact(bundleUploader, binaryPatch.patchBundleFilePath, platform, identifier, {
|
|
69
|
+
type: 'binary-patch',
|
|
70
|
+
targetBinaryVersion: binaryVersion,
|
|
71
|
+
packageHash,
|
|
72
|
+
}, 'binary patch bundle');
|
|
64
73
|
console.log(`log: Binary patch archive uploaded (download url: ${patchDownloadUrl})`);
|
|
65
74
|
}
|
|
66
75
|
const diffPackages = {};
|
|
@@ -69,7 +78,12 @@ export async function release(bundleUploader, getReleaseHistory, setReleaseHisto
|
|
|
69
78
|
// one that cannot be uploaded is left out of the history instead of failing the
|
|
70
79
|
// release the other two artifacts are ready for.
|
|
71
80
|
try {
|
|
72
|
-
const diffDownloadUrl = await uploadFile(bundleUploader, filePath, platform, identifier
|
|
81
|
+
const diffDownloadUrl = await uploadFile(bundleUploader, filePath, platform, identifier, {
|
|
82
|
+
type: 'asset-diff',
|
|
83
|
+
targetBinaryVersion: binaryVersion,
|
|
84
|
+
packageHash,
|
|
85
|
+
basePackageHash,
|
|
86
|
+
});
|
|
73
87
|
diffPackages[basePackageHash] = diffDownloadUrl;
|
|
74
88
|
console.log(`log: Asset diff archive against ${basePackageHash} uploaded (download url: ${diffDownloadUrl})`);
|
|
75
89
|
}
|
|
@@ -180,13 +194,14 @@ async function makeBinaryPatchArtifact({ baseBundlePath, contentsPath, bundleFil
|
|
|
180
194
|
*
|
|
181
195
|
* @return {Promise<AssetDiffArtifact[]>} The diff archives to upload, each naming the package it was built against.
|
|
182
196
|
*/
|
|
183
|
-
async function makeAssetDiffArtifacts({ patchBundleFilePath, releaseHistory, diffBaseCount, bundleDownloader, bundleDirectory, packageHash, platform, identifier, }) {
|
|
197
|
+
async function makeAssetDiffArtifacts({ patchBundleFilePath, releaseHistory, diffBaseCount, bundleDownloader, bundleDirectory, packageHash, targetBinaryVersion, platform, identifier, }) {
|
|
184
198
|
const bases = await resolveAssetDiffBases({
|
|
185
199
|
releaseHistory,
|
|
186
200
|
diffBaseCount,
|
|
187
201
|
bundleDownloader,
|
|
188
202
|
platform,
|
|
189
203
|
identifier,
|
|
204
|
+
targetBinaryVersion,
|
|
190
205
|
});
|
|
191
206
|
const artifacts = [];
|
|
192
207
|
const builtAgainst = new Set();
|
|
@@ -278,16 +293,16 @@ function warnOnBaseBundleMismatch(outputPath, baseBundlePath) {
|
|
|
278
293
|
}
|
|
279
294
|
}
|
|
280
295
|
/** Uploads an artifact the release cannot go out without, so a failure ends the program. */
|
|
281
|
-
async function uploadArtifact(bundleUploader, filePath, platform, identifier, artifactName) {
|
|
296
|
+
async function uploadArtifact(bundleUploader, filePath, platform, identifier, artifact, artifactName) {
|
|
282
297
|
try {
|
|
283
|
-
return await uploadFile(bundleUploader, filePath, platform, identifier);
|
|
298
|
+
return await uploadFile(bundleUploader, filePath, platform, identifier, artifact);
|
|
284
299
|
}
|
|
285
300
|
catch (error) {
|
|
286
301
|
console.error(`Failed to upload the ${artifactName} file. Exiting the program.\n`, error);
|
|
287
302
|
process.exit(1);
|
|
288
303
|
}
|
|
289
304
|
}
|
|
290
|
-
async function uploadFile(bundleUploader, filePath, platform, identifier) {
|
|
291
|
-
const { downloadUrl } = await bundleUploader(filePath, platform, identifier);
|
|
305
|
+
async function uploadFile(bundleUploader, filePath, platform, identifier, artifact) {
|
|
306
|
+
const { downloadUrl } = await bundleUploader(filePath, platform, identifier, artifact);
|
|
292
307
|
return downloadUrl;
|
|
293
308
|
}
|
|
@@ -66,12 +66,12 @@ class ProcessExitError extends Error {
|
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
function recordingUploader(uploads, failOn) {
|
|
69
|
-
return async (filePath) => {
|
|
69
|
+
return async (filePath, _platform, _identifier, artifact) => {
|
|
70
70
|
if (failOn?.(filePath)) {
|
|
71
71
|
throw new Error(`upload rejected: ${path.basename(filePath)}`);
|
|
72
72
|
}
|
|
73
73
|
const downloadUrl = `https://cdn.example.com/${path.basename(filePath)}`;
|
|
74
|
-
uploads.push({ filePath, downloadUrl, logCountBeforeUpload: logs.length });
|
|
74
|
+
uploads.push({ artifact, filePath, downloadUrl, logCountBeforeUpload: logs.length });
|
|
75
75
|
return { downloadUrl };
|
|
76
76
|
};
|
|
77
77
|
}
|
|
@@ -124,11 +124,21 @@ afterEach(() => {
|
|
|
124
124
|
fs.rmSync(path.resolve(process.cwd(), `${BINARY_VERSION}.json`), { force: true });
|
|
125
125
|
});
|
|
126
126
|
describe("release without --binary-bundle-path", () => {
|
|
127
|
+
it("keeps existing three-argument uploaders callable", async () => {
|
|
128
|
+
const legacyUploader = async (source, _platform, _identifier) => ({ downloadUrl: source });
|
|
129
|
+
const uploader = legacyUploader;
|
|
130
|
+
await expect(uploader('bundle.zip', 'ios')).resolves.toEqual({ downloadUrl: 'bundle.zip' });
|
|
131
|
+
});
|
|
127
132
|
it("uploads the full bundle only, exactly as before binary patches existed", async () => {
|
|
128
133
|
const staged = await stageBundleOutput("full-only");
|
|
129
134
|
const { uploads, releaseHistories } = await runRelease(staged);
|
|
130
135
|
expect(uploads).toHaveLength(1);
|
|
131
136
|
expect(uploads[0].filePath).toBe(`${staged.bundleDirectory}/${staged.bundleFileName}`);
|
|
137
|
+
expect(uploads[0].artifact).toEqual({
|
|
138
|
+
type: 'full-bundle',
|
|
139
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
140
|
+
packageHash: staged.bundleFileName,
|
|
141
|
+
});
|
|
132
142
|
expect(fs.readdirSync(staged.bundleDirectory)).toEqual([staged.bundleFileName]);
|
|
133
143
|
expect(releaseHistories[0][APP_VERSION]).toEqual({
|
|
134
144
|
enabled: true,
|
|
@@ -426,11 +436,11 @@ describe("release with asset diff bases", () => {
|
|
|
426
436
|
}
|
|
427
437
|
/** Serves the staged base archives, and records which releases were asked for. */
|
|
428
438
|
function recordingDownloader(bases, downloads) {
|
|
429
|
-
return async (
|
|
430
|
-
downloads.push(downloadUrl);
|
|
431
|
-
const base = bases.find((candidate) => candidate.downloadUrl === downloadUrl);
|
|
439
|
+
return async (archive) => {
|
|
440
|
+
downloads.push(archive.downloadUrl);
|
|
441
|
+
const base = bases.find((candidate) => candidate.downloadUrl === archive.downloadUrl);
|
|
432
442
|
if (!base) {
|
|
433
|
-
throw new Error(`the downloader was called with an unexpected url: ${downloadUrl}`);
|
|
443
|
+
throw new Error(`the downloader was called with an unexpected url: ${archive.downloadUrl}`);
|
|
434
444
|
}
|
|
435
445
|
return { downloadedFilePath: base.archivePath };
|
|
436
446
|
};
|
|
@@ -452,6 +462,24 @@ describe("release with asset diff bases", () => {
|
|
|
452
462
|
`${staged.bundleFileName}${BINARY_PATCH_ARCHIVE_SUFFIX}`,
|
|
453
463
|
diffFileName,
|
|
454
464
|
]);
|
|
465
|
+
expect(uploads.map(({ artifact }) => artifact)).toEqual([
|
|
466
|
+
{
|
|
467
|
+
type: 'full-bundle',
|
|
468
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
469
|
+
packageHash: staged.bundleFileName,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
type: 'binary-patch',
|
|
473
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
474
|
+
packageHash: staged.bundleFileName,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
type: 'asset-diff',
|
|
478
|
+
targetBinaryVersion: BINARY_VERSION,
|
|
479
|
+
packageHash: staged.bundleFileName,
|
|
480
|
+
basePackageHash: base.packageHash,
|
|
481
|
+
},
|
|
482
|
+
]);
|
|
455
483
|
expect(downloads).toEqual([base.downloadUrl]);
|
|
456
484
|
// Every artifact is uploaded before the history points at any of them.
|
|
457
485
|
expect(uploadCountsWhenHistorySaved).toEqual([3]);
|
|
@@ -25,7 +25,7 @@ const TEMP_DIR_PREFIX = 'codepush-asset-diff-base-';
|
|
|
25
25
|
* @param bundleDownloader Consumer-provided downloader for a released archive
|
|
26
26
|
* @return The bases that downloaded and verified, newest release first.
|
|
27
27
|
*/
|
|
28
|
-
export async function resolveAssetDiffBases({ releaseHistory, diffBaseCount, bundleDownloader, platform, identifier, }) {
|
|
28
|
+
export async function resolveAssetDiffBases({ releaseHistory, diffBaseCount, bundleDownloader, platform, identifier, targetBinaryVersion, }) {
|
|
29
29
|
// The seeded entry for the update inside the app binary has neither a url nor a hash,
|
|
30
30
|
// and nothing can be diffed against a package that was never published. A key that is
|
|
31
31
|
// not a version cannot be ordered against the others either, and ordering is what picks
|
|
@@ -37,7 +37,12 @@ export async function resolveAssetDiffBases({ releaseHistory, diffBaseCount, bun
|
|
|
37
37
|
const bases = [];
|
|
38
38
|
for (const [version, releaseInfo] of candidates) {
|
|
39
39
|
try {
|
|
40
|
-
const { downloadedFilePath } = await bundleDownloader(
|
|
40
|
+
const { downloadedFilePath } = await bundleDownloader({
|
|
41
|
+
downloadUrl: releaseInfo.downloadUrl,
|
|
42
|
+
targetBinaryVersion,
|
|
43
|
+
releaseVersion: version,
|
|
44
|
+
packageHash: releaseInfo.packageHash,
|
|
45
|
+
}, platform, identifier);
|
|
41
46
|
if (!(await matchesPackageHash(downloadedFilePath, releaseInfo.packageHash))) {
|
|
42
47
|
console.warn(`warn: Skipping the asset diff base v${version}: the downloaded archive does not hash to the ` +
|
|
43
48
|
`package hash recorded for it (${releaseInfo.packageHash}).`);
|
|
@@ -13,6 +13,7 @@ import { resolveAssetDiffBases } from "./resolveAssetDiffBases.js";
|
|
|
13
13
|
const CONTENTS_DIR_NAME = 'CodePush';
|
|
14
14
|
/** Where the resolver unpacks a base for verification, so leftovers are recognizable. */
|
|
15
15
|
const TEMP_DIR_PREFIX = 'codepush-asset-diff-base-';
|
|
16
|
+
const TARGET_BINARY_VERSION = '1.0.0';
|
|
16
17
|
let workDir;
|
|
17
18
|
let bundleDirectory;
|
|
18
19
|
/** Releases one full archive the way the CLI does, and returns what the history records. */
|
|
@@ -49,16 +50,16 @@ function releaseHistoryOf(releases) {
|
|
|
49
50
|
/** Stands in for the consumer's downloader: hands back a local archive per download url. */
|
|
50
51
|
function fakeDownloader(archives) {
|
|
51
52
|
const calls = [];
|
|
52
|
-
const download = async (
|
|
53
|
-
calls.push([
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
56
|
-
throw
|
|
53
|
+
const download = async (downloadInfo, platform, identifier) => {
|
|
54
|
+
calls.push([downloadInfo, platform, identifier]);
|
|
55
|
+
const downloadedArchive = archives[downloadInfo.downloadUrl];
|
|
56
|
+
if (downloadedArchive instanceof Error) {
|
|
57
|
+
throw downloadedArchive;
|
|
57
58
|
}
|
|
58
|
-
if (!
|
|
59
|
-
throw new Error(`the downloader was called with an unexpected url: ${downloadUrl}`);
|
|
59
|
+
if (!downloadedArchive) {
|
|
60
|
+
throw new Error(`the downloader was called with an unexpected url: ${downloadInfo.downloadUrl}`);
|
|
60
61
|
}
|
|
61
|
-
return { downloadedFilePath:
|
|
62
|
+
return { downloadedFilePath: downloadedArchive };
|
|
62
63
|
};
|
|
63
64
|
return { download, calls };
|
|
64
65
|
}
|
|
@@ -86,14 +87,15 @@ describe("resolveAssetDiffBases", () => {
|
|
|
86
87
|
bundleDownloader: download,
|
|
87
88
|
platform: 'android',
|
|
88
89
|
identifier: 'my-app',
|
|
90
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
89
91
|
});
|
|
90
92
|
expect(bases).toEqual([
|
|
91
93
|
{ basePackageHash: newest.packageHash, baseBundleFilePath: newest.archivePath },
|
|
92
94
|
{ basePackageHash: second.packageHash, baseBundleFilePath: second.archivePath },
|
|
93
95
|
]);
|
|
94
96
|
expect(calls).toEqual([
|
|
95
|
-
[newest.downloadUrl, 'android', 'my-app'],
|
|
96
|
-
[second.downloadUrl, 'android', 'my-app'],
|
|
97
|
+
[{ downloadUrl: newest.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: newest.version, packageHash: newest.packageHash }, 'android', 'my-app'],
|
|
98
|
+
[{ downloadUrl: second.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: second.version, packageHash: second.packageHash }, 'android', 'my-app'],
|
|
97
99
|
]);
|
|
98
100
|
});
|
|
99
101
|
it("skips history entries that lack a download url or a package hash", async () => {
|
|
@@ -109,11 +111,16 @@ describe("resolveAssetDiffBases", () => {
|
|
|
109
111
|
diffBaseCount: 1,
|
|
110
112
|
bundleDownloader: download,
|
|
111
113
|
platform: 'ios',
|
|
114
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
112
115
|
});
|
|
113
116
|
expect(bases).toEqual([
|
|
114
117
|
{ basePackageHash: released.packageHash, baseBundleFilePath: released.archivePath },
|
|
115
118
|
]);
|
|
116
|
-
expect(calls).toEqual([[
|
|
119
|
+
expect(calls).toEqual([[
|
|
120
|
+
{ downloadUrl: released.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: released.version, packageHash: released.packageHash },
|
|
121
|
+
'ios',
|
|
122
|
+
undefined,
|
|
123
|
+
]]);
|
|
117
124
|
});
|
|
118
125
|
it("ignores a history entry whose key is not a version, and resolves the rest", async () => {
|
|
119
126
|
const [released] = await stageReleases(['1.4.0']);
|
|
@@ -131,11 +138,16 @@ describe("resolveAssetDiffBases", () => {
|
|
|
131
138
|
diffBaseCount: 2,
|
|
132
139
|
bundleDownloader: download,
|
|
133
140
|
platform: 'ios',
|
|
141
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
134
142
|
});
|
|
135
143
|
expect(bases).toEqual([
|
|
136
144
|
{ basePackageHash: released.packageHash, baseBundleFilePath: released.archivePath },
|
|
137
145
|
]);
|
|
138
|
-
expect(calls).toEqual([[
|
|
146
|
+
expect(calls).toEqual([[
|
|
147
|
+
{ downloadUrl: released.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: released.version, packageHash: released.packageHash },
|
|
148
|
+
'ios',
|
|
149
|
+
undefined,
|
|
150
|
+
]]);
|
|
139
151
|
});
|
|
140
152
|
it("drops a base whose downloaded bytes do not match its recorded package hash", async () => {
|
|
141
153
|
const [older, newer] = await stageReleases(['1.2.0', '1.2.1']);
|
|
@@ -150,6 +162,7 @@ describe("resolveAssetDiffBases", () => {
|
|
|
150
162
|
diffBaseCount: 2,
|
|
151
163
|
bundleDownloader: download,
|
|
152
164
|
platform: 'android',
|
|
165
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
153
166
|
});
|
|
154
167
|
expect(bases).toEqual([{ basePackageHash: older.packageHash, baseBundleFilePath: older.archivePath }]);
|
|
155
168
|
expect(warn.mock.calls.join('\n')).toMatch(/1\.2\.1/);
|
|
@@ -167,6 +180,7 @@ describe("resolveAssetDiffBases", () => {
|
|
|
167
180
|
diffBaseCount: 2,
|
|
168
181
|
bundleDownloader: download,
|
|
169
182
|
platform: 'android',
|
|
183
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
170
184
|
});
|
|
171
185
|
expect(bases).toEqual([{ basePackageHash: older.packageHash, baseBundleFilePath: older.archivePath }]);
|
|
172
186
|
expect(warn.mock.calls.join('\n')).toMatch(/1\.3\.1.*the network is down/s);
|
|
@@ -4,7 +4,7 @@ import path from "path";
|
|
|
4
4
|
import { afterAll, afterEach, beforeAll, describe, expect, it, jest } from "@jest/globals";
|
|
5
5
|
import { makeCodePushBundle } from "./makeCodePushBundle.js";
|
|
6
6
|
import { resolveAssetDiffBases } from "./resolveAssetDiffBases.js";
|
|
7
|
-
import type { CliConfigInterface, ReleaseHistoryInterface } from "../../typings/react-native-code-push.d.ts";
|
|
7
|
+
import type { BundleDownloadInfo, CliConfigInterface, ReleaseHistoryInterface } from "../../typings/react-native-code-push.d.ts";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Exercises base acquisition against real archives and real hashes: a base is only usable
|
|
@@ -17,6 +17,7 @@ const CONTENTS_DIR_NAME = 'CodePush';
|
|
|
17
17
|
|
|
18
18
|
/** Where the resolver unpacks a base for verification, so leftovers are recognizable. */
|
|
19
19
|
const TEMP_DIR_PREFIX = 'codepush-asset-diff-base-';
|
|
20
|
+
const TARGET_BINARY_VERSION = '1.0.0';
|
|
20
21
|
|
|
21
22
|
type StagedRelease = {
|
|
22
23
|
version: string;
|
|
@@ -68,22 +69,22 @@ function releaseHistoryOf(releases: StagedRelease[]): ReleaseHistoryInterface {
|
|
|
68
69
|
|
|
69
70
|
/** Stands in for the consumer's downloader: hands back a local archive per download url. */
|
|
70
71
|
function fakeDownloader(archives: Record<string, string | Error>) {
|
|
71
|
-
const calls: Array<[
|
|
72
|
+
const calls: Array<[BundleDownloadInfo, string, string | undefined]> = [];
|
|
72
73
|
const download: NonNullable<CliConfigInterface['bundleDownloader']> = async (
|
|
73
|
-
|
|
74
|
+
downloadInfo,
|
|
74
75
|
platform,
|
|
75
76
|
identifier,
|
|
76
77
|
) => {
|
|
77
|
-
calls.push([
|
|
78
|
+
calls.push([downloadInfo, platform, identifier]);
|
|
78
79
|
|
|
79
|
-
const
|
|
80
|
-
if (
|
|
81
|
-
throw
|
|
80
|
+
const downloadedArchive = archives[downloadInfo.downloadUrl];
|
|
81
|
+
if (downloadedArchive instanceof Error) {
|
|
82
|
+
throw downloadedArchive;
|
|
82
83
|
}
|
|
83
|
-
if (!
|
|
84
|
-
throw new Error(`the downloader was called with an unexpected url: ${downloadUrl}`);
|
|
84
|
+
if (!downloadedArchive) {
|
|
85
|
+
throw new Error(`the downloader was called with an unexpected url: ${downloadInfo.downloadUrl}`);
|
|
85
86
|
}
|
|
86
|
-
return { downloadedFilePath:
|
|
87
|
+
return { downloadedFilePath: downloadedArchive };
|
|
87
88
|
};
|
|
88
89
|
return { download, calls };
|
|
89
90
|
}
|
|
@@ -119,6 +120,7 @@ describe("resolveAssetDiffBases", () => {
|
|
|
119
120
|
bundleDownloader: download,
|
|
120
121
|
platform: 'android',
|
|
121
122
|
identifier: 'my-app',
|
|
123
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
122
124
|
});
|
|
123
125
|
|
|
124
126
|
expect(bases).toEqual([
|
|
@@ -126,8 +128,8 @@ describe("resolveAssetDiffBases", () => {
|
|
|
126
128
|
{ basePackageHash: second.packageHash, baseBundleFilePath: second.archivePath },
|
|
127
129
|
]);
|
|
128
130
|
expect(calls).toEqual([
|
|
129
|
-
[newest.downloadUrl, 'android', 'my-app'],
|
|
130
|
-
[second.downloadUrl, 'android', 'my-app'],
|
|
131
|
+
[{ downloadUrl: newest.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: newest.version, packageHash: newest.packageHash }, 'android', 'my-app'],
|
|
132
|
+
[{ downloadUrl: second.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: second.version, packageHash: second.packageHash }, 'android', 'my-app'],
|
|
131
133
|
]);
|
|
132
134
|
});
|
|
133
135
|
|
|
@@ -145,12 +147,17 @@ describe("resolveAssetDiffBases", () => {
|
|
|
145
147
|
diffBaseCount: 1,
|
|
146
148
|
bundleDownloader: download,
|
|
147
149
|
platform: 'ios',
|
|
150
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
148
151
|
});
|
|
149
152
|
|
|
150
153
|
expect(bases).toEqual([
|
|
151
154
|
{ basePackageHash: released.packageHash, baseBundleFilePath: released.archivePath },
|
|
152
155
|
]);
|
|
153
|
-
expect(calls).toEqual([[
|
|
156
|
+
expect(calls).toEqual([[
|
|
157
|
+
{ downloadUrl: released.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: released.version, packageHash: released.packageHash },
|
|
158
|
+
'ios',
|
|
159
|
+
undefined,
|
|
160
|
+
]]);
|
|
154
161
|
});
|
|
155
162
|
|
|
156
163
|
it("ignores a history entry whose key is not a version, and resolves the rest", async () => {
|
|
@@ -170,12 +177,17 @@ describe("resolveAssetDiffBases", () => {
|
|
|
170
177
|
diffBaseCount: 2,
|
|
171
178
|
bundleDownloader: download,
|
|
172
179
|
platform: 'ios',
|
|
180
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
173
181
|
});
|
|
174
182
|
|
|
175
183
|
expect(bases).toEqual([
|
|
176
184
|
{ basePackageHash: released.packageHash, baseBundleFilePath: released.archivePath },
|
|
177
185
|
]);
|
|
178
|
-
expect(calls).toEqual([[
|
|
186
|
+
expect(calls).toEqual([[
|
|
187
|
+
{ downloadUrl: released.downloadUrl, targetBinaryVersion: TARGET_BINARY_VERSION, releaseVersion: released.version, packageHash: released.packageHash },
|
|
188
|
+
'ios',
|
|
189
|
+
undefined,
|
|
190
|
+
]]);
|
|
179
191
|
});
|
|
180
192
|
|
|
181
193
|
it("drops a base whose downloaded bytes do not match its recorded package hash", async () => {
|
|
@@ -192,6 +204,7 @@ describe("resolveAssetDiffBases", () => {
|
|
|
192
204
|
diffBaseCount: 2,
|
|
193
205
|
bundleDownloader: download,
|
|
194
206
|
platform: 'android',
|
|
207
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
195
208
|
});
|
|
196
209
|
|
|
197
210
|
expect(bases).toEqual([{ basePackageHash: older.packageHash, baseBundleFilePath: older.archivePath }]);
|
|
@@ -212,6 +225,7 @@ describe("resolveAssetDiffBases", () => {
|
|
|
212
225
|
diffBaseCount: 2,
|
|
213
226
|
bundleDownloader: download,
|
|
214
227
|
platform: 'android',
|
|
228
|
+
targetBinaryVersion: TARGET_BINARY_VERSION,
|
|
215
229
|
});
|
|
216
230
|
|
|
217
231
|
expect(bases).toEqual([{ basePackageHash: older.packageHash, baseBundleFilePath: older.archivePath }]);
|
|
@@ -40,12 +40,14 @@ export async function resolveAssetDiffBases({
|
|
|
40
40
|
bundleDownloader,
|
|
41
41
|
platform,
|
|
42
42
|
identifier,
|
|
43
|
+
targetBinaryVersion,
|
|
43
44
|
}: {
|
|
44
45
|
releaseHistory: ReleaseHistoryInterface;
|
|
45
46
|
diffBaseCount: number;
|
|
46
47
|
bundleDownloader: NonNullable<CliConfigInterface['bundleDownloader']>;
|
|
47
48
|
platform: 'ios' | 'android';
|
|
48
49
|
identifier?: string;
|
|
50
|
+
targetBinaryVersion: string;
|
|
49
51
|
}): Promise<AssetDiffBase[]> {
|
|
50
52
|
// The seeded entry for the update inside the app binary has neither a url nor a hash,
|
|
51
53
|
// and nothing can be diffed against a package that was never published. A key that is
|
|
@@ -60,7 +62,12 @@ export async function resolveAssetDiffBases({
|
|
|
60
62
|
const bases: AssetDiffBase[] = [];
|
|
61
63
|
for (const [version, releaseInfo] of candidates) {
|
|
62
64
|
try {
|
|
63
|
-
const { downloadedFilePath } = await bundleDownloader(
|
|
65
|
+
const { downloadedFilePath } = await bundleDownloader({
|
|
66
|
+
downloadUrl: releaseInfo.downloadUrl,
|
|
67
|
+
targetBinaryVersion,
|
|
68
|
+
releaseVersion: version,
|
|
69
|
+
packageHash: releaseInfo.packageHash,
|
|
70
|
+
}, platform, identifier);
|
|
64
71
|
|
|
65
72
|
if (!(await matchesPackageHash(downloadedFilePath, releaseInfo.packageHash))) {
|
|
66
73
|
console.warn(
|
package/package.json
CHANGED
|
@@ -633,6 +633,31 @@ declare namespace CodePush {
|
|
|
633
633
|
|
|
634
634
|
export default CodePush;
|
|
635
635
|
|
|
636
|
+
/**
|
|
637
|
+
* Identifies the archive passed to `bundleUploader` during a release.
|
|
638
|
+
*
|
|
639
|
+
* `targetBinaryVersion` is the value of the release command's `--binary-version` option.
|
|
640
|
+
* A full bundle's `packageHash` identifies its contents across target binary versions, while
|
|
641
|
+
* binary patch and asset diff archives need the target binary version to distinguish their contents.
|
|
642
|
+
* Asset diff archives also identify the released package they were built against.
|
|
643
|
+
*/
|
|
644
|
+
export type BundleUploadArtifact = {
|
|
645
|
+
targetBinaryVersion: string;
|
|
646
|
+
packageHash: string;
|
|
647
|
+
} & (
|
|
648
|
+
| { type: 'full-bundle' }
|
|
649
|
+
| { type: 'binary-patch' }
|
|
650
|
+
| { type: 'asset-diff'; basePackageHash: string }
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
/** Identifies the previously released full archive passed to `bundleDownloader`. */
|
|
654
|
+
export interface BundleDownloadInfo {
|
|
655
|
+
downloadUrl: string;
|
|
656
|
+
targetBinaryVersion: string;
|
|
657
|
+
releaseVersion: ReleaseVersion;
|
|
658
|
+
packageHash: string;
|
|
659
|
+
}
|
|
660
|
+
|
|
636
661
|
/**
|
|
637
662
|
* Interface for the config file required for `npx code-push` CLI operation.
|
|
638
663
|
*
|
|
@@ -647,26 +672,16 @@ export interface CliConfigInterface {
|
|
|
647
672
|
*
|
|
648
673
|
* @param source The relative path of the generated bundle file. (e.g. build/bundleOutput/1087bc338fc45a961c...)
|
|
649
674
|
* @param platform The target platform of the bundle file. This is the string passed when executing the CLI command. ('ios'/'android')
|
|
675
|
+
* @param artifact Information that identifies the full bundle, binary patch, or asset diff archive. The release command always supplies it; it remains optional so existing callers and three-parameter implementations stay compatible.
|
|
650
676
|
* @return {Promise<{downloadUrl: string}>} An object containing the `downloadUrl` property, which is the URL from which the uploaded bundle file can be downloaded. This URL will be recorded in the release history.
|
|
651
677
|
*/
|
|
652
678
|
bundleUploader: (
|
|
653
679
|
source: string,
|
|
654
680
|
platform: "ios" | "android",
|
|
655
681
|
identifier?: string,
|
|
682
|
+
artifact?: BundleUploadArtifact,
|
|
656
683
|
) => Promise<{downloadUrl: string}>;
|
|
657
684
|
|
|
658
|
-
/**
|
|
659
|
-
* Downloads a previously released update archive so the release command can compute
|
|
660
|
-
* asset diffs against it. Receives the `downloadUrl` recorded in the release history and
|
|
661
|
-
* must resolve with the local path of the downloaded file.
|
|
662
|
-
* Optional: when absent, releases are published without asset diff archives.
|
|
663
|
-
*/
|
|
664
|
-
bundleDownloader?: (
|
|
665
|
-
downloadUrl: string,
|
|
666
|
-
platform: "ios" | "android",
|
|
667
|
-
identifier?: string,
|
|
668
|
-
) => Promise<{ downloadedFilePath: string }>;
|
|
669
|
-
|
|
670
685
|
/**
|
|
671
686
|
* Interface that must be implemented to retrieve ReleaseHistory information.
|
|
672
687
|
*
|
|
@@ -702,4 +717,19 @@ export interface CliConfigInterface {
|
|
|
702
717
|
platform: "ios" | "android",
|
|
703
718
|
identifier?: string,
|
|
704
719
|
) => Promise<void>;
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Downloads a previously released update archive so the release command can compute
|
|
723
|
+
* asset diffs against it. Receives the `downloadUrl` recorded in the release history and
|
|
724
|
+
* must resolve with the local path of the downloaded file.
|
|
725
|
+
* Optional: when absent, releases are published without asset diff archives.
|
|
726
|
+
*
|
|
727
|
+
* @param archive Information that identifies the released full archive. The release command
|
|
728
|
+
* supplies its download URL, target binary version, release version, and package hash together.
|
|
729
|
+
*/
|
|
730
|
+
bundleDownloader?: (
|
|
731
|
+
archive: BundleDownloadInfo,
|
|
732
|
+
platform: "ios" | "android",
|
|
733
|
+
identifier?: string,
|
|
734
|
+
) => Promise<{ downloadedFilePath: string }>;
|
|
705
735
|
}
|