How to use SVN blame to count the ugly code (e.g. general exceptions) for each developer? [PowerShell Script]


In a team, each developer writes bad code sometimes. For example, in this post, the total number of general exceptions (C#) is counted in a code-base.

Writing general exceptions is considered a very bad practice because whoever writes this intends to suppress any errors. Funny enough, some developers when facing tight deadlines, fix the bugs by adding try-catch statement. But hiding errors result in (or just causing or postpone) bigger errors afterwards.

In simple words, the following code style is bad:

1
2
3
4
5
try {
 
} catch (Exception anything) {
  // hide the errors
}
try {

} catch (Exception anything) {
  // hide the errors
}

The following uses the Powershell script to count the number of general exceptions written by each developer. So you, as a team leader, can keep an eye (monitor) on the progress and take precautions measures if someone adds ‘too much’ ugly code (and possibly needs training if identified).

The command svn blame or svn praise, svn annotate is used depending on the mood 🙂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    # project path
    $SolutionDir = "E:\Trunk4.0\Project"
 
    # get all the *.cs files after filtering
    $files = Get-ChildItem "$SolutionDir" -filter "*.cs" -Recurse | Where-Object {!(($_.FullName -like "*esigner*.cs") -or ($_.FullName -like "*AssemblyInfo*.cs"))}
 
    # total violations (general exception)
    $cnt = 0
 
    # general exception regular expression
    $pattern = "catch(\s*\(\s*Exception[\w\s]*\)|\s*$\s*\{|\s*\{)"
 
    # dictionary object to hold counter for each developer
    $dict = @{}
 
    for ($i = 0; $i -lt $files.Count; $i++) { # loop each source file
        $filename = $files[$i].FullName
        if (Test-Path $filename) {        
            $content = (Get-Content $filename -Raw)  # get content
            if ($content.Length -gt 0) {
                $matches = [regex]::matches($content, $pattern)                
                if ($matches.Count -gt 0) {  # if there are general exceptions
                    Write-Host "Processing $filename"
                    $cnt = $cnt + $matches.Count
                    $output = &svn blame -g -x -b "$filename" | grep -n -P "$pattern"
                    ForEach ($obj in $output) {
                        $author = $obj.Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)
                        if ($author.Length -gt 3) { # valid result
                            if ($dict.ContainsKey($author[2])) { # update the result
                                $cur = $dict[$author[2]]
                                $dict[$author[2]] = $cur + 1
                            } else {
                                $dict[$author[2]] = 1
                            }
                        }
                    }
                }
            }
        }
    }
 
    $dict.GetEnumerator() | Sort-Object Value -descending
    Write-Host "Total = $cnt"
    # project path
    $SolutionDir = "E:\Trunk4.0\Project"

    # get all the *.cs files after filtering
    $files = Get-ChildItem "$SolutionDir" -filter "*.cs" -Recurse | Where-Object {!(($_.FullName -like "*esigner*.cs") -or ($_.FullName -like "*AssemblyInfo*.cs"))}

    # total violations (general exception)
    $cnt = 0

    # general exception regular expression
    $pattern = "catch(\s*\(\s*Exception[\w\s]*\)|\s*$\s*\{|\s*\{)"

    # dictionary object to hold counter for each developer
    $dict = @{}

    for ($i = 0; $i -lt $files.Count; $i++) { # loop each source file
        $filename = $files[$i].FullName
        if (Test-Path $filename) {        
            $content = (Get-Content $filename -Raw)  # get content
            if ($content.Length -gt 0) {
                $matches = [regex]::matches($content, $pattern)                
                if ($matches.Count -gt 0) {  # if there are general exceptions
                    Write-Host "Processing $filename"
                    $cnt = $cnt + $matches.Count
                    $output = &svn blame -g -x -b "$filename" | grep -n -P "$pattern"
                    ForEach ($obj in $output) {
                        $author = $obj.Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)
                        if ($author.Length -gt 3) { # valid result
                            if ($dict.ContainsKey($author[2])) { # update the result
                                $cur = $dict[$author[2]]
                                $dict[$author[2]] = $cur + 1
                            } else {
                                $dict[$author[2]] = 1
                            }
                        }
                    }
                }
            }
        }
    }

    $dict.GetEnumerator() | Sort-Object Value -descending
    Write-Host "Total = $cnt"

After a while, (the svn blame is time consuming and did take a while depending on the size of the project and number of violations. This command will connect to SVN server and get the last author to modify each line), the output would be something like this:

Name                           Value                                                                                                                                                                                                                                           
----                           -----                                                                                                                                                                                                                                           
Jack                           184
Tom                            180
Total = 364

We use [regex]::matches($content, $pattern) to check if there are matches and only proceed to svn blame if there are. So as the number of violations is reduced, the entire scan speed should be faster and faster. The most time-consuming part is the svn blame which will list the last-modified author for each line in the file. And the result is pipelined into grep which looks again for the regular expression matches.

The svn takes -g to consider the merged branches and -x -b to exclude white spaces so that only meaningful changes will be considered when it decides who touches the file last.

Finally, the $dict.GetEnumerator() | Sort-Object Value -descending is used to sort the results by the number of violations in descending order. The next step is to plot a line for each developer on the CI (Continuous Integration) build server.

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
608 words
Last Post: How to Connect Laptop to Three Monitors?
Next Post: Does TeamViewer Support Multi Screens (Monitors)?

The Permanent URL is: How to use SVN blame to count the ugly code (e.g. general exceptions) for each developer? [PowerShell Script]

Leave a Reply