Skip to content

Commit c6652ec

Browse files
Alex Holmbergclaude
authored andcommitted
style: format dclint tool files
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7835625 commit c6652ec

2 files changed

Lines changed: 120 additions & 55 deletions

File tree

src/agent/tools/dclint.rs

Lines changed: 119 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
1515
use serde_json::json;
1616
use std::path::PathBuf;
1717

18-
use crate::analyzer::dclint::{lint, lint_file, DclintConfig, LintResult, Severity, RuleCategory};
18+
use crate::analyzer::dclint::{DclintConfig, LintResult, RuleCategory, Severity, lint, lint_file};
1919

2020
/// Arguments for the dclint tool
2121
#[derive(Debug, Deserialize)]
@@ -83,21 +83,43 @@ impl DclintTool {
8383
/// Get actionable fix recommendation for a rule
8484
fn get_fix_recommendation(code: &str) -> &'static str {
8585
match code {
86-
"DCL001" => "Remove either the 'build' or 'image' field, or add 'pull_policy' if both are intentional.",
87-
"DCL002" => "Use unique container names for each service, or remove explicit container_name to use auto-generated names.",
88-
"DCL003" => "Use different host ports for each service, or bind to different interfaces (e.g., 127.0.0.1:8080:80).",
86+
"DCL001" => {
87+
"Remove either the 'build' or 'image' field, or add 'pull_policy' if both are intentional."
88+
}
89+
"DCL002" => {
90+
"Use unique container names for each service, or remove explicit container_name to use auto-generated names."
91+
}
92+
"DCL003" => {
93+
"Use different host ports for each service, or bind to different interfaces (e.g., 127.0.0.1:8080:80)."
94+
}
8995
"DCL004" => "Remove quotes from volume paths. YAML doesn't require quotes for paths.",
90-
"DCL005" => "Add explicit interface binding, e.g., '127.0.0.1:8080:80' instead of '8080:80' for local-only access.",
91-
"DCL006" => "Remove the 'version' field. Docker Compose now infers the version automatically.",
96+
"DCL005" => {
97+
"Add explicit interface binding, e.g., '127.0.0.1:8080:80' instead of '8080:80' for local-only access."
98+
}
99+
"DCL006" => {
100+
"Remove the 'version' field. Docker Compose now infers the version automatically."
101+
}
92102
"DCL007" => "Add 'name: myproject' at the top level for explicit project naming.",
93-
"DCL008" => "Quote port mappings to prevent YAML parsing issues, e.g., \"8080:80\" instead of 8080:80.",
94-
"DCL009" => "Use lowercase container names with only letters, numbers, hyphens, and underscores.",
95-
"DCL010" => "Sort dependencies alphabetically for better readability and easier merges.",
96-
"DCL011" => "Use explicit version tags (e.g., nginx:1.25) instead of implicit latest or untagged images.",
97-
"DCL012" => "Reorder service keys to follow convention: image, build, container_name, ports, volumes, environment, etc.",
103+
"DCL008" => {
104+
"Quote port mappings to prevent YAML parsing issues, e.g., \"8080:80\" instead of 8080:80."
105+
}
106+
"DCL009" => {
107+
"Use lowercase container names with only letters, numbers, hyphens, and underscores."
108+
}
109+
"DCL010" => {
110+
"Sort dependencies alphabetically for better readability and easier merges."
111+
}
112+
"DCL011" => {
113+
"Use explicit version tags (e.g., nginx:1.25) instead of implicit latest or untagged images."
114+
}
115+
"DCL012" => {
116+
"Reorder service keys to follow convention: image, build, container_name, ports, volumes, environment, etc."
117+
}
98118
"DCL013" => "Sort port mappings alphabetically/numerically for consistency.",
99119
"DCL014" => "Sort services alphabetically for better navigation and easier merges.",
100-
"DCL015" => "Reorder top-level keys: name, services, networks, volumes, configs, secrets.",
120+
"DCL015" => {
121+
"Reorder top-level keys: name, services, networks, volumes, configs, secrets."
122+
}
101123
_ => "Review the rule documentation for specific guidance.",
102124
}
103125
}
@@ -123,7 +145,10 @@ impl DclintTool {
123145
"DCL015" => "top-level-properties-order-rule",
124146
_ => return String::new(),
125147
};
126-
format!("https://github.com/zavoloklom/docker-compose-linter/blob/main/docs/rules/{}.md", rule_name)
148+
format!(
149+
"https://github.com/zavoloklom/docker-compose-linter/blob/main/docs/rules/{}.md",
150+
rule_name
151+
)
127152
} else {
128153
String::new()
129154
}
@@ -132,41 +157,54 @@ impl DclintTool {
132157
/// Format result optimized for agent decision-making
133158
fn format_result(result: &LintResult, filename: &str) -> String {
134159
// Categorize and enrich failures
135-
let enriched_failures: Vec<serde_json::Value> = result.failures.iter().map(|f| {
136-
let code = f.code.as_str();
137-
let priority = Self::get_priority(f.severity, f.category);
138-
139-
json!({
140-
"code": code,
141-
"ruleName": f.rule_name,
142-
"severity": f.severity.as_str(),
143-
"priority": priority,
144-
"category": f.category.as_str(),
145-
"message": f.message,
146-
"line": f.line,
147-
"column": f.column,
148-
"fixable": f.fixable,
149-
"fix": Self::get_fix_recommendation(code),
150-
"docs": Self::get_rule_url(code),
160+
let enriched_failures: Vec<serde_json::Value> = result
161+
.failures
162+
.iter()
163+
.map(|f| {
164+
let code = f.code.as_str();
165+
let priority = Self::get_priority(f.severity, f.category);
166+
167+
json!({
168+
"code": code,
169+
"ruleName": f.rule_name,
170+
"severity": f.severity.as_str(),
171+
"priority": priority,
172+
"category": f.category.as_str(),
173+
"message": f.message,
174+
"line": f.line,
175+
"column": f.column,
176+
"fixable": f.fixable,
177+
"fix": Self::get_fix_recommendation(code),
178+
"docs": Self::get_rule_url(code),
179+
})
151180
})
152-
}).collect();
181+
.collect();
153182

154183
// Group by priority for agent decision ordering
155-
let critical: Vec<_> = enriched_failures.iter()
184+
let critical: Vec<_> = enriched_failures
185+
.iter()
156186
.filter(|f| f["priority"] == "critical")
157-
.cloned().collect();
158-
let high: Vec<_> = enriched_failures.iter()
187+
.cloned()
188+
.collect();
189+
let high: Vec<_> = enriched_failures
190+
.iter()
159191
.filter(|f| f["priority"] == "high")
160-
.cloned().collect();
161-
let medium: Vec<_> = enriched_failures.iter()
192+
.cloned()
193+
.collect();
194+
let medium: Vec<_> = enriched_failures
195+
.iter()
162196
.filter(|f| f["priority"] == "medium")
163-
.cloned().collect();
164-
let low: Vec<_> = enriched_failures.iter()
197+
.cloned()
198+
.collect();
199+
let low: Vec<_> = enriched_failures
200+
.iter()
165201
.filter(|f| f["priority"] == "low")
166-
.cloned().collect();
202+
.cloned()
203+
.collect();
167204

168205
// Group by category for thematic fixes
169-
let mut by_category: std::collections::HashMap<&str, Vec<_>> = std::collections::HashMap::new();
206+
let mut by_category: std::collections::HashMap<&str, Vec<_>> =
207+
std::collections::HashMap::new();
170208
for f in &enriched_failures {
171209
let cat = f["category"].as_str().unwrap_or("other");
172210
by_category.entry(cat).or_default().push(f.clone());
@@ -188,7 +226,10 @@ impl DclintTool {
188226
};
189227

190228
// Count fixable issues
191-
let fixable_count = enriched_failures.iter().filter(|f| f["fixable"] == true).count();
229+
let fixable_count = enriched_failures
230+
.iter()
231+
.filter(|f| f["fixable"] == true)
232+
.count();
192233

193234
// Build agent-optimized output
194235
let mut output = json!({
@@ -222,14 +263,18 @@ impl DclintTool {
222263

223264
// Add quick fixes summary for agent
224265
if !enriched_failures.is_empty() {
225-
let quick_fixes: Vec<String> = enriched_failures.iter()
266+
let quick_fixes: Vec<String> = enriched_failures
267+
.iter()
226268
.filter(|f| f["priority"] == "critical" || f["priority"] == "high")
227269
.take(5)
228-
.map(|f| format!("Line {}: {} - {}",
229-
f["line"],
230-
f["code"].as_str().unwrap_or(""),
231-
f["fix"].as_str().unwrap_or("")
232-
))
270+
.map(|f| {
271+
format!(
272+
"Line {}: {} - {}",
273+
f["line"],
274+
f["code"].as_str().unwrap_or(""),
275+
f["fix"].as_str().unwrap_or("")
276+
)
277+
})
233278
.collect();
234279

235280
if !quick_fixes.is_empty() {
@@ -364,12 +409,15 @@ mod tests {
364409
let tool = DclintTool::new(temp_dir());
365410
let args = DclintArgs {
366411
compose_file: None,
367-
content: Some(r#"
412+
content: Some(
413+
r#"
368414
services:
369415
web:
370416
build: .
371417
image: nginx:latest
372-
"#.to_string()),
418+
"#
419+
.to_string(),
420+
),
373421
ignore: vec![],
374422
threshold: None,
375423
fix: false,
@@ -392,12 +440,15 @@ services:
392440
let tool = DclintTool::new(temp_dir());
393441
let args = DclintArgs {
394442
compose_file: None,
395-
content: Some(r#"
443+
content: Some(
444+
r#"
396445
version: "3.8"
397446
services:
398447
web:
399448
image: nginx:latest
400-
"#.to_string()),
449+
"#
450+
.to_string(),
451+
),
401452
ignore: vec!["DCL006".to_string(), "DCL011".to_string()],
402453
threshold: None,
403454
fix: false,
@@ -424,14 +475,18 @@ services:
424475
let temp = temp_dir().join("dclint_test");
425476
fs::create_dir_all(&temp).unwrap();
426477
let compose_file = temp.join("docker-compose.yml");
427-
fs::write(&compose_file, r#"
478+
fs::write(
479+
&compose_file,
480+
r#"
428481
name: myproject
429482
services:
430483
web:
431484
image: nginx:1.25
432485
ports:
433486
- "8080:80"
434-
"#).unwrap();
487+
"#,
488+
)
489+
.unwrap();
435490

436491
let tool = DclintTool::new(temp.clone());
437492
let args = DclintArgs {
@@ -481,7 +536,17 @@ services:
481536
assert!(parsed["success"].as_bool().unwrap_or(false));
482537
assert!(parsed["decision_context"].is_string());
483538
// Should not have critical or high priority issues
484-
assert_eq!(parsed["summary"]["by_priority"]["critical"].as_u64().unwrap_or(99), 0);
485-
assert_eq!(parsed["summary"]["by_priority"]["high"].as_u64().unwrap_or(99), 0);
539+
assert_eq!(
540+
parsed["summary"]["by_priority"]["critical"]
541+
.as_u64()
542+
.unwrap_or(99),
543+
0
544+
);
545+
assert_eq!(
546+
parsed["summary"]["by_priority"]["high"]
547+
.as_u64()
548+
.unwrap_or(99),
549+
0
550+
);
486551
}
487552
}

src/agent/tools/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ mod truncation;
5252
pub use truncation::TruncationLimits;
5353

5454
pub use analyze::AnalyzeTool;
55+
pub use dclint::DclintTool;
5556
pub use diagnostics::DiagnosticsTool;
5657
pub use file_ops::{ListDirectoryTool, ReadFileTool, WriteFileTool, WriteFilesTool};
57-
pub use dclint::DclintTool;
5858
pub use hadolint::HadolintTool;
5959
pub use plan::{PlanCreateTool, PlanListTool, PlanNextTool, PlanUpdateTool};
6060
pub use security::{SecurityScanTool, VulnerabilitiesTool};

0 commit comments

Comments
 (0)