Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/src/content/docs/hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ Hooks can use template variables that expand at runtime:
| | `{{ base_worktree_path }}` | Base worktree path |
| | `{{ target }}` | Target branch name |
| | `{{ target_worktree_path }}` | Target worktree path (when target has a worktree) |
| | `{{ pr_number }}` | PR/MR number (post-switch, pre-start, post-start; when creating via `pr:N` / `mr:N`) |
| | `{{ pr_url }}` | PR/MR web URL (post-switch, pre-start, post-start; when creating via `pr:N` / `mr:N`) |
| | `{{ pr_number }}` | PR/MR number (switch and create hooks; when switching via `pr:N` / `mr:N`) |
| | `{{ pr_url }}` | PR/MR web URL (switch and create hooks; when switching via `pr:N` / `mr:N`) |
| repo | `{{ repo }}` | Repository directory name |
| | `{{ repo_path }}` | Absolute path to repository root |
| | `{{ owner }}` | Primary remote owner path (may include subgroups) |
Expand Down Expand Up @@ -161,7 +161,7 @@ All hooks share the same perspective — `{{ branch | hash_port }}` produces the

`cwd` is the worktree root where the hook command runs. It equals `worktree_path` except in three cases:

- `pre-switch`: hook runs in the source worktree; `worktree_path` is the destination
- `pre-switch`: hook runs in the source worktree; `worktree_path` is the destination when that worktree already exists — a switch that creates one has no destination directory yet, so `worktree_path` stays on the source (use `pre-start` to work in the new worktree)
- `post-remove`: the active worktree is gone, so the hook runs in the primary worktree
- `post-merge` with removal: the active worktree is gone, so the hook runs in the target worktree

Expand Down
6 changes: 3 additions & 3 deletions plugins/worktrunk/skills/worktrunk/reference/hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ Hooks can use template variables that expand at runtime:
| | `{{ base_worktree_path }}` | Base worktree path |
| | `{{ target }}` | Target branch name |
| | `{{ target_worktree_path }}` | Target worktree path (when target has a worktree) |
| | `{{ pr_number }}` | PR/MR number (post-switch, pre-start, post-start; when creating via `pr:N` / `mr:N`) |
| | `{{ pr_url }}` | PR/MR web URL (post-switch, pre-start, post-start; when creating via `pr:N` / `mr:N`) |
| | `{{ pr_number }}` | PR/MR number (switch and create hooks; when switching via `pr:N` / `mr:N`) |
| | `{{ pr_url }}` | PR/MR web URL (switch and create hooks; when switching via `pr:N` / `mr:N`) |
| repo | `{{ repo }}` | Repository directory name |
| | `{{ repo_path }}` | Absolute path to repository root |
| | `{{ owner }}` | Primary remote owner path (may include subgroups) |
Expand Down Expand Up @@ -155,7 +155,7 @@ All hooks share the same perspective — `{{ branch | hash_port }}` produces the

`cwd` is the worktree root where the hook command runs. It equals `worktree_path` except in three cases:

- `pre-switch`: hook runs in the source worktree; `worktree_path` is the destination
- `pre-switch`: hook runs in the source worktree; `worktree_path` is the destination when that worktree already exists — a switch that creates one has no destination directory yet, so `worktree_path` stays on the source (use `pre-start` to work in the new worktree)
- `post-remove`: the active worktree is gone, so the hook runs in the primary worktree
- `post-merge` with removal: the active worktree is gone, so the hook runs in the target worktree

Expand Down
6 changes: 3 additions & 3 deletions skills/worktrunk/reference/hook.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1670,8 +1670,8 @@ Hooks can use template variables that expand at runtime:
| | `{{ base_worktree_path }}` | Base worktree path |
| | `{{ target }}` | Target branch name |
| | `{{ target_worktree_path }}` | Target worktree path (when target has a worktree) |
| | `{{ pr_number }}` | PR/MR number (post-switch, pre-start, post-start; when creating via `pr:N` / `mr:N`) |
| | `{{ pr_url }}` | PR/MR web URL (post-switch, pre-start, post-start; when creating via `pr:N` / `mr:N`) |
| | `{{ pr_number }}` | PR/MR number (switch and create hooks; when switching via `pr:N` / `mr:N`) |
| | `{{ pr_url }}` | PR/MR web URL (switch and create hooks; when switching via `pr:N` / `mr:N`) |
| repo | `{{ repo }}` | Repository directory name |
| | `{{ repo_path }}` | Absolute path to repository root |
| | `{{ owner }}` | Primary remote owner path (may include subgroups) |
Expand Down Expand Up @@ -1701,7 +1701,7 @@ All hooks share the same perspective — `{{ branch | hash_port }}` produces the

`cwd` is the worktree root where the hook command runs. It equals `worktree_path` except in three cases:

- `pre-switch`: hook runs in the source worktree; `worktree_path` is the destination
- `pre-switch`: hook runs in the source worktree; `worktree_path` is the destination when that worktree already exists — a switch that creates one has no destination directory yet, so `worktree_path` stays on the source (use `pre-start` to work in the new worktree)
- `post-remove`: the active worktree is gone, so the hook runs in the primary worktree
- `post-merge` with removal: the active worktree is gone, so the hook runs in the target worktree

Expand Down
20 changes: 11 additions & 9 deletions src/commands/template_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ impl TemplateVars {
///
/// `target` matches the bare vars (the destination); `base` is the source
/// — the branched-from for creates, the source worktree for existing
/// switches. PR/MR identity propagates into post-* hooks.
/// switches. PR/MR identity is not read off the result: it belongs to the
/// argument, not to what the switch did with it, so the caller applies it
/// with [`with_pr`](Self::with_pr) — an `Existing` switch onto a
/// `pr:N` branch has the same identity as the run that created it.
pub fn for_post_switch(
result: &SwitchResult,
branch_info: &SwitchBranchInfo,
Expand All @@ -164,12 +167,8 @@ impl TemplateVars {
SwitchResult::Created {
base_branch,
base_worktree_path,
pr_number,
pr_url,
..
} => vars
.with_base_strs(base_branch.as_deref(), base_worktree_path.as_deref())
.with_pr(*pr_number, pr_url.as_deref()),
} => vars.with_base_strs(base_branch.as_deref(), base_worktree_path.as_deref()),
SwitchResult::Existing { .. } | SwitchResult::AlreadyAt(_) => {
let base = (!source_branch.is_empty()).then_some(source_branch);
let path = (!source_path.is_empty()).then_some(source_path);
Expand Down Expand Up @@ -247,21 +246,24 @@ mod tests {
assert!(!pairs.iter().any(|(k, _)| *k == "base_worktree_path"));
}

/// The switch pipeline layers the PR/MR identity on afterwards, the same
/// way for a create as for a switch onto an existing worktree.
#[test]
fn for_post_switch_created_with_pr() {
fn for_post_switch_created_takes_pr_from_caller() {
let result = SwitchResult::Created {
path: PathBuf::from("/repo.fork"),
created_branch: false,
base_branch: Some("main".to_string()),
base_worktree_path: Some("/repo".to_string()),
from_remote: None,
pr_number: Some(42),
pr_url: Some("https://example.test/pr/42".to_string()),
};
let info = SwitchBranchInfo {
branch: Some("contributor/feature".to_string()),
};
let vars = TemplateVars::for_post_switch(&result, &info, "", "");
assert!(!vars.as_extra_vars().iter().any(|(k, _)| *k == "pr_number"));

let vars = vars.with_pr(Some(42), Some("https://example.test/pr/42"));
let pairs = vars.as_extra_vars();
assert!(pairs.contains(&("base", "main")));
assert!(pairs.contains(&("base_worktree_path", "/repo")));
Expand Down
Loading
Loading