@capawesome/cli 1.3.2 → 1.4.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/CHANGELOG.md +19 -0
- package/README.md +36 -1
- package/dist/commands/apps/bundles/create.js +58 -22
- package/dist/services/app-bundles.js +4 -29
- package/dist/services/update.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [1.4.1](https://github.com/capawesome-team/cli/compare/v1.4.0...v1.4.1) (2025-02-16)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **bundles:** add retry mechanism for file upload on failure ([86a62da](https://github.com/capawesome-team/cli/commit/86a62daa2ae50d691791714ef6a5812a6e87dc4b))
|
|
11
|
+
|
|
12
|
+
## [1.4.0](https://github.com/capawesome-team/cli/compare/v1.3.2...v1.4.0) (2025-01-29)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* **bundles:** support custom properties ([#31](https://github.com/capawesome-team/cli/issues/31)) ([405634b](https://github.com/capawesome-team/cli/commit/405634b8a46a77a72ea9812fb350f54ca79a8387))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* convert command arguments to string if not undefined ([b147e21](https://github.com/capawesome-team/cli/commit/b147e214b4ee0da3babc82773b1426162f753c36)), closes [#33](https://github.com/capawesome-team/cli/issues/33)
|
|
23
|
+
|
|
5
24
|
## [1.3.2](https://github.com/capawesome-team/cli/compare/v1.3.1...v1.3.2) (2024-12-30)
|
|
6
25
|
|
|
7
26
|
|
package/README.md
CHANGED
|
@@ -10,6 +10,16 @@ The Capawesome Cloud CLI can be installed globally via npm:
|
|
|
10
10
|
npm install -g @capawesome/cli
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
The Capawesome Cloud CLI can be invoked with the `capawesome` command.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx capawesome <command> [options]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
You can find a list of available commands in the [Command Reference](https://capawesome.io/cloud/cli/).
|
|
22
|
+
|
|
13
23
|
## Help
|
|
14
24
|
|
|
15
25
|
The Capawesome Cloud CLI ships with command documentation that is accessible with the `--help` flag.
|
|
@@ -18,10 +28,35 @@ The Capawesome Cloud CLI ships with command documentation that is accessible wit
|
|
|
18
28
|
npx capawesome --help
|
|
19
29
|
```
|
|
20
30
|
|
|
31
|
+
## Development
|
|
32
|
+
|
|
33
|
+
Run the following commands to get started with development:
|
|
34
|
+
|
|
35
|
+
1. Clone the repository:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/capawesome-team/cli.git
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
2. Install dependencies:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. Copy the `.capawesomerc.example` file to `.capawesomerc`
|
|
48
|
+
4. Run your first command:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm start -- --help
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Note:** The `--` is required to pass arguments to the script.
|
|
55
|
+
|
|
21
56
|
## Changelog
|
|
22
57
|
|
|
23
58
|
See [CHANGELOG](./CHANGELOG.md).
|
|
24
59
|
|
|
25
60
|
## License
|
|
26
61
|
|
|
27
|
-
See [LICENSE](./LICENSE.md).
|
|
62
|
+
See [LICENSE](./LICENSE.md).
|
|
@@ -52,6 +52,10 @@ exports.default = (0, citty_1.defineCommand)({
|
|
|
52
52
|
type: 'string',
|
|
53
53
|
description: 'Channel to associate the bundle with.',
|
|
54
54
|
},
|
|
55
|
+
customProperty: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'A custom property to assign to the bundle. Must be in the format `key=value`. Can be specified multiple times.',
|
|
58
|
+
},
|
|
55
59
|
expiresInDays: {
|
|
56
60
|
type: 'string',
|
|
57
61
|
description: 'The number of days until the bundle is automatically deleted.',
|
|
@@ -86,19 +90,20 @@ exports.default = (0, citty_1.defineCommand)({
|
|
|
86
90
|
consola_1.default.error('You must be logged in to run this command.');
|
|
87
91
|
process.exit(1);
|
|
88
92
|
}
|
|
89
|
-
let androidMax = ctx.args.androidMax;
|
|
90
|
-
let androidMin = ctx.args.androidMin;
|
|
93
|
+
let androidMax = ctx.args.androidMax === undefined ? undefined : ctx.args.androidMax + ''; // Convert to string
|
|
94
|
+
let androidMin = ctx.args.androidMin === undefined ? undefined : ctx.args.androidMin + ''; // Convert to string
|
|
91
95
|
let appId = ctx.args.appId;
|
|
92
96
|
let artifactType = ctx.args.artifactType === 'manifest' || ctx.args.artifactType === 'zip'
|
|
93
97
|
? ctx.args.artifactType
|
|
94
98
|
: 'zip';
|
|
95
99
|
let channelName = ctx.args.channel;
|
|
96
|
-
let
|
|
97
|
-
let
|
|
98
|
-
let
|
|
100
|
+
let customProperty = ctx.args.customProperty;
|
|
101
|
+
let expiresInDays = ctx.args.expiresInDays === undefined ? undefined : ctx.args.expiresInDays + ''; // Convert to string
|
|
102
|
+
let iosMax = ctx.args.iosMax === undefined ? undefined : ctx.args.iosMax + ''; // Convert to string
|
|
103
|
+
let iosMin = ctx.args.iosMin === undefined ? undefined : ctx.args.iosMin + ''; // Convert to string
|
|
99
104
|
let path = ctx.args.path;
|
|
100
105
|
let privateKey = ctx.args.privateKey;
|
|
101
|
-
let rolloutAsString = ctx.args.rollout;
|
|
106
|
+
let rolloutAsString = ctx.args.rollout === undefined ? undefined : ctx.args.rollout + ''; // Convert to string
|
|
102
107
|
let url = ctx.args.url;
|
|
103
108
|
// Validate the expiration days
|
|
104
109
|
let expiresAt;
|
|
@@ -200,6 +205,7 @@ exports.default = (0, citty_1.defineCommand)({
|
|
|
200
205
|
appId,
|
|
201
206
|
artifactType,
|
|
202
207
|
channelName,
|
|
208
|
+
customProperties: parseCustomProperties(customProperty),
|
|
203
209
|
expiresAt: expiresAt,
|
|
204
210
|
url,
|
|
205
211
|
maxAndroidAppVersionCode: androidMax,
|
|
@@ -239,23 +245,31 @@ exports.default = (0, citty_1.defineCommand)({
|
|
|
239
245
|
}),
|
|
240
246
|
});
|
|
241
247
|
const uploadFile = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
+
try {
|
|
249
|
+
// Generate checksum
|
|
250
|
+
const hash = yield (0, hash_1.createHash)(options.fileBuffer);
|
|
251
|
+
// Sign the bundle
|
|
252
|
+
let signature;
|
|
253
|
+
if (options.privateKeyBuffer) {
|
|
254
|
+
signature = yield (0, signature_1.createSignature)(options.privateKeyBuffer, options.fileBuffer);
|
|
255
|
+
}
|
|
256
|
+
// Create the multipart upload
|
|
257
|
+
return yield app_bundle_files_1.default.create({
|
|
258
|
+
appId: options.appId,
|
|
259
|
+
appBundleId: options.appBundleId,
|
|
260
|
+
checksum: hash,
|
|
261
|
+
fileBuffer: options.fileBuffer,
|
|
262
|
+
fileName: options.fileName,
|
|
263
|
+
href: options.href,
|
|
264
|
+
signature,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
if (options.retryOnFailure) {
|
|
269
|
+
return uploadFile(Object.assign(Object.assign({}, options), { retryOnFailure: false }));
|
|
270
|
+
}
|
|
271
|
+
throw error;
|
|
248
272
|
}
|
|
249
|
-
// Create the multipart upload
|
|
250
|
-
return app_bundle_files_1.default.create({
|
|
251
|
-
appId: options.appId,
|
|
252
|
-
appBundleId: options.appBundleId,
|
|
253
|
-
checksum: hash,
|
|
254
|
-
fileBuffer: options.fileBuffer,
|
|
255
|
-
fileName: options.fileName,
|
|
256
|
-
href: options.href,
|
|
257
|
-
signature,
|
|
258
|
-
});
|
|
259
273
|
});
|
|
260
274
|
const uploadFiles = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
275
|
// Generate the manifest file
|
|
@@ -282,6 +296,7 @@ const uploadFiles = (options) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
282
296
|
fileName,
|
|
283
297
|
href,
|
|
284
298
|
privateKeyBuffer: options.privateKeyBuffer,
|
|
299
|
+
retryOnFailure: true,
|
|
285
300
|
});
|
|
286
301
|
yield uploadNextFile();
|
|
287
302
|
});
|
|
@@ -315,3 +330,24 @@ const uploadZip = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
315
330
|
appBundleFileId: result.id,
|
|
316
331
|
};
|
|
317
332
|
});
|
|
333
|
+
const parseCustomProperties = (customProperty) => {
|
|
334
|
+
let customProperties;
|
|
335
|
+
if (customProperty) {
|
|
336
|
+
customProperties = {};
|
|
337
|
+
if (Array.isArray(customProperty)) {
|
|
338
|
+
for (const property of customProperty) {
|
|
339
|
+
const [key, value] = property.split('=');
|
|
340
|
+
if (key && value) {
|
|
341
|
+
customProperties[key] = value;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
const [key, value] = customProperty.split('=');
|
|
347
|
+
if (key && value) {
|
|
348
|
+
customProperties[key] = value;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return customProperties;
|
|
353
|
+
};
|
|
@@ -12,7 +12,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
const form_data_1 = __importDefault(require("form-data"));
|
|
16
15
|
const http_client_1 = __importDefault(require("../utils/http-client"));
|
|
17
16
|
const authorization_service_1 = __importDefault(require("./authorization-service"));
|
|
18
17
|
class AppBundlesServiceImpl {
|
|
@@ -21,34 +20,10 @@ class AppBundlesServiceImpl {
|
|
|
21
20
|
}
|
|
22
21
|
create(dto) {
|
|
23
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
if (dto.expiresAt) {
|
|
30
|
-
formData.append('expiresAt', dto.expiresAt);
|
|
31
|
-
}
|
|
32
|
-
if (dto.url) {
|
|
33
|
-
formData.append('url', dto.url);
|
|
34
|
-
}
|
|
35
|
-
if (dto.maxAndroidAppVersionCode) {
|
|
36
|
-
formData.append('maxAndroidAppVersionCode', dto.maxAndroidAppVersionCode);
|
|
37
|
-
}
|
|
38
|
-
if (dto.maxIosAppVersionCode) {
|
|
39
|
-
formData.append('maxIosAppVersionCode', dto.maxIosAppVersionCode);
|
|
40
|
-
}
|
|
41
|
-
if (dto.minAndroidAppVersionCode) {
|
|
42
|
-
formData.append('minAndroidAppVersionCode', dto.minAndroidAppVersionCode);
|
|
43
|
-
}
|
|
44
|
-
if (dto.minIosAppVersionCode) {
|
|
45
|
-
formData.append('minIosAppVersionCode', dto.minIosAppVersionCode);
|
|
46
|
-
}
|
|
47
|
-
if (dto.rolloutPercentage) {
|
|
48
|
-
formData.append('rolloutPercentage', dto.rolloutPercentage.toString());
|
|
49
|
-
}
|
|
50
|
-
const response = yield this.httpClient.post(`/apps/${dto.appId}/bundles`, formData, {
|
|
51
|
-
headers: Object.assign({ Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}` }, formData.getHeaders()),
|
|
23
|
+
const response = yield this.httpClient.post(`/apps/${dto.appId}/bundles`, dto, {
|
|
24
|
+
headers: {
|
|
25
|
+
Authorization: `Bearer ${authorization_service_1.default.getCurrentAuthorizationToken()}`,
|
|
26
|
+
},
|
|
52
27
|
});
|
|
53
28
|
return response.data;
|
|
54
29
|
});
|
package/dist/services/update.js
CHANGED
package/package.json
CHANGED