airborne-devkit 0.26.1 ā 0.28.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/CHANGELOG.md +78 -0
- package/package.json +1 -1
- package/src/index.js +122 -30
- package/src/utils/common.js +85 -8
- package/src/utils/file.js +54 -24
- package/src/utils/package.js +2 -2
- package/src/utils/release.js +11 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,84 @@
|
|
|
2
2
|
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
|
|
3
3
|
|
|
4
4
|
- - -
|
|
5
|
+
## airborne_cli-v0.3.0 - 2026-03-26
|
|
6
|
+
#### Features
|
|
7
|
+
- add platform-specific configuration and improve file processing and update smithy-cli-generator submodule - (823cfe5) - Yash Rajput
|
|
8
|
+
|
|
9
|
+
- - -
|
|
10
|
+
|
|
11
|
+
## v0.27.0 - 2026-03-26
|
|
12
|
+
#### Miscellaneous Chores
|
|
13
|
+
- **(version)** v0.27.0 [skip ci] - (75587e4) - Airborne Bot
|
|
14
|
+
|
|
15
|
+
- - -
|
|
16
|
+
|
|
17
|
+
## v0.26.1 - 2026-03-26
|
|
18
|
+
#### Miscellaneous Chores
|
|
19
|
+
- **(version)** v0.26.1 [skip ci] - (7b0b420) - Airborne Bot
|
|
20
|
+
|
|
21
|
+
- - -
|
|
22
|
+
|
|
23
|
+
## v0.26.0 - 2026-03-26
|
|
24
|
+
#### Miscellaneous Chores
|
|
25
|
+
- **(version)** v0.26.0 [skip ci] - (e987bfa) - Airborne Bot
|
|
26
|
+
|
|
27
|
+
- - -
|
|
28
|
+
|
|
29
|
+
## v0.25.0 - 2026-03-26
|
|
30
|
+
#### Miscellaneous Chores
|
|
31
|
+
- **(version)** v0.25.0 [skip ci] - (8a22156) - Airborne Bot
|
|
32
|
+
|
|
33
|
+
- - -
|
|
34
|
+
|
|
35
|
+
## v0.24.4 - 2026-03-26
|
|
36
|
+
#### Miscellaneous Chores
|
|
37
|
+
- **(version)** v0.24.4 [skip ci] - (3398e93) - Airborne Bot
|
|
38
|
+
|
|
39
|
+
- - -
|
|
40
|
+
|
|
41
|
+
## v0.24.3 - 2026-03-26
|
|
42
|
+
#### Miscellaneous Chores
|
|
43
|
+
- **(version)** v0.24.3 [skip ci] - (bd6d431) - Airborne Bot
|
|
44
|
+
|
|
45
|
+
- - -
|
|
46
|
+
|
|
47
|
+
## v0.24.2 - 2026-03-26
|
|
48
|
+
#### Miscellaneous Chores
|
|
49
|
+
- **(version)** v0.24.2 [skip ci] - (3c27527) - Airborne Bot
|
|
50
|
+
|
|
51
|
+
- - -
|
|
52
|
+
|
|
53
|
+
## v0.24.1 - 2026-03-26
|
|
54
|
+
#### Miscellaneous Chores
|
|
55
|
+
- **(version)** v0.24.1 [skip ci] - (c89ac50) - Airborne Bot
|
|
56
|
+
|
|
57
|
+
- - -
|
|
58
|
+
|
|
59
|
+
## v0.24.0 - 2026-03-26
|
|
60
|
+
#### Miscellaneous Chores
|
|
61
|
+
- **(version)** v0.24.0 [skip ci] - (d127ca2) - Airborne Bot
|
|
62
|
+
|
|
63
|
+
- - -
|
|
64
|
+
|
|
65
|
+
## v0.23.3 - 2026-03-26
|
|
66
|
+
#### Miscellaneous Chores
|
|
67
|
+
- **(version)** v0.23.3 [skip ci] - (fea39f7) - Airborne Bot
|
|
68
|
+
|
|
69
|
+
- - -
|
|
70
|
+
|
|
71
|
+
## v0.23.2 - 2026-03-26
|
|
72
|
+
#### Miscellaneous Chores
|
|
73
|
+
- **(version)** v0.23.2 [skip ci] - (1a6ac61) - Airborne Bot
|
|
74
|
+
|
|
75
|
+
- - -
|
|
76
|
+
|
|
77
|
+
## v0.23.1 - 2026-03-26
|
|
78
|
+
#### Miscellaneous Chores
|
|
79
|
+
- **(version)** v0.23.1 [skip ci] - (1644fd6) - Airborne Bot
|
|
80
|
+
|
|
81
|
+
- - -
|
|
82
|
+
|
|
5
83
|
## airborne_cli-v0.2.0 - 2026-02-05
|
|
6
84
|
#### Features
|
|
7
85
|
- add Expo project support in cli - (751a4f5) - Yash Rajput
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { Command, InvalidOptionArgumentError } from "commander";
|
|
4
4
|
import coreCli from "airborne-core-cli";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
readAndResolveAirborneConfig,
|
|
7
7
|
writeAirborneConfig,
|
|
8
8
|
normalizeOptions,
|
|
9
9
|
formatCommand,
|
|
@@ -17,16 +17,27 @@ import {
|
|
|
17
17
|
readReleaseConfig,
|
|
18
18
|
releaseConfigExists,
|
|
19
19
|
updateLocalReleaseConfig,
|
|
20
|
+
writeReleaseConfig,
|
|
20
21
|
} from "./utils/release.js";
|
|
21
22
|
import { createFiles, uploadFiles } from "./utils/file.js";
|
|
22
23
|
import { createPackageFromLocalRelease } from "./utils/package.js";
|
|
23
24
|
import { PostLoginAction } from "airborne-core-cli/action";
|
|
25
|
+
import { getBaseUrl, setBaseUrl } from "airborne-core-cli";
|
|
24
26
|
const program = new Command();
|
|
25
27
|
|
|
28
|
+
try{
|
|
29
|
+
const baseUrl = await getBaseUrl();
|
|
30
|
+
if(!baseUrl){
|
|
31
|
+
await setBaseUrl("https://airborne.juspay.in");
|
|
32
|
+
}
|
|
33
|
+
}catch(err){
|
|
34
|
+
await setBaseUrl("https://airborne.juspay.in");
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
program
|
|
27
38
|
.name("airborne-devkit")
|
|
28
39
|
.description("Command-line interface for Airborne operations")
|
|
29
|
-
.version("0.
|
|
40
|
+
.version("0.28.0");
|
|
30
41
|
|
|
31
42
|
coreCli.commands.forEach((cmd, i) => {
|
|
32
43
|
if (cmd._name !== "PostLogin") {
|
|
@@ -48,8 +59,10 @@ program
|
|
|
48
59
|
|
|
49
60
|
Usage 2 - With all options specified:
|
|
50
61
|
$ airborne-devkit create-local-airborne-config [directoryPath] \\
|
|
51
|
-
-
|
|
52
|
-
-
|
|
62
|
+
--android-organisation <android-organisation> \\
|
|
63
|
+
--ios-organisation <ios-organisation> \\
|
|
64
|
+
--android-namespace <android-namespace> \\
|
|
65
|
+
--ios-namespace <ios-namespace> \\
|
|
53
66
|
-j <js-entry-file> \\
|
|
54
67
|
-a <android-index-file> \\
|
|
55
68
|
-i <ios-index-file> \\
|
|
@@ -57,8 +70,10 @@ program
|
|
|
57
70
|
|
|
58
71
|
Parameters:
|
|
59
72
|
[directoryPath] (optional) : Directory where config will be created (defaults to current directory)
|
|
60
|
-
-
|
|
61
|
-
-
|
|
73
|
+
--android-organisation <string> (optional) : Organisation name for Android
|
|
74
|
+
--ios-organisation <string> (optional) : Organisation name for iOS
|
|
75
|
+
--android-namespace <string> (optional) : Namespace or application name for Android
|
|
76
|
+
--ios-namespace <string> (optional) : Namespace or application name for iOS
|
|
62
77
|
-j, --js-entry-file <string> (optional) : Path to the JavaScript entry file
|
|
63
78
|
-a, --android-index-file <string> (optional) : Path to the Android bundle output file
|
|
64
79
|
-i, --ios-index-file <string> (optional) : Path to the iOS bundle output file
|
|
@@ -66,10 +81,21 @@ program
|
|
|
66
81
|
|
|
67
82
|
`
|
|
68
83
|
)
|
|
69
|
-
.option("-o, --organisation <org>", "Organisation name of the package")
|
|
70
84
|
.option(
|
|
71
|
-
"-
|
|
72
|
-
"
|
|
85
|
+
"--android-organisation <org>",
|
|
86
|
+
"Organisation name for Android"
|
|
87
|
+
)
|
|
88
|
+
.option(
|
|
89
|
+
"--ios-organisation <org>",
|
|
90
|
+
"Organisation name for iOS"
|
|
91
|
+
)
|
|
92
|
+
.option(
|
|
93
|
+
"--android-namespace <namespace>",
|
|
94
|
+
"Namespace or application name for Android"
|
|
95
|
+
)
|
|
96
|
+
.option(
|
|
97
|
+
"--ios-namespace <namespace>",
|
|
98
|
+
"Namespace or application name for iOS"
|
|
73
99
|
)
|
|
74
100
|
.option("-j, --js-entry-file <path>", "Path to the JavaScript entry file")
|
|
75
101
|
.option(
|
|
@@ -91,29 +117,35 @@ Examples:
|
|
|
91
117
|
|
|
92
118
|
3. Create config with all options specified:
|
|
93
119
|
$ airborne-devkit create-local-airborne-config \\
|
|
94
|
-
-
|
|
95
|
-
-
|
|
120
|
+
--android-organisation "MyCompany" \\
|
|
121
|
+
--ios-organisation "MyCompany" \\
|
|
122
|
+
--android-namespace "MyApp" \\
|
|
123
|
+
--ios-namespace "MyApp" \\
|
|
96
124
|
-j "index.js" \\
|
|
97
125
|
-a "android/app/build/generated/assets/react/release/index.android.bundle" \\
|
|
98
126
|
-i "ios/main.jsbundle"
|
|
99
127
|
|
|
100
128
|
4. Create config in specific directory with options:
|
|
101
129
|
$ airborne-devkit create-local-airborne-config ./my-rn-project \\
|
|
102
|
-
-
|
|
103
|
-
-
|
|
130
|
+
--android-organisation "MyCompany" \\
|
|
131
|
+
--ios-organisation "MyCompany" \\
|
|
132
|
+
--android-namespace "MyApp" \\
|
|
133
|
+
--ios-namespace "MyApp"
|
|
104
134
|
|
|
105
135
|
5. Create config for an Expo project:
|
|
106
136
|
$ airborne-devkit create-local-airborne-config -e
|
|
107
137
|
|
|
108
138
|
6. Create config for Expo project with all options:
|
|
109
139
|
$ airborne-devkit create-local-airborne-config \\
|
|
110
|
-
-
|
|
111
|
-
-
|
|
140
|
+
--android-organisation "MyCompany" \\
|
|
141
|
+
--ios-organisation "MyCompany" \\
|
|
142
|
+
--android-namespace "MyApp" \\
|
|
143
|
+
--ios-namespace "MyApp" \\
|
|
112
144
|
-e
|
|
113
145
|
|
|
114
146
|
Notes:
|
|
115
147
|
- If directoryPath is not provided, current working directory will be used
|
|
116
|
-
- If
|
|
148
|
+
- If organisations, namespaces, and others are not provided, you'll be prompted to enter them
|
|
117
149
|
- Command will fail if an airborne config already exists in the target directory`
|
|
118
150
|
)
|
|
119
151
|
.action(async (directoryPath, options) => {
|
|
@@ -245,8 +277,9 @@ Notes:
|
|
|
245
277
|
);
|
|
246
278
|
}
|
|
247
279
|
const normalizedOptions = normalizeOptions(options);
|
|
248
|
-
const airborneConfig = await
|
|
249
|
-
normalizedOptions.directory_path
|
|
280
|
+
const airborneConfig = await readAndResolveAirborneConfig(
|
|
281
|
+
normalizedOptions.directory_path,
|
|
282
|
+
normalizedOptions.platform
|
|
250
283
|
);
|
|
251
284
|
const releaseConfig = await releaseConfigExists(
|
|
252
285
|
normalizedOptions.directory_path,
|
|
@@ -383,7 +416,10 @@ Notes:
|
|
|
383
416
|
}
|
|
384
417
|
const normalizedOptions = normalizeOptions(options);
|
|
385
418
|
|
|
386
|
-
const config = await
|
|
419
|
+
const config = await readAndResolveAirborneConfig(
|
|
420
|
+
normalizedOptions.directory_path,
|
|
421
|
+
options.platform
|
|
422
|
+
);
|
|
387
423
|
await updateLocalReleaseConfig(
|
|
388
424
|
config,
|
|
389
425
|
normalizedOptions,
|
|
@@ -492,8 +528,9 @@ Notes:
|
|
|
492
528
|
);
|
|
493
529
|
}
|
|
494
530
|
const normalizedOptions = normalizeOptions(options);
|
|
495
|
-
let airborneConfig = await
|
|
496
|
-
normalizedOptions.directory_path
|
|
531
|
+
let airborneConfig = await readAndResolveAirborneConfig(
|
|
532
|
+
normalizedOptions.directory_path,
|
|
533
|
+
normalizedOptions.platform
|
|
497
534
|
);
|
|
498
535
|
|
|
499
536
|
airborneConfig = { ...airborneConfig, ...normalizedOptions };
|
|
@@ -502,27 +539,81 @@ Notes:
|
|
|
502
539
|
airborneConfig.platform,
|
|
503
540
|
airborneConfig.namespace
|
|
504
541
|
);
|
|
505
|
-
|
|
506
|
-
releaseConfig.package.index
|
|
507
|
-
);
|
|
542
|
+
|
|
508
543
|
try {
|
|
509
544
|
airborneConfig.token = await loadToken(normalizedOptions.directory_path)
|
|
510
545
|
.access_token;
|
|
511
546
|
} catch (err) {
|
|
512
547
|
throw new Error("Please log in first");
|
|
513
548
|
}
|
|
549
|
+
|
|
550
|
+
let baseUrl;
|
|
514
551
|
if (!options.upload) {
|
|
515
|
-
|
|
552
|
+
baseUrl = await promptWithType(
|
|
516
553
|
"\n Provide your base url for files: ",
|
|
517
554
|
"string"
|
|
518
555
|
);
|
|
519
556
|
if (baseUrl[baseUrl.length - 1] !== "/") {
|
|
520
557
|
baseUrl = baseUrl + "/";
|
|
521
558
|
}
|
|
522
|
-
await createFiles(filesToUpload, airborneConfig, baseUrl);
|
|
523
|
-
} else {
|
|
524
|
-
await uploadFiles(filesToUpload, airborneConfig);
|
|
525
559
|
}
|
|
560
|
+
|
|
561
|
+
const processFiles = async (files) => {
|
|
562
|
+
if (!files || files.length === 0) return;
|
|
563
|
+
if (options.upload) {
|
|
564
|
+
return await uploadFiles(files, airborneConfig);
|
|
565
|
+
} else {
|
|
566
|
+
return await createFiles(files, airborneConfig, baseUrl);
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
const applyResults = (entries, results) => {
|
|
571
|
+
if (!entries || !results) return;
|
|
572
|
+
for (const entry of entries) {
|
|
573
|
+
if (results[entry.file_path]) {
|
|
574
|
+
entry.url = results[entry.file_path].url;
|
|
575
|
+
entry.checksum = results[entry.file_path].checksum;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
console.log("Processing index file");
|
|
581
|
+
const indexFiles = [releaseConfig.package.index];
|
|
582
|
+
const indexResults = await processFiles(indexFiles);
|
|
583
|
+
applyResults(indexFiles, indexResults);
|
|
584
|
+
releaseConfig.package.index = indexFiles[0];
|
|
585
|
+
|
|
586
|
+
const importantFiles = releaseConfig.package.important || [];
|
|
587
|
+
if (importantFiles.length > 0) {
|
|
588
|
+
console.log("Processing important files");
|
|
589
|
+
const importantResults = await processFiles(importantFiles);
|
|
590
|
+
applyResults(importantFiles, importantResults);
|
|
591
|
+
releaseConfig.package.important = importantFiles;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const lazyFiles = releaseConfig.package.lazy || [];
|
|
595
|
+
if (lazyFiles.length > 0) {
|
|
596
|
+
console.log("Processing lazy files");
|
|
597
|
+
const lazyResults = await processFiles(lazyFiles);
|
|
598
|
+
applyResults(lazyFiles, lazyResults);
|
|
599
|
+
releaseConfig.package.lazy = lazyFiles;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
const resourceFiles = releaseConfig.resources || [];
|
|
603
|
+
if (resourceFiles.length > 0) {
|
|
604
|
+
console.log("Processing resource files");
|
|
605
|
+
const resourceResults = await processFiles(resourceFiles);
|
|
606
|
+
applyResults(resourceFiles, resourceResults);
|
|
607
|
+
releaseConfig.resources = resourceFiles;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
await writeReleaseConfig(
|
|
611
|
+
releaseConfig,
|
|
612
|
+
airborneConfig.platform,
|
|
613
|
+
airborneConfig.namespace,
|
|
614
|
+
airborneConfig.directory_path
|
|
615
|
+
);
|
|
616
|
+
|
|
526
617
|
process.exit(0);
|
|
527
618
|
} catch (err) {
|
|
528
619
|
console.error("ā Failed to create remote files:", err.message);
|
|
@@ -631,8 +722,9 @@ Notes:
|
|
|
631
722
|
);
|
|
632
723
|
}
|
|
633
724
|
const normalizedOptions = normalizeOptions(options);
|
|
634
|
-
let airborneConfig = await
|
|
635
|
-
normalizedOptions.directory_path
|
|
725
|
+
let airborneConfig = await readAndResolveAirborneConfig(
|
|
726
|
+
normalizedOptions.directory_path,
|
|
727
|
+
normalizedOptions.platform
|
|
636
728
|
);
|
|
637
729
|
|
|
638
730
|
airborneConfig = { ...airborneConfig, ...normalizedOptions };
|
package/src/utils/common.js
CHANGED
|
@@ -4,11 +4,76 @@ import { createHash } from "crypto";
|
|
|
4
4
|
import { createReadStream } from "fs";
|
|
5
5
|
import { promptWithType } from "./prompt.js";
|
|
6
6
|
|
|
7
|
+
function persistToConfig(configPath, platform, fields, label) {
|
|
8
|
+
try {
|
|
9
|
+
const raw = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
10
|
+
if (!raw[platform]) {
|
|
11
|
+
raw[platform] = {};
|
|
12
|
+
}
|
|
13
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
14
|
+
raw[platform][key] = value;
|
|
15
|
+
}
|
|
16
|
+
fs.writeFileSync(configPath, JSON.stringify(raw, null, 2), "utf8");
|
|
17
|
+
const keys = Object.keys(fields).join(", ");
|
|
18
|
+
console.log(`ā
Updated ${label} ${keys} in ${configPath}`);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error(
|
|
21
|
+
`ā ļø Could not persist ${label} config to file:`,
|
|
22
|
+
err.message
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function readAndResolveAirborneConfig(directoryPath, platform) {
|
|
28
|
+
const airborneConfig = await readAirborneConfig(directoryPath);
|
|
29
|
+
const configPath = path.join(directoryPath, "airborne-config.json");
|
|
30
|
+
const label = platform === "android" ? "Android" : "iOS";
|
|
31
|
+
|
|
32
|
+
if (!airborneConfig[platform]) {
|
|
33
|
+
airborneConfig[platform] = {};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const fieldsToPersist = {};
|
|
37
|
+
|
|
38
|
+
if (!airborneConfig[platform].organisation) {
|
|
39
|
+
const oldOrganisation = airborneConfig.organisation || undefined;
|
|
40
|
+
|
|
41
|
+
airborneConfig[platform].organisation = await promptWithType(
|
|
42
|
+
`\n Please enter the ${label} organisation name${oldOrganisation ? ` (default: ${oldOrganisation})` : ""}: `,
|
|
43
|
+
"string",
|
|
44
|
+
oldOrganisation
|
|
45
|
+
);
|
|
46
|
+
fieldsToPersist.organisation = airborneConfig[platform].organisation;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!airborneConfig[platform].namespace) {
|
|
50
|
+
const oldNamespace = airborneConfig.namespace || undefined;
|
|
51
|
+
|
|
52
|
+
airborneConfig[platform].namespace = await promptWithType(
|
|
53
|
+
`\n Please enter the ${label} namespace/application name${oldNamespace ? ` (default: ${oldNamespace})` : ""}: `,
|
|
54
|
+
"string",
|
|
55
|
+
oldNamespace
|
|
56
|
+
);
|
|
57
|
+
fieldsToPersist.namespace = airborneConfig[platform].namespace;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (Object.keys(fieldsToPersist).length > 0) {
|
|
61
|
+
persistToConfig(configPath, platform, fieldsToPersist, label);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
airborneConfig.namespace = airborneConfig[platform].namespace;
|
|
65
|
+
airborneConfig.organisation = airborneConfig[platform].organisation;
|
|
66
|
+
|
|
67
|
+
return airborneConfig;
|
|
68
|
+
}
|
|
69
|
+
|
|
7
70
|
const cliToConfigMap = {
|
|
8
71
|
platform: "platform",
|
|
9
72
|
tag: "tag",
|
|
10
|
-
|
|
11
|
-
|
|
73
|
+
androidOrganisation: "android.organisation",
|
|
74
|
+
iosOrganisation: "ios.organisation",
|
|
75
|
+
androidNamespace: "android.namespace",
|
|
76
|
+
iosNamespace: "ios.namespace",
|
|
12
77
|
jsEntryFile: "js_entry_file",
|
|
13
78
|
androidIndex: "android.index_file_path",
|
|
14
79
|
iosIndex: "ios.index_file_path",
|
|
@@ -55,14 +120,16 @@ export async function writeAirborneConfig(options) {
|
|
|
55
120
|
try {
|
|
56
121
|
const filledOptions = await fillAirborneConfigOptions(options);
|
|
57
122
|
const config = {
|
|
58
|
-
organisation: filledOptions.organisation,
|
|
59
|
-
namespace: filledOptions.namespace,
|
|
60
123
|
expo: filledOptions.expo,
|
|
61
124
|
js_entry_file: filledOptions.js_entry_file,
|
|
62
125
|
android: {
|
|
126
|
+
organisation: filledOptions.android.organisation,
|
|
127
|
+
namespace: filledOptions.android.namespace,
|
|
63
128
|
index_file_path: filledOptions.android.index_file_path,
|
|
64
129
|
},
|
|
65
130
|
ios: {
|
|
131
|
+
organisation: filledOptions.ios.organisation,
|
|
132
|
+
namespace: filledOptions.ios.namespace,
|
|
66
133
|
index_file_path: filledOptions.ios.index_file_path,
|
|
67
134
|
},
|
|
68
135
|
};
|
|
@@ -107,13 +174,23 @@ export async function fillAirborneConfigOptions(options = {}) {
|
|
|
107
174
|
|
|
108
175
|
const questions = [
|
|
109
176
|
{
|
|
110
|
-
key: "organisation",
|
|
111
|
-
question: "\n Please enter the organisation name: ",
|
|
177
|
+
key: "android.organisation",
|
|
178
|
+
question: "\n Please enter the Android organisation name: ",
|
|
179
|
+
expectedType: "string",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
key: "ios.organisation",
|
|
183
|
+
question: "\n Please enter the iOS organisation name: ",
|
|
184
|
+
expectedType: "string",
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
key: "android.namespace",
|
|
188
|
+
question: "\n Please enter the Android namespace/application name: ",
|
|
112
189
|
expectedType: "string",
|
|
113
190
|
},
|
|
114
191
|
{
|
|
115
|
-
key: "namespace",
|
|
116
|
-
question: "\n Please enter namespace/application name: ",
|
|
192
|
+
key: "ios.namespace",
|
|
193
|
+
question: "\n Please enter the iOS namespace/application name: ",
|
|
117
194
|
expectedType: "string",
|
|
118
195
|
},
|
|
119
196
|
{
|
package/src/utils/file.js
CHANGED
|
@@ -82,6 +82,8 @@ export const uploadFiles = async (filesToUpload, config) => {
|
|
|
82
82
|
errors: [],
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
+
const fileResults = {};
|
|
86
|
+
|
|
85
87
|
try {
|
|
86
88
|
for (let index = 0; index < filesToUpload.length; index++) {
|
|
87
89
|
const fileObj = filesToUpload[index];
|
|
@@ -90,10 +92,10 @@ export const uploadFiles = async (filesToUpload, config) => {
|
|
|
90
92
|
try {
|
|
91
93
|
console.log(`${fileProgress} š Processing ${fileObj.file_path}...`);
|
|
92
94
|
|
|
93
|
-
const
|
|
95
|
+
const stored = await getMappedChecksumAndURL(
|
|
94
96
|
config.directory_path,
|
|
95
97
|
fileObj.file_path,
|
|
96
|
-
config
|
|
98
|
+
config
|
|
97
99
|
);
|
|
98
100
|
|
|
99
101
|
const baseDir = path.isAbsolute(config.directory_path)
|
|
@@ -115,10 +117,11 @@ export const uploadFiles = async (filesToUpload, config) => {
|
|
|
115
117
|
|
|
116
118
|
const checksum = await sha256FileHex(fileFullPath);
|
|
117
119
|
|
|
118
|
-
if (
|
|
120
|
+
if (stored?.checksum === checksum) {
|
|
119
121
|
console.log(
|
|
120
122
|
`${fileProgress} ā
File already exists, checksum matches`
|
|
121
123
|
);
|
|
124
|
+
fileResults[fileObj.file_path] = { url: stored.url, checksum: stored.checksum };
|
|
122
125
|
results.existing++;
|
|
123
126
|
continue;
|
|
124
127
|
}
|
|
@@ -144,11 +147,18 @@ export const uploadFiles = async (filesToUpload, config) => {
|
|
|
144
147
|
await createFileMapping(
|
|
145
148
|
config.directory_path,
|
|
146
149
|
uploadOutput.file_path,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
{
|
|
151
|
+
id: uploadOutput.id,
|
|
152
|
+
checksum: uploadOutput.checksum,
|
|
153
|
+
url: uploadOutput.url,
|
|
154
|
+
organisation: config.organisation,
|
|
155
|
+
namespace: config.namespace,
|
|
156
|
+
tag: uploadOutput.tag,
|
|
157
|
+
}
|
|
150
158
|
);
|
|
151
159
|
|
|
160
|
+
fileResults[fileObj.file_path] = { url: uploadOutput.url, checksum: uploadOutput.checksum };
|
|
161
|
+
|
|
152
162
|
// Check if this was a new upload or existing file returned
|
|
153
163
|
if (uploadOutput.checksum === checksum) {
|
|
154
164
|
console.log(
|
|
@@ -185,6 +195,8 @@ export const uploadFiles = async (filesToUpload, config) => {
|
|
|
185
195
|
console.error("\nš„ Upload process failed:", err.message);
|
|
186
196
|
throw err;
|
|
187
197
|
}
|
|
198
|
+
|
|
199
|
+
return fileResults;
|
|
188
200
|
};
|
|
189
201
|
|
|
190
202
|
export async function createFiles(filesToCreate, config, prefixUrl) {
|
|
@@ -199,6 +211,8 @@ export async function createFiles(filesToCreate, config, prefixUrl) {
|
|
|
199
211
|
errors: [],
|
|
200
212
|
};
|
|
201
213
|
|
|
214
|
+
const fileResults = {};
|
|
215
|
+
|
|
202
216
|
try {
|
|
203
217
|
for (let index = 0; index < filesToCreate.length; index++) {
|
|
204
218
|
const fileObj = filesToCreate[index];
|
|
@@ -207,10 +221,10 @@ export async function createFiles(filesToCreate, config, prefixUrl) {
|
|
|
207
221
|
try {
|
|
208
222
|
console.log(`${fileProgress} š Processing ${fileObj.file_path}...`);
|
|
209
223
|
|
|
210
|
-
const
|
|
224
|
+
const stored = await getMappedChecksumAndURL(
|
|
211
225
|
config.directory_path,
|
|
212
226
|
fileObj.file_path,
|
|
213
|
-
config
|
|
227
|
+
config
|
|
214
228
|
);
|
|
215
229
|
|
|
216
230
|
const baseDir = path.isAbsolute(config.directory_path)
|
|
@@ -230,14 +244,15 @@ export async function createFiles(filesToCreate, config, prefixUrl) {
|
|
|
230
244
|
throw new Error(`File not found: ${fileFullPath}`);
|
|
231
245
|
}
|
|
232
246
|
|
|
233
|
-
if (
|
|
247
|
+
if (stored?.checksum) {
|
|
234
248
|
console.log(`${fileProgress} š Calculating checksum...`);
|
|
235
249
|
const checksum = await sha256FileHex(fileFullPath);
|
|
236
250
|
|
|
237
|
-
if (
|
|
251
|
+
if (stored.checksum === checksum) {
|
|
238
252
|
console.log(
|
|
239
253
|
`${fileProgress} ā
File already exists, checksum matches`
|
|
240
254
|
);
|
|
255
|
+
fileResults[fileObj.file_path] = { url: stored.url, checksum: stored.checksum };
|
|
241
256
|
results.existing++;
|
|
242
257
|
continue;
|
|
243
258
|
}
|
|
@@ -270,11 +285,18 @@ export async function createFiles(filesToCreate, config, prefixUrl) {
|
|
|
270
285
|
await createFileMapping(
|
|
271
286
|
config.directory_path,
|
|
272
287
|
output.file_path,
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
288
|
+
{
|
|
289
|
+
id: output.id,
|
|
290
|
+
checksum: output.checksum,
|
|
291
|
+
url: output.url,
|
|
292
|
+
organisation: config.organisation,
|
|
293
|
+
namespace: config.namespace,
|
|
294
|
+
tag: output.tag,
|
|
295
|
+
}
|
|
276
296
|
);
|
|
277
297
|
|
|
298
|
+
fileResults[fileObj.file_path] = { url: output.url, checksum: output.checksum };
|
|
299
|
+
|
|
278
300
|
console.log(
|
|
279
301
|
`${fileProgress} ā
Successfully processed file record for ${fileObj.file_path}`
|
|
280
302
|
);
|
|
@@ -304,14 +326,14 @@ export async function createFiles(filesToCreate, config, prefixUrl) {
|
|
|
304
326
|
console.error("\nš„ File creation process failed:", err.message);
|
|
305
327
|
throw err;
|
|
306
328
|
}
|
|
329
|
+
|
|
330
|
+
return fileResults;
|
|
307
331
|
}
|
|
308
332
|
|
|
309
333
|
export async function createFileMapping(
|
|
310
334
|
directory_path,
|
|
311
335
|
file_path,
|
|
312
|
-
id,
|
|
313
|
-
checksum,
|
|
314
|
-
tag
|
|
336
|
+
{ id, checksum, url, organisation, namespace, tag }
|
|
315
337
|
) {
|
|
316
338
|
const airborneDir = path.join(directory_path, ".airborne");
|
|
317
339
|
const mappingFile = path.join(airborneDir, "mappings.json");
|
|
@@ -329,12 +351,18 @@ export async function createFileMapping(
|
|
|
329
351
|
tag = "__default__";
|
|
330
352
|
}
|
|
331
353
|
|
|
332
|
-
if (!mappings[
|
|
333
|
-
mappings[
|
|
354
|
+
if (!mappings[organisation]) {
|
|
355
|
+
mappings[organisation] = {};
|
|
356
|
+
}
|
|
357
|
+
if (!mappings[organisation][namespace]) {
|
|
358
|
+
mappings[organisation][namespace] = {};
|
|
359
|
+
}
|
|
360
|
+
if (!mappings[organisation][namespace][tag]) {
|
|
361
|
+
mappings[organisation][namespace][tag] = {};
|
|
334
362
|
}
|
|
335
363
|
|
|
336
|
-
// Update or insert mapping with checksum
|
|
337
|
-
mappings[tag][file_path] = { id, checksum };
|
|
364
|
+
// Update or insert mapping with checksum and url
|
|
365
|
+
mappings[organisation][namespace][tag][file_path] = { id, checksum, url };
|
|
338
366
|
|
|
339
367
|
// Write updated mappings back
|
|
340
368
|
await fs.promises.writeFile(
|
|
@@ -348,7 +376,7 @@ export async function createFileMapping(
|
|
|
348
376
|
}
|
|
349
377
|
}
|
|
350
378
|
|
|
351
|
-
export async function
|
|
379
|
+
export async function getMappedChecksumAndURL(directory_path, file_path, { organisation, namespace, tag }) {
|
|
352
380
|
const mappingFile = path.join(directory_path, ".airborne", "mappings.json");
|
|
353
381
|
if (!tag) {
|
|
354
382
|
tag = "__default__";
|
|
@@ -357,13 +385,15 @@ export async function getMappedChecksum(directory_path, file_path, tag) {
|
|
|
357
385
|
try {
|
|
358
386
|
const data = await fs.promises.readFile(mappingFile, "utf8");
|
|
359
387
|
const mappings = JSON.parse(data);
|
|
360
|
-
|
|
388
|
+
const entry = mappings[organisation]?.[namespace]?.[tag]?.[file_path];
|
|
389
|
+
if (!entry) return null;
|
|
390
|
+
return { checksum: entry.checksum || null, url: entry.url || null };
|
|
361
391
|
} catch (err) {
|
|
362
392
|
return null;
|
|
363
393
|
}
|
|
364
394
|
}
|
|
365
395
|
|
|
366
|
-
export async function readFileMapping(directory_path, file_path, tag) {
|
|
396
|
+
export async function readFileMapping(directory_path, file_path, { organisation, namespace, tag }) {
|
|
367
397
|
const mappingFile = path.join(directory_path, ".airborne", "mappings.json");
|
|
368
398
|
|
|
369
399
|
if (!tag) {
|
|
@@ -373,7 +403,7 @@ export async function readFileMapping(directory_path, file_path, tag) {
|
|
|
373
403
|
try {
|
|
374
404
|
const data = await fs.promises.readFile(mappingFile, "utf8");
|
|
375
405
|
const mappings = JSON.parse(data);
|
|
376
|
-
return mappings[tag][file_path] || null;
|
|
406
|
+
return mappings[organisation]?.[namespace]?.[tag]?.[file_path] || null;
|
|
377
407
|
} catch (err) {
|
|
378
408
|
return null;
|
|
379
409
|
}
|
package/src/utils/package.js
CHANGED
|
@@ -17,7 +17,7 @@ export async function createPackageFromLocalRelease(
|
|
|
17
17
|
const indexMapping = await readFileMapping(
|
|
18
18
|
airborneConfig.directory_path,
|
|
19
19
|
indexFilePath,
|
|
20
|
-
airborneConfig
|
|
20
|
+
airborneConfig
|
|
21
21
|
);
|
|
22
22
|
if (!indexMapping) {
|
|
23
23
|
throw new Error(`Missing upload for index file: ${indexFilePath}`);
|
|
@@ -36,7 +36,7 @@ export async function createPackageFromLocalRelease(
|
|
|
36
36
|
const mapping = await readFileMapping(
|
|
37
37
|
airborneConfig.directory_path,
|
|
38
38
|
file_path,
|
|
39
|
-
airborneConfig
|
|
39
|
+
airborneConfig
|
|
40
40
|
);
|
|
41
41
|
if (!mapping) {
|
|
42
42
|
throw new Error(`Missing mapping for file: ${file_path}`);
|
package/src/utils/release.js
CHANGED
|
@@ -141,11 +141,13 @@ export async function createLocalReleaseConfig(
|
|
|
141
141
|
properties: {},
|
|
142
142
|
},
|
|
143
143
|
package: {
|
|
144
|
+
name: airborneConfig.namespace,
|
|
144
145
|
version: "",
|
|
145
146
|
prooerties: {},
|
|
146
147
|
index: {
|
|
147
148
|
file_path: airborneConfig[platform].index_file_path,
|
|
148
149
|
url: "",
|
|
150
|
+
checksum: "",
|
|
149
151
|
},
|
|
150
152
|
important: remotebundleContents
|
|
151
153
|
.filter(
|
|
@@ -291,11 +293,13 @@ export async function updateLocalReleaseConfig(
|
|
|
291
293
|
properties: existingReleaseConfig?.config?.properties || {},
|
|
292
294
|
},
|
|
293
295
|
package: {
|
|
296
|
+
name: airborneConfig.namespace,
|
|
294
297
|
version: existingReleaseConfig?.package?.version || "",
|
|
295
298
|
properties: existingReleaseConfig?.package?.properties || {},
|
|
296
299
|
index: {
|
|
297
300
|
file_path: airborneConfig[options.platform].index_file_path,
|
|
298
|
-
url:
|
|
301
|
+
url: "",
|
|
302
|
+
checksum: "",
|
|
299
303
|
},
|
|
300
304
|
important: remotebundleContents
|
|
301
305
|
.filter(
|
|
@@ -305,10 +309,14 @@ export async function updateLocalReleaseConfig(
|
|
|
305
309
|
.map((item) => ({
|
|
306
310
|
file_path: item.path,
|
|
307
311
|
url: "",
|
|
312
|
+
checksum: "",
|
|
308
313
|
})),
|
|
309
|
-
lazy:
|
|
314
|
+
lazy: [],
|
|
310
315
|
},
|
|
311
|
-
resources: existingReleaseConfig?.resources || []
|
|
316
|
+
resources: (existingReleaseConfig?.resources || []).filter(
|
|
317
|
+
(res) =>
|
|
318
|
+
!remotebundleContents.some((item) => item.path === res.file_path)
|
|
319
|
+
),
|
|
312
320
|
};
|
|
313
321
|
|
|
314
322
|
await writeReleaseConfig(
|