Skip to content
Draft
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
10 changes: 5 additions & 5 deletions qlty-check/src/planner/invocation_directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl InvocationDirectoryPlanner {
#[cfg(test)]
mod test {
use super::*;
use crate::{planner::target::Target, tool::null_tool::NullTool};
use crate::{planner::target::Target, tool::shell_tool::ShellTool};
use qlty_analysis::{utils::fs::path_to_string, WorkspaceEntryKind};
use qlty_config::config::InvocationDirectoryDef;
use qlty_test_utilities::git::sample_repo;
Expand Down Expand Up @@ -144,13 +144,13 @@ mod test {
config_files: vec!["config_file.json".into()],
..Default::default()
},
tool: Box::new(NullTool {
tool: Box::new(ShellTool {
parent_directory: temp_dir
.to_path_buf()
.join(".qlty")
.join("cache")
.join("tools")
.join("null_tool"),
.join("shell_tool"),
plugin_name: "mock_plugin".to_string(),
plugin: Default::default(),
}),
Expand Down Expand Up @@ -304,13 +304,13 @@ mod test {
config_files: vec!["config_file.json".into()],
..Default::default()
},
tool: Box::new(NullTool {
tool: Box::new(ShellTool {
parent_directory: temp_dir_path
.to_path_buf()
.join(".qlty")
.join("cache")
.join("tools")
.join("null_tool"),
.join("shell_tool"),
plugin_name: "mock_plugin".to_string(),
plugin: Default::default(),
}),
Expand Down
6 changes: 3 additions & 3 deletions qlty-check/src/planner/target_batcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ fn normalize_config_path(
#[cfg(test)]
mod test {
use super::*;
use crate::tool::null_tool::NullTool;
use crate::tool::shell_tool::ShellTool;
use qlty_analysis::WorkspaceEntryKind;
use qlty_config::config::{InvocationDirectoryDef, InvocationDirectoryType, PluginDef};
use qlty_test_utilities::git::sample_repo;
Expand Down Expand Up @@ -288,7 +288,7 @@ mod test {
config_files: vec!["config1".into(), "config2".into()],
..Default::default()
},
tool: Box::new(NullTool {
tool: Box::new(ShellTool {
plugin_name: "mock_plugin".to_string(),
plugin: Default::default(),
..Default::default()
Expand Down Expand Up @@ -520,7 +520,7 @@ mod test {
config_files: vec!["config_file.json".into()],
..Default::default()
},
tool: Box::new(NullTool {
tool: Box::new(ShellTool {
plugin_name: "mock_plugin".to_string(),
plugin: Default::default(),
..Default::default()
Expand Down
4 changes: 2 additions & 2 deletions qlty-check/src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ pub mod go;
mod installations;
pub mod java;
pub mod node;
pub mod null_tool;
pub mod php;
pub mod python;
pub mod ruby;
mod ruby_source;
mod runnable_archive;
pub mod rust;
pub mod shell_tool;
pub mod tool_builder;

use crate::tool::download::Download;
Expand Down Expand Up @@ -120,7 +120,7 @@ pub enum ToolType {
Download,
RuntimePackage,
GitHubRelease,
NullTool,
ShellTool,
}

pub trait Tool: Debug + Sync + Send {
Expand Down
70 changes: 0 additions & 70 deletions qlty-check/src/tool/null_tool.rs

This file was deleted.

178 changes: 178 additions & 0 deletions qlty-check/src/tool/shell_tool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
use std::path::PathBuf;

use super::{global_tools_root, ToolType};
use crate::{ui::ProgressTask, Tool};
use anyhow::Result;
use qlty_analysis::utils::fs::path_to_string;
use qlty_config::config::PluginDef;

#[derive(Debug, Clone)]
pub struct ShellTool {
pub parent_directory: PathBuf,
pub plugin_name: String,
pub plugin: PluginDef,
}

impl Default for ShellTool {
fn default() -> Self {
Self {
parent_directory: PathBuf::from(global_tools_root()),
plugin_name: "ShellTool".to_string(),
plugin: Default::default(),
}
}
}

impl Tool for ShellTool {
fn parent_directory(&self) -> String {
path_to_string(self.parent_directory.join(self.name()))
}

fn plugin(&self) -> Option<PluginDef> {
Some(self.plugin.clone())
}

fn name(&self) -> String {
self.plugin_name.clone()
}

fn tool_type(&self) -> ToolType {
ToolType::ShellTool
}

fn version(&self) -> Option<String> {
self.plugin.version.clone()
}

fn version_command(&self) -> Option<String> {
self.plugin.version_command.clone()
}

fn version_regex(&self) -> String {
self.plugin.version_regex.clone()
}

fn package_install(&self, _: &ProgressTask, _: &str, _: &str) -> Result<()> {
Ok(())
}

fn clone_box(&self) -> Box<dyn Tool> {
Box::new(self.clone())
}

fn install_and_validate(&self, task: &ProgressTask) -> Result<()> {
if self.plugin.install_script.is_some() {
self.internal_pre_install(task)?;
self.install(task)?;
}
Ok(())
}

fn install(&self, _task: &ProgressTask) -> Result<()> {
if let Some(ref script_path) = self.plugin.install_script {
let script_path =
std::fs::canonicalize(script_path).unwrap_or_else(|_| PathBuf::from(script_path));
self.run_command(duct::cmd!("sh", script_path))?;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this logic is lifted from elsewhere it would make want to think about extracting duplication to avoid subtle bugs later.

}
Ok(())
}

fn is_installed(&self) -> bool {
if self.plugin.install_script.is_some() {
self.donefile_path().exists() && self.exists()
} else {
true
}
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::Progress;
use std::path::PathBuf;
use tempfile::tempdir;

#[test]
fn test_setup_runs_install_script() {
let temp_dir = tempdir().unwrap();
let script_path = temp_dir.path().join("install.sh");
std::fs::write(&script_path, "touch marker.txt").unwrap();

let tool = ShellTool {
parent_directory: temp_dir.path().join("tools"),
plugin_name: "test_plugin".to_string(),
plugin: PluginDef {
version: Some("1.0.0".to_string()),
install_script: Some(script_path.to_string_lossy().to_string()),
..Default::default()
},
};

let task = Progress::new(false, 1).task("TEST", "installing");
tool.setup(&task).unwrap();

assert!(tool.is_installed());
assert!(PathBuf::from(tool.directory()).join("marker.txt").exists());
}

#[test]
fn test_setup_without_install_script_is_noop() {
let tool = ShellTool {
plugin_name: "noop_plugin".to_string(),
plugin: PluginDef {
version: Some("1.0.0".to_string()),
..Default::default()
},
..Default::default()
};

assert!(tool.is_installed());
}

#[test]
fn test_setup_failing_install_script() {
let temp_dir = tempdir().unwrap();
let script_path = temp_dir.path().join("bad_install.sh");
std::fs::write(&script_path, "exit 1").unwrap();

let tool = ShellTool {
parent_directory: temp_dir.path().join("tools"),
plugin_name: "failing_plugin".to_string(),
plugin: PluginDef {
version: Some("1.0.0".to_string()),
install_script: Some(script_path.to_string_lossy().to_string()),
..Default::default()
},
};

let task = Progress::new(false, 1).task("TEST", "installing");
let result = tool.setup(&task);

assert!(result.is_err());
assert!(!tool.is_installed());
}

#[test]
fn test_setup_is_idempotent() {
let temp_dir = tempdir().unwrap();
let script_path = temp_dir.path().join("install.sh");
std::fs::write(&script_path, "touch marker.txt").unwrap();

let tool = ShellTool {
parent_directory: temp_dir.path().join("tools"),
plugin_name: "test_plugin".to_string(),
plugin: PluginDef {
version: Some("1.0.0".to_string()),
install_script: Some(script_path.to_string_lossy().to_string()),
..Default::default()
},
};

let task = Progress::new(false, 1).task("TEST", "installing");
tool.setup(&task).unwrap();
tool.setup(&task).unwrap();

assert!(tool.is_installed());
}
}
8 changes: 4 additions & 4 deletions qlty-check/src/tool/tool_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use crate::Tool;
use super::{
download::{Download, DownloadTool},
github::{GitHubRelease, GitHubReleaseTool},
go, java, node,
null_tool::NullTool,
php, python, ruby, rust, RuntimeTool,
go, java, node, php, python, ruby, rust,
shell_tool::ShellTool,
RuntimeTool,
};

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -135,7 +135,7 @@ impl ToolBuilder<'_> {
} else if let Some(download_name) = self.plugin.downloads.first() {
self.build_download_tool(download_name, &plugin_version)
} else {
Ok(Box::new(NullTool {
Ok(Box::new(ShellTool {
plugin_name: self.plugin_name.to_string(),
plugin: self.plugin.clone(),
..Default::default()
Expand Down
4 changes: 4 additions & 0 deletions qlty-cli/tests/cmd/check/install_script.in/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.qlty/results
.qlty/logs
.qlty/out
.qlty/sources
14 changes: 14 additions & 0 deletions qlty-cli/tests/cmd/check/install_script.in/.qlty/qlty.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
config_version = "0"

[plugins.definitions.greeter]
file_types = ["shell"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works because shell will cause it to self-lint but is a bit obscure. Might warrant a comment.

install_script = "install.sh"

[plugins.definitions.greeter.drivers.lint]
script = "sh ${linter}/greet.sh ${target}"
success_codes = [0]
output = "pass_fail"

[[plugin]]
name = "greeter"
version = "1.0.0"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think version is optional but we should confirm. Certainly it's not doing anything here.

4 changes: 4 additions & 0 deletions qlty-cli/tests/cmd/check/install_script.in/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/sh
echo '#!/bin/sh' > greet.sh
echo 'grep -q "hello" "$1" && exit 0 || exit 1' >> greet.sh
chmod +x greet.sh
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

2 changes: 2 additions & 0 deletions qlty-cli/tests/cmd/check/install_script.in/sample.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
echo "hello world"
3 changes: 3 additions & 0 deletions qlty-cli/tests/cmd/check/install_script.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[0/1] [..]Planning... [..]s
[1/1] [..]Analyzing all targets...
✔ No issues
Loading
Loading