@revopush/code-push-cli 0.0.7 → 0.0.8-rc.1
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/bin/script/binary-utils.js +176 -0
- package/bin/script/command-executor.js +377 -44
- package/bin/script/command-parser.js +265 -1
- package/bin/script/expo-utils.js +13 -0
- package/bin/script/management-sdk.js +50 -3
- package/bin/script/react-native-utils.js +23 -2
- package/bin/script/types/cli.js +2 -0
- package/bin/script/utils/file-utils.js +33 -2
- package/bin/test/management-sdk.js +7 -0
- package/package.json +8 -3
- package/script/binary-utils.ts +209 -0
- package/script/command-executor.ts +458 -51
- package/script/command-parser.ts +295 -2
- package/script/expo-utils.ts +14 -0
- package/script/management-sdk.ts +65 -3
- package/script/react-native-utils.ts +34 -3
- package/script/types/cli.ts +13 -0
- package/script/types/rest-definitions.ts +12 -0
- package/script/types.ts +1 -0
- package/script/utils/file-utils.ts +36 -1
- package/test/management-sdk.ts +9 -0
|
@@ -203,7 +203,13 @@ function deploymentRemove(commandName, yargs) {
|
|
|
203
203
|
yargs
|
|
204
204
|
.usage(USAGE_PREFIX + " deployment " + commandName + " <appName> <deploymentName>")
|
|
205
205
|
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
|
|
206
|
-
.example("deployment " + commandName + " MyApp MyDeployment", 'Removes deployment "MyDeployment" from app "MyApp"')
|
|
206
|
+
.example("deployment " + commandName + " MyApp MyDeployment", 'Removes deployment "MyDeployment" from app "MyApp"')
|
|
207
|
+
.option("force", {
|
|
208
|
+
default: false,
|
|
209
|
+
demand: false,
|
|
210
|
+
description: "Bypass confirmation when removing deployments",
|
|
211
|
+
type: "boolean",
|
|
212
|
+
});
|
|
207
213
|
addCommonConfiguration(yargs);
|
|
208
214
|
}
|
|
209
215
|
function deploymentHistory(commandName, yargs) {
|
|
@@ -616,6 +622,13 @@ yargs
|
|
|
616
622
|
default: null,
|
|
617
623
|
demand: false,
|
|
618
624
|
description: "Path to the gradle file which specifies the binary version you want to target this release at (android only).",
|
|
625
|
+
})
|
|
626
|
+
.option("initial", {
|
|
627
|
+
alias: "i",
|
|
628
|
+
default: false,
|
|
629
|
+
demand: false,
|
|
630
|
+
description: "Specifies whether release is initial (base) for given targetBinaryVersion.",
|
|
631
|
+
type: "boolean",
|
|
619
632
|
})
|
|
620
633
|
.option("mandatory", {
|
|
621
634
|
alias: "m",
|
|
@@ -730,6 +743,207 @@ yargs
|
|
|
730
743
|
return checkValidReleaseOptions(argv);
|
|
731
744
|
});
|
|
732
745
|
addCommonConfiguration(yargs);
|
|
746
|
+
})
|
|
747
|
+
.command("release-expo", "Release an Expo / React Native update to an app deployment", (yargs) => {
|
|
748
|
+
isValidCommand = true;
|
|
749
|
+
yargs
|
|
750
|
+
.usage(USAGE_PREFIX + " release-expo <appName> <platform> [options]")
|
|
751
|
+
.demand(/*count*/ 2, /*max*/ 2) // Require exactly two non-option arguments
|
|
752
|
+
.example("release-expo MyApp ios", 'Releases the Expo-managed iOS project in the current working directory to the "MyApp" app\'s "Staging" deployment')
|
|
753
|
+
.example("release-expo MyApp android -d Production", 'Releases the Expo-managed Android project in the current working directory to the "MyApp" app\'s "Production" deployment')
|
|
754
|
+
.option("bundleName", {
|
|
755
|
+
alias: "b",
|
|
756
|
+
default: null,
|
|
757
|
+
demand: false,
|
|
758
|
+
description: 'Name of the generated JS bundle file. If unspecified, the standard bundle name will be used, depending on the specified platform: "main.jsbundle" (iOS), "index.android.bundle" (Android) or "index.windows.bundle" (Windows)',
|
|
759
|
+
type: "string",
|
|
760
|
+
})
|
|
761
|
+
.option("deploymentName", {
|
|
762
|
+
alias: "d",
|
|
763
|
+
default: "Staging",
|
|
764
|
+
demand: false,
|
|
765
|
+
description: "Deployment to release the update to",
|
|
766
|
+
type: "string",
|
|
767
|
+
})
|
|
768
|
+
.option("description", {
|
|
769
|
+
alias: "des",
|
|
770
|
+
default: null,
|
|
771
|
+
demand: false,
|
|
772
|
+
description: "Description of the changes made to the app with this release",
|
|
773
|
+
type: "string",
|
|
774
|
+
})
|
|
775
|
+
.option("development", {
|
|
776
|
+
alias: "dev",
|
|
777
|
+
default: false,
|
|
778
|
+
demand: false,
|
|
779
|
+
description: "Specifies whether to generate a dev or release build",
|
|
780
|
+
type: "boolean",
|
|
781
|
+
})
|
|
782
|
+
.option("disabled", {
|
|
783
|
+
alias: "x",
|
|
784
|
+
default: false,
|
|
785
|
+
demand: false,
|
|
786
|
+
description: "Specifies whether this release should be immediately downloadable",
|
|
787
|
+
type: "boolean",
|
|
788
|
+
})
|
|
789
|
+
.option("entryFile", {
|
|
790
|
+
alias: "e",
|
|
791
|
+
default: null,
|
|
792
|
+
demand: false,
|
|
793
|
+
description: 'Path to the app\'s entry Javascript file. If omitted, "index.<platform>.js" and then "index.js" will be used (if they exist)',
|
|
794
|
+
type: "string",
|
|
795
|
+
})
|
|
796
|
+
.option("gradleFile", {
|
|
797
|
+
alias: "g",
|
|
798
|
+
default: null,
|
|
799
|
+
demand: false,
|
|
800
|
+
description: "Path to the gradle file which specifies the binary version you want to target this release at (android only).",
|
|
801
|
+
})
|
|
802
|
+
.option("initial", {
|
|
803
|
+
alias: "i",
|
|
804
|
+
default: false,
|
|
805
|
+
demand: false,
|
|
806
|
+
description: "Specifies whether release is initial (base) for given targetBinaryVersion.",
|
|
807
|
+
type: "boolean",
|
|
808
|
+
})
|
|
809
|
+
.option("mandatory", {
|
|
810
|
+
alias: "m",
|
|
811
|
+
default: false,
|
|
812
|
+
demand: false,
|
|
813
|
+
description: "Specifies whether this release should be considered mandatory",
|
|
814
|
+
type: "boolean",
|
|
815
|
+
})
|
|
816
|
+
.option("noDuplicateReleaseError", {
|
|
817
|
+
default: false,
|
|
818
|
+
demand: false,
|
|
819
|
+
description: "When this flag is set, releasing a package that is identical to the latest release will produce a warning instead of an error",
|
|
820
|
+
type: "boolean",
|
|
821
|
+
})
|
|
822
|
+
.option("plistFile", {
|
|
823
|
+
alias: "p",
|
|
824
|
+
default: null,
|
|
825
|
+
demand: false,
|
|
826
|
+
description: "Path to the plist file which specifies the binary version you want to target this release at (iOS only).",
|
|
827
|
+
})
|
|
828
|
+
.option("plistFilePrefix", {
|
|
829
|
+
alias: "pre",
|
|
830
|
+
default: null,
|
|
831
|
+
demand: false,
|
|
832
|
+
description: "Prefix to append to the file name when attempting to find your app's Info.plist file (iOS only).",
|
|
833
|
+
})
|
|
834
|
+
.option("rollout", {
|
|
835
|
+
alias: "r",
|
|
836
|
+
default: "100%",
|
|
837
|
+
demand: false,
|
|
838
|
+
description: "Percentage of users this release should be immediately available to",
|
|
839
|
+
type: "string",
|
|
840
|
+
})
|
|
841
|
+
.option("sourcemapOutput", {
|
|
842
|
+
alias: "s",
|
|
843
|
+
default: null,
|
|
844
|
+
demand: false,
|
|
845
|
+
description: "Path to where the sourcemap for the resulting bundle should be written. If omitted, a sourcemap will not be generated.",
|
|
846
|
+
type: "string",
|
|
847
|
+
})
|
|
848
|
+
.option("targetBinaryVersion", {
|
|
849
|
+
alias: "t",
|
|
850
|
+
default: null,
|
|
851
|
+
demand: false,
|
|
852
|
+
description: 'Semver expression that specifies the binary app version(s) this release is targeting (e.g. 1.1.0, ~1.2.3). If omitted, the release will target the exact version specified in the "Info.plist" (iOS), "build.gradle" (Android) or "Package.appxmanifest" (Windows) files.',
|
|
853
|
+
type: "string",
|
|
854
|
+
})
|
|
855
|
+
.option("outputDir", {
|
|
856
|
+
alias: "o",
|
|
857
|
+
default: null,
|
|
858
|
+
demand: false,
|
|
859
|
+
description: "Path to where the bundle and sourcemap should be written. If omitted, a bundle and sourcemap will not be written.",
|
|
860
|
+
type: "string",
|
|
861
|
+
})
|
|
862
|
+
.option("useHermes", {
|
|
863
|
+
alias: "h",
|
|
864
|
+
default: false,
|
|
865
|
+
demand: false,
|
|
866
|
+
description: "Enable hermes and bypass automatic checks",
|
|
867
|
+
type: "boolean",
|
|
868
|
+
})
|
|
869
|
+
.option("podFile", {
|
|
870
|
+
alias: "pod",
|
|
871
|
+
default: null,
|
|
872
|
+
demand: false,
|
|
873
|
+
description: "Path to the cocopods config file (iOS only).",
|
|
874
|
+
type: "string",
|
|
875
|
+
})
|
|
876
|
+
.option("extraHermesFlags", {
|
|
877
|
+
alias: "hf",
|
|
878
|
+
default: [],
|
|
879
|
+
demand: false,
|
|
880
|
+
description: "Flags that get passed to Hermes, JavaScript to bytecode compiler. Can be specified multiple times.",
|
|
881
|
+
type: "array",
|
|
882
|
+
})
|
|
883
|
+
.option("privateKeyPath", {
|
|
884
|
+
alias: "k",
|
|
885
|
+
default: null,
|
|
886
|
+
demand: false,
|
|
887
|
+
description: "Path to private key used for code signing.",
|
|
888
|
+
type: "string",
|
|
889
|
+
})
|
|
890
|
+
.option("xcodeProjectFile", {
|
|
891
|
+
alias: "xp",
|
|
892
|
+
default: null,
|
|
893
|
+
demand: false,
|
|
894
|
+
description: "Path to the Xcode project or project.pbxproj file",
|
|
895
|
+
type: "string",
|
|
896
|
+
})
|
|
897
|
+
.option("xcodeTargetName", {
|
|
898
|
+
alias: "xt",
|
|
899
|
+
default: undefined,
|
|
900
|
+
demand: false,
|
|
901
|
+
description: "Name of target (PBXNativeTarget) which specifies the binary version you want to target this release at (iOS only)",
|
|
902
|
+
type: "string",
|
|
903
|
+
})
|
|
904
|
+
.option("buildConfigurationName", {
|
|
905
|
+
alias: "c",
|
|
906
|
+
default: undefined,
|
|
907
|
+
demand: false,
|
|
908
|
+
description: "Name of build configuration which specifies the binary version you want to target this release at. For example, 'Debug' or 'Release' (iOS only)",
|
|
909
|
+
type: "string",
|
|
910
|
+
})
|
|
911
|
+
.option("extraBundlerOption", {
|
|
912
|
+
alias: "eo",
|
|
913
|
+
default: [],
|
|
914
|
+
demand: false,
|
|
915
|
+
description: "Option that gets passed to react-native bundler. Can be specified multiple times.",
|
|
916
|
+
type: "array",
|
|
917
|
+
})
|
|
918
|
+
.check((argv) => {
|
|
919
|
+
return checkValidReleaseOptions(argv);
|
|
920
|
+
});
|
|
921
|
+
addCommonConfiguration(yargs);
|
|
922
|
+
})
|
|
923
|
+
.command("release-native", "Release a binary update to an app deployment", (yargs) => {
|
|
924
|
+
yargs
|
|
925
|
+
.usage(USAGE_PREFIX + " release-native <appName> <platform> <targetBinary> [options]")
|
|
926
|
+
.demand(/*count*/ 3, /*max*/ 3) // Require exactly three non-option arguments
|
|
927
|
+
.example("release-native MyApp ios ./app.ipa", 'Releases the React Native iOS project from "./app.ipa" to the "MyApp" app\'s "Staging" deployment')
|
|
928
|
+
.example("release-native MyApp android ./app.apk -d Production", 'Releases the React Native Android project from "./app.apk" to the "MyApp" app\'s "Production" deployment')
|
|
929
|
+
.option("deploymentName", {
|
|
930
|
+
alias: "d",
|
|
931
|
+
default: "Staging",
|
|
932
|
+
demand: false,
|
|
933
|
+
description: "Deployment to release the update to",
|
|
934
|
+
type: "string",
|
|
935
|
+
})
|
|
936
|
+
.option("targetBinaryVersion", {
|
|
937
|
+
alias: "t",
|
|
938
|
+
default: null,
|
|
939
|
+
demand: false,
|
|
940
|
+
description: "Semver expression that specifies the binary app version(s) this release is targeting (e.g. 1.1.0, ~1.2.3).",
|
|
941
|
+
type: "string",
|
|
942
|
+
})
|
|
943
|
+
.check((argv, aliases) => {
|
|
944
|
+
return checkValidReleaseOptions(argv);
|
|
945
|
+
});
|
|
946
|
+
addCommonConfiguration(yargs);
|
|
733
947
|
})
|
|
734
948
|
.command("rollback", "Rollback the latest release for an app deployment", (yargs) => {
|
|
735
949
|
yargs
|
|
@@ -933,6 +1147,7 @@ function createCommand() {
|
|
|
933
1147
|
const deploymentRemoveCommand = cmd;
|
|
934
1148
|
deploymentRemoveCommand.appName = arg2;
|
|
935
1149
|
deploymentRemoveCommand.deploymentName = arg3;
|
|
1150
|
+
deploymentRemoveCommand.isForce = argv["force"];
|
|
936
1151
|
}
|
|
937
1152
|
break;
|
|
938
1153
|
case "rename":
|
|
@@ -1039,6 +1254,7 @@ function createCommand() {
|
|
|
1039
1254
|
releaseReactCommand.entryFile = argv["entryFile"];
|
|
1040
1255
|
releaseReactCommand.gradleFile = argv["gradleFile"];
|
|
1041
1256
|
releaseReactCommand.mandatory = argv["mandatory"];
|
|
1257
|
+
releaseReactCommand.initial = argv["initial"];
|
|
1042
1258
|
releaseReactCommand.noDuplicateReleaseError = argv["noDuplicateReleaseError"];
|
|
1043
1259
|
releaseReactCommand.plistFile = argv["plistFile"];
|
|
1044
1260
|
releaseReactCommand.plistFilePrefix = argv["plistFilePrefix"];
|
|
@@ -1055,6 +1271,54 @@ function createCommand() {
|
|
|
1055
1271
|
releaseReactCommand.extraBundlerOptions = argv["extraBundlerOption"];
|
|
1056
1272
|
}
|
|
1057
1273
|
break;
|
|
1274
|
+
case "release-expo":
|
|
1275
|
+
if (arg1 && arg2) {
|
|
1276
|
+
cmd = { type: cli.CommandType.releaseExpo };
|
|
1277
|
+
const releaseExpoCommand = cmd;
|
|
1278
|
+
releaseExpoCommand.appName = arg1;
|
|
1279
|
+
releaseExpoCommand.platform = arg2;
|
|
1280
|
+
releaseExpoCommand.appStoreVersion = argv["targetBinaryVersion"];
|
|
1281
|
+
releaseExpoCommand.bundleName = argv["bundleName"];
|
|
1282
|
+
releaseExpoCommand.deploymentName = argv["deploymentName"];
|
|
1283
|
+
releaseExpoCommand.disabled = argv["disabled"];
|
|
1284
|
+
releaseExpoCommand.description = argv["description"] ? backslash(argv["description"]) : "";
|
|
1285
|
+
releaseExpoCommand.development = argv["development"];
|
|
1286
|
+
releaseExpoCommand.entryFile = argv["entryFile"];
|
|
1287
|
+
releaseExpoCommand.gradleFile = argv["gradleFile"];
|
|
1288
|
+
releaseExpoCommand.mandatory = argv["mandatory"];
|
|
1289
|
+
releaseExpoCommand.initial = argv["initial"];
|
|
1290
|
+
releaseExpoCommand.noDuplicateReleaseError = argv["noDuplicateReleaseError"];
|
|
1291
|
+
releaseExpoCommand.plistFile = argv["plistFile"];
|
|
1292
|
+
releaseExpoCommand.plistFilePrefix = argv["plistFilePrefix"];
|
|
1293
|
+
releaseExpoCommand.rollout = getRolloutValue(argv["rollout"]);
|
|
1294
|
+
releaseExpoCommand.sourcemapOutput = argv["sourcemapOutput"];
|
|
1295
|
+
releaseExpoCommand.outputDir = argv["outputDir"];
|
|
1296
|
+
releaseExpoCommand.useHermes = argv["useHermes"];
|
|
1297
|
+
releaseExpoCommand.extraHermesFlags = argv["extraHermesFlags"];
|
|
1298
|
+
releaseExpoCommand.podFile = argv["podFile"];
|
|
1299
|
+
releaseExpoCommand.privateKeyPath = argv["privateKeyPath"];
|
|
1300
|
+
releaseExpoCommand.xcodeProjectFile = argv["xcodeProjectFile"];
|
|
1301
|
+
releaseExpoCommand.xcodeTargetName = argv["xcodeTargetName"];
|
|
1302
|
+
releaseExpoCommand.buildConfigurationName = argv["buildConfigurationName"];
|
|
1303
|
+
releaseExpoCommand.extraBundlerOptions = argv["extraBundlerOption"];
|
|
1304
|
+
}
|
|
1305
|
+
break;
|
|
1306
|
+
case "release-native":
|
|
1307
|
+
if (arg1 && arg2 && arg3) {
|
|
1308
|
+
cmd = { type: cli.CommandType.releaseNative };
|
|
1309
|
+
const releaseBinaryCommand = cmd;
|
|
1310
|
+
releaseBinaryCommand.appName = arg1;
|
|
1311
|
+
releaseBinaryCommand.platform = arg2;
|
|
1312
|
+
releaseBinaryCommand.targetBinary = arg3;
|
|
1313
|
+
releaseBinaryCommand.deploymentName = argv["deploymentName"];
|
|
1314
|
+
releaseBinaryCommand.appStoreVersion = argv["targetBinaryVersion"];
|
|
1315
|
+
releaseBinaryCommand.initial = true;
|
|
1316
|
+
releaseBinaryCommand.disabled = true;
|
|
1317
|
+
releaseBinaryCommand.mandatory = false;
|
|
1318
|
+
// TODO add support for releaseBinaryCommand.bundleName
|
|
1319
|
+
// TODO add support for releaseBinaryCommand.outputDir
|
|
1320
|
+
}
|
|
1321
|
+
break;
|
|
1058
1322
|
case "rollback":
|
|
1059
1323
|
if (arg1 && arg2) {
|
|
1060
1324
|
cmd = { type: cli.CommandType.rollback };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getExpoCliPath = void 0;
|
|
4
|
+
const childProcess = require("child_process");
|
|
5
|
+
function getExpoCliPath() {
|
|
6
|
+
const result = childProcess.spawnSync("node", ["--print", "require.resolve('@expo/cli')"]);
|
|
7
|
+
const cliPath = result.stdout.toString().trim();
|
|
8
|
+
if (result.status === 0 && cliPath) {
|
|
9
|
+
return cliPath;
|
|
10
|
+
}
|
|
11
|
+
throw new Error('Unable to resolve "@expo/cli". Please make sure it is installed in your project (e.g. "npm install --save-dev @expo/cli").');
|
|
12
|
+
}
|
|
13
|
+
exports.getExpoCliPath = getExpoCliPath;
|
|
@@ -195,6 +195,9 @@ class AccountManager {
|
|
|
195
195
|
getDeployment(appName, deploymentName) {
|
|
196
196
|
return this.get(urlEncode([`/apps/${appName}/deployments/${deploymentName}`])).then((res) => res.body.deployment);
|
|
197
197
|
}
|
|
198
|
+
getBaseRelease(appName, deploymentName, appVerison) {
|
|
199
|
+
return this.get(urlEncode([`/apps/${appName}/deployments/${deploymentName}/basebundle?appVersion=${appVerison}`])).then((res) => res.body.basebundle);
|
|
200
|
+
}
|
|
198
201
|
renameDeployment(appName, oldDeploymentName, newDeploymentName) {
|
|
199
202
|
return this.patch(urlEncode([`/apps/${appName}/deployments/${oldDeploymentName}`]), JSON.stringify({ name: newDeploymentName })).then(() => null);
|
|
200
203
|
}
|
|
@@ -207,9 +210,8 @@ class AccountManager {
|
|
|
207
210
|
getDeploymentHistory(appName, deploymentName) {
|
|
208
211
|
return this.get(urlEncode([`/apps/${appName}/deployments/${deploymentName}/history`])).then((res) => res.body.history);
|
|
209
212
|
}
|
|
210
|
-
release(appName, deploymentName, filePath,
|
|
213
|
+
release(appName, deploymentName, filePath, updateMetadata, uploadProgressCallback) {
|
|
211
214
|
return Promise((resolve, reject, notify) => {
|
|
212
|
-
updateMetadata.appVersion = targetBinaryVersion;
|
|
213
215
|
const request = superagent.post(this._serverUrl + urlEncode([`/apps/${appName}/deployments/${deploymentName}/release`]));
|
|
214
216
|
this.attachCredentials(request);
|
|
215
217
|
const getPackageFilePromise = Q.Promise((resolve, reject) => {
|
|
@@ -266,6 +268,51 @@ class AccountManager {
|
|
|
266
268
|
});
|
|
267
269
|
});
|
|
268
270
|
}
|
|
271
|
+
releaseNative(appName, deploymentName, filePath, updateMetadata, uploadProgressCallback) {
|
|
272
|
+
return Promise((resolve, reject, notify) => {
|
|
273
|
+
const request = superagent.post(this._serverUrl + urlEncode([`/apps/${appName}/deployments/${deploymentName}/nativerelease`]));
|
|
274
|
+
this.attachCredentials(request);
|
|
275
|
+
const file = fs.createReadStream(filePath);
|
|
276
|
+
request
|
|
277
|
+
.attach("package", file)
|
|
278
|
+
.field("packageInfo", JSON.stringify(updateMetadata))
|
|
279
|
+
.on("progress", (event) => {
|
|
280
|
+
if (uploadProgressCallback && event && event.total > 0) {
|
|
281
|
+
const currentProgress = (event.loaded / event.total) * 100;
|
|
282
|
+
uploadProgressCallback(currentProgress);
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
.end((err, res) => {
|
|
286
|
+
fs.unlinkSync(filePath);
|
|
287
|
+
if (err) {
|
|
288
|
+
reject(this.getCodePushError(err, res));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
if (res.ok) {
|
|
292
|
+
resolve(null);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
let body;
|
|
296
|
+
try {
|
|
297
|
+
body = JSON.parse(res.text);
|
|
298
|
+
}
|
|
299
|
+
catch (err) { }
|
|
300
|
+
if (body) {
|
|
301
|
+
reject({
|
|
302
|
+
message: body.message,
|
|
303
|
+
statusCode: res && res.status,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
reject({
|
|
308
|
+
message: res.text,
|
|
309
|
+
statusCode: res && res.status,
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
269
316
|
patchRelease(appName, deploymentName, label, updateMetadata) {
|
|
270
317
|
updateMetadata.label = label;
|
|
271
318
|
const requestBody = JSON.stringify({ packageInfo: updateMetadata });
|
|
@@ -414,7 +461,7 @@ class AccountManager {
|
|
|
414
461
|
}
|
|
415
462
|
request.set("Accept", `application/vnd.code-push.v${AccountManager.API_VERSION}+json`);
|
|
416
463
|
request.set("Authorization", `Bearer ${this._accessKey}`);
|
|
417
|
-
request.set("X-CodePush-SDK-Version", packageJson.version);
|
|
464
|
+
request.set("X-CodePush-SDK-Version", packageJson.version); // TODO get version differently without require("../../package.json");
|
|
418
465
|
}
|
|
419
466
|
}
|
|
420
467
|
module.exports = AccountManager;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getReactNativeVersion = exports.directoryExistsSync = exports.getReactNativePackagePath = exports.isHermesEnabled = exports.getMinifyParams = exports.getXcodeDotEnvValue = exports.runHermesEmitBinaryCommand = exports.getBundleSourceMapOutput = exports.isValidVersion = void 0;
|
|
3
|
+
exports.getReactNativeVersion = exports.directoryExistsSync = exports.getReactNativePackagePath = exports.isHermesEnabled = exports.getMinifyParams = exports.getXcodeDotEnvValue = exports.runHermesEmitBinaryCommand = exports.takeHermesBaseBytecode = exports.getBundleSourceMapOutput = exports.isValidVersion = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const chalk = require("chalk");
|
|
6
6
|
const path = require("path");
|
|
@@ -8,6 +8,7 @@ const childProcess = require("child_process");
|
|
|
8
8
|
const semver_1 = require("semver");
|
|
9
9
|
const file_utils_1 = require("./utils/file-utils");
|
|
10
10
|
const dotenv = require("dotenv");
|
|
11
|
+
const command_executor_1 = require("./command-executor");
|
|
11
12
|
const g2js = require("gradle-to-js/lib/parser");
|
|
12
13
|
function isValidVersion(version) {
|
|
13
14
|
return !!(0, semver_1.valid)(version) || /^\d+\.\d+$/.test(version);
|
|
@@ -44,7 +45,22 @@ async function getBundleSourceMapOutput(command, bundleName, sourcemapOutputFold
|
|
|
44
45
|
return bundleSourceMapOutput;
|
|
45
46
|
}
|
|
46
47
|
exports.getBundleSourceMapOutput = getBundleSourceMapOutput;
|
|
47
|
-
async function
|
|
48
|
+
async function takeHermesBaseBytecode(command, baseReleaseTmpFolder, outputFolder, bundleName) {
|
|
49
|
+
const { bundleBlobUrl } = await command_executor_1.sdk.getBaseRelease(command.appName, command.deploymentName, command.appStoreVersion);
|
|
50
|
+
if (!bundleBlobUrl) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const baseReleaseArchive = await (0, file_utils_1.downloadBlob)(bundleBlobUrl, baseReleaseTmpFolder);
|
|
54
|
+
await (0, file_utils_1.extractIPA)(baseReleaseArchive, baseReleaseTmpFolder);
|
|
55
|
+
const baseReleaseBundle = path.join(baseReleaseTmpFolder, path.basename(outputFolder), bundleName);
|
|
56
|
+
if (!fs.existsSync(baseReleaseBundle)) {
|
|
57
|
+
(0, command_executor_1.log)(chalk.cyan("\nNo base release available...\n"));
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return baseReleaseBundle;
|
|
61
|
+
}
|
|
62
|
+
exports.takeHermesBaseBytecode = takeHermesBaseBytecode;
|
|
63
|
+
async function runHermesEmitBinaryCommand(command, bundleName, outputFolder, sourcemapOutputFolder, extraHermesFlags, gradleFile, baseBytecode) {
|
|
48
64
|
const hermesArgs = [];
|
|
49
65
|
const envNodeArgs = process.env.CODE_PUSH_NODE_ARGS;
|
|
50
66
|
if (typeof envNodeArgs !== "undefined") {
|
|
@@ -56,11 +72,16 @@ async function runHermesEmitBinaryCommand(command, bundleName, outputFolder, sou
|
|
|
56
72
|
"-out",
|
|
57
73
|
path.join(outputFolder, bundleName + ".hbc"),
|
|
58
74
|
path.join(outputFolder, bundleName),
|
|
75
|
+
"-w",
|
|
76
|
+
"-max-diagnostic-width=80",
|
|
59
77
|
...extraHermesFlags,
|
|
60
78
|
]);
|
|
61
79
|
if (sourcemapOutputFolder) {
|
|
62
80
|
hermesArgs.push("-output-source-map");
|
|
63
81
|
}
|
|
82
|
+
if (baseBytecode) {
|
|
83
|
+
hermesArgs.push("-base-bytecode", baseBytecode);
|
|
84
|
+
}
|
|
64
85
|
console.log(chalk.cyan("Converting JS bundle to byte code via Hermes, running command:\n"));
|
|
65
86
|
const hermesCommand = await getHermesCommand(gradleFile);
|
|
66
87
|
const hermesProcess = childProcess.spawn(hermesCommand, hermesArgs);
|
package/bin/script/types/cli.js
CHANGED
|
@@ -37,4 +37,6 @@ var CommandType;
|
|
|
37
37
|
CommandType[CommandType["sessionList"] = 29] = "sessionList";
|
|
38
38
|
CommandType[CommandType["sessionRemove"] = 30] = "sessionRemove";
|
|
39
39
|
CommandType[CommandType["whoami"] = 31] = "whoami";
|
|
40
|
+
CommandType[CommandType["releaseExpo"] = 32] = "releaseExpo";
|
|
41
|
+
CommandType[CommandType["releaseNative"] = 33] = "releaseNative";
|
|
40
42
|
})(CommandType || (exports.CommandType = CommandType = {}));
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.normalizePath = exports.fileDoesNotExistOrIsDirectory = exports.copyFileToTmpDir = exports.fileExists = exports.isDirectory = exports.isBinaryOrZip = void 0;
|
|
3
|
+
exports.extractAPK = exports.extractIPA = exports.downloadBlob = exports.normalizePath = exports.fileDoesNotExistOrIsDirectory = exports.copyFileToTmpDir = exports.fileExists = exports.isDirectory = exports.isBinaryOrZip = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const rimraf = require("rimraf");
|
|
7
7
|
const temp = require("temp");
|
|
8
|
+
const unzipper = require("unzipper");
|
|
9
|
+
const AdmZip = require("adm-zip");
|
|
10
|
+
const superagent = require("superagent");
|
|
8
11
|
function isBinaryOrZip(path) {
|
|
9
12
|
return path.search(/\.zip$/i) !== -1 || path.search(/\.apk$/i) !== -1 || path.search(/\.ipa$/i) !== -1;
|
|
10
13
|
}
|
|
@@ -22,7 +25,6 @@ function fileExists(file) {
|
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
exports.fileExists = fileExists;
|
|
25
|
-
;
|
|
26
28
|
function copyFileToTmpDir(filePath) {
|
|
27
29
|
if (!isDirectory(filePath)) {
|
|
28
30
|
const outputFolderPath = temp.mkdirSync("code-push");
|
|
@@ -48,3 +50,32 @@ function normalizePath(filePath) {
|
|
|
48
50
|
return filePath.replace(/\\/g, "/");
|
|
49
51
|
}
|
|
50
52
|
exports.normalizePath = normalizePath;
|
|
53
|
+
async function downloadBlob(url, folder, filename = "blob.zip") {
|
|
54
|
+
const destination = path.join(folder, filename);
|
|
55
|
+
const writeStream = fs.createWriteStream(destination);
|
|
56
|
+
return new Promise((resolve, reject) => {
|
|
57
|
+
writeStream.on("finish", () => resolve(destination));
|
|
58
|
+
writeStream.on("error", reject);
|
|
59
|
+
superagent
|
|
60
|
+
.get(url)
|
|
61
|
+
.ok((res) => res.status < 400)
|
|
62
|
+
.on("error", (err) => {
|
|
63
|
+
writeStream.destroy();
|
|
64
|
+
reject(err);
|
|
65
|
+
})
|
|
66
|
+
.pipe(writeStream);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
exports.downloadBlob = downloadBlob;
|
|
70
|
+
async function extractIPA(zipPath, extractTo) {
|
|
71
|
+
const extractStream = unzipper.Extract({ path: extractTo });
|
|
72
|
+
await new Promise((resolve, reject) => {
|
|
73
|
+
fs.createReadStream(zipPath).pipe(extractStream).on("close", resolve).on("error", reject);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
exports.extractIPA = extractIPA;
|
|
77
|
+
async function extractAPK(zipPath, extractTo) {
|
|
78
|
+
const zip = new AdmZip(zipPath);
|
|
79
|
+
zip.extractAllTo(extractTo, true);
|
|
80
|
+
}
|
|
81
|
+
exports.extractAPK = extractAPK;
|
|
@@ -154,6 +154,13 @@ describe("Management SDK", () => {
|
|
|
154
154
|
done();
|
|
155
155
|
}, rejectHandler);
|
|
156
156
|
});
|
|
157
|
+
it("getBaseBundle handles JSON response", (done) => {
|
|
158
|
+
mockReturn(JSON.stringify({ basebundle: { bundleBlobUrl: "https://test.test/release.zip" } }), 200, {});
|
|
159
|
+
manager.getBaseRelease("appName", "deploymentName", "1.2.3").done((obj) => {
|
|
160
|
+
assert.ok(obj);
|
|
161
|
+
done();
|
|
162
|
+
}, rejectHandler);
|
|
163
|
+
});
|
|
157
164
|
it("getDeployments handles JSON response", (done) => {
|
|
158
165
|
mockReturn(JSON.stringify({ deployments: [] }), 200, {});
|
|
159
166
|
manager.getDeployments("appName").done((obj) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revopush/code-push-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8-rc.1",
|
|
4
4
|
"description": "Management CLI for the CodePush service",
|
|
5
5
|
"main": "./script/cli.js",
|
|
6
6
|
"scripts": {
|
|
@@ -23,7 +23,10 @@
|
|
|
23
23
|
"Revopush"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"@devicefarmer/adbkit-apkreader": "^3.2.4",
|
|
27
|
+
"adm-zip": "^0.5.16",
|
|
26
28
|
"backslash": "^0.2.0",
|
|
29
|
+
"bplist-parser": "^0.3.2",
|
|
27
30
|
"chalk": "^4.1.2",
|
|
28
31
|
"cli-table": "^0.3.11",
|
|
29
32
|
"dotenv": "^17.2.1",
|
|
@@ -33,7 +36,7 @@
|
|
|
33
36
|
"moment": "^2.29.4",
|
|
34
37
|
"opener": "^1.5.2",
|
|
35
38
|
"parse-duration": "1.1.0",
|
|
36
|
-
"plist": "^3.0
|
|
39
|
+
"plist": "^3.1.0",
|
|
37
40
|
"progress": "^2.0.3",
|
|
38
41
|
"prompt": "^1.3.0",
|
|
39
42
|
"properties": "^1.2.1",
|
|
@@ -45,6 +48,7 @@
|
|
|
45
48
|
"slash": "1.0.0",
|
|
46
49
|
"superagent": "^8.0.9",
|
|
47
50
|
"temp": "^0.9.4",
|
|
51
|
+
"unzipper": "^0.12.3",
|
|
48
52
|
"which": "^1.2.7",
|
|
49
53
|
"wordwrap": "1.0.0",
|
|
50
54
|
"xcode": "^3.0.1",
|
|
@@ -59,6 +63,7 @@
|
|
|
59
63
|
"@types/node": "^20.3.1",
|
|
60
64
|
"@types/q": "^1.5.8",
|
|
61
65
|
"@types/sinon": "^10.0.15",
|
|
66
|
+
"@types/unzipper": "^0.10.11",
|
|
62
67
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
63
68
|
"@typescript-eslint/parser": "^6.0.0",
|
|
64
69
|
"eslint": "^8.45.0",
|
|
@@ -68,8 +73,8 @@
|
|
|
68
73
|
"prettier": "^2.8.8",
|
|
69
74
|
"sinon": "15.1.2",
|
|
70
75
|
"superagent-mock": "^4.0.0",
|
|
71
|
-
"typescript": "^5.1.3",
|
|
72
76
|
"ts-node": "^10.9.2",
|
|
77
|
+
"typescript": "^5.1.3",
|
|
73
78
|
"which": "^3.0.1"
|
|
74
79
|
}
|
|
75
80
|
}
|