< Summary - Repometa Coverage

Information
Class: dotnetDetector
Assembly: repometa
File(s): /home/runner/work/repometa/repometa/detect_dotnet.go
Line coverage
96%
Covered lines: 59
Uncovered lines: 2
Coverable lines: 61
Total lines: 144
Line coverage: 96.7%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
detect0%0096.72%

File(s)

/home/runner/work/repometa/repometa/detect_dotnet.go

#LineLine coverage
 1package repometa
 2
 3import (
 4  "path/filepath"
 5  "regexp"
 6  "strings"
 7)
 8
 9type dotnetDetector struct{}
 10
 11// slnProjectLineRE matches the Project(...) header lines that .sln files
 12// use to declare each member project. Format:
 13//
 14//  Project("{TYPE-GUID}") = "Name", "relative/path/to/Name.csproj", "{PROJECT-GUID}"
 15//
 16// Only the second field (the path) is captured; the type GUID (which
 17// distinguishes projects from solution folders) is inspected downstream
 18// by the extension of the path itself.
 19var slnProjectLineRE = regexp.MustCompile(`(?i)^Project\([^)]+\)\s*=\s*"[^"]*",\s*"([^"]+)"`)
 20
 8421func (dotnetDetector) detect(dv dirVisit, cfg options) []finding {
 8422  var out []finding
 8423
 8424  for _, f := range dv.files {
 025    if f.IsDir() {
 026      continue
 27    }
 8528    name := f.Name()
 8529    ext := strings.ToLower(filepath.Ext(name))
 8530
 8531    switch ext {
 332    case ".sln":
 333      // A .sln is the Visual Studio solution format used across
 334      // every MSBuild language (C#, F#, VB, and C++). We only
 335      // emit dotnet-solution when the .sln references at least
 336      // one .NET project file — a pure-C++ solution or one whose
 337      // projects are all solution folders is not a .NET workspace
 338      // and should not be labeled as such. The C++ projects it
 339      // does contain still surface as cpp-project components at
 340      // their own directories.
 341      members := parseSlnMembers(filepath.Join(dv.abs, name), cfg)
 242      if len(members) == 0 {
 243        continue
 44      }
 145      out = append(out, finding{
 146        Kind:       KindDotNetSolution,
 147        Confidence: 1.0,
 148        Evidence: []Evidence{{
 149          Path:   relJoin(dv.rel, name),
 150          Reason: ".sln at directory root",
 151        }},
 152        Workspaces: []Workspace{{
 153          Kind:    WorkspaceDotNetSolution,
 154          Members: expandMembers(dv.abs, members, dv.rel),
 155        }},
 156      })
 57
 558    case ".csproj", ".fsproj", ".vbproj":
 559      out = append(out, finding{
 560        Kind:       KindDotNetProject,
 561        Confidence: 1.0,
 562        Evidence: []Evidence{{
 563          Path:   relJoin(dv.rel, name),
 564          Reason: ext + " project file",
 565        }},
 566        Attributes: map[string]string{
 567          "dotnet.language": dotnetLanguageFor(ext),
 568        },
 569      })
 70
 271    case ".vcxproj":
 272      // Visual Studio C++ project. Shares the MSBuild machinery
 273      // with .csproj but targets native C/C++ code, so it maps to
 274      // LanguageC in the polyglot classifier and suppresses loose
 275      // C-source detection inside the same directory (see
 276      // isCBuildKind in scan.go).
 277      out = append(out, finding{
 278        Kind:       KindCppProject,
 279        Confidence: 1.0,
 280        Evidence: []Evidence{{
 281          Path:   relJoin(dv.rel, name),
 282          Reason: ".vcxproj project file",
 283        }},
 284      })
 85    }
 86  }
 8487  return out
 88}
 89
 90// dotnetLanguageFor maps a project-file extension to the language label
 91// exposed on the dotnet.language attribute.
 92func dotnetLanguageFor(ext string) string {
 93  switch ext {
 94  case ".csproj":
 95    return "csharp"
 96  case ".fsproj":
 97    return "fsharp"
 98  case ".vbproj":
 99    return "vb"
 100  }
 101  return ""
 102}
 103
 104// parseSlnMembers walks the Project(...) lines of a .sln file and returns
 105// the directory-relative paths of every C#/F#/VB project it references.
 106// Solution folders (identified by their type GUID) reuse the Project(...)
 107// prefix but point at a virtual name rather than a real project file —
 108// they are filtered out by extension so members line up with the
 109// dotnet-project components emitted by the walker.
 110//
 111// .sln paths are Windows-style with backslashes; they are normalized to
 112// forward slashes for cross-platform stability.
 113func parseSlnMembers(path string, cfg options) []string {
 114  data := readManifestOrNil(path, cfg)
 115  if data == nil {
 116    return nil
 117  }
 118  var members []string
 119  seen := make(map[string]bool)
 120  for line := range strings.SplitSeq(string(data), "\n") {
 121    trim := strings.TrimSpace(line)
 122    if !strings.HasPrefix(trim, "Project(") {
 123      continue
 124    }
 125    m := slnProjectLineRE.FindStringSubmatch(trim)
 126    if len(m) != 2 {
 127      continue
 128    }
 129    p := strings.ReplaceAll(m[1], `\`, "/")
 130    ext := strings.ToLower(filepath.Ext(p))
 131    if ext != ".csproj" && ext != ".fsproj" && ext != ".vbproj" {
 132      continue
 133    }
 134    dir := filepath.ToSlash(filepath.Dir(p))
 135    if dir == "" || dir == "." {
 136      continue
 137    }
 138    if !seen[dir] {
 139      seen[dir] = true
 140      members = append(members, dir)
 141    }
 142  }
 143  return members
 144}

Methods/Properties

detect