@ship-et/buildatlas-cli 0.0.0-stage → 0.12.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.
Files changed (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +81 -2
  3. package/dist/browser-login.d.ts +12 -0
  4. package/dist/browser-login.d.ts.map +1 -0
  5. package/dist/browser-login.js +94 -0
  6. package/dist/browser-login.js.map +1 -0
  7. package/dist/client.d.ts +33 -0
  8. package/dist/client.d.ts.map +1 -0
  9. package/dist/client.js +164 -0
  10. package/dist/client.js.map +1 -0
  11. package/dist/client.test.d.ts +2 -0
  12. package/dist/client.test.d.ts.map +1 -0
  13. package/dist/client.test.js +158 -0
  14. package/dist/client.test.js.map +1 -0
  15. package/dist/commands/auth.d.ts +3 -0
  16. package/dist/commands/auth.d.ts.map +1 -0
  17. package/dist/commands/auth.js +88 -0
  18. package/dist/commands/auth.js.map +1 -0
  19. package/dist/commands/build.d.ts +4 -0
  20. package/dist/commands/build.d.ts.map +1 -0
  21. package/dist/commands/build.js +362 -0
  22. package/dist/commands/build.js.map +1 -0
  23. package/dist/commands/builds.d.ts +3 -0
  24. package/dist/commands/builds.d.ts.map +1 -0
  25. package/dist/commands/builds.js +102 -0
  26. package/dist/commands/builds.js.map +1 -0
  27. package/dist/commands/credentials-wizard.d.ts +25 -0
  28. package/dist/commands/credentials-wizard.d.ts.map +1 -0
  29. package/dist/commands/credentials-wizard.js +274 -0
  30. package/dist/commands/credentials-wizard.js.map +1 -0
  31. package/dist/commands/credentials.d.ts +3 -0
  32. package/dist/commands/credentials.d.ts.map +1 -0
  33. package/dist/commands/credentials.js +249 -0
  34. package/dist/commands/credentials.js.map +1 -0
  35. package/dist/commands/env.d.ts +37 -0
  36. package/dist/commands/env.d.ts.map +1 -0
  37. package/dist/commands/env.js +220 -0
  38. package/dist/commands/env.js.map +1 -0
  39. package/dist/commands/expo-tokens.d.ts +3 -0
  40. package/dist/commands/expo-tokens.d.ts.map +1 -0
  41. package/dist/commands/expo-tokens.js +103 -0
  42. package/dist/commands/expo-tokens.js.map +1 -0
  43. package/dist/commands/init.d.ts +6 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +204 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/projects.d.ts +11 -0
  48. package/dist/commands/projects.d.ts.map +1 -0
  49. package/dist/commands/projects.js +148 -0
  50. package/dist/commands/projects.js.map +1 -0
  51. package/dist/commands/submit.d.ts +10 -0
  52. package/dist/commands/submit.d.ts.map +1 -0
  53. package/dist/commands/submit.js +118 -0
  54. package/dist/commands/submit.js.map +1 -0
  55. package/dist/commands/update.d.ts +10 -0
  56. package/dist/commands/update.d.ts.map +1 -0
  57. package/dist/commands/update.js +93 -0
  58. package/dist/commands/update.js.map +1 -0
  59. package/dist/config.d.ts +66 -0
  60. package/dist/config.d.ts.map +1 -0
  61. package/dist/config.js +255 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/detach.d.ts +18 -0
  64. package/dist/detach.d.ts.map +1 -0
  65. package/dist/detach.js +42 -0
  66. package/dist/detach.js.map +1 -0
  67. package/dist/eas-credentials-zip.d.ts +38 -0
  68. package/dist/eas-credentials-zip.d.ts.map +1 -0
  69. package/dist/eas-credentials-zip.js +63 -0
  70. package/dist/eas-credentials-zip.js.map +1 -0
  71. package/dist/eas-json.d.ts +21 -0
  72. package/dist/eas-json.d.ts.map +1 -0
  73. package/dist/eas-json.js +32 -0
  74. package/dist/eas-json.js.map +1 -0
  75. package/dist/index.d.ts +3 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +67 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/logs.d.ts +13 -0
  80. package/dist/logs.d.ts.map +1 -0
  81. package/dist/logs.js +70 -0
  82. package/dist/logs.js.map +1 -0
  83. package/dist/packaging.test.d.ts +2 -0
  84. package/dist/packaging.test.d.ts.map +1 -0
  85. package/dist/packaging.test.js +79 -0
  86. package/dist/packaging.test.js.map +1 -0
  87. package/dist/profiles.test.d.ts +2 -0
  88. package/dist/profiles.test.d.ts.map +1 -0
  89. package/dist/profiles.test.js +56 -0
  90. package/dist/profiles.test.js.map +1 -0
  91. package/dist/project-hint.d.ts +12 -0
  92. package/dist/project-hint.d.ts.map +1 -0
  93. package/dist/project-hint.js +19 -0
  94. package/dist/project-hint.js.map +1 -0
  95. package/dist/project-type.d.ts +43 -0
  96. package/dist/project-type.d.ts.map +1 -0
  97. package/dist/project-type.js +88 -0
  98. package/dist/project-type.js.map +1 -0
  99. package/dist/project-type.test.d.ts +2 -0
  100. package/dist/project-type.test.d.ts.map +1 -0
  101. package/dist/project-type.test.js +77 -0
  102. package/dist/project-type.test.js.map +1 -0
  103. package/dist/prompt.d.ts +56 -0
  104. package/dist/prompt.d.ts.map +1 -0
  105. package/dist/prompt.js +157 -0
  106. package/dist/prompt.js.map +1 -0
  107. package/dist/tarball.d.ts +39 -0
  108. package/dist/tarball.d.ts.map +1 -0
  109. package/dist/tarball.js +208 -0
  110. package/dist/tarball.js.map +1 -0
  111. package/dist/tarball.test.d.ts +2 -0
  112. package/dist/tarball.test.d.ts.map +1 -0
  113. package/dist/tarball.test.js +97 -0
  114. package/dist/tarball.test.js.map +1 -0
  115. package/package.json +55 -4
@@ -0,0 +1,88 @@
1
+ import pc from 'picocolors';
2
+ import { startBrowserLogin, defaultTokenName } from '../browser-login.js';
3
+ import { AtlasApiError, apiRequest } from '../client.js';
4
+ import { DEFAULT_API_URL, configPath, loadConfig, saveConfig, storedApiUrl } from '../config.js';
5
+ import { withPrompter } from '../prompt.js';
6
+ /**
7
+ * Validate a token against the server, then persist it. Shared by the browser flow, a
8
+ * pasted token and the `--token` CI path — a dead token fails here rather than on the
9
+ * next command, where it is harder to diagnose.
10
+ */
11
+ async function finishLogin(apiUrl, token) {
12
+ try {
13
+ const { user } = await apiRequest({ apiUrl }, '/auth/me', {
14
+ token,
15
+ });
16
+ await saveConfig({ apiUrl, token, email: user.email });
17
+ console.log(pc.green('✔'), `Logged in as ${pc.bold(user.email)} at ${pc.dim(apiUrl)}`);
18
+ console.log(pc.dim(` token stored in ${configPath()} (mode 0600)`));
19
+ }
20
+ catch (err) {
21
+ if (err instanceof AtlasApiError) {
22
+ console.error(pc.red('✖'), `Token rejected: ${err.message}`);
23
+ }
24
+ else {
25
+ console.error(pc.red('✖'), `Could not reach ${apiUrl}: ${err.message}`);
26
+ }
27
+ process.exitCode = 1;
28
+ }
29
+ }
30
+ export function registerAuthCommands(program) {
31
+ program
32
+ .command('login')
33
+ .description('Log in — opens the browser, mints a token, and captures it automatically')
34
+ .option('--api <url>', 'API base URL (default: your instance, remembered after first login)')
35
+ .option('--name <name>', 'Name for the token that gets created (default: this machine)')
36
+ .option('--create', 'Prompt for a token name instead of defaulting to this machine')
37
+ .option('--token <token>', 'Use this token directly and skip the browser (for CI)')
38
+ .action(async (opts) => {
39
+ // The server: an explicit flag, then a previous login, then the instance this CLI
40
+ // ships pointed at. No prompt in the common case.
41
+ const apiUrl = (opts.api ?? (await storedApiUrl()) ?? DEFAULT_API_URL).replace(/\/+$/, '');
42
+ // CI path: a token was supplied, so there is nothing to open.
43
+ if (opts.token) {
44
+ await finishLogin(apiUrl, opts.token);
45
+ return;
46
+ }
47
+ await withPrompter(async (prompter) => {
48
+ const chosen = opts.name ?? (opts.create ? (await prompter.ask('Token name: ')).trim() : '');
49
+ const tokenName = chosen || defaultTokenName();
50
+ const login = startBrowserLogin(apiUrl, tokenName);
51
+ // Race the browser callback against a paste, so a box that cannot open a browser
52
+ // (SSH, locked down) still has a way through. An empty line is ignored — it just
53
+ // means "keep waiting for the browser".
54
+ const paste = prompter
55
+ .ask(pc.dim(' …or paste a token here and press enter: '))
56
+ .then((v) => v.trim())
57
+ .catch(() => '');
58
+ const winner = await Promise.race([
59
+ login.done.then((t) => ({ src: 'browser', t })),
60
+ paste.then((t) => ({ src: 'paste', t })),
61
+ ]);
62
+ let token;
63
+ if (winner.src === 'paste' && winner.t) {
64
+ login.abort();
65
+ token = winner.t;
66
+ }
67
+ else {
68
+ token = winner.src === 'browser' ? winner.t : await login.done;
69
+ }
70
+ if (!token) {
71
+ console.error(pc.red('✖'), 'No token received (the browser login timed out).');
72
+ console.error(pc.dim(' Retry, or create one at'), pc.cyan(`${apiUrl}/settings`), pc.dim('and paste it.'));
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+ await finishLogin(apiUrl, token);
77
+ });
78
+ });
79
+ program
80
+ .command('logout')
81
+ .description('Remove the stored token')
82
+ .action(async () => {
83
+ const config = await loadConfig();
84
+ await saveConfig({ apiUrl: config.apiUrl });
85
+ console.log(pc.green('✔'), 'Token removed');
86
+ });
87
+ }
88
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { Command } from 'commander';
2
+ export declare function assertProfileExists(projectDir: string, profile: string): Promise<void>;
3
+ export declare function registerBuildCommand(program: Command): void;
4
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2GzC,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5F;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsD3D"}
@@ -0,0 +1,362 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { createReadStream } from 'node:fs';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { join, resolve } from 'node:path';
5
+ import { promisify } from 'node:util';
6
+ import pc from 'picocolors';
7
+ import { AtlasApiError, apiRequest } from '../client.js';
8
+ import { reportProject } from '../project-hint.js';
9
+ import { loadConfig, resolveProject } from '../config.js';
10
+ import { detachOnInterrupt } from '../detach.js';
11
+ import { LARGE_UPLOAD_BYTES, packProject } from '../tarball.js';
12
+ import { streamLogs } from '../logs.js';
13
+ import { seedEnvFromEasJson } from './env.js';
14
+ import { detectProjectType } from '../project-type.js';
15
+ import { readShape } from './init.js';
16
+ const exec = promisify(execFile);
17
+ async function gitInfo(cwd) {
18
+ const run = async (args) => {
19
+ try {
20
+ return (await exec('git', args, { cwd })).stdout.trim();
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ };
26
+ const [sha, ref, status, subject] = await Promise.all([
27
+ run(['rev-parse', 'HEAD']),
28
+ run(['rev-parse', '--abbrev-ref', 'HEAD']),
29
+ run(['status', '--porcelain']),
30
+ // %s is the subject line only; a full body would flood the build list.
31
+ run(['log', '-1', '--pretty=%s']),
32
+ ]);
33
+ // Recording dirtiness matters: it is the difference between "this artifact is
34
+ // reproducible from a commit" and "this came off somebody's laptop".
35
+ return {
36
+ gitSha: sha,
37
+ gitRef: ref,
38
+ gitDirty: status === undefined ? undefined : status.length > 0,
39
+ gitCommitMessage: subject,
40
+ };
41
+ }
42
+ /**
43
+ * Which branch `--git` means.
44
+ *
45
+ * A bare `--git` builds the branch you are on, because that is what somebody standing in
46
+ * a checkout means by it. Outside a checkout there is nothing to infer from, and
47
+ * guessing `main` would build something other than what was asked for — so it asks.
48
+ */
49
+ /** Packs the working tree, announcing the size the way the upload path always has. */
50
+ async function packSource(projectDir) {
51
+ process.stdout.write(pc.dim('packing project… '));
52
+ const tarball = await packProject(projectDir);
53
+ console.log(pc.dim(`${(tarball.sizeBytes / 1024 / 1024).toFixed(1)} MB`));
54
+ return tarball;
55
+ }
56
+ async function resolveGitBranch(cwd, flag) {
57
+ if (typeof flag === 'string' && flag.trim())
58
+ return flag.trim();
59
+ let branch;
60
+ try {
61
+ branch = (await exec('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd })).stdout.trim();
62
+ }
63
+ catch {
64
+ throw new Error('This directory is not a git checkout, so there is no branch to infer. ' +
65
+ 'Name one: `ba build --git <branch>`.');
66
+ }
67
+ if (!branch || branch === 'HEAD') {
68
+ throw new Error('You are not on a branch (detached HEAD). Name one: `ba build --git <branch>`.');
69
+ }
70
+ return branch;
71
+ }
72
+ /**
73
+ * Checks the profile exists before uploading anything.
74
+ *
75
+ * Reads buildatlas.json first, then eas.json — the same order the server uses. It only
76
+ * looked at eas.json, so a native Android or iOS project with a perfectly good
77
+ * buildatlas.json was told "No eas.json in this directory", which is both wrong and
78
+ * points at a file it should not need: supporting projects that have never touched EAS
79
+ * is the reason buildatlas.json exists.
80
+ *
81
+ * Neither file is an error only if the profile is not a known default. With no config at
82
+ * all the server falls back to built-in profiles, and refusing here would block the
83
+ * zero-configuration case that is supposed to just work.
84
+ */
85
+ const DEFAULT_PROFILE_NAMES = ['development', 'preview', 'production'];
86
+ export async function assertProfileExists(projectDir, profile) {
87
+ const read = async (name) => {
88
+ try {
89
+ const parsed = JSON.parse(await readFile(join(projectDir, name), 'utf8'));
90
+ return Object.keys(parsed.build ?? {});
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ };
96
+ const fromBuildAtlas = await read('buildatlas.json');
97
+ const available = fromBuildAtlas ?? (await read('eas.json'));
98
+ const source = fromBuildAtlas ? 'buildatlas.json' : 'eas.json';
99
+ if (!available) {
100
+ // No config of any kind. Fine, as long as the profile is one the server defaults to.
101
+ if (DEFAULT_PROFILE_NAMES.includes(profile))
102
+ return;
103
+ throw new Error(`No buildatlas.json or eas.json here, and "${profile}" is not a built-in profile ` +
104
+ `(${DEFAULT_PROFILE_NAMES.join(', ')}). Run \`buildatlas init\` to write one, or ` +
105
+ 'run this from your project root.');
106
+ }
107
+ if (!available.includes(profile)) {
108
+ // Fail here rather than after a multi-megabyte upload and a queue wait.
109
+ throw new Error(`Build profile "${profile}" is not in ${source}. Available: ${available.join(', ') || '(none)'}`);
110
+ }
111
+ }
112
+ export function registerBuildCommand(program) {
113
+ program
114
+ .command('build')
115
+ .description('Queue a build of the current project')
116
+ .requiredOption('-p, --platform <platform>', 'ios or android')
117
+ .option('-e, --profile <profile>', 'eas.json build profile', 'production')
118
+ .option('--project <slug>', 'BuildAtlas project slug (default: $BUILDATLAS_PROJECT, else app.json)')
119
+ .option('--dir <path>', 'Project directory', process.cwd())
120
+ .option('--no-wait', 'Return as soon as the build is queued')
121
+ .option('--retain-workdir', 'Keep the build directory on the runner for debugging')
122
+ // Negated, because native is the default now. Commander gives `opts.local` the
123
+ // value true unless --no-local is passed, so the flag reads the way it behaves.
124
+ .option('--no-local', 'Build with the legacy eas-cli strategy instead of driving Xcode and Gradle directly. Needs an Expo account and an eas.json.')
125
+ .option('--build-number <n>', 'Use this exact build number, ignoring the descriptor and the counter. For when a store has already taken the next one.')
126
+ .option('--app-version <version>', 'Use this marketing version (CFBundleShortVersionString / versionName) instead of the one in your app config.')
127
+ .option('--git [branch]', "Build the project's configured repository instead of uploading this directory. With no value, uses the branch you are on.")
128
+ .option('--ios-signer <tool>', 'For a signed iOS --local build: "xcodebuild" (default) or "fastlane" (gym). Same signing setup either way; they differ in which tool archives and exports, and in how they fail.')
129
+ .action(async (opts) => {
130
+ try {
131
+ await runBuild(opts);
132
+ }
133
+ catch (err) {
134
+ const message = err instanceof AtlasApiError ? `${err.message} (${err.code})` : err.message;
135
+ console.error(pc.red('✖'), message);
136
+ process.exitCode = 1;
137
+ }
138
+ });
139
+ }
140
+ /**
141
+ * This project's type, as the CLI sees it.
142
+ *
143
+ * Best-effort on purpose: detection throwing (an empty directory, an unreadable
144
+ * package.json) must not stop a build that the server would have been able to type
145
+ * itself. An explicit `projectType` in buildatlas.json wins, because that is what it
146
+ * is for.
147
+ */
148
+ async function detectedProjectType(projectDir) {
149
+ try {
150
+ const descriptor = JSON.parse(await readFile(join(projectDir, 'buildatlas.json'), 'utf8'));
151
+ if (descriptor.projectType)
152
+ return { projectType: descriptor.projectType };
153
+ }
154
+ catch {
155
+ // No descriptor, or not readable. Fall through to detection.
156
+ }
157
+ try {
158
+ return { projectType: detectProjectType(await readShape(projectDir)).type };
159
+ }
160
+ catch {
161
+ return {};
162
+ }
163
+ }
164
+ async function runBuild(opts) {
165
+ if (opts.platform !== 'ios' && opts.platform !== 'android') {
166
+ throw new Error('--platform must be "ios" or "android"');
167
+ }
168
+ const config = await loadConfig();
169
+ if (!config.token)
170
+ throw new Error('Not logged in. Run `buildatlas login` first.');
171
+ const projectDir = resolve(opts.dir);
172
+ // Resolved against the same directory the source is packed from, so --dir moves
173
+ // both together and they cannot disagree.
174
+ const resolved = await resolveProject(opts.project, projectDir);
175
+ reportProject(resolved);
176
+ const slug = resolved.slug;
177
+ /*
178
+ * The two ways source reaches a runner.
179
+ *
180
+ * With --git nothing is packed and nothing is uploaded: the runner clones the
181
+ * project's repository itself, which is the whole point — on a large project the
182
+ * upload is the slowest part of a build and the part most likely to fail.
183
+ *
184
+ * Checked against the server first so "that project has no repository configured"
185
+ * arrives immediately, rather than after the build row already exists.
186
+ */
187
+ const gitBranch = opts.git === undefined || opts.git === false
188
+ ? null
189
+ : await resolveGitBranch(projectDir, opts.git);
190
+ if (gitBranch) {
191
+ const status = await apiRequest(config, `/projects/${slug}/git/status`, {
192
+ token: config.token,
193
+ });
194
+ if (!status.configured) {
195
+ throw new Error(`${status.reason ?? 'This project cannot build from git.'}\n` +
196
+ ' Set the repository on the project (dashboard → Project → Details → Repository).');
197
+ }
198
+ console.log(pc.dim(`building ${status.fullName ?? 'the configured repository'} @ ${gitBranch} — nothing uploaded`));
199
+ }
200
+ // Only the uploaded path builds what is in this directory. With --git the profile,
201
+ // the project type and the eas.json env all come from the repository the runner
202
+ // clones — reading them here would validate the wrong tree, and on a laptop sitting
203
+ // in some other project it would reject a profile that exists perfectly well in the
204
+ // one being built.
205
+ if (!gitBranch) {
206
+ await assertProfileExists(projectDir, opts.profile);
207
+ }
208
+ if (opts.iosSigner && opts.iosSigner !== 'xcodebuild' && opts.iosSigner !== 'fastlane') {
209
+ throw new Error('--ios-signer must be "xcodebuild" or "fastlane"');
210
+ }
211
+ if (opts.iosSigner && !opts.local) {
212
+ // It is only consulted by the native strategy, so accepting it silently here
213
+ // would look like it had been applied.
214
+ throw new Error('--ios-signer does not apply to a --no-local build. eas-cli does its own signing.');
215
+ }
216
+ if (opts.buildNumber !== undefined) {
217
+ const n = Number(opts.buildNumber);
218
+ // Checked before a tarball is uploaded: a rejected build number after a
219
+ // ten-minute build is the failure this flag exists to avoid.
220
+ if (!Number.isInteger(n) || n < 1) {
221
+ throw new Error('--build-number must be a positive whole number.');
222
+ }
223
+ }
224
+ if (opts.iosSigner && opts.platform !== 'ios') {
225
+ throw new Error('--ios-signer only applies to --platform ios.');
226
+ }
227
+ if (opts.local && !gitBranch) {
228
+ // Best-effort: a native build's actual env still comes from the worker
229
+ // reading eas.json directly, so a failure here (e.g. a non-admin token —
230
+ // setting env requires admin) must never block the build itself.
231
+ try {
232
+ const { added } = await seedEnvFromEasJson({
233
+ config,
234
+ slug,
235
+ projectDir,
236
+ profile: opts.profile,
237
+ overwrite: false,
238
+ });
239
+ if (added.length) {
240
+ console.log(pc.dim(`seeded env from eas.json: ${added.join(', ')}`));
241
+ }
242
+ }
243
+ catch (err) {
244
+ console.log(pc.dim(`(could not seed dashboard env vars from eas.json: ${err.message})`));
245
+ }
246
+ }
247
+ const tarball = gitBranch ? null : await packSource(projectDir);
248
+ // An oversized upload is invisible exactly when it matters. A Flutter app shipped
249
+ // 1,175 MB and the only symptom was a build that sat in "Fetch source" for an hour and
250
+ // sixteen minutes — on a link from Addis, uphill both ways, for a two-minute build.
251
+ // Said here, before the upload, where it is still cheap to fix.
252
+ if (tarball && tarball.sizeBytes > LARGE_UPLOAD_BYTES) {
253
+ console.log(pc.yellow('!'), `That is a large upload. It is sent to storage now and downloaded again by the runner,\n so it is paid for twice on every build.`);
254
+ for (const entry of tarball.largest) {
255
+ console.log(pc.dim(` ${(entry.bytes / 1024 / 1024).toFixed(0)} MB ${entry.path}`));
256
+ }
257
+ console.log(pc.dim(' Anything here that is build output rather than source belongs in .easignore\n' +
258
+ ' (or .gitignore) — the runner rebuilds it from scratch regardless.'));
259
+ }
260
+ // Said before the build starts, not after it fails ten minutes later. The runner
261
+ // cannot detect this — from its side the file simply does not exist.
262
+ for (const name of tarball?.excludedButRelevant ?? []) {
263
+ console.log(pc.yellow('!'), `${name} is excluded by your ignore rules, so the runner will not see it.`);
264
+ console.log(pc.dim(` It affects how dependencies install. If it holds no secrets, add "!${name}" to ` +
265
+ '.easignore so it is uploaded.'));
266
+ }
267
+ try {
268
+ // Recorded from the local checkout only when the local checkout is what is being
269
+ // built. For a --git build the laptop's HEAD is not the source, and sending its sha
270
+ // would put a plausible, wrong commit on the build row; the runner reports the real
271
+ // one after it clones.
272
+ const git = gitBranch ? { gitRef: gitBranch } : await gitInfo(projectDir);
273
+ const { build, uploadUrl } = await apiRequest(config, `/projects/${slug}/builds`, {
274
+ method: 'POST',
275
+ token: config.token,
276
+ body: JSON.stringify({
277
+ platform: opts.platform,
278
+ profile: opts.profile,
279
+ strategy: opts.local ? 'native' : 'eas-local',
280
+ ...(opts.iosSigner ? { iosSigner: opts.iosSigner } : {}),
281
+ ...(opts.buildNumber ? { buildNumber: Number(opts.buildNumber) } : {}),
282
+ ...(opts.appVersion ? { appVersion: opts.appVersion } : {}),
283
+ ...(gitBranch ? { sourceKind: 'git' } : { sourceSha256: tarball.sha256 }),
284
+ retainWorkdir: opts.retainWorkdir ?? false,
285
+ // Sent so the server can route the build while it is still queued: a Flutter
286
+ // build is only buildable on a runner with the Flutter SDK, and nothing looks
287
+ // at the source until a runner has already claimed it. Advisory — the worker
288
+ // reads the tree itself and corrects this.
289
+ ...(gitBranch ? {} : await detectedProjectType(projectDir)),
290
+ ...git,
291
+ }),
292
+ });
293
+ console.log(`${pc.green('✔')} build ${pc.bold(build.id)} created · ${build.platform} · ${build.profile} · build number ${build.buildNumber}`);
294
+ if (tarball && uploadUrl) {
295
+ process.stdout.write(pc.dim('uploading source… '));
296
+ await uploadTarball(uploadUrl, tarball.path, tarball.sizeBytes);
297
+ console.log(pc.dim('done'));
298
+ }
299
+ // Retried, unlike the create above: the build row and its source already exist,
300
+ // and enqueueing it twice queues the same build. Losing this call after a source
301
+ // upload that took minutes leaves a build that exists and will never run.
302
+ await apiRequest(config, `/builds/${build.id}/enqueue`, {
303
+ method: 'POST',
304
+ token: config.token,
305
+ retry: 'safe',
306
+ });
307
+ console.log(`${pc.green('✔')} queued`);
308
+ if (!opts.wait) {
309
+ console.log(pc.dim(`follow with: buildatlas logs ${build.id}`));
310
+ return;
311
+ }
312
+ // From here the build exists server-side, so Ctrl-C must detach rather than
313
+ // silently exit and look like a cancellation.
314
+ const stopDetaching = detachOnInterrupt(build.id);
315
+ try {
316
+ const finalStatus = await streamLogs(config, build.id);
317
+ if (finalStatus !== 'finished')
318
+ process.exitCode = 1;
319
+ }
320
+ finally {
321
+ stopDetaching();
322
+ }
323
+ }
324
+ finally {
325
+ // The tarball is a temp file; leaving copies of source archives in /tmp on
326
+ // every developer's laptop is not acceptable. (A --git build packed nothing.)
327
+ await tarball?.cleanup();
328
+ }
329
+ }
330
+ async function uploadTarball(url, path, size) {
331
+ // The host comes from the server's presigned URL, not from our own config, so
332
+ // when it is unreachable the useful thing to report is which host that was.
333
+ // Bare "fetch failed" sends people looking at their own network.
334
+ const host = (() => {
335
+ try {
336
+ return new URL(url).host;
337
+ }
338
+ catch {
339
+ return url;
340
+ }
341
+ })();
342
+ let res;
343
+ try {
344
+ res = await fetch(url, {
345
+ method: 'PUT',
346
+ // A Node ReadableStream body requires duplex: 'half'; without it fetch
347
+ // refuses to stream and would buffer the whole archive in memory.
348
+ body: createReadStream(path),
349
+ duplex: 'half',
350
+ headers: { 'content-type': 'application/gzip', 'content-length': String(size) },
351
+ });
352
+ }
353
+ catch (err) {
354
+ throw new Error(`Could not reach object storage at ${host} to upload the source (${err.message}).\n` +
355
+ ' The server hands out this address, so it has to be reachable from here.\n' +
356
+ ' If BuildAtlas is on another machine, set S3_PUBLIC_URL on the server to an address this one can reach.');
357
+ }
358
+ if (!res.ok) {
359
+ throw new Error(`Source upload to ${host} failed: ${res.status} ${res.statusText}`);
360
+ }
361
+ }
362
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/commands/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerBuildQueryCommands(program: Command): void;
3
+ //# sourceMappingURL=builds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builds.d.ts","sourceRoot":"","sources":["../../src/commands/builds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmDzC,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8EjE"}
@@ -0,0 +1,102 @@
1
+ import pc from 'picocolors';
2
+ import { AtlasApiError, apiRequest } from '../client.js';
3
+ import { reportProject } from '../project-hint.js';
4
+ import { loadConfig, resolveProject } from '../config.js';
5
+ import { detachOnInterrupt } from '../detach.js';
6
+ import { streamLogs } from '../logs.js';
7
+ const STATUS_COLOR = {
8
+ finished: pc.green,
9
+ errored: pc.red,
10
+ canceled: pc.yellow,
11
+ running: pc.cyan,
12
+ queued: pc.blue,
13
+ pending: pc.dim,
14
+ };
15
+ const colorStatus = (status) => (STATUS_COLOR[status] ?? pc.white)(status.padEnd(8));
16
+ function duration(from, to) {
17
+ if (!to)
18
+ return '—';
19
+ const seconds = Math.round((new Date(to).getTime() - new Date(from).getTime()) / 1000);
20
+ return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, '0')}s`;
21
+ }
22
+ async function requireAuth() {
23
+ const config = await loadConfig();
24
+ if (!config.token)
25
+ throw new Error('Not logged in. Run `buildatlas login` first.');
26
+ return config;
27
+ }
28
+ function fail(err) {
29
+ const message = err instanceof AtlasApiError ? `${err.message} (${err.code})` : err.message;
30
+ console.error(pc.red('✖'), message);
31
+ process.exitCode = 1;
32
+ }
33
+ export function registerBuildQueryCommands(program) {
34
+ program
35
+ .command('builds')
36
+ .description('List recent builds for a project')
37
+ .option('--project <slug>', 'Project slug (default: $BUILDATLAS_PROJECT, else app.json)')
38
+ .option('-n, --limit <count>', 'How many to show', '20')
39
+ .action(async (opts) => {
40
+ try {
41
+ const config = await requireAuth();
42
+ const resolved = await resolveProject(opts.project);
43
+ reportProject(resolved);
44
+ const slug = resolved.slug;
45
+ const { builds } = await apiRequest(config, `/projects/${slug}/builds?limit=${encodeURIComponent(opts.limit)}`, { token: config.token });
46
+ if (!builds.length) {
47
+ console.log(pc.dim('No builds yet.'));
48
+ return;
49
+ }
50
+ for (const b of builds) {
51
+ const version = `${b.appVersion ?? '?'} (${b.buildNumber ?? '?'})`;
52
+ console.log(`${colorStatus(b.status)} ${b.id.slice(0, 8)} ${b.platform.padEnd(7)} ${b.profile.padEnd(12)} ${version.padEnd(14)} ${duration(b.createdAt, b.finishedAt).padStart(7)}`);
53
+ if (b.errorMessage)
54
+ console.log(pc.dim(` ↳ ${b.errorMessage}`));
55
+ }
56
+ }
57
+ catch (err) {
58
+ fail(err);
59
+ }
60
+ });
61
+ program
62
+ .command('logs <buildId>')
63
+ .description('Follow (or replay) a build log')
64
+ .action(async (buildId) => {
65
+ try {
66
+ const config = await requireAuth();
67
+ // Following someone else's build must not imply ownership of it either.
68
+ const stopDetaching = detachOnInterrupt(buildId);
69
+ let status;
70
+ try {
71
+ status = await streamLogs(config, buildId);
72
+ }
73
+ finally {
74
+ stopDetaching();
75
+ }
76
+ console.log(status === 'finished' ? pc.green(`\n✔ ${status}`) : pc.red(`\n✖ ${status}`));
77
+ if (status !== 'finished')
78
+ process.exitCode = 1;
79
+ }
80
+ catch (err) {
81
+ fail(err);
82
+ }
83
+ });
84
+ program
85
+ .command('cancel <buildId>')
86
+ .description('Cancel a queued or running build')
87
+ .action(async (buildId) => {
88
+ try {
89
+ const config = await requireAuth();
90
+ const { result } = await apiRequest(config, `/builds/${buildId}/cancel`,
91
+ // Cancelling a cancelled build is still a cancelled build, so a 504 from a
92
+ // proxy is worth retrying rather than leaving a person unsure whether the
93
+ // build they wanted stopped is still burning minutes.
94
+ { method: 'POST', token: config.token, retry: 'safe' });
95
+ console.log(pc.green('✔'), result === 'removed' ? 'removed from the queue' : 'cancel signalled to the runner');
96
+ }
97
+ catch (err) {
98
+ fail(err);
99
+ }
100
+ });
101
+ }
102
+ //# sourceMappingURL=builds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builds.js","sourceRoot":"","sources":["../../src/commands/builds.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { Prompter } from '../prompt.ts';
2
+ export type WizardKind = 'android_keystore' | 'ios_dist_cert' | 'ios_provisioning_profile' | 'asc_api_key' | 'play_service_account';
3
+ export interface WizardResult {
4
+ kind: WizardKind;
5
+ label: string;
6
+ payload: Record<string, unknown>;
7
+ }
8
+ /**
9
+ * Interactive `credentials add`.
10
+ *
11
+ * Running the command bare used to fail with "required option '-k, --kind' not
12
+ * specified", which tells you a flag is missing but not which of six values it
13
+ * takes, nor which extra flags each one then needs. The flags still work and are
14
+ * still what CI uses; this is for the person doing it once by hand.
15
+ *
16
+ * For Android it also offers to *create* the keystore. That is the part most worth
17
+ * automating: keytool's defaults are wrong for this job in three separate ways —
18
+ * it writes to ~/.keystore rather than the project, issues a 90-day certificate
19
+ * that is useless for Play, and names the key `mykey`. Getting any of those wrong
20
+ * is only discovered later.
21
+ */
22
+ export declare function runCredentialsWizard(p: Prompter, defaults: {
23
+ dir: string;
24
+ }): Promise<WizardResult>;
25
+ //# sourceMappingURL=credentials-wizard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials-wizard.d.ts","sourceRoot":"","sources":["../../src/commands/credentials-wizard.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,MAAM,UAAU,GAClB,kBAAkB,GAClB,eAAe,GACf,0BAA0B,GAC1B,aAAa,GACb,sBAAsB,CAAC;AAE3B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,CAAC,EAAE,QAAQ,EACX,QAAQ,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACxB,OAAO,CAAC,YAAY,CAAC,CAyCvB"}