@bravemobile/react-native-code-push 8.3.0 → 9.0.0-alpha.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/CodePush.js +107 -136
- package/README.md +0 -5
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java +1 -4
- package/babel-plugin-code-push/index.js +197 -0
- package/babel-plugin-code-push/package-lock.json +10463 -0
- package/babel-plugin-code-push/package.json +26 -0
- package/babel-plugin-code-push/test/.babelrc.js +12 -0
- package/babel-plugin-code-push/test/cases/test1-config +15 -0
- package/babel-plugin-code-push/test/cases/test1-input +3 -0
- package/babel-plugin-code-push/test/cases/test1-output +11 -0
- package/babel-plugin-code-push/test/cases/test2-config +9 -0
- package/babel-plugin-code-push/test/cases/test2-input +3 -0
- package/babel-plugin-code-push/test/cases/test2-output +7 -0
- package/babel-plugin-code-push/test/codepush.config.js +15 -0
- package/babel-plugin-code-push/test/plugin.test.js +44 -0
- package/babel.config.js +3 -0
- package/cli/commands/bundleCommand/bundleCodePush.js +49 -0
- package/cli/commands/bundleCommand/index.js +25 -0
- package/cli/commands/createHistoryCommand/createReleaseHistory.js +53 -0
- package/cli/commands/createHistoryCommand/index.js +28 -0
- package/cli/commands/releaseCommand/addToReleaseHistory.js +75 -0
- package/cli/commands/releaseCommand/index.js +61 -0
- package/cli/commands/releaseCommand/release.js +88 -0
- package/cli/commands/showHistoryCommand/index.js +28 -0
- package/cli/commands/updateHistoryCommand/index.js +49 -0
- package/cli/commands/updateHistoryCommand/updateReleaseHistory.js +62 -0
- package/cli/constant.js +3 -0
- package/cli/functions/getReactTempDir.js +16 -0
- package/cli/functions/makeCodePushBundle.js +27 -0
- package/cli/functions/prepareToBundleJS.js +12 -0
- package/cli/functions/runHermesEmitBinaryCommand.js +213 -0
- package/cli/functions/runReactNativeBundleCommand.js +59 -0
- package/cli/index.js +43 -0
- package/cli/utils/file-utils.js +42 -0
- package/cli/utils/fsUtils.js +49 -0
- package/cli/utils/hash-utils.js +227 -0
- package/cli/utils/promisfied-fs.js +29 -0
- package/cli/utils/showLogo.js +23 -0
- package/cli/utils/zip.js +89 -0
- package/code-push.config.example.supabase.ts +114 -0
- package/docs/setup-android.md +3 -11
- package/eslint.config.mjs +32 -0
- package/package-mixins.js +1 -8
- package/package.json +26 -23
- package/react-native.config.js +3 -1
- package/typings/react-native-code-push.d.ts +91 -16
- package/versioning/BaseVersioning.js +126 -0
- package/versioning/BaseVersioning.test.js +15 -0
- package/versioning/IncrementalVersioning.js +9 -0
- package/versioning/IncrementalVersioning.test.js +186 -0
- package/versioning/SemverVersioning.js +10 -0
- package/versioning/SemverVersioning.test.js +205 -0
- package/versioning/index.js +7 -0
- package/.azurepipelines/build-rn-code-push-1es.yml +0 -104
- package/.azurepipelines/test-rn-code-push.yml +0 -94
- package/.config/CredScanSuppressions.json +0 -14
- package/docs/setup-windows.md +0 -121
- package/request-fetch-adapter.js +0 -52
- package/scripts/postlink/android/postlink.js +0 -87
- package/scripts/postlink/ios/postlink.js +0 -116
- package/scripts/postlink/run.js +0 -11
- package/scripts/postunlink/android/postunlink.js +0 -74
- package/scripts/postunlink/ios/postunlink.js +0 -87
- package/scripts/postunlink/run.js +0 -11
- package/scripts/tools/linkToolsAndroid.js +0 -57
- package/scripts/tools/linkToolsIos.js +0 -130
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* code based on appcenter-cli
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* NOTE!!! This utility file is duplicated for use by the CodePush service (for server-driven hashing/
|
|
7
|
+
* integrity checks) and Management SDK (for end-to-end code signing), please keep them in sync.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const crypto = require('crypto');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { isDirectory } = require('./file-utils');
|
|
14
|
+
const { walk } = require('./promisfied-fs');
|
|
15
|
+
|
|
16
|
+
// Do not throw an exception if either of these modules are missing, as they may not be needed by the
|
|
17
|
+
// consumer of this file.
|
|
18
|
+
const HASH_ALGORITHM = 'sha256';
|
|
19
|
+
class PackageManifest {
|
|
20
|
+
/**
|
|
21
|
+
* @type {Map<string, string>}
|
|
22
|
+
* @private
|
|
23
|
+
*/
|
|
24
|
+
_map;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param map {Map<string, string>?}
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
constructor(map) {
|
|
31
|
+
if (map == null) {
|
|
32
|
+
map = new Map();
|
|
33
|
+
}
|
|
34
|
+
this._map = map;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @return {Map<string, string>}
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
toMap() {
|
|
42
|
+
return this._map;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @return {string}
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
computePackageHash() {
|
|
50
|
+
/**
|
|
51
|
+
* @type {string[]}
|
|
52
|
+
*/
|
|
53
|
+
let entries = [];
|
|
54
|
+
this._map.forEach((hash, name) => {
|
|
55
|
+
entries.push(name + ':' + hash);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Make sure this list is alphabetically ordered so that other clients
|
|
59
|
+
// can also compute this hash easily given the update contents.
|
|
60
|
+
entries = entries.sort();
|
|
61
|
+
|
|
62
|
+
return crypto.createHash(HASH_ALGORITHM).update(JSON.stringify(entries)).digest('hex');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @return {string}
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
serialize() {
|
|
70
|
+
const obj = {};
|
|
71
|
+
|
|
72
|
+
this._map.forEach(function (value, key) {
|
|
73
|
+
obj[key] = value;
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return JSON.stringify(obj);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param filePath {string}
|
|
81
|
+
* @return {string}
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
84
|
+
static normalizePath(filePath) {
|
|
85
|
+
//replace all backslashes coming from cli running on windows machines by slashes
|
|
86
|
+
return filePath.replace(/\\/g, '/');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param relativeFilePath {string}
|
|
91
|
+
* @return {boolean}
|
|
92
|
+
* @public
|
|
93
|
+
*/
|
|
94
|
+
static isIgnored(relativeFilePath) {
|
|
95
|
+
const __MACOSX = '__MACOSX/';
|
|
96
|
+
const DS_STORE = '.DS_Store';
|
|
97
|
+
const CODEPUSH_METADATA = '.codepushrelease';
|
|
98
|
+
return (
|
|
99
|
+
relativeFilePath.startsWith(__MACOSX) ||
|
|
100
|
+
relativeFilePath === DS_STORE ||
|
|
101
|
+
relativeFilePath.endsWith('/' + DS_STORE) ||
|
|
102
|
+
relativeFilePath === CODEPUSH_METADATA ||
|
|
103
|
+
relativeFilePath.endsWith('/' + CODEPUSH_METADATA)
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
*
|
|
110
|
+
* @param directoryPath {string}
|
|
111
|
+
* @param basePath {string}
|
|
112
|
+
* @return {Promise<string>}
|
|
113
|
+
*/
|
|
114
|
+
async function generatePackageHashFromDirectory(directoryPath, basePath) {
|
|
115
|
+
try {
|
|
116
|
+
if (!isDirectory(directoryPath)) {
|
|
117
|
+
throw new Error('Not a directory. Please either create a directory, or use hashFile().');
|
|
118
|
+
}
|
|
119
|
+
} catch (error) {
|
|
120
|
+
throw new Error('Directory does not exist. Please either create a directory, or use hashFile().');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @type {PackageManifest}
|
|
125
|
+
*/
|
|
126
|
+
const manifest = await generatePackageManifestFromDirectory(directoryPath, basePath);
|
|
127
|
+
return manifest.computePackageHash();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
*
|
|
132
|
+
* @param directoryPath {string}
|
|
133
|
+
* @param basePath {string}
|
|
134
|
+
* @return {Promise<PackageManifest>}
|
|
135
|
+
*/
|
|
136
|
+
function generatePackageManifestFromDirectory(directoryPath, basePath) {
|
|
137
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
138
|
+
return new Promise(async (resolve, reject) => {
|
|
139
|
+
/**
|
|
140
|
+
* @type {Map<string, string>}
|
|
141
|
+
*/
|
|
142
|
+
const fileHashesMap = new Map();
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @type {string[]}
|
|
146
|
+
*/
|
|
147
|
+
const files = await walk(directoryPath);
|
|
148
|
+
|
|
149
|
+
if (!files || files.length === 0) {
|
|
150
|
+
reject('Error: Cannot sign the release because no files were found.');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @type {Promise<void>}
|
|
156
|
+
*/
|
|
157
|
+
// Hash the files sequentially, because streaming them in parallel is not necessarily faster
|
|
158
|
+
const generateManifestPromise = files.reduce((soFar, filePath) => {
|
|
159
|
+
return soFar.then(() => {
|
|
160
|
+
/**
|
|
161
|
+
* @type {string}
|
|
162
|
+
*/
|
|
163
|
+
const relativePath = PackageManifest.normalizePath(path.relative(basePath, filePath));
|
|
164
|
+
if (!PackageManifest.isIgnored(relativePath)) {
|
|
165
|
+
return hashFile(filePath).then((hash) => {
|
|
166
|
+
fileHashesMap.set(relativePath, hash);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}, Promise.resolve(null));
|
|
171
|
+
|
|
172
|
+
generateManifestPromise.then(() => {
|
|
173
|
+
resolve(new PackageManifest(fileHashesMap));
|
|
174
|
+
}, reject);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
*
|
|
180
|
+
* @param filePath {string}
|
|
181
|
+
* @return {Promise<string>}
|
|
182
|
+
*/
|
|
183
|
+
function hashFile(filePath) {
|
|
184
|
+
/**
|
|
185
|
+
* @type {fs.ReadStream}
|
|
186
|
+
*/
|
|
187
|
+
const readStream = fs.createReadStream(filePath);
|
|
188
|
+
return hashStream(readStream);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
* @param readStream {stream.Readable}
|
|
194
|
+
* @return {Promise<string>}
|
|
195
|
+
*/
|
|
196
|
+
function hashStream(readStream) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
/**
|
|
199
|
+
* @type {stream.Transform}
|
|
200
|
+
*/
|
|
201
|
+
const _hashStream = crypto.createHash(HASH_ALGORITHM)
|
|
202
|
+
|
|
203
|
+
readStream
|
|
204
|
+
.on('error', (error) => {
|
|
205
|
+
_hashStream.end();
|
|
206
|
+
reject(error);
|
|
207
|
+
})
|
|
208
|
+
.on('end', () => {
|
|
209
|
+
_hashStream.end();
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @type {Buffer}
|
|
213
|
+
*/
|
|
214
|
+
const buffer = _hashStream.read();
|
|
215
|
+
/**
|
|
216
|
+
* @type {string}
|
|
217
|
+
*/
|
|
218
|
+
const hash = buffer.toString('hex');
|
|
219
|
+
|
|
220
|
+
resolve(hash);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
readStream.pipe(_hashStream);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = { generatePackageHashFromDirectory };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* code based on appcenter-cli
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { promises: fs } = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param dir {string}
|
|
11
|
+
* @return {Promise<string[]>}
|
|
12
|
+
*/
|
|
13
|
+
async function walk(dir) {
|
|
14
|
+
const stats = await fs.stat(dir);
|
|
15
|
+
if (stats.isDirectory()) {
|
|
16
|
+
/**
|
|
17
|
+
* @type {string[]}
|
|
18
|
+
*/
|
|
19
|
+
let files = [];
|
|
20
|
+
for (const file of await fs.readdir(dir)) {
|
|
21
|
+
files = files.concat(await walk(path.join(dir, file)));
|
|
22
|
+
}
|
|
23
|
+
return files;
|
|
24
|
+
} else {
|
|
25
|
+
return [dir];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { walk };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function showLogo() {
|
|
2
|
+
const logo = `
|
|
3
|
+
|
|
4
|
+
+------------------------------------------------------------------+
|
|
5
|
+
| |
|
|
6
|
+
| ______ __ ____ __ |
|
|
7
|
+
| / ____/___ ____/ /__ / __ \\__ _______/ /_ |
|
|
8
|
+
| / / / __ \\/ __ / _ \\/ /_/ / / / / ___/ __ \\ |
|
|
9
|
+
| / /___/ /_/ / /_/ / __/ ____/ /_/ (__ ) / / / |
|
|
10
|
+
| \\____/\\____/\\__,_/\\___/_/ \\__,_/____/_/ /_/ |
|
|
11
|
+
| |
|
|
12
|
+
| |
|
|
13
|
+
| 🚀 @bravemobile/react-native-code-push |
|
|
14
|
+
+------------------------------------------------------------------+
|
|
15
|
+
|
|
16
|
+
Please refer to help command for more information.
|
|
17
|
+
|
|
18
|
+
(interactive mode is not supported yet.)
|
|
19
|
+
`;
|
|
20
|
+
console.log(logo);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = { showLogo };
|
package/cli/utils/zip.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* code based on appcenter-cli
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const yazl = require('yazl');
|
|
8
|
+
const { generateRandomFilename, normalizePath, isDirectory } = require('./file-utils');
|
|
9
|
+
const { walk } = require('./promisfied-fs');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {{ sourceLocation: string, targetLocation: string }} ReleaseFile
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param updateContentsPath {string}
|
|
17
|
+
* @return {Promise<string>}
|
|
18
|
+
*/
|
|
19
|
+
function zip(updateContentsPath) {
|
|
20
|
+
|
|
21
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
22
|
+
return new Promise(async (resolve, reject) => {
|
|
23
|
+
/**
|
|
24
|
+
* @type {ReleaseFile[]}
|
|
25
|
+
*/
|
|
26
|
+
const releaseFiles = [];
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
if (!isDirectory(updateContentsPath)) {
|
|
30
|
+
releaseFiles.push({
|
|
31
|
+
sourceLocation: updateContentsPath,
|
|
32
|
+
targetLocation: normalizePath(path.basename(updateContentsPath)), // Put the file in the root
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
error.message = error.message + ' Make sure you have added the platform you are making a release to.`.';
|
|
37
|
+
reject(error);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @type {string}
|
|
42
|
+
*/
|
|
43
|
+
const directoryPath = updateContentsPath;
|
|
44
|
+
const baseDirectoryPath = path.join(directoryPath, '..'); // For legacy reasons, put the root directory in the zip
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @type {string[]}
|
|
48
|
+
*/
|
|
49
|
+
const files = await walk(updateContentsPath);
|
|
50
|
+
|
|
51
|
+
files.forEach((filePath) => {
|
|
52
|
+
/**
|
|
53
|
+
* @type {string}
|
|
54
|
+
*/
|
|
55
|
+
const relativePath = path.relative(baseDirectoryPath, filePath);
|
|
56
|
+
releaseFiles.push({
|
|
57
|
+
sourceLocation: filePath,
|
|
58
|
+
targetLocation: normalizePath(relativePath),
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @type {string}
|
|
64
|
+
*/
|
|
65
|
+
const packagePath = path.join(process.cwd(), generateRandomFilename(15) + '.zip');
|
|
66
|
+
const zipFile = new yazl.ZipFile();
|
|
67
|
+
/**
|
|
68
|
+
* @type {fs.WriteStream}
|
|
69
|
+
*/
|
|
70
|
+
const writeStream = fs.createWriteStream(packagePath);
|
|
71
|
+
|
|
72
|
+
zipFile.outputStream
|
|
73
|
+
.pipe(writeStream)
|
|
74
|
+
.on('error', (error) => {
|
|
75
|
+
reject(error);
|
|
76
|
+
})
|
|
77
|
+
.on('close', () => {
|
|
78
|
+
resolve(packagePath);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
releaseFiles.forEach((releaseFile) => {
|
|
82
|
+
zipFile.addFile(releaseFile.sourceLocation, releaseFile.targetLocation);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
zipFile.end();
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = zip;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
CliConfigInterface,
|
|
6
|
+
ReleaseHistoryInterface,
|
|
7
|
+
} from "@bravemobile/react-native-code-push";
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import axios from "axios"; // install as devDependency
|
|
10
|
+
import * as SupabaseSDK from "@supabase/supabase-js"; // install as devDependency
|
|
11
|
+
|
|
12
|
+
const SUPABASE_URL = process.env.SUPABASE_URL;
|
|
13
|
+
const SUPABASE_KEY = process.env.SUPABASE_KEY;
|
|
14
|
+
const supabase = SupabaseSDK.createClient(SUPABASE_URL!, SUPABASE_KEY!);
|
|
15
|
+
const BUCKET_NAME = "codePush";
|
|
16
|
+
const STORAGE_HOST = `${SUPABASE_URL}/storage/v1/object/public`;
|
|
17
|
+
|
|
18
|
+
function historyJsonFileRemotePath(
|
|
19
|
+
platform: "ios" | "android",
|
|
20
|
+
identifier: string,
|
|
21
|
+
binaryVersion: string,
|
|
22
|
+
) {
|
|
23
|
+
return `histories/${platform}/${identifier}/${binaryVersion}.json`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function bundleFileRemotePath(
|
|
27
|
+
platform: "ios" | "android",
|
|
28
|
+
identifier: string,
|
|
29
|
+
fileName: string,
|
|
30
|
+
) {
|
|
31
|
+
return `bundles/${platform}/${identifier}/${fileName}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Config: CliConfigInterface = {
|
|
35
|
+
bundleUploader: async (
|
|
36
|
+
source: string,
|
|
37
|
+
platform: "ios" | "android",
|
|
38
|
+
identifier = "staging",
|
|
39
|
+
): Promise<{downloadUrl: string}> => {
|
|
40
|
+
const fileName = source.split("/").pop();
|
|
41
|
+
const fileStream = fs.createReadStream(source);
|
|
42
|
+
const remotePath = bundleFileRemotePath(platform, identifier, fileName!);
|
|
43
|
+
|
|
44
|
+
const {data, error} = await supabase.storage
|
|
45
|
+
.from(BUCKET_NAME)
|
|
46
|
+
.upload(remotePath, fileStream, {
|
|
47
|
+
contentType: "application/zip",
|
|
48
|
+
duplex: "half",
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (error) {
|
|
52
|
+
console.error("Error uploading file:", error.message);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
console.log("Bundle File uploaded:", `${STORAGE_HOST}/${data.fullPath}`);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
downloadUrl: `${STORAGE_HOST}/${data.fullPath}`,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
getReleaseHistory: async (
|
|
64
|
+
targetBinaryVersion: string,
|
|
65
|
+
platform: "ios" | "android",
|
|
66
|
+
identifier = "staging",
|
|
67
|
+
): Promise<ReleaseHistoryInterface> => {
|
|
68
|
+
const remoteJsonPath = historyJsonFileRemotePath(
|
|
69
|
+
platform,
|
|
70
|
+
identifier,
|
|
71
|
+
targetBinaryVersion,
|
|
72
|
+
);
|
|
73
|
+
const {data} = await axios.get(
|
|
74
|
+
`${STORAGE_HOST}/${BUCKET_NAME}/${remoteJsonPath}`,
|
|
75
|
+
);
|
|
76
|
+
return data as ReleaseHistoryInterface;
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
setReleaseHistory: async (
|
|
80
|
+
targetBinaryVersion: string,
|
|
81
|
+
jsonFilePath: string,
|
|
82
|
+
releaseInfo: ReleaseHistoryInterface,
|
|
83
|
+
platform: "ios" | "android",
|
|
84
|
+
identifier = "staging",
|
|
85
|
+
): Promise<void> => {
|
|
86
|
+
// upload JSON file or call API using `releaseInfo` metadata.
|
|
87
|
+
|
|
88
|
+
const fileContent = fs.readFileSync(jsonFilePath, "utf8");
|
|
89
|
+
const remoteJsonPath = historyJsonFileRemotePath(
|
|
90
|
+
platform,
|
|
91
|
+
identifier,
|
|
92
|
+
targetBinaryVersion,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const {data, error} = await supabase.storage
|
|
96
|
+
.from(BUCKET_NAME)
|
|
97
|
+
.upload(remoteJsonPath, Buffer.from(fileContent), {
|
|
98
|
+
contentType: "application/json",
|
|
99
|
+
cacheControl: "5",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (error) {
|
|
103
|
+
console.error("Error uploading file:", error.message);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
console.log(
|
|
108
|
+
"Release history File uploaded:",
|
|
109
|
+
`${STORAGE_HOST}/${data.fullPath}`,
|
|
110
|
+
);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
module.exports = Config;
|
package/docs/setup-android.md
CHANGED
|
@@ -19,15 +19,7 @@ In order to integrate CodePush into your Android project, please perform the fol
|
|
|
19
19
|
|
|
20
20
|
### Plugin Installation and Configuration for React Native 0.60 version and above (Android)
|
|
21
21
|
|
|
22
|
-
1. In your `android/
|
|
23
|
-
|
|
24
|
-
```gradle
|
|
25
|
-
...
|
|
26
|
-
include ':app', ':react-native-code-push'
|
|
27
|
-
project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-code-push/android/app')
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
2. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition to the end of the file:
|
|
22
|
+
1. In your `android/app/build.gradle` file, add the `codepush.gradle` file as an additional build task definition to the end of the file:
|
|
31
23
|
|
|
32
24
|
```gradle
|
|
33
25
|
...
|
|
@@ -35,7 +27,7 @@ In order to integrate CodePush into your Android project, please perform the fol
|
|
|
35
27
|
...
|
|
36
28
|
```
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
2. Update the `MainApplication` file to use CodePush via the following changes:
|
|
39
31
|
|
|
40
32
|
For React Native 0.73 and above: update the `MainApplication.kt`
|
|
41
33
|
|
|
@@ -83,7 +75,7 @@ In order to integrate CodePush into your Android project, please perform the fol
|
|
|
83
75
|
}
|
|
84
76
|
```
|
|
85
77
|
|
|
86
|
-
|
|
78
|
+
3. Add the Deployment key to `strings.xml`:
|
|
87
79
|
|
|
88
80
|
To let the CodePush runtime know which deployment it should query for updates, open your app's `strings.xml` file and add a new string named `CodePushDeploymentKey`, whose value is the key of the deployment you want to configure this app against (like the key for the `Staging` deployment for the `FooBar` app). You can retrieve this value by running `appcenter codepush deployment list -a <ownerName>/<appName> -k` in the CodePush CLI (the `-k` flag is necessary since keys aren't displayed by default) and copying the value of the `Key` column which corresponds to the deployment you want to use (see below). Note that using the deployment's name (like Staging) will not work. The "friendly name" is intended only for authenticated management usage from the CLI, and not for public consumption within your app.
|
|
89
81
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import globals from "globals";
|
|
2
|
+
import pluginJs from "@eslint/js";
|
|
3
|
+
import tseslint from "typescript-eslint";
|
|
4
|
+
import pluginReact from "eslint-plugin-react";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export default [
|
|
8
|
+
{files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"]},
|
|
9
|
+
{languageOptions: { globals: {
|
|
10
|
+
...globals.node,
|
|
11
|
+
...globals.mocha,
|
|
12
|
+
...globals.browser,
|
|
13
|
+
...globals.jest
|
|
14
|
+
} }},
|
|
15
|
+
pluginJs.configs.recommended,
|
|
16
|
+
...tseslint.configs.recommended,
|
|
17
|
+
pluginReact.configs.flat.recommended,
|
|
18
|
+
{"rules": {
|
|
19
|
+
"@typescript-eslint/no-require-imports": "warn",
|
|
20
|
+
"@typescript-eslint/no-unused-vars": "warn",
|
|
21
|
+
"@typescript-eslint/no-unused-expressions": "warn",
|
|
22
|
+
"no-empty": "warn",
|
|
23
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
24
|
+
"no-var": "warn",
|
|
25
|
+
"@typescript-eslint/no-this-alias": "warn",
|
|
26
|
+
"@typescript-eslint/no-empty-object-type": "warn",
|
|
27
|
+
"react/no-deprecated": "warn",
|
|
28
|
+
"no-extra-boolean-cast": "warn",
|
|
29
|
+
"no-useless-escape": "warn",
|
|
30
|
+
"no-control-regex": "warn",
|
|
31
|
+
}}
|
|
32
|
+
];
|
package/package-mixins.js
CHANGED
|
@@ -5,7 +5,7 @@ import log from "./logging";
|
|
|
5
5
|
// package objects with additional functionality/properties
|
|
6
6
|
// beyond what is included in the metadata sent by the server.
|
|
7
7
|
module.exports = (NativeCodePush) => {
|
|
8
|
-
const remote = (
|
|
8
|
+
const remote = () => {
|
|
9
9
|
return {
|
|
10
10
|
async download(downloadProgressCallback) {
|
|
11
11
|
if (!this.downloadUrl) {
|
|
@@ -30,13 +30,6 @@ module.exports = (NativeCodePush) => {
|
|
|
30
30
|
|
|
31
31
|
const downloadedPackage = await NativeCodePush.downloadUpdate(updatePackageCopy, !!downloadProgressCallback);
|
|
32
32
|
|
|
33
|
-
if (reportStatusDownload) {
|
|
34
|
-
reportStatusDownload(this)
|
|
35
|
-
.catch((err) => {
|
|
36
|
-
log(`Report download status failed: ${err}`);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
33
|
return { ...downloadedPackage, ...local };
|
|
41
34
|
} finally {
|
|
42
35
|
downloadProgressSubscription && downloadProgressSubscription.remove();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bravemobile/react-native-code-push",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.0-alpha.0",
|
|
4
4
|
"description": "React Native plugin for the CodePush service",
|
|
5
5
|
"main": "CodePush.js",
|
|
6
6
|
"typings": "typings/react-native-code-push.d.ts",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
],
|
|
13
13
|
"author": "Soomgo Mobile Team (originally Microsoft Corporation)",
|
|
14
14
|
"license": "MIT",
|
|
15
|
+
"bin": {
|
|
16
|
+
"code-push": "cli/index.js"
|
|
17
|
+
},
|
|
15
18
|
"scripts": {
|
|
16
19
|
"clean": "shx rm -rf bin",
|
|
17
20
|
"setup": "npm install --quiet --no-progress",
|
|
@@ -29,53 +32,53 @@
|
|
|
29
32
|
"test:debugger:android": "mocha --recursive --inspect-brk=0.0.0.0 bin/test --android",
|
|
30
33
|
"test:debugger:ios": "mocha --recursive --inspect-brk=0.0.0.0 bin/test --ios",
|
|
31
34
|
"tslint": "tslint -c tslint.json test/**/*.ts",
|
|
32
|
-
"publish": "npm publish --access=public"
|
|
35
|
+
"publish": "npm publish --access=public",
|
|
36
|
+
"eslint": "eslint --quiet .",
|
|
37
|
+
"jest": "jest versioning/*"
|
|
33
38
|
},
|
|
34
39
|
"repository": {
|
|
35
40
|
"type": "git",
|
|
36
|
-
"url": "https://github.com/Soomgo-Mobile/react-native-code-push"
|
|
41
|
+
"url": "git+https://github.com/Soomgo-Mobile/react-native-code-push.git"
|
|
37
42
|
},
|
|
38
43
|
"dependencies": {
|
|
39
|
-
"
|
|
40
|
-
"glob": "^7.1.7",
|
|
44
|
+
"commander": "^12.1.0",
|
|
41
45
|
"hoist-non-react-statics": "^3.3.2",
|
|
42
|
-
"inquirer": "^8.1.5",
|
|
43
|
-
"plist": "^3.0.4",
|
|
44
46
|
"semver": "^7.3.5",
|
|
45
|
-
"
|
|
47
|
+
"shelljs": "^0.8.5",
|
|
48
|
+
"yazl": "^3.3.1"
|
|
46
49
|
},
|
|
47
50
|
"devDependencies": {
|
|
51
|
+
"@babel/core": "^7.26.0",
|
|
52
|
+
"@babel/preset-env": "^7.26.0",
|
|
53
|
+
"@eslint/js": "^9.13.0",
|
|
48
54
|
"@types/assert": "^1.5.2",
|
|
49
55
|
"@types/mkdirp": "^1.0.1",
|
|
50
56
|
"@types/mocha": "^9.0.0",
|
|
51
57
|
"@types/node": "^14.0.27",
|
|
52
58
|
"@types/q": "^1.5.4",
|
|
59
|
+
"@types/semver": "^7.5.8",
|
|
60
|
+
"@types/shelljs": "^0.8.15",
|
|
53
61
|
"archiver": "latest",
|
|
62
|
+
"babel-jest": "^29.7.0",
|
|
54
63
|
"body-parser": "latest",
|
|
55
64
|
"code-push-plugin-testing-framework": "file:./code-push-plugin-testing-framework",
|
|
56
65
|
"del": "v6.0.0",
|
|
66
|
+
"eslint": "^9.13.0",
|
|
67
|
+
"eslint-plugin-react": "^7.37.2",
|
|
57
68
|
"express": "latest",
|
|
69
|
+
"globals": "^15.11.0",
|
|
70
|
+
"jest": "^29.7.0",
|
|
58
71
|
"mkdirp": "latest",
|
|
59
72
|
"mocha": "^9.2.0",
|
|
60
73
|
"q": "^1.5.1",
|
|
61
|
-
"run-sequence": "latest",
|
|
62
74
|
"shx": "^0.3.4",
|
|
63
75
|
"slash": "^3.0.0",
|
|
76
|
+
"ts-node": "^10.9.2",
|
|
64
77
|
"tslint": "^6.1.3",
|
|
65
|
-
"typescript": "^4.4.3"
|
|
78
|
+
"typescript": "^4.4.3",
|
|
79
|
+
"typescript-eslint": "^8.11.0"
|
|
66
80
|
},
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"packageInstance": "new CodePush(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)"
|
|
70
|
-
},
|
|
71
|
-
"ios": {
|
|
72
|
-
"sharedLibraries": [
|
|
73
|
-
"libz"
|
|
74
|
-
]
|
|
75
|
-
},
|
|
76
|
-
"commands": {
|
|
77
|
-
"postlink": "node node_modules/react-native-code-push/scripts/postlink/run",
|
|
78
|
-
"postunlink": "node node_modules/react-native-code-push/scripts/postunlink/run"
|
|
79
|
-
}
|
|
81
|
+
"engines": {
|
|
82
|
+
"node": ">=18"
|
|
80
83
|
}
|
|
81
84
|
}
|
package/react-native.config.js
CHANGED
|
@@ -2,8 +2,10 @@ module.exports = {
|
|
|
2
2
|
dependency: {
|
|
3
3
|
platforms: {
|
|
4
4
|
android: {
|
|
5
|
+
packageImportPath: "import com.microsoft.codepush.react.CodePush;",
|
|
5
6
|
packageInstance:
|
|
6
|
-
"new CodePush(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)"
|
|
7
|
+
"new CodePush(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)",
|
|
8
|
+
sourceDir: './android/app'
|
|
7
9
|
}
|
|
8
10
|
}
|
|
9
11
|
}
|