diff --git a/LICENSE b/LICENSE index e052ef6..7fcbf6e 100644 --- a/LICENSE +++ b/LICENSE @@ -19,3 +19,164 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- + +The binary distribution of this package on nuget.org incorporates material from the projects listed below: + +--- + +MSBuild.StructuredLogger + +The MIT License (MIT) + +Copyright (c) 2016 Kirill Osenkov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +Microsoft.Build.Framework & Microsoft.Build.Utilities.Core + +MICROSOFT SOFTWARE LICENSE TERMS + +MICROSOFT .NET LIBRARY + +These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. They apply to the software named above. The terms also apply to any Microsoft services or updates for the software, except to the extent those have different terms. + +If you comply with these license terms, you have the rights below. +1. INSTALLATION AND USE RIGHTS. + +You may install and use any number of copies of the software to design, develop and test you’re applications. You may modify, copy, distribute or deploy any .js files contained in the software as part of your applications. +2. THIRD PARTY COMPONENTS. The software may include third party components with separate legal notices or governed by other agreements, as may be described in the ThirdPartyNotices file(s) accompanying the software. +3. ADDITIONAL LICENSING REQUIREMENTS AND/OR USE RIGHTS. +a. DISTRIBUTABLE CODE. In addition to the .js files described above, the software is comprised of Distributable Code. “Distributable Code” is code that you are permitted to distribute in programs you develop if you comply with the terms below. +i. Right to Use and Distribute. + +· You may copy and distribute the object code form of the software. + +· Third Party Distribution. You may permit distributors of your programs to copy and distribute the Distributable Code as part of those programs. +ii. Distribution Requirements. For any Distributable Code you distribute, you must + +· use the Distributable Code in your programs and not as a standalone distribution; + +· require distributors and external end users to agree to terms that protect it at least as much as this agreement; + +· display your valid copyright notice on your programs; and + +· indemnify, defend, and hold harmless Microsoft from any claims, including attorneys’ fees, related to the distribution or use of your applications, except to the extent that any claim is based solely on the Distributable Code. +iii. Distribution Restrictions. You may not + +· alter any copyright, trademark or patent notice in the Distributable Code; + +· use Microsoft’s trademarks in your programs’ names or in a way that suggests your programs come from or are endorsed by Microsoft; + +· include Distributable Code in malicious, deceptive or unlawful programs; or + +· modify or distribute the source code of any Distributable Code so that any part of it becomes subject to an Excluded License. An Excluded License is one that requires, as a condition of use, modification or distribution, that + +· the code be disclosed or distributed in source code form; or + +· others have the right to modify it. +4. DATA. +a. Data Collection. The software may collect information about you and your use of the software, and send that to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may opt-out of many of these scenarios, but not all, as described in the product documentation. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. +b. Processing of Personal Data. To the extent Microsoft is a processor or subprocessor of personal data in connection with the software, Microsoft makes the commitments in the European Union General Data Protection Regulation Terms of the Online Services Terms to all customers effective May 25, 2018, at http://go.microsoft.com/?linkid=9840733. +5. Scope of License. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not + +· work around any technical limitations in the software; + +· reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software, except and to the extent required by third party licensing terms governing use of certain open source components that may be included in the software; + +· remove, minimize, block or modify any notices of Microsoft or its suppliers in the software; + +· use the software in any way that is against the law; or + +· share, publish, rent or lease the software, provide the software as a stand-alone offering for others to use, or transfer the software or this agreement to any third party. +6. Export Restrictions. You must comply with all domestic and international export laws and regulations that apply to the software, which include restrictions on destinations, end users, and end use. For further information on export restrictions, visit www.microsoft.com/exporting. +7. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it. +8. Entire Agreement. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services. +9. Applicable Law. If you acquired the software in the United States, Washington law applies to interpretation of and claims for breach of this agreement, and the laws of the state where you live apply to all other claims. If you acquired the software in any other country, its laws apply. +10. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state or country. Separate and apart from your relationship with Microsoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state or country do not permit it to do so. For example, if you acquired the software in one of the below regions, or mandatory country law applies, then the following provisions apply to you: +a) Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is intended to affect those rights. +b) Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the automatic update feature, disconnecting your device from the Internet (if and when you re-connect to the Internet, however, the software will resume checking for and installing updates), or uninstalling the software. The product documentation, if any, may also specify how to turn off updates for your specific device or software. +c) Germany and Austria. + +(i) Warranty. The software will perform substantially as described in any Microsoft materials that accompany it. However, Microsoft gives no contractual guarantee in relation to the software. + +(ii) Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as well as in case of death or personal or physical injury, Microsoft is liable according to the statutory law. +Subject to the foregoing clause (ii), Microsoft will only be liable for slight negligence if Microsoft is in breach of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence +11. Disclaimer of Warranty. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +12. Limitation on and Exclusion of Remedies and Damages. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES. + +This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law. + +It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your state or country may not allow the exclusion or limitation of incidental, consequential or other damages. + +Please note: As this software is distributed in Quebec, Canada, some of the clauses in this agreement are provided below in French. + + +Remarque : Ce logiciel étant distribué au Québec, Canada, certaines des clauses dans ce contrat sont fournies ci-dessous en français. + + + +EXONÉRATION DE GARANTIE. Le logiciel visé par une licence est offert « tel quel ». Toute utilisation de ce logiciel est à votre seule risque et péril. Microsoft n’accorde aucune autre garantie expresse. Vous pouvez bénéficier de droits additionnels en vertu du droit local sur la protection des consommateurs, que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les garanties implicites de qualité marchande, d’adéquation à un usage particulier et d’absence de contrefaçon sont exclues. + + +LIMITATION DES DOMMAGES-INTÉRÊTS ET EXCLUSION DE RESPONSABILITÉ POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et de ses fournisseurs une indemnisation en cas de dommages directs uniquement à hauteur de 5,00 $ US. Vous ne pouvez prétendre à aucune indemnisation pour les autres dommages, y compris les dommages spéciaux, indirects ou accessoires et pertes de bénéfices. + + +Cette limitation concerne: + +· tout ce qui est relié au logiciel, aux services ou au contenu (y compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ; et + +· les réclamations au titre de violation de contrat ou de garantie, ou au titre de responsabilité stricte, de négligence ou d’une autre faute dans la limite autorisée par la loi en vigueur. + + +Elle s’applique également, même si Microsoft connaissait ou devrait connaître l’éventualité d’un tel dommage. Si votre pays n’autorise pas l’exclusion ou la limitation de responsabilité pour les dommages indirects, accessoires ou de quelque nature que ce soit, il se peut que la limitation ou l’exclusion ci-dessus ne s’appliquera pas à votre égard. + + +EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous pourriez avoir d’autres droits prévus par les lois de votre pays. Le présent contrat ne modifie pas les droits que vous confèrent les lois de votre pays si celles-ci ne le permettent pas. + +--- + +System.Collections.Immutable + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/nuspec/nuget/Cake.Issues.MsBuild.nuspec b/nuspec/nuget/Cake.Issues.MsBuild.nuspec index b394655..2939bf3 100644 --- a/nuspec/nuget/Cake.Issues.MsBuild.nuspec +++ b/nuspec/nuget/Cake.Issues.MsBuild.nuspec @@ -19,16 +19,20 @@ See the Project Site for an overview of the whole ecosystem of addins for workin 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 + https://cdn.jsdelivr.net/gh/cake-contrib/graphics@a5cf0f881c390650144b2243ae551d5b9f836196/png/cake-contrib-medium.png false Copyright © 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.6.0 + https://github.com/cake-contrib/Cake.Issues.MsBuild/releases/tag/0.6.1 + + + + \ No newline at end of file diff --git a/setup.cake b/setup.cake index 2e76762..1e7f328 100644 --- a/setup.cake +++ b/setup.cake @@ -16,7 +16,7 @@ BuildParameters.PrintParameters(Context); ToolSettings.SetToolSettings( context: Context, - dupFinderExcludePattern: new string[] { BuildParameters.RootDirectoryPath + "/src/Cake.Issues.MsBuild.Tests/*.cs", BuildParameters.RootDirectoryPath + "/src/Cake.Issues.MsBuild*/**/*.AssemblyInfo.cs" }, + dupFinderExcludePattern: new string[] { BuildParameters.RootDirectoryPath + "/src/Cake.Issues.MsBuild.Tests/**/*.cs", BuildParameters.RootDirectoryPath + "/src/Cake.Issues.MsBuild*/**/*.AssemblyInfo.cs" }, testCoverageFilter: "+[*]* -[xunit.*]* -[Cake.Core]* -[Cake.Testing]* -[*.Tests]* -[Cake.Issues]* -[Cake.Issues.Testing]*", testCoverageExcludeByAttribute: "*.ExcludeFromCodeCoverage*", testCoverageExcludeByFile: "*/*Designer.cs;*/*.g.cs;*/*.g.i.cs"); diff --git a/src/Cake.Issues.MsBuild.Tests.ruleset b/src/Cake.Issues.MsBuild.Tests.ruleset index 73e07dc..a91faec 100644 --- a/src/Cake.Issues.MsBuild.Tests.ruleset +++ b/src/Cake.Issues.MsBuild.Tests.ruleset @@ -2,7 +2,9 @@ + + \ No newline at end of file diff --git a/src/Cake.Issues.MsBuild.Tests/BaseMsBuildLogFileFormatTests.cs b/src/Cake.Issues.MsBuild.Tests/BaseMsBuildLogFileFormatTests.cs new file mode 100644 index 0000000..e4a5d99 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/BaseMsBuildLogFileFormatTests.cs @@ -0,0 +1,338 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using Cake.Issues.Testing; + using Cake.Testing; + using Shouldly; + using Xunit; + + public sealed class BaseMsBuildLogFileFormatTests + { + public sealed class TheValidateFilePathMethod + { + [Fact] + public void Should_Throw_If_FilePath_Is_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + string filePath = null; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.ValidateFilePath(filePath, settings)); + + // Then + result.IsArgumentNullException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_Empty() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = string.Empty; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.ValidateFilePath(filePath, settings)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_WhiteSpace() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = " "; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.ValidateFilePath(filePath, settings)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = @"c:\repo\foo.ch"; + RepositorySettings settings = null; + + // When + var result = Record.Exception(() => format.ValidateFilePath(filePath, settings)); + + // Then + result.IsArgumentNullException("repositorySettings"); + } + + [Theory] + [InlineData(@"c:\foo\bar.cs", @"c:\foo\", true)] + [InlineData(@"c:\foo\bar.cs", @"c:\foo", true)] + [InlineData(@"c:\foo\bar.cs", @"c:\bar", false)] + public void Should_Return_Correct_Value_For_Valid( + string filePath, + string repoRoot, + bool expectedValue) + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var settings = new RepositorySettings(repoRoot); + + // When + var result = format.ValidateFilePath(filePath, settings); + + // Then + result.Valid.ShouldBe(expectedValue); + } + + [Theory] + [InlineData(@"c:\foo\bar.cs", @"c:\foo\", @"bar.cs")] + [InlineData(@"c:\foo\bar.cs", @"c:\foo", @"bar.cs")] + [InlineData(@"c:\foo\bar.cs", @"c:\bar", @"")] + public void Should_Return_Correct_Value_For_FilePath( + string filePath, + string repoRoot, + string expectedValue) + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var settings = new RepositorySettings(repoRoot); + + // When + var result = format.ValidateFilePath(filePath, settings); + + // Then + result.FilePath.ShouldBe(expectedValue); + } + } + + public sealed class TheCheckIfFileIsInRepositoryMethod + { + [Fact] + public void Should_Throw_If_FilePath_Is_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + string filePath = null; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.CheckIfFileIsInRepository(filePath, settings)); + + // Then + result.IsArgumentNullException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_Empty() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = string.Empty; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.CheckIfFileIsInRepository(filePath, settings)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_WhiteSpace() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = " "; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.CheckIfFileIsInRepository(filePath, settings)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = @"c:\repo\foo.ch"; + RepositorySettings settings = null; + + // When + var result = Record.Exception(() => format.CheckIfFileIsInRepository(filePath, settings)); + + // Then + result.IsArgumentNullException("repositorySettings"); + } + + [Theory] + [InlineData(@"c:\foo\bar.cs", @"c:\foo\", true)] + [InlineData(@"c:\foo\bar.cs", @"c:\foo", true)] + [InlineData(@"c:\foo\bar.cs", @"c:\bar", false)] + public void Should_Check_If_File_Is_In_Repository( + string filePath, + string repoRoot, + bool expectedValue) + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var settings = new RepositorySettings(repoRoot); + + // When + var result = format.CheckIfFileIsInRepository(filePath, settings); + + // Then + result.ShouldBe(expectedValue); + } + } + + public sealed class TheMakeFilePathRelativeToRepositoryRootMethod + { + [Fact] + public void Should_Throw_If_FilePath_Is_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + string filePath = null; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.MakeFilePathRelativeToRepositoryRoot(filePath, settings)); + + // Then + result.IsArgumentNullException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_Empty() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = string.Empty; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.MakeFilePathRelativeToRepositoryRoot(filePath, settings)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_WhiteSpace() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = " "; + var settings = new RepositorySettings(@"c:\repo"); + + // When + var result = Record.Exception(() => format.MakeFilePathRelativeToRepositoryRoot(filePath, settings)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_Settings_Are_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = @"c:\repo\foo.ch"; + RepositorySettings settings = null; + + // When + var result = Record.Exception(() => format.MakeFilePathRelativeToRepositoryRoot(filePath, settings)); + + // Then + result.IsArgumentNullException("repositorySettings"); + } + + [Theory] + [InlineData(@"c:\foo\bar.cs", @"c:\foo\", @"\bar.cs")] + [InlineData(@"c:\foo\bar.cs", @"c:\foo", @"\bar.cs")] + public void Should_Make_FilePath_Relative_To_Repository_Root( + string filePath, + string repoRoot, + string expectedValue) + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var settings = new RepositorySettings(repoRoot); + + // When + var result = format.MakeFilePathRelativeToRepositoryRoot(filePath, settings); + + // Then + result.ShouldBe(expectedValue); + } + } + + public sealed class TheRemoveLeadingDirectorySeparatorMethod + { + [Fact] + public void Should_Throw_If_FilePath_Is_Null() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + string filePath = null; + + // When + var result = Record.Exception(() => format.RemoveLeadingDirectorySeparator(filePath)); + + // Then + result.IsArgumentNullException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_Empty() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = string.Empty; + + // When + var result = Record.Exception(() => format.RemoveLeadingDirectorySeparator(filePath)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Fact] + public void Should_Throw_If_FilePath_Is_WhiteSpace() + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + var filePath = " "; + + // When + var result = Record.Exception(() => format.RemoveLeadingDirectorySeparator(filePath)); + + // Then + result.IsArgumentOutOfRangeException("filePath"); + } + + [Theory] + [InlineData(@"\foo\bar.cs", @"foo\bar.cs")] + [InlineData(@"foo\bar.cs", @"foo\bar.cs")] + public void Should_Remove_Leading_Directory_Separator(string filePath, string expectedValue) + { + // Given + var format = new FakeMsBuildLogFileFormat(new FakeLog()); + + // When + var result = format.RemoveLeadingDirectorySeparator(filePath); + + // Then + result.ShouldBe(expectedValue); + } + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj b/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj index 05a3762..334904b 100644 --- a/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj +++ b/src/Cake.Issues.MsBuild.Tests/Cake.Issues.MsBuild.Tests.csproj @@ -15,6 +15,7 @@ + @@ -24,6 +25,7 @@ + @@ -39,7 +41,7 @@ - + diff --git a/src/Cake.Issues.MsBuild.Tests/FakeMsBuildLogFileFormat.cs b/src/Cake.Issues.MsBuild.Tests/FakeMsBuildLogFileFormat.cs new file mode 100644 index 0000000..3d128df --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/FakeMsBuildLogFileFormat.cs @@ -0,0 +1,43 @@ +namespace Cake.Issues.MsBuild.Tests +{ + using System; + using System.Collections.Generic; + using Cake.Core.Diagnostics; + + internal class FakeMsBuildLogFileFormat : BaseMsBuildLogFileFormat + { + public FakeMsBuildLogFileFormat(ICakeLog log) + : base(log) + { + } + + public new (bool Valid, string FilePath) ValidateFilePath(string filePath, RepositorySettings repositorySettings) + { + return base.ValidateFilePath(filePath, repositorySettings); + } + + public new bool CheckIfFileIsInRepository(string filePath, RepositorySettings repositorySettings) + { + return base.CheckIfFileIsInRepository(filePath, repositorySettings); + } + + public new string MakeFilePathRelativeToRepositoryRoot(string filePath, RepositorySettings repositorySettings) + { + return base.MakeFilePathRelativeToRepositoryRoot(filePath, repositorySettings); + } + + public new string RemoveLeadingDirectorySeparator(string filePath) + { + return base.RemoveLeadingDirectorySeparator(filePath); + } + + public override IEnumerable ReadIssues( + MsBuildIssuesProvider issueProvider, + IssueCommentFormat format, + RepositorySettings repositorySettings, + MsBuildIssuesSettings issueProviderSettings) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/LogFileFormat/BinaryLogFileFormatTests.cs b/src/Cake.Issues.MsBuild.Tests/LogFileFormat/BinaryLogFileFormatTests.cs new file mode 100644 index 0000000..1f93c44 --- /dev/null +++ b/src/Cake.Issues.MsBuild.Tests/LogFileFormat/BinaryLogFileFormatTests.cs @@ -0,0 +1,279 @@ +namespace Cake.Issues.MsBuild.Tests.LogFileFormat +{ + using System.Linq; + using Cake.Core.Diagnostics; + using Cake.Core.IO; + using Cake.Issues.MsBuild.LogFileFormat; + using Cake.Issues.Testing; + using Shouldly; + using Xunit; + + public sealed class BinaryLogFileFormatTests + { + public sealed class TheCtor + { + [Fact] + public void Should_Throw_If_Log_Is_Null() + { + // Given + ICakeLog log = null; + + // When + var result = Record.Exception(() => new BinaryLogFileFormat(log)); + + // Then + result.IsArgumentNullException("log"); + } + } + + public sealed class TheReadIssuesMethod + { + [Fact] + public void Should_Read_Full_Log_Correct() + { + // Given + var fixture = new MsBuildIssuesProviderFixture("FullLog.binlog"); + fixture.RepositorySettings = new RepositorySettings(@"c:\Git\Test\Cake.Prca\"); + + // When + var issues = fixture.ReadIssues().ToList(); + + // Then + issues.Count.ShouldBe(19); + CheckIssue( + issues[0], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 13, + "CS0219", + 300, + "Warning", + @"The variable 'foo' is assigned but its value is never used"); + CheckIssue( + issues[1], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 1, + "SA1652", + 300, + "Warning", + @"Enable XML documentation output"); + CheckIssue( + issues[2], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 1, + "SA1200", + 300, + "Warning", + @"Using directive must appear within a namespace declaration"); + CheckIssue( + issues[3], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 2, + "SA1200", + 300, + "Warning", + @"Using directive must appear within a namespace declaration"); + CheckIssue( + issues[4], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 3, + "SA1200", + 300, + "Warning", + @"Using directive must appear within a namespace declaration"); + CheckIssue( + issues[5], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 4, + "SA1200", + 300, + "Warning", + @"Using directive must appear within a namespace declaration"); + CheckIssue( + issues[6], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 5, + "SA1200", + 300, + "Warning", + @"Using directive must appear within a namespace declaration"); + CheckIssue( + issues[7], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 1, + "SA1633", + 300, + "Warning", + @"The file header is missing or not located at the top of the file."); + CheckIssue( + issues[8], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 1, + "SA1652", + 300, + "Warning", + @"Enable XML documentation output"); + CheckIssue( + issues[9], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 1, + "SA1633", + 300, + "Warning", + @"The file header is missing or not located at the top of the file."); + CheckIssue( + issues[10], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 5, + "SA1028", + 300, + "Warning", + @"Code must not contain trailing whitespace"); + CheckIssue( + issues[11], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 17, + "SA1028", + 300, + "Warning", + @"Code must not contain trailing whitespace"); + CheckIssue( + issues[12], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 18, + "SA1028", + 300, + "Warning", + @"Code must not contain trailing whitespace"); + CheckIssue( + issues[13], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 28, + "SA1028", + 300, + "Warning", + @"Code must not contain trailing whitespace"); + CheckIssue( + issues[14], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Properties\AssemblyInfo.cs", + 32, + "SA1028", + 300, + "Warning", + @"Code must not contain trailing whitespace"); + CheckIssue( + issues[15], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + null, + null, + "CA2210", + 300, + "Warning", + @"Microsoft.Design : Sign 'ClassLibrary1.dll' with a strong name key."); + CheckIssue( + issues[16], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + null, + null, + "CA1014", + 300, + "Warning", + @"Microsoft.Design : Mark 'ClassLibrary1.dll' with CLSCompliant(true) because it exposes externally visible types."); + CheckIssue( + issues[17], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 12, + "CA1822", + 300, + "Warning", + @"Microsoft.Performance : The 'this' parameter (or 'Me' in Visual Basic) of 'Class1.Foo()' is never used. Mark the member as static (or Shared in Visual Basic) or use 'this'/'Me' in the method body or at least one property accessor, if appropriate."); + CheckIssue( + issues[18], + @"src\ClassLibrary1\ClassLibrary1.csproj", + "ClassLibrary1", + @"src\ClassLibrary1\Class1.cs", + 13, + "CA1804", + 300, + "Warning", + @"Microsoft.Performance : 'Class1.Foo()' declares a variable, 'foo', of type 'string', which is never used or is only assigned to. Use this variable or remove it."); + } + + private static void CheckIssue( + IIssue issue, + string projectFileRelativePath, + string projectName, + string affectedFileRelativePath, + int? line, + string rule, + int priority, + string priorityName, + string message) + { + issue.ProviderType.ShouldBe("Cake.Issues.MsBuild.MsBuildIssuesProvider"); + issue.ProviderName.ShouldBe("MSBuild"); + + if (issue.ProjectFileRelativePath == null) + { + projectFileRelativePath.ShouldBeNull(); + } + else + { + issue.ProjectFileRelativePath.ToString().ShouldBe(new FilePath(projectFileRelativePath).ToString()); + issue.ProjectFileRelativePath.IsRelative.ShouldBe(true, "Issue path is not relative"); + } + + issue.ProjectName.ShouldBe(projectName); + + 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.PriorityName.ShouldBe(priorityName); + issue.Message.ShouldBe(message); + } + } + } +} diff --git a/src/Cake.Issues.MsBuild.Tests/LogFileFormat/XmlFileLoggerLogFileFormatTests.cs b/src/Cake.Issues.MsBuild.Tests/LogFileFormat/XmlFileLoggerLogFileFormatTests.cs index e46355c..b8423ff 100644 --- a/src/Cake.Issues.MsBuild.Tests/LogFileFormat/XmlFileLoggerLogFileFormatTests.cs +++ b/src/Cake.Issues.MsBuild.Tests/LogFileFormat/XmlFileLoggerLogFileFormatTests.cs @@ -2,10 +2,10 @@ { using System.Linq; using Cake.Core.Diagnostics; + using Cake.Core.IO; using Cake.Issues.MsBuild.LogFileFormat; - using Core.IO; + using Cake.Issues.Testing; using Shouldly; - using Testing; using Xunit; public sealed class XmlFileLoggerLogFileFormatTests diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs index a41079e..c55b62b 100644 --- a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesProviderTests.cs @@ -1,10 +1,9 @@ namespace Cake.Issues.MsBuild.Tests { - using System.Text; using Cake.Core.Diagnostics; using Cake.Issues.MsBuild.LogFileFormat; + using Cake.Issues.Testing; using Cake.Testing; - using Testing; using Xunit; public sealed class MsBuildIssuesProviderTests diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs index 0814676..e024046 100644 --- a/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildIssuesSettingsTests.cs @@ -1,13 +1,11 @@ namespace Cake.Issues.MsBuild.Tests { using System; - using System.IO; - using System.Text; using Cake.Core.IO; using Cake.Issues.MsBuild.LogFileFormat; + using Cake.Issues.Testing; using Cake.Testing; using Shouldly; - using Testing; using Xunit; public sealed class MsBuildIssuesSettingsTests diff --git a/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs b/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs index a456a38..d2aaa11 100644 --- a/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs +++ b/src/Cake.Issues.MsBuild.Tests/MsBuildRuleUrlResolverTests.cs @@ -1,8 +1,8 @@ namespace Cake.Issues.MsBuild.Tests { using System; + using Cake.Issues.Testing; using Shouldly; - using Testing; using Xunit; public sealed class MsBuildRuleUrlResolverTests diff --git a/src/Cake.Issues.MsBuild.Tests/Testfiles/BinaryLogFileFormat/FullLog.binlog b/src/Cake.Issues.MsBuild.Tests/Testfiles/BinaryLogFileFormat/FullLog.binlog new file mode 100644 index 0000000..0205d2d Binary files /dev/null and b/src/Cake.Issues.MsBuild.Tests/Testfiles/BinaryLogFileFormat/FullLog.binlog differ diff --git a/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs b/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs index 57cec90..34f688e 100644 --- a/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs +++ b/src/Cake.Issues.MsBuild/BaseMsBuildLogFileFormat.cs @@ -15,5 +15,86 @@ protected BaseMsBuildLogFileFormat(ICakeLog log) : base(log) { } + + /// + /// Validates a file path. + /// + /// Full file path. + /// Repository settings. + /// Tuple containing a value if validation was successful, and file path relative to repository root. + protected (bool Valid, string FilePath) ValidateFilePath(string filePath, RepositorySettings repositorySettings) + { + filePath.NotNullOrWhiteSpace(nameof(filePath)); + repositorySettings.NotNull(nameof(repositorySettings)); + + // Ignore files from outside the repository. + if (!this.CheckIfFileIsInRepository(filePath, repositorySettings)) + { + return (false, string.Empty); + } + + // Make path relative to repository root. + filePath = this.MakeFilePathRelativeToRepositoryRoot(filePath, repositorySettings); + + // Remove leading directory separator. + filePath = this.RemoveLeadingDirectorySeparator(filePath); + + return (true, filePath); + } + + /// + /// Checks if a file is part of the repository. + /// + /// Full file path. + /// Repository settings. + /// True if file is in repository, false otherwise. + protected bool CheckIfFileIsInRepository(string filePath, RepositorySettings repositorySettings) + { + filePath.NotNullOrWhiteSpace(nameof(filePath)); + repositorySettings.NotNull(nameof(repositorySettings)); + + if (!filePath.IsSubpathOf(repositorySettings.RepositoryRoot.FullPath)) + { + this.Log.Warning( + "Ignored issue for file '{0}' since it is outside the repository folder at {1}.", + filePath, + repositorySettings.RepositoryRoot); + + return false; + } + + return true; + } + + /// + /// Make path relative to repository root. + /// + /// Full file path. + /// Repository settings. + /// File path relative to the repository root. + protected string MakeFilePathRelativeToRepositoryRoot(string filePath, RepositorySettings repositorySettings) + { + filePath.NotNullOrWhiteSpace(nameof(filePath)); + repositorySettings.NotNull(nameof(repositorySettings)); + + return filePath.Substring(repositorySettings.RepositoryRoot.FullPath.Length); + } + + /// + /// Remove the leading directory separator from a file path. + /// + /// Full file path. + /// File path without leading directory separator. + protected string RemoveLeadingDirectorySeparator(string filePath) + { + filePath.NotNullOrWhiteSpace(nameof(filePath)); + + if (filePath.StartsWith(System.IO.Path.DirectorySeparatorChar.ToString())) + { + return filePath.Substring(1); + } + + return filePath; + } } } diff --git a/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj b/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj index 0823800..66e9f97 100644 --- a/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj +++ b/src/Cake.Issues.MsBuild/Cake.Issues.MsBuild.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -13,6 +13,7 @@ full true ..\Cake.Issues.MsBuild.ruleset + true @@ -27,7 +28,8 @@ - + + diff --git a/src/Cake.Issues.MsBuild/LogFileFormat/BinaryLogFileFormat.cs b/src/Cake.Issues.MsBuild/LogFileFormat/BinaryLogFileFormat.cs new file mode 100644 index 0000000..14c70e4 --- /dev/null +++ b/src/Cake.Issues.MsBuild/LogFileFormat/BinaryLogFileFormat.cs @@ -0,0 +1,148 @@ +namespace Cake.Issues.MsBuild.LogFileFormat +{ + using System; + using System.Collections.Generic; + using Cake.Core.Diagnostics; + using Microsoft.Build.Framework; + using Microsoft.Build.Logging.StructuredLogger; + + /// + /// MsBuild binary log file format. + /// + internal class BinaryLogFileFormat : BaseMsBuildLogFileFormat + { + /// + /// Initializes a new instance of the class. + /// + /// The Cake log instance. + public BinaryLogFileFormat(ICakeLog log) + : base(log) + { + } + + /// + public override IEnumerable ReadIssues( + MsBuildIssuesProvider issueProvider, + IssueCommentFormat format, + RepositorySettings repositorySettings, + MsBuildIssuesSettings issueProviderSettings) + { +#pragma warning disable SA1123 // Do not place regions within elements + #region DupFinder Exclusion +#pragma warning restore SA1123 // Do not place regions within elements + + issueProvider.NotNull(nameof(issueProvider)); + repositorySettings.NotNull(nameof(repositorySettings)); + issueProviderSettings.NotNull(nameof(issueProviderSettings)); + + #endregion + + var result = new List(); + + var binLogReader = new BinLogReader(); + foreach (var record in binLogReader.ReadRecords(issueProviderSettings.LogFileContent)) + { + var buildEventArgs = record.Args; + + if (buildEventArgs is BuildWarningEventArgs buildWarning) + { + var projectFileRelativePath = this.GetProject(buildWarning, repositorySettings); + + // Read affected file from the warning. + if (!this.TryGetFile(buildWarning, repositorySettings, out string fileName)) + { + continue; + } + + var line = GetLine(buildWarning); + var rule = buildWarning.Code; + + // Determine rule URL. + Uri ruleUrl = null; + if (!string.IsNullOrWhiteSpace(rule)) + { + ruleUrl = MsBuildRuleUrlResolver.Instance.ResolveRuleUrl(rule); + } + + // Build issue. + result.Add( + IssueBuilder + .NewIssue(buildWarning.Message, issueProvider) + .WithPriority(IssuePriority.Warning) + .InProject(projectFileRelativePath, System.IO.Path.GetFileNameWithoutExtension(projectFileRelativePath)) + .InFile(fileName, line) + .OfRule(rule, ruleUrl) + .Create()); + } + } + + return result; + } + + /// + /// Reads the affected line from a warning logged in a MsBuild log. + /// + /// Warning element from MsBuild log. + /// Line number or null if warning is not related to a file. + private static int? GetLine(BuildWarningEventArgs warning) + { + var line = warning.LineNumber; + + // Convert negative line numbers or line number 0 to null + if (line <= 0) + { + return null; + } + + return line; + } + + /// + /// Determines the project for a warning logged in a MsBuild log. + /// + /// Warning element from the MsBuild log. + /// Repository settings to use. + /// Relative path to the project. + private string GetProject( + BuildWarningEventArgs warning, + RepositorySettings repositorySettings) + { + var project = warning.ProjectFile; + + // Validate project path and make relative to repository root. + return this.ValidateFilePath(project, repositorySettings).FilePath; + } + + /// + /// 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( + BuildWarningEventArgs warning, + RepositorySettings repositorySettings, + out string fileName) + { + fileName = warning.File; + + if (string.IsNullOrWhiteSpace(fileName)) + { + return true; + } + + // If not absolute path, combine with file path from project file. + if (!fileName.IsFullPath()) + { + var projectDirectory = System.IO.Path.GetDirectoryName(warning.ProjectFile); + fileName = System.IO.Path.Combine(projectDirectory, fileName); + } + + // Validate file path and make relative to repository root. + bool result; + (result, fileName) = this.ValidateFilePath(fileName, repositorySettings); + return result; + } + } +} diff --git a/src/Cake.Issues.MsBuild/LogFileFormat/XmlFileLoggerLogFileFormat.cs b/src/Cake.Issues.MsBuild/LogFileFormat/XmlFileLoggerLogFileFormat.cs index 25349f7..2e1f74b 100644 --- a/src/Cake.Issues.MsBuild/LogFileFormat/XmlFileLoggerLogFileFormat.cs +++ b/src/Cake.Issues.MsBuild/LogFileFormat/XmlFileLoggerLogFileFormat.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.Linq; using System.Xml.Linq; - using Core.Diagnostics; + using Cake.Core.Diagnostics; /// /// MsBuild log format as written by the XmlFileLogger class from MSBuild Extension Pack. @@ -28,10 +28,16 @@ public override IEnumerable ReadIssues( RepositorySettings repositorySettings, MsBuildIssuesSettings issueProviderSettings) { +#pragma warning disable SA1123 // Do not place regions within elements + #region DupFinder Exclusion +#pragma warning restore SA1123 // Do not place regions within elements + issueProvider.NotNull(nameof(issueProvider)); repositorySettings.NotNull(nameof(repositorySettings)); issueProviderSettings.NotNull(nameof(issueProviderSettings)); + #endregion + var result = new List(); // Read log file. @@ -41,7 +47,7 @@ public override IEnumerable ReadIssues( foreach (var warning in logDocument.Descendants("warning")) { // Read affected project from the warning. - if (!TryGetProject(warning, repositorySettings, out string projectFileRelativePath)) + if (!this.TryGetProject(warning, repositorySettings, out string projectFileRelativePath)) { continue; } @@ -142,7 +148,7 @@ private static bool TryGetRule(XElement warning, out string rule) /// Repository settings to use. /// Returns project. /// True if the project could be parsed. - private static bool TryGetProject( + private bool TryGetProject( XElement warning, RepositorySettings repositorySettings, out string project) @@ -167,16 +173,10 @@ private static bool TryGetProject( return true; } - // Make path relative to repository root. - project = project.Substring(repositorySettings.RepositoryRoot.FullPath.Length); - - // Remove leading directory separator. - if (project.StartsWith(System.IO.Path.DirectorySeparatorChar.ToString())) - { - project = project.Substring(1); - } - - return true; + // Validate project path and make relative to repository root. + bool result; + (result, project) = this.ValidateFilePath(project, repositorySettings); + return result; } /// @@ -216,27 +216,10 @@ private bool TryGetFile( } } - // 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(System.IO.Path.DirectorySeparatorChar.ToString())) - { - fileName = fileName.Substring(1); - } - - return true; + // Validate file path and make relative to repository root. + bool result; + (result, fileName) = this.ValidateFilePath(fileName, repositorySettings); + return result; } } } diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.BinaryLogFileFormat.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.BinaryLogFileFormat.cs new file mode 100644 index 0000000..13b3568 --- /dev/null +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.BinaryLogFileFormat.cs @@ -0,0 +1,27 @@ +namespace Cake.Issues.MsBuild +{ + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Issues.MsBuild.LogFileFormat; + + /// + /// Contains functionality related to . + /// + public static partial class MsBuildIssuesAliases + { + /// + /// Gets an instance for the MsBuild binary log format. + /// + /// The context. + /// Instance for the MsBuild binary log format. + [CakePropertyAlias] + [CakeAliasCategory(IssuesAliasConstants.IssueProviderCakeAliasCategory)] + public static BaseMsBuildLogFileFormat MsBuildBinaryLogFileFormat( + this ICakeContext context) + { + context.NotNull(nameof(context)); + + return new BinaryLogFileFormat(context.Log); + } + } +} diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.IssueProvider.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.IssueProvider.cs index 6542fb1..2dfae47 100644 --- a/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.IssueProvider.cs +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.IssueProvider.cs @@ -1,9 +1,8 @@ namespace Cake.Issues.MsBuild { - using System.Text; - using Core; - using Core.Annotations; - using Core.IO; + using Cake.Core; + using Cake.Core.Annotations; + using Cake.Core.IO; /// /// Contains functionality related to . diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs index 4e8a24f..cfbac0b 100644 --- a/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesAliases.cs @@ -1,6 +1,6 @@ namespace Cake.Issues.MsBuild { - using Core.Annotations; + using Cake.Core.Annotations; /// /// Contains functionality for reading warnings from MSBuild log files. diff --git a/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs b/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs index f651712..eba62eb 100644 --- a/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs +++ b/src/Cake.Issues.MsBuild/MsBuildIssuesProvider.cs @@ -1,6 +1,6 @@ namespace Cake.Issues.MsBuild { - using Core.Diagnostics; + using Cake.Core.Diagnostics; /// /// Provider for issues reported as MsBuild warnings. diff --git a/tools/packages.config b/tools/packages.config index 3dec7f9..878c59d 100644 --- a/tools/packages.config +++ b/tools/packages.config @@ -1,4 +1,4 @@ - + \ No newline at end of file