bitrise-api-cli 0.0.3 → 0.0.6
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 +15 -9
- package/dist/bash-complete.js +21 -0
- package/dist/chunk-CF25N4TY.js +6 -0
- package/dist/chunk-SUHWPUKK.js +94 -0
- package/dist/cli.js +10 -0
- package/dist/{bin.js → impl-ESKLIOQY.js} +71 -55
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Bitrise API CLI [![npm
|
|
1
|
+
# Bitrise API CLI [![npm][npm-image]][npm-url] ![npm][npm-dl-stats]
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
🚀 An unofficial CLI tool to interact with Bitrise API, making artifact downloads a breeze.
|
|
@@ -23,7 +23,7 @@ npx bitrise-api-cli@latest download --token <BITRISE_TOKEN> --workflow <WORKFLOW
|
|
|
23
23
|
npx bitrise-api-cli@latest download \
|
|
24
24
|
--token <BITRISE_TOKEN> \
|
|
25
25
|
--workflow <WORKFLOW_NAME> \
|
|
26
|
-
--
|
|
26
|
+
--slug <APP_SLUG>
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
## 🔐 Configuration
|
|
@@ -40,11 +40,12 @@ npx bitrise-api-cli@latest download \
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
Options:
|
|
43
|
-
-t, --token <TOKEN>
|
|
44
|
-
-w, --workflow <
|
|
45
|
-
-s, --
|
|
46
|
-
-
|
|
47
|
-
-
|
|
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
|
|
48
49
|
```
|
|
49
50
|
|
|
50
51
|
## 💡 Examples
|
|
@@ -56,7 +57,7 @@ Options:
|
|
|
56
57
|
npx bitrise-api-cli@latest download \
|
|
57
58
|
--token abc123 \
|
|
58
59
|
--workflow android-release \
|
|
59
|
-
--
|
|
60
|
+
--slug a1b2c3d4e5f6
|
|
60
61
|
|
|
61
62
|
# Enable debug logging
|
|
62
63
|
npx bitrise-api-cli@latest download --debug \
|
|
@@ -100,7 +101,7 @@ Download the latest artifacts to test without building:
|
|
|
100
101
|
npx bitrise-api-cli@latest download \
|
|
101
102
|
--token $BITRISE_API_TOKEN \
|
|
102
103
|
--workflow android-release \
|
|
103
|
-
--
|
|
104
|
+
--slug $BITRISE_APP_SLUG
|
|
104
105
|
```
|
|
105
106
|
|
|
106
107
|
## 📝 License
|
|
@@ -117,3 +118,8 @@ This project is [MIT](LICENSE) licensed.
|
|
|
117
118
|
<div align="center">
|
|
118
119
|
<p>Found this project useful? Give it a ⭐️!</p>
|
|
119
120
|
</div>
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
[npm-image]: https://img.shields.io/npm/v/bitrise-api-cli
|
|
124
|
+
[npm-url]: https://www.npmjs.com/package/bitrise-api-cli
|
|
125
|
+
[npm-dl-stats]: https://img.shields.io/npm/dm/bitrise-api-cli
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
app,
|
|
4
|
+
buildContext
|
|
5
|
+
} from "./chunk-SUHWPUKK.js";
|
|
6
|
+
import "./chunk-CF25N4TY.js";
|
|
7
|
+
|
|
8
|
+
// src/cli/bin/bash-complete.ts
|
|
9
|
+
import { proposeCompletions } from "@stricli/core";
|
|
10
|
+
var inputs = process.argv.slice(3);
|
|
11
|
+
if (process.env["COMP_LINE"]?.endsWith(" ")) {
|
|
12
|
+
inputs.push("");
|
|
13
|
+
}
|
|
14
|
+
await proposeCompletions(app, inputs, buildContext(process));
|
|
15
|
+
try {
|
|
16
|
+
for (const { completion } of await proposeCompletions(app, inputs, buildContext(process))) {
|
|
17
|
+
process.stdout.write(`${completion}
|
|
18
|
+
`);
|
|
19
|
+
}
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
validArtifactTypes
|
|
3
|
+
} from "./chunk-CF25N4TY.js";
|
|
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
|
|
14
|
+
var downloadCommand = buildCommand({
|
|
15
|
+
loader: async () => import("./impl-ESKLIOQY.js"),
|
|
16
|
+
parameters: {
|
|
17
|
+
flags: {
|
|
18
|
+
artifact: {
|
|
19
|
+
kind: "enum",
|
|
20
|
+
brief: 'bitrise artifact type "ios-ipa" or "android-apk"',
|
|
21
|
+
default: "android-apk",
|
|
22
|
+
values: validArtifactTypes
|
|
23
|
+
},
|
|
24
|
+
debug: {
|
|
25
|
+
kind: "boolean",
|
|
26
|
+
brief: "Number of times to say hello",
|
|
27
|
+
default: false
|
|
28
|
+
},
|
|
29
|
+
slug: {
|
|
30
|
+
kind: "parsed",
|
|
31
|
+
brief: "bitrise app slug (or $BITRISE_APP_SLUG) see bitrise project url to get slug",
|
|
32
|
+
default: process.env["BITRISE_APP_SLUG"],
|
|
33
|
+
parse: String,
|
|
34
|
+
placeholder: "APP_SLUG"
|
|
35
|
+
},
|
|
36
|
+
token: {
|
|
37
|
+
kind: "parsed",
|
|
38
|
+
brief: "bitrise api token (or $BITRISE_API_CLI_TOKEN)",
|
|
39
|
+
default: process.env["BITRISE_API_CLI_TOKEN"],
|
|
40
|
+
parse: String,
|
|
41
|
+
placeholder: "API_TOKEN"
|
|
42
|
+
},
|
|
43
|
+
workflow: {
|
|
44
|
+
kind: "parsed",
|
|
45
|
+
brief: "workflow to get apk from (or $BITRISE_API_CLI_WORKFLOW)",
|
|
46
|
+
default: process.env["BITRISE_API_CLI_WORKFLOW"],
|
|
47
|
+
parse: String,
|
|
48
|
+
placeholder: "WORKFLOW_NAME"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
aliases: {
|
|
52
|
+
a: "artifact",
|
|
53
|
+
d: "debug",
|
|
54
|
+
s: "slug",
|
|
55
|
+
t: "token",
|
|
56
|
+
w: "workflow"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
docs: {
|
|
60
|
+
brief: "Download bitrise artifacts. Most parameters can be set via environment variables."
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
var root = buildRouteMap({
|
|
64
|
+
routes: {
|
|
65
|
+
download: downloadCommand
|
|
66
|
+
},
|
|
67
|
+
docs: {
|
|
68
|
+
brief: description
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
var app = buildApplication(root, {
|
|
72
|
+
name,
|
|
73
|
+
versionInfo: {
|
|
74
|
+
currentVersion: version
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// src/cli/context.ts
|
|
79
|
+
import fs from "node:fs";
|
|
80
|
+
import os from "node:os";
|
|
81
|
+
import path from "node:path";
|
|
82
|
+
function buildContext(process2) {
|
|
83
|
+
return {
|
|
84
|
+
process: process2,
|
|
85
|
+
os,
|
|
86
|
+
fs,
|
|
87
|
+
path
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export {
|
|
92
|
+
app,
|
|
93
|
+
buildContext
|
|
94
|
+
};
|
package/dist/cli.js
ADDED
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { Command } from "commander";
|
|
1
|
+
import {
|
|
2
|
+
validArtifactTypes
|
|
3
|
+
} from "./chunk-CF25N4TY.js";
|
|
5
4
|
|
|
6
5
|
// src/bitrise/env.ts
|
|
7
6
|
var ENV = {
|
|
7
|
+
debug: false,
|
|
8
8
|
appSlug: "",
|
|
9
9
|
token: "",
|
|
10
|
-
workflow: ""
|
|
10
|
+
workflow: "",
|
|
11
|
+
artifactType: "android-apk"
|
|
11
12
|
};
|
|
12
13
|
var saveOptions = (options) => {
|
|
13
|
-
ENV.
|
|
14
|
-
ENV.
|
|
15
|
-
ENV.
|
|
14
|
+
ENV.debug = options.debug;
|
|
15
|
+
ENV.appSlug = options.slug;
|
|
16
|
+
ENV.token = options.token;
|
|
17
|
+
ENV.workflow = options.workflow;
|
|
18
|
+
ENV.artifactType = options.artifact;
|
|
16
19
|
};
|
|
17
20
|
var isEnvValid = () => {
|
|
18
21
|
if (ENV.appSlug.length < 1) {
|
|
@@ -27,6 +30,10 @@ var isEnvValid = () => {
|
|
|
27
30
|
console.log("No workflow provided! (see --help for more information)");
|
|
28
31
|
return false;
|
|
29
32
|
}
|
|
33
|
+
if (!validArtifactTypes.includes(ENV.artifactType)) {
|
|
34
|
+
console.log(`Invalid artifact type "${ENV.artifactType}"! (see --help for more information)`);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
30
37
|
return true;
|
|
31
38
|
};
|
|
32
39
|
|
|
@@ -1426,58 +1433,73 @@ var api = {
|
|
|
1426
1433
|
builds: () => new BuildsApi(getApiConfig())
|
|
1427
1434
|
};
|
|
1428
1435
|
|
|
1436
|
+
// src/helper/debugLog.ts
|
|
1437
|
+
var debugLog = (label, data) => console.log(`${label}: ${JSON.stringify(data, void 0, 2)}`);
|
|
1438
|
+
|
|
1429
1439
|
// src/bitrise/fetchArtifact.ts
|
|
1430
1440
|
var fetchArtifact = async ({ artifactSlug, buildSlug }) => {
|
|
1431
1441
|
const { data } = await api.buildArtifact().artifactShow({ appSlug: ENV.appSlug, artifactSlug, buildSlug });
|
|
1432
1442
|
if (!data) throw new Error("buildArtifact().artifactShow returned no data");
|
|
1443
|
+
if (ENV.debug) debugLog("artifact", data);
|
|
1433
1444
|
return data;
|
|
1434
1445
|
};
|
|
1435
1446
|
|
|
1436
|
-
// src/helper/formatBytes.ts
|
|
1437
|
-
var decimals = 0;
|
|
1438
|
-
var formatBytes = (bytes) => {
|
|
1439
|
-
if (bytes === 0) return "0 Bytes";
|
|
1440
|
-
const k = 1024;
|
|
1441
|
-
const dm = decimals || 2;
|
|
1442
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
1443
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1444
|
-
const formattedSize = Number.parseFloat((bytes / k ** i).toFixed(dm));
|
|
1445
|
-
return `${formattedSize} ${sizes[i]}`;
|
|
1446
|
-
};
|
|
1447
|
-
|
|
1448
|
-
// src/downloadLatestArtifacts.ts
|
|
1449
|
-
import { oraPromise } from "ora";
|
|
1450
|
-
|
|
1451
1447
|
// src/bitrise/fetchArtifactList.ts
|
|
1452
1448
|
var fetchArtifactList = async (buildSlug) => {
|
|
1453
1449
|
const { data } = await api.buildArtifact().artifactList({ appSlug: ENV.appSlug, buildSlug });
|
|
1454
1450
|
if (!data) throw new Error("buildArtifact().artifactList returned no data");
|
|
1455
1451
|
return data;
|
|
1456
1452
|
};
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1453
|
+
var fetchArtifactByType = async (buildSlug) => {
|
|
1454
|
+
const artifactInfo = await fetchArtifactList(buildSlug);
|
|
1455
|
+
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
|
+
if (ENV.debug) debugLog("artifactMetadata", artifactMetadata);
|
|
1459
|
+
return artifactMetadata;
|
|
1460
|
+
};
|
|
1460
1461
|
|
|
1461
1462
|
// src/bitrise/fetchBuilds.ts
|
|
1462
1463
|
var getAllBuilds = async () => {
|
|
1463
|
-
const { data } = await api.builds().buildList({ appSlug: ENV.appSlug });
|
|
1464
|
+
const { data } = await api.builds().buildList({ appSlug: ENV.appSlug, status: 1 });
|
|
1464
1465
|
if (!data) throw Error("no build data");
|
|
1465
1466
|
return data;
|
|
1466
1467
|
};
|
|
1467
|
-
var getLatestBuild = async (
|
|
1468
|
+
var getLatestBuild = async () => {
|
|
1468
1469
|
const builds = await getAllBuilds();
|
|
1469
1470
|
const latestBuild = builds.find((build) => build.triggeredWorkflow === ENV.workflow);
|
|
1470
1471
|
if (!latestBuild) throw `Found no build with the workflow: "${ENV.workflow}"`;
|
|
1471
|
-
if (
|
|
1472
|
+
if (ENV.debug) debugLog("latestBuild", latestBuild);
|
|
1472
1473
|
return latestBuild;
|
|
1473
1474
|
};
|
|
1474
1475
|
|
|
1476
|
+
// src/helper/formatBytes.ts
|
|
1477
|
+
var decimals = 0;
|
|
1478
|
+
var formatBytes = (bytes) => {
|
|
1479
|
+
if (bytes === 0) return "0 Bytes";
|
|
1480
|
+
const k = 1024;
|
|
1481
|
+
const dm = decimals || 2;
|
|
1482
|
+
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
1483
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1484
|
+
const formattedSize = Number.parseFloat((bytes / k ** i).toFixed(dm));
|
|
1485
|
+
return `${formattedSize} ${sizes[i]}`;
|
|
1486
|
+
};
|
|
1487
|
+
|
|
1488
|
+
// src/downloadLatestArtifacts.ts
|
|
1489
|
+
import { oraPromise } from "ora";
|
|
1490
|
+
|
|
1475
1491
|
// src/helper/downloadFile.ts
|
|
1476
1492
|
import { createWriteStream } from "node:fs";
|
|
1477
1493
|
import { get } from "node:https";
|
|
1478
1494
|
import { pipeline } from "node:stream/promises";
|
|
1479
1495
|
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
|
|
1480
1501
|
var downloadFile = async (fileUrl, outputLocationPath) => {
|
|
1502
|
+
const startTime = Date.now();
|
|
1481
1503
|
const url = new URL(fileUrl);
|
|
1482
1504
|
const response = await new Promise((resolve, reject) => {
|
|
1483
1505
|
get(url, (res) => {
|
|
@@ -1489,46 +1511,40 @@ var downloadFile = async (fileUrl, outputLocationPath) => {
|
|
|
1489
1511
|
}).on("error", reject);
|
|
1490
1512
|
});
|
|
1491
1513
|
await pipeline(response, createWriteStream(outputLocationPath));
|
|
1514
|
+
return { duration: formatTime(Date.now() - startTime) };
|
|
1492
1515
|
};
|
|
1493
1516
|
|
|
1494
1517
|
// src/downloadLatestArtifacts.ts
|
|
1495
|
-
var targetArtifactType = "android-apk";
|
|
1496
1518
|
var downloadLatestArtifacts = async (options) => {
|
|
1497
1519
|
saveOptions(options);
|
|
1498
1520
|
if (!isEnvValid()) return process.exit(1);
|
|
1499
|
-
const latestBuild = await oraPromise(getLatestBuild(
|
|
1521
|
+
const latestBuild = await oraPromise(getLatestBuild(), {
|
|
1500
1522
|
text: "fetching latest build",
|
|
1501
1523
|
failText: (error) => `fetching latest build failed with error: ${error}`
|
|
1502
1524
|
});
|
|
1503
|
-
if (!latestBuild.slug)
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
if (!artifactMetadata || !artifactMetadata.slug)
|
|
1510
|
-
throw new Error(`Found no apk in build #${latestBuild.buildNumber}`);
|
|
1511
|
-
if (options.debug) debugLog("artifactMetadata", artifactMetadata);
|
|
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");
|
|
1512
1531
|
const artifact = await oraPromise(
|
|
1513
|
-
fetchArtifact({
|
|
1514
|
-
artifactSlug: artifactMetadata.slug,
|
|
1515
|
-
buildSlug: latestBuild.slug
|
|
1516
|
-
}),
|
|
1532
|
+
fetchArtifact({ artifactSlug: artifactMetadata.slug, buildSlug: latestBuild.slug }),
|
|
1517
1533
|
{ text: "fetching artifact metadata" }
|
|
1518
1534
|
);
|
|
1519
|
-
if (
|
|
1520
|
-
if (!artifact || !artifact.expiringDownloadUrl || !artifactMetadata.title) {
|
|
1521
|
-
console.log("Artifact is missing data");
|
|
1522
|
-
return process.exit(1);
|
|
1523
|
-
}
|
|
1535
|
+
if (!artifact.expiringDownloadUrl) throw Error("Artifact is missing expiringDownloadUrl");
|
|
1524
1536
|
const fileSize = formatBytes(artifact.fileSizeBytes ?? 0);
|
|
1525
1537
|
await oraPromise(downloadFile(artifact.expiringDownloadUrl, artifactMetadata.title), {
|
|
1526
|
-
text: `downloading apk file (${fileSize})
|
|
1538
|
+
text: `downloading apk file (${fileSize})`,
|
|
1539
|
+
successText: ({ duration }) => `downloading apk file took ${duration}`
|
|
1527
1540
|
});
|
|
1528
1541
|
};
|
|
1529
1542
|
|
|
1530
|
-
// src/
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1543
|
+
// src/cli/impl.ts
|
|
1544
|
+
async function impl_default(flags) {
|
|
1545
|
+
if (flags.debug) console.log(JSON.stringify(flags, null, 2));
|
|
1546
|
+
return downloadLatestArtifacts(flags);
|
|
1547
|
+
}
|
|
1548
|
+
export {
|
|
1549
|
+
impl_default as default
|
|
1550
|
+
};
|
package/package.json
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bitrise-api-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "bitrise api CLI wrapper",
|
|
5
5
|
"module": "index",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"bitrise-api-cli": "./dist/
|
|
8
|
+
"bitrise-api-cli": "./dist/cli.js",
|
|
9
|
+
"__bitrise-api-cli_bash_complete": "dist/bash-complete.js"
|
|
9
10
|
},
|
|
10
|
-
"keywords": ["bitrise", "bitriseio"],
|
|
11
|
+
"keywords": ["bitrise", "bitriseio", "apk", "downloader"],
|
|
11
12
|
"license": "MIT",
|
|
12
|
-
"main": "dist/
|
|
13
|
+
"main": "dist/cli.js",
|
|
13
14
|
"files": ["dist"],
|
|
14
15
|
"scripts": {
|
|
15
16
|
"build": "tsup",
|
|
16
|
-
"build:dev": "tsup --watch",
|
|
17
|
+
"build:dev": "tsup --watch --clean false",
|
|
17
18
|
"lint": "bunx biome check --fix",
|
|
18
19
|
"lint:CI": "bunx biome check",
|
|
19
20
|
"typecheck": "tsc",
|
|
@@ -22,14 +23,15 @@
|
|
|
22
23
|
"prepublishOnly": "bun i && bun run lint:CI && tsc && bun run build"
|
|
23
24
|
},
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"
|
|
26
|
+
"@stricli/core": "1.1.1",
|
|
27
|
+
"@stricli/auto-complete": "1.1.1",
|
|
26
28
|
"ora": "8.2.0"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"@biomejs/biome": "1.9.4",
|
|
30
32
|
"@openapitools/openapi-generator-cli": "2.16.3",
|
|
31
33
|
"@types/bun": "latest",
|
|
32
|
-
"tsup": "8.3.
|
|
34
|
+
"tsup": "8.3.6",
|
|
33
35
|
"typescript": "5.7.3"
|
|
34
36
|
}
|
|
35
37
|
}
|