mirror of
https://github.com/zed-industries/zed.git
synced 2026-05-24 13:39:08 +00:00
### Summary
This PR starts work on adding basic hook support in the `TaskStore`. To
enable users to setup tasks that are ran when the agent panel creates a
new git worktree to start a thread in. It also adds a new task variable
called `ZED_MAIN_GIT_WORKTREE` that's the absolute path to the main repo
that the newly created linked worktree is based off of.
### Follow Ups
- Get this hook working with the git worktree picker as well
- Make a more general approach to the hook system in `TaskStore`
- Add `ZED_PORT_{1..10}` task variables
- Migrate the task context creation code from `task_ui` to the basic
context provider
Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- N/A *or* Added/Fixed/Improved ...
---------
Co-authored-by: Remco Smits <djsmits12@gmail.com>
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
301 lines
10 KiB
Rust
301 lines
10 KiB
Rust
mod go_locator {
|
|
use collections::HashMap;
|
|
use dap::{DapLocator, adapters::DebugAdapterName};
|
|
use gpui::TestAppContext;
|
|
use project::debugger::locators::go::{DelveLaunchRequest, GoLocator};
|
|
use task::{HideStrategy, RevealStrategy, RevealTarget, SaveStrategy, Shell, TaskTemplate};
|
|
#[gpui::test]
|
|
async fn test_create_scenario_for_go_build(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let task = TaskTemplate {
|
|
label: "go build".into(),
|
|
command: "go".into(),
|
|
args: vec!["build".into(), ".".into()],
|
|
env: Default::default(),
|
|
cwd: Some("${ZED_WORKTREE_ROOT}".into()),
|
|
use_new_terminal: false,
|
|
allow_concurrent_runs: false,
|
|
reveal: RevealStrategy::Always,
|
|
reveal_target: RevealTarget::Dock,
|
|
hide: HideStrategy::Never,
|
|
shell: Shell::System,
|
|
tags: vec![],
|
|
show_summary: true,
|
|
show_command: true,
|
|
save: SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test label", &DebugAdapterName("Delve".into()))
|
|
.await;
|
|
|
|
assert!(scenario.is_none());
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_skip_non_go_commands_with_non_delve_adapter(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let task = TaskTemplate {
|
|
label: "cargo build".into(),
|
|
command: "cargo".into(),
|
|
args: vec!["build".into()],
|
|
env: Default::default(),
|
|
cwd: Some("${ZED_WORKTREE_ROOT}".into()),
|
|
use_new_terminal: false,
|
|
allow_concurrent_runs: false,
|
|
reveal: RevealStrategy::Always,
|
|
reveal_target: RevealTarget::Dock,
|
|
hide: HideStrategy::Never,
|
|
shell: Shell::System,
|
|
tags: vec![],
|
|
show_summary: true,
|
|
show_command: true,
|
|
save: SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(
|
|
&task,
|
|
"test label",
|
|
&DebugAdapterName("SomeOtherAdapter".into()),
|
|
)
|
|
.await;
|
|
assert!(scenario.is_none());
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test label", &DebugAdapterName("Delve".into()))
|
|
.await;
|
|
assert!(scenario.is_none());
|
|
}
|
|
#[gpui::test]
|
|
async fn test_go_locator_run(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let delve = DebugAdapterName("Delve".into());
|
|
|
|
let task = TaskTemplate {
|
|
label: "go run with flags".into(),
|
|
command: "go".into(),
|
|
args: vec![
|
|
"run".to_string(),
|
|
"-race".to_string(),
|
|
"-ldflags".to_string(),
|
|
"-X main.version=1.0".to_string(),
|
|
"./cmd/myapp".to_string(),
|
|
"--config".to_string(),
|
|
"production.yaml".to_string(),
|
|
"--verbose".to_string(),
|
|
],
|
|
env: {
|
|
let mut env = HashMap::default();
|
|
env.insert("GO_ENV".to_string(), "production".to_string());
|
|
env
|
|
},
|
|
cwd: Some("/project/root".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test run label", &delve)
|
|
.await
|
|
.unwrap();
|
|
|
|
let config: DelveLaunchRequest = serde_json::from_value(scenario.config).unwrap();
|
|
|
|
assert_eq!(
|
|
config,
|
|
DelveLaunchRequest {
|
|
request: "launch".to_string(),
|
|
mode: "debug".to_string(),
|
|
program: "./cmd/myapp".to_string(),
|
|
build_flags: vec![
|
|
"-race".to_string(),
|
|
"-ldflags".to_string(),
|
|
"-X main.version=1.0".to_string()
|
|
],
|
|
args: vec![
|
|
"--config".to_string(),
|
|
"production.yaml".to_string(),
|
|
"--verbose".to_string(),
|
|
],
|
|
env: {
|
|
let mut env = HashMap::default();
|
|
env.insert("GO_ENV".to_string(), "production".to_string());
|
|
env
|
|
},
|
|
cwd: Some("/project/root".to_string()),
|
|
}
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_go_locator_test(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let delve = DebugAdapterName("Delve".into());
|
|
|
|
// Test with tags and run flag
|
|
let task_with_tags = TaskTemplate {
|
|
label: "test".into(),
|
|
command: "go".into(),
|
|
args: vec![
|
|
"test".to_string(),
|
|
"-tags".to_string(),
|
|
"integration,unit".to_string(),
|
|
"-run".to_string(),
|
|
"Foo".to_string(),
|
|
".".to_string(),
|
|
],
|
|
..Default::default()
|
|
};
|
|
let result = locator
|
|
.create_scenario(&task_with_tags, "", &delve)
|
|
.await
|
|
.unwrap();
|
|
|
|
let config: DelveLaunchRequest = serde_json::from_value(result.config).unwrap();
|
|
|
|
assert_eq!(
|
|
config,
|
|
DelveLaunchRequest {
|
|
request: "launch".to_string(),
|
|
mode: "test".to_string(),
|
|
program: ".".to_string(),
|
|
build_flags: vec!["-tags".to_string(), "integration,unit".to_string(),],
|
|
args: vec![
|
|
"-test.run".to_string(),
|
|
"Foo".to_string(),
|
|
"-test.v".to_string()
|
|
],
|
|
env: Default::default(),
|
|
cwd: None,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_skip_unsupported_go_commands(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let task = TaskTemplate {
|
|
label: "go clean".into(),
|
|
command: "go".into(),
|
|
args: vec!["clean".into()],
|
|
env: Default::default(),
|
|
cwd: Some("${ZED_WORKTREE_ROOT}".into()),
|
|
use_new_terminal: false,
|
|
allow_concurrent_runs: false,
|
|
reveal: RevealStrategy::Always,
|
|
reveal_target: RevealTarget::Dock,
|
|
hide: HideStrategy::Never,
|
|
shell: Shell::System,
|
|
tags: vec![],
|
|
show_summary: true,
|
|
show_command: true,
|
|
save: SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test label", &DebugAdapterName("Delve".into()))
|
|
.await;
|
|
assert!(scenario.is_none());
|
|
}
|
|
}
|
|
|
|
mod python_locator {
|
|
use dap::{DapLocator, adapters::DebugAdapterName};
|
|
use serde_json::json;
|
|
|
|
use project::debugger::locators::python::*;
|
|
use task::{DebugScenario, TaskTemplate};
|
|
|
|
#[gpui::test]
|
|
async fn test_python_locator() {
|
|
let adapter = DebugAdapterName("Debugpy".into());
|
|
let build_task = TaskTemplate {
|
|
label: "run module '$ZED_FILE'".into(),
|
|
command: "$ZED_CUSTOM_PYTHON_ACTIVE_ZED_TOOLCHAIN".into(),
|
|
args: vec!["-m".into(), "$ZED_CUSTOM_PYTHON_MODULE_NAME".into()],
|
|
env: Default::default(),
|
|
cwd: Some("$ZED_WORKTREE_ROOT".into()),
|
|
use_new_terminal: false,
|
|
allow_concurrent_runs: false,
|
|
reveal: task::RevealStrategy::Always,
|
|
reveal_target: task::RevealTarget::Dock,
|
|
hide: task::HideStrategy::Never,
|
|
tags: vec!["python-module-main-method".into()],
|
|
shell: task::Shell::System,
|
|
show_summary: false,
|
|
show_command: false,
|
|
save: task::SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let expected_scenario = DebugScenario {
|
|
adapter: "Debugpy".into(),
|
|
label: "run module 'main.py'".into(),
|
|
build: None,
|
|
config: json!({
|
|
"request": "launch",
|
|
"python": "$ZED_CUSTOM_PYTHON_ACTIVE_ZED_TOOLCHAIN",
|
|
"args": [],
|
|
"cwd": "$ZED_WORKTREE_ROOT",
|
|
"module": "$ZED_CUSTOM_PYTHON_MODULE_NAME",
|
|
}),
|
|
tcp_connection: None,
|
|
};
|
|
|
|
assert_eq!(
|
|
PythonLocator
|
|
.create_scenario(&build_task, "run module 'main.py'", &adapter)
|
|
.await
|
|
.expect("Failed to create a scenario"),
|
|
expected_scenario
|
|
);
|
|
}
|
|
}
|
|
|
|
mod memory {
|
|
use project::debugger::{
|
|
MemoryCell,
|
|
memory::{MemoryIterator, PageAddress, PageContents},
|
|
};
|
|
|
|
#[test]
|
|
fn iterate_over_unmapped_memory() {
|
|
let empty_iterator = MemoryIterator::new(0..=127, Default::default());
|
|
let actual = empty_iterator.collect::<Vec<_>>();
|
|
let expected = vec![MemoryCell(None); 128];
|
|
assert_eq!(actual.len(), expected.len());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn iterate_over_partially_mapped_memory() {
|
|
let it = MemoryIterator::new(
|
|
0..=127,
|
|
vec![(PageAddress(5), PageContents::mapped(vec![1]))].into_iter(),
|
|
);
|
|
let actual = it.collect::<Vec<_>>();
|
|
let expected = std::iter::repeat_n(MemoryCell(None), 5)
|
|
.chain(std::iter::once(MemoryCell(Some(1))))
|
|
.chain(std::iter::repeat_n(MemoryCell(None), 122))
|
|
.collect::<Vec<_>>();
|
|
assert_eq!(actual.len(), expected.len());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn reads_from_the_middle_of_a_page() {
|
|
let partial_iter = MemoryIterator::new(
|
|
20..=30,
|
|
vec![(PageAddress(0), PageContents::mapped((0..255).collect()))].into_iter(),
|
|
);
|
|
let actual = partial_iter.collect::<Vec<_>>();
|
|
let expected = (20..=30)
|
|
.map(|val| MemoryCell(Some(val)))
|
|
.collect::<Vec<_>>();
|
|
assert_eq!(actual.len(), expected.len());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
}
|