Skip to content

Commit

Permalink
test: Create customized logger to log warnings and errors on committe…
Browse files Browse the repository at this point in the history
…d files

As we are using StyleCop Anyalyzer to lint C# code, we want to show
warnings and errors in the last committed files for every PR request. We
create a customized logger "SALogger" to log warnings and errors in last
committed files instead of all files in the whole project. After we get
the logs, we send it back to PR as comments. Meanwhile, we added a
RingloggerParser to parse log file (log.bin) to txt format which can be
readable.
  • Loading branch information
connected-mhuang authored and connected-cmo committed Dec 11, 2019
1 parent 0e070a5 commit 2de39d2
Show file tree
Hide file tree
Showing 13 changed files with 577 additions and 16 deletions.
57 changes: 41 additions & 16 deletions .circleci/config.yml
Expand Up @@ -14,14 +14,21 @@ jobs:
name: Build Tunnel
command: |
.\tunnel\build.cmd
- run:
name: Build Logger
command: |
cd test/logger
nuget install packages.config -OutputDirectory packages
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe -target:library SALogger.cs -reference:.\packages\Microsoft.Build.Utilities.Core.16.3.0\lib\net472\Microsoft.Build.Utilities.Core.dll,.\packages\Microsoft.Build.Framework.16.3.0\lib\net472\Microsoft.Build.Framework.dll,.\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll
- run:
name: Build Application
command: |
New-Item -ItemType directory -Path test\result
cd ui
nuget restore -SolutionDirectory ./
MSBuild /t:Rebuild /p:Configuration=Release /p:Platform="x64"
MSBuild /t:Rebuild /p:Configuration=Release /p:Platform="x86"
MSBuild /t:Rebuild /p:Configuration=Debug_QA /p:Platform="x64"
MSBuild -t:Rebuild -p:Configuration=Release -p:Platform="x64" -logger:"..\test\logger\SALogger.dll;..\test\result\Output.log"
MSBuild -t:Rebuild -p:Configuration=Release -p:Platform="x86"
MSBuild -t:Rebuild -p:Configuration=Debug_QA -p:Platform="x64"
- run:
name: Build MSI
command: |
Expand Down Expand Up @@ -56,19 +63,37 @@ jobs:
- run:
name: Generate Tests Report
command: |
ui\packages\extent.0.0.3\tools\extent.exe -i test\result\unittests\result.xml -o test\result\unittests
.\ui\coverage.bat
New-Item -ItemType directory -Path test\result\integration-tests
cd test
go get -u github.com/jstemmer/go-junit-report
Get-Content -Path test.out | C:\Users\circleci\go\bin\go-junit-report > ./result/integration-tests/report.xml
cd result\integration-tests
Get-Content report.xml | Set-Content -Encoding utf8 report-utf8.xml
Remove-Item report.xml
npm config set unsafe-perm true
npm i -g xunit-viewer@5.1.11
xunit-viewer --results=report-utf8.xml --output=report.html
Copy-Item "C:\Users\circleci\AppData\Local\Mozilla\FirefoxPrivateNetworkVPN\log.bin" -Destination "..\"
If ([System.IO.File]::Exists("test\result\unittests\result.xml")) {
# unit test report
ui\packages\extent.0.0.3\tools\extent.exe -i test\result\unittests\result.xml -o test\result\unittests;
# code coverage report
.\ui\coverage.bat
}
# integration test report
If ([System.IO.File]::Exists("test\test.out")) {
New-Item -ItemType directory -Path test\result\integration-tests;
cd test;
go get -u github.com/jstemmer/go-junit-report;
Get-Content -Path test.out | C:\Users\circleci\go\bin\go-junit-report > ./result/integration-tests/report.xml;
cd result\integration-tests;
Get-Content report.xml | Set-Content -Encoding utf8 report-utf8.xml;
Remove-Item report.xml;
npm config set unsafe-perm true;
npm i -g xunit-viewer@5.1.11;
xunit-viewer --results=report-utf8.xml --output=report.html;
}
# save application log
If ([System.IO.File]::Exists("C:\Users\circleci\AppData\Local\Mozilla\FirefoxPrivateNetworkVPN\log.bin")) {
cd C:\Users\circleci\project\test\ringloggerParser
MSBuild -t:Rebuild -p:Configuration=Release
.\bin\Release\RingloggerParser.exe C:\Users\circleci\AppData\Local\Mozilla\FirefoxPrivateNetworkVPN\log.bin C:\Users\circleci\project\test\result\log.txt
}
# add comments to PR if there are any warnings or errors on committed files
If ([System.IO.File]::Exists("C:\Users\circleci\project\test\result\Output.log")) {
cd C:\Users\circleci\project\test\comment
npm i
node index.js
}
when: always
- run:
name: Deploy
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Expand Up @@ -73,3 +73,9 @@ wireguard.server.base64.config

#vim
*.swp

#logger
test/logger/packages

#comment
test/comment/node_modules
15 changes: 15 additions & 0 deletions test/comment/index.js
@@ -0,0 +1,15 @@
const bot = require("circle-github-bot").create();
const fs = require('fs');

const path = '../result/Output.log'
fs.readFile(path, (err, data) => {
if (err) {
console.log(`Fail to read file: ${path}, err: ${err.message}`)
}
const regex = /(?<errors>\d*) Error\(s\), (?<warnings>\d*) Warning\(s\)/gm;
const { errors, warnings } = regex.exec(data.toString()).groups
bot.comment(process.env.GH_AUTH_TOKEN, `<h3>Errors: ${errors}, Warnings: ${warnings}</h3>
Details: <strong>${bot.artifactLink('test/result/Output.log', 'details')}</strong>
`);
})

11 changes: 11 additions & 0 deletions test/comment/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions test/comment/package.json
@@ -0,0 +1,15 @@
{
"name": "comment",
"version": "1.0.0",
"description": "",
"main": "comment.js",
"dependencies": {
"circle-github-bot": "^2.0.1"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
146 changes: 146 additions & 0 deletions test/logger/SALogger.cs
@@ -0,0 +1,146 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Management.Automation;
using System.Security;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace SALogger
{
// This logger will derive from the Microsoft.Build.Utilities.Logger class.
public class SALogger : Logger
{
/// <summary>
/// Initialize is guaranteed to be called by MSBuild at the start of the build
/// before any events are raised.
/// </summary>
public override void Initialize(IEventSource eventSource)
{
// The name of the log file should be passed as the first item in the
// "parameters" specification in the /logger switch. It is required
// to pass a log file to this logger. Other loggers may have zero or more than
// one parameters.
if (null == Parameters)
{
throw new LoggerException("Log file was not set.");
}
string[] parameters = Parameters.Split(';');

string logFile = parameters[0];
if (String.IsNullOrEmpty(logFile))
{
throw new LoggerException("Log file was not set.");
}

if (parameters.Length > 1)
{
throw new LoggerException("Too many parameters passed.");
}

try
{
// Open the file
this.streamWriter = new StreamWriter(logFile);
}
catch (Exception ex)
{
if
(
ex is UnauthorizedAccessException
|| ex is ArgumentNullException
|| ex is PathTooLongException
|| ex is DirectoryNotFoundException
|| ex is NotSupportedException
|| ex is ArgumentException
|| ex is SecurityException
|| ex is IOException
)
{
throw new LoggerException("Failed to create log file: " + ex.Message);
}
else
{
// Unexpected failure
throw;
}
}
// Get the files that had changes in the last commit
GetLastCommitChanges();
// For brevity, we'll only register for certain event types. Loggers can also
// register to handle TargetStarted/Finished and other events.
eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised);
eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised);
}

void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e)
{
// BuildErrorEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters
this.numOfErrors++;
string line = String.Format(": ERROR {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
WriteLineWithSenderAndMessage(line, e);
}

void eventSource_WarningRaised(object sender, BuildWarningEventArgs e)
{
foreach(PSObject file in this.results)
{
string lastCommitFile = file.ToString().Replace("/", @"\");

if(lastCommitFile.Contains(e.File))
{
// BuildWarningEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters
this.numOfWarnings++;
string line = String.Format(": Warning {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber);
WriteLineWithSenderAndMessage(line, e);
}
}
}

/// <summary>
/// Write a line to the log, adding the SenderName and Message
/// (these parameters are on all MSBuild event argument objects)
/// </summary>
private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e)
{
WriteLine(e.SenderName + ": " + line, e);
}

/// <summary>
/// Just write a line to the log
/// </summary>
private void WriteLine(string line, BuildEventArgs e)
{
streamWriter.WriteLine(line + e.Message);
}

/// <summary>
/// Get a list of changed files' names from last commit.
/// </summary>
private void GetLastCommitChanges()
{
using (PowerShell powerShell = PowerShell.Create())
{
powerShell.AddScript("cd ..");
powerShell.AddScript(@"git diff-tree --no-commit-id --name-only -r HEAD");
results = powerShell.Invoke();
}
}

/// <summary>
/// Shutdown() is guaranteed to be called by MSBuild at the end of the build, after all
/// events have been raised.
/// </summary>
public override void Shutdown()
{
// Done logging, let go of the file
streamWriter.WriteLine(this.numOfErrors + " Error(s), " + this.numOfWarnings + " Warning(s)");
streamWriter.Close();
}

private StreamWriter streamWriter;
private Collection<PSObject> results;
private int numOfWarnings = 0;
private int numOfErrors = 0;
}
}
6 changes: 6 additions & 0 deletions test/logger/packages.config
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Build.Utilities.Core" version="16.3.0" targetFramework="net472" />
<package id="Microsoft.Build.Framework" version="16.3.0" targetFramework="net472" />
<package id="Microsoft.PowerShell.5.ReferenceAssemblies" version="1.1.0"/>
</packages>
6 changes: 6 additions & 0 deletions test/ringloggerParser/App.config
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
</startup>
</configuration>
35 changes: 35 additions & 0 deletions test/ringloggerParser/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RingloggerParser")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RingloggerParser")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("f12db613-6ee9-46f0-aeee-d8aa701c5acd")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

1 comment on commit 2de39d2

@mhuang-connectedqa
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Errors: 0, Warnings: 0

Details: details

Please sign in to comment.