diff --git a/TESTING.md b/TESTING.md index 3d4f9e6..158115a 100644 --- a/TESTING.md +++ b/TESTING.md @@ -1,23 +1,4 @@ -# Manual Test for CI Publish Workflow - -1. Push a commit to the main branch (or merge the PR) to trigger the workflow. -2. Check the Actions tab in your GitHub repository to see that the "Publish to npm" workflow runs successfully. -3. Verify that the package is published to npm with the expected version (0.0.0-development) without any new commits from the workflow. - -## Important Notes - -- The CI workflow will not make any commits or version bumps -- Version updates should be handled manually outside of CI -- Make sure you have set up the `NPM_TOKEN` secret in your GitHub repository settings - -## New Worktree Sibling Directory Test - -1. In a test repository, run: - ```bash - cwt new editor - ``` -2. Verify that a new sibling directory named `editor` is created. -3. Confirm that the worktree is added to the Git repository and that the Cursor editor opens the new directory. +# Manual Tests for cursor-worktree CLI ## Manual Test for CLI Command Name Change @@ -43,6 +24,15 @@ cwt remove feature/test ``` +## New Worktree Sibling Directory Test + +1. In a test repository, run: + ```bash + cwt new editor + ``` +2. Verify that a new sibling directory named `-editor` is created. +3. Confirm that the worktree is added to the Git repository and that the Cursor editor opens the new directory. + ## Remove Worktree Force Flag Test 1. Create a test worktree: @@ -61,3 +51,44 @@ ``` This should succeed and remove the worktree regardless of its state 5. Verify that the worktree directory is removed and the Git worktree reference is cleaned up + +## Manual Test for Merge Command + +1. **Setup a Test Worktree:** + - Create a new worktree for a test branch: + ```bash + cwt new test-merge + ``` +2. **Make Changes in the Test Worktree:** + - Navigate to the test worktree directory, edit a file, and save your changes. +3. **Run the Merge Command:** + - Go back to your main worktree (current branch) and execute: + ```bash + cwt merge test-merge + ``` +4. **Verify the Merge:** + - Confirm that the changes from `test-merge` are merged into the current branch. + - Check that the test worktree is removed. +5. **Test with Force Flag:** + - Create another test worktree: + ```bash + cwt new test-merge-force + ``` + - Make changes that would prevent normal removal (e.g., untracked files) + - Run the merge with force flag: + ```bash + cwt merge test-merge-force --force + ``` + - Verify that the merge succeeds and the worktree is forcibly removed. + +## Manual Test for CI Publish Workflow + +1. Push a commit to the main branch (or merge the PR) to trigger the workflow. +2. Check the Actions tab in your GitHub repository to see that the "Publish to npm" workflow runs successfully. +3. Verify that the package is published to npm with the expected version (0.0.0-development) without any new commits from the workflow. + +## Important Notes + +- The CI workflow will not make any commits or version bumps +- Version updates should be handled manually outside of CI +- Make sure you have set up the `NPM_TOKEN` secret in your GitHub repository settings diff --git a/src/commands/merge.ts b/src/commands/merge.ts new file mode 100644 index 0000000..c87d10b --- /dev/null +++ b/src/commands/merge.ts @@ -0,0 +1,95 @@ +import { execa } from "execa"; +import chalk from "chalk"; +import { stat, rm } from "node:fs/promises"; +import { resolve } from "node:path"; + +export async function mergeWorktreeHandler( + branchName: string, + options: { force?: boolean } +) { + try { + // Validate that we're in a git repository + await execa("git", ["rev-parse", "--is-inside-work-tree"]); + + // Get the current branch name (the target for merging) + const { stdout: currentBranch } = await execa("git", ["branch", "--show-current"]); + if (!currentBranch) { + console.error(chalk.red("Failed to determine the current branch.")); + process.exit(1); + } + + // Parse worktree list to find the worktree for the target branch + const { stdout } = await execa("git", ["worktree", "list", "--porcelain"]); + let targetPath = ""; + let tempPath = ""; + const lines = stdout.split("\n"); + for (const line of lines) { + if (line.startsWith("worktree ")) { + tempPath = line.replace("worktree ", "").trim(); + } else if (line.startsWith("branch ")) { + const fullBranchRef = line.replace("branch ", "").trim(); + const shortBranch = fullBranchRef.replace("refs/heads/", ""); + if (shortBranch === branchName) { + targetPath = tempPath; + break; + } + } + } + + if (!targetPath) { + console.error(chalk.red(`Could not find a worktree for branch "${branchName}".`)); + process.exit(1); + } + + console.log( + chalk.blue( + `Merging changes from worktree branch "${branchName}" at ${targetPath} into current branch "${currentBranch}".` + ) + ); + + // Step 1: Commit any pending changes in the target branch worktree + try { + await execa("git", ["-C", targetPath, "add", "."]); + await execa("git", [ + "-C", + targetPath, + "commit", + "-m", + `Auto-commit changes before merging ${branchName}`, + ]); + console.log(chalk.green("Committed pending changes in target branch worktree.")); + } catch (commitError) { + console.log( + chalk.yellow("No pending changes to commit in the target branch or commit failed, proceeding with merge.") + ); + } + + // Step 2: Merge the target branch into the current branch + await execa("git", ["merge", branchName]); + console.log(chalk.green(`Merged branch "${branchName}" into "${currentBranch}".`)); + + // Step 3: Remove the worktree for the merged branch (similar to 'cwt remove') + console.log(chalk.blue(`Removing worktree for branch "${branchName}"...`)); + const removeArgs = ["worktree", "remove", ...(options.force ? ["--force"] : []), targetPath]; + await execa("git", removeArgs); + console.log(chalk.green(`Removed worktree at ${targetPath}.`)); + + // Optionally remove the physical directory if it still exists + try { + await stat(targetPath); + await rm(targetPath, { recursive: true, force: true }); + console.log(chalk.green(`Deleted folder ${targetPath}.`)); + } catch { + // If the directory does not exist, it's fine + } + + console.log(chalk.green("Merge command completed successfully!")); + } catch (error) { + if (error instanceof Error) { + console.error(chalk.red("Failed to merge worktree:"), error.message); + } else { + console.error(chalk.red("Failed to merge worktree:"), error); + } + process.exit(1); + } +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d8ec76b..4906285 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import chalk from "chalk"; import { newWorktreeHandler } from "./commands/new.js"; import { listWorktreesHandler } from "./commands/list.js"; import { removeWorktreeHandler } from "./commands/remove.js"; +import { mergeWorktreeHandler } from "./commands/merge.js"; const program = new Command(); @@ -35,4 +36,11 @@ program .description("Remove a specified worktree. Cleans up the .git/worktrees references.") .action(removeWorktreeHandler); +program + .command("merge") + .argument("", "Name of the branch to merge from") + .option("-f, --force", "Force removal of worktree after merge", false) + .description("Commit changes in the target branch and merge them into the current branch, then remove the branch/worktree") + .action(mergeWorktreeHandler); + program.parse(process.argv); \ No newline at end of file