From 0e9a6d9cb2042cf184cbc322a917103dd04e5ad9 Mon Sep 17 00:00:00 2001 From: Pascal Berger Date: Fri, 1 Sep 2017 22:26:49 +0200 Subject: [PATCH] (GH-1) First version based on Cake.Prca.Issues.MsBuild --- .appveyor.yml | 31 +++ .gitattributes | 63 +++++ .gitignore | 25 +- .travis.yml | 10 + CONTRIBUTING.md | 35 +++ GitReleaseManager.yaml | 12 + LICENSE | 2 +- README.md | 41 ++- build.ps1 | 184 +++++++++++++ build.sh | 82 ++++++ nuspec/nuget/Cake.Issues.MsBuild.nuspec | 33 +++ setup.cake | 23 ++ src/Cake.Issues.MsBuild.Tests.ruleset | 8 + .../Cake.Issues.MsBuild.Tests.csproj | 110 ++++++++ .../MsBuildIssuesProviderFixture.cs | 49 ++++ .../MsBuildIssuesProviderTests.cs | 39 +++ .../MsBuildIssuesSettingsTests.cs | 163 ++++++++++++ .../MsBuildRuleUrlResolverTests.cs | 96 +++++++ .../Properties/AssemblyInfo.cs | 35 +++ .../Testfiles/IssueWithFile.xml | 4 + .../Testfiles/IssueWithOnlyFileName.xml | 6 + .../Testfiles/IssueWithoutFile.xml | 4 + .../XmlFileLoggerFormatTests.cs | 115 +++++++++ src/Cake.Issues.MsBuild.Tests/packages.config | 16 ++ src/Cake.Issues.MsBuild.ruleset | 241 ++++++++++++++++++ src/Cake.Issues.MsBuild.sln | 44 ++++ src/Cake.Issues.MsBuild.sln.DotSettings | 3 + .../Cake.Issues.MsBuild.csproj | 77 ++++++ src/Cake.Issues.MsBuild/ILogFileFormat.cs | 21 ++ src/Cake.Issues.MsBuild/LogFileFormat.cs | 33 +++ .../MsBuildIssuesAliases.cs | 234 +++++++++++++++++ .../MsBuildIssuesProvider.cs | 33 +++ .../MsBuildIssuesSettings.cs | 83 ++++++ .../MsBuildRuleDescription.cs | 20 ++ .../MsBuildRuleUrlResolver.cs | 74 ++++++ .../Properties/AssemblyInfo.cs | 40 +++ .../XmlFileLoggerFormat.cs | 178 +++++++++++++ src/Cake.Issues.MsBuild/packages.config | 12 + tools/packages.config | 4 + 39 files changed, 2278 insertions(+), 5 deletions(-) create mode 100644 .appveyor.yml create mode 100644 .gitattributes create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 GitReleaseManager.yaml create mode 100644 build.ps1 create mode 100644 build.sh create mode 100644 nuspec/nuget/Cake.Issues.MsBuild.nuspec create mode 100644 setup.cake create mode 100644 src/Cake.Issues.MsBuild.Tests.ruleset create mode 100644 src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj create mode 100644 src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderFixture.cs create mode 100644 src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs create mode 100644 src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs create mode 100644 src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs create mode 100644 src/Cake.Issues.MsBuild.Tests/Properties/AssemblyInfo.cs create mode 100644 src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithFile.xml create mode 100644 src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithOnlyFileName.xml create mode 100644 src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithoutFile.xml create mode 100644 src/Cake.Issues.MsBuild.Tests/XmlFileLoggerFormatTests.cs create mode 100644 src/Cake.Issues.MsBuild.Tests/packages.config create mode 100644 src/Cake.Issues.MsBuild.ruleset create mode 100644 src/Cake.Issues.MsBuild.sln create mode 100644 src/Cake.Issues.MsBuild.sln.DotSettings create mode 100644 src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj create mode 100644 src/Cake.Issues.MsBuild/ILogFileFormat.cs create mode 100644 src/Cake.Issues.MsBuild/LogFileFormat.cs create mode 100644 src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs create mode 100644 src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs create mode 100644 src/Cake.Issues.MsBuild/MsBuildIssuesSettings.cs create mode 100644 src/Cake.Issues.MsBuild/MsBuildRuleDescription.cs create mode 100644 src/Cake.Issues.MsBuild/MsBuildRuleUrlResolver.cs create mode 100644 src/Cake.Issues.MsBuild/Properties/AssemblyInfo.cs create mode 100644 src/Cake.Issues.MsBuild/XmlFileLoggerFormat.cs create mode 100644 src/Cake.Issues.MsBuild/packages.config create mode 100644 tools/packages.config diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..bd21071 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,31 @@ +#---------------------------------# +# Build Image # +#---------------------------------# +image: Visual Studio 2017 + +#---------------------------------# +# Build Script # +#---------------------------------# +build_script: + - ps: .\build.ps1 -Target AppVeyor + +# Tests +test: off + +#---------------------------------# +# Branches to build # +#---------------------------------# +branches: + # Whitelist + only: + - develop + - master + - /release/.*/ + - /hotfix/.*/ + +#---------------------------------# +# Build Cache # +#---------------------------------# +cache: +- src\packages -> src\**\packages.config +- tools -> setup.cake \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 940794e..ba4e60c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,14 @@ +# Project specific + +BuildArtifacts/ + +# Created by https://www.gitignore.io/api/cake,visualstudio + +### Cake ### +tools/* +!tools/packages.config + +### VisualStudio ### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -148,9 +159,11 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to @@ -286,3 +299,9 @@ __pycache__/ *.btm.cs *.odx.cs *.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + +# End of https://www.gitignore.io/api/cake,visualstudio \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..eb79eee --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: csharp +script: + - ./build.sh -v diagnostic +os: + - linux + - osx +cache: + directories: + - packages + - tools diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..078295e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# Contribution Guidelines + +This repository uses [GitFlow] with default configuration. +Development is happening on `develop` branch. + +To contribute: + +* Fork this repository. +* Create a feature branch from `develop`. +* Implement your changes. +* Push your feature branch. +* Create a pull request. + +## Build + +To build this package we are using Cake. + +On Windows PowerShell run: + +```powershell +./build +``` + +On OSX/Linux run: + +```bash +./build.sh +``` + +## Release + +See [Cake.Recipe documentation] how to create a new release of this addin. + +[GitFlow]: (http://nvie.com/posts/a-successful-git-branching-model/) +[Cake.Recipe documentation]: https://cake-contrib.github.io/Cake.Recipe/docs/usage/creating-release \ No newline at end of file diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml new file mode 100644 index 0000000..721c1ba --- /dev/null +++ b/GitReleaseManager.yaml @@ -0,0 +1,12 @@ +issue-labels-include: +- Breaking change +- Feature +- Bug +- Improvement +- Documentation +issue-labels-exclude: +- Build +issue-labels-alias: + - name: Documentation + header: Documentation + plural: Documentation \ No newline at end of file diff --git a/LICENSE b/LICENSE index f90383f..e052ef6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 Pascal Berger +Copyright (c) 2017 BBT Software AG and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 78f0579..7de82d6 100644 --- a/README.md +++ b/README.md @@ -1 +1,40 @@ -# Cake.Issues.MsBuild \ No newline at end of file +# MsBuild Issue Provider for Cake.Issues Addin + +This addin for the Cake Build Automation System allows you to read issues logged as warnings by MsBuild +using the [Cake Issues addin](https://github.com/cake-contrib/Cake.Issues). + +For more information about this add-in see the [Cake.Issues website](https://cake-contrib.github.io/Cake.Issues.Website) +and for general information about the Cake build automation system see the [Cake website](http://cakebuild.net) + +[![License](http://img.shields.io/:license-mit-blue.svg)](https://github.com/cake-contrib/Cake.Issues.MsBuild/blob/feature/build/LICENSE) + +## Information + +| | Stable | Pre-release | +|:--:|:--:|:--:| +|GitHub Release|-|[![GitHub release](https://img.shields.io/github/release/cake-contrib/Cake.Issues.MsBuild.svg)](https://github.com/cake-contrib/Cake.Issues.MsBuild/releases/latest)| +|NuGet|[![NuGet](https://img.shields.io/nuget/v/Cake.Issues.MsBuild.svg)](https://www.nuget.org/packages/Cake.Issues.MsBuild)|[![NuGet](https://img.shields.io/nuget/vpre/Cake.Issues.MsBuild.svg)](https://www.nuget.org/packages/Cake.Issues.MsBuild)| + +## Build Status + +|Develop|Master| +|:--:|:--:| +|[![Build status](https://ci.appveyor.com/api/projects/status/7e9bedtgp9m30p4m/branch/develop?svg=true)](https://ci.appveyor.com/project/cakecontrib/cake-issues-msbuild/branch/develop)|[![Build status](https://ci.appveyor.com/api/projects/status/7e9bedtgp9m30p4m/branch/develop?svg=true)](https://ci.appveyor.com/project/cakecontrib/cake-issues-msbuild/branch/master)| + +## Code Coverage + +[![Coverage Status](https://coveralls.io/repos/github/cake-contrib/Cake.Issues.MsBuild/badge.svg?branch=develop)](https://coveralls.io/github/cake-contrib/Cake.Issues.MsBuild?branch=develop) + +## Quick Links + +- [Documentation](https://cake-contrib.github.io/Cake.Issues.Website) + +## Chat Room + +Come join in the conversation about this addin in our Gitter Chat Room + +[![Join the chat at https://gitter.im/cake-contrib/Lobby](https://badges.gitter.im/cake-contrib/Lobby.svg)](https://gitter.im/cake-contrib/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +## Contributing + +Contributions are welcome. See [Contribution Guidelines](CONTRIBUTING.md). \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..bdfb32b --- /dev/null +++ b/build.ps1 @@ -0,0 +1,184 @@ +########################################################################## +# This is the Cake bootstrapper script for PowerShell. +# This file was downloaded from https://github.com/cake-build/resources +# Feel free to change this file to fit your needs. +########################################################################## + +<# +.SYNOPSIS +This is a Powershell script to bootstrap a Cake build. +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Cake) +and execute your Cake build script with the parameters you provide. +.PARAMETER Script +The build script to execute. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER Experimental +Tells Cake to use the latest Roslyn release. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER Mono +Tells Cake to use the Mono scripting engine. +.PARAMETER SkipToolPackageRestore +Skips restoring of packages. +.PARAMETER ScriptArgs +Remaining arguments are added here. +.LINK +http://cakebuild.net +#> + +[CmdletBinding()] +Param( + [string]$Script = "setup.cake", + [string]$Target = "Default", + [ValidateSet("Release", "Debug")] + [string]$Configuration = "Release", + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity = "Verbose", + [switch]$Experimental, + [Alias("DryRun","Noop")] + [switch]$WhatIf, + [switch]$Mono, + [switch]$SkipToolPackageRestore, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +[Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null +function MD5HashFile([string] $filePath) +{ + if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf)) + { + return $null + } + + [System.IO.Stream] $file = $null; + [System.Security.Cryptography.MD5] $md5 = $null; + try + { + $md5 = [System.Security.Cryptography.MD5]::Create() + $file = [System.IO.File]::OpenRead($filePath) + return [System.BitConverter]::ToString($md5.ComputeHash($file)) + } + finally + { + if ($file -ne $null) + { + $file.Dispose() + } + } +} + +Write-Host "Preparing to run build script..." + +if(!$PSScriptRoot){ + $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +} + +$TOOLS_DIR = Join-Path $PSScriptRoot "tools" +$NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe" +$CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" +$PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" + +# Should we use mono? +$UseMono = ""; +if($Mono.IsPresent) { + Write-Verbose -Message "Using the Mono based scripting engine." + $UseMono = "-mono" +} + +# Should we use the new Roslyn? +$UseExperimental = ""; +if($Experimental.IsPresent -and !($Mono.IsPresent)) { + Write-Verbose -Message "Using experimental version of Roslyn." + $UseExperimental = "-experimental" +} + +# Is this a dry run? +$UseDryRun = ""; +if($WhatIf.IsPresent) { + $UseDryRun = "-dryrun" +} + +# Make sure tools folder exists +if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) { + Write-Verbose -Message "Creating tools directory..." + New-Item -Path $TOOLS_DIR -Type directory | out-null +} + +# Make sure that packages.config exist. +if (!(Test-Path $PACKAGES_CONFIG)) { + Write-Verbose -Message "Downloading packages.config..." + try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch { + Throw "Could not download packages.config." + } +} + +# Try find NuGet.exe in path if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Trying to find nuget.exe in PATH..." + $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_) } + $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1 + if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) { + Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)." + $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName + } +} + +# Try download NuGet.exe if not exists +if (!(Test-Path $NUGET_EXE)) { + Write-Verbose -Message "Downloading NuGet.exe..." + try { + (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE) + } catch { + Throw "Could not download NuGet.exe." + } +} + +# Save nuget.exe path to environment to be available to child processed +$ENV:NUGET_EXE = $NUGET_EXE + +# Restore tools from NuGet? +if(-Not $SkipToolPackageRestore.IsPresent) { + Push-Location + Set-Location $TOOLS_DIR + + # Check for changes in packages.config and remove installed tools if true. + [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG) + if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or + ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) { + Write-Verbose -Message "Missing or changed package.config hash..." + Remove-Item * -Recurse -Exclude packages.config,nuget.exe + } + + Write-Verbose -Message "Restoring tools from NuGet..." + $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -PreRelease -OutputDirectory `"$TOOLS_DIR`" -Source https://www.myget.org/F/cake/api/v3/index.json" + + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NuGet tools." + } + else + { + $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII" + } + Write-Verbose -Message ($NuGetOutput | out-string) + Pop-Location +} + +# Make sure that Cake has been installed. +if (!(Test-Path $CAKE_EXE)) { + Throw "Could not find Cake.exe at $CAKE_EXE" +} + +# Start Cake +Write-Host "Running build script..." +Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs" +exit $LASTEXITCODE \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..a541ec1 --- /dev/null +++ b/build.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +############################################################### +# This is the Cake bootstrapper script that is responsible for +# downloading Cake and all specified tools from NuGet. +############################################################### + +# Define directories. +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +TOOLS_DIR=$SCRIPT_DIR/tools +NUGET_EXE=$TOOLS_DIR/nuget.exe +CAKE_EXE=$TOOLS_DIR/Cake/Cake.exe + +# Define default arguments. +SCRIPT="setup.cake" +TARGET="Default" +CONFIGURATION="Release" +VERBOSITY="verbose" +DRYRUN= +SHOW_VERSION=false +SCRIPT_ARGUMENTS=() + +# Parse arguments. +for i in "$@"; do + case $1 in + -s|--script) SCRIPT="$2"; shift ;; + -t|--target) TARGET="$2"; shift ;; + -c|--configuration) CONFIGURATION="$2"; shift ;; + -v|--verbosity) VERBOSITY="$2"; shift ;; + -d|--dryrun) DRYRUN="-dryrun" ;; + --version) SHOW_VERSION=true ;; + --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; + *) SCRIPT_ARGUMENTS+=("$1") ;; + esac + shift +done + +# Make sure the tools folder exist. +if [ ! -d $TOOLS_DIR ]; then + mkdir $TOOLS_DIR +fi + +# Make sure that packages.config exist. +if [ ! -f $TOOLS_DIR/packages.config ]; then + echo "Downloading packages.config..." + curl -Lsfo $TOOLS_DIR/packages.config http://cakebuild.net/bootstrapper/packages + if [ $? -ne 0 ]; then + echo "An error occured while downloading packages.config." + exit 1 + fi +fi + +# Download NuGet if it does not exist. +if [ ! -f $NUGET_EXE ]; then + echo "Downloading NuGet..." + curl -Lsfo $NUGET_EXE https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + if [ $? -ne 0 ]; then + echo "An error occured while downloading nuget.exe." + exit 1 + fi +fi + +# Restore tools from NuGet. +pushd $TOOLS_DIR >/dev/null +mono $NUGET_EXE install -ExcludeVersion -PreRelease -Source https://www.myget.org/F/cake/api/v3/index.json +if [ $? -ne 0 ]; then + echo "Could not restore NuGet packages." + exit 1 +fi +popd >/dev/null + +# Make sure that Cake has been installed. +if [ ! -f $CAKE_EXE ]; then + echo "Could not find Cake.exe at '$CAKE_EXE'." + exit 1 +fi + +# Start Cake +if $SHOW_VERSION; then + exec mono $CAKE_EXE -version +else + exec mono $CAKE_EXE $SCRIPT -verbosity=$VERBOSITY -configuration=$CONFIGURATION -target=$TARGET $DRYRUN "${SCRIPT_ARGUMENTS[@]}" +fi diff --git a/nuspec/nuget/Cake.Issues.MsBuild.nuspec b/nuspec/nuget/Cake.Issues.MsBuild.nuspec new file mode 100644 index 0000000..634466c --- /dev/null +++ b/nuspec/nuget/Cake.Issues.MsBuild.nuspec @@ -0,0 +1,33 @@ + + + + Cake.Issues.MsBuild + Cake.Issues.MsBuild + 0.0.0 + BBT Software AG and contributors + bbtsoftware, pascalberger, cake-contrib + MsBuild support for the Cake.Issues addin for Cake Build Automation System + +The MsBuild support for the Cake.Issues addin for Cake allows you to read issues logged as warnings in a MsBuild log. + +This addin provides the aliases for reading MsBuild warnings and providing them to the Cake.Issues addin. +It also requires the core Cake.Issues addin. + +There are also additional addins for generating reports or posting issues to pull requests. + +See the Project Site for an overview of the whole ecosystem of addins for working with issues in Cake scripts. + + https://github.com/cake-contrib/Cake.Issues.MsBuild/blob/develop/LICENSE + http://cake-contrib.github.io/Cake.Issues.Website + https://cdn.rawgit.com/cake-contrib/graphics/a5cf0f881c390650144b2243ae551d5b9f836196/png/cake-contrib-medium.png + false + Copyright © 2017 BBT Software AG and contributors + Cake Script Cake-Issues Cake-IssueProvider CodeAnalysis Linting MsBuild + https://github.com/cake-contrib/Cake.Issues.MsBuild/releases/tag/0.1.0 + + + + + + + \ No newline at end of file diff --git a/setup.cake b/setup.cake new file mode 100644 index 0000000..657a438 --- /dev/null +++ b/setup.cake @@ -0,0 +1,23 @@ +#load nuget:https://www.myget.org/F/cake-contrib/api/v2?package=Cake.Recipe&prerelease + +Environment.SetVariableNames(); + +BuildParameters.SetParameters( + context: Context, + buildSystem: BuildSystem, + sourceDirectoryPath: "./src", + title: "Cake.Issues.MsBuild", + repositoryOwner: "cake-contrib", + repositoryName: "Cake.Issues.MsBuild", + appVeyorAccountName: "cakecontrib"); + +BuildParameters.PrintParameters(Context); + +ToolSettings.SetToolSettings( + context: Context, + dupFinderExcludePattern: new string[] { BuildParameters.RootDirectoryPath + "/src/Cake.Issues.MsBuild.Tests/*.cs" }, + testCoverageFilter: "+[*]* -[xunit.*]* -[Cake.Core]* -[Cake.Testing]* -[*.Tests]* -[Cake.Issues]* -[Cake.Issues.Testing]*", + testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", + testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs"); + +Build.Run(); diff --git a/src/Cake.Issues.MsBuild.Tests.ruleset b/src/Cake.Issues.MsBuild.Tests.ruleset new file mode 100644 index 0000000..73e07dc --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests.ruleset @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj b/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj new file mode 100644 index 0000000..5f7d7f5 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj @@ -0,0 +1,110 @@ + + + + + + Debug + AnyCPU + {C69329F6-A4D1-4E33-BD9D-5E59973BE781} + Library + Properties + Cake.Issues.MsBuild.Tests + Cake.Issues.MsBuild.Tests + v4.5.2 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + ..\Cake.Issues.MsBuild.Tests.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + ..\Cake.Issues.MsBuild.Tests.ruleset + + + + ..\packages\Cake.Core.0.16.2\lib\net45\Cake.Core.dll + + + ..\packages\Cake.Issues.0.1.0-beta0001\lib\net45\Cake.Issues.dll + + + ..\packages\Cake.Issues.Testing.0.1.0-beta0001\lib\net45\Cake.Issues.Testing.dll + + + ..\packages\Cake.Testing.0.16.2\lib\net45\Cake.Testing.dll + + + ..\packages\Shouldly.2.8.3\lib\net451\Shouldly.dll + + + + + + + + + + + ..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + + + ..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll + + + ..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll + + + ..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll + + + + + + + + + + + + + {1a6c74ce-4775-458a-b013-bde1986c5b88} + Cake.Issues.MsBuild + + + + + + + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderFixture.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderFixture.cs new file mode 100644 index 0000000..830f03e --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderFixture.cs @@ -0,0 +1,49 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using System.Collections.Generic; + using System.IO; + using Cake.Testing; + using Core.Diagnostics; + using IssueProvider; + + internal class MsBuildIssuesProviderFixture + { + public MsBuildIssuesProviderFixture(string fileResourceName) + { + this.Log = new FakeLog { Verbosity = Verbosity.Normal }; + + using (var stream = this.GetType().Assembly.GetManifestResourceStream("Cake.Issues.MsBuild.Tests.Testfiles." + fileResourceName)) + { + using (var sr = new StreamReader(stream)) + { + this.MsBuildIssuesSettings = + MsBuildIssuesSettings.FromContent( + sr.ReadToEnd(), + new XmlFileLoggerFormat(this.Log)); + } + } + + this.RepositorySettings = + new RepositorySettings(@"c:\Source\Cake.Issues.MsBuild"); + } + + public FakeLog Log { get; set; } + + public MsBuildIssuesSettings MsBuildIssuesSettings { get; set; } + + public RepositorySettings RepositorySettings { get; set; } + + public MsBuildIssuesProvider Create() + { + var provider = new MsBuildIssuesProvider(this.Log, this.MsBuildIssuesSettings); + provider.Initialize(this.RepositorySettings); + return provider; + } + + public IEnumerable ReadIssues() + { + var issueProvider = this.Create(); + return issueProvider.ReadIssues(IssueCommentFormat.PlainText); + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs new file mode 100644 index 0000000..0e08b9a --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs @@ -0,0 +1,39 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using Cake.Testing; + using Testing; + using Xunit; + + public class MsBuildIssuesProviderTests + { + public sealed class TheMsBuildCodeAnalysisProviderCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => + new MsBuildIssuesProvider( + null, + MsBuildIssuesSettings.FromContent( + "Foo", + new XmlFileLoggerFormat(new FakeLog())))); + + // Then + result.IsArgumentNullException("log"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + var result = Record.Exception(() => + new MsBuildIssuesProvider( + new FakeLog(), + null)); + + // Then + result.IsArgumentNullException("settings"); + } + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs new file mode 100644 index 0000000..1d70647 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs @@ -0,0 +1,163 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using System; + using System.IO; + using System.Linq; + using System.Text; + using Cake.Testing; + using Shouldly; + using Testing; + using Xunit; + + public class MsBuildIssuesSettingsTests + { + public sealed class TheMsBuildCodeAnalysisSettingsCtor + { + [Fact] + public void Should_Throw_If_LogFilePath_Is_Null() + { + // Given / When + var result = Record.Exception(() => + MsBuildIssuesSettings.FromFilePath( + null, + new XmlFileLoggerFormat(new FakeLog()))); + + // Then + result.IsArgumentNullException("logFilePath"); + } + + [Fact] + public void Should_Throw_If_Format_For_LogFilePath_Is_Null() + { + // Given / When + var result = Record.Exception(() => + MsBuildIssuesSettings.FromFilePath( + @"C:\foo.log", + null)); + + // Then + result.IsArgumentNullException("format"); + } + + [Fact] + public void Should_Throw_If_LogFileContent_Is_Null() + { + // Given / When + var result = Record.Exception(() => + MsBuildIssuesSettings.FromContent( + null, + new XmlFileLoggerFormat(new FakeLog()))); + + // Then + result.IsArgumentNullException("logFileContent"); + } + + [Fact] + public void Should_Throw_If_LogFileContent_Is_Empty() + { + // Given / When + var result = Record.Exception(() => + MsBuildIssuesSettings.FromContent( + string.Empty, + new XmlFileLoggerFormat(new FakeLog()))); + + // Then + result.IsArgumentOutOfRangeException("logFileContent"); + } + + [Fact] + public void Should_Throw_If_LogFileContent_Is_WhiteSpace() + { + // Given / When + var result = Record.Exception(() => + MsBuildIssuesSettings.FromContent( + " ", + new XmlFileLoggerFormat(new FakeLog()))); + + // Then + result.IsArgumentOutOfRangeException("logFileContent"); + } + + [Fact] + public void Should_Throw_If_Format_For_LogFileContent_Is_Null() + { + // Given / When + var result = Record.Exception(() => + MsBuildIssuesSettings.FromContent( + "foo", + null)); + + // Then + result.IsArgumentNullException("format"); + } + + [Fact] + public void Should_Set_Property_Values_Passed_To_Constructor() + { + // Given + const string logFileContent = "foo"; + var format = new XmlFileLoggerFormat(new FakeLog()); + + // When + var settings = MsBuildIssuesSettings.FromContent(logFileContent, format); + + // Then + settings.LogFileContent.ShouldBe(logFileContent); + settings.Format.ShouldBe(format); + } + + [Fact] + public void Should_Read_File_From_Disk() + { + var fileName = Path.GetTempFileName(); + try + { + // Given + string expected; + using (var ms = new MemoryStream()) + using (var stream = this.GetType().Assembly.GetManifestResourceStream("Cake.Issues.MsBuild.Tests.Testfiles.IssueWithFile.xml")) + { + stream.CopyTo(ms); + var data = ms.ToArray(); + + using (var file = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + { + file.Write(data, 0, data.Length); + } + + expected = ConvertFromUtf8(data); + } + + // When + var settings = + MsBuildIssuesSettings.FromFilePath( + fileName, + new XmlFileLoggerFormat(new FakeLog())); + + // Then + settings.LogFileContent.ShouldBe(expected); + } + finally + { + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + } + } + + private static string ConvertFromUtf8(byte[] bytes) + { + var enc = new UTF8Encoding(true); + var preamble = enc.GetPreamble(); + + if (preamble.Where((p, i) => p != bytes[i]).Any()) + { + throw new ArgumentException("Not utf8-BOM"); + } + + return enc.GetString(bytes.Skip(preamble.Length).ToArray()); + } + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs new file mode 100644 index 0000000..c0ed31d --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs @@ -0,0 +1,96 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using System; + using Shouldly; + using Testing; + using Xunit; + + public class MsBuildRuleUrlResolverTests + { + public sealed class TheResolveRuleUrlMethod + { + [Fact] + public void Should_Throw_If_Rule_Is_Null() + { + // Given / When + var result = Record.Exception(() => MsBuildRuleUrlResolver.Instance.ResolveRuleUrl(null)); + + // Then + result.IsArgumentNullException("rule"); + } + + [Fact] + public void Should_Throw_If_Rule_Is_Empty() + { + // Given / When + var result = Record.Exception(() => MsBuildRuleUrlResolver.Instance.ResolveRuleUrl(string.Empty)); + + // Then + result.IsArgumentOutOfRangeException("rule"); + } + + [Fact] + public void Should_Throw_If_Rule_Is_WhiteSpace() + { + // Given / When + var result = Record.Exception(() => MsBuildRuleUrlResolver.Instance.ResolveRuleUrl(" ")); + + // Then + result.IsArgumentOutOfRangeException("rule"); + } + + [Theory] + [InlineData("CA2201", "https://www.google.im/search?q=\"CA2201:\"+site:msdn.microsoft.com")] + [InlineData("SA1652", "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1652.md")] + public void Should_Resolve_Url(string rule, string expectedUrl) + { + // Given + var urlResolver = MsBuildRuleUrlResolver.Instance; + + // When + var ruleUrl = urlResolver.ResolveRuleUrl(rule); + + // Then + ruleUrl.ToString().ShouldBe(expectedUrl); + } + + [Theory] + [InlineData("CA")] + [InlineData("2201")] + [InlineData("CA2201Foo")] + [InlineData("CS0219")] + public void Should_Return_Null_For_Unknown_Rules(string rule) + { + // Given + var urlResolver = MsBuildRuleUrlResolver.Instance; + + // When + var ruleUrl = urlResolver.ResolveRuleUrl(rule); + + // Then + ruleUrl.ShouldBeNull(); + } + + [Fact] + public void Should_Resolve_Url_From_Custom_Resolvers() + { + // Given + const string foo = "FOO123"; + const string fooUrl = "http://foo.com/"; + const string bar = "BAR123"; + const string barUrl = "http://bar.com/"; + var urlResolver = MsBuildRuleUrlResolver.Instance; + urlResolver.AddUrlResolver(x => x.Rule == foo ? new Uri(fooUrl) : null); + urlResolver.AddUrlResolver(x => x.Rule == bar ? new Uri(barUrl) : null); + + // When + var fooRuleUrl = urlResolver.ResolveRuleUrl(foo); + var barRuleUrl = urlResolver.ResolveRuleUrl(bar); + + // Then + fooRuleUrl.ToString().ShouldBe(fooUrl); + barRuleUrl.ToString().ShouldBe(barUrl); + } + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/Properties/AssemblyInfo.cs b/src/Cake.Issues.MsBuild.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c2f0bc3 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/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("Cake.Issues.MsBuild")] +[assembly: AssemblyDescription("MsBuild support for the Cake.Issues Addin for Cake Build Automation System")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("BBT Software AG")] +[assembly: AssemblyProduct("Cake.Issues")] +[assembly: AssemblyCopyright("Copyright © 2017 BBT Software AG, Root/Zermatt, Switzerland")] +[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("c69329f6-a4d1-4e33-bd9d-5e59973be781")] + +// 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")] diff --git a/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithFile.xml b/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithFile.xml new file mode 100644 index 0000000..f4cc173 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithFile.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithOnlyFileName.xml b/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithOnlyFileName.xml new file mode 100644 index 0000000..965aea2 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithOnlyFileName.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithoutFile.xml b/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithoutFile.xml new file mode 100644 index 0000000..fd20b4d --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/Testfiles/IssueWithoutFile.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.Tests/XmlFileLoggerFormatTests.cs b/src/Cake.Issues.MsBuild.Tests/XmlFileLoggerFormatTests.cs new file mode 100644 index 0000000..d07e4dd --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/XmlFileLoggerFormatTests.cs @@ -0,0 +1,115 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using System.Linq; + using Core.IO; + using IssueProvider; + using Shouldly; + using Testing; + using Xunit; + + public class XmlFileLoggerFormatTests + { + public sealed class TheXmlFileLoggerFormatCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given / When + var result = Record.Exception(() => new XmlFileLoggerFormat(null)); + + // Then + result.IsArgumentNullException("log"); + } + } + + public sealed class TheReadIssuesMethod + { + [Fact] + public void Should_Read_Issue_With_File_Correct() + { + // Given + var fixture = new MsBuildIssuesProviderFixture("IssueWithFile.xml"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + var issue = issues.Single(); + CheckIssue( + issue, + @"src\Cake.Issues.MsBuild.Tests\MsBuildIssuesProviderTests.cs", + 1311, + "CA2201", + 0, + @"Microsoft.Usage : 'ConfigurationManager.GetSortedConfigFiles(String)' creates an exception of type 'ApplicationException', an exception type that is not sufficiently specific and should never be raised by user code. If this exception instance might be thrown, use a different exception type."); + } + + [Fact] + public void Should_Read_Issue_With_File_Without_Path_Correct() + { + // Given + var fixture = new MsBuildIssuesProviderFixture("IssueWithOnlyFileName.xml"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + var issue = issues.Single(); + CheckIssue( + issue, + @"src\Cake.Issues.MsBuild.Tests\MsBuildIssuesProviderTests.cs", + 13, + "CS0219", + 0, + "The variable 'foo' is assigned but its value is never used"); + } + + [Fact] + public void Should_Read_Issue_Without_File_Correct() + { + // Given + var fixture = new MsBuildIssuesProviderFixture("IssueWithoutFile.xml"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(1); + var issue = issues.Single(); + CheckIssue( + issue, + null, + null, + "CA1711", + 0, + "Microsoft.Naming : Rename type name 'UniqueQueue(Of T)' so that it does not end in 'Queue'."); + } + + private static void CheckIssue( + IIssue issue, + string affectedFileRelativePath, + int? line, + string rule, + int priority, + string message) + { + if (issue.AffectedFileRelativePath == null) + { + affectedFileRelativePath.ShouldBeNull(); + } + else + { + issue.AffectedFileRelativePath.ToString().ShouldBe(new FilePath(affectedFileRelativePath).ToString()); + issue.AffectedFileRelativePath.IsRelative.ShouldBe(true, "Issue path is not relative"); + } + + issue.Line.ShouldBe(line); + issue.Rule.ShouldBe(rule); + issue.Priority.ShouldBe(priority); + issue.Message.ShouldBe(message); + } + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/packages.config b/src/Cake.Issues.MsBuild.Tests/packages.config new file mode 100644 index 0000000..d8c638c --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/packages.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.ruleset b/src/Cake.Issues.MsBuild.ruleset new file mode 100644 index 0000000..1d18efa --- /dev/null +++ b/src/Cake.Issues.MsBuild.ruleset @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.sln b/src/Cake.Issues.MsBuild.sln new file mode 100644 index 0000000..d8f23a9 --- /dev/null +++ b/src/Cake.Issues.MsBuild.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26730.8 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.Issues.MsBuild", "Cake.Issues.MsBuild\Cake.Issues.MsBuild.csproj", "{1A6C74CE-4775-458A-B013-BDE1986C5B88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.Issues.MsBuild.Tests", "Cake.Issues.MsBuild.Tests\Cake.Issues.MsBuild.Tests.csproj", "{C69329F6-A4D1-4E33-BD9D-5E59973BE781}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2EBEB9BA-3A3B-4EDC-95C0-44DD001AFFDC}" + ProjectSection(SolutionItems) = preProject + ..\setup.cake = ..\setup.cake + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuspec", "nuspec", "{3E340FDE-17DA-429E-BC41-AA5F5F5271DB}" + ProjectSection(SolutionItems) = preProject + ..\nuspec\nuget\Cake.Issues.MsBuild.nuspec = ..\nuspec\nuget\Cake.Issues.MsBuild.nuspec + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1A6C74CE-4775-458A-B013-BDE1986C5B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A6C74CE-4775-458A-B013-BDE1986C5B88}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1A6C74CE-4775-458A-B013-BDE1986C5B88}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1A6C74CE-4775-458A-B013-BDE1986C5B88}.Release|Any CPU.Build.0 = Release|Any CPU + {C69329F6-A4D1-4E33-BD9D-5E59973BE781}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C69329F6-A4D1-4E33-BD9D-5E59973BE781}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C69329F6-A4D1-4E33-BD9D-5E59973BE781}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C69329F6-A4D1-4E33-BD9D-5E59973BE781}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3E340FDE-17DA-429E-BC41-AA5F5F5271DB} = {2EBEB9BA-3A3B-4EDC-95C0-44DD001AFFDC} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {896FC38E-24E4-4A35-8CF6-01E8EADDB346} + EndGlobalSection +EndGlobal diff --git a/src/Cake.Issues.MsBuild.sln.DotSettings b/src/Cake.Issues.MsBuild.sln.DotSettings new file mode 100644 index 0000000..7cc51a4 --- /dev/null +++ b/src/Cake.Issues.MsBuild.sln.DotSettings @@ -0,0 +1,3 @@ + + DO_NOT_SHOW + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj b/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj new file mode 100644 index 0000000..e64a533 --- /dev/null +++ b/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {1A6C74CE-4775-458A-B013-BDE1986C5B88} + Library + Properties + Cake.Issues.MsBuild + Cake.Issues.MsBuild + v4.5.2 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + bin\Debug\Cake.Issues.MsBuild.xml + ..\Cake.Issues.MsBuild.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\Cake.Issues.MsBuild.xml + ..\Cake.Issues.MsBuild.ruleset + + + + ..\packages\Cake.Core.0.16.2\lib\net45\Cake.Core.dll + + + ..\packages\Cake.Issues.0.1.0-beta0001\lib\net45\Cake.Issues.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild/ILogFileFormat.cs b/src/Cake.Issues.MsBuild/ILogFileFormat.cs new file mode 100644 index 0000000..9cf4ab3 --- /dev/null +++ b/src/Cake.Issues.MsBuild/ILogFileFormat.cs @@ -0,0 +1,21 @@ +namespace Cake.Issues.MsBuild +{ + using System.Collections.Generic; + using IssueProvider; + + /// + /// Definition of a MsBuild log file format. + /// + public interface ILogFileFormat + { + /// + /// Gets all code analysis issues. + /// + /// Repository settings to use. + /// Settings for code analysis provider to use. + /// List of code analysis issues + IEnumerable ReadIssues( + RepositorySettings repositorySettings, + MsBuildIssuesSettings msBuildIssuesSettings); + } +} diff --git a/src/Cake.Issues.MsBuild/LogFileFormat.cs b/src/Cake.Issues.MsBuild/LogFileFormat.cs new file mode 100644 index 0000000..d431edf --- /dev/null +++ b/src/Cake.Issues.MsBuild/LogFileFormat.cs @@ -0,0 +1,33 @@ +namespace Cake.Issues.MsBuild +{ + using System.Collections.Generic; + using Core.Diagnostics; + using IssueProvider; + + /// + /// Base class for all MsBuild log file format implementations. + /// + public abstract class LogFileFormat : ILogFileFormat + { + /// + /// Initializes a new instance of the class. + /// + /// The Cake log instance. + protected LogFileFormat(ICakeLog log) + { + log.NotNull(nameof(log)); + + this.Log = log; + } + + /// + /// Gets the Cake log instance. + /// + protected ICakeLog Log { get; private set; } + + /// + public abstract IEnumerable ReadIssues( + RepositorySettings repositorySettings, + MsBuildIssuesSettings msBuildIssuesSettings); + } +} diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs new file mode 100644 index 0000000..a3870ef --- /dev/null +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs @@ -0,0 +1,234 @@ +namespace Cake.Issues.MsBuild +{ + using System; + using Core; + using Core.Annotations; + using Core.IO; + using IssueProvider; + + /// + /// Contains functionality related to importing code analysis issues from MSBuild logs to write them to + /// pull requests. + /// + [CakeAliasCategory(IssuesAliasConstants.MainCakeAliasCategory)] + public static class MsBuildIssuesAliases + { + /// + /// Registers a new URL resolver with default priority of 0. + /// + /// The context. + /// Resolver which returns an linking to a site + /// containing help for a specific . + /// + /// Adds a provider with default priority of 0 returning a link for all rules of the category CA to + /// search msdn.microsoft.com with Google for the rule: + /// + /// + /// x.Category.ToUpperInvariant() == "CA" ? + /// new Uri("https://www.google.com/search?q=%22" + x.Rule + ":%22+site:msdn.microsoft.com") : + /// null) + /// ]]> + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static void MsBuildAddRuleUrlResolver( + this ICakeContext context, + Func resolver) + { + context.NotNull(nameof(context)); + resolver.NotNull(nameof(resolver)); + + MsBuildRuleUrlResolver.Instance.AddUrlResolver(resolver); + } + + /// + /// Registers a new URL resolver with a specific priority. + /// + /// The context. + /// Resolver which returns an linking to a site + /// containing help for a specific . + /// Priority of the resolver. Resolver with a higher priority are considered + /// first during resolving of the URL. + /// + /// Adds a provider of priority 5 returning a link for all rules of the category CA to + /// search msdn.microsoft.com with Google for the rule: + /// + /// + /// x.Category.ToUpperInvariant() == "CA" ? + /// new Uri("https://www.google.com/search?q=%22" + x.Rule + ":%22+site:msdn.microsoft.com") : + /// null, + /// 5) + /// ]]> + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static void MsBuildAddRuleUrlResolver( + this ICakeContext context, + Func resolver, + int priority) + { + context.NotNull(nameof(context)); + resolver.NotNull(nameof(resolver)); + + MsBuildRuleUrlResolver.Instance.AddUrlResolver(resolver, priority); + } + + /// + /// + /// Gets an instance for the MsBuild log format as written by the XmlFileLogger class + /// from MSBuild Extension Pack. + /// + /// + /// You can add the logger to the MSBuildSettings like this: + /// + /// var settings = new MsBuildSettings() + /// .WithLogger( + /// Context.Tools.Resolve("MSBuild.ExtensionPack.Loggers.dll").FullPath, + /// "XmlFileLogger", + /// string.Format( + /// "logfile=\"{0}\";verbosity=Detailed;encoding=UTF-8", + /// @"C:\build\msbuild.log") + /// ) + /// + /// + /// + /// In order to use the above logger, include the following in your build.cake file to download and + /// install from NuGet.org: + /// + /// #tool "nuget:?package=MSBuild.Extension.Pack" + /// + /// + /// + /// The context. + /// Instance for the MsBuild log format. + [CakePropertyAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static ILogFileFormat MsBuildXmlFileLoggerFormat( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return new XmlFileLoggerFormat(context.Log); + } + + /// + /// Gets an instance of a provider for code analysis issues reported as MsBuild warnings using a log file from disk. + /// + /// The context. + /// Path to the the MsBuild log file. + /// The log file needs to be in the format as defined by the parameter. + /// Format of the provided MsBuild log file. + /// Instance of a provider for code analysis issues reported as MsBuild warnings. + /// + /// Report code analysis issues reported as MsBuild warnings to a TFS pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider MsBuildIssuesFromFilePath( + this ICakeContext context, + FilePath logFilePath, + ILogFileFormat format) + { + context.NotNull(nameof(context)); + logFilePath.NotNull(nameof(logFilePath)); + format.NotNull(nameof(format)); + + return context.MsBuildIssues(MsBuildIssuesSettings.FromFilePath(logFilePath, format)); + } + + /// + /// Gets an instance of a provider for code analysis issues reported as MsBuild warnings using log content. + /// + /// The context. + /// Content of the the MsBuild log file. + /// The log file needs to be in the format as defined by the parameter. + /// Format of the provided MsBuild log file. + /// Instance of a provider for code analysis issues reported as MsBuild warnings. + /// + /// Report code analysis issues reported as MsBuild warnings to a TFS pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider MsBuildIssuesFromContent( + this ICakeContext context, + string logFileContent, + ILogFileFormat format) + { + context.NotNull(nameof(context)); + logFileContent.NotNullOrWhiteSpace(nameof(logFileContent)); + format.NotNull(nameof(format)); + + return context.MsBuildIssues(MsBuildIssuesSettings.FromContent(logFileContent, format)); + } + + /// + /// Gets an instance of a provider for code analysis issues reported as MsBuild warnings using specified settings. + /// + /// The context. + /// Settings for reading the MSBuild log. + /// Instance of a provider for code analysis issues reported as MsBuild warnings. + /// + /// Report code analysis issues reported as MsBuild warnings to a TFS pull request: + /// + /// + /// + /// + [CakeMethodAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static IIssueProvider MsBuildIssues( + this ICakeContext context, + MsBuildIssuesSettings settings) + { + context.NotNull(nameof(context)); + settings.NotNull(nameof(settings)); + + return new MsBuildIssuesProvider(context.Log, settings); + } + } +} diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs new file mode 100644 index 0000000..f50ee4c --- /dev/null +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs @@ -0,0 +1,33 @@ +namespace Cake.Issues.MsBuild +{ + using System.Collections.Generic; + using Core.Diagnostics; + using IssueProvider; + + /// + /// Provider for code analysis issues reported as MsBuild warnings. + /// + internal class MsBuildIssuesProvider : IssueProvider + { + private readonly MsBuildIssuesSettings msBuildIssuesSettings; + + /// + /// Initializes a new instance of the class. + /// + /// The Cake log context. + /// Settings for reading the log file. + public MsBuildIssuesProvider(ICakeLog log, MsBuildIssuesSettings settings) + : base(log) + { + settings.NotNull(nameof(settings)); + + this.msBuildIssuesSettings = settings; + } + + /// + protected override IEnumerable InternalReadIssues(IssueCommentFormat format) + { + return this.msBuildIssuesSettings.Format.ReadIssues(this.Settings, this.msBuildIssuesSettings); + } + } +} diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesSettings.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesSettings.cs new file mode 100644 index 0000000..892eb91 --- /dev/null +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesSettings.cs @@ -0,0 +1,83 @@ +namespace Cake.Issues.MsBuild +{ + using System.IO; + using Core.IO; + + /// + /// Settings for . + /// + public class MsBuildIssuesSettings + { + /// + /// Initializes a new instance of the class. + /// + /// Path to the the MsBuild log file. + /// The log file needs to be in the format as defined by the parameter. + /// Format of the provided MsBuild log file. + protected MsBuildIssuesSettings(FilePath logFilePath, ILogFileFormat format) + { + logFilePath.NotNull(nameof(logFilePath)); + format.NotNull(nameof(format)); + + this.Format = format; + + using (var stream = new FileStream(logFilePath.FullPath, FileMode.Open, FileAccess.Read)) + { + using (var sr = new StreamReader(stream)) + { + this.LogFileContent = sr.ReadToEnd(); + } + } + } + + /// + /// Initializes a new instance of the class. + /// + /// Content of the the MsBuild log file. + /// The log file needs to be in the format as defined by the parameter. + /// Format of the provided MsBuild log file. + protected MsBuildIssuesSettings(string logFileContent, ILogFileFormat format) + { + logFileContent.NotNullOrWhiteSpace(nameof(logFileContent)); + format.NotNull(nameof(format)); + + this.LogFileContent = logFileContent; + this.Format = format; + } + + /// + /// Gets the format of the MsBuild log file. + /// + public ILogFileFormat Format { get; private set; } + + /// + /// Gets the content of the log file. + /// + public string LogFileContent { get; private set; } + + /// + /// Returns a new instance of the class from a log file on disk. + /// + /// Path to the MsBuild log file. + /// The log file needs to be in the format as defined by the parameter. + /// Format of the provided MsBuild log file. + /// Instance of the class. + public static MsBuildIssuesSettings FromFilePath(FilePath logFilePath, ILogFileFormat format) + { + return new MsBuildIssuesSettings(logFilePath, format); + } + + /// + /// Returns a new instance of the class from the content + /// of a MsBuild log file. + /// + /// Content of the MsBuild log file. + /// The log file needs to be in the format as defined by the parameter. + /// Format of the provided MsBuild log file. + /// Instance of the class. + public static MsBuildIssuesSettings FromContent(string logFileContent, ILogFileFormat format) + { + return new MsBuildIssuesSettings(logFileContent, format); + } + } +} diff --git a/src/Cake.Issues.MsBuild/MsBuildRuleDescription.cs b/src/Cake.Issues.MsBuild/MsBuildRuleDescription.cs new file mode 100644 index 0000000..e25c270 --- /dev/null +++ b/src/Cake.Issues.MsBuild/MsBuildRuleDescription.cs @@ -0,0 +1,20 @@ +namespace Cake.Issues.MsBuild +{ + using IssueProvider; + + /// + /// Class describing rules appearing in MsBuild logs. + /// + public class MsBuildRuleDescription : BaseRuleDescription + { + /// + /// Gets or sets the category of the rule. + /// + public string Category { get; set; } + + /// + /// Gets or sets the identifier of the rule. + /// + public int RuleId { get; set; } + } +} \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild/MsBuildRuleUrlResolver.cs b/src/Cake.Issues.MsBuild/MsBuildRuleUrlResolver.cs new file mode 100644 index 0000000..b59fd66 --- /dev/null +++ b/src/Cake.Issues.MsBuild/MsBuildRuleUrlResolver.cs @@ -0,0 +1,74 @@ +namespace Cake.Issues.MsBuild +{ + using System; + using System.Text; + using IssueProvider; + + /// + /// Class for retrieving an URL linking to a site describing a rule. + /// + internal class MsBuildRuleUrlResolver : BaseRuleUrlResolver + { + private static readonly Lazy InstanceValue = + new Lazy(() => new MsBuildRuleUrlResolver()); + + /// + /// Initializes a new instance of the class. + /// + private MsBuildRuleUrlResolver() + { + // Add resolver for common known issue categories. + this.AddUrlResolver(x => + x.Category.ToUpperInvariant() == "CA" ? + new Uri("https://www.google.im/search?q=%22" + x.Rule + ":%22+site:msdn.microsoft.com") : + null); + this.AddUrlResolver(x => + x.Category.ToUpperInvariant() == "SA" ? + new Uri("https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/" + x.Rule + ".md") : + null); + } + + /// + /// Gets the instance of the rule resolver. + /// + public static MsBuildRuleUrlResolver Instance => InstanceValue.Value; + + /// + protected override bool TryGetRuleDescription(string rule, MsBuildRuleDescription ruleDescription) + { + // Parse the rule. Expect it in the form starting with a identifier containing characters + // followed by the rule id as a number. + var digitIndex = -1; + var categoryBuilder = new StringBuilder(); + for (var index = 0; index < rule.Length; index++) + { + var currentChar = rule[index]; + if (char.IsDigit(currentChar)) + { + digitIndex = index; + break; + } + + categoryBuilder.Append(currentChar); + } + + // If rule doesn't contain numbers return false. + if (digitIndex < 0) + { + return false; + } + + // Try to parse the part after the first number to an integer. + int ruleId; + if (!int.TryParse(rule.Substring(digitIndex), out ruleId)) + { + return false; + } + + ruleDescription.RuleId = ruleId; + ruleDescription.Category = categoryBuilder.ToString(); + + return true; + } + } +} diff --git a/src/Cake.Issues.MsBuild/Properties/AssemblyInfo.cs b/src/Cake.Issues.MsBuild/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..cf1a87a --- /dev/null +++ b/src/Cake.Issues.MsBuild/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +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("Cake.Issues.MsBuild")] +[assembly: AssemblyDescription("MsBuild support for the Cake.Issues Addin for Cake Build Automation System")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("BBT Software AG")] +[assembly: AssemblyProduct("Cake.Issues")] +[assembly: AssemblyCopyright("Copyright © 2017 BBT Software AG, Root/Zermatt, Switzerland")] +[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("1a6c74ce-4775-458a-b013-bde1986c5b88")] + +// 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")] + +[assembly: CLSCompliant(true)] +[assembly: InternalsVisibleTo("Cake.Issues.MsBuild.Tests")] diff --git a/src/Cake.Issues.MsBuild/XmlFileLoggerFormat.cs b/src/Cake.Issues.MsBuild/XmlFileLoggerFormat.cs new file mode 100644 index 0000000..09238d7 --- /dev/null +++ b/src/Cake.Issues.MsBuild/XmlFileLoggerFormat.cs @@ -0,0 +1,178 @@ +namespace Cake.Issues.MsBuild +{ + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Xml.Linq; + using Core.Diagnostics; + using IssueProvider; + + /// + /// MsBuild log format as written by the XmlFileLogger class from MSBuild Extension Pack. + /// + internal class XmlFileLoggerFormat : LogFileFormat + { + /// + /// Initializes a new instance of the class. + /// + /// The Cake log instance. + public XmlFileLoggerFormat(ICakeLog log) + : base(log) + { + } + + /// + public override IEnumerable ReadIssues( + RepositorySettings repositorySettings, + MsBuildIssuesSettings msBuildIssuesSettings) + { + repositorySettings.NotNull(nameof(repositorySettings)); + msBuildIssuesSettings.NotNull(nameof(msBuildIssuesSettings)); + + var result = new List(); + + var logDocument = XDocument.Parse(msBuildIssuesSettings.LogFileContent); + + // Loop through all warning tags. + foreach (var warning in logDocument.Descendants("warning")) + { + // Read affected file from the warning. + if (!this.TryGetFile(warning, repositorySettings, out string fileName)) + { + continue; + } + + // Read affected line from the warning. + if (!TryGetLine(warning, out var line)) + { + continue; + } + + // Read rule code from the warning. + if (!TryGetRule(warning, out string rule)) + { + continue; + } + + result.Add(new Issue( + fileName, + line, + warning.Value, + 0, + rule, + MsBuildRuleUrlResolver.Instance.ResolveRuleUrl(rule))); + } + + return result; + } + + /// + /// Reads the affected line from a warning logged in a MsBuild log. + /// + /// Warning element from MsBuild log. + /// Returns line. + /// True if the line could be parsed. + private static bool TryGetLine(XElement warning, out int? line) + { + line = null; + + var lineAttr = warning.Attribute("line"); + + var lineValue = lineAttr?.Value; + if (string.IsNullOrWhiteSpace(lineValue)) + { + return false; + } + + line = int.Parse(lineValue, CultureInfo.InvariantCulture); + + // Convert negative lines numbers to null + if (line < 0) + { + line = null; + } + + return true; + } + + /// + /// Reads the rule code from a warning logged in a MsBuild log. + /// + /// Warning element from MsBuild log. + /// Returns the code of the rule. + /// True if the rule code could be parsed. + private static bool TryGetRule(XElement warning, out string rule) + { + rule = string.Empty; + + var codeAttr = warning.Attribute("code"); + if (codeAttr == null) + { + return false; + } + + rule = codeAttr.Value; + return !string.IsNullOrWhiteSpace(rule); + } + + /// + /// Reads the affected file path from a warning logged in a MsBuild log. + /// + /// Warning element from MsBuild log. + /// Repository settings to use. + /// Returns the full path to the affected file. + /// True if the file path could be parsed. + private bool TryGetFile( + XElement warning, + RepositorySettings repositorySettings, + out string fileName) + { + fileName = string.Empty; + + var fileAttr = warning.Attribute("file"); + if (fileAttr == null) + { + return true; + } + + fileName = fileAttr.Value; + if (string.IsNullOrWhiteSpace(fileName)) + { + return true; + } + + // If not absolute path, combine with file path from compile task. + if (!fileName.IsFullPath()) + { + var parentFileAttr = warning.Parent?.Attribute("file"); + if (parentFileAttr != null) + { + var compileTaskDirectory = Path.GetDirectoryName(parentFileAttr.Value); + fileName = Path.Combine(compileTaskDirectory, fileName); + } + } + + // Ignore files from outside the repository. + if (!fileName.IsSubpathOf(repositorySettings.RepositoryRoot.FullPath)) + { + this.Log.Warning( + "Ignored issue for file '{0}' since it is outside the repository folder at {1}.", + fileName, + repositorySettings.RepositoryRoot); + + return false; + } + + // Make path relative to repository root. + fileName = fileName.Substring(repositorySettings.RepositoryRoot.FullPath.Length); + + // Remove leading directory separator. + if (fileName.StartsWith(Path.DirectorySeparatorChar.ToString())) + { + fileName = fileName.Substring(1); + } + + return true; + } + } +} diff --git a/src/Cake.Issues.MsBuild/packages.config b/src/Cake.Issues.MsBuild/packages.config new file mode 100644 index 0000000..d7a63d1 --- /dev/null +++ b/src/Cake.Issues.MsBuild/packages.config @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/packages.config b/tools/packages.config new file mode 100644 index 0000000..3b95cb1 --- /dev/null +++ b/tools/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file