@capuchoo/cli 0.2.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/README.md +351 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +5 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +5 -0
- package/dist/base-command.d.ts +15 -0
- package/dist/base-command.d.ts.map +1 -0
- package/dist/base-command.js +61 -0
- package/dist/base-command.js.map +1 -0
- package/dist/commands/auth/login.d.ts +19 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +74 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/logout.d.ts +6 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +22 -0
- package/dist/commands/auth/logout.js.map +1 -0
- package/dist/commands/auth/whoami.d.ts +9 -0
- package/dist/commands/auth/whoami.d.ts.map +1 -0
- package/dist/commands/auth/whoami.js +77 -0
- package/dist/commands/auth/whoami.js.map +1 -0
- package/dist/commands/channel/list.d.ts +9 -0
- package/dist/commands/channel/list.d.ts.map +1 -0
- package/dist/commands/channel/list.js +47 -0
- package/dist/commands/channel/list.js.map +1 -0
- package/dist/commands/config/list.d.ts +9 -0
- package/dist/commands/config/list.d.ts.map +1 -0
- package/dist/commands/config/list.js +116 -0
- package/dist/commands/config/list.js.map +1 -0
- package/dist/commands/config/set.d.ts +11 -0
- package/dist/commands/config/set.d.ts.map +1 -0
- package/dist/commands/config/set.js +44 -0
- package/dist/commands/config/set.js.map +1 -0
- package/dist/commands/deploy/native.d.ts +23 -0
- package/dist/commands/deploy/native.d.ts.map +1 -0
- package/dist/commands/deploy/native.js +39 -0
- package/dist/commands/deploy/native.js.map +1 -0
- package/dist/commands/deploy/ota.d.ts +20 -0
- package/dist/commands/deploy/ota.d.ts.map +1 -0
- package/dist/commands/deploy/ota.js +20 -0
- package/dist/commands/deploy/ota.js.map +1 -0
- package/dist/commands/init.d.ts +17 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +232 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/version/bump.d.ts +13 -0
- package/dist/commands/version/bump.d.ts.map +1 -0
- package/dist/commands/version/bump.js +52 -0
- package/dist/commands/version/bump.js.map +1 -0
- package/dist/commands/version/sync.d.ts +12 -0
- package/dist/commands/version/sync.d.ts.map +1 -0
- package/dist/commands/version/sync.js +81 -0
- package/dist/commands/version/sync.js.map +1 -0
- package/dist/deploy/execute.d.ts +48 -0
- package/dist/deploy/execute.d.ts.map +1 -0
- package/dist/deploy/execute.js +280 -0
- package/dist/deploy/execute.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/pipeline/android.d.ts +37 -0
- package/dist/pipeline/android.d.ts.map +1 -0
- package/dist/pipeline/android.js +96 -0
- package/dist/pipeline/android.js.map +1 -0
- package/dist/pipeline/build.d.ts +69 -0
- package/dist/pipeline/build.d.ts.map +1 -0
- package/dist/pipeline/build.js +138 -0
- package/dist/pipeline/build.js.map +1 -0
- package/dist/pipeline/deploy.d.ts +74 -0
- package/dist/pipeline/deploy.d.ts.map +1 -0
- package/dist/pipeline/deploy.js +198 -0
- package/dist/pipeline/deploy.js.map +1 -0
- package/dist/pipeline/flavour.d.ts +66 -0
- package/dist/pipeline/flavour.d.ts.map +1 -0
- package/dist/pipeline/flavour.js +120 -0
- package/dist/pipeline/flavour.js.map +1 -0
- package/dist/pipeline/native-config.d.ts +43 -0
- package/dist/pipeline/native-config.d.ts.map +1 -0
- package/dist/pipeline/native-config.js +127 -0
- package/dist/pipeline/native-config.js.map +1 -0
- package/dist/pipeline/toolchain.d.ts +80 -0
- package/dist/pipeline/toolchain.d.ts.map +1 -0
- package/dist/pipeline/toolchain.js +146 -0
- package/dist/pipeline/toolchain.js.map +1 -0
- package/dist/pipeline/zip.d.ts +22 -0
- package/dist/pipeline/zip.d.ts.map +1 -0
- package/dist/pipeline/zip.js +188 -0
- package/dist/pipeline/zip.js.map +1 -0
- package/dist/services/cloud.d.ts +58 -0
- package/dist/services/cloud.d.ts.map +1 -0
- package/dist/services/cloud.js +89 -0
- package/dist/services/cloud.js.map +1 -0
- package/dist/utils/config.d.ts +52 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +144 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/exec.d.ts +44 -0
- package/dist/utils/exec.d.ts.map +1 -0
- package/dist/utils/exec.js +136 -0
- package/dist/utils/exec.js.map +1 -0
- package/dist/utils/http.d.ts +37 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +137 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/reporter.d.ts +48 -0
- package/dist/utils/reporter.d.ts.map +1 -0
- package/dist/utils/reporter.js +108 -0
- package/dist/utils/reporter.js.map +1 -0
- package/oclif.manifest.json +568 -0
- package/package.json +81 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
|
2
|
+
import { bumpVersion } from "@capuchoo/core";
|
|
3
|
+
import { Command, Flags } from "@oclif/core";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { describeFailure, formatBytes, runDeploy, } from "../pipeline/deploy.js";
|
|
8
|
+
import { CloudClient } from "../services/cloud.js";
|
|
9
|
+
import { readAppVersion, requireProjectConfig, resolveCredentials, writeAppVersion, } from "../utils/config.js";
|
|
10
|
+
import { Reporter } from "../utils/reporter.js";
|
|
11
|
+
/**
|
|
12
|
+
* Shared implementation for `deploy ota` and `deploy native`.
|
|
13
|
+
*
|
|
14
|
+
* The two commands were previously separate 300-line files that differed in
|
|
15
|
+
* about twenty lines. Every fix had to be applied twice, and in practice was
|
|
16
|
+
* not: the OTA path never sent `version_code`, so the backend could not
|
|
17
|
+
* evaluate a bundle's `min_update_version` gate for it, while the native path
|
|
18
|
+
* did.
|
|
19
|
+
*/
|
|
20
|
+
/** Flags both deploy commands accept. */
|
|
21
|
+
export const commonDeployFlags = {
|
|
22
|
+
channel: Flags.string({
|
|
23
|
+
char: "c",
|
|
24
|
+
description: "Channel to publish to. Its environment selects the flavour.",
|
|
25
|
+
}),
|
|
26
|
+
note: Flags.string({ char: "n", description: "Release notes shown to users" }),
|
|
27
|
+
version: Flags.string({
|
|
28
|
+
char: "v",
|
|
29
|
+
description: "Bump the app version before publishing",
|
|
30
|
+
options: ["major", "minor", "patch"],
|
|
31
|
+
}),
|
|
32
|
+
active: Flags.boolean({
|
|
33
|
+
char: "a",
|
|
34
|
+
allowNo: true,
|
|
35
|
+
description: "Serve this release immediately",
|
|
36
|
+
}),
|
|
37
|
+
required: Flags.boolean({
|
|
38
|
+
char: "r",
|
|
39
|
+
allowNo: true,
|
|
40
|
+
description: "Users cannot postpone this release",
|
|
41
|
+
}),
|
|
42
|
+
"skip-assets": Flags.boolean({
|
|
43
|
+
default: false,
|
|
44
|
+
description: "Do not regenerate launcher icons",
|
|
45
|
+
}),
|
|
46
|
+
"skip-build": Flags.boolean({
|
|
47
|
+
default: false,
|
|
48
|
+
description: "Publish the existing build output as-is",
|
|
49
|
+
}),
|
|
50
|
+
"dry-run": Flags.boolean({
|
|
51
|
+
default: false,
|
|
52
|
+
description: "Build and package, but upload nothing",
|
|
53
|
+
}),
|
|
54
|
+
json: Flags.boolean({
|
|
55
|
+
default: false,
|
|
56
|
+
description: "Emit a machine-readable result on stdout",
|
|
57
|
+
}),
|
|
58
|
+
verbose: Flags.boolean({
|
|
59
|
+
default: false,
|
|
60
|
+
description: "Stream build output to the terminal",
|
|
61
|
+
}),
|
|
62
|
+
yes: Flags.boolean({
|
|
63
|
+
char: "y",
|
|
64
|
+
default: false,
|
|
65
|
+
description: "Accept every prompt - required in CI",
|
|
66
|
+
}),
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* `Command#error` always throws at runtime, but its overload set resolves to
|
|
70
|
+
* `void` when called with a bare string, so TypeScript does not narrow after a
|
|
71
|
+
* call and every following access looks possibly-null. This restores the `never`
|
|
72
|
+
* the runtime actually has.
|
|
73
|
+
*/
|
|
74
|
+
function fail(command, message) {
|
|
75
|
+
command.error(message);
|
|
76
|
+
throw new Error(message); // unreachable
|
|
77
|
+
}
|
|
78
|
+
export async function executeDeploy(options) {
|
|
79
|
+
const { kind, command, flags } = options;
|
|
80
|
+
const appDir = process.cwd();
|
|
81
|
+
const json = flags.json;
|
|
82
|
+
// In JSON mode stdout carries only the result document, so every human-facing
|
|
83
|
+
// line goes to stderr. Non-interactive shells get the same treatment.
|
|
84
|
+
const reporter = new Reporter({ quiet: json || !process.stdout.isTTY });
|
|
85
|
+
const project = requireProjectConfig(appDir);
|
|
86
|
+
const credentials = resolveCredentials();
|
|
87
|
+
if (!credentials) {
|
|
88
|
+
fail(command, "Not authenticated. Run " +
|
|
89
|
+
chalk.cyan("capuchoo auth login") +
|
|
90
|
+
", or set CAPUCHO_ENDPOINT and CAPUCHO_API_KEY.");
|
|
91
|
+
}
|
|
92
|
+
const cloud = new CloudClient(credentials.endpoint, credentials.apiKey);
|
|
93
|
+
const profile = await cloud.whoami();
|
|
94
|
+
if (!profile) {
|
|
95
|
+
fail(command, `The credentials for ${credentials.endpoint} were rejected. ` +
|
|
96
|
+
(credentials.source === "environment"
|
|
97
|
+
? "Check CAPUCHO_API_KEY."
|
|
98
|
+
: `Run ${chalk.cyan("capuchoo auth login")} again.`));
|
|
99
|
+
}
|
|
100
|
+
if (!json) {
|
|
101
|
+
command.log("");
|
|
102
|
+
command.log(chalk.bold(`Capucho ${kind === "ota" ? "OTA" : "native"} deploy`));
|
|
103
|
+
command.log(chalk.dim(` app ${project.appName} (${project.appId})`));
|
|
104
|
+
command.log(chalk.dim(` account ${profile.user.email}`));
|
|
105
|
+
command.log(chalk.dim(` endpoint ${credentials.endpoint}`));
|
|
106
|
+
command.log("");
|
|
107
|
+
}
|
|
108
|
+
// --- channel, and therefore environment ------------------------------------
|
|
109
|
+
let channelName = flags.channel;
|
|
110
|
+
if (!channelName) {
|
|
111
|
+
if (flags.yes || json) {
|
|
112
|
+
fail(command, "--channel is required when running non-interactively.");
|
|
113
|
+
}
|
|
114
|
+
const channels = await cloud.channels(project.cloudAppId);
|
|
115
|
+
const deployable = channels.filter((channel) => channel.environment);
|
|
116
|
+
if (deployable.length === 0) {
|
|
117
|
+
fail(command, "This app has no channel with an environment set. Create one in the dashboard.");
|
|
118
|
+
}
|
|
119
|
+
channelName = await select({
|
|
120
|
+
message: "Channel",
|
|
121
|
+
choices: deployable.map((channel) => ({
|
|
122
|
+
name: `${channel.name} ${chalk.dim(`(${channel.environment})`)}`,
|
|
123
|
+
value: channel.name,
|
|
124
|
+
})),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const channel = await cloud.requireChannel(project.cloudAppId, channelName);
|
|
128
|
+
const environment = channel.environment;
|
|
129
|
+
// --- release options -------------------------------------------------------
|
|
130
|
+
const interactive = !flags.yes && !json;
|
|
131
|
+
const active = flags.active ??
|
|
132
|
+
(interactive ? await confirm({ message: "Serve immediately?", default: true }) : true);
|
|
133
|
+
const required = flags.required ??
|
|
134
|
+
(interactive ? await confirm({ message: "Mark as required?", default: false }) : false);
|
|
135
|
+
let bump = flags.version;
|
|
136
|
+
if (!bump && interactive) {
|
|
137
|
+
const answer = await select({
|
|
138
|
+
message: "Bump the version?",
|
|
139
|
+
choices: [
|
|
140
|
+
{ name: "No bump", value: "" },
|
|
141
|
+
{ name: "patch", value: "patch" },
|
|
142
|
+
{ name: "minor", value: "minor" },
|
|
143
|
+
{ name: "major", value: "major" },
|
|
144
|
+
],
|
|
145
|
+
default: "",
|
|
146
|
+
});
|
|
147
|
+
bump = answer === "" ? undefined : answer;
|
|
148
|
+
}
|
|
149
|
+
const note = flags.note ?? (interactive ? await input({ message: "Release notes (optional)" }) : "");
|
|
150
|
+
const currentVersion = readAppVersion(appDir);
|
|
151
|
+
const version = bump ? bumpVersion(currentVersion, bump) : currentVersion;
|
|
152
|
+
const buildType = (flags.type ?? "release");
|
|
153
|
+
const platform = (flags.platform ?? "android");
|
|
154
|
+
// --- confirmation ----------------------------------------------------------
|
|
155
|
+
if (interactive) {
|
|
156
|
+
command.log("");
|
|
157
|
+
command.log(chalk.dim(" ─────────────────────────────────────────"));
|
|
158
|
+
command.log(` channel ${chalk.green(channel.name)} (${environment})`);
|
|
159
|
+
command.log(` version ${chalk.green(version)}${bump ? chalk.dim(` (${bump} from ${currentVersion})`) : ""}`);
|
|
160
|
+
if (kind === "native") {
|
|
161
|
+
command.log(` platform ${chalk.green(platform)} / ${buildType}`);
|
|
162
|
+
}
|
|
163
|
+
command.log(` serve now ${active ? chalk.green("yes") : "no"}`);
|
|
164
|
+
command.log(` required ${required ? chalk.yellow("yes") : "no"}`);
|
|
165
|
+
if (flags["dry-run"])
|
|
166
|
+
command.log(` ${chalk.yellow("dry run - nothing is uploaded")}`);
|
|
167
|
+
command.log(chalk.dim(" ─────────────────────────────────────────"));
|
|
168
|
+
command.log("");
|
|
169
|
+
const proceed = await confirm({ message: "Deploy?", default: true });
|
|
170
|
+
if (!proceed) {
|
|
171
|
+
command.log(chalk.dim("Cancelled."));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// The version is written only after confirmation, so an abandoned prompt
|
|
176
|
+
// leaves package.json untouched.
|
|
177
|
+
if (bump)
|
|
178
|
+
writeAppVersion(appDir, version);
|
|
179
|
+
const request = {
|
|
180
|
+
appDir,
|
|
181
|
+
project,
|
|
182
|
+
kind,
|
|
183
|
+
platform,
|
|
184
|
+
channel: channel.name,
|
|
185
|
+
environment,
|
|
186
|
+
version,
|
|
187
|
+
buildType,
|
|
188
|
+
skipAssets: flags["skip-assets"],
|
|
189
|
+
skipBuild: flags["skip-build"],
|
|
190
|
+
allowUnsigned: flags["allow-unsigned"] ?? false,
|
|
191
|
+
dryRun: flags["dry-run"],
|
|
192
|
+
verbose: flags.verbose,
|
|
193
|
+
quiet: json,
|
|
194
|
+
};
|
|
195
|
+
try {
|
|
196
|
+
const outcome = await runDeploy(request, reporter);
|
|
197
|
+
const artifact = outcome.artifact;
|
|
198
|
+
if (!artifact)
|
|
199
|
+
throw new Error("The pipeline produced no artefact");
|
|
200
|
+
let uploaded = false;
|
|
201
|
+
if (!flags["dry-run"]) {
|
|
202
|
+
reporter.begin("upload");
|
|
203
|
+
const result = kind === "ota"
|
|
204
|
+
? await cloud.uploadBundle({
|
|
205
|
+
filePath: artifact.filePath,
|
|
206
|
+
appId: project.appId,
|
|
207
|
+
channel: channel.name,
|
|
208
|
+
platform,
|
|
209
|
+
versionName: outcome.version,
|
|
210
|
+
releaseNotes: note ?? "",
|
|
211
|
+
active,
|
|
212
|
+
required,
|
|
213
|
+
})
|
|
214
|
+
: await cloud.uploadNative({
|
|
215
|
+
filePath: artifact.filePath,
|
|
216
|
+
appId: project.appId,
|
|
217
|
+
channel: channel.name,
|
|
218
|
+
platform,
|
|
219
|
+
versionName: outcome.version,
|
|
220
|
+
versionCode: outcome.versionCode,
|
|
221
|
+
releaseNotes: note ?? "",
|
|
222
|
+
active,
|
|
223
|
+
required,
|
|
224
|
+
});
|
|
225
|
+
uploaded = result.status >= 200 && result.status < 300;
|
|
226
|
+
reporter.note(`${formatBytes(artifact.byteSize)} accepted`);
|
|
227
|
+
// The OTA archive is a build artefact; the APK is not - it may be needed
|
|
228
|
+
// for a store submission, so it stays.
|
|
229
|
+
if (uploaded && kind === "ota") {
|
|
230
|
+
fs.rmSync(artifact.filePath, { force: true });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
reporter.finish(flags["dry-run"]
|
|
234
|
+
? `Dry run complete - v${outcome.version} was built but not uploaded`
|
|
235
|
+
: `v${outcome.version} published to "${channel.name}"`);
|
|
236
|
+
for (const warning of outcome.warnings) {
|
|
237
|
+
process.stderr.write(`${chalk.yellow("!")} ${warning}\n`);
|
|
238
|
+
}
|
|
239
|
+
if (json) {
|
|
240
|
+
// stdout carries the result document and nothing else.
|
|
241
|
+
command.log(JSON.stringify({
|
|
242
|
+
ok: true,
|
|
243
|
+
kind,
|
|
244
|
+
version: outcome.version,
|
|
245
|
+
versionCode: outcome.versionCode,
|
|
246
|
+
channel: channel.name,
|
|
247
|
+
environment: outcome.environment,
|
|
248
|
+
platform,
|
|
249
|
+
uploaded,
|
|
250
|
+
dryRun: flags["dry-run"],
|
|
251
|
+
artifact: {
|
|
252
|
+
path: flags["dry-run"] ? artifact.filePath : undefined,
|
|
253
|
+
bytes: artifact.byteSize,
|
|
254
|
+
files: artifact.fileCount,
|
|
255
|
+
signed: artifact.signed,
|
|
256
|
+
},
|
|
257
|
+
nativeConfig: outcome.nativeConfigMethod,
|
|
258
|
+
skipped: outcome.skipped,
|
|
259
|
+
warnings: outcome.warnings,
|
|
260
|
+
}, null, 2));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
const message = describeFailure(error, appDir);
|
|
265
|
+
reporter.fail("Deploy failed");
|
|
266
|
+
if (json) {
|
|
267
|
+
command.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
268
|
+
process.exitCode = 1;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (bump) {
|
|
272
|
+
// Say so explicitly: the file on disk no longer matches what is
|
|
273
|
+
// published, and a silent mismatch is how a version gets skipped.
|
|
274
|
+
process.stderr.write(chalk.yellow(`\n! package.json was already bumped to ${version}. ` +
|
|
275
|
+
`Revert it with: git checkout -- ${path.join(".", "package.json")}\n`));
|
|
276
|
+
}
|
|
277
|
+
command.error(message);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/deploy/execute.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type RunOptions } from "../utils/exec.js";
|
|
2
|
+
/**
|
|
3
|
+
* Android compilation and artefact discovery.
|
|
4
|
+
*
|
|
5
|
+
* The important addition here is the signature check. `assembleRelease` on a
|
|
6
|
+
* project with no `signingConfig` succeeds and writes
|
|
7
|
+
* `app-release-unsigned.apk`. The old `findApk` accepted any `.apk` in the
|
|
8
|
+
* variant directory, so the CLI happily uploaded an unsigned APK as a release -
|
|
9
|
+
* and Android refuses to install it. The failure only showed up on a user's
|
|
10
|
+
* phone, days later.
|
|
11
|
+
*/
|
|
12
|
+
export type BuildType = "debug" | "release";
|
|
13
|
+
export interface AndroidBuildResult {
|
|
14
|
+
apkPath: string;
|
|
15
|
+
signed: boolean;
|
|
16
|
+
byteSize: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function assembleAndroid(androidDir: string, buildType: BuildType, options: Omit<RunOptions, "cwd">): Promise<void>;
|
|
19
|
+
/** Finds the APK produced for a variant. */
|
|
20
|
+
export declare function findApk(androidDir: string, buildType: BuildType): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Reports whether an APK carries a signature block.
|
|
23
|
+
*
|
|
24
|
+
* An APK is a zip; a signed one contains either a v1 signature
|
|
25
|
+
* (`META-INF/*.RSA|DSA|EC`) or a v2/v3 "APK Sig Block 42" magic before the
|
|
26
|
+
* central directory. Checking both covers modern and legacy signing without
|
|
27
|
+
* needing apksigner on PATH.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isApkSigned(apkPath: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Locates the build artefact and refuses an unsigned release.
|
|
32
|
+
*
|
|
33
|
+
* `allowUnsigned` exists for the case where signing happens later in a separate
|
|
34
|
+
* pipeline stage, but it has to be asked for explicitly.
|
|
35
|
+
*/
|
|
36
|
+
export declare function collectAndroidArtifact(androidDir: string, buildType: BuildType, allowUnsigned: boolean): AndroidBuildResult;
|
|
37
|
+
//# sourceMappingURL=android.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../src/pipeline/android.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAExD;;;;;;;;;GASG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;AAE5C,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAuBD,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,4CAA4C;AAC5C,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAuB/E;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWpD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,OAAO,GACrB,kBAAkB,CAsBpB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { run } from "../utils/exec.js";
|
|
4
|
+
function gradleWrapper(androidDir) {
|
|
5
|
+
const name = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
6
|
+
const wrapper = path.join(androidDir, name);
|
|
7
|
+
if (!fs.existsSync(wrapper)) {
|
|
8
|
+
throw new Error(`No Gradle wrapper at ${wrapper}. Run "cap add android" in the app first.`);
|
|
9
|
+
}
|
|
10
|
+
// Gradle's wrapper must be executable; a fresh git clone on Unix sometimes
|
|
11
|
+
// loses the bit.
|
|
12
|
+
if (process.platform !== "win32") {
|
|
13
|
+
try {
|
|
14
|
+
fs.accessSync(wrapper, fs.constants.X_OK);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
fs.chmodSync(wrapper, 0o755);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return process.platform === "win32" ? wrapper : `./${name}`;
|
|
21
|
+
}
|
|
22
|
+
export async function assembleAndroid(androidDir, buildType, options) {
|
|
23
|
+
const task = buildType === "release" ? "assembleRelease" : "assembleDebug";
|
|
24
|
+
await run(gradleWrapper(androidDir), [task], {
|
|
25
|
+
...options,
|
|
26
|
+
cwd: androidDir,
|
|
27
|
+
// Gradle on a cold cache legitimately takes a long time; 30 minutes is
|
|
28
|
+
// generous rather than a hang.
|
|
29
|
+
timeoutMs: 30 * 60 * 1000,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Finds the APK produced for a variant. */
|
|
33
|
+
export function findApk(androidDir, buildType) {
|
|
34
|
+
const variantDir = path.join(androidDir, "app", "build", "outputs", "apk", buildType);
|
|
35
|
+
if (!fs.existsSync(variantDir))
|
|
36
|
+
return null;
|
|
37
|
+
const found = [];
|
|
38
|
+
const walk = (dir) => {
|
|
39
|
+
for (const item of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
40
|
+
const absolute = path.join(dir, item.name);
|
|
41
|
+
if (item.isDirectory()) {
|
|
42
|
+
walk(absolute);
|
|
43
|
+
}
|
|
44
|
+
else if (item.name.endsWith(".apk") && !item.name.includes("androidTest")) {
|
|
45
|
+
found.push({ file: absolute, mtime: fs.statSync(absolute).mtimeMs });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
walk(variantDir);
|
|
50
|
+
if (found.length === 0)
|
|
51
|
+
return null;
|
|
52
|
+
// Newest wins - a stale APK from a previous variant can linger here.
|
|
53
|
+
found.sort((a, b) => b.mtime - a.mtime);
|
|
54
|
+
return found[0].file;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Reports whether an APK carries a signature block.
|
|
58
|
+
*
|
|
59
|
+
* An APK is a zip; a signed one contains either a v1 signature
|
|
60
|
+
* (`META-INF/*.RSA|DSA|EC`) or a v2/v3 "APK Sig Block 42" magic before the
|
|
61
|
+
* central directory. Checking both covers modern and legacy signing without
|
|
62
|
+
* needing apksigner on PATH.
|
|
63
|
+
*/
|
|
64
|
+
export function isApkSigned(apkPath) {
|
|
65
|
+
const contents = fs.readFileSync(apkPath);
|
|
66
|
+
// v2/v3: the APK Signing Block sits just before the central directory and is
|
|
67
|
+
// terminated by this 16-byte magic.
|
|
68
|
+
if (contents.includes(Buffer.from("APK Sig Block 42", "latin1")))
|
|
69
|
+
return true;
|
|
70
|
+
// v1: JAR signing puts the certificate in META-INF. Entry names appear in the
|
|
71
|
+
// central directory as plain text, so a substring scan is sufficient.
|
|
72
|
+
const text = contents.toString("latin1");
|
|
73
|
+
return /META-INF\/[^/]+\.(RSA|DSA|EC)/.test(text);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Locates the build artefact and refuses an unsigned release.
|
|
77
|
+
*
|
|
78
|
+
* `allowUnsigned` exists for the case where signing happens later in a separate
|
|
79
|
+
* pipeline stage, but it has to be asked for explicitly.
|
|
80
|
+
*/
|
|
81
|
+
export function collectAndroidArtifact(androidDir, buildType, allowUnsigned) {
|
|
82
|
+
const apkPath = findApk(androidDir, buildType);
|
|
83
|
+
if (!apkPath) {
|
|
84
|
+
throw new Error(`Gradle reported success but no ${buildType} APK exists under ` +
|
|
85
|
+
`${path.join(androidDir, "app/build/outputs/apk", buildType)}.`);
|
|
86
|
+
}
|
|
87
|
+
const signed = isApkSigned(apkPath);
|
|
88
|
+
if (buildType === "release" && !signed && !allowUnsigned) {
|
|
89
|
+
throw new Error(`${path.basename(apkPath)} is not signed, so Android will refuse to install it.\n` +
|
|
90
|
+
" Add a release signingConfig to android/app/build.gradle and provide the\n" +
|
|
91
|
+
" keystore, build with --type debug, or pass --allow-unsigned if this\n" +
|
|
92
|
+
" artefact is signed later in your pipeline.");
|
|
93
|
+
}
|
|
94
|
+
return { apkPath, signed, byteSize: fs.statSync(apkPath).size };
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=android.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/pipeline/android.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type RunOptions } from "../utils/exec.js";
|
|
2
|
+
import type { ResolvedFlavour } from "./flavour.js";
|
|
3
|
+
import { type Toolchain } from "./toolchain.js";
|
|
4
|
+
/**
|
|
5
|
+
* The web build, icon generation and Capacitor sync.
|
|
6
|
+
*
|
|
7
|
+
* Every step here resolves its own executable out of `node_modules/.bin` rather
|
|
8
|
+
* than going through a package.json script. The old pipeline ran
|
|
9
|
+
* `pnpm run assets:<env>`, `pnpm build:<env>` and `pnpm exec cap sync`, which
|
|
10
|
+
* meant an application had to define scripts with exactly those names, use
|
|
11
|
+
* pnpm, and duplicate the flavour wiring in every one of them - the same
|
|
12
|
+
* `dotenv -e build/<env>/.env.<env> --` prefix repeated a dozen times, drifting
|
|
13
|
+
* a little each time.
|
|
14
|
+
*/
|
|
15
|
+
export interface StepContext {
|
|
16
|
+
toolchain: Toolchain;
|
|
17
|
+
flavour: ResolvedFlavour;
|
|
18
|
+
/** Flavour values plus the resolved version. */
|
|
19
|
+
env: Record<string, string>;
|
|
20
|
+
runOptions: Omit<RunOptions, "cwd" | "env">;
|
|
21
|
+
}
|
|
22
|
+
export type StepOutcome = {
|
|
23
|
+
ran: true;
|
|
24
|
+
via: string;
|
|
25
|
+
} | {
|
|
26
|
+
ran: false;
|
|
27
|
+
reason: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Generates launcher icons and splash screens.
|
|
31
|
+
*
|
|
32
|
+
* Optional by design: icons rarely change and an app may not ship source
|
|
33
|
+
* artwork at all, so a missing tool or asset directory is a skip, not a
|
|
34
|
+
* failure.
|
|
35
|
+
*/
|
|
36
|
+
export declare function generateAssets(context: StepContext, platform: "android" | "ios"): Promise<StepOutcome>;
|
|
37
|
+
/**
|
|
38
|
+
* Builds the web assets.
|
|
39
|
+
*
|
|
40
|
+
* Resolution order, most explicit first:
|
|
41
|
+
* 1. `build.command` in project.json - the app has said exactly what to run.
|
|
42
|
+
* 2. A `build:<mode>` script, if the app already has one that works.
|
|
43
|
+
* 3. Vite directly, with `--mode <flavour>`.
|
|
44
|
+
*
|
|
45
|
+
* The flavour's variables are passed as environment rather than through
|
|
46
|
+
* `dotenv-cli`, so no extra dependency is needed and the values are identical
|
|
47
|
+
* to the ones the native configuration step receives.
|
|
48
|
+
*/
|
|
49
|
+
export declare function buildWeb(context: StepContext, build: {
|
|
50
|
+
command?: string;
|
|
51
|
+
cwd?: string;
|
|
52
|
+
}): Promise<StepOutcome>;
|
|
53
|
+
/**
|
|
54
|
+
* Copies the built web assets into the native project and updates plugins.
|
|
55
|
+
*
|
|
56
|
+
* Runs after the native configuration step, because `cap sync` regenerates
|
|
57
|
+
* plugin registration files and rewriting the identity afterwards would leave
|
|
58
|
+
* those pointing at the previous package name.
|
|
59
|
+
*/
|
|
60
|
+
export declare function syncCapacitor(context: StepContext, platform: "android" | "ios"): Promise<StepOutcome>;
|
|
61
|
+
/**
|
|
62
|
+
* Splits a command string into argv, honouring quoted segments.
|
|
63
|
+
*
|
|
64
|
+
* Needed because `build.command` comes from a config file as one string. The
|
|
65
|
+
* previous code passed such strings straight to a shell, so a path containing a
|
|
66
|
+
* space became two arguments.
|
|
67
|
+
*/
|
|
68
|
+
export declare function tokenize(command: string): string[];
|
|
69
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/pipeline/build.ts"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAExE;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,eAAe,CAAC;IACzB,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC;CAC7C;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,GAAG,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,SAAS,GAAG,KAAK,GAC1B,OAAO,CAAC,WAAW,CAAC,CA8BtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,WAAW,CAAC,CAsCtB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,SAAS,GAAG,KAAK,GAC1B,OAAO,CAAC,WAAW,CAAC,CAatB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAkClD"}
|