@devdogsuga/devtools 0.1.51-next.541 → 0.1.51-next.545
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dist/{cli-BoTmTNqH.js → cli-DNZ-6WEI.js} +105 -61
- package/dist/{root-CsocfxnK.js → failure-log-MSdCgvLc.js} +5 -75
- package/dist/launch.js +28 -11
- package/dist/{load-Cp8AMERM.js → load-Z2CXCpyx.js} +7 -4
- package/dist/load-yn7JCcS2.js +2 -0
- package/dist/{menu-C30rQm5v.js → menu-oQE5IqAI.js} +168 -146
- package/dist/root-DfH38DFq.js +2 -0
- package/dist/root-PA8K5G2d.js +77 -0
- package/dist/{supabase-project-BoJKMCxL.js → run-CRBte7p0.js} +235 -249
- package/dist/{session-rbONwFvY.js → session-CuexI1f9.js} +1 -1
- package/dist/{session-CmDxHEMn.js → session-DzgtIg6K.js} +1 -1
- package/dist/spawn-BvLQzc_K.js +100 -0
- package/dist/{stack-7Lbym6Wq.js → stack-BRevXgI3.js} +1 -1
- package/dist/stack-Cl_B_dt7.js +2 -0
- package/dist/{telemetry-BKFDtzXI.js → telemetry-BDTAGquh.js} +19 -4
- package/dist/telemetry.js +2 -2
- package/dist/with-env.js +15 -17
- package/package.json +6 -4
- package/dist/load-Czhayrsk.js +0 -2
- package/dist/stack-7qA2UP9g.js +0 -2
package/README.md
CHANGED
|
@@ -97,12 +97,15 @@ name `devdogs-monorepo` or `backstage`; the layout code is
|
|
|
97
97
|
|
|
98
98
|
A repository with a `devtools.config.json` at its root is a **product** (DogDays, DogPack): devtools
|
|
99
99
|
reads the file and serves a smaller command set that needs no tiers, no env registry and no workspace.
|
|
100
|
-
|
|
100
|
+
Both products carry a `package.json` whose `devtools` script is a `pnpm dlx` run of the published CLI, so
|
|
101
|
+
inside a checkout:
|
|
101
102
|
|
|
102
103
|
```sh
|
|
103
|
-
|
|
104
|
+
pnpm devtools setup
|
|
104
105
|
```
|
|
105
106
|
|
|
107
|
+
Anywhere else, the one-off form is `pnpm dlx @devdogsuga/devtools@next setup`.
|
|
108
|
+
|
|
106
109
|
| Command | What it does |
|
|
107
110
|
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
108
111
|
| `setup [--local \| --hosted]` | Writes `.env` from `.env.example`; starts the Docker stack (or takes your own hosted project's URL, keys and session-pooler `DB_URL`); `db sync`; the types; then `oauth`. |
|
|
@@ -136,7 +139,7 @@ How it works, in short:
|
|
|
136
139
|
`oauth` (the tooling file) check that they are git-ignored and add them to the repo's `.gitignore`
|
|
137
140
|
when they are not (Flutter's default ignore file leaves them out).
|
|
138
141
|
- **The pinned CLI.** devtools finds `supabase` in `node_modules/.bin` or on PATH when its version is the
|
|
139
|
-
pin, and otherwise runs `npx --yes supabase@<pin
|
|
142
|
+
pin, and otherwise runs `pnpm dlx supabase@<pin>` (`npx --yes supabase@<pin>` only when pnpm is not on PATH).
|
|
140
143
|
- **A hosted project** needs custom OAuth providers turned on and the app's return addresses allowed.
|
|
141
144
|
`setup` does both through the Management API when `SUPABASE_ACCESS_TOKEN` is set, and prints the two
|
|
142
145
|
dashboard steps when it is not.
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { A as
|
|
4
|
-
import { d as
|
|
5
|
-
import {
|
|
1
|
+
import { n as execSync, r as spawnProcess } from "./spawn-BvLQzc_K.js";
|
|
2
|
+
import { n as discoverRepoRoot, r as findRepoRoot } from "./root-PA8K5G2d.js";
|
|
3
|
+
import { A as findApp, M as listApps, N as resolveAppPath, O as appWorkspaceRoot, P as resolveLayout, _ as dryRunKind, c as supabaseRoot, d as loadEnvLoad, f as loadEnvSession, g as runInGroup, h as reportRan, i as runWithStderr, j as layoutAt, k as devdogsugaRootOrNull, l as getEnvSync, n as reportRuns, o as supabase, p as repoPeerUrl, r as run$1, t as dbPush, u as loadEnv, v as isDryRun, x as wouldRunLine } from "./run-CRBte7p0.js";
|
|
4
|
+
import { A as renderHelp, C as loadProductConfig, D as catalog, M as probeEnvironment, O as helpPath, T as isProductMode, _ as explain, a as recordEnteredTier, b as ProductConfigError, c as nonEmpty, d as sessionLabel, g as errorMessage, h as bail, i as beginInvocation, j as describeEnvironment, k as renderCommandList, l as resolveDbConnection, n as bareGroupStartPath, o as recordResolved, r as runMenu, s as reproducibleCommand, t as bareGroupStartFlags, u as sessionIsLocal, v as explainError, w as activeCatalog, x as currentProduct, y as unwrap } from "./menu-oQE5IqAI.js";
|
|
5
|
+
import { a as isVersionRequest, c as cliName, m as positionals, o as ownPackageDir, p as flagValue, s as ownVersion } from "./failure-log-MSdCgvLc.js";
|
|
6
|
+
import { f as hasYes, n as captureDevtoolsError, o as initDevtoolsTelemetry, p as isNonInteractive } from "./telemetry-BDTAGquh.js";
|
|
7
|
+
import { t as runStackCommand } from "./stack-BRevXgI3.js";
|
|
6
8
|
import { register } from "node:module";
|
|
7
9
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
8
10
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
9
11
|
import { z } from "zod";
|
|
10
12
|
import { confirm, intro, log, multiselect, note, outro, password, select, spinner, text } from "@clack/prompts";
|
|
11
13
|
import { chmod, readFile, writeFile } from "node:fs/promises";
|
|
12
|
-
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
13
14
|
import { pathToFileURL } from "node:url";
|
|
15
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
14
16
|
import { parse } from "dotenv";
|
|
15
17
|
import postgres from "postgres";
|
|
16
18
|
import { flattenDiagnosticMessageText, parseConfigFileTextToJson } from "typescript";
|
|
@@ -1417,14 +1419,11 @@ function checkEnvKeysPresent(env, keys) {
|
|
|
1417
1419
|
}
|
|
1418
1420
|
function has$1(cmd, args) {
|
|
1419
1421
|
try {
|
|
1420
|
-
return
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
],
|
|
1426
|
-
encoding: "utf8"
|
|
1427
|
-
}).trim();
|
|
1422
|
+
return execSync(cmd, args, { stdio: [
|
|
1423
|
+
"ignore",
|
|
1424
|
+
"pipe",
|
|
1425
|
+
"ignore"
|
|
1426
|
+
] }).trim();
|
|
1428
1427
|
} catch {
|
|
1429
1428
|
return null;
|
|
1430
1429
|
}
|
|
@@ -3325,7 +3324,7 @@ async function startTemporaryWrangler(app, requestedPort) {
|
|
|
3325
3324
|
process.stderr.write(`devtools jobs: building ${app}'s workspace dependencies failed (exit ${buildCode}); not starting ${runtime}.\n`);
|
|
3326
3325
|
return null;
|
|
3327
3326
|
}
|
|
3328
|
-
const child =
|
|
3327
|
+
const child = spawnProcess("pnpm", vinextDevArgs(app, port), {
|
|
3329
3328
|
cwd: appWorkspaceRoot(app),
|
|
3330
3329
|
stdio: "inherit",
|
|
3331
3330
|
detached: process.platform !== "win32",
|
|
@@ -4895,9 +4894,8 @@ function formatValue(value) {
|
|
|
4895
4894
|
//#endregion
|
|
4896
4895
|
//#region src/oauth/db.ts
|
|
4897
4896
|
function runStatus(argv, cwd) {
|
|
4898
|
-
return
|
|
4897
|
+
return execSync(argv[0], argv.slice(1), {
|
|
4899
4898
|
cwd,
|
|
4900
|
-
encoding: "utf-8",
|
|
4901
4899
|
stdio: [
|
|
4902
4900
|
"pipe",
|
|
4903
4901
|
"pipe",
|
|
@@ -4922,7 +4920,7 @@ function productPin(cwd) {
|
|
|
4922
4920
|
* a sibling project, where the Supabase CLI is normally installed globally;
|
|
4923
4921
|
* this monorepo, where it is a workspace devDependency and not on PATH at all;
|
|
4924
4922
|
* and a product repo (`devtools.config.json`), where `devtools setup` ran the
|
|
4925
|
-
* pinned CLI through `
|
|
4923
|
+
* pinned CLI through `pnpm dlx` and a new member has none installed. A global install
|
|
4926
4924
|
* wins, since `pnpm exec` in a non-pnpm project would fail for reasons that have
|
|
4927
4925
|
* nothing to do with Supabase.
|
|
4928
4926
|
*/
|
|
@@ -4944,19 +4942,32 @@ function detectLocalSupabase(cwd) {
|
|
|
4944
4942
|
...status
|
|
4945
4943
|
]];
|
|
4946
4944
|
const pin = productPin(cwd);
|
|
4947
|
-
if (pin !== null)
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4945
|
+
if (pin !== null) {
|
|
4946
|
+
attempts.push([
|
|
4947
|
+
"pnpm",
|
|
4948
|
+
"dlx",
|
|
4949
|
+
`supabase@${pin}`,
|
|
4950
|
+
...status
|
|
4951
|
+
]);
|
|
4952
|
+
attempts.push([
|
|
4953
|
+
"npx",
|
|
4954
|
+
"--yes",
|
|
4955
|
+
`supabase@${pin}`,
|
|
4956
|
+
...status
|
|
4957
|
+
]);
|
|
4958
|
+
}
|
|
4953
4959
|
let output;
|
|
4954
4960
|
let first;
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4961
|
+
let pnpmMissing = false;
|
|
4962
|
+
for (const argv of attempts) {
|
|
4963
|
+
if (argv[0] === "npx" && !pnpmMissing) continue;
|
|
4964
|
+
try {
|
|
4965
|
+
output = runStatus(argv, cwd);
|
|
4966
|
+
break;
|
|
4967
|
+
} catch (error) {
|
|
4968
|
+
first ??= error;
|
|
4969
|
+
if (argv[0] === "pnpm" && error.code === "ENOENT") pnpmMissing = true;
|
|
4970
|
+
}
|
|
4960
4971
|
}
|
|
4961
4972
|
if (output === void 0) {
|
|
4962
4973
|
if (first.code === "ENOENT") throw new Error("supabase CLI not found — install it from https://supabase.com/docs/guides/cli");
|
|
@@ -5097,14 +5108,22 @@ async function fetchIssuerFromAny(baseUrls) {
|
|
|
5097
5108
|
//#region src/oauth/browser.ts
|
|
5098
5109
|
/** Opens `url` in the user's default browser, cross-platform. */
|
|
5099
5110
|
function openBrowser(url) {
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
"
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5111
|
+
const [command, args] = browserCommand(url, process.platform);
|
|
5112
|
+
spawnProcess(command, args, {
|
|
5113
|
+
stdio: "ignore",
|
|
5114
|
+
detached: true
|
|
5115
|
+
}).on("error", () => void 0).unref();
|
|
5116
|
+
}
|
|
5117
|
+
/**
|
|
5118
|
+
* The program that opens `url`. Windows uses `rundll32`, a real executable, not
|
|
5119
|
+
* `cmd /c start`: through `cmd.exe` an `&` in the URL ends the command and
|
|
5120
|
+
* starts another, which truncates every OAuth authorize URL at its first query
|
|
5121
|
+
* parameter.
|
|
5122
|
+
*/
|
|
5123
|
+
function browserCommand(url, platform) {
|
|
5124
|
+
if (platform === "win32") return ["rundll32", ["url.dll,FileProtocolHandler", url]];
|
|
5125
|
+
if (platform === "darwin") return ["open", [url]];
|
|
5126
|
+
return ["xdg-open", [url]];
|
|
5108
5127
|
}
|
|
5109
5128
|
//#endregion
|
|
5110
5129
|
//#region src/oauth/pkce.ts
|
|
@@ -6756,14 +6775,11 @@ const handleScript = async (rest) => {
|
|
|
6756
6775
|
*/
|
|
6757
6776
|
function has(cmd, args = ["--version"]) {
|
|
6758
6777
|
try {
|
|
6759
|
-
return
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
],
|
|
6765
|
-
encoding: "utf8"
|
|
6766
|
-
}).trim();
|
|
6778
|
+
return execSync(cmd, args, { stdio: [
|
|
6779
|
+
"ignore",
|
|
6780
|
+
"pipe",
|
|
6781
|
+
"ignore"
|
|
6782
|
+
] }).trim();
|
|
6767
6783
|
} catch {
|
|
6768
6784
|
return null;
|
|
6769
6785
|
}
|
|
@@ -6988,7 +7004,7 @@ const OAUTH = {
|
|
|
6988
7004
|
//#endregion
|
|
6989
7005
|
//#region src/product/exec.ts
|
|
6990
7006
|
const spawnRunner = (command, args, options) => new Promise((resolve, reject) => {
|
|
6991
|
-
const child =
|
|
7007
|
+
const child = spawnProcess(command, args, {
|
|
6992
7008
|
cwd: options.cwd,
|
|
6993
7009
|
env: {
|
|
6994
7010
|
...process.env,
|
|
@@ -7031,7 +7047,9 @@ function commandLine(command, args) {
|
|
|
7031
7047
|
*
|
|
7032
7048
|
* 1. `node_modules/.bin/supabase` in the repo, when its version is the pin;
|
|
7033
7049
|
* 2. a `supabase` on PATH whose version is the pin;
|
|
7034
|
-
* 3. `
|
|
7050
|
+
* 3. `pnpm dlx supabase@<pin>`, which downloads and caches the right one.
|
|
7051
|
+
* Members are expected to have pnpm (both product repos pin it);
|
|
7052
|
+
* 4. `npx --yes supabase@<pin>`, only when pnpm is not on PATH.
|
|
7035
7053
|
*
|
|
7036
7054
|
* The pin is also part of the generated-types hash, so a contributor on a
|
|
7037
7055
|
* different CLI would generate different types than CI; matching it is not
|
|
@@ -7060,6 +7078,13 @@ async function resolveSupabaseCli(root, pin, run, fileExists = existsSync) {
|
|
|
7060
7078
|
const result = await run(candidate.command, ["--version"], { cwd: root });
|
|
7061
7079
|
if (result.code === 0 && versionOf(result.stdout) === pin) return candidate;
|
|
7062
7080
|
} catch {}
|
|
7081
|
+
try {
|
|
7082
|
+
if ((await run("pnpm", ["--version"], { cwd: root })).code === 0) return {
|
|
7083
|
+
command: "pnpm",
|
|
7084
|
+
prefix: ["dlx", `supabase@${pin}`],
|
|
7085
|
+
source: "pnpm"
|
|
7086
|
+
};
|
|
7087
|
+
} catch {}
|
|
7063
7088
|
return {
|
|
7064
7089
|
command: "npx",
|
|
7065
7090
|
prefix: ["--yes", `supabase@${pin}`],
|
|
@@ -7209,6 +7234,15 @@ var DevDataError = class extends Error {
|
|
|
7209
7234
|
this.name = "DevDataError";
|
|
7210
7235
|
}
|
|
7211
7236
|
};
|
|
7237
|
+
/**
|
|
7238
|
+
* Whether `err` is Postgres saying a table or schema does not exist
|
|
7239
|
+
* (SQLSTATE 42P01 undefined_table, 3F000 invalid_schema_name): the database
|
|
7240
|
+
* has not had the product's schema applied yet.
|
|
7241
|
+
*/
|
|
7242
|
+
function isMissingSchemaError(err) {
|
|
7243
|
+
const code = err?.code;
|
|
7244
|
+
return code === "42P01" || code === "3F000";
|
|
7245
|
+
}
|
|
7212
7246
|
function postgresSession(dbUrl) {
|
|
7213
7247
|
const sql = postgres(dbUrl, {
|
|
7214
7248
|
max: 1,
|
|
@@ -7262,22 +7296,28 @@ async function runDevData(product, target, open, options) {
|
|
|
7262
7296
|
const text = readFileSync(file, "utf8");
|
|
7263
7297
|
const session = open(target.dbUrl);
|
|
7264
7298
|
try {
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
log(`Would run ${devData.file} (${text.split("\n").length} lines) in one transaction.`);
|
|
7270
|
-
return null;
|
|
7271
|
-
}
|
|
7272
|
-
await session.runAs(member.id, text);
|
|
7273
|
-
return {
|
|
7274
|
-
member,
|
|
7275
|
-
file: devData.file
|
|
7276
|
-
};
|
|
7299
|
+
return await seed(session, devData.file, text, options, log);
|
|
7300
|
+
} catch (err) {
|
|
7301
|
+
if (isMissingSchemaError(err)) throw new DevDataError(`This database does not have ${product.config.name}'s tables yet (${err.message}). Run \`devtools setup\` first, or \`devtools db sync\` if you have already set up.`);
|
|
7302
|
+
throw err;
|
|
7277
7303
|
} finally {
|
|
7278
7304
|
await session.close();
|
|
7279
7305
|
}
|
|
7280
7306
|
}
|
|
7307
|
+
async function seed(session, file, text, options, log) {
|
|
7308
|
+
const member = options.member ? await session.memberByRef(options.member) : (await session.members(options.provider))[0] ?? null;
|
|
7309
|
+
if (!member) throw new DevDataError(options.member ? `No user matches ${options.member} in this database.` : `Nobody has signed in with DevDogs on this database yet. Start the app, sign in, then run this again (or name someone with --member).`);
|
|
7310
|
+
log(`Seeding as ${member.email ?? member.id} (${member.id})`);
|
|
7311
|
+
if (options.dryRun) {
|
|
7312
|
+
log(`Would run ${file} (${text.split("\n").length} lines) in one transaction.`);
|
|
7313
|
+
return null;
|
|
7314
|
+
}
|
|
7315
|
+
await session.runAs(member.id, text);
|
|
7316
|
+
return {
|
|
7317
|
+
member,
|
|
7318
|
+
file
|
|
7319
|
+
};
|
|
7320
|
+
}
|
|
7281
7321
|
//#endregion
|
|
7282
7322
|
//#region src/product/management.ts
|
|
7283
7323
|
/**
|
|
@@ -8033,7 +8073,7 @@ async function runDoctor(product, deps) {
|
|
|
8033
8073
|
const info = (message) => void lines.push(`INFO ${message}`);
|
|
8034
8074
|
ok(`${product.config.name} (${product.config.product}), Supabase CLI pinned at ${product.config.supabase.version}`);
|
|
8035
8075
|
const cli = await cliFor(product, deps);
|
|
8036
|
-
if (cli.source === "npx") info(`The pinned Supabase CLI is fetched with
|
|
8076
|
+
if (cli.source === "pnpm" || cli.source === "npx") info(`The pinned Supabase CLI is fetched with ${cli.command} on first use (${cliLine(cli, ["--version"])}).`);
|
|
8037
8077
|
else ok(`Supabase CLI ${product.config.supabase.version} (${cli.source})`);
|
|
8038
8078
|
const docker = await deps.run("docker", [
|
|
8039
8079
|
"info",
|
|
@@ -8507,7 +8547,7 @@ async function main(typed) {
|
|
|
8507
8547
|
await handleCompletions(argv.slice(1));
|
|
8508
8548
|
return;
|
|
8509
8549
|
}
|
|
8510
|
-
if (argv
|
|
8550
|
+
if (isVersionRequest(argv)) {
|
|
8511
8551
|
process.stdout.write(`${ownVersion()}\n`);
|
|
8512
8552
|
return;
|
|
8513
8553
|
}
|
|
@@ -8517,6 +8557,10 @@ async function main(typed) {
|
|
|
8517
8557
|
return;
|
|
8518
8558
|
}
|
|
8519
8559
|
const startPath = process.stdin.isTTY ? bareGroupStartPath(catalog, argv) : null;
|
|
8560
|
+
if (argv.length === 0 && isNonInteractive()) {
|
|
8561
|
+
console.log(renderHelp(catalog));
|
|
8562
|
+
return;
|
|
8563
|
+
}
|
|
8520
8564
|
const banners = !isNonInteractive();
|
|
8521
8565
|
if (banners) intro("DevDogs devtools");
|
|
8522
8566
|
let closing;
|
|
@@ -270,6 +270,10 @@ function ownVersion() {
|
|
|
270
270
|
const pkg = JSON.parse(readFileSync(join(ownPackageDir(), "package.json"), "utf8"));
|
|
271
271
|
return typeof pkg.version === "string" ? pkg.version : "0.0.0";
|
|
272
272
|
}
|
|
273
|
+
/** `devtools version`, `devtools --version`, `devtools -V`: answered anywhere. */
|
|
274
|
+
function isVersionRequest(argv) {
|
|
275
|
+
return argv[0] === "version" || argv[0] === "--version" || argv[0] === "-V";
|
|
276
|
+
}
|
|
273
277
|
//#endregion
|
|
274
278
|
//#region ../cli-core/src/failure-log.ts
|
|
275
279
|
/**
|
|
@@ -425,78 +429,4 @@ function installFailureLog(options) {
|
|
|
425
429
|
});
|
|
426
430
|
}
|
|
427
431
|
//#endregion
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Where devtools finds the DevDogsUGA checkout it is running against.
|
|
431
|
-
*
|
|
432
|
-
* devtools used to live inside `packages/devtools` of that repo, so its own
|
|
433
|
-
* `import.meta.url` WAS a path into the repo (`PROJECT_ROOT` /
|
|
434
|
-
* `REPO_ROOT` walked up a fixed number of `..` segments from this file).
|
|
435
|
-
* Published as its own package and run through `pnpm dlx`, that assumption
|
|
436
|
-
* breaks: this file's `import.meta.url` points into a dlx cache directory
|
|
437
|
-
* or an isolated `node_modules` tree that has nothing to do with the repo
|
|
438
|
-
* the contributor is standing in.
|
|
439
|
-
*
|
|
440
|
-
* So repo discovery walks up from `process.cwd()` instead, looking for the
|
|
441
|
-
* marker validated in the `devtools-dlx` prototype
|
|
442
|
-
* (`/home/sloan/scratchpad/devdogs/prototypes/devtools-dlx/FINDINGS.md`,
|
|
443
|
-
* experiment 1): a directory containing `pnpm-workspace.yaml` AND whose
|
|
444
|
-
* `package.json` has `"name": "devdogs-monorepo"` (DevDogsUGA) or
|
|
445
|
-
* `"backstage"` (Backstage, which the CLIs also run from; `layout.ts` says
|
|
446
|
-
* what differs). The name check is not redundant — a bare
|
|
447
|
-
* `pnpm-workspace.yaml` matches any pnpm workspace, which devtools should
|
|
448
|
-
* refuse rather than silently "find".
|
|
449
|
-
*/
|
|
450
|
-
/**
|
|
451
|
-
* The `package.json` names a repo root may carry: DevDogsUGA's, and Backstage's
|
|
452
|
-
* (the CLIs run from both; see `layout.ts`).
|
|
453
|
-
*/
|
|
454
|
-
const REPO_MARKER_NAMES = ["devdogs-monorepo", "backstage"];
|
|
455
|
-
var RepoNotFoundError = class extends Error {
|
|
456
|
-
constructor() {
|
|
457
|
-
super("run this from inside a DevDogsUGA clone");
|
|
458
|
-
this.name = "RepoNotFoundError";
|
|
459
|
-
}
|
|
460
|
-
};
|
|
461
|
-
function looksLikeRepoRoot(dir) {
|
|
462
|
-
if (!existsSync(join(dir, "pnpm-workspace.yaml"))) return false;
|
|
463
|
-
try {
|
|
464
|
-
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
|
|
465
|
-
return REPO_MARKER_NAMES.includes(pkg.name);
|
|
466
|
-
} catch {
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Walks up from `startDir` (default `process.cwd()`) looking for the repo
|
|
472
|
-
* marker. Returns `null` rather than throwing — `findRepoRoot()` below is
|
|
473
|
-
* the throwing convenience most callers want; this is exported for callers
|
|
474
|
-
* (like `setup`) that need to know without failing.
|
|
475
|
-
*/
|
|
476
|
-
function discoverRepoRoot(startDir = process.cwd()) {
|
|
477
|
-
let dir = startDir;
|
|
478
|
-
for (;;) {
|
|
479
|
-
if (looksLikeRepoRoot(dir)) return dir;
|
|
480
|
-
const parent = dirname(dir);
|
|
481
|
-
if (parent === dir) return null;
|
|
482
|
-
dir = parent;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
let cachedRoot;
|
|
486
|
-
/**
|
|
487
|
-
* The memoized, throwing repo-root lookup. Lazy on purpose: importing this
|
|
488
|
-
* module must never fail just because nothing has called it yet (`setup`
|
|
489
|
-
* and `completions` in `launch.ts` never need a repo at all, and must stay
|
|
490
|
-
* that way — see that file's header comment on why).
|
|
491
|
-
*
|
|
492
|
-
* Resolved once per process: `process.cwd()` does not change mid-invocation
|
|
493
|
-
* for this CLI, and re-walking the filesystem on every call would be pure
|
|
494
|
-
* waste.
|
|
495
|
-
*/
|
|
496
|
-
function findRepoRoot() {
|
|
497
|
-
if (cachedRoot === void 0) cachedRoot = process.env.DEVTOOLS_TEST_REPO_ROOT ?? discoverRepoRoot();
|
|
498
|
-
if (cachedRoot === null) throw new RepoNotFoundError();
|
|
499
|
-
return cachedRoot;
|
|
500
|
-
}
|
|
501
|
-
//#endregion
|
|
502
|
-
export { noteError as a, ownPackageDir as c, JSON_FLAG as d, SCOPES as f, positionals as g, flagValue as h, installFailureLog as i, ownVersion as l, createCatalog as m, discoverRepoRoot as n, noteRan as o, YES as p, findRepoRoot as r, suppressFailureLog as s, RepoNotFoundError as t, cliName as u };
|
|
432
|
+
export { isVersionRequest as a, cliName as c, YES as d, createCatalog as f, suppressFailureLog as i, JSON_FLAG as l, positionals as m, noteError as n, ownPackageDir as o, flagValue as p, noteRan as r, ownVersion as s, installFailureLog as t, SCOPES as u };
|
package/dist/launch.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { D as
|
|
4
|
-
import {
|
|
1
|
+
import { n as discoverRepoRoot, r as findRepoRoot, t as RepoNotFoundError } from "./root-PA8K5G2d.js";
|
|
2
|
+
import { b as setDryRun, d as loadEnvLoad, f as loadEnvSession, m as formatCommand, v as isDryRun, y as resolveDryRun } from "./run-CRBte7p0.js";
|
|
3
|
+
import { D as catalog, E as setProductMode, N as setEnvironmentRoot, O as helpPath, S as findProductRoot, c as nonEmpty, f as enterSessionEnvironment, g as errorMessage, h as bail, m as setMenuEnvHook, n as bareGroupStartPath, p as realEnvEntryDeps, y as unwrap } from "./menu-oQE5IqAI.js";
|
|
4
|
+
import { a as isVersionRequest, c as cliName, t as installFailureLog } from "./failure-log-MSdCgvLc.js";
|
|
5
|
+
import { c as lastSentryEventId, f as hasYes, h as stripTierFlag, m as stripNoEnvFlag, n as captureDevtoolsError, o as initDevtoolsTelemetry, p as isNonInteractive } from "./telemetry-BDTAGquh.js";
|
|
5
6
|
import { confirm, select } from "@clack/prompts";
|
|
6
7
|
//#region ../cli-core/src/session.ts
|
|
7
8
|
/**
|
|
@@ -158,10 +159,20 @@ function isEnvFreeCommand(rest) {
|
|
|
158
159
|
function skipsEnvEntry(rest) {
|
|
159
160
|
return declaredCommand(rest)?.noEnv === true;
|
|
160
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* The one clear sentence for a command that needs a checkout when run from
|
|
164
|
+
* somewhere that is neither a DevDogsUGA clone nor a product repository.
|
|
165
|
+
* Printed and exited on directly, so it is never a stack trace or a Sentry
|
|
166
|
+
* event: the person only needs to change directory.
|
|
167
|
+
*/
|
|
168
|
+
function outsideRepoMessage(rest) {
|
|
169
|
+
const path = helpPath(rest);
|
|
170
|
+
return `${path.length > 0 ? `\`devtools ${path.join(" ")}\`` : "`devtools`"} needs a DevDogsUGA clone or a product repository (one with a devtools.config.json, like DogDays or DogPack), and this directory is neither. \`devtools --help\` and \`devtools --version\` work anywhere.`;
|
|
171
|
+
}
|
|
161
172
|
/** The offer's stack start (`env-entry.ts` holds the TTY prompt, this holds
|
|
162
173
|
* the lifecycle command), imported lazily like the rest of the commands. */
|
|
163
174
|
async function startStack() {
|
|
164
|
-
const { runStackCommand } = await import("./stack-
|
|
175
|
+
const { runStackCommand } = await import("./stack-Cl_B_dt7.js");
|
|
165
176
|
return runStackCommand("start");
|
|
166
177
|
}
|
|
167
178
|
/**
|
|
@@ -172,11 +183,11 @@ async function startStack() {
|
|
|
172
183
|
* post-tier-resolution path.
|
|
173
184
|
*/
|
|
174
185
|
async function dispatch(argv) {
|
|
175
|
-
const { main } = await import("./cli-
|
|
186
|
+
const { main } = await import("./cli-DNZ-6WEI.js");
|
|
176
187
|
try {
|
|
177
188
|
await main(argv);
|
|
178
189
|
} catch (err) {
|
|
179
|
-
process.stderr.write(`devtools: ${errorMessage(err)}\n`);
|
|
190
|
+
process.stderr.write(`devtools: ${err instanceof RepoNotFoundError ? outsideRepoMessage(argv) : errorMessage(err)}\n`);
|
|
180
191
|
await captureDevtoolsError(err);
|
|
181
192
|
process.exit(1);
|
|
182
193
|
}
|
|
@@ -242,8 +253,10 @@ async function launch(argv) {
|
|
|
242
253
|
});
|
|
243
254
|
ignoreClosedPipes();
|
|
244
255
|
initDevtoolsTelemetry(rest[0] ?? "menu");
|
|
245
|
-
|
|
256
|
+
const productRoot = findProductRoot();
|
|
257
|
+
if (productRoot !== null) {
|
|
246
258
|
setProductMode(true);
|
|
259
|
+
setEnvironmentRoot(productRoot);
|
|
247
260
|
process.env.DEPLOY_ENV = "development";
|
|
248
261
|
await dispatch(rest);
|
|
249
262
|
return;
|
|
@@ -253,10 +266,14 @@ async function launch(argv) {
|
|
|
253
266
|
await dispatch(rest);
|
|
254
267
|
return;
|
|
255
268
|
}
|
|
256
|
-
if (rest
|
|
269
|
+
if (isVersionRequest(rest)) {
|
|
257
270
|
await dispatch(rest);
|
|
258
271
|
return;
|
|
259
272
|
}
|
|
273
|
+
if (discoverRepoRoot() === null && rest[0] !== "setup" && rest[0] !== "completions" && !skipsEnvEntry(rest) && !isEnvFreeCommand(rest)) {
|
|
274
|
+
process.stderr.write(`devtools: ${outsideRepoMessage(rest)}\n`);
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
260
277
|
const envLoad = await loadEnvLoad();
|
|
261
278
|
const envSession = await loadEnvSession();
|
|
262
279
|
process.env[envLoad.SHELL_KEYS_ENV] ??= Object.keys(process.env).join(",");
|
|
@@ -303,7 +320,7 @@ async function launch(argv) {
|
|
|
303
320
|
return;
|
|
304
321
|
}
|
|
305
322
|
const run = () => gated(tier, rest, () => dispatch(rest), void 0);
|
|
306
|
-
if (noEnv || skipsEnvEntry(rest)) {
|
|
323
|
+
if (noEnv || skipsEnvEntry(rest) || isEnvFreeCommand(rest) && discoverRepoRoot() === null) {
|
|
307
324
|
process.env.DEPLOY_ENV = tier;
|
|
308
325
|
if (devDatabase !== void 0) process.env.DEV_DB = devDatabase;
|
|
309
326
|
await run();
|
|
@@ -313,4 +330,4 @@ async function launch(argv) {
|
|
|
313
330
|
}
|
|
314
331
|
if (import.meta.url === `file://${process.argv[1]}`) await launch(process.argv.slice(2));
|
|
315
332
|
//#endregion
|
|
316
|
-
export { launch, stripTierFlag };
|
|
333
|
+
export { launch, outsideRepoMessage, stripTierFlag };
|
|
@@ -520,7 +520,10 @@ async function probeLocalStack(port = LOCAL_STACK_PORT, timeoutMs = 250) {
|
|
|
520
520
|
* exiting the whole process out from under an unrelated caller would be a far
|
|
521
521
|
* worse failure than a rejected promise.
|
|
522
522
|
*/
|
|
523
|
-
async function
|
|
523
|
+
async function locateRepoRoot() {
|
|
524
|
+
const { discoverRepoRoot, RepoNotFoundError } = await import("./root-DfH38DFq.js");
|
|
525
|
+
const fromCwd = discoverRepoRoot();
|
|
526
|
+
if (fromCwd !== null) return fromCwd;
|
|
524
527
|
const { existsSync } = await import("node:fs");
|
|
525
528
|
const { dirname, join, resolve } = await import("node:path");
|
|
526
529
|
const { fileURLToPath } = await import("node:url");
|
|
@@ -528,7 +531,7 @@ async function findRepoRoot() {
|
|
|
528
531
|
for (;;) {
|
|
529
532
|
if (existsSync(join(dir, "pnpm-workspace.yaml"))) return dir;
|
|
530
533
|
const parent = dirname(dir);
|
|
531
|
-
if (parent === dir) throw new
|
|
534
|
+
if (parent === dir) throw new RepoNotFoundError();
|
|
532
535
|
dir = parent;
|
|
533
536
|
}
|
|
534
537
|
}
|
|
@@ -564,7 +567,7 @@ async function findRepoRoot() {
|
|
|
564
567
|
*/
|
|
565
568
|
async function loadEnvironment(deployEnv, options, context) {
|
|
566
569
|
const override = options?.override ?? false;
|
|
567
|
-
const root = context?.root ?? await
|
|
570
|
+
const root = context?.root ?? await locateRepoRoot();
|
|
568
571
|
let exists = context?.exists;
|
|
569
572
|
if (!exists) {
|
|
570
573
|
const { existsSync } = await import("node:fs");
|
|
@@ -637,4 +640,4 @@ async function loadEnvironment(deployEnv, options, context) {
|
|
|
637
640
|
};
|
|
638
641
|
}
|
|
639
642
|
//#endregion
|
|
640
|
-
export {
|
|
643
|
+
export { UnknownEnvironmentError as _, LocalStackOfflineError as a, applyDeployTierAliases as c, loadEnvironment as d, locateRepoRoot as f, DEPLOY_ENVIRONMENTS as g, selectEnvFiles as h, LOCAL_STACK_PORT as i, applyWranglerLocalDatabaseAlias as l, probeLocalStack as m, GENERATED_FILE as n, MissingEnvFileError as o, parseRawAssignments as p, HYPERDRIVE_LOCAL_CONNECTION_ENV as r, SHELL_KEYS_ENV as s, DEV_DB_ENV as t, isDevDatabase as u, fileFor as v, isDeployEnvironment as y };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as LocalStackOfflineError, c as applyDeployTierAliases, d as loadEnvironment, f as locateRepoRoot, h as selectEnvFiles, i as LOCAL_STACK_PORT, l as applyWranglerLocalDatabaseAlias, m as probeLocalStack, n as GENERATED_FILE, o as MissingEnvFileError, p as parseRawAssignments, r as HYPERDRIVE_LOCAL_CONNECTION_ENV, s as SHELL_KEYS_ENV, t as DEV_DB_ENV, u as isDevDatabase } from "./load-Z2CXCpyx.js";
|
|
2
|
+
export { DEV_DB_ENV, GENERATED_FILE, HYPERDRIVE_LOCAL_CONNECTION_ENV, LOCAL_STACK_PORT, LocalStackOfflineError, MissingEnvFileError, SHELL_KEYS_ENV, applyDeployTierAliases, applyWranglerLocalDatabaseAlias, isDevDatabase, loadEnvironment, locateRepoRoot, parseRawAssignments, probeLocalStack, selectEnvFiles };
|