@better-update/cli 0.3.0 → 0.4.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/dist/index.mjs +5190 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +12 -9
- package/CHANGELOG.md +0 -58
- package/oxlint.config.ts +0 -6
- package/src/app-layer.ts +0 -29
- package/src/application/build-workflow.ts +0 -222
- package/src/application/command-exit.ts +0 -13
- package/src/application/login.ts +0 -87
- package/src/application/update-promote.ts +0 -88
- package/src/application/update-publish.ts +0 -402
- package/src/application/update-rollback.ts +0 -275
- package/src/commands/analytics/adoption.ts +0 -40
- package/src/commands/analytics/channels.ts +0 -35
- package/src/commands/analytics/helpers.ts +0 -3
- package/src/commands/analytics/index.ts +0 -13
- package/src/commands/analytics/platforms.ts +0 -39
- package/src/commands/analytics/updates.ts +0 -35
- package/src/commands/audit-logs/helpers.ts +0 -3
- package/src/commands/audit-logs/index.ts +0 -8
- package/src/commands/audit-logs/list.ts +0 -66
- package/src/commands/branches.ts +0 -70
- package/src/commands/build/android.ts +0 -129
- package/src/commands/build/index.ts +0 -63
- package/src/commands/build/ios.ts +0 -199
- package/src/commands/build/reserve-and-upload.test.ts +0 -263
- package/src/commands/build/reserve-and-upload.ts +0 -160
- package/src/commands/build/run-step.ts +0 -131
- package/src/commands/builds/compatibility-matrix.ts +0 -48
- package/src/commands/builds/delete.ts +0 -15
- package/src/commands/builds/get.ts +0 -34
- package/src/commands/builds/helpers.ts +0 -3
- package/src/commands/builds/index.ts +0 -20
- package/src/commands/builds/install-link.ts +0 -20
- package/src/commands/builds/list.ts +0 -38
- package/src/commands/channels/create.ts +0 -37
- package/src/commands/channels/delete.ts +0 -15
- package/src/commands/channels/helpers.ts +0 -18
- package/src/commands/channels/index.ts +0 -24
- package/src/commands/channels/list.ts +0 -38
- package/src/commands/channels/pause.ts +0 -15
- package/src/commands/channels/resume.ts +0 -15
- package/src/commands/channels/rollout/complete.ts +0 -17
- package/src/commands/channels/rollout/create.ts +0 -36
- package/src/commands/channels/rollout/index.ts +0 -11
- package/src/commands/channels/rollout/revert.ts +0 -17
- package/src/commands/channels/rollout/update.ts +0 -23
- package/src/commands/channels/update.ts +0 -32
- package/src/commands/credentials/delete.ts +0 -24
- package/src/commands/credentials/index.ts +0 -10
- package/src/commands/credentials/list.ts +0 -33
- package/src/commands/credentials/upload.ts +0 -91
- package/src/commands/env/delete.ts +0 -35
- package/src/commands/env/export.ts +0 -27
- package/src/commands/env/get.ts +0 -25
- package/src/commands/env/helpers.ts +0 -13
- package/src/commands/env/import.ts +0 -31
- package/src/commands/env/index.ts +0 -24
- package/src/commands/env/list.ts +0 -44
- package/src/commands/env/pull.ts +0 -27
- package/src/commands/env/set.ts +0 -42
- package/src/commands/fingerprint/compare.ts +0 -25
- package/src/commands/fingerprint/generate.ts +0 -18
- package/src/commands/fingerprint/index.ts +0 -9
- package/src/commands/init.ts +0 -35
- package/src/commands/login.ts +0 -13
- package/src/commands/logout.ts +0 -12
- package/src/commands/projects.ts +0 -84
- package/src/commands/status.ts +0 -48
- package/src/commands/update/delete.ts +0 -15
- package/src/commands/update/helpers.ts +0 -22
- package/src/commands/update/index.ts +0 -22
- package/src/commands/update/list.ts +0 -60
- package/src/commands/update/promote.ts +0 -30
- package/src/commands/update/publish.ts +0 -94
- package/src/commands/update/rollback.ts +0 -42
- package/src/commands/update/rollout/complete.ts +0 -17
- package/src/commands/update/rollout/index.ts +0 -10
- package/src/commands/update/rollout/revert.ts +0 -17
- package/src/commands/update/rollout/set.ts +0 -23
- package/src/index.ts +0 -53
- package/src/lib/android-keystore.test.ts +0 -114
- package/src/lib/android-keystore.ts +0 -76
- package/src/lib/android-signing-gradle.test.ts +0 -95
- package/src/lib/android-signing-gradle.ts +0 -52
- package/src/lib/app-json.ts +0 -81
- package/src/lib/apple-auth.test.ts +0 -402
- package/src/lib/apple-auth.ts +0 -132
- package/src/lib/artifact-finder.test.ts +0 -195
- package/src/lib/artifact-finder.ts +0 -122
- package/src/lib/browser-login.test.ts +0 -88
- package/src/lib/browser-login.ts +0 -193
- package/src/lib/build-profile.test.ts +0 -290
- package/src/lib/build-profile.ts +0 -234
- package/src/lib/cli-schemas.ts +0 -39
- package/src/lib/command-errors.ts +0 -60
- package/src/lib/credentials-downloader.ts +0 -181
- package/src/lib/credentials-manager.ts +0 -354
- package/src/lib/env-exporter.test.ts +0 -96
- package/src/lib/env-exporter.ts +0 -28
- package/src/lib/exit-codes.ts +0 -82
- package/src/lib/expo-config.ts +0 -130
- package/src/lib/expo-export.test.ts +0 -94
- package/src/lib/expo-export.ts +0 -281
- package/src/lib/fingerprint.ts +0 -67
- package/src/lib/format-error.ts +0 -22
- package/src/lib/git-context.ts +0 -56
- package/src/lib/gradle-config.ts +0 -126
- package/src/lib/ios-export-options.test.ts +0 -98
- package/src/lib/ios-export-options.ts +0 -62
- package/src/lib/ios-keychain.ts +0 -181
- package/src/lib/ios-provisioning.test.ts +0 -115
- package/src/lib/ios-provisioning.ts +0 -179
- package/src/lib/output.ts +0 -32
- package/src/lib/pkcs12.ts +0 -73
- package/src/lib/plist.ts +0 -39
- package/src/lib/post-build-validation.ts +0 -146
- package/src/lib/presigned-upload.test.ts +0 -140
- package/src/lib/presigned-upload.ts +0 -35
- package/src/lib/record.ts +0 -5
- package/src/lib/resolve-named-resource.ts +0 -24
- package/src/lib/runtime-version.test.ts +0 -119
- package/src/lib/runtime-version.ts +0 -62
- package/src/lib/sha256.test.ts +0 -108
- package/src/lib/sha256.ts +0 -80
- package/src/lib/signed-payloads.test.ts +0 -181
- package/src/lib/signed-payloads.ts +0 -164
- package/src/lib/string-utils.ts +0 -4
- package/src/lib/temp-dir.ts +0 -14
- package/src/lib/test-utils.ts +0 -13
- package/src/lib/update-platforms.test.ts +0 -45
- package/src/lib/update-platforms.ts +0 -19
- package/src/lib/xcpretty-formatter.ts +0 -21
- package/src/services/api-client.ts +0 -42
- package/src/services/apple-session-store.ts +0 -100
- package/src/services/auth-store.ts +0 -85
- package/src/services/cli-runtime.ts +0 -46
- package/src/services/config-store.ts +0 -108
- package/src/services/presigned-upload.ts +0 -84
- package/src/services/update-asset-uploader.ts +0 -72
- package/src/types/keychain.d.ts +0 -22
- package/tests/e2e/build.test.ts +0 -270
- package/tests/e2e/commands.test.ts +0 -694
- package/tests/e2e/ota-lifecycle.test.ts +0 -275
- package/tests/e2e/publish.test.ts +0 -150
- package/tests/helpers/cli-e2e.ts +0 -426
- package/tests/helpers/pty-driver.ts +0 -142
- package/tests/interactive/harness/provider-prompt.ts +0 -54
- package/tests/interactive/login.test.ts +0 -47
- package/tests/interactive/provider-select.test.ts +0 -59
- package/tsconfig.json +0 -7
- package/vitest.config.ts +0 -38
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Console, Effect, Option } from "effect";
|
|
3
|
-
|
|
4
|
-
import { readProjectId } from "../../lib/app-json";
|
|
5
|
-
import { printTable } from "../../lib/output";
|
|
6
|
-
import { apiClient } from "../../services/api-client";
|
|
7
|
-
import { handleAnalyticsCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
const period = Options.choice("period", ["1d", "7d", "30d", "90d"]).pipe(Options.optional);
|
|
10
|
-
|
|
11
|
-
export const adoptionCommand = Command.make("adoption", { period }, (opts) =>
|
|
12
|
-
Effect.gen(function* () {
|
|
13
|
-
const projectId = yield* readProjectId;
|
|
14
|
-
const api = yield* apiClient;
|
|
15
|
-
|
|
16
|
-
const periodFilter = Option.match(opts.period, {
|
|
17
|
-
onNone: () => ({}) as Record<string, string>,
|
|
18
|
-
onSome: (periodValue) => ({ period: periodValue }) as Record<string, string>,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const result = yield* api.analytics.adoption({
|
|
22
|
-
urlParams: { projectId, ...periodFilter },
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (result.updates.length === 0) {
|
|
26
|
-
yield* Console.log("No adoption data found.");
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
yield* printTable(
|
|
31
|
-
["Update ID", "Devices", "First Seen", "Last Seen"],
|
|
32
|
-
result.updates.map((update) => [
|
|
33
|
-
update.updateId,
|
|
34
|
-
String(update.devices),
|
|
35
|
-
update.firstSeen,
|
|
36
|
-
update.lastSeen,
|
|
37
|
-
]),
|
|
38
|
-
);
|
|
39
|
-
}).pipe(handleAnalyticsCommandErrors),
|
|
40
|
-
);
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Effect, Option } from "effect";
|
|
3
|
-
|
|
4
|
-
import { readProjectId } from "../../lib/app-json";
|
|
5
|
-
import { printKeyValue } from "../../lib/output";
|
|
6
|
-
import { apiClient } from "../../services/api-client";
|
|
7
|
-
import { handleAnalyticsCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
const channel = Options.text("channel");
|
|
10
|
-
const period = Options.choice("period", ["1d", "7d", "30d", "90d"]).pipe(Options.optional);
|
|
11
|
-
|
|
12
|
-
export const channelsCommand = Command.make("channels", { channel, period }, (opts) =>
|
|
13
|
-
Effect.gen(function* () {
|
|
14
|
-
const projectId = yield* readProjectId;
|
|
15
|
-
const api = yield* apiClient;
|
|
16
|
-
|
|
17
|
-
const periodFilter = Option.match(opts.period, {
|
|
18
|
-
onNone: () => ({}) as Record<string, string>,
|
|
19
|
-
onSome: (periodValue) => ({ period: periodValue }) as Record<string, string>,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const result = yield* api.analytics.channels({
|
|
23
|
-
urlParams: { projectId, channel: opts.channel, ...periodFilter },
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
yield* printKeyValue([
|
|
27
|
-
["Channel", result.channel],
|
|
28
|
-
["Total Requests", String(result.totalRequests)],
|
|
29
|
-
["Unique Devices", String(result.uniqueDevices)],
|
|
30
|
-
["Manifest", String(result.responseTypeDistribution.manifest)],
|
|
31
|
-
["Directive", String(result.responseTypeDistribution.directive)],
|
|
32
|
-
["No Update", String(result.responseTypeDistribution.no_update)],
|
|
33
|
-
]);
|
|
34
|
-
}).pipe(handleAnalyticsCommandErrors),
|
|
35
|
-
);
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console } from "effect";
|
|
3
|
-
|
|
4
|
-
import { adoptionCommand } from "./adoption";
|
|
5
|
-
import { channelsCommand } from "./channels";
|
|
6
|
-
import { platformsCommand } from "./platforms";
|
|
7
|
-
import { updatesCommand } from "./updates";
|
|
8
|
-
|
|
9
|
-
export const analyticsCommand = Command.make("analytics", {}, () =>
|
|
10
|
-
Console.log("View deployment analytics. Run with --help for subcommands."),
|
|
11
|
-
).pipe(
|
|
12
|
-
Command.withSubcommands([adoptionCommand, updatesCommand, channelsCommand, platformsCommand]),
|
|
13
|
-
);
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Console, Effect, Option } from "effect";
|
|
3
|
-
|
|
4
|
-
import { readProjectId } from "../../lib/app-json";
|
|
5
|
-
import { printTable } from "../../lib/output";
|
|
6
|
-
import { apiClient } from "../../services/api-client";
|
|
7
|
-
import { handleAnalyticsCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
const period = Options.choice("period", ["1d", "7d", "30d", "90d"]).pipe(Options.optional);
|
|
10
|
-
|
|
11
|
-
export const platformsCommand = Command.make("platforms", { period }, (opts) =>
|
|
12
|
-
Effect.gen(function* () {
|
|
13
|
-
const projectId = yield* readProjectId;
|
|
14
|
-
const api = yield* apiClient;
|
|
15
|
-
|
|
16
|
-
const periodFilter = Option.match(opts.period, {
|
|
17
|
-
onNone: () => ({}) as Record<string, string>,
|
|
18
|
-
onSome: (periodValue) => ({ period: periodValue }) as Record<string, string>,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const result = yield* api.analytics.platforms({
|
|
22
|
-
urlParams: { projectId, ...periodFilter },
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
if (result.platforms.length === 0) {
|
|
26
|
-
yield* Console.log("No platform data found.");
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
yield* printTable(
|
|
31
|
-
["Platform", "Requests", "Devices"],
|
|
32
|
-
result.platforms.map((platform) => [
|
|
33
|
-
platform.platform,
|
|
34
|
-
String(platform.requests),
|
|
35
|
-
String(platform.devices),
|
|
36
|
-
]),
|
|
37
|
-
);
|
|
38
|
-
}).pipe(handleAnalyticsCommandErrors),
|
|
39
|
-
);
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Effect, Option } from "effect";
|
|
3
|
-
|
|
4
|
-
import { readProjectId } from "../../lib/app-json";
|
|
5
|
-
import { printKeyValue } from "../../lib/output";
|
|
6
|
-
import { apiClient } from "../../services/api-client";
|
|
7
|
-
import { handleAnalyticsCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
const updateId = Options.text("update-id");
|
|
10
|
-
const period = Options.choice("period", ["1d", "7d", "30d", "90d"]).pipe(Options.optional);
|
|
11
|
-
|
|
12
|
-
export const updatesCommand = Command.make("updates", { updateId, period }, (opts) =>
|
|
13
|
-
Effect.gen(function* () {
|
|
14
|
-
const projectId = yield* readProjectId;
|
|
15
|
-
const api = yield* apiClient;
|
|
16
|
-
|
|
17
|
-
const periodFilter = Option.match(opts.period, {
|
|
18
|
-
onNone: () => ({}) as Record<string, string>,
|
|
19
|
-
onSome: (periodValue) => ({ period: periodValue }) as Record<string, string>,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const result = yield* api.analytics.updates({
|
|
23
|
-
urlParams: { projectId, updateId: opts.updateId, ...periodFilter },
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
yield* printKeyValue([
|
|
27
|
-
["Update ID", result.updateId],
|
|
28
|
-
["Total Requests", String(result.totalRequests)],
|
|
29
|
-
["Unique Devices", String(result.uniqueDevices)],
|
|
30
|
-
["Manifest", String(result.byResponseType.manifest)],
|
|
31
|
-
["Directive", String(result.byResponseType.directive)],
|
|
32
|
-
["No Update", String(result.byResponseType.no_update)],
|
|
33
|
-
]);
|
|
34
|
-
}).pipe(handleAnalyticsCommandErrors),
|
|
35
|
-
);
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console } from "effect";
|
|
3
|
-
|
|
4
|
-
import { listCommand } from "./list";
|
|
5
|
-
|
|
6
|
-
export const auditLogsCommand = Command.make("audit-logs", {}, () =>
|
|
7
|
-
Console.log("View audit logs. Run with --help for subcommands."),
|
|
8
|
-
).pipe(Command.withSubcommands([listCommand]));
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Console, Effect, Option } from "effect";
|
|
3
|
-
|
|
4
|
-
import { printTable } from "../../lib/output";
|
|
5
|
-
import { apiClient } from "../../services/api-client";
|
|
6
|
-
import { handleAuditLogCommandErrors } from "./helpers";
|
|
7
|
-
|
|
8
|
-
const action = Options.text("action").pipe(Options.optional);
|
|
9
|
-
const resourceType = Options.text("resource-type").pipe(Options.optional);
|
|
10
|
-
const actorId = Options.text("actor-id").pipe(Options.optional);
|
|
11
|
-
const from = Options.text("from").pipe(Options.optional);
|
|
12
|
-
const to = Options.text("to").pipe(Options.optional);
|
|
13
|
-
|
|
14
|
-
export const listCommand = Command.make(
|
|
15
|
-
"list",
|
|
16
|
-
{ action, resourceType, actorId, from, to },
|
|
17
|
-
(opts) =>
|
|
18
|
-
Effect.gen(function* () {
|
|
19
|
-
const api = yield* apiClient;
|
|
20
|
-
|
|
21
|
-
const filters = {
|
|
22
|
-
...Option.match(opts.action, {
|
|
23
|
-
onNone: () => ({}),
|
|
24
|
-
onSome: (value) => ({ action: value }),
|
|
25
|
-
}),
|
|
26
|
-
...Option.match(opts.resourceType, {
|
|
27
|
-
onNone: () => ({}),
|
|
28
|
-
onSome: (value) => ({ resourceType: value }),
|
|
29
|
-
}),
|
|
30
|
-
...Option.match(opts.actorId, {
|
|
31
|
-
onNone: () => ({}),
|
|
32
|
-
onSome: (value) => ({ actorId: value }),
|
|
33
|
-
}),
|
|
34
|
-
...Option.match(opts.from, {
|
|
35
|
-
onNone: () => ({}),
|
|
36
|
-
onSome: (value) => ({ from: value }),
|
|
37
|
-
}),
|
|
38
|
-
...Option.match(opts.to, {
|
|
39
|
-
onNone: () => ({}),
|
|
40
|
-
onSome: (value) => ({ to: value }),
|
|
41
|
-
}),
|
|
42
|
-
} as Record<string, string>;
|
|
43
|
-
|
|
44
|
-
const { items } = yield* api["audit-logs"].list({
|
|
45
|
-
urlParams: { ...filters, page: 1, limit: 100 },
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
if (items.length === 0) {
|
|
49
|
-
yield* Console.log("No audit log entries found.");
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
yield* printTable(
|
|
54
|
-
["ID", "Action", "Resource Type", "Resource ID", "Actor", "Source", "Created"],
|
|
55
|
-
items.map((log) => [
|
|
56
|
-
log.id,
|
|
57
|
-
log.action,
|
|
58
|
-
log.resourceType,
|
|
59
|
-
log.resourceId ?? "-",
|
|
60
|
-
log.actorEmail,
|
|
61
|
-
log.source,
|
|
62
|
-
log.createdAt,
|
|
63
|
-
]),
|
|
64
|
-
);
|
|
65
|
-
}).pipe(handleAuditLogCommandErrors),
|
|
66
|
-
);
|
package/src/commands/branches.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { Args, Command, Options } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { readProjectId } from "../lib/app-json";
|
|
5
|
-
import { makeCommandErrorHandler } from "../lib/command-errors";
|
|
6
|
-
import { printKeyValue, printTable } from "../lib/output";
|
|
7
|
-
import { apiClient } from "../services/api-client";
|
|
8
|
-
|
|
9
|
-
const handleErrors = makeCommandErrorHandler();
|
|
10
|
-
|
|
11
|
-
const idArg = Args.text({ name: "id" });
|
|
12
|
-
const nameOption = Options.text("name");
|
|
13
|
-
|
|
14
|
-
const listCommand = Command.make("list", {}, () =>
|
|
15
|
-
Effect.gen(function* () {
|
|
16
|
-
const projectId = yield* readProjectId;
|
|
17
|
-
const api = yield* apiClient;
|
|
18
|
-
const { items } = yield* api.branches.list({
|
|
19
|
-
urlParams: { projectId, page: 1, limit: 1000 },
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
if (items.length === 0) {
|
|
23
|
-
yield* Console.log("No branches found.");
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
yield* printTable(
|
|
28
|
-
["ID", "Name", "Created"],
|
|
29
|
-
items.map((branch) => [branch.id, branch.name, branch.createdAt]),
|
|
30
|
-
);
|
|
31
|
-
}).pipe(handleErrors),
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const createCommand = Command.make("create", { name: nameOption }, (opts) =>
|
|
35
|
-
Effect.gen(function* () {
|
|
36
|
-
const projectId = yield* readProjectId;
|
|
37
|
-
const api = yield* apiClient;
|
|
38
|
-
const branch = yield* api.branches.create({
|
|
39
|
-
payload: { projectId, name: opts.name },
|
|
40
|
-
});
|
|
41
|
-
yield* printKeyValue([
|
|
42
|
-
["ID", branch.id],
|
|
43
|
-
["Name", branch.name],
|
|
44
|
-
["Created", branch.createdAt],
|
|
45
|
-
]);
|
|
46
|
-
}).pipe(handleErrors),
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const renameCommand = Command.make("rename", { id: idArg, name: nameOption }, (opts) =>
|
|
50
|
-
Effect.gen(function* () {
|
|
51
|
-
const api = yield* apiClient;
|
|
52
|
-
const branch = yield* api.branches.rename({
|
|
53
|
-
path: { id: opts.id },
|
|
54
|
-
payload: { name: opts.name },
|
|
55
|
-
});
|
|
56
|
-
yield* Console.log(`Branch renamed to "${branch.name}".`);
|
|
57
|
-
}).pipe(handleErrors),
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
const deleteCommand = Command.make("delete", { id: idArg }, (opts) =>
|
|
61
|
-
Effect.gen(function* () {
|
|
62
|
-
const api = yield* apiClient;
|
|
63
|
-
yield* api.branches.delete({ path: { id: opts.id } });
|
|
64
|
-
yield* Console.log(`Branch ${opts.id} deleted.`);
|
|
65
|
-
}).pipe(handleErrors),
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
export const branchesCommand = Command.make("branches", {}, () =>
|
|
69
|
-
Console.log("Manage branches. Run with --help for subcommands."),
|
|
70
|
-
).pipe(Command.withSubcommands([listCommand, createCommand, renameCommand, deleteCommand]));
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import { Command, FileSystem } from "@effect/platform";
|
|
4
|
-
import { Effect } from "effect";
|
|
5
|
-
|
|
6
|
-
import type { CommandExecutor } from "@effect/platform";
|
|
7
|
-
import type { PlatformError } from "@effect/platform/Error";
|
|
8
|
-
|
|
9
|
-
import { renderSigningGradle } from "../../lib/android-signing-gradle";
|
|
10
|
-
import { findAndroidArtifact } from "../../lib/artifact-finder";
|
|
11
|
-
import { downloadAndroidCredentials } from "../../lib/credentials-downloader";
|
|
12
|
-
import { sha256File } from "../../lib/sha256";
|
|
13
|
-
import { capitalize } from "../../lib/string-utils";
|
|
14
|
-
import { CliRuntime } from "../../services/cli-runtime";
|
|
15
|
-
import { runStep } from "./run-step";
|
|
16
|
-
|
|
17
|
-
import type { AndroidProfile } from "../../lib/build-profile";
|
|
18
|
-
import type {
|
|
19
|
-
ArtifactNotFoundError,
|
|
20
|
-
BuildFailedError,
|
|
21
|
-
MissingCredentialsError,
|
|
22
|
-
} from "../../lib/exit-codes";
|
|
23
|
-
import type { ApiClient } from "../../services/api-client";
|
|
24
|
-
|
|
25
|
-
export interface RunAndroidBuildInput {
|
|
26
|
-
readonly api: ApiClient;
|
|
27
|
-
readonly tempDir: string;
|
|
28
|
-
readonly projectRoot: string;
|
|
29
|
-
readonly androidProfile: AndroidProfile;
|
|
30
|
-
readonly applicationIdentifier: string;
|
|
31
|
-
readonly envVars: Record<string, string>;
|
|
32
|
-
readonly projectId: string;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface RunAndroidBuildResult {
|
|
36
|
-
readonly artifactPath: string;
|
|
37
|
-
readonly byteSize: number;
|
|
38
|
-
readonly sha256: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Compose the Gradle task name from flavor, format, and buildType.
|
|
43
|
-
*
|
|
44
|
-
* Gradle naming convention: `<verb><Flavor><Variant>`, e.g.
|
|
45
|
-
* - no flavor + apk + release → `assembleRelease`
|
|
46
|
-
* - no flavor + aab + release → `bundleRelease`
|
|
47
|
-
* - flavor=prod + aab + release → `bundleProdRelease`
|
|
48
|
-
* - flavor=prod + apk + debug → `assembleProdDebug`
|
|
49
|
-
*/
|
|
50
|
-
const gradleTaskName = (
|
|
51
|
-
format: "apk" | "aab",
|
|
52
|
-
flavor: string | undefined,
|
|
53
|
-
buildType: "debug" | "release",
|
|
54
|
-
): string => {
|
|
55
|
-
const verb = format === "aab" ? "bundle" : "assemble";
|
|
56
|
-
return flavor
|
|
57
|
-
? `${verb}${capitalize(flavor)}${capitalize(buildType)}`
|
|
58
|
-
: `${verb}${capitalize(buildType)}`;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const runAndroidBuild = (
|
|
62
|
-
input: RunAndroidBuildInput,
|
|
63
|
-
): Effect.Effect<
|
|
64
|
-
RunAndroidBuildResult,
|
|
65
|
-
BuildFailedError | MissingCredentialsError | ArtifactNotFoundError | PlatformError,
|
|
66
|
-
CliRuntime | CommandExecutor.CommandExecutor | FileSystem.FileSystem
|
|
67
|
-
> =>
|
|
68
|
-
Effect.gen(function* () {
|
|
69
|
-
const { api, tempDir, projectRoot, androidProfile, applicationIdentifier, envVars, projectId } =
|
|
70
|
-
input;
|
|
71
|
-
const runtime = yield* CliRuntime;
|
|
72
|
-
|
|
73
|
-
// Record build start so artifact-finder can reject stale outputs from
|
|
74
|
-
// Earlier builds that may still live in `android/app/build/outputs/`.
|
|
75
|
-
const buildStartMs = Date.now();
|
|
76
|
-
|
|
77
|
-
const { format } = androidProfile;
|
|
78
|
-
const { flavor } = androidProfile;
|
|
79
|
-
const buildType = androidProfile.buildType ?? "release";
|
|
80
|
-
const androidDir = path.join(projectRoot, "android");
|
|
81
|
-
const commandEnv = yield* runtime.commandEnvironment(envVars);
|
|
82
|
-
|
|
83
|
-
const credentials = yield* downloadAndroidCredentials(api, {
|
|
84
|
-
projectId,
|
|
85
|
-
applicationIdentifier,
|
|
86
|
-
tempDir,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
yield* runStep(
|
|
90
|
-
Command.make("bunx", "expo", "prebuild", "--platform", "android", "--clean").pipe(
|
|
91
|
-
Command.workingDirectory(projectRoot),
|
|
92
|
-
Command.env(commandEnv),
|
|
93
|
-
),
|
|
94
|
-
"expo prebuild android",
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
const fs = yield* FileSystem.FileSystem;
|
|
98
|
-
const signingGradlePath = path.join(tempDir, "signing.gradle");
|
|
99
|
-
yield* fs.writeFileString(
|
|
100
|
-
signingGradlePath,
|
|
101
|
-
renderSigningGradle({
|
|
102
|
-
keystorePath: credentials.keystorePath,
|
|
103
|
-
storePassword: credentials.storePassword,
|
|
104
|
-
keyAlias: credentials.keyAlias,
|
|
105
|
-
keyPassword: credentials.keyPassword,
|
|
106
|
-
}),
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const taskName = gradleTaskName(format, flavor, buildType);
|
|
110
|
-
yield* runStep(
|
|
111
|
-
Command.make("./gradlew", "--init-script", signingGradlePath, `:app:${taskName}`).pipe(
|
|
112
|
-
Command.workingDirectory(androidDir),
|
|
113
|
-
Command.env(commandEnv),
|
|
114
|
-
),
|
|
115
|
-
"gradlew",
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
const artifactPath = yield* findAndroidArtifact({
|
|
119
|
-
projectRoot,
|
|
120
|
-
format,
|
|
121
|
-
...(flavor === undefined ? {} : { flavor }),
|
|
122
|
-
buildType,
|
|
123
|
-
minMtimeMs: buildStartMs,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const { sha256, byteSize } = yield* sha256File(artifactPath);
|
|
127
|
-
|
|
128
|
-
return { artifactPath, byteSize, sha256 };
|
|
129
|
-
});
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Effect, Option } from "effect";
|
|
3
|
-
|
|
4
|
-
import type { BadArgument, SystemError } from "@effect/platform/Error";
|
|
5
|
-
|
|
6
|
-
import { runBuildWorkflow } from "../../application/build-workflow";
|
|
7
|
-
import { exitWith } from "../../application/command-exit";
|
|
8
|
-
|
|
9
|
-
import type {
|
|
10
|
-
ArtifactNotFoundError,
|
|
11
|
-
AuthRequiredError,
|
|
12
|
-
BuildFailedError,
|
|
13
|
-
BuildProfileError,
|
|
14
|
-
CompleteError,
|
|
15
|
-
EnvExportError,
|
|
16
|
-
KeychainError,
|
|
17
|
-
MissingCredentialsError,
|
|
18
|
-
PresignedUrlExpiredError,
|
|
19
|
-
ProjectNotLinkedError,
|
|
20
|
-
ProvisioningError,
|
|
21
|
-
ReserveError,
|
|
22
|
-
RuntimeVersionError,
|
|
23
|
-
UploadFailedError,
|
|
24
|
-
} from "../../lib/exit-codes";
|
|
25
|
-
|
|
26
|
-
const platform = Options.choice("platform", ["ios", "android"] as const);
|
|
27
|
-
const profile = Options.text("profile").pipe(Options.withDefault("production"));
|
|
28
|
-
const message = Options.text("message").pipe(Options.optional);
|
|
29
|
-
const noUpload = Options.boolean("no-upload");
|
|
30
|
-
const rawOutput = Options.boolean("raw-output");
|
|
31
|
-
|
|
32
|
-
export const buildCommand = Command.make(
|
|
33
|
-
"build",
|
|
34
|
-
{ platform, profile, message, noUpload, rawOutput },
|
|
35
|
-
(opts) =>
|
|
36
|
-
runBuildWorkflow({
|
|
37
|
-
platform: opts.platform,
|
|
38
|
-
profileName: opts.profile,
|
|
39
|
-
message: Option.getOrUndefined(opts.message),
|
|
40
|
-
noUpload: opts.noUpload,
|
|
41
|
-
rawOutput: opts.rawOutput,
|
|
42
|
-
}).pipe(
|
|
43
|
-
Effect.catchTags({
|
|
44
|
-
AuthRequiredError: (err: AuthRequiredError) => exitWith(3, err.message),
|
|
45
|
-
ProjectNotLinkedError: (err: ProjectNotLinkedError) => exitWith(4, err.message),
|
|
46
|
-
BuildProfileError: (err: BuildProfileError) => exitWith(2, err.message),
|
|
47
|
-
RuntimeVersionError: (err: RuntimeVersionError) => exitWith(2, err.message),
|
|
48
|
-
MissingCredentialsError: (err: MissingCredentialsError) =>
|
|
49
|
-
exitWith(5, `${err.message}\n${err.hint}`),
|
|
50
|
-
BuildFailedError: (err: BuildFailedError) => exitWith(6, err.message),
|
|
51
|
-
KeychainError: (err: KeychainError) => exitWith(6, err.message),
|
|
52
|
-
ProvisioningError: (err: ProvisioningError) => exitWith(6, err.message),
|
|
53
|
-
ArtifactNotFoundError: (err: ArtifactNotFoundError) => exitWith(6, err.message),
|
|
54
|
-
ReserveError: (err: ReserveError) => exitWith(7, err.message),
|
|
55
|
-
UploadFailedError: (err: UploadFailedError) => exitWith(7, err.message),
|
|
56
|
-
PresignedUrlExpiredError: (err: PresignedUrlExpiredError) => exitWith(7, err.message),
|
|
57
|
-
CompleteError: (err: CompleteError) => exitWith(7, err.message),
|
|
58
|
-
EnvExportError: (err: EnvExportError) => exitWith(7, err.message),
|
|
59
|
-
SystemError: (err: SystemError) => exitWith(6, `Filesystem error: ${err.message}`),
|
|
60
|
-
BadArgument: (err: BadArgument) => exitWith(6, `Invalid argument: ${err.message}`),
|
|
61
|
-
}),
|
|
62
|
-
),
|
|
63
|
-
);
|