From da9c86fd6fc076adcb27d275e7ea32b21eb358b3 Mon Sep 17 00:00:00 2001 From: Marcin Dobosz Date: Mon, 9 Nov 2015 11:59:33 -0800 Subject: [PATCH 01/18] (#37) Add CustomRawUrlProvider to enable arbitrary content URLs A new CustomRawUrlProvider is added that acts as the final IProvider candidate. This provider interprets the TargetUrl parameter (`-u`) as the url to use for the RawGitUrl property of the provider. This enables supporting custom github/bitbucket content proxies as well as opens up an easy way to support conforming alternative git services without having to write a new IProvider implementation for each one. --- README.md | 8 ++ src/GitLink.Tests/GitLink.Tests.csproj | 1 + .../Providers/CustomRawUrlProviderFacts.cs | 82 +++++++++++++++++++ .../Providers/ProviderManagerFacts.cs | 1 + src/GitLink/GitLink.csproj | 1 + src/GitLink/Providers/CustomRawUrlProvider.cs | 42 ++++++++++ src/GitLink/Providers/ProviderManager.cs | 8 +- 7 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/GitLink.Tests/Providers/CustomRawUrlProviderFacts.cs create mode 100644 src/GitLink/Providers/CustomRawUrlProvider.cs diff --git a/README.md b/README.md index e95eb56..1da835d 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,14 @@ When specific projects should be ignored, use the *-ignore* option. This option GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -ignore Catel.Core.WP80,Catel.MVVM.WP80 +## Running for a custom raw content URL + +When working with a content proxy or an alternative git VCS system that supports direct HTTP access to specific file revisions use the `-u` parameter with the custom raw content root URL + + GitLink.exe c:\source\catel -u https://raw.githubusercontent.com/catel/catel + +The custom url will be used to fill in the following pattern `{customUrl}/{revision}/{raltiveFilePath}` when generating the source mapping. + ## Getting help When you need help about GitLink, use the following command line: diff --git a/src/GitLink.Tests/GitLink.Tests.csproj b/src/GitLink.Tests/GitLink.Tests.csproj index abfd43a..244120a 100644 --- a/src/GitLink.Tests/GitLink.Tests.csproj +++ b/src/GitLink.Tests/GitLink.Tests.csproj @@ -92,6 +92,7 @@ + diff --git a/src/GitLink.Tests/Providers/CustomRawUrlProviderFacts.cs b/src/GitLink.Tests/Providers/CustomRawUrlProviderFacts.cs new file mode 100644 index 0000000..1065e26 --- /dev/null +++ b/src/GitLink.Tests/Providers/CustomRawUrlProviderFacts.cs @@ -0,0 +1,82 @@ +namespace GitLink.Tests.Providers +{ + using GitLink.Providers; + using NUnit.Framework; + + public class CustomRawUrlProviderFacts + { + [TestFixture] + public class TheInitialization + { + [TestCase("http://example.com/repo", true)] + [TestCase("https://example.com/repo", true)] + [TestCase("https://example.com/repo/", true)] + [TestCase("gopher://example.com/repo", false)] + public void CorrectlyValidatesForUrls(string url, bool expectedValue) + { + var provider = new CustomRawUrlProvider(); + var valid = provider.Initialize(url); + + Assert.AreEqual(expectedValue, valid); + } + } + + [TestFixture] + public class TheGitHubProviderProperties + { + [TestCase] + public void ReturnsNullCompany() + { + var provider = new CustomRawUrlProvider(); + provider.Initialize("http://example.com/repo"); + + Assert.IsNull(provider.CompanyName); + } + + [TestCase] + public void ReturnsNullCompanyUrl() + { + var provider = new CustomRawUrlProvider(); + provider.Initialize("http://example.com/repo"); + + Assert.IsNull(provider.CompanyUrl); + } + + [TestCase] + public void ReturnsNullProject() + { + var provider = new CustomRawUrlProvider(); + provider.Initialize("http://example.com/repo"); + + Assert.IsNull(provider.ProjectName); + } + + [TestCase] + public void ReturnsNullProjectUrl() + { + var provider = new CustomRawUrlProvider(); + provider.Initialize("http://example.com/repo"); + + Assert.IsNull(provider.ProjectUrl); + } + + [TestCase] + public void ReturnsValidRawGitUrl() + { + var provider = new CustomRawUrlProvider(); + provider.Initialize("http://example.com/repo"); + + Assert.AreEqual("http://example.com/repo", provider.RawGitUrl); + } + + [TestCase] + public void ReturnsValidRawGitUrlWithNoTrailingSlash() + { + var provider = new CustomRawUrlProvider(); + provider.Initialize("http://example.com/repo/"); + + Assert.AreEqual("http://example.com/repo", provider.RawGitUrl); + } + } + } +} diff --git a/src/GitLink.Tests/Providers/ProviderManagerFacts.cs b/src/GitLink.Tests/Providers/ProviderManagerFacts.cs index 655d023..2670de8 100644 --- a/src/GitLink.Tests/Providers/ProviderManagerFacts.cs +++ b/src/GitLink.Tests/Providers/ProviderManagerFacts.cs @@ -18,6 +18,7 @@ public class TheProviderGetProviderMethod { [TestCase("https://bitbucket.org/CatenaLogic/GitLink", typeof(BitBucketProvider))] [TestCase("https://github.com/CatenaLogic/GitLink", typeof(GitHubProvider))] + [TestCase("https://example.com/repo", typeof(CustomRawUrlProvider))] [TestCase("", null)] public void ReturnsRightProvider(string url, Type expectedType) { diff --git a/src/GitLink/GitLink.csproj b/src/GitLink/GitLink.csproj index a1838c2..2f57231 100644 --- a/src/GitLink/GitLink.csproj +++ b/src/GitLink/GitLink.csproj @@ -111,6 +111,7 @@ + diff --git a/src/GitLink/Providers/CustomRawUrlProvider.cs b/src/GitLink/Providers/CustomRawUrlProvider.cs new file mode 100644 index 0000000..dc7b5d6 --- /dev/null +++ b/src/GitLink/Providers/CustomRawUrlProvider.cs @@ -0,0 +1,42 @@ +namespace GitLink.Providers +{ + using System; + using System.Text.RegularExpressions; + using GitTools.Git; + + public sealed class CustomRawUrlProvider : ProviderBase + { + private readonly Regex _regex = new Regex(@"https?://.+"); + + private string _rawUrl; + + public CustomRawUrlProvider() + : base(new GitPreparer()) + { + } + + public override string RawGitUrl + { + get + { + return _rawUrl; + } + } + + public override bool Initialize(string url) + { + if (string.IsNullOrEmpty(url) || !_regex.IsMatch(url)) + { + return false; + } + + _rawUrl = url; + if (_rawUrl.EndsWith("/", StringComparison.Ordinal)) + { + _rawUrl = _rawUrl.TrimEnd('/'); + } + + return true; + } + } +} diff --git a/src/GitLink/Providers/ProviderManager.cs b/src/GitLink/Providers/ProviderManager.cs index e7df24c..8fc4304 100644 --- a/src/GitLink/Providers/ProviderManager.cs +++ b/src/GitLink/Providers/ProviderManager.cs @@ -14,7 +14,7 @@ public class ProviderManager : IProviderManager { public ProviderBase GetProvider(string url) { - var providerTypes = TypeCache.GetTypes(x => typeof(ProviderBase).IsAssignableFromEx(x) && !x.IsAbstract); + var providerTypes = TypeCache.GetTypes(x => typeof(ProviderBase).IsAssignableFromEx(x) && !x.IsAbstract && x != typeof(CustomRawUrlProvider)); var typeFactory = TypeFactory.Default; @@ -27,6 +27,12 @@ public ProviderBase GetProvider(string url) } } + var customProvider = typeFactory.CreateInstance(); + if (customProvider.Initialize(url)) + { + return customProvider; + } + return null; } } From ab160c0e08a292f192dc6eeed4ea618bc7cf87f3 Mon Sep 17 00:00:00 2001 From: Geert van Horrik Date: Thu, 12 Nov 2015 08:36:03 +0100 Subject: [PATCH 02/18] Readme maintenance --- README.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1da835d..550331d 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,6 @@ GitLink makes symbol servers obsolete which saves you both time with uploading s ![Stepping through external source code](doc/images/GitLink_example.gif) - -This application is based on the SourceLink project. SourceLink requires FAKE to run and not everyone likes to write code in F#. GitLink is a wrapper around SourceLink specifically written to be easily used from any build system (locally or a build server) and in any .NET language. It also provides new features such as standard integration with GitHub and BitBucket and the possibility to use remote repositories. GitLink is available as console application and can be referenced as assembly to be used in other .NET assemblies. - The advantage of GitLink is that it is fully customized for Git. It also works with GitHub or BitBucket urls so it **does not require a local git repository to work**. This makes it perfectly usable in continuous integration servers such as Continua CI. Updating all the pdb files is very fast. A solution with over 85 projects will be handled in less than 30 seconds. @@ -53,6 +50,7 @@ GitLink supports the following providers out of the box (will auto-detect based * BitBucket * GitHub +* Custom Provider (custom urls) Providers currently being worked on: @@ -119,7 +117,7 @@ When working with a content proxy or an alternative git VCS system that supports GitLink.exe c:\source\catel -u https://raw.githubusercontent.com/catel/catel -The custom url will be used to fill in the following pattern `{customUrl}/{revision}/{raltiveFilePath}` when generating the source mapping. +The custom url will be used to fill in the following pattern `{customUrl}/{revision}/{relativeFilePath}` when generating the source mapping. ## Getting help @@ -143,18 +141,14 @@ The command line implementation uses the same available API. To link files to a Git project, a context must be created. The command line version does this by using the *ArgumentParser* class. It is also possible to create a context from scratch as shown in the example below: -```csharp -var context = new GitLink.Context(); -context.SolutionDirectory = @"c:\source\catel"; -context.TargetUrl = "https://github.com/catel/catel"; -context.TargetBranch = "develop"; -``` + var context = new GitLink.Context(); + context.SolutionDirectory = @"c:\source\catel"; + context.TargetUrl = "https://github.com/catel/catel"; + context.TargetBranch = "develop"; It is possible to create a context based on command line arguments: -```csharp -var context = ArgumentParser.Parse(@"c:\source\catel -u https://github.com/catel/catel -b develop"); -``` + var context = ArgumentParser.Parse(@"c:\source\catel -u https://github.com/catel/catel -b develop"); ## Linking a context @@ -221,6 +215,7 @@ Below is a list of projects already using GitLink (alphabetically ordered). - Orc.SupportPackage - Orc.SystemInfo - Orc.WorkspaceManagement +- Orc.Wizard - Orchestra - OxyPlot - Romantic Web From 35ee9d05fb2d5426a9ed9674b847d2484a080003 Mon Sep 17 00:00:00 2001 From: Pedro Lamas Date: Wed, 18 Nov 2015 15:47:27 +0000 Subject: [PATCH 03/18] Added support to specify what projects to include --- src/GitLink.Tests/ArgumentParserFacts.cs | 15 +++++++++++++++ src/GitLink/ArgumentParser.cs | 6 ++++++ src/GitLink/Context.cs | 3 +++ src/GitLink/Extensions/ProjectExtensions.cs | 14 +++++++------- src/GitLink/Linker.cs | 2 +- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/GitLink.Tests/ArgumentParserFacts.cs b/src/GitLink.Tests/ArgumentParserFacts.cs index c2ccf3f..187bf6a 100644 --- a/src/GitLink.Tests/ArgumentParserFacts.cs +++ b/src/GitLink.Tests/ArgumentParserFacts.cs @@ -119,6 +119,21 @@ public void CorrectlyParsesIgnoredProjects() Assert.AreEqual("test2", context.IgnoredProjects[1]); } + [TestCase] + public void CorrectlyParsesIncludedProjects() + { + var context = ArgumentParser.ParseArguments("solutionDirectory -u http://github.com/CatenaLogic/GitLink -debug -c someConfiguration -include test1,test2"); + + Assert.AreEqual("solutionDirectory", context.SolutionDirectory); + Assert.AreEqual("http://github.com/CatenaLogic/GitLink", context.TargetUrl); + Assert.AreEqual("someConfiguration", context.ConfigurationName); + Assert.IsTrue(context.IsDebug); + + Assert.AreEqual(2, context.IncludedProjects.Count); + Assert.AreEqual("test1", context.IncludedProjects[0]); + Assert.AreEqual("test2", context.IncludedProjects[1]); + } + [TestCase] public void ThrowsExceptionForUnknownArgument() { diff --git a/src/GitLink/ArgumentParser.cs b/src/GitLink/ArgumentParser.cs index 0e6c2bd..3860642 100644 --- a/src/GitLink/ArgumentParser.cs +++ b/src/GitLink/ArgumentParser.cs @@ -134,6 +134,12 @@ public static Context ParseArguments(List commandLineArguments, IProvide continue; } + if (IsSwitch("include", name)) + { + context.IncludedProjects.AddRange(value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())); + continue; + } + if (IsSwitch("ignore", name)) { context.IgnoredProjects.AddRange(value.Split(new []{ ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())); diff --git a/src/GitLink/Context.cs b/src/GitLink/Context.cs index a45b72e..11fed4b 100644 --- a/src/GitLink/Context.cs +++ b/src/GitLink/Context.cs @@ -31,6 +31,7 @@ public Context(IProviderManager providerManager) Authentication = new Authentication(); ConfigurationName = "Release"; PlatformName = "AnyCPU"; + IncludedProjects = new List(); IgnoredProjects = new List(); } @@ -92,6 +93,8 @@ public string TargetBranch public string SolutionFile { get; set; } + public List IncludedProjects { get; private set; } + public List IgnoredProjects { get; private set; } public string PdbFilesDirectory { get; set; } diff --git a/src/GitLink/Extensions/ProjectExtensions.cs b/src/GitLink/Extensions/ProjectExtensions.cs index 8f68831..6cc6cc0 100644 --- a/src/GitLink/Extensions/ProjectExtensions.cs +++ b/src/GitLink/Extensions/ProjectExtensions.cs @@ -20,20 +20,20 @@ public static class ProjectExtensions { private static readonly ILog Log = LogManager.GetCurrentClassLogger(); - public static bool ShouldBeIgnored(this Project project, IEnumerable projectsToIgnore) + public static bool ShouldBeIgnored(this Project project, ICollection projectsToInclude, ICollection projectsToIgnore) { Argument.IsNotNull(() => project); var projectName = GetProjectName(project).ToLower(); - foreach (var projectToIgnore in projectsToIgnore) + if (projectsToIgnore.Any(projectToIgnore => string.Equals(projectName, projectToIgnore, StringComparison.InvariantCultureIgnoreCase))) { - var lowerCaseProjectToIgnore = projectToIgnore.ToLower(); + return true; + } - if (string.Equals(projectName, lowerCaseProjectToIgnore)) - { - return true; - } + if (projectsToInclude.Count > 0 && !projectsToInclude.Any(projectToInclude => string.Equals(projectName, projectToInclude, StringComparison.InvariantCultureIgnoreCase))) + { + return true; } return false; diff --git a/src/GitLink/Linker.cs b/src/GitLink/Linker.cs index 6366185..b884111 100644 --- a/src/GitLink/Linker.cs +++ b/src/GitLink/Linker.cs @@ -96,7 +96,7 @@ public static int Link(Context context) { try { - if (project.ShouldBeIgnored(context.IgnoredProjects)) + if (project.ShouldBeIgnored(context.IncludedProjects, context.IgnoredProjects)) { Log.Info("Ignoring '{0}'", project.GetProjectName()); Log.Info(string.Empty); From 9e3de76e2f08d8a017d3e9ed2fa8c4287c573084 Mon Sep 17 00:00:00 2001 From: neutmute Date: Wed, 25 Nov 2015 14:29:01 +1100 Subject: [PATCH 04/18] #70 allow periods in the bitbucket repository name --- src/GitLink.Tests/Providers/BitBucketProviderFacts.cs | 9 +++++++++ src/GitLink/Providers/BitBucketProvider.cs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/GitLink.Tests/Providers/BitBucketProviderFacts.cs b/src/GitLink.Tests/Providers/BitBucketProviderFacts.cs index c4c48ec..5623278 100644 --- a/src/GitLink.Tests/Providers/BitBucketProviderFacts.cs +++ b/src/GitLink.Tests/Providers/BitBucketProviderFacts.cs @@ -72,6 +72,15 @@ public void ReturnsValidProjectUrl() Assert.AreEqual("https://bitbucket.org/CatenaLogic/GitLink", provider.ProjectUrl); } + [TestCase] + public void ReturnsValidProjectUrlWhenContainsPeriod() + { + var provider = new BitBucketProvider(); + provider.Initialize("https://bitbucket.org/CatenaLogic/dotted.Project"); + + Assert.AreEqual("https://bitbucket.org/CatenaLogic/dotted.Project", provider.ProjectUrl); + } + [TestCase] public void ReturnsValidRawGitUrl() { diff --git a/src/GitLink/Providers/BitBucketProvider.cs b/src/GitLink/Providers/BitBucketProvider.cs index 637737d..b124d98 100644 --- a/src/GitLink/Providers/BitBucketProvider.cs +++ b/src/GitLink/Providers/BitBucketProvider.cs @@ -13,7 +13,7 @@ namespace GitLink.Providers public class BitBucketProvider : ProviderBase { - private readonly Regex _gitHubRegex = new Regex(@"(?(?(?:https://)?bitbucket\.org/(?[^/]+))/(?[^\./]+))"); + private readonly Regex _gitHubRegex = new Regex(@"(?(?(?:https://)?bitbucket\.org/(?[^/]+))/(?[^/]+))"); public BitBucketProvider() : base(new GitPreparer()) From 3dba7ca33cf66fdceeb2b0c87c5e0fab3a18ac95 Mon Sep 17 00:00:00 2001 From: neutmute Date: Thu, 26 Nov 2015 12:31:07 +1100 Subject: [PATCH 05/18] documentation --- README.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 550331d..bfca872 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ GitLink let's users step through your code hosted on GitHub! **Help make .NET op **Important note** -*GitLink* was formerly named *GitHubLink*. By adding support to more Git hosting services the name seemed not covering the whole package. Note that the old GitHubLink packages on NuGet and Chocolatey will no long be updated / maintained. +*GitLink* was formerly named *GitHubLink*. By adding support to more Git hosting services the name seemed not covering the whole package. The old GitHubLink packages on NuGet and Chocolatey will no longer be updated or maintained. -- @@ -32,18 +32,26 @@ The advantage of GitLink is that it is fully customized for Git. It also works w Updating all the pdb files is very fast. A solution with over 85 projects will be handled in less than 30 seconds. -When using GitLink, the user no longer has to specify symbol servers. He/she only has to enable the support for source servers in Visual Studio as shown in the image below: +When using GitLink, the user no longer has to specify symbol servers. The only requirement is to ensure the check the `Enable source server support` option in Visual Studio as shown below: ![Enabling source server support](doc/images/visualstudio_enablesourceserversupport.png) # Troubleshooting -**Note that Visual Studio 2012 needs to run elevated in order to download the source server files due to a bug in Visual Studio 2012.** +## Source Stepping isn't working -If the source stepping is not working, double check that Visual Studio has a valid symbol cache directory to store the source files being downloaded: +* Visual Studio 2012 needs to run elevated in order to download the source server files + +* Specify a value for Visual Studio -> Options -> Debugging -> Symbols -> `Cache Symbols in this directory` ![Enabling source server support](doc/images/visualstudio_symbolslocation.png) +## Source Stepping returns HTML +If your repository is private, you are likely seeing the logon HTML from your git host. + +* Log onto your git host in Internet Explorer +* Purge your local symbol cache + # Supported git providers GitLink supports the following providers out of the box (will auto-detect based on the url): @@ -70,10 +78,11 @@ It is also possible to specify a custom url provider. Using GitLink via the command line is very simple: -1. Build the software (in release mode with pdb files enabled) +1. Build the solution - in release mode with pdb files enabled 2. Run the console application with the right command line parameters +3. Include the PDB in your nuget package -Below are a few examples. +See [Oren Novotony's blog post](https://oren.codes/2015/09/23/enabling-source-code-debugging-for-your-nuget-packages-with-gitlink/) for even more detail and examples on build integration. ## Most simple usage From fc4ec898c37f4ea639a834ad90c2c1c750702f95 Mon Sep 17 00:00:00 2001 From: Simon Musy Date: Mon, 30 Nov 2015 16:56:54 +0100 Subject: [PATCH 06/18] I tried to implement the functionality mentioned in the issue #66 I did pretty much the same thing as Marcind with his CustomRawUrlProvider, here is the readme part. Running for an uncommon URL When working with a repository using uncommon URL you can use placeholders to specifiy where the filename and revision hash should be, use -u parameter with the custom URL GitLink.exe c:\source\catel -u "https://host/projects/catel/repos/catel/browse/{filename}?at={revision}&raw" The custom url will be used to fill the placeholders with the relative file path and the revision hash. I also added an option to download the sources with powershell because SRCSRV http support doesn't accept characters like "?" thus another option was needed --- README.md | 7 ++ src/GitLink.Tests/ArgumentParserFacts.cs | 8 ++ .../Providers/CustomUrlProviderFacts.cs | 82 +++++++++++++++++++ src/GitLink/ArgumentParser.cs | 6 ++ src/GitLink/Context.cs | 1 + src/GitLink/CustomUrlProvider.cs | 44 ++++++++++ src/GitLink/Extensions/ProjectExtensions.cs | 8 +- src/GitLink/HelpWriter.cs | 2 + src/GitLink/Linker.cs | 10 ++- src/GitLink/Pdb/SrcSrv.cs | 20 +++-- src/GitLink/ProviderManager.cs | 45 ++++++++++ 11 files changed, 222 insertions(+), 11 deletions(-) create mode 100644 src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs create mode 100644 src/GitLink/CustomUrlProvider.cs create mode 100644 src/GitLink/ProviderManager.cs diff --git a/README.md b/README.md index bfca872..5099290 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,13 @@ When specific projects should be ignored, use the *-ignore* option. This option GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -ignore Catel.Core.WP80,Catel.MVVM.WP80 +## Running for an uncommon / customized URL + +When working with a repository using uncommon URL you can use placeholders to specifiy where the filename and revision hash should be, use `-u` parameter with the custom URL + + GitLink.exe c:\source\catel -u "https://host/projects/catel/repos/catel/browse/{filename}?at={revision}&raw" + +The custom url will be used to fill the placeholders with the relative file path and the revision hash. ## Running for a custom raw content URL When working with a content proxy or an alternative git VCS system that supports direct HTTP access to specific file revisions use the `-u` parameter with the custom raw content root URL diff --git a/src/GitLink.Tests/ArgumentParserFacts.cs b/src/GitLink.Tests/ArgumentParserFacts.cs index c2ccf3f..0a67082 100644 --- a/src/GitLink.Tests/ArgumentParserFacts.cs +++ b/src/GitLink.Tests/ArgumentParserFacts.cs @@ -124,5 +124,13 @@ public void ThrowsExceptionForUnknownArgument() { ExceptionTester.CallMethodAndExpectException(() => ArgumentParser.ParseArguments("solutionDirectory -x logFilePath")); } + + [TestCase] + public void PowershellDownloadSetToTrue() + { + var context = ArgumentParser.ParseArguments("solutionDirectory -u http://github.com/CatenaLogic/GitLink -powershell"); + + Assert.IsTrue(context.DownloadWithPowershell); + } } } \ No newline at end of file diff --git a/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs b/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs new file mode 100644 index 0000000..3bd8ea0 --- /dev/null +++ b/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs @@ -0,0 +1,82 @@ +using GitLink.Providers; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GitLink.Tests.Providers +{ + public class CustomUrlProviderFacts + { + private const string correctUrl = "https://bitbucket.intra.company.com/projects/aaa/repos/a/browse/{filename}?at={revision}&raw"; + [TestFixture] + public class TheInitialization + { + [TestCase(correctUrl, true)] + [TestCase("https://example.com/repo", false)] + [TestCase("https://bitbucket.intra.company.com/projects/aaa/repos/a/browse/{filename}?raw", true)] + [TestCase("gopher://example.com/repo", false)] + public void CorrectlyValidatesForUrls(string url, bool expectedValue) + { + var provider = new CustomUrlProvider(); + var valid = provider.Initialize(url); + + Assert.AreEqual(expectedValue, valid); + } + } + + [TestFixture] + public class TheGitHubProviderProperties + { + [TestCase] + public void ReturnsNullCompany() + { + var provider = new CustomUrlProvider(); + provider.Initialize(correctUrl); + + Assert.IsNull(provider.CompanyName); + } + + [TestCase] + public void ReturnsNullCompanyUrl() + { + var provider = new CustomUrlProvider(); + provider.Initialize(correctUrl); + + Assert.IsNull(provider.CompanyUrl); + } + + [TestCase] + public void ReturnsNullProject() + { + var provider = new CustomUrlProvider(); + provider.Initialize(correctUrl); + + Assert.IsNull(provider.ProjectName); + } + + [TestCase] + public void ReturnsNullProjectUrl() + { + var provider = new CustomUrlProvider(); + provider.Initialize(correctUrl); + + Assert.IsNull(provider.ProjectUrl); + } + + [TestCase] + public void ReturnsValidRawGitUrl() + { + var provider = new CustomUrlProvider(); + provider.Initialize(correctUrl); + + string correctReturnedUrl = correctUrl.Replace("{filename}", "%var2%"); + correctReturnedUrl = correctReturnedUrl.Replace("{revision}", "{0}"); + + Assert.AreEqual(correctReturnedUrl, provider.RawGitUrl); + } + } + } +} diff --git a/src/GitLink/ArgumentParser.cs b/src/GitLink/ArgumentParser.cs index 0e6c2bd..bc6ce29 100644 --- a/src/GitLink/ArgumentParser.cs +++ b/src/GitLink/ArgumentParser.cs @@ -80,6 +80,12 @@ public static Context ParseArguments(List commandLineArguments, IProvide continue; } + if (IsSwitch("powershell", name)) + { + context.DownloadWithPowershell = true; + continue; + } + // After this point, all arguments should have a value index++; var valueInfo = GetValue(namedArguments, index); diff --git a/src/GitLink/Context.cs b/src/GitLink/Context.cs index a45b72e..892de72 100644 --- a/src/GitLink/Context.cs +++ b/src/GitLink/Context.cs @@ -34,6 +34,7 @@ public Context(IProviderManager providerManager) IgnoredProjects = new List(); } + public bool DownloadWithPowershell { get; set; } = false; public bool IsHelp { get; set; } public bool IsDebug { get; set; } diff --git a/src/GitLink/CustomUrlProvider.cs b/src/GitLink/CustomUrlProvider.cs new file mode 100644 index 0000000..776d14a --- /dev/null +++ b/src/GitLink/CustomUrlProvider.cs @@ -0,0 +1,44 @@ +namespace GitLink.Providers +{ + using GitTools.Git; + using System.Text.RegularExpressions; + + public sealed class CustomUrlProvider : ProviderBase + { + private static readonly string fileNamePlaceHolder = "{filename}"; + private static readonly string revisionPlaceHolder = "{revision}"; + private readonly Regex _regexUrl = new Regex(@"https?://.+"); + + private string _rawUrl; + + public CustomUrlProvider() + : base(new GitPreparer()) + { + } + + public override string RawGitUrl + { + get + { + return _rawUrl; + } + } + + public override bool Initialize(string url) + { + if (string.IsNullOrEmpty(url) || !_regexUrl.IsMatch(url) ||( + !url.Contains(fileNamePlaceHolder) && !url.Contains(revisionPlaceHolder))) + { + return false; + } + + if(url.Contains(fileNamePlaceHolder)) + _rawUrl = url.Replace(fileNamePlaceHolder, "%var2%"); + + if(url.Contains(revisionPlaceHolder)) + _rawUrl = _rawUrl.Replace(revisionPlaceHolder, "{0}"); + + return true; + } + } +} diff --git a/src/GitLink/Extensions/ProjectExtensions.cs b/src/GitLink/Extensions/ProjectExtensions.cs index 8f68831..88d0ab8 100644 --- a/src/GitLink/Extensions/ProjectExtensions.cs +++ b/src/GitLink/Extensions/ProjectExtensions.cs @@ -47,7 +47,7 @@ public static string GetProjectName(this Project project) return projectName ?? Path.GetFileName(project.FullPath); } - public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths) + public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, bool DownloadWithPowershell) { Argument.IsNotNull(() => project); Argument.IsNotNullOrWhitespace(() => rawUrl); @@ -55,17 +55,17 @@ public static void CreateSrcSrv(this Project project, string rawUrl, string revi var srcsrvFile = GetOutputSrcSrvFile(project); - CreateSrcSrv(project, rawUrl, revision, paths, srcsrvFile); + CreateSrcSrv(project, rawUrl, revision, paths, srcsrvFile, DownloadWithPowershell); } - public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, string srcsrvFile) + public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, string srcsrvFile, bool DownloadWithPowershell) { Argument.IsNotNull(() => project); Argument.IsNotNullOrWhitespace(() => rawUrl); Argument.IsNotNullOrWhitespace(() => revision); Argument.IsNotNullOrWhitespace(() => srcsrvFile); - File.WriteAllBytes(srcsrvFile, SrcSrv.Create(rawUrl, revision, paths.Select(x => new Tuple(x.Key, x.Value)))); + File.WriteAllBytes(srcsrvFile, SrcSrv.Create(rawUrl, revision, paths.Select(x => new Tuple(x.Key, x.Value)), DownloadWithPowershell)); } public static IEnumerable GetCompilableItems(this Project project) diff --git a/src/GitLink/HelpWriter.cs b/src/GitLink/HelpWriter.cs index 603f8c9..f16a2f8 100644 --- a/src/GitLink/HelpWriter.cs +++ b/src/GitLink/HelpWriter.cs @@ -39,6 +39,8 @@ solutionPath The directory containing the solution with the pdb files. -s [shaHash] The SHA-1 hash of the commit. -d [pdbDirectory] The directory where pdb files exists, default value is the normal project output directory. + -powershell Use an indexing strategy that won't rely on SRCSRV http support, + but use a powershell command for URL download instead. -errorsaswarnings Don't fail on errors, but treat them as warnings instead. -skipverify Skip pdb verification in case it causes issues (it's a formality anyway) -debug Enables debug mode with special dumps of msbuild. diff --git a/src/GitLink/Linker.cs b/src/GitLink/Linker.cs index 6366185..4ed4b57 100644 --- a/src/GitLink/Linker.cs +++ b/src/GitLink/Linker.cs @@ -199,7 +199,13 @@ private static bool LinkProject(Context context, Project project, string pdbStrF } } - var rawUrl = string.Format("{0}/{{0}}/%var2%", context.Provider.RawGitUrl); + var rawUrl = context.Provider.RawGitUrl; + + if(!rawUrl.Contains("%var2%") && !rawUrl.Contains("{0}")) + { + rawUrl= string.Format("{0}/{{0}}/%var2%", context.Provider.RawGitUrl); + } + var paths = new Dictionary(); foreach (var compilable in compilables) { @@ -212,7 +218,7 @@ private static bool LinkProject(Context context, Project project, string pdbStrF paths.Add(compilable, relativePathForUrl); } - project.CreateSrcSrv(rawUrl, shaHash, paths, projectSrcSrvFile); + project.CreateSrcSrv(rawUrl, shaHash, paths, projectSrcSrvFile, context.DownloadWithPowershell); Log.Debug("Created source server link file, updating pdb file '{0}'", context.GetRelativePath(projectPdbFile)); diff --git a/src/GitLink/Pdb/SrcSrv.cs b/src/GitLink/Pdb/SrcSrv.cs index 147103b..53e0473 100644 --- a/src/GitLink/Pdb/SrcSrv.cs +++ b/src/GitLink/Pdb/SrcSrv.cs @@ -19,7 +19,7 @@ private static string CreateTarget(string rawUrl, string revision) return string.Format(rawUrl, revision); } - public static byte[] Create(string rawUrl, string revision, IEnumerable> paths) + public static byte[] Create(string rawUrl, string revision, IEnumerable> paths, bool DebugWithPowershell) { Argument.IsNotNullOrWhitespace(() => rawUrl); Argument.IsNotNullOrWhitespace(() => revision); @@ -29,12 +29,22 @@ public static byte[] Create(string rawUrl, string revision, IEnumerable +// Copyright (c) 2014 - 2014 CatenaLogic. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- + + +namespace GitLink.Providers +{ + using Catel.IoC; + using Catel.Reflection; + + public class ProviderManager : IProviderManager + { + public ProviderBase GetProvider(string url) + { + var providerTypes = TypeCache.GetTypes(x => typeof(ProviderBase).IsAssignableFromEx(x) && !x.IsAbstract && x != typeof(CustomRawUrlProvider) && x != typeof(CustomUrlProvider)); + + var typeFactory = TypeFactory.Default; + + var customUrlProvider = typeFactory.CreateInstance(); + if (customUrlProvider.Initialize(url)) + { + return customUrlProvider; + } + + foreach (var providerType in providerTypes) + { + var provider = (ProviderBase) typeFactory.CreateInstance(providerType); + if (provider.Initialize(url)) + { + return provider; + } + } + + var customProvider = typeFactory.CreateInstance(); + if (customProvider.Initialize(url)) + { + return customProvider; + } + + return null; + } + } +} \ No newline at end of file From a741c1f0ed43afac8ddfb9deeaddee4400c24364 Mon Sep 17 00:00:00 2001 From: Simon Musy Date: Sun, 6 Dec 2015 19:40:46 +0100 Subject: [PATCH 07/18] Applied changed mentioned by #GeertvanHorrik --- src/GitLink.Tests/GitLink.Tests.csproj | 1 + .../Providers/CustomUrlProviderFacts.cs | 18 +++++++++--------- src/GitLink/Context.cs | 3 ++- src/GitLink/Extensions/ProjectExtensions.cs | 4 ++-- src/GitLink/GitLink.csproj | 1 + src/GitLink/Pdb/SrcSrv.cs | 6 +++--- .../{ => Providers}/CustomUrlProvider.cs | 18 +++++++++++------- 7 files changed, 29 insertions(+), 22 deletions(-) rename src/GitLink/{ => Providers}/CustomUrlProvider.cs (59%) diff --git a/src/GitLink.Tests/GitLink.Tests.csproj b/src/GitLink.Tests/GitLink.Tests.csproj index 244120a..d36b251 100644 --- a/src/GitLink.Tests/GitLink.Tests.csproj +++ b/src/GitLink.Tests/GitLink.Tests.csproj @@ -93,6 +93,7 @@ + diff --git a/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs b/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs index 3bd8ea0..1c26e06 100644 --- a/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs +++ b/src/GitLink.Tests/Providers/CustomUrlProviderFacts.cs @@ -1,13 +1,13 @@ -using GitLink.Providers; -using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace GitLink.Tests.Providers +namespace GitLink.Tests.Providers { + using GitLink.Providers; + using NUnit.Framework; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + public class CustomUrlProviderFacts { private const string correctUrl = "https://bitbucket.intra.company.com/projects/aaa/repos/a/browse/{filename}?at={revision}&raw"; diff --git a/src/GitLink/Context.cs b/src/GitLink/Context.cs index 892de72..fb891d7 100644 --- a/src/GitLink/Context.cs +++ b/src/GitLink/Context.cs @@ -34,7 +34,8 @@ public Context(IProviderManager providerManager) IgnoredProjects = new List(); } - public bool DownloadWithPowershell { get; set; } = false; + public bool DownloadWithPowershell { get; set; } + public bool IsHelp { get; set; } public bool IsDebug { get; set; } diff --git a/src/GitLink/Extensions/ProjectExtensions.cs b/src/GitLink/Extensions/ProjectExtensions.cs index 88d0ab8..8098d6c 100644 --- a/src/GitLink/Extensions/ProjectExtensions.cs +++ b/src/GitLink/Extensions/ProjectExtensions.cs @@ -47,7 +47,7 @@ public static string GetProjectName(this Project project) return projectName ?? Path.GetFileName(project.FullPath); } - public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, bool DownloadWithPowershell) + public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, bool downloadWithPowershell) { Argument.IsNotNull(() => project); Argument.IsNotNullOrWhitespace(() => rawUrl); @@ -55,7 +55,7 @@ public static void CreateSrcSrv(this Project project, string rawUrl, string revi var srcsrvFile = GetOutputSrcSrvFile(project); - CreateSrcSrv(project, rawUrl, revision, paths, srcsrvFile, DownloadWithPowershell); + CreateSrcSrv(project, rawUrl, revision, paths, srcsrvFile, downloadWithPowershell); } public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, string srcsrvFile, bool DownloadWithPowershell) diff --git a/src/GitLink/GitLink.csproj b/src/GitLink/GitLink.csproj index 2f57231..f02cf08 100644 --- a/src/GitLink/GitLink.csproj +++ b/src/GitLink/GitLink.csproj @@ -112,6 +112,7 @@ + diff --git a/src/GitLink/Pdb/SrcSrv.cs b/src/GitLink/Pdb/SrcSrv.cs index 53e0473..3bbff14 100644 --- a/src/GitLink/Pdb/SrcSrv.cs +++ b/src/GitLink/Pdb/SrcSrv.cs @@ -19,7 +19,7 @@ private static string CreateTarget(string rawUrl, string revision) return string.Format(rawUrl, revision); } - public static byte[] Create(string rawUrl, string revision, IEnumerable> paths, bool DebugWithPowershell) + public static byte[] Create(string rawUrl, string revision, IEnumerable> paths, bool downloadWithPowershell) { Argument.IsNotNullOrWhitespace(() => rawUrl); Argument.IsNotNullOrWhitespace(() => revision); @@ -34,11 +34,11 @@ public static byte[] Create(string rawUrl, string revision, IEnumerable Date: Mon, 14 Dec 2015 12:51:17 +0100 Subject: [PATCH 08/18] Used lowercase variable, reformated code and readme --- README.md | 1 + src/GitLink/Extensions/ProjectExtensions.cs | 4 ++-- src/GitLink/Linker.cs | 2 +- src/GitLink/Providers/CustomUrlProvider.cs | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5099290..b2762e2 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ When working with a repository using uncommon URL you can use placeholders to sp GitLink.exe c:\source\catel -u "https://host/projects/catel/repos/catel/browse/{filename}?at={revision}&raw" The custom url will be used to fill the placeholders with the relative file path and the revision hash. + ## Running for a custom raw content URL When working with a content proxy or an alternative git VCS system that supports direct HTTP access to specific file revisions use the `-u` parameter with the custom raw content root URL diff --git a/src/GitLink/Extensions/ProjectExtensions.cs b/src/GitLink/Extensions/ProjectExtensions.cs index 8098d6c..9e5dbd4 100644 --- a/src/GitLink/Extensions/ProjectExtensions.cs +++ b/src/GitLink/Extensions/ProjectExtensions.cs @@ -58,14 +58,14 @@ public static void CreateSrcSrv(this Project project, string rawUrl, string revi CreateSrcSrv(project, rawUrl, revision, paths, srcsrvFile, downloadWithPowershell); } - public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, string srcsrvFile, bool DownloadWithPowershell) + public static void CreateSrcSrv(this Project project, string rawUrl, string revision, Dictionary paths, string srcsrvFile, bool downloadWithPowershell) { Argument.IsNotNull(() => project); Argument.IsNotNullOrWhitespace(() => rawUrl); Argument.IsNotNullOrWhitespace(() => revision); Argument.IsNotNullOrWhitespace(() => srcsrvFile); - File.WriteAllBytes(srcsrvFile, SrcSrv.Create(rawUrl, revision, paths.Select(x => new Tuple(x.Key, x.Value)), DownloadWithPowershell)); + File.WriteAllBytes(srcsrvFile, SrcSrv.Create(rawUrl, revision, paths.Select(x => new Tuple(x.Key, x.Value)), downloadWithPowershell)); } public static IEnumerable GetCompilableItems(this Project project) diff --git a/src/GitLink/Linker.cs b/src/GitLink/Linker.cs index 4ed4b57..153bc26 100644 --- a/src/GitLink/Linker.cs +++ b/src/GitLink/Linker.cs @@ -203,7 +203,7 @@ private static bool LinkProject(Context context, Project project, string pdbStrF if(!rawUrl.Contains("%var2%") && !rawUrl.Contains("{0}")) { - rawUrl= string.Format("{0}/{{0}}/%var2%", context.Provider.RawGitUrl); + rawUrl= string.Format("{0}/{{0}}/%var2%", rawUrl); } var paths = new Dictionary(); diff --git a/src/GitLink/Providers/CustomUrlProvider.cs b/src/GitLink/Providers/CustomUrlProvider.cs index 7465b01..8086b42 100644 --- a/src/GitLink/Providers/CustomUrlProvider.cs +++ b/src/GitLink/Providers/CustomUrlProvider.cs @@ -26,8 +26,8 @@ public override string RawGitUrl public override bool Initialize(string url) { - if (string.IsNullOrEmpty(url) || !_regexUrl.IsMatch(url) ||( - !url.Contains(FileNamePlaceHolder) && !url.Contains(RevisionPlaceHolder))) + if (string.IsNullOrEmpty(url) || !_regexUrl.IsMatch(url) || + (!url.Contains(FileNamePlaceHolder) && !url.Contains(RevisionPlaceHolder))) { return false; } From 137378fbc68203cf024f38f62459310d2b793511 Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Sat, 2 Jan 2016 22:56:45 +0200 Subject: [PATCH 09/18] Added unit tests on inclusion/exclusion logic --- src/GitLink.Tests/GitLink.Tests.csproj | 1 + src/GitLink.Tests/ProjectExtensionsFacts.cs | 44 +++++++++++++++++++++ src/GitLink/Extensions/ProjectExtensions.cs | 6 +-- src/GitLink/Linker.cs | 3 +- 4 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 src/GitLink.Tests/ProjectExtensionsFacts.cs diff --git a/src/GitLink.Tests/GitLink.Tests.csproj b/src/GitLink.Tests/GitLink.Tests.csproj index d36b251..337ceeb 100644 --- a/src/GitLink.Tests/GitLink.Tests.csproj +++ b/src/GitLink.Tests/GitLink.Tests.csproj @@ -89,6 +89,7 @@ + diff --git a/src/GitLink.Tests/ProjectExtensionsFacts.cs b/src/GitLink.Tests/ProjectExtensionsFacts.cs new file mode 100644 index 0000000..27303c8 --- /dev/null +++ b/src/GitLink.Tests/ProjectExtensionsFacts.cs @@ -0,0 +1,44 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2014 - 2016 CatenaLogic. All rights reserved. +// +// -------------------------------------------------------------------------------------------------------------------- +namespace GitLink.Tests +{ + using NUnit.Framework; + + [TestFixture] + public class ProjectExtensionsFacts + { + [Test] + public void NoIncludesExcludes_ProjectNotIgnored() + { + Assert.IsFalse(ProjectExtensions.ShouldBeIgnored("project", new string[0], new string[0])); + } + + [TestCase("ignoredProject", true)] + [TestCase("nonIgnoredProject", false)] + public void ExcludedProject_IgnoredOnlySpecifiedOne(string projectName, bool expectedIgnore) + { + Assert.AreEqual(expectedIgnore, ProjectExtensions.ShouldBeIgnored(projectName, new string[0], new[] { "ignoredProject" })); + } + + [TestCase("anotherProject", true)] + [TestCase("includedProject", false)] + public void ExplicitlyIncludedProject_OthersAreIgnored(string projectName, bool expectedIgnore) + { + Assert.AreEqual(expectedIgnore, ProjectExtensions.ShouldBeIgnored(projectName, new[] { "includedProject" }, new string[0])); + } + + [TestCase("excludedProject", true)] + [TestCase("includedProject", false)] + [TestCase("includedAndExcludedProject", true)] + [TestCase("notIncludedNorExcludedProject", true)] + public void BothIncludedAndExcludedProjects(string projectName, bool expectedIgnore) + { + Assert.AreEqual(expectedIgnore, ProjectExtensions.ShouldBeIgnored(projectName, + new[] { "includedProject", "includedAndExcludedProject" }, + new[] { "excludedProject", "includedAndExcludedProject" })); + } + } +} \ No newline at end of file diff --git a/src/GitLink/Extensions/ProjectExtensions.cs b/src/GitLink/Extensions/ProjectExtensions.cs index 53f6a53..6e8a0a0 100644 --- a/src/GitLink/Extensions/ProjectExtensions.cs +++ b/src/GitLink/Extensions/ProjectExtensions.cs @@ -20,11 +20,9 @@ public static class ProjectExtensions { private static readonly ILog Log = LogManager.GetCurrentClassLogger(); - public static bool ShouldBeIgnored(this Project project, ICollection projectsToInclude, ICollection projectsToIgnore) + public static bool ShouldBeIgnored(string projectName, ICollection projectsToInclude, ICollection projectsToIgnore) { - Argument.IsNotNull(() => project); - - var projectName = GetProjectName(project).ToLower(); + Argument.IsNotNull(() => projectName); if (projectsToIgnore.Any(projectToIgnore => string.Equals(projectName, projectToIgnore, StringComparison.InvariantCultureIgnoreCase))) { diff --git a/src/GitLink/Linker.cs b/src/GitLink/Linker.cs index e181834..6a9014c 100644 --- a/src/GitLink/Linker.cs +++ b/src/GitLink/Linker.cs @@ -96,7 +96,8 @@ public static int Link(Context context) { try { - if (project.ShouldBeIgnored(context.IncludedProjects, context.IgnoredProjects)) + var projectName = project.GetProjectName(); + if (ProjectExtensions.ShouldBeIgnored(projectName, context.IncludedProjects, context.IgnoredProjects)) { Log.Info("Ignoring '{0}'", project.GetProjectName()); Log.Info(string.Empty); From 3c7d8051370bf21aa9f09e45e3b5b76b099cd72b Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Sat, 2 Jan 2016 22:59:03 +0200 Subject: [PATCH 10/18] Moved ShouldBeIgnored method from ProjectExtensions to ProjectHelpers as it is no longer an extension --- src/GitLink.Tests/ProjectExtensionsFacts.cs | 12 ++++++------ src/GitLink/Extensions/ProjectExtensions.cs | 17 ----------------- src/GitLink/Helpers/ProjectHelper.cs | 17 +++++++++++++++++ src/GitLink/Linker.cs | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/GitLink.Tests/ProjectExtensionsFacts.cs b/src/GitLink.Tests/ProjectExtensionsFacts.cs index 27303c8..9c45f6f 100644 --- a/src/GitLink.Tests/ProjectExtensionsFacts.cs +++ b/src/GitLink.Tests/ProjectExtensionsFacts.cs @@ -13,21 +13,21 @@ public class ProjectExtensionsFacts [Test] public void NoIncludesExcludes_ProjectNotIgnored() { - Assert.IsFalse(ProjectExtensions.ShouldBeIgnored("project", new string[0], new string[0])); + Assert.IsFalse(ProjectHelper.ShouldBeIgnored("project", new string[0], new string[0])); } [TestCase("ignoredProject", true)] [TestCase("nonIgnoredProject", false)] public void ExcludedProject_IgnoredOnlySpecifiedOne(string projectName, bool expectedIgnore) { - Assert.AreEqual(expectedIgnore, ProjectExtensions.ShouldBeIgnored(projectName, new string[0], new[] { "ignoredProject" })); + Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, new string[0], new[] { "ignoredProject" })); } [TestCase("anotherProject", true)] [TestCase("includedProject", false)] public void ExplicitlyIncludedProject_OthersAreIgnored(string projectName, bool expectedIgnore) { - Assert.AreEqual(expectedIgnore, ProjectExtensions.ShouldBeIgnored(projectName, new[] { "includedProject" }, new string[0])); + Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, new[] { "includedProject" }, new string[0])); } [TestCase("excludedProject", true)] @@ -36,9 +36,9 @@ public void ExplicitlyIncludedProject_OthersAreIgnored(string projectName, bool [TestCase("notIncludedNorExcludedProject", true)] public void BothIncludedAndExcludedProjects(string projectName, bool expectedIgnore) { - Assert.AreEqual(expectedIgnore, ProjectExtensions.ShouldBeIgnored(projectName, - new[] { "includedProject", "includedAndExcludedProject" }, - new[] { "excludedProject", "includedAndExcludedProject" })); + Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, + new[] { "includedProject", "includedAndExcludedProject" }, + new[] { "excludedProject", "includedAndExcludedProject" })); } } } \ No newline at end of file diff --git a/src/GitLink/Extensions/ProjectExtensions.cs b/src/GitLink/Extensions/ProjectExtensions.cs index 6e8a0a0..af0c1e9 100644 --- a/src/GitLink/Extensions/ProjectExtensions.cs +++ b/src/GitLink/Extensions/ProjectExtensions.cs @@ -20,23 +20,6 @@ public static class ProjectExtensions { private static readonly ILog Log = LogManager.GetCurrentClassLogger(); - public static bool ShouldBeIgnored(string projectName, ICollection projectsToInclude, ICollection projectsToIgnore) - { - Argument.IsNotNull(() => projectName); - - if (projectsToIgnore.Any(projectToIgnore => string.Equals(projectName, projectToIgnore, StringComparison.InvariantCultureIgnoreCase))) - { - return true; - } - - if (projectsToInclude.Count > 0 && !projectsToInclude.Any(projectToInclude => string.Equals(projectName, projectToInclude, StringComparison.InvariantCultureIgnoreCase))) - { - return true; - } - - return false; - } - public static string GetProjectName(this Project project) { Argument.IsNotNull(() => project); diff --git a/src/GitLink/Helpers/ProjectHelper.cs b/src/GitLink/Helpers/ProjectHelper.cs index d28e20f..ff04594 100644 --- a/src/GitLink/Helpers/ProjectHelper.cs +++ b/src/GitLink/Helpers/ProjectHelper.cs @@ -116,5 +116,22 @@ public static Project LoadProject(string projectFile, string configurationName, return null; } } + + public static bool ShouldBeIgnored(string projectName, ICollection projectsToInclude, ICollection projectsToIgnore) + { + Argument.IsNotNull(() => projectName); + + if (projectsToIgnore.Any(projectToIgnore => String.Equals(projectName, projectToIgnore, StringComparison.InvariantCultureIgnoreCase))) + { + return true; + } + + if (projectsToInclude.Count > 0 && !projectsToInclude.Any(projectToInclude => String.Equals(projectName, projectToInclude, StringComparison.InvariantCultureIgnoreCase))) + { + return true; + } + + return false; + } } } \ No newline at end of file diff --git a/src/GitLink/Linker.cs b/src/GitLink/Linker.cs index 6a9014c..75ab87d 100644 --- a/src/GitLink/Linker.cs +++ b/src/GitLink/Linker.cs @@ -97,7 +97,7 @@ public static int Link(Context context) try { var projectName = project.GetProjectName(); - if (ProjectExtensions.ShouldBeIgnored(projectName, context.IncludedProjects, context.IgnoredProjects)) + if (ProjectHelper.ShouldBeIgnored(projectName, context.IncludedProjects, context.IgnoredProjects)) { Log.Info("Ignoring '{0}'", project.GetProjectName()); Log.Info(string.Empty); From aa2d9ff0efc8593cecb7593915685bbc9c320adb Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Sat, 2 Jan 2016 23:17:14 +0200 Subject: [PATCH 11/18] Added support for regex patterns to project inclusions/exclusions with unit tests --- src/GitLink.Tests/ArgumentParserFacts.cs | 15 +++++++++++++ src/GitLink.Tests/ProjectExtensionsFacts.cs | 24 ++++++++++++++------- src/GitLink/Helpers/ProjectHelper.cs | 20 +++++++++++++++-- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/GitLink.Tests/ArgumentParserFacts.cs b/src/GitLink.Tests/ArgumentParserFacts.cs index 5a53ba0..f93bd13 100644 --- a/src/GitLink.Tests/ArgumentParserFacts.cs +++ b/src/GitLink.Tests/ArgumentParserFacts.cs @@ -134,6 +134,21 @@ public void CorrectlyParsesIncludedProjects() Assert.AreEqual("test2", context.IncludedProjects[1]); } + [TestCase] + public void CorrectlyParsesIncludedProjectsWithRegex() + { + var context = ArgumentParser.ParseArguments("solutionDirectory -u http://github.com/CatenaLogic/GitLink -debug -c someConfiguration -include test1,/*.test*2/"); + + Assert.AreEqual("solutionDirectory", context.SolutionDirectory); + Assert.AreEqual("http://github.com/CatenaLogic/GitLink", context.TargetUrl); + Assert.AreEqual("someConfiguration", context.ConfigurationName); + Assert.IsTrue(context.IsDebug); + + Assert.AreEqual(2, context.IncludedProjects.Count); + Assert.AreEqual("test1", context.IncludedProjects[0]); + Assert.AreEqual("/*.test*2/", context.IncludedProjects[1]); + } + [TestCase] public void ThrowsExceptionForUnknownArgument() { diff --git a/src/GitLink.Tests/ProjectExtensionsFacts.cs b/src/GitLink.Tests/ProjectExtensionsFacts.cs index 9c45f6f..5a68e51 100644 --- a/src/GitLink.Tests/ProjectExtensionsFacts.cs +++ b/src/GitLink.Tests/ProjectExtensionsFacts.cs @@ -16,18 +16,26 @@ public void NoIncludesExcludes_ProjectNotIgnored() Assert.IsFalse(ProjectHelper.ShouldBeIgnored("project", new string[0], new string[0])); } - [TestCase("ignoredProject", true)] - [TestCase("nonIgnoredProject", false)] - public void ExcludedProject_IgnoredOnlySpecifiedOne(string projectName, bool expectedIgnore) + [TestCase("ignoredProject", "ignoredProject", true)] + [TestCase("ignoredProject", "ignoredproject", true)] + [TestCase("ignoredProject", "/ignoredProject/", true)] + [TestCase("ignoredProject", "/ignoredproject/", true)] + [TestCase("ignoredProject", "/^i\\w+t$/", true)] + [TestCase("nonIgnoredProject", "ignoredProject", false)] + public void ExcludedProject_IgnoredOnlySpecifiedOne(string projectName, string ignorePattern, bool expectedIgnore) { - Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, new string[0], new[] { "ignoredProject" })); + Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, new string[0], new[] { ignorePattern })); } - [TestCase("anotherProject", true)] - [TestCase("includedProject", false)] - public void ExplicitlyIncludedProject_OthersAreIgnored(string projectName, bool expectedIgnore) + [TestCase("anotherProject", "includedProject", true)] + [TestCase("anotherProject", "includedproject", true)] + [TestCase("anotherProject", "/includedProject/", true)] + [TestCase("anotherProject", "/includedproject/", true)] + [TestCase("anotherProject", "/[a-z]+/", false)] + [TestCase("includedProject", "includedProject", false)] + public void ExplicitlyIncludedProject_OthersAreIgnored(string projectName, string includePattern, bool expectedIgnore) { - Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, new[] { "includedProject" }, new string[0])); + Assert.AreEqual(expectedIgnore, ProjectHelper.ShouldBeIgnored(projectName, new[] { includePattern }, new string[0])); } [TestCase("excludedProject", true)] diff --git a/src/GitLink/Helpers/ProjectHelper.cs b/src/GitLink/Helpers/ProjectHelper.cs index ff04594..778e13f 100644 --- a/src/GitLink/Helpers/ProjectHelper.cs +++ b/src/GitLink/Helpers/ProjectHelper.cs @@ -16,6 +16,7 @@ namespace GitLink using Catel.Reflection; using Microsoft.Build.Evaluation; using System.IO; + using System.Text.RegularExpressions; public static class ProjectHelper { @@ -121,17 +122,32 @@ public static bool ShouldBeIgnored(string projectName, ICollection proje { Argument.IsNotNull(() => projectName); - if (projectsToIgnore.Any(projectToIgnore => String.Equals(projectName, projectToIgnore, StringComparison.InvariantCultureIgnoreCase))) + if (projectsToIgnore.Any(projectToIgnore => ProjectNameMatchesPattern(projectName, projectToIgnore))) { return true; } - if (projectsToInclude.Count > 0 && !projectsToInclude.Any(projectToInclude => String.Equals(projectName, projectToInclude, StringComparison.InvariantCultureIgnoreCase))) + if (projectsToInclude.Count == 0) return false; + + if (projectsToInclude.All(projectToInclude => !ProjectNameMatchesPattern(projectName, projectToInclude))) { return true; } return false; } + + // pattern may be either a literal string, and then we'll be comparing literally ignoring case + // or it can be a regex eclosed in slashes like /this-is-my-regex/ + private static bool ProjectNameMatchesPattern(string projectName, string pattern) + { + if (pattern.Length > 2 && pattern.StartsWith("/") && pattern.EndsWith("/")) + { + var ignoreRegex = new Regex(pattern.Substring(1, pattern.Length - 2), RegexOptions.IgnoreCase); + if (ignoreRegex.IsMatch(projectName)) + return true; + } + return string.Equals(projectName, pattern, StringComparison.InvariantCultureIgnoreCase); + } } } \ No newline at end of file From 24f8169ed1cc06efc254ecf1f95e83d9552eb240 Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Sat, 2 Jan 2016 23:25:34 +0200 Subject: [PATCH 12/18] Updated docs in readme with new -include and -exclude enhancements --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b2762e2..450bb06 100644 --- a/README.md +++ b/README.md @@ -114,12 +114,22 @@ Sometimes a repository contains more than 1 solution file. By default, all solut GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -## Ignoring projects +## Ignoring projects and excplicitly including them -When specific projects should be ignored, use the *-ignore* option. This option accepts a comma separated list of projects to ignore: +When specific projects should be ignored, use the *-ignore* option. This option accepts a comma separated list of patterns to ignore. Each pattern is either a literal project name (case-insensitive) or a regex enclosed in slashes. For example: GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -ignore Catel.Core.WP80,Catel.MVVM.WP80 + GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -ignore /^.+\.WP80$/,Catel.Core +In case you want to ignore most of your projects, you can explicitly *-include* only the projects you need - others will be ignored automatically. Same as *-ignore* it accepts list of patterns. For example: + + GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -include Catel.Core + GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -include /Catel\..*$/,SomeOtherProject + +Finally, you can set both *-ignore* and *-include* options. In this case only projects matching one of *-include* patterns will be taken, but if and only if they don't match one of *-ignore*s. For example, the following command line will include only Catel.* projects, except "Catel.Core": + + GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -include /Catel\..*$/ -ignore Catel.Core + ## Running for an uncommon / customized URL When working with a repository using uncommon URL you can use placeholders to specifiy where the filename and revision hash should be, use `-u` parameter with the custom URL From 655f4c16f8d89b1a32a1aae298d615a0ffa1522f Mon Sep 17 00:00:00 2001 From: ivan-danilov Date: Mon, 4 Jan 2016 15:05:56 +0200 Subject: [PATCH 13/18] Fixup after review and typo fix. --- src/GitLink/Helpers/ProjectHelper.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/GitLink/Helpers/ProjectHelper.cs b/src/GitLink/Helpers/ProjectHelper.cs index 778e13f..f4172fa 100644 --- a/src/GitLink/Helpers/ProjectHelper.cs +++ b/src/GitLink/Helpers/ProjectHelper.cs @@ -127,7 +127,10 @@ public static bool ShouldBeIgnored(string projectName, ICollection proje return true; } - if (projectsToInclude.Count == 0) return false; + if (projectsToInclude.Count == 0) + { + return false; + } if (projectsToInclude.All(projectToInclude => !ProjectNameMatchesPattern(projectName, projectToInclude))) { @@ -138,14 +141,18 @@ public static bool ShouldBeIgnored(string projectName, ICollection proje } // pattern may be either a literal string, and then we'll be comparing literally ignoring case - // or it can be a regex eclosed in slashes like /this-is-my-regex/ + // or it can be a regex enclosed in slashes like /this-is-my-regex/ private static bool ProjectNameMatchesPattern(string projectName, string pattern) { + Argument.IsNotNull(() => pattern); + if (pattern.Length > 2 && pattern.StartsWith("/") && pattern.EndsWith("/")) { var ignoreRegex = new Regex(pattern.Substring(1, pattern.Length - 2), RegexOptions.IgnoreCase); if (ignoreRegex.IsMatch(projectName)) + { return true; + } } return string.Equals(projectName, pattern, StringComparison.InvariantCultureIgnoreCase); } From a4e0a1c6e58f974c1061a3abea63e56dcb2ce507 Mon Sep 17 00:00:00 2001 From: Cameron MacFarland Date: Thu, 7 Jan 2016 18:23:03 +0800 Subject: [PATCH 14/18] Fixed resource location when GitLink isn't the entry assembly --- src/GitLink/Helpers/ResourceHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitLink/Helpers/ResourceHelper.cs b/src/GitLink/Helpers/ResourceHelper.cs index 402036c..e19cbe7 100644 --- a/src/GitLink/Helpers/ResourceHelper.cs +++ b/src/GitLink/Helpers/ResourceHelper.cs @@ -14,7 +14,7 @@ public static class ResourceHelper { public static void ExtractEmbeddedResource(string resourceName, string destinationFileName) { - var assembly = AssemblyHelper.GetEntryAssembly(); + var assembly = typeof(ResourceHelper).Assembly; using (var resource = assembly.GetManifestResourceStream(resourceName)) { From 3ce21eae683a4a7b30ace7d0aa4ac31613d1a864 Mon Sep 17 00:00:00 2001 From: Cameron MacFarland Date: Thu, 7 Jan 2016 18:23:19 +0800 Subject: [PATCH 15/18] Updated example code in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 450bb06..b0c798f 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ The command line implementation uses the same available API. To link files to a Git project, a context must be created. The command line version does this by using the *ArgumentParser* class. It is also possible to create a context from scratch as shown in the example below: - var context = new GitLink.Context(); + var context = new GitLink.Context(new ProviderManager()); context.SolutionDirectory = @"c:\source\catel"; context.TargetUrl = "https://github.com/catel/catel"; context.TargetBranch = "develop"; From 0f3c4e53d36d9f59fac7bacf09e53f54f0e83d2a Mon Sep 17 00:00:00 2001 From: Geert van Horrik Date: Sun, 10 Jan 2016 17:40:02 +0100 Subject: [PATCH 16/18] Fixed typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b0c798f..0ba8c41 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ Sometimes a repository contains more than 1 solution file. By default, all solut GitLink.exe c:\source\catel -u https://github.com/catel/catel -f Catel.sln -## Ignoring projects and excplicitly including them +## Ignoring projects and explicitly including them When specific projects should be ignored, use the *-ignore* option. This option accepts a comma separated list of patterns to ignore. Each pattern is either a literal project name (case-insensitive) or a regex enclosed in slashes. For example: From d0341e92b09b4a35ecc4f906e6789e388518a555 Mon Sep 17 00:00:00 2001 From: Geoffrey Huntley Date: Mon, 28 Mar 2016 09:05:49 +1100 Subject: [PATCH 17/18] ReactiveUI is now using GitLink --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0ba8c41..c9dc396 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,7 @@ Below is a list of projects already using GitLink (alphabetically ordered). - Orc.Wizard - Orchestra - OxyPlot +- ReactiveUI - Romantic Web - xUnit.net - xUnit.net Visual Studio Runner From 5c32172ee4550292074c73b88b7c00aff69e6ff2 Mon Sep 17 00:00:00 2001 From: nopara73 Date: Fri, 13 May 2016 12:58:21 +0900 Subject: [PATCH 18/18] NBitcoin, NBitcoin.Indexer and QBitNinja added to the project list --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c9dc396..a9d532e 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,8 @@ Below is a list of projects already using GitLink (alphabetically ordered). - Fluent.Ribbon - GitLink - MahApps.Metro +- NBitcoin +- NBitcoin.Indexer - NEST and Elasticsearch.NET - Orc.Analytics - Orc.AutomaticSupport @@ -245,6 +247,7 @@ Below is a list of projects already using GitLink (alphabetically ordered). - Orc.Wizard - Orchestra - OxyPlot +- QBitNinja - ReactiveUI - Romantic Web - xUnit.net