Remove clippy too_many_lines lint and decompose long functions (#7064)

This commit is contained in:
Bradley Axen
2026-02-06 20:10:24 -08:00
committed by GitHub
parent 948cb91d54
commit b18120bec3
12 changed files with 256 additions and 412 deletions

View File

@@ -56,7 +56,7 @@
**Rust checks:**
- `cargo fmt --check` - Code formatting (rustfmt)
- `cargo test --jobs 2` - All tests
- `./scripts/clippy-lint.sh` - Linting (clippy)
- `cargo clippy --all-targets -- -D warnings` - Linting (clippy)
- `just check-openapi-schema` - OpenAPI schema validation
**Desktop app checks:**
@@ -76,7 +76,7 @@
Do not comment on:
- **Style/formatting** - CI handles this (rustfmt, prettier)
- **Clippy warnings** - CI handles this (clippy-lint.sh)
- **Clippy warnings** - CI handles this (clippy)
- **Test failures** - CI handles this (full test suite)
- **Missing dependencies** - CI handles this (npm ci will fail)
- **Minor naming suggestions** - unless truly confusing

View File

@@ -95,7 +95,10 @@ jobs:
# play nicely with hermit-managed rust
hermit uninstall rustup
export CARGO_INCREMENTAL=0
./scripts/clippy-lint.sh
cargo clippy --all-targets -- -D warnings
- name: Check for banned TLS crates
run: ./scripts/check-no-native-tls.sh
openapi-schema-check:
name: Check OpenAPI Schema is Up-to-Date

View File

@@ -95,7 +95,7 @@ env:
- [ ] cargo check
- [ ] cargo test (affected crates)
- [ ] cargo fmt
- [ ] ./scripts/clippy-lint.sh
- [ ] cargo clippy --all-targets -- -D warnings
- [ ] Fix failures, retry up to 3 times
## Phase 6: Confirm (MANDATORY)

View File

@@ -28,8 +28,7 @@ just record-mcp-tests # record MCP
### Lint/Format
```bash
cargo fmt
./scripts/clippy-lint.sh
cargo clippy --fix
cargo clippy --all-targets -- -D warnings
```
### UI
@@ -63,7 +62,7 @@ ui/desktop/ # Electron app
# 3. cargo fmt
# 4. cargo build
# 5. cargo test -p <crate>
# 6. ./scripts/clippy-lint.sh
# 6. cargo clippy --all-targets -- -D warnings
# 7. [if server] just generate-openapi
```
@@ -92,7 +91,7 @@ Logging: Clean up existing logs, don't add more unless for errors or security ev
Never: Edit ui/desktop/openapi.json manually
Never: Edit Cargo.toml use cargo add
Never: Skip cargo fmt
Never: Merge without ./scripts/clippy-lint.sh
Never: Merge without running clippy
Never: Comment self-evident operations (`// Initialize`, `// Return result`), getters/setters, constructors, or standard Rust idioms
## Entry Points

View File

@@ -103,7 +103,7 @@ When making changes to the Rust code, test them on the CLI or run checks, tests,
cargo check # verify changes compile
cargo test # run tests with changes
cargo fmt # format code
./scripts/clippy-lint.sh # run the linter
cargo clippy --all-targets -- -D warnings # run the linter
```
### Node

View File

@@ -142,7 +142,7 @@ If you're new to Rust, configure your AI tool to help you learn:
This is a Rust project using cargo workspaces.
- Follow existing error handling patterns using anyhow::Result
- Use async/await for I/O operations
- Follow the project's clippy lints (see clippy-baselines/)
- Follow the project's clippy lints (see clippy.toml)
- Run cargo fmt before committing
```
@@ -240,7 +240,7 @@ cargo build -p goose-mcp
cargo test -p goose-mcp
# Run clippy
./scripts/clippy-lint.sh
cargo clippy --all-targets -- -D warnings
```
### Example 2: Fixing a Rust Compiler Error
@@ -314,4 +314,4 @@ cargo build -p goose-cli -p goose
# Run tests
cargo test -p goose-cli
```
```

View File

@@ -10,7 +10,9 @@ check-everything:
@echo " → Formatting Rust code..."
cargo fmt --all
@echo " → Running clippy linting..."
./scripts/clippy-lint.sh
cargo clippy --all-targets -- -D warnings
@echo " → Checking for banned TLS crates..."
./scripts/check-no-native-tls.sh
@echo " → Checking UI code formatting..."
cd ui/desktop && npm run lint:check
@echo " → Validating OpenAPI schema..."

View File

@@ -1,26 +0,0 @@
crates/goose-cli/src/commands/configure.rs::configure_provider_dialog
crates/goose-cli/src/commands/configure.rs::configure_tool_permissions_dialog
crates/goose-cli/src/commands/project.rs::handle_project_default
crates/goose-cli/src/commands/project.rs::handle_projects_interactive
crates/goose-cli/src/session/builder.rs::build_session
crates/goose-cli/src/session/export.rs::tool_response_to_markdown
crates/goose-cli/src/session/mod.rs::process_agent_response
crates/goose-mcp/src/computercontroller/mod.rs::new
crates/goose-mcp/src/computercontroller/pdf_tool.rs::pdf_tool
crates/goose-mcp/src/memory/mod.rs::new
crates/goose-server/src/openapi.rs::convert_typed_schema
crates/goose-server/src/openapi.rs::convert_typed_schema
crates/goose/src/agents/agent.rs::create_recipe
crates/goose/src/agents/agent.rs::dispatch_tool_call
crates/goose/src/agents/agent.rs::reply
crates/goose/src/agents/agent.rs::reply_internal
crates/goose/src/providers/claude_code.rs::execute_command
crates/goose/src/providers/codex.rs::execute_command
crates/goose/src/providers/formats/anthropic.rs::format_messages
crates/goose/src/providers/formats/anthropic.rs::response_to_streaming_message
crates/goose/src/providers/formats/databricks.rs::format_messages
crates/goose/src/providers/formats/google.rs::format_messages
crates/goose/src/providers/formats/openai.rs::format_messages
crates/goose/src/providers/formats/openai.rs::response_to_streaming_message
crates/goose/src/providers/snowflake.rs::post
crates/goose/src/security/mod.rs::analyze_tool_requests

1
clippy.toml Normal file
View File

@@ -0,0 +1 @@
too-many-lines-threshold = 200

View File

@@ -337,36 +337,26 @@ async fn load_extensions(
agent_ptr
}
pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
goose::posthog::set_session_context("cli", session_config.resume);
struct ResolvedProviderConfig {
provider_name: String,
model_name: String,
model_config: goose::model::ModelConfig,
}
let config = Config::global();
let agent: Agent = Agent::new();
if session_config.container.is_some() {
agent.set_container(session_config.container.clone()).await;
}
let session_manager = agent.config.session_manager.clone();
let (saved_provider, saved_model_config) = if session_config.resume {
if let Some(ref session_id) = session_config.session_id {
match session_manager.get_session(session_id, false).await {
Ok(session_data) => (session_data.provider_name, session_data.model_config),
Err(_) => (None, None),
}
} else {
(None, None)
}
} else {
(None, None)
};
let recipe = session_config.recipe.as_ref();
let recipe_settings = recipe.and_then(|r| r.settings.as_ref());
fn resolve_provider_and_model(
session_config: &SessionBuilderConfig,
config: &Config,
saved_provider: Option<String>,
saved_model_config: Option<goose::model::ModelConfig>,
) -> ResolvedProviderConfig {
let recipe_settings = session_config
.recipe
.as_ref()
.and_then(|r| r.settings.as_ref());
let provider_name = session_config
.provider
.clone()
.or(saved_provider)
.or_else(|| recipe_settings.and_then(|s| s.goose_provider.clone()))
.or_else(|| config.get_goose_provider().ok())
@@ -374,6 +364,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
let model_name = session_config
.model
.clone()
.or_else(|| saved_model_config.as_ref().map(|mc| mc.model_name.clone()))
.or_else(|| recipe_settings.and_then(|s| s.goose_model.clone()))
.or_else(|| config.get_goose_model().ok())
@@ -399,6 +390,215 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
.with_temperature(temperature)
};
ResolvedProviderConfig {
provider_name,
model_name,
model_config,
}
}
async fn resolve_session_id(
session_config: &SessionBuilderConfig,
session_manager: &goose::session::session_manager::SessionManager,
) -> String {
if session_config.no_session {
let working_dir = std::env::current_dir().expect("Could not get working directory");
let session = session_manager
.create_session(working_dir, "CLI Session".to_string(), SessionType::Hidden)
.await
.expect("Could not create session");
session.id
} else if session_config.resume {
if let Some(ref session_id) = session_config.session_id {
match session_manager.get_session(session_id, false).await {
Ok(_) => session_id.clone(),
Err(_) => {
output::render_error(&format!(
"Cannot resume session {} - no such session exists",
style(session_id).cyan()
));
process::exit(1);
}
}
} else {
match session_manager.list_sessions().await {
Ok(sessions) if !sessions.is_empty() => sessions[0].id.clone(),
_ => {
output::render_error("Cannot resume - no previous sessions found");
process::exit(1);
}
}
}
} else {
session_config.session_id.clone().unwrap()
}
}
async fn handle_resumed_session_workdir(agent: &Agent, session_id: &str, interactive: bool) {
let session = agent
.config
.session_manager
.get_session(session_id, false)
.await
.unwrap_or_else(|e| {
output::render_error(&format!("Failed to read session metadata: {}", e));
process::exit(1);
});
let current_workdir = std::env::current_dir().expect("Failed to get current working directory");
if current_workdir == session.working_dir {
return;
}
if interactive {
let change_workdir = cliclack::confirm(format!(
"{} The original working directory of this session was set to {}. \
Your current directory is {}. \
Do you want to switch back to the original working directory?",
style("WARNING:").yellow(),
style(session.working_dir.display()).cyan(),
style(current_workdir.display()).cyan(),
))
.initial_value(true)
.interact()
.expect("Failed to get user input");
if change_workdir {
if !session.working_dir.exists() {
output::render_error(&format!(
"Cannot switch to original working directory - {} no longer exists",
style(session.working_dir.display()).cyan()
));
} else if let Err(e) = std::env::set_current_dir(&session.working_dir) {
output::render_error(&format!(
"Failed to switch to original working directory: {}",
e
));
}
}
} else {
eprintln!(
"{}",
style(format!(
"Warning: Working directory differs from session (current: {}, session: {}). \
Staying in current directory.",
current_workdir.display(),
session.working_dir.display()
))
.yellow()
);
}
}
async fn resolve_and_load_extensions(
agent: Agent,
session_config: &SessionBuilderConfig,
recipe: Option<&Recipe>,
session_id: &str,
provider_for_debug: Arc<dyn goose::providers::base::Provider>,
) -> Arc<Agent> {
for warning in goose::config::get_warnings() {
eprintln!("{}", style(format!("Warning: {}", warning)).yellow());
}
let configured_extensions: Vec<ExtensionConfig> = if session_config.resume {
agent
.config
.session_manager
.get_session(session_id, false)
.await
.ok()
.and_then(|s| EnabledExtensionsState::from_extension_data(&s.extension_data))
.map(|state| state.extensions)
.unwrap_or_else(get_enabled_extensions)
} else if session_config.no_profile {
Vec::new()
} else {
resolve_extensions_for_new_session(recipe.and_then(|r| r.extensions.as_deref()), None)
};
let cli_flag_extensions = parse_cli_flag_extensions(
&session_config.extensions,
&session_config.streamable_http_extensions,
&session_config.builtins,
);
let mut extensions_to_load: Vec<(String, ExtensionConfig)> = configured_extensions
.iter()
.map(|cfg| (cfg.name(), cfg.clone()))
.collect();
extensions_to_load.extend(cli_flag_extensions);
load_extensions(
agent,
extensions_to_load,
provider_for_debug,
session_config.interactive,
session_id,
)
.await
}
async fn configure_session_prompts(
session: &CliSession,
config: &Config,
session_config: &SessionBuilderConfig,
session_id: &str,
) {
if let Err(e) = session.agent.persist_extension_state(session_id).await {
tracing::warn!("Failed to save extension state: {}", e);
}
session
.agent
.extend_system_prompt(super::prompt::get_cli_prompt())
.await;
if let Some(ref additional_prompt) = session_config.additional_system_prompt {
session
.agent
.extend_system_prompt(additional_prompt.clone())
.await;
}
let system_prompt_file: Option<String> = config.get_param("GOOSE_SYSTEM_PROMPT_FILE_PATH").ok();
if let Some(ref path) = system_prompt_file {
let override_prompt =
std::fs::read_to_string(path).expect("Failed to read system prompt file");
session.agent.override_system_prompt(override_prompt).await;
}
}
pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
goose::posthog::set_session_context("cli", session_config.resume);
let config = Config::global();
let agent: Agent = Agent::new();
if session_config.container.is_some() {
agent.set_container(session_config.container.clone()).await;
}
let session_manager = agent.config.session_manager.clone();
let (saved_provider, saved_model_config) = if session_config.resume {
if let Some(ref session_id) = session_config.session_id {
match session_manager.get_session(session_id, false).await {
Ok(session_data) => (session_data.provider_name, session_data.model_config),
Err(_) => (None, None),
}
} else {
(None, None)
}
} else {
(None, None)
};
let resolved =
resolve_provider_and_model(&session_config, config, saved_provider, saved_model_config);
let recipe = session_config.recipe.as_ref();
agent
.apply_recipe_components(
recipe.and_then(|r| r.sub_recipes.clone()),
@@ -407,7 +607,7 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
)
.await;
let new_provider = match create(&provider_name, model_config).await {
let new_provider = match create(&resolved.provider_name, resolved.model_config).await {
Ok(provider) => provider,
Err(e) => {
output::render_error(&format!(
@@ -430,40 +630,10 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
worker_model
);
} else {
tracing::info!("🤖 Using model: {}", model_name);
tracing::info!("🤖 Using model: {}", resolved.model_name);
}
let session_id: String = if session_config.no_session {
let working_dir = std::env::current_dir().expect("Could not get working directory");
let session = session_manager
.create_session(working_dir, "CLI Session".to_string(), SessionType::Hidden)
.await
.expect("Could not create session");
session.id
} else if session_config.resume {
if let Some(session_id) = session_config.session_id {
match session_manager.get_session(&session_id, false).await {
Ok(_) => session_id,
Err(_) => {
output::render_error(&format!(
"Cannot resume session {} - no such session exists",
style(&session_id).cyan()
));
process::exit(1);
}
}
} else {
match session_manager.list_sessions().await {
Ok(sessions) if !sessions.is_empty() => sessions[0].id.clone(),
_ => {
output::render_error("Cannot resume - no previous sessions found");
process::exit(1);
}
}
}
} else {
session_config.session_id.unwrap()
};
let session_id = resolve_session_id(&session_config, &session_manager).await;
agent
.update_provider(new_provider, &session_id)
@@ -474,96 +644,19 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
});
if session_config.resume {
let session = agent
.config
.session_manager
.get_session(&session_id, false)
.await
.unwrap_or_else(|e| {
output::render_error(&format!("Failed to read session metadata: {}", e));
process::exit(1);
});
let current_workdir =
std::env::current_dir().expect("Failed to get current working directory");
if current_workdir != session.working_dir {
if session_config.interactive {
let change_workdir = cliclack::confirm(format!("{} The original working directory of this session was set to {}. Your current directory is {}. Do you want to switch back to the original working directory?", style("WARNING:").yellow(), style(session.working_dir.display()).cyan(), style(current_workdir.display()).cyan()))
.initial_value(true)
.interact().expect("Failed to get user input");
if change_workdir {
if !session.working_dir.exists() {
output::render_error(&format!(
"Cannot switch to original working directory - {} no longer exists",
style(session.working_dir.display()).cyan()
));
} else if let Err(e) = std::env::set_current_dir(&session.working_dir) {
output::render_error(&format!(
"Failed to switch to original working directory: {}",
e
));
}
}
} else {
eprintln!(
"{}",
style(format!(
"Warning: Working directory differs from session (current: {}, session: {}). Staying in current directory.",
current_workdir.display(),
session.working_dir.display()
))
.yellow()
);
}
}
handle_resumed_session_workdir(&agent, &session_id, session_config.interactive).await;
}
// Setup extensions for the agent
// Extensions need to be added after the session is created because we change directory when resuming a session
for warning in goose::config::get_warnings() {
eprintln!("{}", style(format!("Warning: {}", warning)).yellow());
}
let configured_extensions: Vec<ExtensionConfig> = if session_config.resume {
agent
.config
.session_manager
.get_session(&session_id, false)
.await
.ok()
.and_then(|s| EnabledExtensionsState::from_extension_data(&s.extension_data))
.map(|state| state.extensions)
.unwrap_or_else(get_enabled_extensions)
} else if session_config.no_profile {
Vec::new()
} else {
resolve_extensions_for_new_session(recipe.and_then(|r| r.extensions.as_deref()), None)
};
let cli_flag_extensions_to_load = parse_cli_flag_extensions(
&session_config.extensions,
&session_config.streamable_http_extensions,
&session_config.builtins,
);
let mut extensions_to_load: Vec<(String, ExtensionConfig)> = configured_extensions
.iter()
.map(|cfg| (cfg.name(), cfg.clone()))
.collect();
extensions_to_load.extend(cli_flag_extensions_to_load);
let agent_ptr = load_extensions(
// Extensions are loaded after session creation because we may change directory when resuming
let agent_ptr = resolve_and_load_extensions(
agent,
extensions_to_load,
Arc::clone(&provider_for_display),
session_config.interactive,
&session_config,
recipe,
&session_id,
Arc::clone(&provider_for_display),
)
.await;
// Determine editor mode
let edit_mode = config
.get_param::<String>("EDIT_MODE")
.ok()
@@ -590,38 +683,13 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
)
.await;
if let Err(e) = session
.agent
.persist_extension_state(&session_id.clone())
.await
{
tracing::warn!("Failed to save extension state: {}", e);
}
configure_session_prompts(&session, config, &session_config, &session_id).await;
// Add CLI-specific system prompt extension
session
.agent
.extend_system_prompt(super::prompt::get_cli_prompt())
.await;
if let Some(additional_prompt) = session_config.additional_system_prompt {
session.agent.extend_system_prompt(additional_prompt).await;
}
// Only override system prompt if a system override exists
let system_prompt_file: Option<String> = config.get_param("GOOSE_SYSTEM_PROMPT_FILE_PATH").ok();
if let Some(ref path) = system_prompt_file {
let override_prompt =
std::fs::read_to_string(path).expect("Failed to read system prompt file");
session.agent.override_system_prompt(override_prompt).await;
}
// Display session information unless in quiet mode
if !session_config.quiet {
output::display_session_info(
session_config.resume,
&provider_name,
&model_name,
&resolved.provider_name,
&resolved.model_name,
&Some(session_id),
Some(&provider_for_display),
);

View File

@@ -1,161 +0,0 @@
#!/bin/bash
# Baseline clippy rules - only fail on NEW violations
#
# Format: "rule_name|violation_parser"
#
# Violation parsers (run clippy on your rule to see which fits):
# function_name - When spans show: "fn my_function(..."
# type_name - When spans show: "struct MyStruct" or "enum MyEnum"
# file_only - When spans show file-level issues
#
# Note: If your rule doesn't fit these parsers, you may need to add a new parser
# to the parse_violation() function below
#
# To add new rules:
# 1. Add rule below: "clippy::your_rule|violation_parser"
# 2. Generate baseline: ./scripts/clippy-baseline.sh generate clippy::your_rule
BASELINE_RULES=(
"clippy::too_many_lines|function_name"
)
parse_violation() {
local rule_code="$1"
local violation_parser="$2"
case "$violation_parser" in
"function_name")
jq -r 'select(.message.code.code == "'"$rule_code"'") |
.message.spans[0] as $span |
($span.text | map(.text) | map(select(test("\\bfn\\b"))) | first // "") as $line |
if $line == "" then empty else "\($span.file_name)::\($line | capture("fn\\s+(?<name>[a-z_][a-z0-9_]*)") | .name)" end'
;;
"type_name")
jq -r 'select(.message.code.code == "'"$rule_code"'") |
"\(.message.spans[0].file_name)::\(.message.spans[0].text[0].text | split(" ")[1] | split(" ")[0])"'
;;
"file_only")
jq -r 'select(.message.code.code == "'"$rule_code"'") |
"\(.message.spans[0].file_name)"'
;;
*)
echo "Unknown violation parser: $violation_parser" >&2
exit 1
;;
esac
}
get_baseline_file() {
local rule_name="$1"
local safe_name=$(echo "$rule_name" | sed 's/clippy:://' | sed 's/:/-/g')
echo "clippy-baselines/${safe_name}.txt"
}
generate_baseline() {
local rule_name="$1"
[[ -z "$rule_name" ]] && { echo "Missing rule name"; return 1; }
local violation_parser=""
for rule in "${BASELINE_RULES[@]}"; do
[[ "${rule%|*}" == "$rule_name" ]] && { violation_parser="${rule#*|}"; break; }
done
[[ -z "$violation_parser" ]] && { echo "Unknown rule: $rule_name"; return 1; }
local baseline_file=$(get_baseline_file "$rule_name")
cargo clippy --jobs 2 --message-format=json -- -W "$rule_name" | \
parse_violation "$rule_name" "$violation_parser" | \
sort > "$baseline_file"
echo "✅ Generated baseline for $rule_name ($(wc -l < "$baseline_file") violations)"
}
# Check a single rule from pre-generated JSON (optimized version)
check_rule_from_json() {
local temp_json="$1"
local rule_name="$2"
local violation_parser="$3"
local baseline_file="$4"
echo " → Checking $rule_name"
if [[ ! -f "$baseline_file" ]]; then
echo "$rule_name: baseline file not found"
return 1
fi
local temp_parsed=$(mktemp)
cat "$temp_json" | parse_violation "$rule_name" "$violation_parser" | sort > "$temp_parsed"
local new_violations_file=$(mktemp)
diff <(sort "$baseline_file") <(sort "$temp_parsed") | grep "^>" | cut -c3- > "$new_violations_file"
if [[ -s "$new_violations_file" ]]; then
echo "$rule_name: NEW violations found:"
while IFS= read -r violation; do
# Extract all violations for this rule and find the matching one
cat "$temp_json" | jq -c 'select(.message.code.code == "'"$rule_name"'")' 2>/dev/null | while read -r json_line; do
parsed_id=$(echo "$json_line" | parse_violation "$rule_name" "$violation_parser")
if [[ "$parsed_id" == "$violation" ]]; then
echo "$json_line" | jq -r '.message.rendered' | sed 's/^/ /'
fi
done
done < "$new_violations_file"
rm "$temp_parsed" "$new_violations_file"
return 1
fi
rm "$new_violations_file"
echo "$rule_name: ok"
rm "$temp_parsed"
return 0
}
check_all_baseline_rules() {
echo "🔍 Checking baseline clippy rules..."
local clippy_flags=""
for rule in "${BASELINE_RULES[@]}"; do
local rule_name="${rule%|*}"
clippy_flags="$clippy_flags -W $rule_name"
done
local temp_json=$(mktemp)
cargo clippy --jobs 2 --message-format=json -- $clippy_flags | tee "$temp_json"
local failed_rules=()
# Check each rule against its baseline
for rule in "${BASELINE_RULES[@]}"; do
local rule_name="${rule%|*}"
local violation_parser="${rule#*|}"
local baseline_file=$(get_baseline_file "$rule_name")
if ! check_rule_from_json "$temp_json" "$rule_name" "$violation_parser" "$baseline_file"; then
failed_rules+=("$rule_name")
fi
done
rm "$temp_json"
if [[ ${#failed_rules[@]} -gt 0 ]]; then
echo ""
echo "❌ Failed baseline checks for: ${failed_rules[*]}"
exit 1
else
echo ""
echo "✅ All baseline clippy checks passed!"
fi
}
if [[ "$1" == "generate" ]]; then
generate_baseline "$2"
fi

View File

@@ -1,42 +0,0 @@
#!/bin/bash
# Combined lint script
# Runs standard clippy (strict) + baseline clippy rules
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Source the baseline functions
source "$SCRIPT_DIR/clippy-baseline.sh"
echo "🔍 Running all clippy checks..."
FIX_MODE=0
[[ "$1" == "--fix" ]] && FIX_MODE=1
run_clippy() {
if [[ "$FIX_MODE" -eq 1 ]]; then
cargo fmt
cargo clippy --all-targets --jobs 2 \
--fix --allow-dirty --allow-staged \
-- -D warnings
else
cargo clippy --all-targets --jobs 2 -- -D warnings
fi
}
if [[ "$FIX_MODE" -eq 1 ]]; then
echo "🛠 Applying fixes..."
else
echo "🔍 Running clippy..."
fi
run_clippy
echo ""
check_all_baseline_rules
echo ""
echo "🔒 Checking for banned TLS crates..."
"$SCRIPT_DIR/check-no-native-tls.sh"
echo ""
echo "✅ Done"