bitrise-api-cli 0.0.6 → 0.0.8

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/README.md CHANGED
@@ -1,87 +1,42 @@
1
1
  # Bitrise API CLI [![npm][npm-image]][npm-url] ![npm][npm-dl-stats]
2
2
 
3
- <div align="center">
4
- 🚀 An unofficial CLI tool to interact with Bitrise API, making artifact downloads a breeze.
5
- </div>
3
+ 🚀 An unofficial CLI tool for Bitrise API artifact downloads.
6
4
 
7
5
  ## 🎯 Features
8
6
 
9
- - Download artifacts from your latest successful builds
10
- - Simple workflow-based artifact retrieval
11
- - Easy integration with CI/CD pipelines
12
- - Supports both CLI arguments and environment variables
7
+ - Download artifacts from successful builds
8
+ - Workflow-based retrieval
9
+ - CI/CD integration
13
10
 
14
11
  ## 🚀 Quick Start
15
12
 
16
13
  ### Download Artifacts
17
14
 
18
15
  ```bash
19
- # Using npx (recommended)
20
- npx bitrise-api-cli@latest download --token <BITRISE_TOKEN> --workflow <WORKFLOW_NAME>
21
-
22
- # If running locally, you'll need to specify the app slug
23
- npx bitrise-api-cli@latest download \
24
- --token <BITRISE_TOKEN> \
25
- --workflow <WORKFLOW_NAME> \
26
- --slug <APP_SLUG>
16
+ npx bitrise-api-cli@latest download --token <BITRISE_TOKEN> --workflow <WORKFLOW_NAME> [--slug <APP_SLUG>]
27
17
  ```
28
18
 
29
19
  ## 🔐 Configuration
30
20
 
31
- ### Environment Variables
32
-
33
- | Variable | Description | Required |
34
- | -------------------------- | ---------------------------------------- |--------------|
35
- | `BITRISE_API_CLI_TOKEN` | Your Bitrise API token | Yes |
36
- | `BITRISE_API_CLI_WORKFLOW` | Workflow name to download artifacts from | Yes |
37
- | `BITRISE_APP_SLUG` | App Slug (auto-set in Bitrise CI) | only locally |
21
+ ### Environment Variables (instead of CLI flags)
38
22
 
39
- ### CLI Options
40
-
41
- ```bash
42
- Options:
43
- -t, --token <TOKEN> bitrise api token (or $BITRISE_API_CLI_TOKEN)
44
- -w, --workflow <WORKFLOW_NAME> workflow to get apk from (or $BITRISE_API_CLI_WORKFLOW)
45
- -s, --slug <APP_SLUG> bitrise app slug (or $BITRISE_APP_SLUG) see bitrise project url to get slug
46
- -a, --artifact <ARTIFACT_TYPE> bitrise artifact type "ios-ipa" or "android-apk"
47
- -d, --debug output extra debugging (default: false)
48
- -h, --help display help for command
49
- ```
23
+ | Variable | Description | Required |
24
+ | -------------------------- | ------------------------------------ | ------------ |
25
+ | `BITRISE_API_CLI_TOKEN` | Your Bitrise API token | Yes |
26
+ | `BITRISE_API_CLI_WORKFLOW` | Workflow name for artifact downloads | Yes |
27
+ | `BITRISE_APP_SLUG` | App Slug (auto-set in Bitrise CI) | Locally only |
50
28
 
51
29
  ## 💡 Examples
52
30
 
53
- ### Using Command Line Arguments
54
-
55
- ```bash
56
- # Download artifacts from a specific workflow
57
- npx bitrise-api-cli@latest download \
58
- --token abc123 \
59
- --workflow android-release \
60
- --slug a1b2c3d4e5f6
61
-
62
- # Enable debug logging
63
- npx bitrise-api-cli@latest download --debug \
64
- --token abc123 \
65
- --workflow android-release
66
- ```
67
-
68
- ### Using Environment Variables
31
+ ### Command Line
69
32
 
70
33
  ```bash
71
- # Set environment variables
72
- export BITRISE_API_CLI_TOKEN=abc123
73
- export BITRISE_API_CLI_WORKFLOW=android-release
74
- export BITRISE_APP_SLUG=a1b2c3d4e5f6
75
-
76
- # Run the command
77
- npx bitrise-api-cli@latest download
34
+ npx bitrise-api-cli@latest download --token abc123 --workflow android-release --slug a1b2c3d4e5f6
78
35
  ```
79
36
 
80
- ## 🔍 Common Use Cases
81
-
82
37
  ### CI/CD Integration
83
38
 
84
- Perfect for downloading artifacts from previous builds instead of rebuilding from source:
39
+ Integrate this CLI tool using the "Script" Step to download artifacts from previous builds, eliminating the need to rebuild from source.
85
40
 
86
41
  ```yaml
87
42
  steps:
@@ -93,33 +48,16 @@ steps:
93
48
  --token $BITRISE_API_TOKEN
94
49
  ```
95
50
 
96
- ### Local Development
97
-
98
- Download the latest artifacts to test without building:
99
-
100
- ```bash
101
- npx bitrise-api-cli@latest download \
102
- --token $BITRISE_API_TOKEN \
103
- --workflow android-release \
104
- --slug $BITRISE_APP_SLUG
105
- ```
106
-
107
51
  ## 📝 License
108
52
 
109
53
  This project is [MIT](LICENSE) licensed.
110
54
 
111
- ## 🙏 Acknowledgments
112
-
113
- - Thanks to [Bitrise](https://www.bitrise.io/) for their excellent API
114
- - Built with ❤️ for the mobile CI/CD community
115
-
116
55
  ---
117
56
 
118
57
  <div align="center">
119
58
  <p>Found this project useful? Give it a ⭐️!</p>
120
59
  </div>
121
60
 
122
-
123
61
  [npm-image]: https://img.shields.io/npm/v/bitrise-api-cli
124
62
  [npm-url]: https://www.npmjs.com/package/bitrise-api-cli
125
63
  [npm-dl-stats]: https://img.shields.io/npm/dm/bitrise-api-cli
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  app,
4
4
  buildContext
5
- } from "./chunk-SUHWPUKK.js";
5
+ } from "./chunk-WFYIERBR.js";
6
6
  import "./chunk-CF25N4TY.js";
7
7
 
8
8
  // src/cli/bin/bash-complete.ts
@@ -2,17 +2,10 @@ import {
2
2
  validArtifactTypes
3
3
  } from "./chunk-CF25N4TY.js";
4
4
 
5
- // src/cli/app.ts
6
- import { buildApplication, buildCommand, buildRouteMap } from "@stricli/core";
7
-
8
- // package.json
9
- var name = "bitrise-api-cli";
10
- var version = "0.0.6";
11
- var description = "bitrise api CLI wrapper";
12
-
13
- // src/cli/app.ts
5
+ // src/cli/commands/download/command.ts
6
+ import { buildCommand } from "@stricli/core";
14
7
  var downloadCommand = buildCommand({
15
- loader: async () => import("./impl-ESKLIOQY.js"),
8
+ loader: async () => import("./impl-PVD6QYYZ.js"),
16
9
  parameters: {
17
10
  flags: {
18
11
  artifact: {
@@ -46,6 +39,11 @@ var downloadCommand = buildCommand({
46
39
  default: process.env["BITRISE_API_CLI_WORKFLOW"],
47
40
  parse: String,
48
41
  placeholder: "WORKFLOW_NAME"
42
+ },
43
+ install: {
44
+ kind: "boolean",
45
+ brief: "Install the downloaded artifact [android only]",
46
+ default: false
49
47
  }
50
48
  },
51
49
  aliases: {
@@ -53,13 +51,24 @@ var downloadCommand = buildCommand({
53
51
  d: "debug",
54
52
  s: "slug",
55
53
  t: "token",
56
- w: "workflow"
54
+ w: "workflow",
55
+ i: "install"
57
56
  }
58
57
  },
59
58
  docs: {
60
59
  brief: "Download bitrise artifacts. Most parameters can be set via environment variables."
61
60
  }
62
61
  });
62
+
63
+ // src/cli/app.ts
64
+ import { buildApplication, buildRouteMap } from "@stricli/core";
65
+
66
+ // package.json
67
+ var name = "bitrise-api-cli";
68
+ var version = "0.0.8";
69
+ var description = "bitrise api CLI wrapper";
70
+
71
+ // src/cli/app.ts
63
72
  var root = buildRouteMap({
64
73
  routes: {
65
74
  download: downloadCommand
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  app,
4
4
  buildContext
5
- } from "./chunk-SUHWPUKK.js";
5
+ } from "./chunk-WFYIERBR.js";
6
6
  import "./chunk-CF25N4TY.js";
7
7
 
8
8
  // src/cli/bin/cli.ts
@@ -36,6 +36,55 @@ var isEnvValid = () => {
36
36
  }
37
37
  return true;
38
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
+
60
+ // src/helper/formatTime.ts
61
+ var formatTime = (timeMs) => {
62
+ if (timeMs < 1e3) return `${timeMs}ms`;
63
+ return `${(timeMs / 1e3).toFixed(1)}s`;
64
+ };
65
+
66
+ // src/helper/oraHelper.ts
67
+ var getOraTexts = (label) => ({
68
+ text: label,
69
+ failText: (error) => `${label} failed with error: ${error.message}`,
70
+ successText: (data) => {
71
+ if (data && typeof data === "object" && "duration" in data && typeof data.duration === "number") {
72
+ return `${label} [took ${formatTime(data.duration)}]`;
73
+ }
74
+ return label;
75
+ }
76
+ });
77
+
78
+ // src/device/install/run.ts
79
+ import { oraPromise } from "ora";
80
+ var installApp = async ({ file, flags }) => {
81
+ if (flags.artifact === "android-apk") {
82
+ if (!file.endsWith(".apk")) return console.log("Artifact is not an APK file");
83
+ await oraPromise(installApk(file), getOraTexts("installing APK"));
84
+ } else {
85
+ return console.log("Installing on iOS is not supported yet");
86
+ }
87
+ };
39
88
 
40
89
  // src/generated_api/runtime.ts
41
90
  var BASE_PATH = "https://api.bitrise.io/v0.1".replace(/\/+$/, "");
@@ -1436,12 +1485,20 @@ var api = {
1436
1485
  // src/helper/debugLog.ts
1437
1486
  var debugLog = (label, data) => console.log(`${label}: ${JSON.stringify(data, void 0, 2)}`);
1438
1487
 
1488
+ // src/helper/ensureMandatoryFields.ts
1489
+ var ensureMandatoryFields = (input, mandatory) => {
1490
+ for (const field of mandatory) {
1491
+ if (!input[field]) throw new Error(`Missing mandatory field: ${String(field)}`);
1492
+ }
1493
+ return input;
1494
+ };
1495
+
1439
1496
  // src/bitrise/fetchArtifact.ts
1440
1497
  var fetchArtifact = async ({ artifactSlug, buildSlug }) => {
1441
1498
  const { data } = await api.buildArtifact().artifactShow({ appSlug: ENV.appSlug, artifactSlug, buildSlug });
1442
1499
  if (!data) throw new Error("buildArtifact().artifactShow returned no data");
1443
1500
  if (ENV.debug) debugLog("artifact", data);
1444
- return data;
1501
+ return ensureMandatoryFields(data, ["expiringDownloadUrl"]);
1445
1502
  };
1446
1503
 
1447
1504
  // src/bitrise/fetchArtifactList.ts
@@ -1453,10 +1510,9 @@ var fetchArtifactList = async (buildSlug) => {
1453
1510
  var fetchArtifactByType = async (buildSlug) => {
1454
1511
  const artifactInfo = await fetchArtifactList(buildSlug);
1455
1512
  const artifactMetadata = artifactInfo.find((artifact) => artifact.artifactType === ENV.artifactType);
1456
- if (!artifactMetadata || !artifactMetadata.slug)
1457
- throw new Error(`Found no ${ENV.artifactType} in build Slug: ${buildSlug}`);
1458
1513
  if (ENV.debug) debugLog("artifactMetadata", artifactMetadata);
1459
- return artifactMetadata;
1514
+ if (!artifactMetadata) throw new Error(`Found no ${ENV.artifactType} in build Slug: ${buildSlug}`);
1515
+ return ensureMandatoryFields(artifactMetadata, ["slug", "title"]);
1460
1516
  };
1461
1517
 
1462
1518
  // src/bitrise/fetchBuilds.ts
@@ -1470,7 +1526,7 @@ var getLatestBuild = async () => {
1470
1526
  const latestBuild = builds.find((build) => build.triggeredWorkflow === ENV.workflow);
1471
1527
  if (!latestBuild) throw `Found no build with the workflow: "${ENV.workflow}"`;
1472
1528
  if (ENV.debug) debugLog("latestBuild", latestBuild);
1473
- return latestBuild;
1529
+ return ensureMandatoryFields(latestBuild, ["slug"]);
1474
1530
  };
1475
1531
 
1476
1532
  // src/helper/formatBytes.ts
@@ -1486,18 +1542,13 @@ var formatBytes = (bytes) => {
1486
1542
  };
1487
1543
 
1488
1544
  // src/downloadLatestArtifacts.ts
1489
- import { oraPromise } from "ora";
1545
+ import { oraPromise as oraPromise2 } from "ora";
1490
1546
 
1491
1547
  // src/helper/downloadFile.ts
1492
1548
  import { createWriteStream } from "node:fs";
1493
1549
  import { get } from "node:https";
1494
1550
  import { pipeline } from "node:stream/promises";
1495
1551
  import { URL } from "node:url";
1496
-
1497
- // src/helper/formatTime.ts
1498
- var formatTime = (timeMs) => `${(timeMs / 1e3).toFixed(1)}s`;
1499
-
1500
- // src/helper/downloadFile.ts
1501
1552
  var downloadFile = async (fileUrl, outputLocationPath) => {
1502
1553
  const startTime = Date.now();
1503
1554
  const url = new URL(fileUrl);
@@ -1511,39 +1562,35 @@ var downloadFile = async (fileUrl, outputLocationPath) => {
1511
1562
  }).on("error", reject);
1512
1563
  });
1513
1564
  await pipeline(response, createWriteStream(outputLocationPath));
1514
- return { duration: formatTime(Date.now() - startTime) };
1565
+ return { file: outputLocationPath, duration: Date.now() - startTime };
1515
1566
  };
1516
1567
 
1517
1568
  // src/downloadLatestArtifacts.ts
1518
1569
  var downloadLatestArtifacts = async (options) => {
1519
- saveOptions(options);
1520
- if (!isEnvValid()) return process.exit(1);
1521
- const latestBuild = await oraPromise(getLatestBuild(), {
1522
- text: "fetching latest build",
1523
- failText: (error) => `fetching latest build failed with error: ${error}`
1524
- });
1525
- if (!latestBuild.slug) throw Error("Latest build contained no Slug");
1526
- const artifactMetadata = await oraPromise(fetchArtifactByType(latestBuild.slug), {
1527
- text: "fetching artifact list",
1528
- failText: (error) => `fetching artifact list failed with error: ${error}`
1529
- });
1530
- if (!artifactMetadata.slug || !artifactMetadata.title) throw Error("Artifact was Invalid");
1531
- const artifact = await oraPromise(
1570
+ const latestBuild = await oraPromise2(getLatestBuild(), getOraTexts("fetching latest build"));
1571
+ const artifactMetadata = await oraPromise2(
1572
+ fetchArtifactByType(latestBuild.slug),
1573
+ getOraTexts("fetching artifact list")
1574
+ );
1575
+ const artifact = await oraPromise2(
1532
1576
  fetchArtifact({ artifactSlug: artifactMetadata.slug, buildSlug: latestBuild.slug }),
1533
- { text: "fetching artifact metadata" }
1577
+ getOraTexts("fetching artifact metadata")
1534
1578
  );
1535
- if (!artifact.expiringDownloadUrl) throw Error("Artifact is missing expiringDownloadUrl");
1536
- const fileSize = formatBytes(artifact.fileSizeBytes ?? 0);
1537
- await oraPromise(downloadFile(artifact.expiringDownloadUrl, artifactMetadata.title), {
1538
- text: `downloading apk file (${fileSize})`,
1539
- successText: ({ duration }) => `downloading apk file took ${duration}`
1579
+ const { file } = await oraPromise2(downloadFile(artifact.expiringDownloadUrl, artifactMetadata.title), {
1580
+ ...getOraTexts("downloading apk file"),
1581
+ text: `downloading apk file [${formatBytes(artifact.fileSizeBytes ?? 0)}]`
1540
1582
  });
1583
+ return file;
1541
1584
  };
1542
1585
 
1543
- // src/cli/impl.ts
1586
+ // src/cli/commands/download/impl.ts
1544
1587
  async function impl_default(flags) {
1545
- if (flags.debug) console.log(JSON.stringify(flags, null, 2));
1546
- return downloadLatestArtifacts(flags);
1588
+ if (!setupEnv(flags)) return process.exit(1);
1589
+ const file = await downloadLatestArtifacts(flags);
1590
+ if (flags.install) {
1591
+ await installApp({ file, flags }).catch(() => {
1592
+ });
1593
+ }
1547
1594
  }
1548
1595
  export {
1549
1596
  impl_default as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bitrise-api-cli",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "bitrise api CLI wrapper",
5
5
  "module": "index",
6
6
  "type": "module",
@@ -23,15 +23,17 @@
23
23
  "prepublishOnly": "bun i && bun run lint:CI && tsc && bun run build"
24
24
  },
25
25
  "dependencies": {
26
- "@stricli/core": "1.1.1",
27
26
  "@stricli/auto-complete": "1.1.1",
28
- "ora": "8.2.0"
27
+ "@stricli/core": "1.1.1",
28
+ "ora": "8.2.0",
29
+ "teen_process": "2.2.3"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@biomejs/biome": "1.9.4",
32
33
  "@openapitools/openapi-generator-cli": "2.16.3",
33
34
  "@types/bun": "latest",
34
- "tsup": "8.3.6",
35
+ "@types/teen_process": "^2.0.4",
36
+ "tsup": "8.4.0",
35
37
  "typescript": "5.7.3"
36
38
  }
37
39
  }