bitrise-api-cli 0.0.7 → 0.0.9-beta

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.
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  app,
4
4
  buildContext
5
- } from "./chunk-4KG3SWIX.js";
5
+ } from "./chunk-5TJLDQ3K.js";
6
6
  import "./chunk-CF25N4TY.js";
7
7
 
8
8
  // src/cli/bin/bash-complete.ts
@@ -5,7 +5,7 @@ import {
5
5
  // src/cli/commands/download/command.ts
6
6
  import { buildCommand } from "@stricli/core";
7
7
  var downloadCommand = buildCommand({
8
- loader: async () => import("./impl-5KTEXOJU.js"),
8
+ loader: async () => import("./impl-YQ6WYRXO.js"),
9
9
  parameters: {
10
10
  flags: {
11
11
  artifact: {
@@ -42,7 +42,7 @@ var downloadCommand = buildCommand({
42
42
  },
43
43
  install: {
44
44
  kind: "boolean",
45
- brief: "Install the downloaded artifact [android only]",
45
+ brief: "Install the downloaded apk/aab artifact [android only]",
46
46
  default: false
47
47
  }
48
48
  },
@@ -65,7 +65,7 @@ import { buildApplication, buildRouteMap } from "@stricli/core";
65
65
 
66
66
  // package.json
67
67
  var name = "bitrise-api-cli";
68
- var version = "0.0.7";
68
+ var version = "0.0.9-beta";
69
69
  var description = "bitrise api CLI wrapper";
70
70
 
71
71
  // src/cli/app.ts
@@ -85,15 +85,9 @@ var app = buildApplication(root, {
85
85
  });
86
86
 
87
87
  // src/cli/context.ts
88
- import fs from "node:fs";
89
- import os from "node:os";
90
- import path from "node:path";
91
88
  function buildContext(process2) {
92
89
  return {
93
- process: process2,
94
- os,
95
- fs,
96
- path
90
+ process: process2
97
91
  };
98
92
  }
99
93
 
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  app,
4
4
  buildContext
5
- } from "./chunk-4KG3SWIX.js";
5
+ } from "./chunk-5TJLDQ3K.js";
6
6
  import "./chunk-CF25N4TY.js";
7
7
 
8
8
  // src/cli/bin/cli.ts
@@ -2,31 +2,6 @@ import {
2
2
  validArtifactTypes
3
3
  } from "./chunk-CF25N4TY.js";
4
4
 
5
- // src/device/install/android.ts
6
- import { exec } from "teen_process";
7
- var adbPath = `${process.env.ANDROID_HOME}/platform-tools/adb`;
8
- var installApk = async (apkPath) => {
9
- const { stdout, stderr, code } = await exec(adbPath, ["install", "-r", "-d", apkPath]);
10
- if (code !== 0) {
11
- console.log(stderr);
12
- throw new Error(`Failed to install apk: ${stderr}`);
13
- }
14
- };
15
-
16
- // src/device/install/run.ts
17
- import { oraPromise } from "ora";
18
- var installApp = async ({ file, flags }) => {
19
- if (flags.artifact === "android-apk") {
20
- if (!file.endsWith(".apk")) return console.log("Artifact is not an APK file");
21
- await oraPromise(installApk(file), {
22
- text: "installing APK",
23
- failText: (error) => `installing APK failed with error: ${error}`
24
- });
25
- } else {
26
- return console.log("Installing on iOS is not supported yet");
27
- }
28
- };
29
-
30
5
  // src/bitrise/env.ts
31
6
  var ENV = {
32
7
  debug: false,
@@ -61,6 +36,122 @@ var isEnvValid = () => {
61
36
  }
62
37
  return true;
63
38
  };
39
+ var setupEnv = (flags) => {
40
+ if (flags.debug) console.log(JSON.stringify(flags, null, 2));
41
+ saveOptions(flags);
42
+ return isEnvValid();
43
+ };
44
+
45
+ // src/device/install/android.ts
46
+ import { exec } from "teen_process";
47
+ var adbPath = `${process.env.ANDROID_HOME}/platform-tools/adb`;
48
+ var installApk = async (apkPath) => {
49
+ const startTime = Date.now();
50
+ try {
51
+ const { stdout, stderr, code } = await exec(adbPath, ["install", "-r", "-d", apkPath]);
52
+ if (code !== 0) throw new Error(`Failed to install apk error code: ${code}`);
53
+ return { duration: Date.now() - startTime };
54
+ } catch (e) {
55
+ if (e instanceof Error && "stderr" in e) throw new Error(`${e.stderr}`);
56
+ throw new Error("unknown Error");
57
+ }
58
+ };
59
+ var installSplitApk = async (apkFolder) => {
60
+ const startTime = Date.now();
61
+ try {
62
+ const { stdout, stderr, code } = await exec(adbPath, ["install-multiple", "-r", "-d", `${apkFolder}/*`], {
63
+ shell: true
64
+ });
65
+ if (code !== 0) throw new Error(`Failed to install split apk error code: ${code}`);
66
+ return { duration: Date.now() - startTime };
67
+ } catch (e) {
68
+ if (e instanceof Error && "stderr" in e) throw new Error(`${e.stderr}`);
69
+ throw new Error("unknown Error");
70
+ }
71
+ };
72
+
73
+ // src/device/install/convertAabToApk.ts
74
+ import fs2 from "node:fs/promises";
75
+ import path2 from "node:path";
76
+
77
+ // src/helper/tempDir.ts
78
+ import fs from "node:fs/promises";
79
+ import { tmpdir } from "node:os";
80
+ import path from "node:path";
81
+ var createTempDir = async (prefix) => {
82
+ const tmpDir = path.join(tmpdir(), `${prefix}-${Date.now()}`);
83
+ await fs.mkdir(tmpDir, { recursive: true });
84
+ return tmpDir;
85
+ };
86
+
87
+ // src/device/install/convertAabToApk.ts
88
+ import { exec as exec2 } from "teen_process";
89
+ var convertAabToApk = async (aabPath) => {
90
+ const startTime = Date.now();
91
+ try {
92
+ const tempDir = await createTempDir("bitrise-api-cli");
93
+ const fileName = path2.basename(aabPath, ".aab");
94
+ const outPath = path2.join(tempDir, `${fileName}.apks`);
95
+ const zipPath = path2.join(tempDir, `${fileName}.zip`);
96
+ const { code } = await exec2("bundletool", [
97
+ "build-apks",
98
+ "--connected-device",
99
+ `--bundle=${fileName}.aab`,
100
+ `--output=${outPath}`
101
+ ]);
102
+ if (code !== 0) throw new Error(`Failed to convert aab to apk: ${code}`);
103
+ await fs2.rename(outPath, zipPath);
104
+ const { code: code2 } = await exec2("unzip", ["-o", zipPath, "-d", tempDir]);
105
+ if (code2 !== 0) throw new Error(`Failed to unzip ${code2}`);
106
+ return { apkFolder: path2.join(tempDir, "./splits"), duration: Date.now() - startTime };
107
+ } catch (e) {
108
+ if (e instanceof Error && "stderr" in e) throw new Error(`${e.stderr}`);
109
+ throw new Error("unknown Error");
110
+ }
111
+ };
112
+
113
+ // src/helper/formatTime.ts
114
+ var formatTime = (timeMs) => {
115
+ if (timeMs < 1e3) return `${timeMs}ms`;
116
+ return `${(timeMs / 1e3).toFixed(1)}s`;
117
+ };
118
+
119
+ // src/helper/typeHelper.ts
120
+ var isFetchError = (e) => {
121
+ if (typeof e !== "object" || !e) return false;
122
+ return "response" in e && typeof e.response === "object" && !!e.response && "status" in e.response && "statusText" in e.response;
123
+ };
124
+
125
+ // src/helper/oraHelper.ts
126
+ var getOraTexts = (label) => ({
127
+ text: label,
128
+ failText: (error) => {
129
+ if (isFetchError(error))
130
+ return `${label} failed with HTTP Error ${error.response.status} ${error.response.statusText}`;
131
+ return `${label} failed with error: ${error.message}`;
132
+ },
133
+ successText: (data) => {
134
+ if (data && typeof data === "object" && "duration" in data && typeof data.duration === "number") {
135
+ return `${label} [took ${formatTime(data.duration)}]`;
136
+ }
137
+ return label;
138
+ }
139
+ });
140
+
141
+ // src/device/install/run.ts
142
+ import { oraPromise } from "ora";
143
+ var installApp = async ({ file, flags }) => {
144
+ if (flags.artifact === "android-apk" && file.endsWith(".aab")) {
145
+ const { apkFolder } = await oraPromise(convertAabToApk(file), getOraTexts("Convert AAB to Split APK"));
146
+ await oraPromise(installSplitApk(apkFolder), getOraTexts("installing Split APK"));
147
+ } else if (flags.artifact === "android-apk" && file.endsWith(".apk")) {
148
+ await oraPromise(installApk(file), getOraTexts("installing APK"));
149
+ } else if (flags.artifact === "android-apk") {
150
+ throw Error("Artifact is not an APK or AAB file");
151
+ } else {
152
+ return console.log("Installing on iOS is not supported yet");
153
+ }
154
+ };
64
155
 
65
156
  // src/generated_api/runtime.ts
66
157
  var BASE_PATH = "https://api.bitrise.io/v0.1".replace(/\/+$/, "");
@@ -737,6 +828,7 @@ function V0BuildTriggerParamsBuildParamsToJSONTyped(value, ignoreDiscriminator =
737
828
  "environments": value["environments"] == null ? void 0 : value["environments"].map(V0BuildParamsEnvironmentToJSON),
738
829
  "head_repository_url": value["headRepositoryUrl"],
739
830
  "pipeline_id": value["pipelineId"],
831
+ "priority": value["priority"],
740
832
  "pull_request_author": value["pullRequestAuthor"],
741
833
  "pull_request_head_branch": value["pullRequestHeadBranch"],
742
834
  "pull_request_id": value["pullRequestId"],
@@ -1051,6 +1143,12 @@ var BuildsApi = class extends BaseAPI {
1051
1143
  'Required parameter "before" was null or undefined when calling archivedBuildsList().'
1052
1144
  );
1053
1145
  }
1146
+ if (requestParameters["limit"] == null) {
1147
+ throw new RequiredError(
1148
+ "limit",
1149
+ 'Required parameter "limit" was null or undefined when calling archivedBuildsList().'
1150
+ );
1151
+ }
1054
1152
  const queryParameters = {};
1055
1153
  if (requestParameters["after"] != null) {
1056
1154
  queryParameters["after"] = requestParameters["after"];
@@ -1058,6 +1156,9 @@ var BuildsApi = class extends BaseAPI {
1058
1156
  if (requestParameters["before"] != null) {
1059
1157
  queryParameters["before"] = requestParameters["before"];
1060
1158
  }
1159
+ if (requestParameters["limit"] != null) {
1160
+ queryParameters["limit"] = requestParameters["limit"];
1161
+ }
1061
1162
  const headerParameters = {};
1062
1163
  if (this.configuration && this.configuration.apiKey) {
1063
1164
  headerParameters["Bitrise-Addon-Auth-Token"] = await this.configuration.apiKey("Bitrise-Addon-Auth-Token");
@@ -1461,12 +1562,20 @@ var api = {
1461
1562
  // src/helper/debugLog.ts
1462
1563
  var debugLog = (label, data) => console.log(`${label}: ${JSON.stringify(data, void 0, 2)}`);
1463
1564
 
1565
+ // src/helper/ensureMandatoryFields.ts
1566
+ var ensureMandatoryFields = (input, mandatory) => {
1567
+ for (const field of mandatory) {
1568
+ if (!input[field]) throw new Error(`Missing mandatory field: ${String(field)}`);
1569
+ }
1570
+ return input;
1571
+ };
1572
+
1464
1573
  // src/bitrise/fetchArtifact.ts
1465
1574
  var fetchArtifact = async ({ artifactSlug, buildSlug }) => {
1466
1575
  const { data } = await api.buildArtifact().artifactShow({ appSlug: ENV.appSlug, artifactSlug, buildSlug });
1467
1576
  if (!data) throw new Error("buildArtifact().artifactShow returned no data");
1468
1577
  if (ENV.debug) debugLog("artifact", data);
1469
- return data;
1578
+ return ensureMandatoryFields(data, ["expiringDownloadUrl"]);
1470
1579
  };
1471
1580
 
1472
1581
  // src/bitrise/fetchArtifactList.ts
@@ -1478,10 +1587,9 @@ var fetchArtifactList = async (buildSlug) => {
1478
1587
  var fetchArtifactByType = async (buildSlug) => {
1479
1588
  const artifactInfo = await fetchArtifactList(buildSlug);
1480
1589
  const artifactMetadata = artifactInfo.find((artifact) => artifact.artifactType === ENV.artifactType);
1481
- if (!artifactMetadata || !artifactMetadata.slug)
1482
- throw new Error(`Found no ${ENV.artifactType} in build Slug: ${buildSlug}`);
1483
1590
  if (ENV.debug) debugLog("artifactMetadata", artifactMetadata);
1484
- return artifactMetadata;
1591
+ if (!artifactMetadata) throw new Error(`Found no ${ENV.artifactType} in build Slug: ${buildSlug}`);
1592
+ return ensureMandatoryFields(artifactMetadata, ["slug", "title"]);
1485
1593
  };
1486
1594
 
1487
1595
  // src/bitrise/fetchBuilds.ts
@@ -1495,7 +1603,7 @@ var getLatestBuild = async () => {
1495
1603
  const latestBuild = builds.find((build) => build.triggeredWorkflow === ENV.workflow);
1496
1604
  if (!latestBuild) throw `Found no build with the workflow: "${ENV.workflow}"`;
1497
1605
  if (ENV.debug) debugLog("latestBuild", latestBuild);
1498
- return latestBuild;
1606
+ return ensureMandatoryFields(latestBuild, ["slug"]);
1499
1607
  };
1500
1608
 
1501
1609
  // src/helper/formatBytes.ts
@@ -1518,11 +1626,6 @@ import { createWriteStream } from "node:fs";
1518
1626
  import { get } from "node:https";
1519
1627
  import { pipeline } from "node:stream/promises";
1520
1628
  import { URL } from "node:url";
1521
-
1522
- // src/helper/formatTime.ts
1523
- var formatTime = (timeMs) => `${(timeMs / 1e3).toFixed(1)}s`;
1524
-
1525
- // src/helper/downloadFile.ts
1526
1629
  var downloadFile = async (fileUrl, outputLocationPath) => {
1527
1630
  const startTime = Date.now();
1528
1631
  const url = new URL(fileUrl);
@@ -1536,42 +1639,34 @@ var downloadFile = async (fileUrl, outputLocationPath) => {
1536
1639
  }).on("error", reject);
1537
1640
  });
1538
1641
  await pipeline(response, createWriteStream(outputLocationPath));
1539
- return { file: outputLocationPath, duration: formatTime(Date.now() - startTime) };
1642
+ return { file: outputLocationPath, duration: Date.now() - startTime };
1540
1643
  };
1541
1644
 
1542
1645
  // src/downloadLatestArtifacts.ts
1543
1646
  var downloadLatestArtifacts = async (options) => {
1544
- saveOptions(options);
1545
- if (!isEnvValid()) return process.exit(1);
1546
- const latestBuild = await oraPromise2(getLatestBuild(), {
1547
- text: "fetching latest build",
1548
- failText: (error) => `fetching latest build failed with error: ${error}`
1549
- });
1550
- if (!latestBuild.slug) throw Error("Latest build contained no Slug");
1551
- const artifactMetadata = await oraPromise2(fetchArtifactByType(latestBuild.slug), {
1552
- text: "fetching artifact list",
1553
- failText: (error) => `fetching artifact list failed with error: ${error}`
1554
- });
1555
- if (!artifactMetadata.slug || !artifactMetadata.title) throw Error("Artifact was Invalid");
1647
+ const latestBuild = await oraPromise2(getLatestBuild(), getOraTexts("fetching latest build"));
1648
+ const artifactMetadata = await oraPromise2(
1649
+ fetchArtifactByType(latestBuild.slug),
1650
+ getOraTexts("fetching artifact list")
1651
+ );
1556
1652
  const artifact = await oraPromise2(
1557
1653
  fetchArtifact({ artifactSlug: artifactMetadata.slug, buildSlug: latestBuild.slug }),
1558
- { text: "fetching artifact metadata" }
1654
+ getOraTexts("fetching artifact metadata")
1559
1655
  );
1560
- if (!artifact.expiringDownloadUrl) throw Error("Artifact is missing expiringDownloadUrl");
1561
- const fileSize = formatBytes(artifact.fileSizeBytes ?? 0);
1562
1656
  const { file } = await oraPromise2(downloadFile(artifact.expiringDownloadUrl, artifactMetadata.title), {
1563
- text: `downloading apk file (${fileSize})`,
1564
- successText: ({ duration }) => `downloading apk file took ${duration}`
1657
+ ...getOraTexts("downloading apk file"),
1658
+ text: `downloading apk file [${formatBytes(artifact.fileSizeBytes ?? 0)}]`
1565
1659
  });
1566
1660
  return file;
1567
1661
  };
1568
1662
 
1569
1663
  // src/cli/commands/download/impl.ts
1570
1664
  async function impl_default(flags) {
1571
- if (flags.debug) console.log(JSON.stringify(flags, null, 2));
1665
+ if (!setupEnv(flags)) return process.exit(1);
1572
1666
  const file = await downloadLatestArtifacts(flags);
1573
1667
  if (flags.install) {
1574
- await installApp({ file, flags });
1668
+ await installApp({ file, flags }).catch(() => {
1669
+ });
1575
1670
  }
1576
1671
  }
1577
1672
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitrise-api-cli",
3
- "version": "0.0.7",
3
+ "version": "0.0.9-beta",
4
4
  "description": "bitrise api CLI wrapper",
5
5
  "module": "index",
6
6
  "type": "module",
@@ -23,17 +23,16 @@
23
23
  "prepublishOnly": "bun i && bun run lint:CI && tsc && bun run build"
24
24
  },
25
25
  "dependencies": {
26
- "@stricli/auto-complete": "1.1.1",
27
26
  "@stricli/core": "1.1.1",
28
27
  "ora": "8.2.0",
29
- "teen_process": "2.2.3"
28
+ "teen_process": "2.3.1"
30
29
  },
31
30
  "devDependencies": {
32
31
  "@biomejs/biome": "1.9.4",
33
- "@openapitools/openapi-generator-cli": "2.16.3",
32
+ "@openapitools/openapi-generator-cli": "2.18.4",
34
33
  "@types/bun": "latest",
35
34
  "@types/teen_process": "^2.0.4",
36
35
  "tsup": "8.4.0",
37
- "typescript": "5.7.3"
36
+ "typescript": "5.8.2"
38
37
  }
39
38
  }