@lage-run/cli 0.23.3 → 0.23.5

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/CHANGELOG.json CHANGED
@@ -2,7 +2,49 @@
2
2
  "name": "@lage-run/cli",
3
3
  "entries": [
4
4
  {
5
- "date": "Tue, 08 Oct 2024 20:03:26 GMT",
5
+ "date": "Thu, 10 Oct 2024 20:14:49 GMT",
6
+ "version": "0.23.5",
7
+ "tag": "@lage-run/cli_v0.23.5",
8
+ "comments": {
9
+ "patch": [
10
+ {
11
+ "author": "kchau@microsoft.com",
12
+ "package": "@lage-run/cli",
13
+ "commit": "cad4d2b233433e70c2fd24cfa5a779d0715d778a",
14
+ "comment": "shutoff at 3 minutes"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Wed, 09 Oct 2024 17:20:33 GMT",
21
+ "version": "0.23.4",
22
+ "tag": "@lage-run/cli_v0.23.4",
23
+ "comments": {
24
+ "patch": [
25
+ {
26
+ "author": "kchau@microsoft.com",
27
+ "package": "@lage-run/cli",
28
+ "commit": "41964958d510982762eaa7a496cad7bbb560bcc5",
29
+ "comment": "fixing up the lage integrate with buildxl to utilize lage-server"
30
+ },
31
+ {
32
+ "author": "beachball",
33
+ "package": "@lage-run/cli",
34
+ "comment": "Bump @lage-run/scheduler to v1.3.3",
35
+ "commit": "not available"
36
+ },
37
+ {
38
+ "author": "beachball",
39
+ "package": "@lage-run/cli",
40
+ "comment": "Bump @lage-run/worker-threads-pool to v0.8.4",
41
+ "commit": "not available"
42
+ }
43
+ ]
44
+ }
45
+ },
46
+ {
47
+ "date": "Tue, 08 Oct 2024 20:03:36 GMT",
6
48
  "version": "0.23.3",
7
49
  "tag": "@lage-run/cli_v0.23.3",
8
50
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,12 +1,30 @@
1
1
  # Change Log - @lage-run/cli
2
2
 
3
- <!-- This log was last generated on Tue, 08 Oct 2024 20:03:26 GMT and should not be manually modified. -->
3
+ <!-- This log was last generated on Thu, 10 Oct 2024 20:14:49 GMT and should not be manually modified. -->
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 0.23.5
8
+
9
+ Thu, 10 Oct 2024 20:14:49 GMT
10
+
11
+ ### Patches
12
+
13
+ - shutoff at 3 minutes (kchau@microsoft.com)
14
+
15
+ ## 0.23.4
16
+
17
+ Wed, 09 Oct 2024 17:20:33 GMT
18
+
19
+ ### Patches
20
+
21
+ - fixing up the lage integrate with buildxl to utilize lage-server (kchau@microsoft.com)
22
+ - Bump @lage-run/scheduler to v1.3.3
23
+ - Bump @lage-run/worker-threads-pool to v0.8.4
24
+
7
25
  ## 0.23.3
8
26
 
9
- Tue, 08 Oct 2024 20:03:26 GMT
27
+ Tue, 08 Oct 2024 20:03:36 GMT
10
28
 
11
29
  ### Patches
12
30
 
@@ -19,6 +19,7 @@ function _interop_require_default(obj) {
19
19
  }
20
20
  async function execAction(options, command) {
21
21
  const logger = (0, _logger.default)();
22
+ options.cwd = options.cwd ?? process.cwd();
22
23
  options.logLevel = options.logLevel ?? "info";
23
24
  options.reporter = options.reporter ?? "json";
24
25
  (0, _initializeReporters.initializeReporters)(logger, options);
@@ -1,5 +1,6 @@
1
1
  import type { ReporterInitOptions } from "../../types/ReporterInitOptions.js";
2
2
  interface ExecRemotelyOptions extends ReporterInitOptions {
3
+ cwd?: string;
3
4
  server?: string | boolean;
4
5
  timeout?: number;
5
6
  }
@@ -16,6 +16,10 @@ const _simulateFileAccess = require("./simulateFileAccess.js");
16
16
  const _execa = /*#__PURE__*/ _interop_require_default(require("execa"));
17
17
  const _getBinPaths = require("../../getBinPaths.js");
18
18
  const _parseServerOption = require("../parseServerOption.js");
19
+ const _properlockfile = /*#__PURE__*/ _interop_require_default(require("proper-lockfile"));
20
+ const _path = /*#__PURE__*/ _interop_require_default(require("path"));
21
+ const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
22
+ const _workspacetools = require("workspace-tools");
19
23
  function _interop_require_default(obj) {
20
24
  return obj && obj.__esModule ? obj : {
21
25
  default: obj
@@ -64,13 +68,47 @@ async function executeOnServer(args, client, logger) {
64
68
  throw new Error("No task provided");
65
69
  }
66
70
  const { taskArgs } = (0, _filterArgsForTasks.filterArgsForTasks)(args ?? []);
67
- const response = await client.runTarget({
68
- packageName,
69
- task,
70
- taskArgs
71
- });
72
- logger.info(`Task ${response.packageName} ${response.task} exited with code ${response.exitCode} `);
73
- return response;
71
+ try {
72
+ const response = await client.runTarget({
73
+ packageName,
74
+ task,
75
+ taskArgs
76
+ });
77
+ logger.info(`Task ${response.packageName} ${response.task} exited with code ${response.exitCode} `);
78
+ return response;
79
+ } catch (error) {
80
+ if (error instanceof _rpc.ConnectError) {
81
+ logger.error("Error connecting to server", {
82
+ error
83
+ });
84
+ } else {
85
+ logger.error("Error running task", {
86
+ error
87
+ });
88
+ }
89
+ }
90
+ }
91
+ function isAlive(pid) {
92
+ try {
93
+ return process.kill(pid, 0);
94
+ } catch {
95
+ return false;
96
+ }
97
+ }
98
+ function ensurePidFile(lockfilePath) {
99
+ if (!_fs.default.existsSync(_path.default.dirname(lockfilePath))) {
100
+ _fs.default.mkdirSync(_path.default.dirname(lockfilePath), {
101
+ recursive: true
102
+ });
103
+ }
104
+ if (!_fs.default.existsSync(lockfilePath)) {
105
+ try {
106
+ const fd = _fs.default.openSync(lockfilePath, "w");
107
+ _fs.default.closeSync(fd);
108
+ } catch {
109
+ // ignore
110
+ }
111
+ }
74
112
  }
75
113
  async function executeRemotely(options, command) {
76
114
  // launch a 'lage-server.js' process, detached if it is not already running
@@ -82,30 +120,61 @@ async function executeRemotely(options, command) {
82
120
  options.logLevel = options.logLevel ?? "info";
83
121
  options.reporter = options.reporter ?? "json";
84
122
  (0, _initializeReporters.initializeReporters)(logger, options);
123
+ const root = (0, _workspacetools.getWorkspaceRoot)(options.cwd ?? process.cwd());
124
+ const lockfilePath = _path.default.join(root, `node_modules/.cache/lage/.lage-server-${host}-${port}.pid`);
85
125
  let client = await tryCreateClient(host, port);
86
126
  const args = command.args;
87
127
  if (!client) {
88
128
  logger.info(`Starting server on http://${host}:${port}`);
89
- const binPaths = (0, _getBinPaths.getBinPaths)();
90
- const lageServerBinPath = binPaths["lage-server"];
91
- const lageServerArgs = [
92
- "--host",
93
- host,
94
- "--port",
95
- port,
96
- "--timeout",
97
- timeout,
98
- ...args
99
- ];
100
- logger.info(`Launching lage-server with these parameters: ${lageServerArgs.join(" ")}`);
101
- const child = (0, _execa.default)(lageServerBinPath, lageServerArgs, {
102
- detached: true,
103
- stdio: "ignore"
129
+ logger.info(`acquiring lock: ${lockfilePath}`);
130
+ ensurePidFile(lockfilePath);
131
+ const releaseLock = await _properlockfile.default.lock(lockfilePath, {
132
+ stale: 1000 * 60 * 1,
133
+ retries: {
134
+ retries: 10,
135
+ factor: 3,
136
+ minTimeout: 0.5 * 1000,
137
+ maxTimeout: 60 * 1000,
138
+ randomize: true
139
+ }
104
140
  });
105
- child.unref();
106
- logger.info("Server started", {
107
- pid: child.pid
141
+ const pid = parseInt(_fs.default.readFileSync(lockfilePath, "utf-8"));
142
+ const isServerRunning = pid && isAlive(pid);
143
+ logger.info("Checking if server is already running", {
144
+ pid,
145
+ isServerRunning
108
146
  });
147
+ if (pid && isServerRunning) {
148
+ logger.info("Server already running", {
149
+ pid
150
+ });
151
+ } else {
152
+ const binPaths = (0, _getBinPaths.getBinPaths)();
153
+ const lageServerBinPath = binPaths["lage-server"];
154
+ const lageServerArgs = [
155
+ "--host",
156
+ host,
157
+ "--port",
158
+ port,
159
+ "--timeout",
160
+ timeout,
161
+ ...args
162
+ ];
163
+ logger.info(`Launching lage-server with these parameters: ${lageServerArgs.join(" ")}`);
164
+ const child = (0, _execa.default)(lageServerBinPath, lageServerArgs, {
165
+ cwd: root,
166
+ detached: true,
167
+ stdio: "ignore"
168
+ });
169
+ if (child && child.pid) {
170
+ _fs.default.writeFileSync(lockfilePath, child.pid.toString());
171
+ }
172
+ child.unref();
173
+ logger.info("Server started", {
174
+ pid: child.pid
175
+ });
176
+ }
177
+ await releaseLock();
109
178
  logger.info("Creating a client to connect to the background services");
110
179
  client = await tryCreateClientWithRetries(host, port, logger);
111
180
  if (!client) {
@@ -114,11 +183,15 @@ async function executeRemotely(options, command) {
114
183
  }
115
184
  logger.info(`Executing on server http://${host}:${port}`);
116
185
  const response = await executeOnServer(args, client, logger);
117
- process.stdout.write(response.stdout);
118
- process.stderr.write(response.stderr);
119
- process.exitCode = response.exitCode;
120
- if (response.exitCode === 0) {
121
- await (0, _simulateFileAccess.simulateFileAccess)(logger, response.inputs, response.outputs);
186
+ if (response) {
187
+ process.stdout.write(response.stdout);
188
+ process.stderr.write(response.stderr);
189
+ process.exitCode = response.exitCode;
190
+ if (response.exitCode === 0) {
191
+ await (0, _simulateFileAccess.simulateFileAccess)(logger, response.inputs, response.outputs);
192
+ }
193
+ } else {
194
+ process.exitCode = 1;
122
195
  }
123
196
  logger.info("Task execution finished");
124
197
  }
@@ -20,5 +20,5 @@ function _interop_require_default(obj) {
20
20
  const execCommand = new _commander.Command("exec");
21
21
  execCommand.option("-c|--concurrency <number>", "max jobs to run at a time", (v)=>parseInt(v), _os.default.cpus().length - 1);
22
22
  execCommand.option("-s|--server [host:port]", "lage server host");
23
- execCommand.option("-t|--timeout <seconds>", "lage server autoshutoff timeout", (v)=>parseInt(v), 1 * 60);
23
+ execCommand.option("-t|--timeout <seconds>", "lage server autoshutoff timeout", (v)=>parseInt(v), 3 * 60);
24
24
  (0, _addLoggerOptions.addLoggerOptions)(execCommand).action(_action.execAction);
@@ -76,7 +76,7 @@ async function infoAction(options, command) {
76
76
  async function optimizeTargetGraph(graph, runnerPicker) {
77
77
  const targetMinimizedNodes = await (0, _targetgraph.removeNodes)([
78
78
  ...graph.targets.values()
79
- ] ?? [], async (target)=>{
79
+ ], async (target)=>{
80
80
  if (target.type === "noop") {
81
81
  return true;
82
82
  }
@@ -30,9 +30,18 @@ function findAllTasks(pipeline) {
30
30
  }
31
31
  return Array.from(tasks);
32
32
  }
33
- let context;
34
- async function initializeOnce(cwd, logger) {
35
- if (!context) {
33
+ let initializedPromise;
34
+ /**
35
+ * Initializes the lageService: the extra "initializePromise" ensures only one initialization is done at a time across threads
36
+ * @param cwd
37
+ * @param logger
38
+ * @returns
39
+ */ async function initialize(cwd, logger) {
40
+ if (initializedPromise) {
41
+ return await initializedPromise;
42
+ }
43
+ async function createInitializedPromise() {
44
+ logger.info("Initializing context");
36
45
  const config = await (0, _config.getConfig)(cwd);
37
46
  const root = (0, _workspacetools.getWorkspaceRoot)(cwd);
38
47
  const { pipeline } = config;
@@ -61,8 +70,9 @@ async function initializeOnce(cwd, logger) {
61
70
  packageInfos,
62
71
  includeUntracked: true
63
72
  });
73
+ logger.info("Initializing Package Tree");
64
74
  await packageTree.initialize();
65
- context = {
75
+ return {
66
76
  config,
67
77
  targetGraph,
68
78
  packageTree,
@@ -70,7 +80,8 @@ async function initializeOnce(cwd, logger) {
70
80
  root
71
81
  };
72
82
  }
73
- return context;
83
+ initializedPromise = createInitializedPromise();
84
+ return await initializedPromise;
74
85
  }
75
86
  let pool;
76
87
  async function createLageService({ cwd , serverControls , logger , maxWorkers }) {
@@ -94,18 +105,21 @@ async function createLageService({ cwd , serverControls , logger , maxWorkers }
94
105
  },
95
106
  async runTarget (request) {
96
107
  serverControls.clearCountdown();
108
+ const { config , targetGraph , dependencyMap , packageTree , root } = await initialize(cwd, logger);
97
109
  logger.info("Running target", request);
98
- const { config , targetGraph , dependencyMap , packageTree , root } = await initializeOnce(cwd, logger);
99
110
  const runners = (0, _runnerPickerOptions.runnerPickerOptions)(request.nodeOptions, config.npmClient, request.taskArgs);
100
111
  const id = (0, _targetgraph.getTargetId)(request.packageName, request.task);
101
112
  if (!targetGraph.targets.has(id)) {
102
- logger.error(`Target not found: ${request.packageName}#${request.task}`);
113
+ logger.info(`Target not found: ${request.packageName}#${request.task}`);
103
114
  return {
104
115
  packageName: request.packageName,
105
116
  task: request.task,
106
117
  exitCode: 1
107
118
  };
108
119
  }
120
+ logger.info("Target found", {
121
+ id
122
+ });
109
123
  const target = targetGraph.targets.get(id);
110
124
  const task = {
111
125
  target,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lage-run/cli",
3
- "version": "0.23.3",
3
+ "version": "0.23.5",
4
4
  "description": "Command Line Interface for Lage",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,19 +29,21 @@
29
29
  "@lage-run/reporters": "^1.2.11",
30
30
  "@lage-run/rpc": "^1.2.3",
31
31
  "@lage-run/runners": "^1.0.3",
32
- "@lage-run/scheduler": "^1.3.2",
32
+ "@lage-run/scheduler": "^1.3.3",
33
33
  "@lage-run/scheduler-types": "^0.3.16",
34
34
  "@lage-run/target-graph": "^0.9.0",
35
- "@lage-run/worker-threads-pool": "^0.8.3",
35
+ "@lage-run/worker-threads-pool": "^0.8.4",
36
36
  "chokidar": "3.5.3",
37
37
  "commander": "9.5.0",
38
38
  "execa": "5.1.1",
39
39
  "fast-glob": "3.3.2",
40
+ "proper-lockfile": "^4.1.2",
40
41
  "workspace-tools": "0.36.4"
41
42
  },
42
43
  "devDependencies": {
43
44
  "@lage-run/monorepo-fixture": "*",
44
- "@lage-run/monorepo-scripts": "*"
45
+ "@lage-run/monorepo-scripts": "*",
46
+ "@types/proper-lockfile": "^4.1.4"
45
47
  },
46
48
  "publishConfig": {
47
49
  "access": "public"