lucy-cli 0.8.3 โ†’ 0.9.1

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/src/helpers.ts CHANGED
@@ -1,15 +1,14 @@
1
1
  import chalk from 'chalk';
2
- import { join } from 'path';
3
2
  import { simpleGit } from 'simple-git';
4
- import fs from 'fs/promises';
5
3
  import { spawnSync } from 'child_process';
6
4
  // https://www.sergevandenoever.nl/run-gulp4-tasks-programatically-from-node/
7
5
  import path from 'path';
8
6
  import { fileURLToPath } from 'url';
9
7
  import { ModuleSettings, ProjectSettings } from '.';
10
8
  import { exec } from 'child_process';
9
+ import os from 'os';
11
10
 
12
- import { blue, green, orange, red } from './index.js';
11
+ import { blue, green, orange, red, yellow, magenta } from './index.js';
13
12
 
14
13
  export async function installPackages(wixPackages: Record<string, string>, devPackages: Record<string, string>, cwd: string, locked: boolean ) {
15
14
  if (locked) console.log("๐Ÿ•" + blue.underline(` => Installing & version locked packages!`));
@@ -83,19 +82,84 @@ export async function runGulp(moduleSettings: ModuleSettings, projectSettings: P
83
82
  /**
84
83
  * Clean up and run a command before exiting the process.
85
84
  */
86
- export function handleExit() {
85
+ export function cleanupWatchers() {
86
+ console.log(`๐Ÿงน ${magenta.underline('Cleaning up Watchman watchers...')}`);
87
87
  const cwd = process.cwd();
88
- const command = `watchman watch-del '${cwd}'`;
89
-
90
- console.log("๐Ÿ•" + blue.underline(' => Cleaning up...'));
88
+ const command = `watchman watch-del "${cwd}"`; // Adjust for Windows paths
91
89
  exec(command, (error, stdout, stderr) => {
92
90
  if (error) {
93
- console.error(`๐Ÿ’ฉ Failed to run cleanup: ${error.message}`);
91
+ console.error(`๐Ÿ’ฉ ${red.underline('Failed to run cleanup:')} ${orange(error.message)}`);
94
92
  return;
95
93
  }
96
94
  if (stderr) {
97
- console.error(`โš ๏ธ Watchman stderr: ${stderr}`);
95
+ console.error(`โš ๏ธ ${yellow.underline('Watchman stderr:')} ${stderr}`);
98
96
  }
99
- console.log(`โœ… Watchman cleanup success: ${stdout}`);
97
+ console.log(`โœ… ${green.underline('Watchman cleanup success:')} ${stdout}`);
100
98
  });
101
99
  }
100
+
101
+ /**
102
+ * Kill all processes matching a specific substring in their command, with a fallback for Windows.
103
+ * @param {string} processPattern - The substring to match (e.g., "wix:dev" or "@wix/cli/bin/wix.cjs").
104
+ */
105
+ export function killAllProcesses(processPattern: string) {
106
+ const isWindows = os.platform() === 'win32';
107
+ const command = isWindows
108
+ ? `tasklist /FI "IMAGENAME eq node.exe" /FO CSV | findstr "${processPattern}"` // Adjust for Node.js processes
109
+ : `ps -eo pid,command | grep "${processPattern}" | grep -v grep`;
110
+
111
+ exec(command, (error, stdout, stderr) => {
112
+ if (error) {
113
+ console.error(`๐Ÿ’ฉ ${red.underline('Failed to find processes:')} ${orange(error.message)}`);
114
+ return;
115
+ }
116
+ if (stderr) {
117
+ console.error(`โš ๏ธ ${yellow.underline('Error output:')} ${stderr}`);
118
+ }
119
+ if (!stdout.trim()) {
120
+ console.log(`โ„น๏ธ ${blue.underline(`No processes found matching pattern:`)} ${orange(processPattern)}`);
121
+ return;
122
+ }
123
+
124
+ console.log(`๐Ÿ“ ${magenta.underline('Found matching processes:')}\n${stdout}`);
125
+ const lines = stdout.trim().split('\n');
126
+ const pids = isWindows
127
+ ? lines.map(line => line.match(/"(\d+)"/)?.[1]) // Extract PID from Windows tasklist output
128
+ : lines.map(line => line.trim().split(/\s+/)[0]).filter(pid => !isNaN(Number(pid)));
129
+
130
+ pids.forEach(pid => {
131
+ if (!pid) return;
132
+ try {
133
+ const killCommand = isWindows
134
+ ? `taskkill /PID ${pid} /T /F` // Forcefully terminate the process on Windows
135
+ : `kill -SIGTERM ${pid}`;
136
+
137
+ exec(killCommand, (killError) => {
138
+ if (killError) {
139
+ console.error(`โš ๏ธ ${yellow.underline('Failed to kill process with PID')} ${orange(pid)}: ${red(killError.message)}`);
140
+ } else {
141
+ console.log(`โœ… ${green.underline('Killed process with PID:')} ${orange(pid)}`);
142
+ }
143
+ });
144
+
145
+ // Schedule SIGKILL fallback for non-Windows platforms
146
+ if (!isWindows) {
147
+ setTimeout(() => {
148
+ try {
149
+ process.kill(parseInt(pid, 10), 'SIGKILL');
150
+ console.log(`๐Ÿ”ช ${red.underline('Sent SIGKILL to process with PID:')} ${orange(pid)} (fallback).`);
151
+ } catch (killError: any) {
152
+ if (killError.code === 'ESRCH') {
153
+ console.log(`โœ… ${green.underline('Process with PID')} ${orange(pid)} ${green.underline('already terminated.')}`);
154
+ } else {
155
+ console.error(`โš ๏ธ ${yellow.underline('Failed to send SIGKILL to process with PID')} ${orange(pid)}: ${red(killError.message)}`);
156
+ }
157
+ }
158
+ }, 10000);
159
+ }
160
+ } catch (err: any) {
161
+ console.error(`โš ๏ธ ${yellow.underline('Failed to kill process with PID')} ${orange(pid)}: ${red(err.message)}`);
162
+ }
163
+ });
164
+ });
165
+ }
package/src/index.ts CHANGED
@@ -11,7 +11,7 @@ import fs from 'fs/promises';
11
11
 
12
12
  import { init } from './init.js';
13
13
  import { sync } from './sync.js';
14
- import { runGulp, installPackages, handleExit } from './helpers.js';
14
+ import { runGulp, installPackages, killAllProcesses, cleanupWatchers } from './helpers.js';
15
15
  import { prepare } from './prepare.js';
16
16
  import { spawnSync } from 'child_process';
17
17
 
@@ -71,10 +71,50 @@ const __filename = fileURLToPath(import.meta.url);
71
71
  // eslint-disable-next-line @typescript-eslint/naming-convention
72
72
  const __dirname = dirname(__filename);
73
73
 
74
+ // const cwd = process.cwd();
75
+ // const command = `watchman watch-del '${cwd}'`;
76
+ // killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
77
+ // killAllProcesses('wix:dev');
78
+
79
+
80
+ process.on('exit', (code) => {
81
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
82
+ killAllProcesses('wix:dev');
83
+ cleanupWatchers();
84
+ console.log(`๐Ÿšช ${magenta.underline('Process exiting with code:')} ${orange(code)}`);
85
+ });
86
+
74
87
  process.on('SIGINT', () => {
75
- console.log("๐Ÿ• Received Ctrl+C, cleaning up...");
76
- handleExit();
77
- process.exit(); // Exit the process explicitly
88
+ console.log(`๐Ÿ• ${green.underline('Received Ctrl+C (SIGINT), cleaning up...')}`);
89
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
90
+ killAllProcesses('wix:dev');
91
+ cleanupWatchers();
92
+ process.exit(); // Exit explicitly after handling
93
+ });
94
+
95
+ process.on('SIGTERM', () => {
96
+ console.log(`๐Ÿ›‘ ${red.underline('Received termination signal (SIGTERM), cleaning up...')}`);
97
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
98
+ killAllProcesses('wix:dev');
99
+ cleanupWatchers();
100
+ process.exit(); // Exit explicitly after handling
101
+ });
102
+
103
+ process.on('uncaughtException', (error) => {
104
+ console.error(`๐Ÿ’ฅ ${red.underline('Uncaught Exception:')}`, error);
105
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
106
+ killAllProcesses('wix:dev');
107
+ cleanupWatchers();
108
+ process.exit(1); // Exit with an error code
109
+ });
110
+
111
+ process.on('unhandledRejection', (reason, promise) => {
112
+ console.error(`๐Ÿšจ ${yellow.underline('Unhandled Rejection at:')} ${orange(promise)}`);
113
+ console.error(`๐Ÿšจ ${red.underline('Reason:')} ${reason}`); cleanupWatchers();
114
+ killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
115
+ killAllProcesses('wix:dev');
116
+ cleanupWatchers();
117
+ process.exit(1); // Exit with an error code
78
118
  });
79
119
 
80
120
  /**
@@ -115,6 +155,8 @@ async function main(): Promise<void> {
115
155
  console.log("๐Ÿฆฎ " + magenta.bold('install') + " : Installs all Wix npm packages listed in the 'lucy.json' file in the project directory.");
116
156
  console.log("๐Ÿฆฎ " + magenta.bold('fix') + " : Runs a fix command to resolve common issues in development or production settings.");
117
157
  console.log("๐Ÿฆฎ " + magenta.bold('docs') + " : Generates documentation for the project.");
158
+ console.log("๐Ÿฆฎ " + magenta.bold('cypress') + " : Starts the cypress test runner.");
159
+ console.log("๐Ÿฆฎ " + magenta.bold('e2e') + " : Starts the cypress test runner in CI mode. first argument is the key second is the build id <e2e <somekey <someID>");
118
160
  console.log("\nOptions:");
119
161
  console.log("๐Ÿฆฎ " + magenta.bold('-h, help') + " : Displays this help message.");
120
162
  console.log("๐Ÿฆฎ " + magenta.bold('-v, version') + " : Displays the current version of Lucy CLI as defined in the projectโ€™s package.json.");
@@ -194,11 +236,40 @@ async function main(): Promise<void> {
194
236
  if(moduleSettings.args.includes('docs')){
195
237
  const res = spawnSync('yarn docs', { shell: true, stdio: 'inherit' });
196
238
  if (res.error) {
197
- return console.log((`๐Ÿ’ฉ ${red.underline.bold("=> Failed to install dev packages =>")} ${orange(res.error.message)}`));
239
+ return console.log((`๐Ÿ’ฉ ${red.underline.bold("=> Failed to Docs generated => ")} ${orange(res.error.message)}`));
198
240
  }
199
241
  return console.log("๐Ÿ•" + blue.underline(` => Docs generated!`));
200
242
  }
201
243
 
244
+ if(moduleSettings.args.includes('cypress')){
245
+ const res = spawnSync('yarn cypress', { shell: true, stdio: 'inherit' });
246
+ if (res.error) {
247
+ return console.log((`๐Ÿ’ฉ ${red.underline.bold("=> Failed to start cypress => ")} ${orange(res.error.message)}`));
248
+ }
249
+ return console.log("๐Ÿ•" + blue.underline(` => Started Cypress`));
250
+ }
251
+
252
+ if (moduleSettings.args.includes('e2e')) {
253
+ // Extract arguments
254
+ const e2eIndex = moduleSettings.args.indexOf('e2e');
255
+ const key = moduleSettings.args[e2eIndex + 1];
256
+ const buildId = moduleSettings.args[e2eIndex + 2];
257
+
258
+ // Validate that both arguments are provided
259
+ if (!key && !buildId) {
260
+ console.log(`๐Ÿ’ฉ ${red.underline.bold("=> Missing required arguments:")} ${orange("key")} and ${orange("build ID")}`);
261
+ process.exit(1);
262
+ }
263
+
264
+ // Run Cypress with the provided arguments
265
+ const res = spawnSync(`yarn e2e --key ${key} --ci-build-id ${buildId}`, { shell: true, stdio: 'inherit' });
266
+ if (res.error) {
267
+ console.log(`๐Ÿ’ฉ ${red.underline.bold("=> Failed to start Cypress =>")} ${orange(res.error.message)}`);
268
+ process.exit(1);
269
+ }
270
+ return console.log("๐Ÿ• " + blue.underline(`=> Started Cypress successfully`));
271
+ }
272
+
202
273
  if(moduleSettings.args.includes('prepare')){
203
274
  await prepare( moduleSettings, projectSettings);
204
275
 
package/src/settings.json CHANGED
@@ -57,6 +57,8 @@
57
57
  "fix-wix": "lucy-cli fix-wix",
58
58
  "tsc": "tsc -p ./typescript/tsconfig.json --noEmit",
59
59
  "test": "jest --config jest.config.ts --passWithNoTests",
60
- "test:watch": "jest --config jest.config.ts --watch"
60
+ "test:watch": "jest --config jest.config.ts --watch",
61
+ "cypress": "cypress open",
62
+ "e2e": "cypress-cloud run --parallel --record"
61
63
  }
62
64
  }
package/src/types.d.ts CHANGED
@@ -4,4 +4,5 @@ declare module 'gulp-foreach';
4
4
  declare module 'gulp-string-replace';
5
5
  declare module 'gulp-wait';
6
6
  declare module 'gulp-jest';
7
- declare module 'gulp-flatmap';
7
+ declare module 'gulp-flatmap';
8
+ declare module 'gulp-swc';