0

I'm trying to get code coverage using Sonarqube. The coverage report is generated by karma. For some reason, the coverage file generated by Karma changes the case of 22 files inside the report. As a result, I'm unable to get coverage for those 22 files. I use a PowerShell script in my Jenkins to generate a canonical path. Below is the script. My script should perform the below steps:

  1. Access the coverage report (unit-tests-lcov.info)
  2. Read the report line by line
  3. Use every file inside unit-tests-lcov.info starting with 'SF' and pass it to the canonical function
  4. Save the file

I'm unable to write a script for the 3rd step. Can anyone make necessary changes to my script below?

$getPathNameSignature = @'
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern uint GetLongPathName(
    string shortPath, 
    StringBuilder sb, 
    int bufferSize);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError=true)]
public static extern uint GetShortPathName(
   string longPath,
   StringBuilder shortPath,
   uint bufferSize);
'@
$getPathNameType = Add-Type -MemberDefinition $getPathNameSignature -Name GetPathNameType -UsingNamespace System.Text -PassThru


function Get-PathCanonicalCase
{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        # Gets the real case of a path
        $Path
    )

    if( -not (Test-Path $Path) )
    {
        Write-Error "Path '$Path' doesn't exist."
        return
    }

    $shortBuffer = New-Object Text.StringBuilder ($Path.Length * 2)
    [void] $getPathNameType::GetShortPathName( $Path, $shortBuffer, $shortBuffer.Capacity )

    $longBuffer = New-Object Text.StringBuilder ($Path.Length * 2)
    [void] $getPathNameType::GetLongPathName( $shortBuffer.ToString(), $longBuffer, $longBuffer.Capacity )

    return $longBuffer.ToString()
}

$file3 = "$env:WORKSPACE\UIArtifacts\unit-tests-lcov.info"           
$text = (Get-Content -Path $file3 -ReadCount 0) -join "`n"  
$ran = $text -Includes 'SF'                                  
Get-PathCanonicalCase($text) | Set-Content -Path $file3    

A part of the input file looks like: I need to pass the file paths to the Get-Canonical function. PS. Part of the file paths is the environment variable.

TN:
c:\sysapps\hudson\.jenkins\jobs\CropObsUi-Metrics\workspace\encirca\encConf.js
FNF:0
FNH:0
DA:10,1
DA:14,1
DA:30,1
DA:31,1
DA:32,1
DA:33,1
DA:34,1
DA:35,1
DA:36,1
DA:37,1
DA:39,1
LF:11
LH:11
BRF:0
BRH:0
end_of_record
TN:
c:\sysapps\hudson\.jenkins\jobs\CropObsUi-Metrics\workspace\encirca\common\util\data.js
FN:25,(anonymous_1)
FN:57,(anonymous_2)
FN:87,(anonymous_3)
FN:149,(anonymous_4)
FNF:4
FNH:0
FNDA:0,(anonymous_1)
FNDA:0,(anonymous_2)
FNDA:0,(anonymous_3)
FNDA:0,(anonymous_4)
TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56
  • Glad to see you have something started. Can you show us what the content of the file looks like? If it is long only a few lines are required. Stuff you wanted including content you don't – Matt Nov 02 '15 at 23:51
  • Why are you joining the content into one string (` -join "\`n"`)? If you want to parse the file line by line it doesn't make sense to connect the lines into one string. – TheMadTechnician Nov 03 '15 at 00:09
  • @Matt Right now I don't have the report file, but it contains several thousands of lines and out of them 458 lines start with 'SF' followed by the path to the javascript file. – Shravan Br Nov 03 '15 at 11:56
  • @TheMadTechnician I'm new to powershell. Can you suggest anything other than join? I need help with the last four lines of the script. – Shravan Br Nov 03 '15 at 11:57
  • I guess we can make use of a loop (foreach) in such a way that whenever a line starts with SF, it should be assigned to a variable and that variable should be passed to the function Get-PathCanonicalCase. Can anyone help me write a script for this? – Shravan Br Nov 03 '15 at 12:00
  • Answers for what you want already exist. Start here for some good and simple examples: http://stackoverflow.com/questions/9439210/how-can-i-make-this-powershell-script-parse-large-files-faster – Matt Nov 03 '15 at 12:47
  • @Matt Thanks for the suggestion, but that link does not answer my question. Can you make modifications to the last four lines of my script in such a way that the script should be able to read my file line by line, take every line that starts with SF and assign it to a variable and later pass that variable as an input to the Get-PathCanonicalCase function? – Shravan Br Nov 03 '15 at 13:09

1 Answers1

1

Ok, short list of issues. I see no reason for the -join command. Normally the Get-Content cmdlet will read a text file in as an array of strings, with each line being one string. When you join them it is then converted to one multi-line string. That is totally opposed to your purposes.

$text = Get-Content -Path $file3

You can filter the lines using a Where statement, and the -like operator.

$ran = $text | Where{$_ -like "SF*"}

When you call a function the correct format is normally:

FunctionName -Parameter Value [-AdditionalParameters AdditionalValues]

You can leave out the parameter names and just put the values in order in most cases. So your last line should be:

Get-PathCanonicalCase $ran | Set-Content -Path $file3

That would only output the lines that started with SF though, and I'm not sure how that's going to work since I don't think a path is going to start with SF. I have a feeling that there is more to the line, and this is not going to deal with your problem like you expect it to. That function expects the string that is passed to it to be a path, and only a path. It does not expect to have to parse a path out of a longer string.

OK to pass to the function:

c:\temp\somefile.csv

Not OK to pass to the function:

SF: c:\temp\somefile.csv <8,732 KB> 11/3/2015 08:16:32.6635

I have no idea what your lines look like in your file, so I just randomly made that up, but the point is that the function is not going to work if your path is a substring of what you are passing to the function. I think you are going to need some additional logic to make this work.

But, this does answer your question as to how to pass each line of the file that starts with SF to the function.

Edit2: Ok, I think you were probably better off before you remove the SF: from the lines with a path in them. Here's why... SF: makes it easy to know what lines need to be passed to the function, while the others can be simply passed through. Trimming the "SF: " off the beginning is easy. So, we're going to use RegEx to replace the path with the updated path that the function provides. We're going to use the 'SF: ' to figure out where the paths are. Here we go...

First import the file just like you were, but don't -join it (explained above).

$text = Get-Content -Path $file3

Then we're going to skip the whole $ran = bit, because there's no need for it. Instead we pipe $text into a ForEach loop, and in that loop look at the line. If the line starts with SF: we replace it with "SF:" followed by the output of the function. For the function we send it a substring starting at the 4th character for the current line, so it skips the 'SF:' and only gets the path. If it isn't a SF: line we simply output the line unchanged.

$text |%{If($_ -like "SF:*"){"SF:$(Get-PathCanonicalCase $_.substring(3))"}else{$_}} | Out-File $file3
TheMadTechnician
  • 34,906
  • 3
  • 42
  • 56
  • You're right. I deleted the SF part and tried what you said. Now I get an error saying ('Get-PathCanonicalCase : Cannot bind argument to parameter 'Path' because it is an empty string.') I appreciate your help in this regard. – Shravan Br Nov 03 '15 at 19:30
  • If you can update your question with a sample of the input file I can help you much better. You can change things so it doesn't have anything confidential in it, just make sure the format is the same, and don't completely delete anything. – TheMadTechnician Nov 03 '15 at 19:35
  • I've updated my question and pasted a part of the input file – Shravan Br Nov 03 '15 at 19:45
  • Ok, I'm going to guess that the paths used to show as something like `SF: c:\sysapps\hudson\.jenkins\jobs\CropObsUi-Metrics\workspace\encirca\encConf.js` is that correct? – TheMadTechnician Nov 03 '15 at 19:50
  • Yes, but now I deleted the SF from the entire file. So don't worry about SF. My requirement now is to pass all the paths starting with c:\sysapps\hudson\.jenkins\jobs\CropObsUi-Metrics\workspace ($env:WORKSPACE=c:\sysapps\hudson\.jenkins\jobs\CropObsUi-Metrics\workspace) to the canonical function. Sorry for all the confusion. – Shravan Br Nov 03 '15 at 20:00
  • Would it be difficult to add it back in, or recreate the file? Having the 'SF: ' in there makes finding the paths simpler. If that is a problem we can work around it, just let me know. – TheMadTechnician Nov 03 '15 at 20:06
  • I can add the SF back there but like you said, wouldn't it make it impossible for us to pass the line starting with SF as the file path to the Canonical function? It would look something like this SF:c:\sysapps\hudson\.jenkins\jobs\CropObsUi-Metrics\workspace – Shravan Br Nov 03 '15 at 20:10
  • Let me worry about that :) Just trust me that having it there makes this simpler, at least for me. Just to be clear, there is no space between the colon and the beginning of the path? So, `SF:c:\sysapps...` and not `SF: c:\sysapps...`, correct? – TheMadTechnician Nov 03 '15 at 20:15
  • Yes you're right. Looks like you've an answer for me. Excited! :) – Shravan Br Nov 03 '15 at 20:18