bitrise-api-cli 0.0.4 → 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 +6 -1
- 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} +49 -57
- 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.
|
|
@@ -118,3 +118,8 @@ This project is [MIT](LICENSE) licensed.
|
|
|
118
118
|
<div align="center">
|
|
119
119
|
<p>Found this project useful? Give it a ⭐️!</p>
|
|
120
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,19 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { Command } from "commander";
|
|
5
|
-
|
|
6
|
-
// src/cliOptions.types.ts
|
|
7
|
-
var validArtifactTypes = ["android-apk", "ios-ipa"];
|
|
1
|
+
import {
|
|
2
|
+
validArtifactTypes
|
|
3
|
+
} from "./chunk-CF25N4TY.js";
|
|
8
4
|
|
|
9
5
|
// src/bitrise/env.ts
|
|
10
6
|
var ENV = {
|
|
7
|
+
debug: false,
|
|
11
8
|
appSlug: "",
|
|
12
9
|
token: "",
|
|
13
10
|
workflow: "",
|
|
14
11
|
artifactType: "android-apk"
|
|
15
12
|
};
|
|
16
13
|
var saveOptions = (options) => {
|
|
14
|
+
ENV.debug = options.debug;
|
|
17
15
|
ENV.appSlug = options.slug;
|
|
18
16
|
ENV.token = options.token;
|
|
19
17
|
ENV.workflow = options.workflow;
|
|
@@ -1435,28 +1433,17 @@ var api = {
|
|
|
1435
1433
|
builds: () => new BuildsApi(getApiConfig())
|
|
1436
1434
|
};
|
|
1437
1435
|
|
|
1436
|
+
// src/helper/debugLog.ts
|
|
1437
|
+
var debugLog = (label, data) => console.log(`${label}: ${JSON.stringify(data, void 0, 2)}`);
|
|
1438
|
+
|
|
1438
1439
|
// src/bitrise/fetchArtifact.ts
|
|
1439
1440
|
var fetchArtifact = async ({ artifactSlug, buildSlug }) => {
|
|
1440
1441
|
const { data } = await api.buildArtifact().artifactShow({ appSlug: ENV.appSlug, artifactSlug, buildSlug });
|
|
1441
1442
|
if (!data) throw new Error("buildArtifact().artifactShow returned no data");
|
|
1443
|
+
if (ENV.debug) debugLog("artifact", data);
|
|
1442
1444
|
return data;
|
|
1443
1445
|
};
|
|
1444
1446
|
|
|
1445
|
-
// src/helper/formatBytes.ts
|
|
1446
|
-
var decimals = 0;
|
|
1447
|
-
var formatBytes = (bytes) => {
|
|
1448
|
-
if (bytes === 0) return "0 Bytes";
|
|
1449
|
-
const k = 1024;
|
|
1450
|
-
const dm = decimals || 2;
|
|
1451
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
1452
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1453
|
-
const formattedSize = Number.parseFloat((bytes / k ** i).toFixed(dm));
|
|
1454
|
-
return `${formattedSize} ${sizes[i]}`;
|
|
1455
|
-
};
|
|
1456
|
-
|
|
1457
|
-
// src/downloadLatestArtifacts.ts
|
|
1458
|
-
import { oraPromise } from "ora";
|
|
1459
|
-
|
|
1460
1447
|
// src/bitrise/fetchArtifactList.ts
|
|
1461
1448
|
var fetchArtifactList = async (buildSlug) => {
|
|
1462
1449
|
const { data } = await api.buildArtifact().artifactList({ appSlug: ENV.appSlug, buildSlug });
|
|
@@ -1468,32 +1455,51 @@ var fetchArtifactByType = async (buildSlug) => {
|
|
|
1468
1455
|
const artifactMetadata = artifactInfo.find((artifact) => artifact.artifactType === ENV.artifactType);
|
|
1469
1456
|
if (!artifactMetadata || !artifactMetadata.slug)
|
|
1470
1457
|
throw new Error(`Found no ${ENV.artifactType} in build Slug: ${buildSlug}`);
|
|
1458
|
+
if (ENV.debug) debugLog("artifactMetadata", artifactMetadata);
|
|
1471
1459
|
return artifactMetadata;
|
|
1472
1460
|
};
|
|
1473
1461
|
|
|
1474
|
-
// src/helper/debugLog.ts
|
|
1475
|
-
var debugLog = (label, data) => console.log(`${label}: ${JSON.stringify(data, void 0, 2)}`);
|
|
1476
|
-
|
|
1477
1462
|
// src/bitrise/fetchBuilds.ts
|
|
1478
1463
|
var getAllBuilds = async () => {
|
|
1479
1464
|
const { data } = await api.builds().buildList({ appSlug: ENV.appSlug, status: 1 });
|
|
1480
1465
|
if (!data) throw Error("no build data");
|
|
1481
1466
|
return data;
|
|
1482
1467
|
};
|
|
1483
|
-
var getLatestBuild = async (
|
|
1468
|
+
var getLatestBuild = async () => {
|
|
1484
1469
|
const builds = await getAllBuilds();
|
|
1485
1470
|
const latestBuild = builds.find((build) => build.triggeredWorkflow === ENV.workflow);
|
|
1486
1471
|
if (!latestBuild) throw `Found no build with the workflow: "${ENV.workflow}"`;
|
|
1487
|
-
if (
|
|
1472
|
+
if (ENV.debug) debugLog("latestBuild", latestBuild);
|
|
1488
1473
|
return latestBuild;
|
|
1489
1474
|
};
|
|
1490
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
|
+
|
|
1491
1491
|
// src/helper/downloadFile.ts
|
|
1492
1492
|
import { createWriteStream } from "node:fs";
|
|
1493
1493
|
import { get } from "node:https";
|
|
1494
1494
|
import { pipeline } from "node:stream/promises";
|
|
1495
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
|
|
1496
1501
|
var downloadFile = async (fileUrl, outputLocationPath) => {
|
|
1502
|
+
const startTime = Date.now();
|
|
1497
1503
|
const url = new URL(fileUrl);
|
|
1498
1504
|
const response = await new Promise((resolve, reject) => {
|
|
1499
1505
|
get(url, (res) => {
|
|
@@ -1505,54 +1511,40 @@ var downloadFile = async (fileUrl, outputLocationPath) => {
|
|
|
1505
1511
|
}).on("error", reject);
|
|
1506
1512
|
});
|
|
1507
1513
|
await pipeline(response, createWriteStream(outputLocationPath));
|
|
1514
|
+
return { duration: formatTime(Date.now() - startTime) };
|
|
1508
1515
|
};
|
|
1509
1516
|
|
|
1510
1517
|
// src/downloadLatestArtifacts.ts
|
|
1511
1518
|
var downloadLatestArtifacts = async (options) => {
|
|
1512
1519
|
saveOptions(options);
|
|
1513
1520
|
if (!isEnvValid()) return process.exit(1);
|
|
1514
|
-
const latestBuild = await oraPromise(getLatestBuild(
|
|
1521
|
+
const latestBuild = await oraPromise(getLatestBuild(), {
|
|
1515
1522
|
text: "fetching latest build",
|
|
1516
1523
|
failText: (error) => `fetching latest build failed with error: ${error}`
|
|
1517
1524
|
});
|
|
1518
|
-
if (!latestBuild.slug)
|
|
1519
|
-
console.log("Latest build contained no Slug");
|
|
1520
|
-
return process.exit(1);
|
|
1521
|
-
}
|
|
1525
|
+
if (!latestBuild.slug) throw Error("Latest build contained no Slug");
|
|
1522
1526
|
const artifactMetadata = await oraPromise(fetchArtifactByType(latestBuild.slug), {
|
|
1523
1527
|
text: "fetching artifact list",
|
|
1524
1528
|
failText: (error) => `fetching artifact list failed with error: ${error}`
|
|
1525
1529
|
});
|
|
1526
|
-
if (
|
|
1527
|
-
if (!artifactMetadata || !artifactMetadata.slug) return process.exit(1);
|
|
1530
|
+
if (!artifactMetadata.slug || !artifactMetadata.title) throw Error("Artifact was Invalid");
|
|
1528
1531
|
const artifact = await oraPromise(
|
|
1529
|
-
fetchArtifact({
|
|
1530
|
-
artifactSlug: artifactMetadata.slug,
|
|
1531
|
-
buildSlug: latestBuild.slug
|
|
1532
|
-
}),
|
|
1532
|
+
fetchArtifact({ artifactSlug: artifactMetadata.slug, buildSlug: latestBuild.slug }),
|
|
1533
1533
|
{ text: "fetching artifact metadata" }
|
|
1534
1534
|
);
|
|
1535
|
-
if (
|
|
1536
|
-
if (!artifact || !artifact.expiringDownloadUrl || !artifactMetadata.title) {
|
|
1537
|
-
console.log("Artifact is missing data");
|
|
1538
|
-
return process.exit(1);
|
|
1539
|
-
}
|
|
1535
|
+
if (!artifact.expiringDownloadUrl) throw Error("Artifact is missing expiringDownloadUrl");
|
|
1540
1536
|
const fileSize = formatBytes(artifact.fileSizeBytes ?? 0);
|
|
1541
1537
|
await oraPromise(downloadFile(artifact.expiringDownloadUrl, artifactMetadata.title), {
|
|
1542
|
-
text: `downloading apk file (${fileSize})
|
|
1538
|
+
text: `downloading apk file (${fileSize})`,
|
|
1539
|
+
successText: ({ duration }) => `downloading apk file took ${duration}`
|
|
1543
1540
|
});
|
|
1544
1541
|
};
|
|
1545
1542
|
|
|
1546
|
-
// src/
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
"-s, --slug <APP_SLUG>",
|
|
1555
|
-
"bitrise app slug (or $BITRISE_APP_SLUG) see bitrise project url to get slug",
|
|
1556
|
-
process.env.BITRISE_APP_SLUG
|
|
1557
|
-
).option("-a, --artifact <ARTIFACT_TYPE>", 'bitrise artifact type "ios-ipa" or "android-apk"', "android-apk").option("-d, --debug", "output extra debugging", false).description("Download bitrise artifacts").action((options) => downloadLatestArtifacts(options).catch(() => process.exit(1)));
|
|
1558
|
-
program.parse(process.argv);
|
|
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
|
}
|