@lumpcode/core 0.0.16 → 0.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.
package/dist/index.js CHANGED
@@ -3745,6 +3745,27 @@ async function collectStepsForContext(params) {
3745
3745
  return collectedSteps;
3746
3746
  }
3747
3747
 
3748
+ async function runOptionalGitCommand(input) {
3749
+ const { label, getCommand, cwd, logger } = input;
3750
+ try {
3751
+ const command = await getCommand();
3752
+ if (command == null || command === '') {
3753
+ return 'ok';
3754
+ }
3755
+ const result = await execAsync(command, { cwd });
3756
+ logger.verbose(`${label} ${JSON.stringify(result)}`);
3757
+ if (!result.success) {
3758
+ logger.error(formatExecFailureMessage({ label, failure: result }));
3759
+ return 'failed';
3760
+ }
3761
+ return 'ok';
3762
+ }
3763
+ catch (error) {
3764
+ const message = error instanceof Error ? error.message : String(error);
3765
+ logger.error(`Failed to run ${label}: ${message}`);
3766
+ return 'failed';
3767
+ }
3768
+ }
3748
3769
  async function executeStepsForContextList({ baseBranch, branchFn, lumpVariables, contextList, gitAddCommandFn, gitCommitCommandFn, gitPushCommandFn, gitCommitMessageFn, projectRoot, steps, setupFn, setupWorkspaceFn, teardownFn, teardownWorkspaceFn, getKeepHistoryFilePathFn, logger: loggerInput, signal, }) {
3749
3770
  const logger = loggerInput ?? createConsoleLogger({});
3750
3771
  const contextNames = contextList.map(context => context.name);
@@ -3943,39 +3964,39 @@ async function executeStepsForContextList({ baseBranch, branchFn, lumpVariables,
3943
3964
  ...injectedGitAndWorkspaceFnsInput,
3944
3965
  context,
3945
3966
  };
3946
- const gitAddCommand = await execAsync(gitAddCommandFn(perContextInput), { cwd: workspacePath });
3947
- logger.verbose(`gitAddCommand ${JSON.stringify(gitAddCommand)}`);
3948
- if (!gitAddCommand.success) {
3967
+ const addOutcome = await runOptionalGitCommand({
3968
+ label: `git add for context ${context.name}`,
3969
+ getCommand: () => gitAddCommandFn(perContextInput),
3970
+ cwd: workspacePath,
3971
+ logger,
3972
+ });
3973
+ if (addOutcome === 'failed') {
3949
3974
  runFailure = {
3950
3975
  success: false,
3951
3976
  data: {
3952
- message: `Failed to add the changes for context ${context.name}: ${gitAddCommand.data.message}`,
3977
+ message: `Failed to add the changes for context ${context.name}`,
3953
3978
  },
3954
3979
  };
3955
3980
  break;
3956
3981
  }
3957
3982
  const commitMessage = gitCommitMessageFn({ context, lumpVariables, baseBranch });
3958
- const commitCommand = await execAsync(gitCommitCommandFn({
3959
- ...perContextInput,
3960
- commitMessage,
3961
- }), { cwd: workspacePath });
3962
- logger.verbose(`commitCommand ${JSON.stringify(commitCommand)}`);
3963
- if (!commitCommand.success) {
3964
- logger.error(formatExecFailureMessage({
3965
- label: `git commit for context ${context.name}`,
3966
- failure: commitCommand,
3967
- }));
3968
- }
3983
+ await runOptionalGitCommand({
3984
+ label: `git commit for context ${context.name}`,
3985
+ getCommand: () => gitCommitCommandFn({
3986
+ ...perContextInput,
3987
+ commitMessage,
3988
+ }),
3989
+ cwd: workspacePath,
3990
+ logger,
3991
+ });
3969
3992
  }
3970
3993
  if (!runFailure) {
3971
- const pushCommand = await execAsync(gitPushCommandFn(injectedGitAndWorkspaceFnsInput), { cwd: workspacePath });
3972
- logger.verbose(`pushCommand ${JSON.stringify(pushCommand)}`);
3973
- if (!pushCommand.success) {
3974
- logger.error(formatExecFailureMessage({
3975
- label: `git push on branch ${branchName}`,
3976
- failure: pushCommand,
3977
- }));
3978
- }
3994
+ await runOptionalGitCommand({
3995
+ label: `git push on branch ${branchName}`,
3996
+ getCommand: () => gitPushCommandFn(injectedGitAndWorkspaceFnsInput),
3997
+ cwd: workspacePath,
3998
+ logger,
3999
+ });
3979
4000
  }
3980
4001
  }
3981
4002
  finally {
@@ -4091,17 +4112,32 @@ async function scanDirectory({ dirPath, allPaths, gitignoresMap, projectRoot, lo
4091
4112
  }
4092
4113
  }
4093
4114
 
4115
+ /**
4116
+ * Refreshes remote-tracking refs for status / planning (one network fetch).
4117
+ * Uses `--no-write-fetch-head` so concurrent preflight/pull paths are safer.
4118
+ */
4119
+ const refreshRemoteTrackingRefs = async (input) => {
4120
+ const { projectRoot, remoteName = 'origin' } = input;
4121
+ const result = await execAsync(`git fetch --prune --no-write-fetch-head ${remoteName}`, { cwd: projectRoot });
4122
+ if (!result.success) {
4123
+ return failure(result.data.message);
4124
+ }
4125
+ return success(undefined);
4126
+ };
4127
+
4094
4128
  async function getContextStatus(params) {
4095
- const { contextName, gitCommitMessageFn, projectRoot, baseBranch, lumpVariables: lumpVariablesInput, contextVariables = {}, remoteName = "origin", logger, } = params;
4129
+ const { contextName, gitCommitMessageFn, projectRoot, baseBranch, lumpVariables: lumpVariablesInput, contextVariables = {}, remoteName = "origin", logger, skipFetch = false, } = params;
4096
4130
  const lumpVariables = (lumpVariablesInput ?? {});
4097
4131
  const commitMessage = gitCommitMessageFn({
4098
4132
  context: { name: contextName, variables: contextVariables },
4099
4133
  lumpVariables,
4100
4134
  baseBranch,
4101
4135
  });
4102
- const fetchAll = await execAsync(`git fetch --all --prune`, { cwd: projectRoot });
4103
- if (!fetchAll.success)
4104
- return 'toDo';
4136
+ if (!skipFetch) {
4137
+ const fetchResult = await refreshRemoteTrackingRefs({ projectRoot, remoteName });
4138
+ if (!fetchResult.success)
4139
+ return 'toDo';
4140
+ }
4105
4141
  const logResult = await execAsync(`git log --remotes=${remoteName} -F --grep=${shellSingleQuote(commitMessage)} --format=${shellSingleQuote('%H %s')}`, { cwd: projectRoot });
4106
4142
  if (!logResult.success)
4107
4143
  return 'toDo';
@@ -4110,6 +4146,7 @@ async function getContextStatus(params) {
4110
4146
  const matchingHashes = parseGitLogHashSubjectLines(logResultOutput)
4111
4147
  .filter((entry) => entry.subject === commitMessage)
4112
4148
  .map((entry) => entry.hash);
4149
+ logger?.verbose(`contextName ${contextName}`);
4113
4150
  logger?.verbose(`remoteName ${remoteName}`);
4114
4151
  logger?.verbose(`baseBranch ${baseBranch}`);
4115
4152
  logger?.verbose(`commitMessage ${commitMessage}`);
@@ -4164,7 +4201,7 @@ function validateContextListNames(contextList) {
4164
4201
  }
4165
4202
 
4166
4203
  async function getToDoContextList(params) {
4167
- const { getContextListFn, lumpVariables, gitCommitMessageFn, projectRoot, baseBranch, logger } = params;
4204
+ const { getContextListFn, lumpVariables, gitCommitMessageFn, projectRoot, baseBranch, logger, refreshRemoteTrackingRefsFn = refreshRemoteTrackingRefs, } = params;
4168
4205
  const codeBasePathsResult = await getCodeBasePaths({ cwd: projectRoot, logger });
4169
4206
  if (!codeBasePathsResult.success) {
4170
4207
  return failure({
@@ -4182,21 +4219,28 @@ async function getToDoContextList(params) {
4182
4219
  const allCtxNames = contextList.flatMap(context => [context.name, ...(context.options?.dependsOnContexts ?? [])]);
4183
4220
  const allCtxNamesSet = new Set(allCtxNames);
4184
4221
  const allCtxNamesList = Array.from(allCtxNamesSet);
4185
- const contextStatusList = await Promise.all(allCtxNamesList.map((contextName) => {
4186
- return getContextStatus({
4187
- contextName: contextName,
4222
+ const refreshResult = await refreshRemoteTrackingRefsFn({ projectRoot });
4223
+ let contextStatusMap;
4224
+ if (!refreshResult.success) {
4225
+ logger?.warn(`Failed to refresh remote-tracking refs for context status; treating contexts as toDo: ${refreshResult.data}`);
4226
+ contextStatusMap = new Map(allCtxNamesList.map((name) => [name, 'toDo']));
4227
+ }
4228
+ else {
4229
+ const contextStatusList = await Promise.all(allCtxNamesList.map((contextName) => getContextStatus({
4230
+ contextName,
4188
4231
  contextVariables: {}, // TODO: Remove contextVariables from getContextStatus, really not needed
4189
4232
  gitCommitMessageFn,
4190
4233
  lumpVariables,
4191
4234
  projectRoot,
4192
4235
  baseBranch,
4193
4236
  logger,
4194
- });
4195
- }));
4196
- const contextStatusMap = new Map(allCtxNamesList.map((contextName, i) => [contextName, contextStatusList[i]]));
4237
+ skipFetch: true,
4238
+ })));
4239
+ contextStatusMap = new Map(allCtxNamesList.map((contextName, i) => [contextName, contextStatusList[i]]));
4240
+ }
4197
4241
  const contextListToDo = contextList
4198
- .filter((context, contextIndex) => {
4199
- const contextStatus = contextStatusList[contextIndex];
4242
+ .filter((context) => {
4243
+ const contextStatus = contextStatusMap.get(context.name);
4200
4244
  if (contextStatus && contextStatus !== 'toDo')
4201
4245
  return false;
4202
4246
  const deps = context.options?.dependsOnContexts;
@@ -4262,7 +4306,7 @@ const defaultSetupWorkspaceFnWithWorktree = async (input) => {
4262
4306
  };
4263
4307
 
4264
4308
  async function runLump(input) {
4265
- const { baseBranch, branchFn, lumpVariables: lumpVariablesInput, getContextListFn, gitAddCommandFn = defaultGitAddCommandFn, gitCommitCommandFn = defaultGitCommitCommandFn, gitCommitMessageFn = defaultGitCommitMessageFn, gitPushCommandFn = defaultGitPushCommandFn, numberOfContextsPerBranch = 1, projectRoot, steps, setupFn = () => ({ contextRunState: {} }), setupWorkspaceFn = defaultSetupWorkspaceFn, teardownFn = () => undefined, teardownWorkspaceFn = defaultTeardownWorkspaceFn, getKeepHistoryFilePathFn = () => undefined, logger: loggerInput, signal, } = input;
4309
+ const { baseBranch, branchFn, lumpVariables: lumpVariablesInput, getContextListFn, gitAddCommandFn = defaultGitAddCommandFn, gitCommitCommandFn = defaultGitCommitCommandFn, gitCommitMessageFn = defaultGitCommitMessageFn, gitPushCommandFn = defaultGitPushCommandFn, numberOfContextsPerBranch = 1, projectRoot, steps, setupFn = () => ({ contextRunState: {} }), setupWorkspaceFn = defaultSetupWorkspaceFn, teardownFn = () => undefined, teardownWorkspaceFn = defaultTeardownWorkspaceFn, getKeepHistoryFilePathFn = () => undefined, logger: loggerInput, signal, refreshRemoteTrackingRefsFn, } = input;
4266
4310
  const lumpVariables = (lumpVariablesInput ?? {});
4267
4311
  const logger = loggerInput ?? createConsoleLogger({});
4268
4312
  const contextListToDoResult = await getToDoContextList({
@@ -4272,6 +4316,7 @@ async function runLump(input) {
4272
4316
  baseBranch,
4273
4317
  gitCommitMessageFn,
4274
4318
  logger,
4319
+ refreshRemoteTrackingRefsFn,
4275
4320
  });
4276
4321
  if (!contextListToDoResult.success) {
4277
4322
  return set(contextListToDoResult, ['data', 'message'], "Error in runLump: Failed to get to do context list. Original Error: " + contextListToDoResult.data.message);
@@ -4318,5 +4363,5 @@ async function runLump(input) {
4318
4363
  });
4319
4364
  }
4320
4365
 
4321
- export { appendHistoryEntry, collectStepsForContext, contextStatus, createConsoleLogger, defaultGitAddCommandFn, defaultGitCommitCommandFn, defaultGitCommitMessageFn, defaultGitPushCommandFn, defaultSetupWorkspaceFn, defaultSetupWorkspaceFnWithWorktree, defaultTeardownWorkspaceFn, defaultTeardownWorkspaceFnWithWorktree, execAsync, execBinary, executeStepsForContextList, failure, formatExecFailureMessage, getCodeBasePaths, getContextStatus, getToDoContextList, historyFormatFromPath, isProcessAlive, killProcessTree, nodeErrnoCode, parseGitLogHashSubjectLines, pathExists, readHistoryFile, resolveSpawnExecutable, runLump, set, shellSingleQuote, success, validateContextListNames, windowsNpmCmdShimBody, writeHistoryFile };
4366
+ export { appendHistoryEntry, collectStepsForContext, contextStatus, createConsoleLogger, defaultGitAddCommandFn, defaultGitCommitCommandFn, defaultGitCommitMessageFn, defaultGitPushCommandFn, defaultSetupWorkspaceFn, defaultSetupWorkspaceFnWithWorktree, defaultTeardownWorkspaceFn, defaultTeardownWorkspaceFnWithWorktree, execAsync, execBinary, executeStepsForContextList, failure, formatExecFailureMessage, getCodeBasePaths, getContextStatus, getToDoContextList, historyFormatFromPath, isProcessAlive, killProcessTree, nodeErrnoCode, parseGitLogHashSubjectLines, pathExists, readHistoryFile, refreshRemoteTrackingRefs, resolveSpawnExecutable, runLump, set, shellSingleQuote, success, validateContextListNames, windowsNpmCmdShimBody, writeHistoryFile };
4322
4367
  //# sourceMappingURL=index.js.map