@smoothbricks/cli 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/cli.js +5 -2
  2. package/dist/github-ci/index.js +4 -3
  3. package/dist/lib/conflict-markers.d.ts.map +1 -1
  4. package/dist/lib/workspace.d.ts +1 -1
  5. package/dist/lib/workspace.d.ts.map +1 -1
  6. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  7. package/dist/monorepo/ci-workflow.js +1 -0
  8. package/dist/monorepo/lockfile.d.ts +2 -0
  9. package/dist/monorepo/lockfile.d.ts.map +1 -1
  10. package/dist/monorepo/lockfile.js +13 -2
  11. package/dist/monorepo/managed-files.d.ts +1 -0
  12. package/dist/monorepo/managed-files.d.ts.map +1 -1
  13. package/dist/monorepo/managed-files.js +12 -5
  14. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  15. package/dist/monorepo/publish-workflow.js +1 -0
  16. package/dist/monorepo/tool-validation.d.ts.map +1 -1
  17. package/dist/monorepo/tool-validation.js +20 -7
  18. package/dist/release/github-release.d.ts +2 -2
  19. package/dist/wrangler/prepare-env.d.ts.map +1 -1
  20. package/dist/wrangler/prepare-env.js +1 -1
  21. package/dist/wrangler/scaffold.d.ts.map +1 -1
  22. package/dist/wrangler/scaffold.js +1 -1
  23. package/managed/raw/tooling/direnv/setup-environment.ts +2 -8
  24. package/managed/raw/tooling/git-hooks/pre-commit.sh +6 -0
  25. package/package.json +3 -13
  26. package/src/cli.ts +7 -4
  27. package/src/github-ci/index.ts +5 -3
  28. package/src/monorepo/__tests__/ci-workflow.test.ts +2 -0
  29. package/src/monorepo/__tests__/publish-workflow.test.ts +12 -4
  30. package/src/monorepo/ci-workflow.ts +2 -0
  31. package/src/monorepo/lockfile.test.ts +157 -0
  32. package/src/monorepo/lockfile.ts +15 -2
  33. package/src/monorepo/managed-files.test.ts +13 -0
  34. package/src/monorepo/managed-files.ts +20 -5
  35. package/src/monorepo/package-policy.test.ts +7 -37
  36. package/src/monorepo/publish-workflow.ts +2 -0
  37. package/src/monorepo/tool-validation.test.ts +59 -24
  38. package/src/monorepo/tool-validation.ts +21 -7
  39. package/src/monorepo/wrangler.test.ts +9 -2
  40. package/src/release/__tests__/fixture-repo.test.ts +8 -0
  41. package/src/release/__tests__/helpers/fixture-repo.ts +28 -8
  42. package/src/wrangler/prepare-env.ts +14 -4
  43. package/src/wrangler/scaffold.ts +8 -3
@@ -82,9 +82,14 @@ export async function writeBuildablePackage(
82
82
  );
83
83
  }
84
84
 
85
- export async function git(root: string, args: string[], env?: Record<string, string>): Promise<void> {
86
- const result = await gitResult(root, args, env);
87
- if (result.exitCode !== 0) {
85
+ export async function git(
86
+ root: string,
87
+ args: string[],
88
+ env?: Record<string, string>,
89
+ timeoutMs = GIT_TIMEOUT_MS,
90
+ ): Promise<void> {
91
+ const result = await gitResult(root, args, env, timeoutMs);
92
+ if (result.timedOut || result.exitCode !== 0) {
88
93
  throw new Error(gitErrorMessage(root, args, result));
89
94
  }
90
95
  }
@@ -101,9 +106,15 @@ export async function gitSucceeds(root: string, args: string[]): Promise<boolean
101
106
  return (await gitResult(root, args)).exitCode === 0;
102
107
  }
103
108
 
104
- async function gitResult(root: string, args: string[], env?: Record<string, string>): Promise<GitResult> {
109
+ async function gitResult(
110
+ root: string,
111
+ args: string[],
112
+ env?: Record<string, string>,
113
+ timeoutMs = GIT_TIMEOUT_MS,
114
+ ): Promise<GitResult> {
105
115
  const proc = Bun.spawn(['git', ...args], {
106
116
  cwd: root,
117
+ detached: true,
107
118
  env: { ...process.env, ...GIT_FIXTURE_ENV, ...env },
108
119
  stdout: 'pipe',
109
120
  stderr: 'pipe',
@@ -111,15 +122,23 @@ async function gitResult(root: string, args: string[], env?: Record<string, stri
111
122
  let timedOut = false;
112
123
  const timeout = setTimeout(() => {
113
124
  timedOut = true;
114
- proc.kill();
115
- }, GIT_TIMEOUT_MS);
125
+ try {
126
+ // `git` may exit after spawning a transport or hook which still owns its
127
+ // pipes. Killing the detached process group closes every inherited pipe.
128
+ process.kill(-proc.pid, 'SIGKILL');
129
+ } catch (error) {
130
+ if (!(error instanceof Error && 'code' in error && error.code === 'ESRCH')) {
131
+ proc.kill('SIGKILL');
132
+ }
133
+ }
134
+ }, timeoutMs);
116
135
  try {
117
136
  const [exitCode, stdout, stderr] = await Promise.all([
118
137
  proc.exited,
119
138
  streamBytes(proc.stdout),
120
139
  streamBytes(proc.stderr),
121
140
  ]);
122
- return { exitCode, stdout, stderr, timedOut };
141
+ return { exitCode, stdout, stderr, timedOut, timeoutMs };
123
142
  } finally {
124
143
  clearTimeout(timeout);
125
144
  }
@@ -151,12 +170,13 @@ interface GitResult {
151
170
  stdout: Uint8Array;
152
171
  stderr: Uint8Array;
153
172
  timedOut: boolean;
173
+ timeoutMs: number;
154
174
  }
155
175
 
156
176
  function gitErrorMessage(root: string, args: string[], result: GitResult): string {
157
177
  const stderr = new TextDecoder().decode(result.stderr).trim();
158
178
  const timeoutText = result.timedOut
159
- ? ` timed out after ${GIT_TIMEOUT_MS}ms`
179
+ ? ` timed out after ${result.timeoutMs}ms`
160
180
  : ` failed with exit code ${result.exitCode}`;
161
181
  return [`git ${args.join(' ')}${timeoutText}`, `cwd: ${root}`, stderr].filter(Boolean).join('\n');
162
182
  }
@@ -60,7 +60,13 @@ function kvIn(toml: string, table: AST.TOMLTable, key: string): AST.TOMLKeyValue
60
60
  }
61
61
 
62
62
  /** The `<field>` KV of the `[[env.<env>.<arrayKey>]]` table whose `binding` matches, or null. */
63
- function arrayTableKv(toml: string, env: string, arrayKey: string, binding: string, field: string): AST.TOMLKeyValue | null {
63
+ function arrayTableKv(
64
+ toml: string,
65
+ env: string,
66
+ arrayKey: string,
67
+ binding: string,
68
+ field: string,
69
+ ): AST.TOMLKeyValue | null {
64
70
  const block = envRecord(toml, env);
65
71
  const rows = isRecord(block) && Array.isArray(block[arrayKey]) ? block[arrayKey] : [];
66
72
  const index = rows.findIndex((r) => isRecord(r) && r.binding === binding);
@@ -173,7 +179,8 @@ export function getD1Name(toml: string, env: string, binding: string): string |
173
179
  const block = envRecord(toml, env);
174
180
  const rows = isRecord(block) && Array.isArray(block.d1_databases) ? block.d1_databases : [];
175
181
  for (const row of rows) {
176
- if (isRecord(row) && row.binding === binding && typeof row.database_name === 'string') return row.database_name || null;
182
+ if (isRecord(row) && row.binding === binding && typeof row.database_name === 'string')
183
+ return row.database_name || null;
177
184
  }
178
185
  return null;
179
186
  }
@@ -193,7 +200,10 @@ export function blankD1Ids(toml: string, env: string): string {
193
200
  /** Blank one field across every `[[env.<env>.<arrayKey>]]` table (value..EOL -> `""`). */
194
201
  function blankArrayField(toml: string, env: string, arrayKey: string, field: string): string {
195
202
  const edits = tables(toml)
196
- .filter((t) => t.kind === 'array' && t.resolvedKey[0] === 'env' && t.resolvedKey[1] === env && t.resolvedKey[2] === arrayKey)
203
+ .filter(
204
+ (t) =>
205
+ t.kind === 'array' && t.resolvedKey[0] === 'env' && t.resolvedKey[1] === env && t.resolvedKey[2] === arrayKey,
206
+ )
197
207
  .map((t) => kvIn(toml, t, field))
198
208
  .flatMap((kv) => (kv ? [{ start: kv.value.range[0], end: endOfLine(toml, kv.value.range[1]) }] : []));
199
209
  return applyBlanks(toml, edits);
@@ -332,7 +342,7 @@ export async function ensureNamespace(logical: string, existing: KvNamespace[],
332
342
  try {
333
343
  await $`bunx wrangler kv namespace create ${logical}`.cwd(cwd).quiet();
334
344
  } catch (err) {
335
- return errText(err).includes('already') ? (await reList(logical, cwd)) : null;
345
+ return errText(err).includes('already') ? await reList(logical, cwd) : null;
336
346
  }
337
347
  return reList(logical, cwd);
338
348
  }
@@ -16,7 +16,10 @@ export interface ScaffoldOptions {
16
16
  }
17
17
 
18
18
  /** Locate a workspace package by nx name, package name, or relative path; must have a wrangler.toml. */
19
- function resolveProject(root: string, project: string): { dir: string; label: string; packageJsonPath: string; json: Record<string, unknown> } {
19
+ function resolveProject(
20
+ root: string,
21
+ project: string,
22
+ ): { dir: string; label: string; packageJsonPath: string; json: Record<string, unknown> } {
20
23
  const manifests = getWorkspacePackageManifests(root);
21
24
  const match = manifests.find((m) => {
22
25
  const nx = recordProperty(m.json, 'nx');
@@ -83,7 +86,7 @@ async function checkMode(env: string): Promise<void> {
83
86
  for (const binding of kvBindings) {
84
87
  const inToml = pe.getKvId(toml, env, binding);
85
88
  const liveId = live.find((n) => n.title === kvTitle(binding, env))?.id ?? null;
86
- p.log.message(\` KV \${binding}: \${!liveId ? '✗ not created' : inToml === liveId ? \`✓ \${liveId}\` : \`⚠ drift (live \${liveId}, toml \${inToml ?? 'unset'})\`}\`);
89
+ p.log.message(\` KV \${binding}: \${!liveId ? '✗ not created' : inToml === liveId ? \`✓ \${liveId}\` : \`! drift (live \${liveId}, toml \${inToml ?? 'unset'})\`}\`);
87
90
  }
88
91
  for (const name of vars) {
89
92
  p.log.message(\` var \${name}: \${pe.getVar(toml, env, name) ? '✓ set' : '✗ empty'}\`);
@@ -234,6 +237,8 @@ export function scaffold(root: string, project: string, options: ScaffoldOptions
234
237
  console.log(`updated ${label}/package.json prepare-env target`);
235
238
  }
236
239
 
237
- console.log(`\nnext: fill secret NAMES in ${label}/.dev.vars.example, then\n bunx nx run ${project}:prepare-env -- <env>`);
240
+ console.log(
241
+ `\nnext: fill secret NAMES in ${label}/.dev.vars.example, then\n bunx nx run ${project}:prepare-env -- <env>`,
242
+ );
238
243
  return scriptPath;
239
244
  }