@revopush/code-push-cli 0.0.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/.eslintrc.json +17 -0
- package/.idea/cli.iml +9 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/misc.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +6 -0
- package/.idea/vcs.xml +6 -0
- package/README.md +774 -0
- package/bin/script/acquisition-sdk.js +178 -0
- package/bin/script/cli.js +23 -0
- package/bin/script/command-executor.js +1290 -0
- package/bin/script/command-parser.js +1097 -0
- package/bin/script/commands/debug.js +125 -0
- package/bin/script/hash-utils.js +203 -0
- package/bin/script/index.js +5 -0
- package/bin/script/management-sdk.js +419 -0
- package/bin/script/react-native-utils.js +249 -0
- package/bin/script/sign.js +69 -0
- package/bin/script/types/cli.js +40 -0
- package/bin/script/types/rest-definitions.js +19 -0
- package/bin/script/types.js +4 -0
- package/bin/script/utils/file-utils.js +50 -0
- package/bin/test/acquisition-rest-mock.js +108 -0
- package/bin/test/acquisition-sdk.js +188 -0
- package/bin/test/cli.js +1342 -0
- package/bin/test/hash-utils.js +149 -0
- package/bin/test/management-sdk.js +338 -0
- package/package.json +68 -0
- package/prettier.config.js +7 -0
- package/script/acquisition-sdk.ts +273 -0
- package/script/cli.ts +27 -0
- package/script/command-executor.ts +1610 -0
- package/script/command-parser.ts +1310 -0
- package/script/commands/debug.ts +148 -0
- package/script/hash-utils.ts +241 -0
- package/script/index.ts +5 -0
- package/script/management-sdk.ts +575 -0
- package/script/react-native-utils.ts +283 -0
- package/script/sign.ts +80 -0
- package/script/types/cli.ts +232 -0
- package/script/types/rest-definitions.ts +152 -0
- package/script/types.ts +35 -0
- package/script/utils/file-utils.ts +46 -0
- package/test/acquisition-rest-mock.ts +125 -0
- package/test/acquisition-sdk.ts +272 -0
- package/test/cli.ts +1692 -0
- package/test/hash-utils.ts +170 -0
- package/test/management-sdk.ts +438 -0
- package/test/resources/TestApp/android/app/build.gradle +56 -0
- package/test/resources/TestApp/iOS/TestApp/Info.plist +49 -0
- package/test/resources/TestApp/index.android.js +2 -0
- package/test/resources/TestApp/index.ios.js +2 -0
- package/test/resources/TestApp/index.windows.js +2 -0
- package/test/resources/TestApp/package.json +6 -0
- package/test/resources/TestApp/windows/TestApp/Package.appxmanifest +46 -0
- package/test/resources/ignoredMetadata.zip +0 -0
- package/test/resources/test.zip +0 -0
- package/test/superagent-mock-config.js +58 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as chalk from "chalk";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as childProcess from "child_process";
|
|
5
|
+
import { coerce, compare, valid } from "semver";
|
|
6
|
+
import { fileDoesNotExistOrIsDirectory } from "./utils/file-utils";
|
|
7
|
+
|
|
8
|
+
const g2js = require("gradle-to-js/lib/parser");
|
|
9
|
+
|
|
10
|
+
export function isValidVersion(version: string): boolean {
|
|
11
|
+
return !!valid(version) || /^\d+\.\d+$/.test(version);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function runHermesEmitBinaryCommand(
|
|
15
|
+
bundleName: string,
|
|
16
|
+
outputFolder: string,
|
|
17
|
+
sourcemapOutput: string,
|
|
18
|
+
extraHermesFlags: string[],
|
|
19
|
+
gradleFile: string
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
const hermesArgs: string[] = [];
|
|
22
|
+
const envNodeArgs: string = process.env.CODE_PUSH_NODE_ARGS;
|
|
23
|
+
|
|
24
|
+
if (typeof envNodeArgs !== "undefined") {
|
|
25
|
+
Array.prototype.push.apply(hermesArgs, envNodeArgs.trim().split(/\s+/));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
Array.prototype.push.apply(hermesArgs, [
|
|
29
|
+
"-emit-binary",
|
|
30
|
+
"-out",
|
|
31
|
+
path.join(outputFolder, bundleName + ".hbc"),
|
|
32
|
+
path.join(outputFolder, bundleName),
|
|
33
|
+
...extraHermesFlags,
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
if (sourcemapOutput) {
|
|
37
|
+
hermesArgs.push("-output-source-map");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
console.log(chalk.cyan("Converting JS bundle to byte code via Hermes, running command:\n"));
|
|
41
|
+
const hermesCommand = await getHermesCommand(gradleFile);
|
|
42
|
+
const hermesProcess = childProcess.spawn(hermesCommand, hermesArgs);
|
|
43
|
+
console.log(`${hermesCommand} ${hermesArgs.join(" ")}`);
|
|
44
|
+
|
|
45
|
+
return new Promise<void>((resolve, reject) => {
|
|
46
|
+
hermesProcess.stdout.on("data", (data: Buffer) => {
|
|
47
|
+
console.log(data.toString().trim());
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
hermesProcess.stderr.on("data", (data: Buffer) => {
|
|
51
|
+
console.error(data.toString().trim());
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
hermesProcess.on("close", (exitCode: number, signal: string) => {
|
|
55
|
+
if (exitCode !== 0) {
|
|
56
|
+
reject(new Error(`"hermes" command failed (exitCode=${exitCode}, signal=${signal}).`));
|
|
57
|
+
}
|
|
58
|
+
// Copy HBC bundle to overwrite JS bundle
|
|
59
|
+
const source = path.join(outputFolder, bundleName + ".hbc");
|
|
60
|
+
const destination = path.join(outputFolder, bundleName);
|
|
61
|
+
fs.copyFile(source, destination, (err) => {
|
|
62
|
+
if (err) {
|
|
63
|
+
console.error(err);
|
|
64
|
+
reject(new Error(`Copying file ${source} to ${destination} failed. "hermes" previously exited with code ${exitCode}.`));
|
|
65
|
+
}
|
|
66
|
+
fs.unlink(source, (err) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
console.error(err);
|
|
69
|
+
reject(err);
|
|
70
|
+
}
|
|
71
|
+
resolve(null as void);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}).then(() => {
|
|
76
|
+
if (!sourcemapOutput) {
|
|
77
|
+
// skip source map compose if source map is not enabled
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const composeSourceMapsPath = getComposeSourceMapsPath();
|
|
82
|
+
if (!composeSourceMapsPath) {
|
|
83
|
+
throw new Error("react-native compose-source-maps.js scripts is not found");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const jsCompilerSourceMapFile = path.join(outputFolder, bundleName + ".hbc" + ".map");
|
|
87
|
+
if (!fs.existsSync(jsCompilerSourceMapFile)) {
|
|
88
|
+
throw new Error(`sourcemap file ${jsCompilerSourceMapFile} is not found`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const composeSourceMapsArgs = [composeSourceMapsPath, sourcemapOutput, jsCompilerSourceMapFile, "-o", sourcemapOutput];
|
|
93
|
+
|
|
94
|
+
// https://github.com/facebook/react-native/blob/master/react.gradle#L211
|
|
95
|
+
// https://github.com/facebook/react-native/blob/master/scripts/react-native-xcode.sh#L178
|
|
96
|
+
// packager.sourcemap.map + hbc.sourcemap.map = sourcemap.map
|
|
97
|
+
const composeSourceMapsProcess = childProcess.spawn("node", composeSourceMapsArgs);
|
|
98
|
+
console.log(`${composeSourceMapsPath} ${composeSourceMapsArgs.join(" ")}`);
|
|
99
|
+
|
|
100
|
+
composeSourceMapsProcess.stdout.on("data", (data: Buffer) => {
|
|
101
|
+
console.log(data.toString().trim());
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
composeSourceMapsProcess.stderr.on("data", (data: Buffer) => {
|
|
105
|
+
console.error(data.toString().trim());
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
composeSourceMapsProcess.on("close", (exitCode: number, signal: string) => {
|
|
109
|
+
if (exitCode !== 0) {
|
|
110
|
+
reject(new Error(`"compose-source-maps" command failed (exitCode=${exitCode}, signal=${signal}).`));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Delete the HBC sourceMap, otherwise it will be included in 'code-push' bundle as well
|
|
114
|
+
fs.unlink(jsCompilerSourceMapFile, (err) => {
|
|
115
|
+
if (err) {
|
|
116
|
+
console.error(err);
|
|
117
|
+
reject(err);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
resolve(null);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function parseBuildGradleFile(gradleFile: string) {
|
|
128
|
+
let buildGradlePath: string = path.join("android", "app");
|
|
129
|
+
if (gradleFile) {
|
|
130
|
+
buildGradlePath = gradleFile;
|
|
131
|
+
}
|
|
132
|
+
if (fs.lstatSync(buildGradlePath).isDirectory()) {
|
|
133
|
+
buildGradlePath = path.join(buildGradlePath, "build.gradle");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (fileDoesNotExistOrIsDirectory(buildGradlePath)) {
|
|
137
|
+
throw new Error(`Unable to find gradle file "${buildGradlePath}".`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return g2js.parseFile(buildGradlePath).catch(() => {
|
|
141
|
+
throw new Error(`Unable to parse the "${buildGradlePath}" file. Please ensure it is a well-formed Gradle file.`);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function getHermesCommandFromGradle(gradleFile: string): Promise<string> {
|
|
146
|
+
const buildGradle: any = await parseBuildGradleFile(gradleFile);
|
|
147
|
+
const hermesCommandProperty: any = Array.from(buildGradle["project.ext.react"] || []).find((prop: string) =>
|
|
148
|
+
prop.trim().startsWith("hermesCommand:")
|
|
149
|
+
);
|
|
150
|
+
if (hermesCommandProperty) {
|
|
151
|
+
return hermesCommandProperty.replace("hermesCommand:", "").trim().slice(1, -1);
|
|
152
|
+
} else {
|
|
153
|
+
return "";
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function getAndroidHermesEnabled(gradleFile: string): boolean {
|
|
158
|
+
return parseBuildGradleFile(gradleFile).then((buildGradle: any) => {
|
|
159
|
+
return Array.from(buildGradle["project.ext.react"] || []).some((line: string) => /^enableHermes\s{0,}:\s{0,}true/.test(line));
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function getiOSHermesEnabled(podFile: string): boolean {
|
|
164
|
+
let podPath = path.join("ios", "Podfile");
|
|
165
|
+
if (podFile) {
|
|
166
|
+
podPath = podFile;
|
|
167
|
+
}
|
|
168
|
+
if (fileDoesNotExistOrIsDirectory(podPath)) {
|
|
169
|
+
throw new Error(`Unable to find Podfile file "${podPath}".`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
const podFileContents = fs.readFileSync(podPath).toString();
|
|
174
|
+
return /([^#\n]*:?hermes_enabled(\s+|\n+)?(=>|:)(\s+|\n+)?true)/.test(podFileContents);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function getHermesOSBin(): string {
|
|
181
|
+
switch (process.platform) {
|
|
182
|
+
case "win32":
|
|
183
|
+
return "win64-bin";
|
|
184
|
+
case "darwin":
|
|
185
|
+
return "osx-bin";
|
|
186
|
+
case "freebsd":
|
|
187
|
+
case "linux":
|
|
188
|
+
case "sunos":
|
|
189
|
+
default:
|
|
190
|
+
return "linux64-bin";
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function getHermesOSExe(): string {
|
|
195
|
+
const react63orAbove = compare(coerce(getReactNativeVersion()).version, "0.63.0") !== -1;
|
|
196
|
+
const hermesExecutableName = react63orAbove ? "hermesc" : "hermes";
|
|
197
|
+
switch (process.platform) {
|
|
198
|
+
case "win32":
|
|
199
|
+
return hermesExecutableName + ".exe";
|
|
200
|
+
default:
|
|
201
|
+
return hermesExecutableName;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async function getHermesCommand(gradleFile: string): Promise<string> {
|
|
206
|
+
const fileExists = (file: string): boolean => {
|
|
207
|
+
try {
|
|
208
|
+
return fs.statSync(file).isFile();
|
|
209
|
+
} catch (e) {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
// Hermes is bundled with react-native since 0.69
|
|
214
|
+
const bundledHermesEngine = path.join(getReactNativePackagePath(), "sdks", "hermesc", getHermesOSBin(), getHermesOSExe());
|
|
215
|
+
if (fileExists(bundledHermesEngine)) {
|
|
216
|
+
return bundledHermesEngine;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const gradleHermesCommand = await getHermesCommandFromGradle(gradleFile);
|
|
220
|
+
if (gradleHermesCommand) {
|
|
221
|
+
return path.join("android", "app", gradleHermesCommand.replace("%OS-BIN%", getHermesOSBin()));
|
|
222
|
+
} else {
|
|
223
|
+
// assume if hermes-engine exists it should be used instead of hermesvm
|
|
224
|
+
const hermesEngine = path.join("node_modules", "hermes-engine", getHermesOSBin(), getHermesOSExe());
|
|
225
|
+
if (fileExists(hermesEngine)) {
|
|
226
|
+
return hermesEngine;
|
|
227
|
+
}
|
|
228
|
+
return path.join("node_modules", "hermesvm", getHermesOSBin(), "hermes");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function getComposeSourceMapsPath(): string {
|
|
233
|
+
// detect if compose-source-maps.js script exists
|
|
234
|
+
const composeSourceMaps = path.join(getReactNativePackagePath(), "scripts", "compose-source-maps.js");
|
|
235
|
+
if (fs.existsSync(composeSourceMaps)) {
|
|
236
|
+
return composeSourceMaps;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function getReactNativePackagePath(): string {
|
|
242
|
+
const result = childProcess.spawnSync("node", ["--print", "require.resolve('react-native/package.json')"]);
|
|
243
|
+
const packagePath = path.dirname(result.stdout.toString());
|
|
244
|
+
if (result.status === 0 && directoryExistsSync(packagePath)) {
|
|
245
|
+
return packagePath;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return path.join("node_modules", "react-native");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export function directoryExistsSync(dirname: string): boolean {
|
|
252
|
+
try {
|
|
253
|
+
return fs.statSync(dirname).isDirectory();
|
|
254
|
+
} catch (err) {
|
|
255
|
+
if (err.code !== "ENOENT") {
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function getReactNativeVersion(): string {
|
|
263
|
+
let packageJsonFilename;
|
|
264
|
+
let projectPackageJson;
|
|
265
|
+
try {
|
|
266
|
+
packageJsonFilename = path.join(process.cwd(), "package.json");
|
|
267
|
+
projectPackageJson = JSON.parse(fs.readFileSync(packageJsonFilename, "utf-8"));
|
|
268
|
+
} catch (error) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Unable to find or read "package.json" in the CWD. The "release-react" command must be executed in a React Native project folder.`
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const projectName: string = projectPackageJson.name;
|
|
275
|
+
if (!projectName) {
|
|
276
|
+
throw new Error(`The "package.json" file in the CWD does not have the "name" field set.`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return (
|
|
280
|
+
(projectPackageJson.dependencies && projectPackageJson.dependencies["react-native"]) ||
|
|
281
|
+
(projectPackageJson.devDependencies && projectPackageJson.devDependencies["react-native"])
|
|
282
|
+
);
|
|
283
|
+
}
|
package/script/sign.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as fs from "fs/promises";
|
|
2
|
+
import * as hashUtils from "./hash-utils";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as jwt from "jsonwebtoken";
|
|
5
|
+
import { copyFileToTmpDir, isDirectory } from "./utils/file-utils";
|
|
6
|
+
|
|
7
|
+
const CURRENT_CLAIM_VERSION: string = "1.0.0";
|
|
8
|
+
const METADATA_FILE_NAME: string = ".codepushrelease";
|
|
9
|
+
|
|
10
|
+
interface CodeSigningClaims {
|
|
11
|
+
claimVersion: string;
|
|
12
|
+
contentHash: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default async function sign(privateKeyPath: string, updateContentsPath: string): Promise<void> {
|
|
16
|
+
if (!privateKeyPath) {
|
|
17
|
+
return Promise.resolve<void>(null);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let privateKey: Buffer;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
privateKey = await fs.readFile(privateKeyPath);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
return Promise.reject(new Error(`The path specified for the signing key ("${privateKeyPath}") was not valid.`));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// If releasing a single file, copy the file to a temporary 'CodePush' directory in which to publish the release
|
|
29
|
+
try {
|
|
30
|
+
if (!isDirectory(updateContentsPath)) {
|
|
31
|
+
updateContentsPath = copyFileToTmpDir(updateContentsPath);
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
Promise.reject(error);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const signatureFilePath: string = path.join(updateContentsPath, METADATA_FILE_NAME);
|
|
38
|
+
let prevSignatureExists = true;
|
|
39
|
+
try {
|
|
40
|
+
await fs.access(signatureFilePath, fs.constants.F_OK);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
if (err.code === "ENOENT") {
|
|
43
|
+
prevSignatureExists = false;
|
|
44
|
+
} else {
|
|
45
|
+
return Promise.reject<void>(
|
|
46
|
+
new Error(
|
|
47
|
+
`Could not delete previous release signature at ${signatureFilePath}.
|
|
48
|
+
Please, check your access rights.`
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (prevSignatureExists) {
|
|
55
|
+
console.log(`Deleting previous release signature at ${signatureFilePath}`);
|
|
56
|
+
await fs.rmdir(signatureFilePath);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const hash: string = await hashUtils.generatePackageHashFromDirectory(updateContentsPath, path.join(updateContentsPath, ".."));
|
|
60
|
+
const claims: CodeSigningClaims = {
|
|
61
|
+
claimVersion: CURRENT_CLAIM_VERSION,
|
|
62
|
+
contentHash: hash,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return new Promise<void>((resolve, reject) => {
|
|
66
|
+
jwt.sign(claims, privateKey, { algorithm: "RS256" }, async (err: Error, signedJwt: string) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
reject(new Error("The specified signing key file was not valid"));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await fs.writeFile(signatureFilePath, signedJwt);
|
|
73
|
+
console.log(`Generated a release signature and wrote it to ${signatureFilePath}`);
|
|
74
|
+
resolve(null);
|
|
75
|
+
} catch (error) {
|
|
76
|
+
reject(error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
import AccountManager = require("../management-sdk");
|
|
5
|
+
|
|
6
|
+
export enum CommandType {
|
|
7
|
+
accessKeyAdd,
|
|
8
|
+
accessKeyPatch,
|
|
9
|
+
accessKeyList,
|
|
10
|
+
accessKeyRemove,
|
|
11
|
+
appAdd,
|
|
12
|
+
appList,
|
|
13
|
+
appRemove,
|
|
14
|
+
appRename,
|
|
15
|
+
appTransfer,
|
|
16
|
+
collaboratorAdd,
|
|
17
|
+
collaboratorList,
|
|
18
|
+
collaboratorRemove,
|
|
19
|
+
debug,
|
|
20
|
+
deploymentAdd,
|
|
21
|
+
deploymentHistory,
|
|
22
|
+
deploymentHistoryClear,
|
|
23
|
+
deploymentList,
|
|
24
|
+
deploymentMetrics,
|
|
25
|
+
deploymentRemove,
|
|
26
|
+
deploymentRename,
|
|
27
|
+
link,
|
|
28
|
+
login,
|
|
29
|
+
logout,
|
|
30
|
+
patch,
|
|
31
|
+
promote,
|
|
32
|
+
register,
|
|
33
|
+
release,
|
|
34
|
+
releaseReact,
|
|
35
|
+
rollback,
|
|
36
|
+
sessionList,
|
|
37
|
+
sessionRemove,
|
|
38
|
+
whoami,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ICommand {
|
|
42
|
+
type: CommandType;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface IAccessKeyAddCommand extends ICommand {
|
|
46
|
+
name: string;
|
|
47
|
+
ttl?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface IAccessKeyPatchCommand extends ICommand {
|
|
51
|
+
newName?: string;
|
|
52
|
+
oldName: string;
|
|
53
|
+
ttl?: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface IAccessKeyListCommand extends ICommand {
|
|
57
|
+
format: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface IAccessKeyRemoveCommand extends ICommand {
|
|
61
|
+
accessKey: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface IAppAddCommand extends ICommand {
|
|
65
|
+
appName: string;
|
|
66
|
+
os: string;
|
|
67
|
+
platform: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface IAppListCommand extends ICommand {
|
|
71
|
+
format: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface IAppRemoveCommand extends ICommand {
|
|
75
|
+
appName: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface IAppRenameCommand extends ICommand {
|
|
79
|
+
currentAppName: string;
|
|
80
|
+
newAppName: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface IAppTransferCommand extends ICommand {
|
|
84
|
+
appName: string;
|
|
85
|
+
email: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface ICollaboratorAddCommand extends ICommand {
|
|
89
|
+
appName: string;
|
|
90
|
+
email: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface ICollaboratorListCommand extends ICommand {
|
|
94
|
+
appName: string;
|
|
95
|
+
format: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ICollaboratorRemoveCommand extends ICommand {
|
|
99
|
+
appName: string;
|
|
100
|
+
email: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface IDebugCommand extends ICommand {
|
|
104
|
+
platform: string;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface IDeploymentAddCommand extends ICommand {
|
|
108
|
+
appName: string;
|
|
109
|
+
deploymentName: string;
|
|
110
|
+
default: boolean;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface IDeploymentHistoryClearCommand extends ICommand {
|
|
114
|
+
appName: string;
|
|
115
|
+
deploymentName: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface IDeploymentHistoryCommand extends ICommand {
|
|
119
|
+
appName: string;
|
|
120
|
+
deploymentName: string;
|
|
121
|
+
format: string;
|
|
122
|
+
displayAuthor: boolean;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface IDeploymentListCommand extends ICommand {
|
|
126
|
+
appName: string;
|
|
127
|
+
format: string;
|
|
128
|
+
displayKeys: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface IDeploymentRemoveCommand extends ICommand {
|
|
132
|
+
appName: string;
|
|
133
|
+
deploymentName: string;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface IDeploymentRenameCommand extends ICommand {
|
|
137
|
+
appName: string;
|
|
138
|
+
currentDeploymentName: string;
|
|
139
|
+
newDeploymentName: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface ILinkCommand extends ICommand {
|
|
143
|
+
serverUrl?: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface ILoginCommand extends ICommand {
|
|
147
|
+
serverUrl?: string;
|
|
148
|
+
accessKey: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface IPackageInfo {
|
|
152
|
+
description?: string;
|
|
153
|
+
label?: string;
|
|
154
|
+
disabled?: boolean;
|
|
155
|
+
mandatory?: boolean;
|
|
156
|
+
rollout?: number;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface IPatchCommand extends ICommand, IPackageInfo {
|
|
160
|
+
appName: string;
|
|
161
|
+
appStoreVersion?: string;
|
|
162
|
+
deploymentName: string;
|
|
163
|
+
label: string;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface IPromoteCommand extends ICommand, IPackageInfo {
|
|
167
|
+
appName: string;
|
|
168
|
+
appStoreVersion?: string;
|
|
169
|
+
sourceDeploymentName: string;
|
|
170
|
+
destDeploymentName: string;
|
|
171
|
+
noDuplicateReleaseError?: boolean;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface IRegisterCommand extends ICommand {
|
|
175
|
+
serverUrl?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface IReleaseBaseCommand extends ICommand, IPackageInfo {
|
|
179
|
+
appName: string;
|
|
180
|
+
appStoreVersion: string;
|
|
181
|
+
deploymentName: string;
|
|
182
|
+
noDuplicateReleaseError?: boolean;
|
|
183
|
+
privateKeyPath?: string;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface IReleaseCommand extends IReleaseBaseCommand {
|
|
187
|
+
package: string;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface IReleaseReactCommand extends IReleaseBaseCommand {
|
|
191
|
+
bundleName?: string;
|
|
192
|
+
development?: boolean;
|
|
193
|
+
entryFile?: string;
|
|
194
|
+
gradleFile?: string;
|
|
195
|
+
platform: string;
|
|
196
|
+
plistFile?: string;
|
|
197
|
+
plistFilePrefix?: string;
|
|
198
|
+
sourcemapOutput?: string;
|
|
199
|
+
outputDir?: string;
|
|
200
|
+
config?: string;
|
|
201
|
+
useHermes?: boolean;
|
|
202
|
+
extraHermesFlags?: string[];
|
|
203
|
+
podFile?: string;
|
|
204
|
+
xcodeProjectFile?: string;
|
|
205
|
+
xcodeTargetName?: string;
|
|
206
|
+
buildConfigurationName?: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface IRollbackCommand extends ICommand {
|
|
210
|
+
appName: string;
|
|
211
|
+
deploymentName: string;
|
|
212
|
+
targetRelease: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface ISessionListCommand extends ICommand {
|
|
216
|
+
format: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface ISessionRemoveCommand extends ICommand {
|
|
220
|
+
machineName: string;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export type ReleaseHook = (
|
|
224
|
+
currentCommand: IReleaseCommand,
|
|
225
|
+
originalCommand: IReleaseCommand,
|
|
226
|
+
sdk: AccountManager
|
|
227
|
+
) => Q.Promise<IReleaseCommand | void>;
|
|
228
|
+
|
|
229
|
+
export interface ReleaseFile {
|
|
230
|
+
sourceLocation: string; // The current location of the file on disk
|
|
231
|
+
targetLocation: string; // The desired location of the file within the zip
|
|
232
|
+
}
|