Skip to main content

null_e/plugins/
dotnet.rs

1//! .NET plugin
2
3use crate::core::{Artifact, ArtifactKind, ArtifactMetadata, MarkerKind, ProjectKind, ProjectMarker};
4use crate::error::Result;
5use crate::plugins::Plugin;
6use std::path::Path;
7
8/// Plugin for .NET projects
9pub struct DotNetPlugin;
10
11impl Plugin for DotNetPlugin {
12    fn id(&self) -> &'static str {
13        "dotnet"
14    }
15
16    fn name(&self) -> &'static str {
17        ".NET"
18    }
19
20    fn supported_kinds(&self) -> &[ProjectKind] {
21        &[ProjectKind::DotNet, ProjectKind::FSharp]
22    }
23
24    fn markers(&self) -> Vec<ProjectMarker> {
25        vec![
26            ProjectMarker {
27                indicator: MarkerKind::AnyOf(vec!["*.csproj", "*.fsproj", "*.vbproj"]),
28                kind: ProjectKind::DotNet,
29                priority: 55,
30            },
31            ProjectMarker {
32                indicator: MarkerKind::File("*.sln"),
33                kind: ProjectKind::DotNet,
34                priority: 50,
35            },
36        ]
37    }
38
39    fn detect(&self, path: &Path) -> Option<ProjectKind> {
40        // Check for project files
41        if let Ok(entries) = std::fs::read_dir(path) {
42            for entry in entries.filter_map(|e| e.ok()) {
43                if let Some(name) = entry.file_name().to_str() {
44                    if name.ends_with(".csproj")
45                        || name.ends_with(".vbproj")
46                        || name.ends_with(".sln")
47                    {
48                        return Some(ProjectKind::DotNet);
49                    }
50                    if name.ends_with(".fsproj") {
51                        return Some(ProjectKind::FSharp);
52                    }
53                }
54            }
55        }
56        None
57    }
58
59    fn find_artifacts(&self, project_root: &Path) -> Result<Vec<Artifact>> {
60        let mut artifacts = Vec::new();
61
62        // bin directory
63        let bin = project_root.join("bin");
64        if bin.exists() {
65            artifacts.push(Artifact {
66                path: bin,
67                kind: ArtifactKind::BuildOutput,
68                size: 0,
69                file_count: 0,
70                age: None,
71                metadata: ArtifactMetadata::restorable("dotnet build"),
72            });
73        }
74
75        // obj directory
76        let obj = project_root.join("obj");
77        if obj.exists() {
78            artifacts.push(Artifact {
79                path: obj,
80                kind: ArtifactKind::BuildOutput,
81                size: 0,
82                file_count: 0,
83                age: None,
84                metadata: ArtifactMetadata::restorable("dotnet build"),
85            });
86        }
87
88        // packages directory (older NuGet style)
89        let packages = project_root.join("packages");
90        if packages.exists() {
91            artifacts.push(Artifact {
92                path: packages,
93                kind: ArtifactKind::Dependencies,
94                size: 0,
95                file_count: 0,
96                age: None,
97                metadata: ArtifactMetadata::restorable("dotnet restore"),
98            });
99        }
100
101        // TestResults
102        let test_results = project_root.join("TestResults");
103        if test_results.exists() {
104            artifacts.push(Artifact {
105                path: test_results,
106                kind: ArtifactKind::TestOutput,
107                size: 0,
108                file_count: 0,
109                age: None,
110                metadata: ArtifactMetadata::restorable("dotnet test"),
111            });
112        }
113
114        Ok(artifacts)
115    }
116
117    fn cleanable_dirs(&self) -> &[&'static str] {
118        &["bin", "obj", "packages", "TestResults"]
119    }
120
121    fn priority(&self) -> u8 {
122        55
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129    use tempfile::TempDir;
130
131    #[test]
132    fn test_detect_dotnet() {
133        let temp = TempDir::new().unwrap();
134        std::fs::write(temp.path().join("MyApp.csproj"), "<Project></Project>").unwrap();
135
136        let plugin = DotNetPlugin;
137        assert_eq!(plugin.detect(temp.path()), Some(ProjectKind::DotNet));
138    }
139
140    #[test]
141    fn test_detect_fsharp() {
142        let temp = TempDir::new().unwrap();
143        std::fs::write(temp.path().join("MyApp.fsproj"), "<Project></Project>").unwrap();
144
145        let plugin = DotNetPlugin;
146        assert_eq!(plugin.detect(temp.path()), Some(ProjectKind::FSharp));
147    }
148
149    #[test]
150    fn test_find_artifacts() {
151        let temp = TempDir::new().unwrap();
152        std::fs::write(temp.path().join("App.csproj"), "").unwrap();
153        std::fs::create_dir(temp.path().join("bin")).unwrap();
154        std::fs::create_dir(temp.path().join("obj")).unwrap();
155
156        let plugin = DotNetPlugin;
157        let artifacts = plugin.find_artifacts(temp.path()).unwrap();
158
159        assert_eq!(artifacts.len(), 2);
160    }
161}