@smoothbricks/cli 0.10.15 → 0.10.17

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 CHANGED
@@ -3,9 +3,10 @@
3
3
  `@smoothbricks/cli` provides `smoo`, the SmoothBricks monorepo automation CLI. It is the control plane for shared CI,
4
4
  release, Git hook, package metadata, and publish validation conventions across SmoothBricks-style repositories.
5
5
 
6
- The tool is intentionally convention-over-configuration. SmoothBricks repos use [Nx], [Bun], [Nix], [devenv], and
7
- [direnv], so `smoo` assumes those pieces exist instead of adding another local config file. Repos should be made correct
8
- by running the mutating initialization path, then kept correct by the read-only validation path.
6
+ The tool is intentionally convention-over-configuration. SmoothBricks repos use [Nx], [Bun], [Nix], and [devenv]
7
+ (activated natively, or through [direnv] in repos that have not migrated), so `smoo` assumes those pieces exist instead
8
+ of adding another local config file. Repos should be made correct by running the mutating initialization path, then kept
9
+ correct by the read-only validation path.
9
10
 
10
11
  ## Install
11
12
 
@@ -266,6 +267,33 @@ Use tool-output names for concrete targets, such as `tsc-js`, `tsdown-js`, and `
266
267
  as aggregate targets. Package scripts may still use developer-friendly colon names, for example `build:wasm`, but those
267
268
  scripts should delegate to unambiguous Nx targets such as `nx run pkg:cargo-wasm`.
268
269
 
270
+ ## Package Structure
271
+
272
+ Workspace packages keep all TypeScript sources — and especially all test files — under a single root: `src/`.
273
+
274
+ ```
275
+ packages/<name>/
276
+ src/
277
+ foo.ts
278
+ foo.test.ts # unit tests: colocated with the module they defend
279
+ __tests__/ # cross-module/integration TS tests, still under src/
280
+ crates/*/tests/ # Rust integration tests (cargo-owned convention, unaffected)
281
+ scripts/ # non-shipped tooling; never *.test.ts
282
+ dist/, target/ # generated output, never scanned
283
+ ```
284
+
285
+ The test-location rule is not tidiness; it is what makes the generated tooling provably cover every test. The convention
286
+ is one _root_, not one path: `tsconfig.test.json` includes are generated as `src/**` patterns, and the bounded
287
+ `bun test` targets run with `cwd <package>/src` — both because `bun test <arg>` treats the argument as a filter over a
288
+ scan rooted at the cwd (scanning from the package root would walk a Rust package's entire cargo `target/` tree, tens of
289
+ seconds per run), and because a second test root would have to be threaded through every one of those consumers forever.
290
+ A test file outside `src/` is therefore neither typechecked nor executed, silently. `smoo monorepo validate` fails on
291
+ any `*.test.ts` / `*.spec.ts(x)` outside `src/` so that gap cannot reappear.
292
+
293
+ Within the single root, separation still exists where it matters: unit tests sit next to their modules, integration
294
+ tests live in `src/__tests__/`, and Rust crates keep cargo's own `tests/` directories, which the rule deliberately
295
+ ignores.
296
+
269
297
  ## Managed Files
270
298
 
271
299
  `smoo monorepo update` writes the managed files into a repository.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/github-ci/index.ts"],"names":[],"mappings":"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"}
@@ -491,7 +491,8 @@ export async function selectStageDeployProjects(candidates, stage, loadProject)
491
491
  const tags = Array.isArray(definition.tags)
492
492
  ? definition.tags.filter((tag) => typeof tag === 'string')
493
493
  : [];
494
- const isStageDerived = typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-stage');
494
+ const isStageDerived = tags.includes('stage-deploy-target') ||
495
+ (typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-stage'));
495
496
  const isStagingOnly = tags.includes('staging-deploy-target');
496
497
  if (isStageDerived || (stage === 'staging' && isStagingOnly)) {
497
498
  selected.push(project);
@@ -15,6 +15,14 @@ export declare function validateRootPackagePolicy(root: string): number;
15
15
  export declare function validateNxReleaseConfig(root: string): number;
16
16
  export declare function validateNxProjectNames(root: string): number;
17
17
  export declare function validatePublicTags(root: string): number;
18
+ /**
19
+ * Every test file must live under the package's `src/`. The convention is
20
+ * otherwise only encoded generatively — tsconfig.test.json includes are
21
+ * `src/**` and the bounded bun-test targets run with cwd `<package>/src` —
22
+ * so a test file anywhere else is neither typechecked nor executed, with no
23
+ * diagnostic. This check turns that silent gap into a validation failure.
24
+ */
25
+ export declare function validateTestFileLocations(root: string): number;
18
26
  export declare function validatePublicPackageMetadata(root: string): number;
19
27
  export declare function validateWorkspaceDependencies(root: string, options?: PackageTargetPolicyOptions): number;
20
28
  //# sourceMappingURL=package-policy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"package-policy.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-policy.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,+CAA+C,CAAC;AAoCvD,YAAY,EAAE,0BAA0B,IAAI,iCAAiC,EAAE,sBAAsB,EAAE,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,CAAC;AAYhE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0C7D;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,IAAI,CAwB7G;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAoB7D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAczD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsC9D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB3D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgElE;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,MAAM,CAkC5G"}
1
+ {"version":3,"file":"package-policy.d.ts","sourceRoot":"","sources":["../../src/monorepo/package-policy.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC5B,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAGL,2BAA2B,EAC3B,uBAAuB,EACxB,MAAM,+CAA+C,CAAC;AAoCvD,YAAY,EAAE,0BAA0B,IAAI,iCAAiC,EAAE,sBAAsB,EAAE,CAAC;AACxG,OAAO,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,CAAC;AAYhE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAuB1D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMxD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA0C7D;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,IAAI,CAwB7G;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzD;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAoB7D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAEvE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAczD;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsC9D;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW5D;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAwB3D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAcvD;AAoBD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW9D;AAgCD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgElE;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,0BAA+B,GAAG,MAAM,CAkC5G"}
@@ -1,4 +1,5 @@
1
- import { join } from 'node:path';
1
+ import { readdirSync } from 'node:fs';
2
+ import { join, relative } from 'node:path';
2
3
  import { applyWorkspaceBoundedTestTargetPolicy, checkWorkspaceBoundedTestTargetPolicy, } from '@smoothbricks/nx-plugin/bounded-test-policy';
3
4
  import { applyPackageTargetPolicy, checkPackageTargetPolicy, } from '@smoothbricks/nx-plugin/package-target-policy';
4
5
  import { applyReleaseConfigPolicy, checkReleaseConfigPolicy, SMOO_NX_RELEASE_TAG_PATTERN, SMOO_NX_VERSION_ACTIONS, } from '@smoothbricks/nx-plugin/release-config-policy';
@@ -258,6 +259,69 @@ export function validatePublicTags(root) {
258
259
  console.log('npm:public tags are valid.');
259
260
  return 0;
260
261
  }
262
+ const testFilePattern = /\.(test|spec)\.tsx?$/;
263
+ /** Directories that legitimately hold generated/vendored trees a test-file
264
+ * scan must never descend into (cargo target/ alone holds 100k+ files). */
265
+ const testScanSkippedDirectories = new Set([
266
+ 'node_modules',
267
+ 'dist',
268
+ 'dist-test',
269
+ 'target',
270
+ 'coverage',
271
+ 'tmp',
272
+ '.git',
273
+ '.devenv',
274
+ '.direnv',
275
+ '.nx',
276
+ '.cache',
277
+ ]);
278
+ /**
279
+ * Every test file must live under the package's `src/`. The convention is
280
+ * otherwise only encoded generatively — tsconfig.test.json includes are
281
+ * `src/**` and the bounded bun-test targets run with cwd `<package>/src` —
282
+ * so a test file anywhere else is neither typechecked nor executed, with no
283
+ * diagnostic. This check turns that silent gap into a validation failure.
284
+ */
285
+ export function validateTestFileLocations(root) {
286
+ let failures = 0;
287
+ for (const pkg of getWorkspacePackages(root)) {
288
+ for (const stray of strayTestFiles(join(root, pkg.path))) {
289
+ console.error(`${pkg.projectName}: test file outside src/ is neither typechecked nor run by the bounded test targets: ${stray}`);
290
+ failures++;
291
+ }
292
+ }
293
+ return failures;
294
+ }
295
+ function strayTestFiles(packagePath) {
296
+ const stray = [];
297
+ const walk = (directory) => {
298
+ let entries;
299
+ try {
300
+ entries = readdirSync(directory, { withFileTypes: true });
301
+ }
302
+ catch {
303
+ return;
304
+ }
305
+ for (const entry of entries) {
306
+ const path = join(directory, entry.name);
307
+ if (entry.isDirectory()) {
308
+ if (testScanSkippedDirectories.has(entry.name)) {
309
+ continue;
310
+ }
311
+ if (directory === packagePath && entry.name === 'src') {
312
+ continue; // src/ is where tests belong.
313
+ }
314
+ walk(path);
315
+ continue;
316
+ }
317
+ if (entry.isFile() && testFilePattern.test(entry.name)) {
318
+ stray.push(relative(packagePath, path));
319
+ }
320
+ }
321
+ };
322
+ walk(packagePath);
323
+ return stray;
324
+ }
261
325
  export function validatePublicPackageMetadata(root) {
262
326
  const rootPackage = readJsonObject(join(root, 'package.json'));
263
327
  const rootRepository = rootPackage ? repositoryInfo(rootPackage) : null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,mBAAmB,CAAC;AAK5E,OAAO,EAKL,KAAK,sBAAsB,EAO5B,MAAM,sBAAsB,CAAC;AAU9B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,WAAW,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,YAAY,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAClE,iBAAiB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAqHD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,EACjC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0B7B;AAuMD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAexG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/monorepo/packs/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,cAAc,EAAsB,MAAM,mBAAmB,CAAC;AAK5E,OAAO,EAKL,KAAK,sBAAsB,EAQ5B,MAAM,sBAAsB,CAAC;AAU9B,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAClD,WAAW,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzD,YAAY,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC1D,gBAAgB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IAClE,iBAAiB,CAAC,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC9F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;CACtB;AAsHD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAItE;AAED,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,mBAAwB,EACjC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CA0B7B;AAuMD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAexG"}
@@ -6,7 +6,7 @@ import { syncBunLockfileVersions, validateBunLockfileVersions } from '../lockfil
6
6
  import { warnOnManagedFileDrift } from '../managed-files.js';
7
7
  import { fixNxSync, validateNxSync } from '../nx-sync.js';
8
8
  import { fixPackageHygiene, validatePackageHygiene } from '../package-hygiene.js';
9
- import { applyFixableMonorepoDefaults, applyNxReleaseDefaults, applyPublicPackageDefaults, applyWorkspaceDependencyDefaults, validateNxProjectNames, validateNxReleaseConfig, validatePublicPackageMetadata, validatePublicTags, validateRootPackagePolicy, validateWorkspaceDependencies, } from '../package-policy.js';
9
+ import { applyFixableMonorepoDefaults, applyNxReleaseDefaults, applyPublicPackageDefaults, applyWorkspaceDependencyDefaults, validateNxProjectNames, validateNxReleaseConfig, validatePublicPackageMetadata, validatePublicTags, validateRootPackagePolicy, validateTestFileLocations, validateWorkspaceDependencies, } from '../package-policy.js';
10
10
  import { validatePackedPublicPackageManifest, validatePackedPublicPackagePublint, validatePackedPublicPackageTypes, } from '../packed-package.js';
11
11
  import { syncRootRuntimeVersions, validateRootRuntimeVersions } from '../runtime.js';
12
12
  import { applyToolConfigDefaults, validateToolConfig } from '../tool-validation.js';
@@ -47,7 +47,8 @@ const packs = [
47
47
  validateNxProjectNames(ctx.root) +
48
48
  validateNxReleaseConfig(ctx.root) +
49
49
  validateBunLockfileVersions(ctx.root) +
50
- (await validateNxSync(ctx.root, ctx.verbose === true)));
50
+ (await validateNxSync(ctx.root, ctx.verbose === true)) +
51
+ validateTestFileLocations(ctx.root));
51
52
  },
52
53
  },
53
54
  {
@@ -388,7 +388,7 @@ function nixPackageComment(name) {
388
388
  return '# Builds ttsc source plugins';
389
389
  }
390
390
  if (name === 'sccache') {
391
- return '# Rust compiler wrapper and cache';
391
+ return '# Rust compiler cache; client of the host-owned daemon (cowshed sccache start)';
392
392
  }
393
393
  return '';
394
394
  }
@@ -1,5 +1,5 @@
1
1
  import type { ReleasePackageInfo, ReleaseTarget } from './core.js';
2
- export type ReleaseVersionMode = 'new' | 'none';
2
+ export type ReleaseVersionMode = 'new' | 'dry-run' | 'none';
3
3
  export interface ReleaseSummary<Package extends ReleasePackageInfo = ReleasePackageInfo> {
4
4
  sha: string;
5
5
  dryRun: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/release/orchestration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/release/orchestration.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ export async function runReleaseVersion(shell, options) {
18
18
  const headBeforeVersioning = await shell.gitHead();
19
19
  const dryRunPackages = await shell.runNxReleaseVersion(versionPackages, options.bump, options.dryRun);
20
20
  if (options.dryRun) {
21
- return { mode: 'none', packages: dryRunPackages, status: 'dry-run' };
21
+ return { mode: 'dry-run', packages: dryRunPackages, status: 'dry-run' };
22
22
  }
23
23
  await shell.assertCleanGitTree();
24
24
  const headAfterVersioning = await shell.gitHead();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smoothbricks/cli",
3
- "version": "0.10.15",
3
+ "version": "0.10.17",
4
4
  "type": "module",
5
5
  "description": "SmoothBricks monorepo automation CLI",
6
6
  "bin": {
@@ -71,7 +71,7 @@
71
71
  "dependencies": {
72
72
  "@arethetypeswrong/core": "^0.18.2",
73
73
  "@prettier/sync": "^0.6.1",
74
- "@smoothbricks/nx-plugin": "0.3.6",
74
+ "@smoothbricks/nx-plugin": "0.3.7",
75
75
  "@smoothbricks/validation": "0.1.5",
76
76
  "commander": "^14.0.3",
77
77
  "prettier": "^3.6.1",
@@ -581,7 +581,8 @@ describe('event-aware stage deployment', () => {
581
581
  },
582
582
  },
583
583
  'conloca-app-backend': {
584
- targets: { deploy: { command: 'smoo wrangler deploy-stage --stage {args.stage}' } },
584
+ tags: ['stage-deploy-target'],
585
+ targets: { deploy: { command: 'bun scripts/deploy-backend.ts --stage={args.stage}' } },
585
586
  },
586
587
  'conloca-e2e-mail-capture': {
587
588
  tags: ['staging-deploy-target'],
@@ -613,7 +613,9 @@ export async function selectStageDeployProjects(
613
613
  const tags = Array.isArray(definition.tags)
614
614
  ? definition.tags.filter((tag): tag is string => typeof tag === 'string')
615
615
  : [];
616
- const isStageDerived = typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-stage');
616
+ const isStageDerived =
617
+ tags.includes('stage-deploy-target') ||
618
+ (typeof commandValue === 'string' && commandValue.includes('smoo wrangler deploy-stage'));
617
619
  const isStagingOnly = tags.includes('staging-deploy-target');
618
620
  if (isStageDerived || (stage === 'staging' && isStagingOnly)) {
619
621
  selected.push(project);
@@ -22,6 +22,7 @@ import {
22
22
  validateNxProjectNames,
23
23
  validateNxReleaseConfig,
24
24
  validateRootPackagePolicy,
25
+ validateTestFileLocations,
25
26
  validateWorkspaceDependencies,
26
27
  } from './package-policy.js';
27
28
 
@@ -200,6 +201,45 @@ describe('root smoo monorepo policy', () => {
200
201
  });
201
202
  });
202
203
 
204
+ describe('test file location policy', () => {
205
+ afterEach(() => {
206
+ console.error = originalConsoleError;
207
+ });
208
+
209
+ it('fails test files outside src/ and skips generated trees', async () => {
210
+ const root = await createWorkspace({
211
+ rootName: '@smoothbricks/codebase',
212
+ packages: [{ dir: 'app', name: '@smoothbricks/app' }],
213
+ });
214
+ try {
215
+ const app = join(root, 'packages/app');
216
+ // Allowed: anywhere under src/.
217
+ await writeSource(join(app, 'src/deep/feature.test.ts'));
218
+ // Ignored: generated/vendored trees are never scanned.
219
+ await writeSource(join(app, 'target/debug/build/foo/out/stray.test.ts'));
220
+ await writeSource(join(app, 'node_modules/dep/dep.test.ts'));
221
+ await writeSource(join(app, 'dist/bundled.test.ts'));
222
+ expect(validateTestFileLocations(root)).toBe(0);
223
+
224
+ // Stray: neither typechecked (tsconfig.test.json includes src/** only)
225
+ // nor run (bounded bun-test targets scan from src/).
226
+ await writeSource(join(app, 'scripts/helper.test.ts'));
227
+ await writeSource(join(app, 'stray.spec.tsx'));
228
+ const errors = captureConsoleErrors();
229
+ expect(validateTestFileLocations(root)).toBe(2);
230
+ expect(errors.join('\n')).toContain('scripts/helper.test.ts');
231
+ expect(errors.join('\n')).toContain('stray.spec.tsx');
232
+ } finally {
233
+ await rm(root, { recursive: true, force: true });
234
+ }
235
+ });
236
+ });
237
+
238
+ async function writeSource(path: string): Promise<void> {
239
+ await mkdir(dirname(path), { recursive: true });
240
+ await writeFile(path, 'export {};\n');
241
+ }
242
+
203
243
  describe('Nx project name policy', () => {
204
244
  it('fixes same-scope packages without touching external or unscoped packages', async () => {
205
245
  const root = await createWorkspace({
@@ -1,4 +1,5 @@
1
- import { join } from 'node:path';
1
+ import { type Dirent, readdirSync } from 'node:fs';
2
+ import { join, relative } from 'node:path';
2
3
  import {
3
4
  applyWorkspaceBoundedTestTargetPolicy,
4
5
  checkWorkspaceBoundedTestTargetPolicy,
@@ -317,6 +318,74 @@ export function validatePublicTags(root: string): number {
317
318
  return 0;
318
319
  }
319
320
 
321
+ const testFilePattern = /\.(test|spec)\.tsx?$/;
322
+
323
+ /** Directories that legitimately hold generated/vendored trees a test-file
324
+ * scan must never descend into (cargo target/ alone holds 100k+ files). */
325
+ const testScanSkippedDirectories = new Set([
326
+ 'node_modules',
327
+ 'dist',
328
+ 'dist-test',
329
+ 'target',
330
+ 'coverage',
331
+ 'tmp',
332
+ '.git',
333
+ '.devenv',
334
+ '.direnv',
335
+ '.nx',
336
+ '.cache',
337
+ ]);
338
+
339
+ /**
340
+ * Every test file must live under the package's `src/`. The convention is
341
+ * otherwise only encoded generatively — tsconfig.test.json includes are
342
+ * `src/**` and the bounded bun-test targets run with cwd `<package>/src` —
343
+ * so a test file anywhere else is neither typechecked nor executed, with no
344
+ * diagnostic. This check turns that silent gap into a validation failure.
345
+ */
346
+ export function validateTestFileLocations(root: string): number {
347
+ let failures = 0;
348
+ for (const pkg of getWorkspacePackages(root)) {
349
+ for (const stray of strayTestFiles(join(root, pkg.path))) {
350
+ console.error(
351
+ `${pkg.projectName}: test file outside src/ is neither typechecked nor run by the bounded test targets: ${stray}`,
352
+ );
353
+ failures++;
354
+ }
355
+ }
356
+ return failures;
357
+ }
358
+
359
+ function strayTestFiles(packagePath: string): string[] {
360
+ const stray: string[] = [];
361
+ const walk = (directory: string): void => {
362
+ let entries: Dirent[];
363
+ try {
364
+ entries = readdirSync(directory, { withFileTypes: true });
365
+ } catch {
366
+ return;
367
+ }
368
+ for (const entry of entries) {
369
+ const path = join(directory, entry.name);
370
+ if (entry.isDirectory()) {
371
+ if (testScanSkippedDirectories.has(entry.name)) {
372
+ continue;
373
+ }
374
+ if (directory === packagePath && entry.name === 'src') {
375
+ continue; // src/ is where tests belong.
376
+ }
377
+ walk(path);
378
+ continue;
379
+ }
380
+ if (entry.isFile() && testFilePattern.test(entry.name)) {
381
+ stray.push(relative(packagePath, path));
382
+ }
383
+ }
384
+ };
385
+ walk(packagePath);
386
+ return stray;
387
+ }
388
+
320
389
  export function validatePublicPackageMetadata(root: string): number {
321
390
  const rootPackage = readJsonObject(join(root, 'package.json'));
322
391
  const rootRepository = rootPackage ? repositoryInfo(rootPackage) : null;
@@ -17,6 +17,7 @@ import {
17
17
  validatePublicPackageMetadata,
18
18
  validatePublicTags,
19
19
  validateRootPackagePolicy,
20
+ validateTestFileLocations,
20
21
  validateWorkspaceDependencies,
21
22
  } from '../package-policy.js';
22
23
  import {
@@ -100,7 +101,8 @@ const packs: MonorepoPack[] = [
100
101
  validateNxProjectNames(ctx.root) +
101
102
  validateNxReleaseConfig(ctx.root) +
102
103
  validateBunLockfileVersions(ctx.root) +
103
- (await validateNxSync(ctx.root, ctx.verbose === true))
104
+ (await validateNxSync(ctx.root, ctx.verbose === true)) +
105
+ validateTestFileLocations(ctx.root)
104
106
  );
105
107
  },
106
108
  },
@@ -169,7 +169,9 @@ describe('tool configuration validation', () => {
169
169
  applyDevenvPackageDefaults(root);
170
170
  expect(validateDevenvPackages(root)).toBe(0);
171
171
  const devenv = await readFile(devenvPath, 'utf8');
172
- expect(devenv).toContain('sccache # Rust compiler wrapper and cache');
172
+ expect(devenv).toContain(
173
+ 'sccache # Rust compiler cache; client of the host-owned daemon (cowshed sccache start)',
174
+ );
173
175
  expect(devenv).toContain('++ lib.optionals pkgs.stdenv.isLinux [');
174
176
  expect(devenv).toContain('pkgs.stdenv.cc');
175
177
  expect(devenv).toContain('stdenv.cc.cc.lib');
@@ -439,7 +439,7 @@ function nixPackageComment(name: string): string {
439
439
  return '# Builds ttsc source plugins';
440
440
  }
441
441
  if (name === 'sccache') {
442
- return '# Rust compiler wrapper and cache';
442
+ return '# Rust compiler cache; client of the host-owned daemon (cowshed sccache start)';
443
443
  }
444
444
  return '';
445
445
  }
@@ -188,13 +188,13 @@ describe('release orchestration', () => {
188
188
  expect(shell.nxRuns).toEqual([{ packages: ['@scope/stable'], bump: 'auto', dryRun: false }]);
189
189
  });
190
190
 
191
- it('reports dry-run version packages resolved by Nx without creating a release mode', async () => {
191
+ it('reports dry-run version packages as a release candidate for validation', async () => {
192
192
  const preview = { ...stable, version: '1.1.0' };
193
193
  const shell = new RecordingVersionShell({ releasePackagesAtHead: [[]], releaseVersionPackages: [stable], preview });
194
194
 
195
195
  const result = await runReleaseVersion(shell, { bump: 'auto', dryRun: true });
196
196
 
197
- expect(result).toEqual({ mode: 'none', packages: [preview], status: 'dry-run' });
197
+ expect(result).toEqual({ mode: 'dry-run', packages: [preview], status: 'dry-run' });
198
198
  expect(shell.nxRuns).toEqual([{ packages: ['@scope/stable'], bump: 'auto', dryRun: true }]);
199
199
  });
200
200
 
@@ -1,7 +1,7 @@
1
1
  import type { ReleasePackageInfo, ReleaseTarget } from './core.js';
2
2
  import { planPublishActions } from './publish-plan.js';
3
3
 
4
- export type ReleaseVersionMode = 'new' | 'none';
4
+ export type ReleaseVersionMode = 'new' | 'dry-run' | 'none';
5
5
 
6
6
  export interface ReleaseSummary<Package extends ReleasePackageInfo = ReleasePackageInfo> {
7
7
  sha: string;
@@ -87,7 +87,7 @@ export async function runReleaseVersion<Package extends ReleasePackageInfo>(
87
87
  const headBeforeVersioning = await shell.gitHead();
88
88
  const dryRunPackages = await shell.runNxReleaseVersion(versionPackages, options.bump, options.dryRun);
89
89
  if (options.dryRun) {
90
- return { mode: 'none', packages: dryRunPackages, status: 'dry-run' };
90
+ return { mode: 'dry-run', packages: dryRunPackages, status: 'dry-run' };
91
91
  }
92
92
 
93
93
  await shell.assertCleanGitTree();