@better-update/cli 0.3.0 → 0.3.2
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.js +5319 -0
- package/dist/index.js.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,131 +0,0 @@
|
|
|
1
|
-
import process from "node:process";
|
|
2
|
-
|
|
3
|
-
import { Command } from "@effect/platform";
|
|
4
|
-
import { Effect, Fiber, Stream } from "effect";
|
|
5
|
-
|
|
6
|
-
import type { CommandExecutor } from "@effect/platform";
|
|
7
|
-
import type { Scope } from "effect";
|
|
8
|
-
|
|
9
|
-
import { BuildFailedError } from "../../lib/exit-codes";
|
|
10
|
-
|
|
11
|
-
import type { XcodebuildFormatter } from "../../lib/xcpretty-formatter";
|
|
12
|
-
|
|
13
|
-
export const runStep = (
|
|
14
|
-
cmd: Command.Command,
|
|
15
|
-
step: string,
|
|
16
|
-
): Effect.Effect<void, BuildFailedError, CommandExecutor.CommandExecutor> =>
|
|
17
|
-
Command.exitCode(cmd.pipe(Command.stdout("inherit"), Command.stderr("inherit"))).pipe(
|
|
18
|
-
Effect.mapError(
|
|
19
|
-
(cause) =>
|
|
20
|
-
new BuildFailedError({
|
|
21
|
-
step,
|
|
22
|
-
exitCode: 1,
|
|
23
|
-
message: `${step} failed to spawn: ${String(cause)}`,
|
|
24
|
-
}),
|
|
25
|
-
),
|
|
26
|
-
Effect.flatMap((code) =>
|
|
27
|
-
code === 0
|
|
28
|
-
? Effect.void
|
|
29
|
-
: Effect.fail(
|
|
30
|
-
new BuildFailedError({
|
|
31
|
-
step,
|
|
32
|
-
exitCode: code,
|
|
33
|
-
message: `${step} exited with code ${code}`,
|
|
34
|
-
}),
|
|
35
|
-
),
|
|
36
|
-
),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Run a build step with stdout piped through a formatter (e.g., xcpretty).
|
|
41
|
-
* stderr passes through to the terminal directly.
|
|
42
|
-
*/
|
|
43
|
-
export const runStepFormatted = (
|
|
44
|
-
cmd: Command.Command,
|
|
45
|
-
step: string,
|
|
46
|
-
formatter: XcodebuildFormatter,
|
|
47
|
-
): Effect.Effect<void, BuildFailedError, CommandExecutor.CommandExecutor | Scope.Scope> =>
|
|
48
|
-
Effect.gen(function* () {
|
|
49
|
-
const proc = yield* Command.start(
|
|
50
|
-
cmd.pipe(Command.stdout("pipe"), Command.stderr("pipe")),
|
|
51
|
-
).pipe(
|
|
52
|
-
Effect.mapError(
|
|
53
|
-
(cause) =>
|
|
54
|
-
new BuildFailedError({
|
|
55
|
-
step,
|
|
56
|
-
exitCode: 1,
|
|
57
|
-
message: `${step} failed to spawn: ${String(cause)}`,
|
|
58
|
-
}),
|
|
59
|
-
),
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
const stdoutFiber = yield* proc.stdout.pipe(
|
|
63
|
-
Stream.decodeText(),
|
|
64
|
-
Stream.splitLines,
|
|
65
|
-
Stream.runForEach((line) => {
|
|
66
|
-
const formatted = formatter.pipe(line);
|
|
67
|
-
return formatted.length > 0
|
|
68
|
-
? Effect.sync(() => {
|
|
69
|
-
for (const output of formatted) {
|
|
70
|
-
process.stdout.write(`${output}\n`);
|
|
71
|
-
}
|
|
72
|
-
})
|
|
73
|
-
: Effect.void;
|
|
74
|
-
}),
|
|
75
|
-
Effect.mapError(
|
|
76
|
-
(cause) =>
|
|
77
|
-
new BuildFailedError({
|
|
78
|
-
step,
|
|
79
|
-
exitCode: 1,
|
|
80
|
-
message: `${step} stdout stream error: ${String(cause)}`,
|
|
81
|
-
}),
|
|
82
|
-
),
|
|
83
|
-
Effect.fork,
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
const stderrFiber = yield* proc.stderr.pipe(
|
|
87
|
-
Stream.decodeText(),
|
|
88
|
-
Stream.splitLines,
|
|
89
|
-
Stream.runForEach((line) => Effect.sync(() => process.stderr.write(`${line}\n`))),
|
|
90
|
-
Effect.mapError(
|
|
91
|
-
(cause) =>
|
|
92
|
-
new BuildFailedError({
|
|
93
|
-
step,
|
|
94
|
-
exitCode: 1,
|
|
95
|
-
message: `${step} stderr stream error: ${String(cause)}`,
|
|
96
|
-
}),
|
|
97
|
-
),
|
|
98
|
-
Effect.fork,
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
// Join fibers concurrently — stream errors are non-fatal, exit code takes precedence.
|
|
102
|
-
yield* Effect.all([Fiber.join(stdoutFiber), Fiber.join(stderrFiber)], {
|
|
103
|
-
concurrency: 2,
|
|
104
|
-
}).pipe(Effect.catchAll(() => Effect.void));
|
|
105
|
-
|
|
106
|
-
const code = yield* proc.exitCode.pipe(
|
|
107
|
-
Effect.mapError(
|
|
108
|
-
(cause) =>
|
|
109
|
-
new BuildFailedError({
|
|
110
|
-
step,
|
|
111
|
-
exitCode: 1,
|
|
112
|
-
message: `${step} exit code error: ${String(cause)}`,
|
|
113
|
-
}),
|
|
114
|
-
),
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
if (code !== 0) {
|
|
118
|
-
// Print build summary on failure for xcpretty diagnostics
|
|
119
|
-
const summary = formatter.getBuildSummary();
|
|
120
|
-
if (summary) {
|
|
121
|
-
process.stderr.write(`${summary}\n`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return yield* new BuildFailedError({
|
|
125
|
-
step,
|
|
126
|
-
exitCode: code,
|
|
127
|
-
message: `${step} exited with code ${code}`,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
return undefined;
|
|
131
|
-
});
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } 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 { handleBuildsCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
export const compatibilityMatrixCommand = Command.make("compatibility-matrix", {}, () =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const projectId = yield* readProjectId;
|
|
12
|
-
const api = yield* apiClient;
|
|
13
|
-
const result = yield* api.builds.compatibilityMatrix({
|
|
14
|
-
urlParams: { projectId },
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
if (result.rows.length === 0 && result.missingRuntimeVersions.length === 0) {
|
|
18
|
-
yield* Console.log("No compatibility data found.");
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (result.rows.length > 0) {
|
|
23
|
-
yield* Console.log("Build-to-Channel Compatibility:");
|
|
24
|
-
yield* printTable(
|
|
25
|
-
["Build ID", "Platform", "Runtime Version", "Channels"],
|
|
26
|
-
result.rows.map((row) => [
|
|
27
|
-
row.id,
|
|
28
|
-
row.platform,
|
|
29
|
-
row.runtimeVersion ?? "-",
|
|
30
|
-
row.channels.map((channel) => channel.channelName).join(", ") || "-",
|
|
31
|
-
]),
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (result.missingRuntimeVersions.length > 0) {
|
|
36
|
-
yield* Console.log("\nMissing Runtime Versions:");
|
|
37
|
-
yield* printTable(
|
|
38
|
-
["Channel", "Platform", "Runtime Version", "Updates"],
|
|
39
|
-
result.missingRuntimeVersions.map((missing) => [
|
|
40
|
-
missing.channelName,
|
|
41
|
-
missing.platform,
|
|
42
|
-
missing.runtimeVersion,
|
|
43
|
-
String(missing.updateCount),
|
|
44
|
-
]),
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}).pipe(handleBuildsCommandErrors),
|
|
48
|
-
);
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { apiClient } from "../../services/api-client";
|
|
5
|
-
import { handleBuildsCommandErrors } from "./helpers";
|
|
6
|
-
|
|
7
|
-
const id = Args.text({ name: "id" });
|
|
8
|
-
|
|
9
|
-
export const deleteCommand = Command.make("delete", { id }, (opts) =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const api = yield* apiClient;
|
|
12
|
-
yield* api.builds.delete({ path: { id: opts.id } });
|
|
13
|
-
yield* Console.log(`Build ${opts.id} deleted.`);
|
|
14
|
-
}).pipe(handleBuildsCommandErrors),
|
|
15
|
-
);
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { printKeyValue } from "../../lib/output";
|
|
5
|
-
import { apiClient } from "../../services/api-client";
|
|
6
|
-
import { handleBuildsCommandErrors } from "./helpers";
|
|
7
|
-
|
|
8
|
-
const id = Args.text({ name: "id" });
|
|
9
|
-
|
|
10
|
-
export const getCommand = Command.make("get", { id }, (opts) =>
|
|
11
|
-
Effect.gen(function* () {
|
|
12
|
-
const api = yield* apiClient;
|
|
13
|
-
const build = yield* api.builds.get({ path: { id: opts.id } });
|
|
14
|
-
yield* printKeyValue([
|
|
15
|
-
["ID", build.id],
|
|
16
|
-
["Platform", build.platform],
|
|
17
|
-
["Profile", build.profile],
|
|
18
|
-
["Distribution", build.distribution],
|
|
19
|
-
["Version", build.appVersion ?? "-"],
|
|
20
|
-
["Build Number", build.buildNumber ?? "-"],
|
|
21
|
-
["Runtime Version", build.runtimeVersion ?? "-"],
|
|
22
|
-
["Bundle ID", build.bundleId ?? "-"],
|
|
23
|
-
["Git Ref", build.gitRef ?? "-"],
|
|
24
|
-
["Message", build.message ?? "-"],
|
|
25
|
-
[
|
|
26
|
-
"Artifact",
|
|
27
|
-
build.artifact
|
|
28
|
-
? `${build.artifact.format} (${String(build.artifact.byteSize)} bytes)`
|
|
29
|
-
: "none",
|
|
30
|
-
],
|
|
31
|
-
["Created", build.createdAt],
|
|
32
|
-
]);
|
|
33
|
-
}).pipe(handleBuildsCommandErrors),
|
|
34
|
-
);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console } from "effect";
|
|
3
|
-
|
|
4
|
-
import { compatibilityMatrixCommand } from "./compatibility-matrix";
|
|
5
|
-
import { deleteCommand } from "./delete";
|
|
6
|
-
import { getCommand } from "./get";
|
|
7
|
-
import { installLinkCommand } from "./install-link";
|
|
8
|
-
import { listCommand } from "./list";
|
|
9
|
-
|
|
10
|
-
export const buildsCommand = Command.make("builds", {}, () =>
|
|
11
|
-
Console.log("Manage builds. Run with --help for subcommands."),
|
|
12
|
-
).pipe(
|
|
13
|
-
Command.withSubcommands([
|
|
14
|
-
listCommand,
|
|
15
|
-
getCommand,
|
|
16
|
-
deleteCommand,
|
|
17
|
-
installLinkCommand,
|
|
18
|
-
compatibilityMatrixCommand,
|
|
19
|
-
]),
|
|
20
|
-
);
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { printKeyValue } from "../../lib/output";
|
|
5
|
-
import { apiClient } from "../../services/api-client";
|
|
6
|
-
import { handleBuildsCommandErrors } from "./helpers";
|
|
7
|
-
|
|
8
|
-
const id = Args.text({ name: "id" });
|
|
9
|
-
|
|
10
|
-
export const installLinkCommand = Command.make("install-link", { id }, (opts) =>
|
|
11
|
-
Effect.gen(function* () {
|
|
12
|
-
const api = yield* apiClient;
|
|
13
|
-
const result = yield* api.builds.getInstallLink({ path: { id: opts.id } });
|
|
14
|
-
yield* printKeyValue([
|
|
15
|
-
["Artifact URL", result.artifactUrl],
|
|
16
|
-
["Install URL", result.installUrl ?? "-"],
|
|
17
|
-
["Expires", String(result.expires)],
|
|
18
|
-
]);
|
|
19
|
-
}).pipe(handleBuildsCommandErrors),
|
|
20
|
-
);
|
|
@@ -1,38 +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 { printTable } from "../../lib/output";
|
|
6
|
-
import { apiClient } from "../../services/api-client";
|
|
7
|
-
import { handleBuildsCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
const platform = Options.choice("platform", ["ios", "android"]).pipe(Options.optional);
|
|
10
|
-
const limit = Options.integer("limit").pipe(Options.withDefault(10));
|
|
11
|
-
|
|
12
|
-
export const listCommand = Command.make("list", { platform, limit }, (opts) =>
|
|
13
|
-
Effect.gen(function* () {
|
|
14
|
-
const projectId = yield* readProjectId;
|
|
15
|
-
const api = yield* apiClient;
|
|
16
|
-
|
|
17
|
-
const platformFilter = Option.match(opts.platform, {
|
|
18
|
-
onNone: () => ({}) as Record<string, string>,
|
|
19
|
-
onSome: (platformValue) => ({ platform: platformValue }) as Record<string, string>,
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const { items } = yield* api.builds.list({
|
|
23
|
-
urlParams: { projectId, ...platformFilter, page: 1, limit: opts.limit },
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
yield* printTable(
|
|
27
|
-
["ID", "Platform", "Profile", "Distribution", "Version", "Created"],
|
|
28
|
-
items.map((build) => [
|
|
29
|
-
build.id,
|
|
30
|
-
build.platform,
|
|
31
|
-
build.profile,
|
|
32
|
-
build.distribution,
|
|
33
|
-
build.appVersion ?? "-",
|
|
34
|
-
build.createdAt,
|
|
35
|
-
]),
|
|
36
|
-
);
|
|
37
|
-
}).pipe(handleBuildsCommandErrors),
|
|
38
|
-
);
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Command, Options } from "@effect/cli";
|
|
2
|
-
import { Effect } 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 { handleChannelCommandErrors, resolveNamedResourceId } from "./helpers";
|
|
8
|
-
|
|
9
|
-
const name = Options.text("name");
|
|
10
|
-
const branch = Options.text("branch");
|
|
11
|
-
|
|
12
|
-
export const createCommand = Command.make("create", { name, branch }, (opts) =>
|
|
13
|
-
Effect.gen(function* () {
|
|
14
|
-
const projectId = yield* readProjectId;
|
|
15
|
-
const api = yield* apiClient;
|
|
16
|
-
|
|
17
|
-
const { items: branches } = yield* api.branches.list({
|
|
18
|
-
urlParams: { projectId, page: 1, limit: 1000 },
|
|
19
|
-
});
|
|
20
|
-
const branchId = yield* resolveNamedResourceId({
|
|
21
|
-
items: branches,
|
|
22
|
-
kind: "Branch",
|
|
23
|
-
name: opts.branch,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
const channel = yield* api.channels.create({
|
|
27
|
-
payload: { projectId, name: opts.name, branchId },
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
yield* printKeyValue([
|
|
31
|
-
["ID", channel.id],
|
|
32
|
-
["Name", channel.name],
|
|
33
|
-
["Branch", opts.branch],
|
|
34
|
-
["Created", channel.createdAt],
|
|
35
|
-
]);
|
|
36
|
-
}).pipe(handleChannelCommandErrors),
|
|
37
|
-
);
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { apiClient } from "../../services/api-client";
|
|
5
|
-
import { handleChannelCommandErrors } from "./helpers";
|
|
6
|
-
|
|
7
|
-
const id = Args.text({ name: "id" });
|
|
8
|
-
|
|
9
|
-
export const deleteCommand = Command.make("delete", { id }, (opts) =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const api = yield* apiClient;
|
|
12
|
-
yield* api.channels.delete({ path: { id: opts.id } });
|
|
13
|
-
yield* Console.log(`Channel ${opts.id} deleted.`);
|
|
14
|
-
}).pipe(handleChannelCommandErrors),
|
|
15
|
-
);
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Data } from "effect";
|
|
2
|
-
|
|
3
|
-
import { makeCommandErrorHandler } from "../../lib/command-errors";
|
|
4
|
-
import { resolveNamedResourceId as resolveNamedResourceIdBase } from "../../lib/resolve-named-resource";
|
|
5
|
-
|
|
6
|
-
export class ChannelCommandError extends Data.TaggedError("ChannelCommandError")<{
|
|
7
|
-
readonly message: string;
|
|
8
|
-
}> {}
|
|
9
|
-
|
|
10
|
-
export const handleChannelCommandErrors = makeCommandErrorHandler({
|
|
11
|
-
ChannelCommandError: 2,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export const resolveNamedResourceId = (params: {
|
|
15
|
-
readonly items: readonly { readonly id: string; readonly name: string }[];
|
|
16
|
-
readonly kind: string;
|
|
17
|
-
readonly name: string;
|
|
18
|
-
}) => resolveNamedResourceIdBase(params, (message) => new ChannelCommandError({ message }));
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console } from "effect";
|
|
3
|
-
|
|
4
|
-
import { createCommand } from "./create";
|
|
5
|
-
import { deleteCommand } from "./delete";
|
|
6
|
-
import { listCommand } from "./list";
|
|
7
|
-
import { pauseCommand } from "./pause";
|
|
8
|
-
import { resumeCommand } from "./resume";
|
|
9
|
-
import { rolloutCommand } from "./rollout";
|
|
10
|
-
import { updateCommand } from "./update";
|
|
11
|
-
|
|
12
|
-
export const channelsCommand = Command.make("channels", {}, () =>
|
|
13
|
-
Console.log("Manage channels. Run with --help for subcommands."),
|
|
14
|
-
).pipe(
|
|
15
|
-
Command.withSubcommands([
|
|
16
|
-
listCommand,
|
|
17
|
-
createCommand,
|
|
18
|
-
updateCommand,
|
|
19
|
-
pauseCommand,
|
|
20
|
-
resumeCommand,
|
|
21
|
-
deleteCommand,
|
|
22
|
-
rolloutCommand,
|
|
23
|
-
]),
|
|
24
|
-
);
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } 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 { handleChannelCommandErrors } from "./helpers";
|
|
8
|
-
|
|
9
|
-
export const listCommand = Command.make("list", {}, () =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const projectId = yield* readProjectId;
|
|
12
|
-
const api = yield* apiClient;
|
|
13
|
-
|
|
14
|
-
const [{ items }, { items: branches }] = yield* Effect.all([
|
|
15
|
-
api.channels.list({ urlParams: { projectId, page: 1, limit: 1000 } }),
|
|
16
|
-
api.branches.list({ urlParams: { projectId, page: 1, limit: 1000 } }),
|
|
17
|
-
]);
|
|
18
|
-
|
|
19
|
-
if (items.length === 0) {
|
|
20
|
-
yield* Console.log("No channels found.");
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const branchNames = new Map(branches.map((branch) => [branch.id, branch.name]));
|
|
25
|
-
|
|
26
|
-
yield* printTable(
|
|
27
|
-
["ID", "Name", "Branch", "Paused", "Rollout", "Created"],
|
|
28
|
-
items.map((channel) => [
|
|
29
|
-
channel.id,
|
|
30
|
-
channel.name,
|
|
31
|
-
branchNames.get(channel.branchId) ?? channel.branchId,
|
|
32
|
-
channel.isPaused ? "yes" : "no",
|
|
33
|
-
channel.branchMappingJson === null ? "-" : "active",
|
|
34
|
-
channel.createdAt,
|
|
35
|
-
]),
|
|
36
|
-
);
|
|
37
|
-
}).pipe(handleChannelCommandErrors),
|
|
38
|
-
);
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { apiClient } from "../../services/api-client";
|
|
5
|
-
import { handleChannelCommandErrors } from "./helpers";
|
|
6
|
-
|
|
7
|
-
const id = Args.text({ name: "id" });
|
|
8
|
-
|
|
9
|
-
export const pauseCommand = Command.make("pause", { id }, (opts) =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const api = yield* apiClient;
|
|
12
|
-
const channel = yield* api.channels.pause({ path: { id: opts.id } });
|
|
13
|
-
yield* Console.log(`Channel "${channel.name}" paused.`);
|
|
14
|
-
}).pipe(handleChannelCommandErrors),
|
|
15
|
-
);
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { apiClient } from "../../services/api-client";
|
|
5
|
-
import { handleChannelCommandErrors } from "./helpers";
|
|
6
|
-
|
|
7
|
-
const id = Args.text({ name: "id" });
|
|
8
|
-
|
|
9
|
-
export const resumeCommand = Command.make("resume", { id }, (opts) =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const api = yield* apiClient;
|
|
12
|
-
const channel = yield* api.channels.resume({ path: { id: opts.id } });
|
|
13
|
-
yield* Console.log(`Channel "${channel.name}" resumed.`);
|
|
14
|
-
}).pipe(handleChannelCommandErrors),
|
|
15
|
-
);
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { apiClient } from "../../../services/api-client";
|
|
5
|
-
import { handleChannelCommandErrors } from "../helpers";
|
|
6
|
-
|
|
7
|
-
const channelId = Args.text({ name: "channelId" });
|
|
8
|
-
|
|
9
|
-
export const completeCommand = Command.make("complete", { channelId }, (opts) =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const api = yield* apiClient;
|
|
12
|
-
const channel = yield* api.channels.completeBranchRollout({
|
|
13
|
-
path: { id: opts.channelId },
|
|
14
|
-
});
|
|
15
|
-
yield* Console.log(`Completed rollout on channel "${channel.name}".`);
|
|
16
|
-
}).pipe(handleChannelCommandErrors),
|
|
17
|
-
);
|
|
@@ -1,36 +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 { rolloutPercentageOption } from "../../../lib/cli-schemas";
|
|
6
|
-
import { apiClient } from "../../../services/api-client";
|
|
7
|
-
import { handleChannelCommandErrors, resolveNamedResourceId } from "../helpers";
|
|
8
|
-
|
|
9
|
-
const channelId = Args.text({ name: "channelId" });
|
|
10
|
-
const branch = Options.text("branch");
|
|
11
|
-
const percentage = rolloutPercentageOption("percentage");
|
|
12
|
-
|
|
13
|
-
export const createCommand = Command.make("create", { channelId, branch, percentage }, (opts) =>
|
|
14
|
-
Effect.gen(function* () {
|
|
15
|
-
const projectId = yield* readProjectId;
|
|
16
|
-
const api = yield* apiClient;
|
|
17
|
-
|
|
18
|
-
const { items: branches } = yield* api.branches.list({
|
|
19
|
-
urlParams: { projectId, page: 1, limit: 1000 },
|
|
20
|
-
});
|
|
21
|
-
const newBranchId = yield* resolveNamedResourceId({
|
|
22
|
-
items: branches,
|
|
23
|
-
kind: "Branch",
|
|
24
|
-
name: opts.branch,
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const channel = yield* api.channels.createBranchRollout({
|
|
28
|
-
path: { id: opts.channelId },
|
|
29
|
-
payload: { newBranchId, percentage: opts.percentage },
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
yield* Console.log(
|
|
33
|
-
`Started rollout on channel "${channel.name}" to branch "${opts.branch}" at ${String(opts.percentage)}%.`,
|
|
34
|
-
);
|
|
35
|
-
}).pipe(handleChannelCommandErrors),
|
|
36
|
-
);
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console } from "effect";
|
|
3
|
-
|
|
4
|
-
import { completeCommand } from "./complete";
|
|
5
|
-
import { createCommand } from "./create";
|
|
6
|
-
import { revertCommand } from "./revert";
|
|
7
|
-
import { updateCommand } from "./update";
|
|
8
|
-
|
|
9
|
-
export const rolloutCommand = Command.make("rollout", {}, () =>
|
|
10
|
-
Console.log("Manage channel branch rollouts. Run with --help for subcommands."),
|
|
11
|
-
).pipe(Command.withSubcommands([createCommand, updateCommand, completeCommand, revertCommand]));
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { apiClient } from "../../../services/api-client";
|
|
5
|
-
import { handleChannelCommandErrors } from "../helpers";
|
|
6
|
-
|
|
7
|
-
const channelId = Args.text({ name: "channelId" });
|
|
8
|
-
|
|
9
|
-
export const revertCommand = Command.make("revert", { channelId }, (opts) =>
|
|
10
|
-
Effect.gen(function* () {
|
|
11
|
-
const api = yield* apiClient;
|
|
12
|
-
const channel = yield* api.channels.revertBranchRollout({
|
|
13
|
-
path: { id: opts.channelId },
|
|
14
|
-
});
|
|
15
|
-
yield* Console.log(`Reverted rollout on channel "${channel.name}".`);
|
|
16
|
-
}).pipe(handleChannelCommandErrors),
|
|
17
|
-
);
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Args, Command } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { rolloutPercentageOption } from "../../../lib/cli-schemas";
|
|
5
|
-
import { apiClient } from "../../../services/api-client";
|
|
6
|
-
import { handleChannelCommandErrors } from "../helpers";
|
|
7
|
-
|
|
8
|
-
const channelId = Args.text({ name: "channelId" });
|
|
9
|
-
const percentage = rolloutPercentageOption("percentage");
|
|
10
|
-
|
|
11
|
-
export const updateCommand = Command.make("update", { channelId, percentage }, (opts) =>
|
|
12
|
-
Effect.gen(function* () {
|
|
13
|
-
const api = yield* apiClient;
|
|
14
|
-
const channel = yield* api.channels.updateBranchRollout({
|
|
15
|
-
path: { id: opts.channelId },
|
|
16
|
-
payload: { percentage: opts.percentage },
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
yield* Console.log(
|
|
20
|
-
`Updated rollout on channel "${channel.name}" to ${String(opts.percentage)}%.`,
|
|
21
|
-
);
|
|
22
|
-
}).pipe(handleChannelCommandErrors),
|
|
23
|
-
);
|
|
@@ -1,32 +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 { apiClient } from "../../services/api-client";
|
|
6
|
-
import { handleChannelCommandErrors, resolveNamedResourceId } from "./helpers";
|
|
7
|
-
|
|
8
|
-
const id = Args.text({ name: "id" });
|
|
9
|
-
const branch = Options.text("branch");
|
|
10
|
-
|
|
11
|
-
export const updateCommand = Command.make("update", { id, branch }, (opts) =>
|
|
12
|
-
Effect.gen(function* () {
|
|
13
|
-
const projectId = yield* readProjectId;
|
|
14
|
-
const api = yield* apiClient;
|
|
15
|
-
|
|
16
|
-
const { items: branches } = yield* api.branches.list({
|
|
17
|
-
urlParams: { projectId, page: 1, limit: 1000 },
|
|
18
|
-
});
|
|
19
|
-
const branchId = yield* resolveNamedResourceId({
|
|
20
|
-
items: branches,
|
|
21
|
-
kind: "Branch",
|
|
22
|
-
name: opts.branch,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const channel = yield* api.channels.update({
|
|
26
|
-
path: { id: opts.id },
|
|
27
|
-
payload: { branchId },
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
yield* Console.log(`Channel "${channel.name}" relinked to branch "${opts.branch}".`);
|
|
31
|
-
}).pipe(handleChannelCommandErrors),
|
|
32
|
-
);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Args, Command, Options } from "@effect/cli";
|
|
2
|
-
import { Console, Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
import { deleteCredential } from "../../lib/credentials-manager";
|
|
5
|
-
import { apiClient } from "../../services/api-client";
|
|
6
|
-
|
|
7
|
-
const id = Args.text({ name: "id" });
|
|
8
|
-
const platform = Options.choice("platform", ["ios", "android"] as const);
|
|
9
|
-
const type = Options.choice("type", [
|
|
10
|
-
"distribution-certificate",
|
|
11
|
-
"provisioning-profile",
|
|
12
|
-
"push-key",
|
|
13
|
-
"asc-api-key",
|
|
14
|
-
"keystore",
|
|
15
|
-
"google-service-account-key",
|
|
16
|
-
] as const);
|
|
17
|
-
|
|
18
|
-
export const deleteCommand = Command.make("delete", { id, platform, type }, (opts) =>
|
|
19
|
-
Effect.gen(function* () {
|
|
20
|
-
const api = yield* apiClient;
|
|
21
|
-
yield* deleteCredential(api, { id: opts.id, platform: opts.platform, type: opts.type });
|
|
22
|
-
yield* Console.log(`Credential ${opts.id} deleted.`);
|
|
23
|
-
}),
|
|
24
|
-
);
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { Command } from "@effect/cli";
|
|
2
|
-
import { Console } from "effect";
|
|
3
|
-
|
|
4
|
-
import { deleteCommand } from "./delete";
|
|
5
|
-
import { listCommand } from "./list";
|
|
6
|
-
import { uploadCommand } from "./upload";
|
|
7
|
-
|
|
8
|
-
export const credentialsCommand = Command.make("credentials", {}, () =>
|
|
9
|
-
Console.log("Manage credentials. Run with --help for subcommands."),
|
|
10
|
-
).pipe(Command.withSubcommands([listCommand, uploadCommand, deleteCommand]));
|