feat: rename NullTool to ShellTool and add install_script support#2691
feat: rename NullTool to ShellTool and add install_script support#2691
Conversation
Rename NullTool to ShellTool and add an install_script field to PluginDef so that plugins without a runtime, GitHub release, or download can run a shell script during tool setup. When install_script is set, ShellTool creates the tool directory and runs the script via `sh`. The script runs with cwd set to the tool install directory. When install_script is not set, the existing no-op behavior is preserved. Install script paths from source plugin.toml files are resolved to absolute paths during source parsing. Relative paths in inline qlty.toml definitions are resolved against the project root at install time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| pub tab_column_width: usize, | ||
|
|
||
| #[serde(default)] | ||
| pub install_script: Option<String>, |
There was a problem hiding this comment.
Since this is on PluginDef, I think it implies that any plugin (including non-ShellTool-based) can define an install_script -- which probably makes sense as a useful hook but we would need to define the semantics / ordering behavior.
To make sure we don't paint ourselves into a corner, we should probably map out all the hooks we intend to have and how they fit together
There was a problem hiding this comment.
Alternatively we could block install_script for any non-ShellTool on the basis that our regular installation is the one true install (e.g. npm install and force those plugins to use a before_install_script or after_install_script as hooks to be clear what order things run in). That may be less prone to plugin author errors.
|
|
||
| Plugin Result Targets Time Debug File | ||
| greeter Success 1 target [..]s .qlty/out/invoke-[..].yaml | ||
| greeter Success 1 target [..]s .qlty/out/invoke-[..].yaml |
There was a problem hiding this comment.
For the purposes of integration testing it would be nice if we can strength the tests...
Overall, we could use more visibility into the install process. This just shows data about what happens post-install during runtime. I think this is a pre-existing deficiency.
The debug files (invocation files) are the gold standard, so ideally we would write out a debug file for the install_script and be able to assert against it (or snapshot it)
| #!/bin/sh | ||
| echo '#!/bin/sh' > greet.sh | ||
| echo 'grep -q "hello" "$1" && exit 0 || exit 1' >> greet.sh | ||
| chmod +x greet.sh |
| config_version = "0" | ||
|
|
||
| [plugins.definitions.greeter] | ||
| file_types = ["shell"] |
There was a problem hiding this comment.
This works because shell will cause it to self-lint but is a bit obscure. Might warrant a comment.
|
|
||
| [[plugin]] | ||
| name = "greeter" | ||
| version = "1.0.0" |
There was a problem hiding this comment.
I think version is optional but we should confirm. Certainly it's not doing anything here.
| 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))?; |
There was a problem hiding this comment.
If this logic is lifted from elsewhere it would make want to think about extracting duplication to avoid subtle bugs later.
Summary
NullTooltoShellTooland addinstall_scriptfield toPluginDefinstall_scriptis set,ShellToolcreates the tool directory and runs the script viashduring tool setup; when unset, preserves existing no-op behaviorplugin.tomlfiles are resolved to absolute paths during source parsing; relative paths in inlineqlty.tomldefinitions are resolved against the project root at install timeTest plan
install_script) demonstrating a plugin that uses an install script to create a checker used by the drivercargo checkpasses🤖 Generated with Claude Code