@nan0web/release 1.0.3 → 3.1.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 (56) hide show
  1. package/README.md +42 -17
  2. package/bin/nan0release.js +3 -39
  3. package/knip.json +21 -0
  4. package/nan0web.nan0 +16 -0
  5. package/package.json +14 -14
  6. package/src/README.md.js +19 -21
  7. package/src/Release/Person.js +1 -1
  8. package/src/agents/inspectors/git-reviewer.md +35 -0
  9. package/src/agents/inspectors/package-hygiene.md +63 -0
  10. package/src/agents/workflows/commit.md +28 -0
  11. package/src/agents/workflows/npm-release.md +40 -0
  12. package/src/agents/workflows/release.md +205 -0
  13. package/src/agents/workflows/zero-tolerance-git.md +21 -0
  14. package/src/domain/App.js +33 -0
  15. package/src/domain/CheckCommand.js +193 -0
  16. package/src/domain/CloseCommand.js +68 -0
  17. package/src/domain/DepsCommand.js +104 -0
  18. package/src/domain/InitCommand.js +57 -0
  19. package/src/domain/PublishCommand.js +89 -0
  20. package/src/domain/SpecCommand.js +43 -0
  21. package/src/domain/StatusCommand.js +25 -0
  22. package/src/index.js +9 -0
  23. package/types/Release/Person.d.ts +3 -3
  24. package/types/Team.d.ts +3 -3
  25. package/types/commands/CheckCommand.d.ts +24 -0
  26. package/types/commands/CloseCommand.d.ts +2 -1
  27. package/types/commands/Command.d.ts +6 -1
  28. package/types/commands/DepsCommand.d.ts +2 -1
  29. package/types/commands/InitCommand.d.ts +2 -1
  30. package/types/commands/PublishCommand.d.ts +2 -1
  31. package/types/commands/SpecCommand.d.ts +2 -1
  32. package/types/domain/App.d.ts +16 -0
  33. package/types/domain/CheckCommand.d.ts +24 -0
  34. package/types/domain/CloseCommand.d.ts +17 -0
  35. package/types/domain/DepsCommand.d.ts +22 -0
  36. package/types/domain/InitCommand.d.ts +18 -0
  37. package/types/domain/PublishCommand.d.ts +27 -0
  38. package/types/domain/SpecCommand.d.ts +17 -0
  39. package/types/domain/StatusCommand.d.ts +7 -0
  40. package/types/index.d.ts +8 -0
  41. package/types/ui/cli/index.d.ts +1 -0
  42. package/types/utils/runSpawn.d.ts +1 -0
  43. package/src/Team.js +0 -35
  44. package/src/cli/index.js +0 -9
  45. package/src/co/AppCommandOptions.js +0 -25
  46. package/src/commands/CloseCommand.js +0 -67
  47. package/src/commands/Command.js +0 -48
  48. package/src/commands/DepsCommand.js +0 -143
  49. package/src/commands/InitCommand.js +0 -57
  50. package/src/commands/PublishCommand.js +0 -105
  51. package/src/commands/SpecCommand.js +0 -41
  52. package/src/commands/StatusCommand.js +0 -26
  53. package/src/db/ReleaseDB.js +0 -54
  54. package/src/ui/cli/ReleaseCLi.js +0 -52
  55. package/src/ui/cli/index.js +0 -0
  56. package/src/utils/runSpawn.js +0 -0
@@ -0,0 +1,89 @@
1
+ import { ModelAsApp, result, show } from '@nan0web/ui'
2
+ import { runSpawn } from '@nan0web/test'
3
+
4
+ export default class PublishCommand extends ModelAsApp {
5
+ static major = {
6
+ help: 'Bump major version',
7
+ default: false,
8
+ }
9
+ static minor = {
10
+ help: 'Bump minor version',
11
+ default: false,
12
+ }
13
+ static patch = {
14
+ help: 'Bump patch version',
15
+ default: false,
16
+ }
17
+ static UI = {
18
+ title: 'publish',
19
+ help: 'Publish npm packages',
20
+ }
21
+
22
+ /**
23
+ * @param {Partial<PublishCommand>} [data]
24
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
25
+ */
26
+ constructor(data = {}, options = {}) {
27
+ super(data, options)
28
+ /** @type {boolean} Bump major version */ this.major
29
+ /** @type {boolean} Bump minor version */ this.minor
30
+ /** @type {boolean} Bump patch version */ this.patch
31
+ }
32
+
33
+ /**
34
+ * @returns {AsyncGenerator<import('@nan0web/ui').Intent, import('@nan0web/ui').ResultIntent, any>}
35
+ */
36
+ async *run() {
37
+ const bump = this.major ? 'major' : this.minor ? 'minor' : this.patch ? 'patch' : null
38
+
39
+ if (bump) {
40
+ const bumpResult = await runSpawn('npm', ['version', bump])
41
+ if (bumpResult.code !== 0) throw new Error('Failed to bump version')
42
+ }
43
+
44
+ const db = /** @type {any} */ (this._).db
45
+ const pkg = await db.loadDocument('package.json', {})
46
+ const tag = `v${pkg.version}`
47
+
48
+ yield show(`🛜 nan0release: publishing @${pkg.name}@${pkg.version}`)
49
+
50
+ const diffRes = await runSpawn('git', ['diff', '--quiet'])
51
+ if (diffRes.code !== 0) throw new Error('Uncommitted changes found')
52
+
53
+ const pullRes = await runSpawn('git', ['pull'])
54
+ if (pullRes.code !== 0) throw new Error('Failed to pull latest changes')
55
+
56
+ const cleanRes = await runSpawn('npm', ['run', 'clean'])
57
+ if (cleanRes.code !== 0) throw new Error('Clean failed')
58
+
59
+ const buildRes = await runSpawn('npm', ['run', 'build'])
60
+ if (buildRes.code !== 0) throw new Error('Build failed')
61
+
62
+ const testRes = await runSpawn('npm', ['test'])
63
+ if (testRes.code !== 0) throw new Error('Tests failed')
64
+
65
+ const tagsResult = await runSpawn('git', ['tag'])
66
+ if (tagsResult.code !== 0) throw new Error('Failed to get tags')
67
+ const tags = tagsResult.text.split('\n').filter(Boolean)
68
+
69
+ if (!tags.includes(tag)) {
70
+ const tagRes = await runSpawn('git', ['tag', '-a', tag, '-m', `Release ${pkg.version}`])
71
+ if (tagRes.code !== 0) throw new Error('Tag creation failed')
72
+ yield show(`Tag ${tag} created`, 'success')
73
+ } else {
74
+ yield show(`Tag ${tag} already exists`, 'warn')
75
+ }
76
+
77
+ const pubRes = await runSpawn('pnpm', ['publish', '--access', 'public'])
78
+ if (pubRes.code !== 0) throw new Error('Publish to npm failed')
79
+
80
+ const pushRes = await runSpawn('git', ['push', 'origin', 'main', '--no-verify'])
81
+ if (pushRes.code !== 0) throw new Error('Git push failed')
82
+
83
+ const pushTagsRes = await runSpawn('git', ['push', 'origin', '--tags', '--no-verify'])
84
+ if (pushTagsRes.code !== 0) throw new Error('Tag push failed')
85
+
86
+ yield show(`${pkg.name}@${pkg.version} published.`, 'success')
87
+ return result({})
88
+ }
89
+ }
@@ -0,0 +1,43 @@
1
+ import { ModelAsApp, result, show } from '@nan0web/ui'
2
+ import { runSpawn } from '@nan0web/test'
3
+ import Scanner from '../Release/Scanner.js'
4
+
5
+ export default class SpecCommand extends ModelAsApp {
6
+ static version = {
7
+ help: 'Release version filter',
8
+ default: '',
9
+ }
10
+ static UI = {
11
+ title: 'spec',
12
+ help: 'Run spec testing for the active release',
13
+ }
14
+
15
+ /**
16
+ * @param {Partial<SpecCommand>} [data]
17
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
18
+ */
19
+ constructor(data = {}, options = {}) {
20
+ super(data, options)
21
+ /** @type {string} Release version filter */ this.version
22
+ }
23
+
24
+ /**
25
+ * @returns {AsyncGenerator<import('@nan0web/ui').Intent, import('@nan0web/ui').ResultIntent, any>}
26
+ */
27
+ async *run() {
28
+ yield show(`🛜 nan0release spec ${this.version || 'all'}`)
29
+ const scanner = new Scanner(process.cwd())
30
+ const specs = scanner.findSpecs(this.version)
31
+ if (specs.length === 0) {
32
+ yield show(`No specs found.`, 'warn')
33
+ return result({})
34
+ }
35
+ const files = specs.map((s) => s.path)
36
+ const spawnResult = await runSpawn('node', ['--test', ...files])
37
+ if (spawnResult.code !== 0) {
38
+ throw new Error('Specs failed')
39
+ }
40
+ yield show(`✅ Specs passed`, 'success')
41
+ return result({})
42
+ }
43
+ }
@@ -0,0 +1,25 @@
1
+ import { ModelAsApp, result, show } from '@nan0web/ui'
2
+ import Scanner from '../Release/Scanner.js'
3
+
4
+ export default class StatusCommand extends ModelAsApp {
5
+ static UI = {
6
+ title: 'status',
7
+ help: 'Show release status',
8
+ }
9
+
10
+ /**
11
+ * @returns {AsyncGenerator<import('@nan0web/ui').Intent, import('@nan0web/ui').ResultIntent, any>}
12
+ */
13
+ async *run() {
14
+ const scanner = new Scanner(process.cwd())
15
+ const statuses = scanner.status()
16
+
17
+ yield show(`🛜 nan0release status`)
18
+ for (const st of statuses) {
19
+ yield show(
20
+ `${st.version.padEnd(10)} | ${st.state.padEnd(6)} | Specs: ${st.specs.length}, Tests: ${st.tests.length}`,
21
+ )
22
+ }
23
+ return result({})
24
+ }
25
+ }
package/src/index.js CHANGED
@@ -16,3 +16,12 @@ export {
16
16
  TaskTestSuite,
17
17
  ChangelogTaskManager
18
18
  }
19
+
20
+ export { App } from './domain/App.js'
21
+ export { default as InitCommand } from './domain/InitCommand.js'
22
+ export { default as CheckCommand } from './domain/CheckCommand.js'
23
+ export { default as CloseCommand } from './domain/CloseCommand.js'
24
+ export { default as DepsCommand } from './domain/DepsCommand.js'
25
+ export { default as PublishCommand } from './domain/PublishCommand.js'
26
+ export { default as SpecCommand } from './domain/SpecCommand.js'
27
+ export { default as StatusCommand } from './domain/StatusCommand.js'
@@ -12,6 +12,6 @@ export default class Person {
12
12
  /** @type {HumanContact[]} */
13
13
  contacts: HumanContact[];
14
14
  }
15
- import { HumanName } from '@nan0web/verse';
16
- import { HumanGender } from '@nan0web/verse';
17
- import { HumanContact } from '@nan0web/verse';
15
+ import { HumanName } from '@nan0web/logos';
16
+ import { HumanGender } from '@nan0web/logos';
17
+ import { HumanContact } from '@nan0web/logos';
package/types/Team.d.ts CHANGED
@@ -22,6 +22,6 @@ declare class Person {
22
22
  /** @type {HumanContact[]} */
23
23
  contacts: HumanContact[];
24
24
  }
25
- import { HumanName } from '@nan0web/verse';
26
- import { HumanGender } from '@nan0web/verse';
27
- import { HumanContact } from '@nan0web/verse';
25
+ import { HumanName } from '@nan0web/logos';
26
+ import { HumanGender } from '@nan0web/logos';
27
+ import { HumanContact } from '@nan0web/logos';
@@ -0,0 +1,24 @@
1
+ export default class CheckCommand extends ModelAsApp {
2
+ static UI: {
3
+ title: string;
4
+ icon: string;
5
+ description: string;
6
+ };
7
+ static name: string;
8
+ /**
9
+ * @returns {AsyncGenerator<any, any, any>}
10
+ */
11
+ run(): AsyncGenerator<any, any, any>;
12
+ /**
13
+ * @param {string} absDir
14
+ * @returns {Promise<string[]>}
15
+ */
16
+ _scanLocal(absDir: string): Promise<string[]>;
17
+ /**
18
+ * @param {string} base
19
+ * @param {string} [dir]
20
+ * @returns {Promise<string[]>}
21
+ */
22
+ _scanDirRecursive(base: string, dir?: string): Promise<string[]>;
23
+ }
24
+ import { ModelAsApp } from '@nan0web/ui';
@@ -10,7 +10,7 @@ export default class CloseCommand extends Command {
10
10
  run(): AsyncGenerator<OutputMessage, void, unknown>;
11
11
  }
12
12
  import Command from './Command.js';
13
- declare class CloseBody {
13
+ declare class CloseBody extends CommandBody {
14
14
  static version: {
15
15
  help: string;
16
16
  defaultValue: string;
@@ -22,4 +22,5 @@ declare class CloseBody {
22
22
  version: string;
23
23
  }
24
24
  import { OutputMessage } from '@nan0web/co';
25
+ import { CommandBody } from './Command.js';
25
26
  export {};
@@ -1,5 +1,10 @@
1
1
  /** @typedef {import("@nan0web/test/types/exec/runSpawn").SpawnResult} SpawnResult */
2
+ export class CommandBody {
3
+ static fs: {};
4
+ static logger: {};
5
+ }
2
6
  export default class Command extends UiMessage {
7
+ static Body: typeof CommandBody;
3
8
  /**
4
9
  * @param {Partial<UiMessage> & { }} [input={}]
5
10
  */
@@ -8,7 +13,7 @@ export default class Command extends UiMessage {
8
13
  fs: DBFS;
9
14
  /** @type {Logger} */
10
15
  logger: Logger;
11
- get Body(): new () => {};
16
+ get Body(): typeof CommandBody;
12
17
  /**
13
18
  * Run the command.
14
19
  * @param {string} cmd
@@ -13,7 +13,7 @@ export default class DepsCommand extends Command {
13
13
  run(msg?: DepsCommand): AsyncGenerator<OutputMessage>;
14
14
  }
15
15
  import Command from './Command.js';
16
- declare class DepsBody {
16
+ declare class DepsBody extends CommandBody {
17
17
  static fix: {
18
18
  help: string;
19
19
  defaultValue: boolean;
@@ -29,4 +29,5 @@ declare class DepsBody {
29
29
  latest: boolean;
30
30
  }
31
31
  import { OutputMessage } from '@nan0web/co';
32
+ import { CommandBody } from './Command.js';
32
33
  export {};
@@ -10,7 +10,7 @@ export default class InitCommand extends Command {
10
10
  run(): AsyncGenerator<OutputMessage, void, unknown>;
11
11
  }
12
12
  import Command from './Command.js';
13
- declare class InitBody {
13
+ declare class InitBody extends CommandBody {
14
14
  static version: {
15
15
  help: string;
16
16
  defaultValue: string;
@@ -22,4 +22,5 @@ declare class InitBody {
22
22
  version: string;
23
23
  }
24
24
  import { OutputMessage } from '@nan0web/co';
25
+ import { CommandBody } from './Command.js';
25
26
  export {};
@@ -10,7 +10,7 @@ export default class PublishCommand extends Command {
10
10
  body: PublishBody;
11
11
  }
12
12
  import Command from './Command.js';
13
- declare class PublishBody {
13
+ declare class PublishBody extends CommandBody {
14
14
  static major: {
15
15
  help: string;
16
16
  defaultValue: boolean;
@@ -35,4 +35,5 @@ declare class PublishBody {
35
35
  /** @type {boolean} */
36
36
  patch: boolean;
37
37
  }
38
+ import { CommandBody } from './Command.js';
38
39
  export {};
@@ -10,7 +10,7 @@ export default class SpecCommand extends Command {
10
10
  run(): AsyncGenerator<OutputMessage, void, unknown>;
11
11
  }
12
12
  import Command from './Command.js';
13
- declare class SpecBody {
13
+ declare class SpecBody extends CommandBody {
14
14
  static version: {
15
15
  help: string;
16
16
  defaultValue: string;
@@ -22,4 +22,5 @@ declare class SpecBody {
22
22
  version: string;
23
23
  }
24
24
  import { OutputMessage } from '@nan0web/co';
25
+ import { CommandBody } from './Command.js';
25
26
  export {};
@@ -0,0 +1,16 @@
1
+ export class App extends ModelAsApp {
2
+ static command: {
3
+ help: string;
4
+ options: (typeof CheckCommand | typeof StatusCommand)[];
5
+ default: null;
6
+ };
7
+ /**
8
+ * @param {Partial<App>} [data]
9
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
10
+ */
11
+ constructor(data?: Partial<App>, options?: Partial<import("@nan0web/ui").ModelAsAppOptions>);
12
+ /** @type {ModelAsApp} Subcommand to run */ command: ModelAsApp;
13
+ }
14
+ import { ModelAsApp } from "@nan0web/ui";
15
+ import CheckCommand from './CheckCommand.js';
16
+ import StatusCommand from './StatusCommand.js';
@@ -0,0 +1,24 @@
1
+ export default class CheckCommand extends ModelAsApp {
2
+ static UI: {
3
+ title: string;
4
+ icon: string;
5
+ description: string;
6
+ };
7
+ static name: string;
8
+ /**
9
+ * @returns {AsyncGenerator<any, any, any>}
10
+ */
11
+ run(): AsyncGenerator<any, any, any>;
12
+ /**
13
+ * @param {string} absDir
14
+ * @returns {Promise<string[]>}
15
+ */
16
+ _scanLocal(absDir: string): Promise<string[]>;
17
+ /**
18
+ * @param {string} base
19
+ * @param {string} [dir]
20
+ * @returns {Promise<string[]>}
21
+ */
22
+ _scanDirRecursive(base: string, dir?: string): Promise<string[]>;
23
+ }
24
+ import { ModelAsApp } from '@nan0web/ui';
@@ -0,0 +1,17 @@
1
+ export default class CloseCommand extends ModelAsApp {
2
+ static version: {
3
+ help: string;
4
+ default: string;
5
+ };
6
+ static UI: {
7
+ title: string;
8
+ help: string;
9
+ };
10
+ /**
11
+ * @param {Partial<CloseCommand>} [data]
12
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
13
+ */
14
+ constructor(data?: Partial<CloseCommand>, options?: Partial<import("@nan0web/ui").ModelAsAppOptions>);
15
+ /** @type {string} Release version */ version: string;
16
+ }
17
+ import { ModelAsApp } from '@nan0web/ui';
@@ -0,0 +1,22 @@
1
+ export default class DepsCommand extends ModelAsApp {
2
+ static fix: {
3
+ help: string;
4
+ default: boolean;
5
+ };
6
+ static latest: {
7
+ help: string;
8
+ default: boolean;
9
+ };
10
+ static UI: {
11
+ title: string;
12
+ help: string;
13
+ };
14
+ /**
15
+ * @param {Partial<DepsCommand>} [data]
16
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
17
+ */
18
+ constructor(data?: Partial<DepsCommand>, options?: Partial<import("@nan0web/ui").ModelAsAppOptions>);
19
+ /** @type {boolean} Apply fixes automatically */ fix: boolean;
20
+ /** @type {boolean} Update packages to the latest available versions */ latest: boolean;
21
+ }
22
+ import { ModelAsApp } from '@nan0web/ui';
@@ -0,0 +1,18 @@
1
+ export default class InitCommand extends ModelAsApp {
2
+ static version: {
3
+ help: string;
4
+ default: string;
5
+ errorRequired: string;
6
+ };
7
+ static UI: {
8
+ title: string;
9
+ help: string;
10
+ };
11
+ /**
12
+ * @param {Partial<InitCommand>} [data]
13
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
14
+ */
15
+ constructor(data?: Partial<InitCommand>, options?: Partial<import("@nan0web/ui").ModelAsAppOptions>);
16
+ /** @type {string} Release version */ version: string;
17
+ }
18
+ import { ModelAsApp } from '@nan0web/ui';
@@ -0,0 +1,27 @@
1
+ export default class PublishCommand extends ModelAsApp {
2
+ static major: {
3
+ help: string;
4
+ default: boolean;
5
+ };
6
+ static minor: {
7
+ help: string;
8
+ default: boolean;
9
+ };
10
+ static patch: {
11
+ help: string;
12
+ default: boolean;
13
+ };
14
+ static UI: {
15
+ title: string;
16
+ help: string;
17
+ };
18
+ /**
19
+ * @param {Partial<PublishCommand>} [data]
20
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
21
+ */
22
+ constructor(data?: Partial<PublishCommand>, options?: Partial<import("@nan0web/ui").ModelAsAppOptions>);
23
+ /** @type {boolean} Bump major version */ major: boolean;
24
+ /** @type {boolean} Bump minor version */ minor: boolean;
25
+ /** @type {boolean} Bump patch version */ patch: boolean;
26
+ }
27
+ import { ModelAsApp } from '@nan0web/ui';
@@ -0,0 +1,17 @@
1
+ export default class SpecCommand extends ModelAsApp {
2
+ static version: {
3
+ help: string;
4
+ default: string;
5
+ };
6
+ static UI: {
7
+ title: string;
8
+ help: string;
9
+ };
10
+ /**
11
+ * @param {Partial<SpecCommand>} [data]
12
+ * @param {Partial<import('@nan0web/ui').ModelAsAppOptions>} [options]
13
+ */
14
+ constructor(data?: Partial<SpecCommand>, options?: Partial<import("@nan0web/ui").ModelAsAppOptions>);
15
+ /** @type {string} Release version filter */ version: string;
16
+ }
17
+ import { ModelAsApp } from '@nan0web/ui';
@@ -0,0 +1,7 @@
1
+ export default class StatusCommand extends ModelAsApp {
2
+ static UI: {
3
+ title: string;
4
+ help: string;
5
+ };
6
+ }
7
+ import { ModelAsApp } from '@nan0web/ui';
package/types/index.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ export { App } from "./domain/App.js";
2
+ export { default as InitCommand } from "./domain/InitCommand.js";
3
+ export { default as CheckCommand } from "./domain/CheckCommand.js";
4
+ export { default as CloseCommand } from "./domain/CloseCommand.js";
5
+ export { default as DepsCommand } from "./domain/DepsCommand.js";
6
+ export { default as PublishCommand } from "./domain/PublishCommand.js";
7
+ export { default as SpecCommand } from "./domain/SpecCommand.js";
8
+ export { default as StatusCommand } from "./domain/StatusCommand.js";
1
9
  import Release from './Release.js';
2
10
  import ReleaseDocument from './Release/Document.js';
3
11
  import Person from './Release/Person.js';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/src/Team.js DELETED
@@ -1,35 +0,0 @@
1
- import { HumanName, HumanGender, HumanContact } from '@nan0web/verse'
2
-
3
- class Person {
4
- /** @type {HumanName} */
5
- name
6
- /** @type {HumanGender} */
7
- gender
8
- /** @type {HumanContact[]} */
9
- contacts
10
-
11
- constructor(name) {
12
- this.name = new HumanName(name)
13
- this.gender = new HumanGender(-1)
14
- this.contacts = []
15
- }
16
- }
17
-
18
- class CLevelTeam {
19
- static name = 'C Level'
20
- static ceo = new Person(['Yaroslav', 'Wise'])
21
- static cfo = new Person(['Chingis'])
22
- }
23
-
24
- class UXTeam {
25
- static name = 'UX'
26
- static designer = new Person(['Taras', 'Shevchenko'])
27
- }
28
-
29
- class Company {
30
- static name = 'NaN•Web'
31
- static c = CLevelTeam
32
- static ux = UXTeam
33
- }
34
-
35
- export default Company
package/src/cli/index.js DELETED
@@ -1,9 +0,0 @@
1
- /**
2
- * Export the UI‑CLI based release CLI.
3
- *
4
- * @module release/cli
5
- */
6
-
7
- import createReleaseCLI from '../ui/cli/ReleaseCLi.js'
8
-
9
- export default createReleaseCLI
@@ -1,25 +0,0 @@
1
- export default class AppCommandOptions {
2
- /** @type {boolean} */
3
- webui = false
4
- /** @type {boolean} */
5
- json = false
6
- /** @type {boolean} */
7
- quiet = false
8
- /** @type {string} */
9
- releaseDir = './releases'
10
- /** @type {boolean} */
11
- write = false
12
- /** @type {string} */
13
- user = 'anonymous'
14
- /** @type {boolean} */
15
- ignoreFailTests = false
16
- /** @type {boolean} */
17
- full = false
18
-
19
- /**
20
- * @param {Object} input
21
- */
22
- constructor(input = {}) {
23
- Object.assign(this, input)
24
- }
25
- }
@@ -1,67 +0,0 @@
1
- import { OutputMessage } from '@nan0web/co'
2
- import Command from './Command.js'
3
- import process from 'node:process'
4
- import Scanner from '../Release/Scanner.js'
5
-
6
- class CloseBody {
7
- static version = { help: 'Release version', defaultValue: '' }
8
- /** @type {string} */
9
- version = ''
10
- constructor({ version = '' } = {}) {
11
- this.version = String(version)
12
- }
13
- }
14
-
15
- export default class CloseCommand extends Command {
16
- static name = 'close'
17
- static help = 'Close a release and move tests to src/'
18
- static Body = CloseBody
19
-
20
- /** @param {Partial<Command> & { body?: Partial<CloseBody> }} [input={}] */
21
- constructor(input = {}) {
22
- super(input)
23
- this.body = new CloseBody(/** @type {*} */ (input))
24
- }
25
-
26
- async *run() {
27
- const v = this.body.version || ''
28
-
29
- yield new OutputMessage(`🛜 nan0release close ${v || 'all'}`)
30
-
31
- const scanner = new Scanner(process.cwd())
32
- const specs = scanner.findSpecs(v)
33
-
34
- if (specs.length === 0) {
35
- yield new OutputMessage(`No pending specs found for version ${v || 'all'}`)
36
- return
37
- }
38
-
39
- yield new OutputMessage(`Running ${specs.length} pending specs...`)
40
-
41
- const files = specs.map((s) => s.path)
42
- await this._run('node', ['--test', ...files], 'Cannot close: Specs failed')
43
-
44
- yield new OutputMessage(`✅ Specs passed. Closing...`)
45
-
46
- let movedCount = 0
47
- const { renameSync, mkdirSync } = await import('node:fs')
48
- const { join, dirname } = await import('node:path')
49
-
50
- for (const spec of specs) {
51
- const relativePath = spec.path.substring(process.cwd().length + 1)
52
- const destRelative = relativePath
53
- .replace(/^releases\//, 'src/releases/')
54
- .replace('.spec.js', '.test.js')
55
- const destPath = join(process.cwd(), destRelative)
56
-
57
- mkdirSync(dirname(destPath), { recursive: true })
58
- renameSync(spec.path, destPath)
59
- movedCount++
60
- }
61
-
62
- yield new OutputMessage({
63
- content: [`✅ Successfully closed ${movedCount} specs and moved to src/releases/`],
64
- type: OutputMessage.TYPES.SUCCESS,
65
- })
66
- }
67
- }