@bravemobile/react-native-code-push 12.0.1 → 12.1.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/README.md +1 -1
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java +1 -52
- package/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java +4 -43
- package/bin/code-push.js +6 -0
- package/cli/commands/bundleCommand/{bundleCodePush.js → bundleCodePush.ts} +16 -24
- package/cli/commands/bundleCommand/{index.js → index.ts} +13 -14
- package/cli/commands/createHistoryCommand/{createReleaseHistory.js → createReleaseHistory.ts} +11 -28
- package/cli/commands/createHistoryCommand/{index.js → index.ts} +12 -13
- package/cli/commands/initCommand/{index.js → index.ts} +3 -3
- package/cli/commands/initCommand/{initAndroid.js → initAndroid.ts} +6 -11
- package/cli/commands/initCommand/initIos.ts +123 -0
- package/cli/commands/initCommand/test/{initAndroid.test.js → initAndroid.test.ts} +5 -4
- package/cli/commands/initCommand/test/{initIos.test.js → initIos.test.ts} +2 -1
- package/cli/commands/releaseCommand/{addToReleaseHistory.js → addToReleaseHistory.ts} +17 -45
- package/cli/commands/releaseCommand/{index.js → index.ts} +24 -25
- package/cli/commands/releaseCommand/release.ts +72 -0
- package/cli/commands/showHistoryCommand/{index.js → index.ts} +11 -12
- package/cli/commands/updateHistoryCommand/{index.js → index.ts} +17 -18
- package/cli/commands/updateHistoryCommand/{updateReleaseHistory.js → updateReleaseHistory.ts} +15 -41
- package/cli/constant.ts +4 -0
- package/cli/dist/commands/bundleCommand/bundleCodePush.js +34 -0
- package/cli/dist/commands/bundleCommand/index.js +14 -0
- package/cli/dist/commands/createHistoryCommand/createReleaseHistory.js +25 -0
- package/cli/dist/commands/createHistoryCommand/index.js +14 -0
- package/cli/dist/commands/initCommand/index.js +12 -0
- package/cli/dist/commands/initCommand/initAndroid.js +37 -0
- package/cli/{commands → dist/commands}/initCommand/initIos.js +13 -33
- package/cli/dist/commands/initCommand/test/initAndroid.test.js +75 -0
- package/cli/dist/commands/initCommand/test/initIos.test.js +95 -0
- package/cli/dist/commands/releaseCommand/addToReleaseHistory.js +32 -0
- package/cli/dist/commands/releaseCommand/index.js +38 -0
- package/cli/dist/commands/releaseCommand/release.js +36 -0
- package/cli/dist/commands/showHistoryCommand/index.js +14 -0
- package/cli/dist/commands/updateHistoryCommand/index.js +30 -0
- package/cli/dist/commands/updateHistoryCommand/updateReleaseHistory.js +26 -0
- package/cli/dist/constant.js +4 -0
- package/cli/dist/functions/getReactTempDir.js +10 -0
- package/cli/{functions → dist/functions}/makeCodePushBundle.js +5 -11
- package/cli/{functions → dist/functions}/prepareToBundleJS.js +2 -5
- package/cli/{functions → dist/functions}/runExpoBundleCommand.js +3 -21
- package/cli/{functions → dist/functions}/runHermesEmitBinaryCommand.js +12 -68
- package/cli/{functions → dist/functions}/runReactNativeBundleCommand.js +3 -23
- package/cli/dist/index.js +38 -0
- package/cli/dist/utils/file-utils.js +19 -0
- package/cli/dist/utils/fsUtils.js +37 -0
- package/cli/{utils → dist/utils}/hash-utils.js +19 -127
- package/cli/{utils → dist/utils}/promisfied-fs.js +5 -16
- package/cli/dist/utils/showLogo.js +21 -0
- package/cli/{utils → dist/utils}/zip.js +15 -51
- package/cli/functions/{getReactTempDir.js → getReactTempDir.ts} +2 -6
- package/cli/functions/makeCodePushBundle.ts +26 -0
- package/cli/functions/prepareToBundleJS.ts +10 -0
- package/cli/functions/runExpoBundleCommand.ts +45 -0
- package/cli/functions/runHermesEmitBinaryCommand.ts +186 -0
- package/cli/functions/runReactNativeBundleCommand.ts +51 -0
- package/cli/index.ts +48 -0
- package/cli/package.json +33 -0
- package/cli/utils/{file-utils.js → file-utils.ts} +4 -21
- package/cli/utils/{fsUtils.js → fsUtils.ts} +12 -19
- package/cli/utils/hash-utils.ts +146 -0
- package/cli/utils/promisfied-fs.ts +19 -0
- package/cli/utils/{showLogo.js → showLogo.ts} +1 -3
- package/cli/utils/zip.ts +65 -0
- package/expo/plugin/withCodePush.js +1 -2
- package/package.json +42 -12
- package/{AlertAdapter.js → src/AlertAdapter.js} +5 -5
- package/CONTRIBUTING.md +0 -134
- package/SECURITY.md +0 -41
- package/android/app/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java +0 -17
- package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/android/gradle/wrapper/gradle-wrapper.properties +0 -5
- package/android/gradlew +0 -164
- package/android/gradlew.bat +0 -90
- package/app.plugin.js +0 -1
- package/babel.config.js +0 -3
- package/cli/commands/releaseCommand/release.js +0 -114
- package/cli/constant.js +0 -6
- package/cli/index.js +0 -49
- package/docs/api-android.md +0 -83
- package/docs/api-ios.md +0 -31
- package/docs/api-js.md +0 -592
- package/docs/multi-deployment-testing-android.md +0 -148
- package/docs/multi-deployment-testing-ios.md +0 -59
- package/eslint.config.mjs +0 -32
- package/scripts/generateBundledResourcesHash.js +0 -125
- package/scripts/getFilesInFolder.js +0 -19
- package/scripts/recordFilesBeforeBundleCommand.js +0 -41
- package/tsconfig.json +0 -18
- package/tslint.json +0 -32
- /package/{CodePush.js → src/CodePush.js} +0 -0
- /package/{logging.js → src/logging.js} +0 -0
- /package/{package-mixins.js → src/package-mixins.js} +0 -0
- /package/{versioning → src/versioning}/BaseVersioning.js +0 -0
- /package/{versioning → src/versioning}/BaseVersioning.test.js +0 -0
- /package/{versioning → src/versioning}/IncrementalVersioning.js +0 -0
- /package/{versioning → src/versioning}/IncrementalVersioning.test.js +0 -0
- /package/{versioning → src/versioning}/SemverVersioning.js +0 -0
- /package/{versioning → src/versioning}/SemverVersioning.test.js +0 -0
- /package/{versioning → src/versioning}/index.js +0 -0
|
@@ -1,46 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* targetBinaryVersion: string,
|
|
19
|
-
* jsonFilePath: string,
|
|
20
|
-
* releaseInfo: ReleaseHistoryInterface,
|
|
21
|
-
* platform: string,
|
|
22
|
-
* identifier?: string
|
|
23
|
-
* ): Promise<void>}
|
|
24
|
-
* @param platform {"ios" | "android"}
|
|
25
|
-
* @param identifier {string?}
|
|
26
|
-
* @param mandatory {boolean?}
|
|
27
|
-
* @param enable {boolean?}
|
|
28
|
-
* @param rollout {number?}
|
|
29
|
-
* @returns {Promise<void>}
|
|
30
|
-
*/
|
|
31
|
-
async function addToReleaseHistory(
|
|
32
|
-
appVersion,
|
|
33
|
-
binaryVersion,
|
|
34
|
-
bundleDownloadUrl,
|
|
35
|
-
packageHash,
|
|
36
|
-
getReleaseHistory,
|
|
37
|
-
setReleaseHistory,
|
|
38
|
-
platform,
|
|
39
|
-
identifier,
|
|
40
|
-
mandatory,
|
|
41
|
-
enable,
|
|
42
|
-
rollout
|
|
43
|
-
) {
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import type { CliConfigInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
4
|
+
|
|
5
|
+
export async function addToReleaseHistory(
|
|
6
|
+
appVersion: string,
|
|
7
|
+
binaryVersion: string,
|
|
8
|
+
bundleDownloadUrl: string,
|
|
9
|
+
packageHash: string,
|
|
10
|
+
getReleaseHistory: CliConfigInterface['getReleaseHistory'],
|
|
11
|
+
setReleaseHistory: CliConfigInterface['setReleaseHistory'],
|
|
12
|
+
platform: 'ios' | 'android',
|
|
13
|
+
identifier: string | undefined,
|
|
14
|
+
mandatory: boolean,
|
|
15
|
+
enable: boolean,
|
|
16
|
+
rollout: number | undefined,
|
|
17
|
+
): Promise<void> {
|
|
44
18
|
const releaseHistory = await getReleaseHistory(binaryVersion, platform, identifier);
|
|
45
19
|
|
|
46
20
|
const updateInfo = releaseHistory[appVersion]
|
|
@@ -77,5 +51,3 @@ async function addToReleaseHistory(
|
|
|
77
51
|
process.exit(1)
|
|
78
52
|
}
|
|
79
53
|
}
|
|
80
|
-
|
|
81
|
-
module.exports = { addToReleaseHistory: addToReleaseHistory }
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { program, Option } from "commander";
|
|
2
|
+
import { findAndReadConfigFile } from "../../utils/fsUtils.js";
|
|
3
|
+
import { release } from "./release.js";
|
|
4
|
+
import { OUTPUT_BUNDLE_DIR, CONFIG_FILE_NAME, ROOT_OUTPUT_DIR, ENTRY_FILE } from "../../constant.js";
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
binaryVersion: string;
|
|
8
|
+
appVersion: string;
|
|
9
|
+
framework: 'expo' | undefined;
|
|
10
|
+
platform: 'ios' | 'android';
|
|
11
|
+
identifier?: string;
|
|
12
|
+
config: string;
|
|
13
|
+
outputPath: string;
|
|
14
|
+
entryFile: string;
|
|
15
|
+
bundleName: string;
|
|
16
|
+
mandatory: boolean;
|
|
17
|
+
enable: boolean;
|
|
18
|
+
rollout?: number;
|
|
19
|
+
skipBundle: boolean;
|
|
20
|
+
skipCleanup: boolean;
|
|
21
|
+
outputBundleDir: string;
|
|
22
|
+
}
|
|
5
23
|
|
|
6
24
|
program.command('release')
|
|
7
25
|
.description('Deploys a new CodePush update for a target binary app.\nAfter creating the CodePush bundle, it uploads the file and updates the ReleaseHistory information.\n`bundleUploader`, `getReleaseHistory`, and `setReleaseHistory` functions should be implemented in the config file.')
|
|
@@ -20,26 +38,7 @@ program.command('release')
|
|
|
20
38
|
.option('--skip-bundle <bool>', 'skip bundle process', parseBoolean, false)
|
|
21
39
|
.option('--skip-cleanup <bool>', 'skip cleanup process', parseBoolean, false)
|
|
22
40
|
.option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
|
|
23
|
-
|
|
24
|
-
* @param {Object} options
|
|
25
|
-
* @param {string} options.binaryVersion
|
|
26
|
-
* @param {string} options.appVersion
|
|
27
|
-
* @param {string} options.framework
|
|
28
|
-
* @param {string} options.platform
|
|
29
|
-
* @param {string} options.identifier
|
|
30
|
-
* @param {string} options.config
|
|
31
|
-
* @param {string} options.outputPath
|
|
32
|
-
* @param {string} options.entryFile
|
|
33
|
-
* @param {string} options.bundleName
|
|
34
|
-
* @param {string} options.mandatory
|
|
35
|
-
* @param {string} options.enable
|
|
36
|
-
* @param {number} options.rollout
|
|
37
|
-
* @param {string} options.skipBundle
|
|
38
|
-
* @param {string} options.skipCleanup
|
|
39
|
-
* @param {string} options.outputBundleDir
|
|
40
|
-
* @return {void}
|
|
41
|
-
*/
|
|
42
|
-
.action(async (options) => {
|
|
41
|
+
.action(async (options: Options) => {
|
|
43
42
|
const config = findAndReadConfigFile(process.cwd(), options.config);
|
|
44
43
|
|
|
45
44
|
if (typeof options.rollout === 'number' && (options.rollout < 0 || options.rollout > 100)) {
|
|
@@ -70,7 +69,7 @@ program.command('release')
|
|
|
70
69
|
console.log('🚀 Release completed.')
|
|
71
70
|
});
|
|
72
71
|
|
|
73
|
-
function parseBoolean(value) {
|
|
72
|
+
function parseBoolean(value: string): boolean | undefined {
|
|
74
73
|
if (value === 'true') return true;
|
|
75
74
|
if (value === 'false') return false;
|
|
76
75
|
else return undefined;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { bundleCodePush } from "../bundleCommand/bundleCodePush.js";
|
|
4
|
+
import { addToReleaseHistory } from "./addToReleaseHistory.js";
|
|
5
|
+
import type { CliConfigInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
6
|
+
|
|
7
|
+
export async function release(
|
|
8
|
+
bundleUploader: CliConfigInterface['bundleUploader'],
|
|
9
|
+
getReleaseHistory: CliConfigInterface['getReleaseHistory'],
|
|
10
|
+
setReleaseHistory: CliConfigInterface['setReleaseHistory'],
|
|
11
|
+
binaryVersion: string,
|
|
12
|
+
appVersion: string,
|
|
13
|
+
framework: 'expo' | undefined,
|
|
14
|
+
platform: 'ios' | 'android',
|
|
15
|
+
identifier: string | undefined,
|
|
16
|
+
outputPath: string,
|
|
17
|
+
entryFile: string,
|
|
18
|
+
jsBundleName: string,
|
|
19
|
+
mandatory: boolean,
|
|
20
|
+
enable: boolean,
|
|
21
|
+
rollout: number | undefined,
|
|
22
|
+
skipBundle: boolean,
|
|
23
|
+
skipCleanup: boolean,
|
|
24
|
+
bundleDirectory: string,
|
|
25
|
+
): Promise<void> {
|
|
26
|
+
const bundleFileName = skipBundle
|
|
27
|
+
? readBundleFileNameFrom(bundleDirectory)
|
|
28
|
+
: await bundleCodePush(framework, platform, outputPath, entryFile, jsBundleName, bundleDirectory);
|
|
29
|
+
const bundleFilePath = `${bundleDirectory}/${bundleFileName}`;
|
|
30
|
+
|
|
31
|
+
const downloadUrl = await (async () => {
|
|
32
|
+
try {
|
|
33
|
+
const { downloadUrl } = await bundleUploader(bundleFilePath, platform, identifier);
|
|
34
|
+
return downloadUrl
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Failed to upload the bundle file. Exiting the program.\n', error)
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
|
|
41
|
+
await addToReleaseHistory(
|
|
42
|
+
appVersion,
|
|
43
|
+
binaryVersion,
|
|
44
|
+
downloadUrl,
|
|
45
|
+
bundleFileName,
|
|
46
|
+
getReleaseHistory,
|
|
47
|
+
setReleaseHistory,
|
|
48
|
+
platform,
|
|
49
|
+
identifier,
|
|
50
|
+
mandatory,
|
|
51
|
+
enable,
|
|
52
|
+
rollout,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if (!skipCleanup) {
|
|
56
|
+
cleanUpOutputs(outputPath);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function cleanUpOutputs(dir: string) {
|
|
61
|
+
fs.rmSync(dir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function readBundleFileNameFrom(bundleDirectory: string): string {
|
|
65
|
+
const files = fs.readdirSync(bundleDirectory);
|
|
66
|
+
if (files.length !== 1) {
|
|
67
|
+
console.error('The bundlePath must contain only one file.');
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const bundleFilePath = path.join(bundleDirectory, files[0]);
|
|
71
|
+
return path.basename(bundleFilePath);
|
|
72
|
+
}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { program, Option } from "commander";
|
|
2
|
+
import { findAndReadConfigFile } from "../../utils/fsUtils.js";
|
|
3
|
+
import { CONFIG_FILE_NAME } from "../../constant.js";
|
|
4
|
+
|
|
5
|
+
type Options = {
|
|
6
|
+
binaryVersion: string;
|
|
7
|
+
platform: 'ios' | 'android';
|
|
8
|
+
identifier?: string;
|
|
9
|
+
config: string;
|
|
10
|
+
}
|
|
4
11
|
|
|
5
12
|
program.command('show-history')
|
|
6
13
|
.description('Retrieves and prints the release history of a specific binary version.\n`getReleaseHistory` function should be implemented in the config file.')
|
|
@@ -8,15 +15,7 @@ program.command('show-history')
|
|
|
8
15
|
.addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
|
|
9
16
|
.option('-i, --identifier <string>', 'reserved characters to distinguish the release.')
|
|
10
17
|
.option('-c, --config <path>', 'configuration file name (JS/TS)', CONFIG_FILE_NAME)
|
|
11
|
-
|
|
12
|
-
* @param {Object} options
|
|
13
|
-
* @param {string} options.binaryVersion
|
|
14
|
-
* @param {string} options.platform
|
|
15
|
-
* @param {string} options.identifier
|
|
16
|
-
* @param {string} options.config
|
|
17
|
-
* @return {void}
|
|
18
|
-
*/
|
|
19
|
-
.action(async (options) => {
|
|
18
|
+
.action(async (options: Options) => {
|
|
20
19
|
const config = findAndReadConfigFile(process.cwd(), options.config);
|
|
21
20
|
|
|
22
21
|
const releaseHistory = await config.getReleaseHistory(
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { program, Option } from "commander";
|
|
2
|
+
import { findAndReadConfigFile } from "../../utils/fsUtils.js";
|
|
3
|
+
import { updateReleaseHistory } from "./updateReleaseHistory.js";
|
|
4
|
+
import { CONFIG_FILE_NAME } from "../../constant.js";
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
appVersion: string;
|
|
8
|
+
binaryVersion: string;
|
|
9
|
+
platform: 'ios' | 'android';
|
|
10
|
+
identifier?: string;
|
|
11
|
+
config: string;
|
|
12
|
+
mandatory?: boolean;
|
|
13
|
+
enable?: boolean;
|
|
14
|
+
rollout?: number;
|
|
15
|
+
}
|
|
5
16
|
|
|
6
17
|
program.command('update-history')
|
|
7
18
|
.description('Updates the release history for a specific binary version.\n`getReleaseHistory`, `setReleaseHistory` functions should be implemented in the config file.')
|
|
@@ -13,19 +24,7 @@ program.command('update-history')
|
|
|
13
24
|
.option('-m, --mandatory <bool>', 'make the release to be mandatory', parseBoolean, undefined)
|
|
14
25
|
.option('-e, --enable <bool>', 'make the release to be enabled', parseBoolean, undefined)
|
|
15
26
|
.option('--rollout <number>', 'rollout percentage (0-100)', parseFloat, undefined)
|
|
16
|
-
|
|
17
|
-
* @param {Object} options
|
|
18
|
-
* @param {string} options.appVersion
|
|
19
|
-
* @param {string} options.binaryVersion
|
|
20
|
-
* @param {string} options.platform
|
|
21
|
-
* @param {string} options.identifier
|
|
22
|
-
* @param {string} options.config
|
|
23
|
-
* @param {string} options.mandatory
|
|
24
|
-
* @param {string} options.enable
|
|
25
|
-
* @param {number} options.rollout
|
|
26
|
-
* @return {void}
|
|
27
|
-
*/
|
|
28
|
-
.action(async (options) => {
|
|
27
|
+
.action(async (options: Options) => {
|
|
29
28
|
const config = findAndReadConfigFile(process.cwd(), options.config);
|
|
30
29
|
|
|
31
30
|
if (typeof options.mandatory !== "boolean" && typeof options.enable !== "boolean") {
|
|
@@ -46,7 +45,7 @@ program.command('update-history')
|
|
|
46
45
|
)
|
|
47
46
|
});
|
|
48
47
|
|
|
49
|
-
function parseBoolean(value) {
|
|
48
|
+
function parseBoolean(value: string) {
|
|
50
49
|
if (value === 'true') return true;
|
|
51
50
|
if (value === 'false') return false;
|
|
52
51
|
else return undefined;
|
package/cli/commands/updateHistoryCommand/{updateReleaseHistory.js → updateReleaseHistory.ts}
RENAMED
|
@@ -1,42 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* targetBinaryVersion: string,
|
|
17
|
-
* jsonFilePath: string,
|
|
18
|
-
* releaseInfo: ReleaseHistoryInterface,
|
|
19
|
-
* platform: string,
|
|
20
|
-
* identifier?: string
|
|
21
|
-
* ): Promise<void>}
|
|
22
|
-
* @param platform {"ios" | "android"}
|
|
23
|
-
* @param identifier {string?}
|
|
24
|
-
* @param mandatory {boolean?}
|
|
25
|
-
* @param enable {boolean?}
|
|
26
|
-
* @param rollout {number?}
|
|
27
|
-
* @returns {Promise<void>}
|
|
28
|
-
*/
|
|
29
|
-
async function updateReleaseHistory(
|
|
30
|
-
appVersion,
|
|
31
|
-
binaryVersion,
|
|
32
|
-
getReleaseHistory,
|
|
33
|
-
setReleaseHistory,
|
|
34
|
-
platform,
|
|
35
|
-
identifier,
|
|
36
|
-
mandatory,
|
|
37
|
-
enable,
|
|
38
|
-
rollout
|
|
39
|
-
) {
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import type { CliConfigInterface } from "../../../typings/react-native-code-push.d.ts";
|
|
4
|
+
|
|
5
|
+
export async function updateReleaseHistory(
|
|
6
|
+
appVersion: string,
|
|
7
|
+
binaryVersion: string,
|
|
8
|
+
getReleaseHistory: CliConfigInterface['getReleaseHistory'],
|
|
9
|
+
setReleaseHistory: CliConfigInterface['setReleaseHistory'],
|
|
10
|
+
platform: 'ios' | 'android',
|
|
11
|
+
identifier: string | undefined,
|
|
12
|
+
mandatory: boolean | undefined,
|
|
13
|
+
enable: boolean | undefined,
|
|
14
|
+
rollout: number | undefined,
|
|
15
|
+
): Promise<void> {
|
|
40
16
|
const releaseHistory = await getReleaseHistory(binaryVersion, platform, identifier);
|
|
41
17
|
|
|
42
18
|
const updateInfo = releaseHistory[appVersion]
|
|
@@ -61,5 +37,3 @@ async function updateReleaseHistory(
|
|
|
61
37
|
process.exit(1)
|
|
62
38
|
}
|
|
63
39
|
}
|
|
64
|
-
|
|
65
|
-
module.exports = { updateReleaseHistory: updateReleaseHistory }
|
package/cli/constant.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { prepareToBundleJS } from "../../functions/prepareToBundleJS.js";
|
|
3
|
+
import { runReactNativeBundleCommand } from "../../functions/runReactNativeBundleCommand.js";
|
|
4
|
+
import { runExpoBundleCommand } from "../../functions/runExpoBundleCommand.js";
|
|
5
|
+
import { getReactTempDir } from "../../functions/getReactTempDir.js";
|
|
6
|
+
import { runHermesEmitBinaryCommand } from "../../functions/runHermesEmitBinaryCommand.js";
|
|
7
|
+
import { makeCodePushBundle } from "../../functions/makeCodePushBundle.js";
|
|
8
|
+
import { ROOT_OUTPUT_DIR, ENTRY_FILE } from "../../constant.js";
|
|
9
|
+
/**
|
|
10
|
+
* @return {Promise<string>} CodePush bundle file name (equals to packageHash)
|
|
11
|
+
*/
|
|
12
|
+
export async function bundleCodePush(framework, platform = 'ios', outputRootPath = ROOT_OUTPUT_DIR, entryFile = ENTRY_FILE, jsBundleName, // JS bundle file name (not CodePush bundle file)
|
|
13
|
+
bundleDirectory) {
|
|
14
|
+
if (fs.existsSync(outputRootPath)) {
|
|
15
|
+
fs.rmSync(outputRootPath, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
const OUTPUT_CONTENT_PATH = `${outputRootPath}/CodePush`;
|
|
18
|
+
const DEFAULT_JS_BUNDLE_NAME = platform === 'ios' ? 'main.jsbundle' : 'index.android.bundle';
|
|
19
|
+
const _jsBundleName = jsBundleName || DEFAULT_JS_BUNDLE_NAME; // react-native JS bundle output name
|
|
20
|
+
const SOURCEMAP_OUTPUT = `${outputRootPath}/${_jsBundleName}.map`;
|
|
21
|
+
prepareToBundleJS({ deleteDirs: [outputRootPath, getReactTempDir()], makeDir: OUTPUT_CONTENT_PATH });
|
|
22
|
+
if (framework === 'expo') {
|
|
23
|
+
runExpoBundleCommand(_jsBundleName, OUTPUT_CONTENT_PATH, platform, SOURCEMAP_OUTPUT, entryFile);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
runReactNativeBundleCommand(_jsBundleName, OUTPUT_CONTENT_PATH, platform, SOURCEMAP_OUTPUT, entryFile);
|
|
27
|
+
}
|
|
28
|
+
console.log('log: JS bundling complete');
|
|
29
|
+
await runHermesEmitBinaryCommand(_jsBundleName, OUTPUT_CONTENT_PATH, SOURCEMAP_OUTPUT);
|
|
30
|
+
console.log('log: Hermes compilation complete');
|
|
31
|
+
const { bundleFileName: codePushBundleFileName } = await makeCodePushBundle(OUTPUT_CONTENT_PATH, bundleDirectory);
|
|
32
|
+
console.log(`log: CodePush bundle created (file path: ./${bundleDirectory}/${codePushBundleFileName})`);
|
|
33
|
+
return codePushBundleFileName;
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { program, Option } from "commander";
|
|
2
|
+
import { bundleCodePush } from "./bundleCodePush.js";
|
|
3
|
+
import { OUTPUT_BUNDLE_DIR, ROOT_OUTPUT_DIR, ENTRY_FILE } from "../../constant.js";
|
|
4
|
+
program.command('bundle')
|
|
5
|
+
.description('Creates a CodePush bundle file (assumes Hermes is enabled).')
|
|
6
|
+
.addOption(new Option('-f, --framework <type>', 'framework type (expo)').choices(['expo']))
|
|
7
|
+
.addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
|
|
8
|
+
.option('-o, --output-path <string>', 'path to output root directory', ROOT_OUTPUT_DIR)
|
|
9
|
+
.option('-e, --entry-file <string>', 'path to JS/TS entry file', ENTRY_FILE)
|
|
10
|
+
.option('-b, --bundle-name <string>', 'bundle file name (default-ios: "main.jsbundle" / default-android: "index.android.bundle")')
|
|
11
|
+
.option('--output-bundle-dir <string>', 'name of directory containing the bundle file created by the "bundle" command', OUTPUT_BUNDLE_DIR)
|
|
12
|
+
.action((options) => {
|
|
13
|
+
bundleCodePush(options.framework, options.platform, options.outputPath, options.entryFile, options.bundleName, `${options.outputPath}/${options.outputBundleDir}`);
|
|
14
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
export async function createReleaseHistory(targetVersion, setReleaseHistory, platform, identifier) {
|
|
4
|
+
const BINARY_RELEASE = {
|
|
5
|
+
enabled: true,
|
|
6
|
+
mandatory: false,
|
|
7
|
+
downloadUrl: "",
|
|
8
|
+
packageHash: "",
|
|
9
|
+
};
|
|
10
|
+
const INITIAL_HISTORY = {
|
|
11
|
+
[targetVersion]: BINARY_RELEASE
|
|
12
|
+
};
|
|
13
|
+
try {
|
|
14
|
+
const JSON_FILE_NAME = `${targetVersion}.json`;
|
|
15
|
+
const JSON_FILE_PATH = path.resolve(process.cwd(), JSON_FILE_NAME);
|
|
16
|
+
console.log(`log: creating JSON file... ("${JSON_FILE_NAME}")\n`, JSON.stringify(INITIAL_HISTORY, null, 2));
|
|
17
|
+
fs.writeFileSync(JSON_FILE_PATH, JSON.stringify(INITIAL_HISTORY));
|
|
18
|
+
await setReleaseHistory(targetVersion, JSON_FILE_PATH, INITIAL_HISTORY, platform, identifier);
|
|
19
|
+
fs.unlinkSync(JSON_FILE_PATH);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error('Error occurred while creating new history:', error);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { program, Option } from "commander";
|
|
2
|
+
import { findAndReadConfigFile } from "../../utils/fsUtils.js";
|
|
3
|
+
import { createReleaseHistory } from "./createReleaseHistory.js";
|
|
4
|
+
import { CONFIG_FILE_NAME } from "../../constant.js";
|
|
5
|
+
program.command('create-history')
|
|
6
|
+
.description('Creates a new release history for the binary app.')
|
|
7
|
+
.requiredOption('-b, --binary-version <string>', '(Required) The target binary version')
|
|
8
|
+
.addOption(new Option('-p, --platform <type>', 'platform').choices(['ios', 'android']).default('ios'))
|
|
9
|
+
.option('-i, --identifier <string>', 'reserved characters to distinguish the release.')
|
|
10
|
+
.option('-c, --config <path>', 'set config file name (JS/TS)', CONFIG_FILE_NAME)
|
|
11
|
+
.action(async (options) => {
|
|
12
|
+
const config = findAndReadConfigFile(process.cwd(), options.config);
|
|
13
|
+
await createReleaseHistory(options.binaryVersion, config.setReleaseHistory, options.platform, options.identifier);
|
|
14
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { initAndroid } from "./initAndroid.js";
|
|
2
|
+
import { initIos } from "./initIos.js";
|
|
3
|
+
import { program } from "commander";
|
|
4
|
+
program
|
|
5
|
+
.command('init')
|
|
6
|
+
.description('Automatically performs iOS/Android native configurations to initialize the CodePush project.')
|
|
7
|
+
.action(async () => {
|
|
8
|
+
console.log('log: Start initializing CodePush...');
|
|
9
|
+
await initAndroid();
|
|
10
|
+
await initIos();
|
|
11
|
+
console.log('log: CodePush has been successfully initialized.');
|
|
12
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { EOL } from "os";
|
|
4
|
+
export function modifyMainApplicationKt(mainApplicationContent) {
|
|
5
|
+
if (mainApplicationContent.includes('CodePush.getJSBundleFile()')) {
|
|
6
|
+
console.log('log: MainApplication.kt already has CodePush initialized.');
|
|
7
|
+
return mainApplicationContent;
|
|
8
|
+
}
|
|
9
|
+
return mainApplicationContent
|
|
10
|
+
.replace('import com.facebook.react.ReactApplication', `import com.facebook.react.ReactApplication${EOL}import com.microsoft.codepush.react.CodePush`)
|
|
11
|
+
.replace('override fun getJSMainModuleName(): String = "index"', `override fun getJSMainModuleName(): String = "index"${EOL} override fun getJSBundleFile(): String = CodePush.getJSBundleFile()`);
|
|
12
|
+
}
|
|
13
|
+
export async function initAndroid() {
|
|
14
|
+
console.log('log: Running Android setup...');
|
|
15
|
+
await applyMainApplication();
|
|
16
|
+
}
|
|
17
|
+
async function applyMainApplication() {
|
|
18
|
+
const mainApplicationPath = await findMainApplication();
|
|
19
|
+
if (!mainApplicationPath) {
|
|
20
|
+
console.log('log: Could not find MainApplication.kt');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (mainApplicationPath.endsWith('.java')) {
|
|
24
|
+
console.log('log: MainApplication.java is not supported. Please migrate to MainApplication.kt.');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const mainApplicationContent = fs.readFileSync(mainApplicationPath, 'utf-8');
|
|
28
|
+
const newContent = modifyMainApplicationKt(mainApplicationContent);
|
|
29
|
+
fs.writeFileSync(mainApplicationPath, newContent);
|
|
30
|
+
console.log('log: Successfully updated MainApplication.kt.');
|
|
31
|
+
}
|
|
32
|
+
async function findMainApplication() {
|
|
33
|
+
const searchPath = path.join(process.cwd(), 'android', 'app', 'src', 'main', 'java');
|
|
34
|
+
const files = fs.readdirSync(searchPath, { encoding: 'utf-8', recursive: true });
|
|
35
|
+
const mainApplicationFile = files.find(file => file.endsWith('MainApplication.java') || file.endsWith('MainApplication.kt'));
|
|
36
|
+
return mainApplicationFile ? path.join(searchPath, mainApplicationFile) : null;
|
|
37
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
async function initIos() {
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
// @ts-expect-error -- types for "xcode" are not available
|
|
4
|
+
import xcode from "xcode";
|
|
5
|
+
export async function initIos() {
|
|
6
6
|
console.log('log: Running iOS setup...');
|
|
7
7
|
const projectDir = path.join(process.cwd(), 'ios');
|
|
8
8
|
const files = fs.readdirSync(projectDir);
|
|
@@ -13,85 +13,72 @@ async function initIos() {
|
|
|
13
13
|
}
|
|
14
14
|
const projectName = xcodeprojFile.replace('.xcodeproj', '');
|
|
15
15
|
const appDelegatePath = findAppDelegate(path.join(projectDir, projectName));
|
|
16
|
-
|
|
17
16
|
if (!appDelegatePath) {
|
|
18
17
|
console.log('log: Could not find AppDelegate file');
|
|
19
18
|
return;
|
|
20
19
|
}
|
|
21
|
-
|
|
22
20
|
if (appDelegatePath.endsWith('.swift')) {
|
|
23
21
|
await setupSwift(appDelegatePath, projectDir, projectName);
|
|
24
|
-
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
25
24
|
await setupObjectiveC(appDelegatePath);
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
console.log('log: Please run `cd ios && pod install` to complete the setup.');
|
|
29
27
|
}
|
|
30
|
-
|
|
31
28
|
function findAppDelegate(searchPath) {
|
|
32
|
-
if (!fs.existsSync(searchPath))
|
|
29
|
+
if (!fs.existsSync(searchPath))
|
|
30
|
+
return null;
|
|
33
31
|
const files = fs.readdirSync(searchPath);
|
|
34
32
|
const appDelegateFile = files.find(file => file.startsWith('AppDelegate') && (file.endsWith('.m') || file.endsWith('.mm') || file.endsWith('.swift')));
|
|
35
33
|
return appDelegateFile ? path.join(searchPath, appDelegateFile) : null;
|
|
36
34
|
}
|
|
37
|
-
|
|
38
|
-
function modifyObjectiveCAppDelegate(appDelegateContent) {
|
|
35
|
+
export function modifyObjectiveCAppDelegate(appDelegateContent) {
|
|
39
36
|
const IMPORT_STATEMENT = '#import <CodePush/CodePush.h>';
|
|
40
37
|
if (appDelegateContent.includes(IMPORT_STATEMENT)) {
|
|
41
38
|
console.log('log: AppDelegate already has CodePush imported.');
|
|
42
39
|
return appDelegateContent;
|
|
43
40
|
}
|
|
44
|
-
|
|
45
41
|
return appDelegateContent
|
|
46
42
|
.replace('#import "AppDelegate.h"\n', `#import "AppDelegate.h"\n${IMPORT_STATEMENT}\n`)
|
|
47
43
|
.replace('[[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];', '[CodePush bundleURL];');
|
|
48
44
|
}
|
|
49
|
-
|
|
50
|
-
function modifySwiftAppDelegate(appDelegateContent) {
|
|
45
|
+
export function modifySwiftAppDelegate(appDelegateContent) {
|
|
51
46
|
const CODEPUSH_CALL_STATEMENT = 'CodePush.bundleURL()';
|
|
52
47
|
if (appDelegateContent.includes(CODEPUSH_CALL_STATEMENT)) {
|
|
53
48
|
console.log('log: AppDelegate.swift already configured for CodePush.');
|
|
54
49
|
return appDelegateContent;
|
|
55
50
|
}
|
|
56
|
-
|
|
57
51
|
return appDelegateContent
|
|
58
52
|
.replace('Bundle.main.url(forResource: "main", withExtension: "jsbundle")', CODEPUSH_CALL_STATEMENT);
|
|
59
53
|
}
|
|
60
|
-
|
|
61
54
|
async function setupObjectiveC(appDelegatePath) {
|
|
62
55
|
const appDelegateContent = fs.readFileSync(appDelegatePath, 'utf-8');
|
|
63
56
|
const newContent = modifyObjectiveCAppDelegate(appDelegateContent);
|
|
64
57
|
fs.writeFileSync(appDelegatePath, newContent);
|
|
65
58
|
console.log('log: Successfully updated AppDelegate.m/mm.');
|
|
66
59
|
}
|
|
67
|
-
|
|
68
60
|
async function setupSwift(appDelegatePath, projectDir, projectName) {
|
|
69
61
|
const bridgingHeaderPath = await ensureBridgingHeader(projectDir, projectName);
|
|
70
62
|
if (!bridgingHeaderPath) {
|
|
71
63
|
console.log('log: Failed to create or find bridging header.');
|
|
72
64
|
return;
|
|
73
65
|
}
|
|
74
|
-
|
|
75
66
|
const appDelegateContent = fs.readFileSync(appDelegatePath, 'utf-8');
|
|
76
67
|
const newContent = modifySwiftAppDelegate(appDelegateContent);
|
|
77
68
|
fs.writeFileSync(appDelegatePath, newContent);
|
|
78
69
|
console.log('log: Successfully updated AppDelegate.swift.');
|
|
79
70
|
}
|
|
80
|
-
|
|
81
71
|
async function ensureBridgingHeader(projectDir, projectName) {
|
|
82
72
|
const projectPath = path.join(projectDir, `${projectName}.xcodeproj`, 'project.pbxproj');
|
|
83
73
|
const myProj = xcode.project(projectPath);
|
|
84
|
-
|
|
85
74
|
return new Promise((resolve, reject) => {
|
|
86
75
|
myProj.parse(function (err) {
|
|
87
76
|
if (err) {
|
|
88
77
|
console.error(`Error parsing Xcode project: ${err}`);
|
|
89
78
|
return reject(err);
|
|
90
79
|
}
|
|
91
|
-
|
|
92
80
|
const bridgingHeaderRelativePath = `${projectName}/${projectName}-Bridging-Header.h`;
|
|
93
81
|
const bridgingHeaderAbsolutePath = path.join(projectDir, bridgingHeaderRelativePath);
|
|
94
|
-
|
|
95
82
|
const configurations = myProj.pbxXCBuildConfigurationSection();
|
|
96
83
|
for (const name in configurations) {
|
|
97
84
|
const config = configurations[name];
|
|
@@ -99,30 +86,23 @@ async function ensureBridgingHeader(projectDir, projectName) {
|
|
|
99
86
|
config.buildSettings.SWIFT_OBJC_BRIDGING_HEADER = `"${bridgingHeaderRelativePath}"`;
|
|
100
87
|
}
|
|
101
88
|
}
|
|
102
|
-
|
|
103
89
|
if (!fs.existsSync(bridgingHeaderAbsolutePath)) {
|
|
104
90
|
fs.mkdirSync(path.dirname(bridgingHeaderAbsolutePath), { recursive: true });
|
|
105
91
|
fs.writeFileSync(bridgingHeaderAbsolutePath, '#import <CodePush/CodePush.h>\n');
|
|
106
92
|
console.log(`log: Created bridging header at ${bridgingHeaderAbsolutePath}`);
|
|
107
93
|
const groupKey = myProj.findPBXGroupKey({ name: projectName });
|
|
108
94
|
myProj.addHeaderFile(bridgingHeaderRelativePath, { public: true }, groupKey);
|
|
109
|
-
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
110
97
|
const headerContent = fs.readFileSync(bridgingHeaderAbsolutePath, 'utf-8');
|
|
111
98
|
if (!headerContent.includes('#import <CodePush/CodePush.h>')) {
|
|
112
99
|
fs.appendFileSync(bridgingHeaderAbsolutePath, '\n#import <CodePush/CodePush.h>\n');
|
|
113
100
|
console.log(`log: Updated bridging header at ${bridgingHeaderAbsolutePath}`);
|
|
114
101
|
}
|
|
115
102
|
}
|
|
116
|
-
|
|
117
103
|
fs.writeFileSync(projectPath, myProj.writeSync());
|
|
118
104
|
console.log('log: Updated Xcode project with bridging header path.');
|
|
119
105
|
resolve(bridgingHeaderAbsolutePath);
|
|
120
106
|
});
|
|
121
107
|
});
|
|
122
108
|
}
|
|
123
|
-
|
|
124
|
-
module.exports = {
|
|
125
|
-
initIos: initIos,
|
|
126
|
-
modifyObjectiveCAppDelegate: modifyObjectiveCAppDelegate,
|
|
127
|
-
modifySwiftAppDelegate: modifySwiftAppDelegate,
|
|
128
|
-
}
|