diff --git a/src/GitVersionCore.Tests/ExecuteCoreTests.cs b/src/GitVersionCore.Tests/ExecuteCoreTests.cs new file mode 100644 index 0000000000..f1018d1107 --- /dev/null +++ b/src/GitVersionCore.Tests/ExecuteCoreTests.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Concurrent; +using System.Text; + +using GitVersion; +using GitVersion.Helpers; + +using NUnit.Framework; + +using Shouldly; + +[TestFixture] +public class ExecuteCoreTests +{ + IFileSystem fileSystem; + + + [SetUp] + public void SetUp() + { + this.fileSystem = new FileSystem(); + } + + + [Test] + public void CacheFileExistsOnDisk() + { + const string versionCacheFileContent = @" +Major: 4 +Minor: 10 +Patch: 3 +PreReleaseTag: test.19 +PreReleaseTagWithDash: -test.19 +BuildMetaData: +BuildMetaDataPadded: +FullBuildMetaData: Branch.feature/test.Sha.dd2a29aff0c948e1bdf3dabbe13e1576e70d5f9f +MajorMinorPatch: 4.10.3 +SemVer: 4.10.3-test.19 +LegacySemVer: 4.10.3-test19 +LegacySemVerPadded: 4.10.3-test0019 +AssemblySemVer: 4.10.3.0 +FullSemVer: 4.10.3-test.19 +InformationalVersion: 4.10.3-test.19+Branch.feature/test.Sha.dd2a29aff0c948e1bdf3dabbe13e1576e70d5f9f +BranchName: feature/test +Sha: dd2a29aff0c948e1bdf3dabbe13e1576e70d5f9f +NuGetVersionV2: 4.10.3-test0019 +NuGetVersion: 4.10.3-test0019 +CommitsSinceVersionSource: 19 +CommitsSinceVersionSourcePadded: 0019 +CommitDate: 2015-11-10 +"; + + var versionAndBranchFinder = new ExecuteCore(this.fileSystem); + + var info = RepositoryScope(versionAndBranchFinder, (fixture, vv) => + { + this.fileSystem.WriteAllText(vv.FileName, versionCacheFileContent); + vv = versionAndBranchFinder.ExecuteGitVersion(null, null, null, null, false, fixture.RepositoryPath, null); + vv.AssemblySemVer.ShouldBe("4.10.3.0"); + }); + + info.ShouldContain("Deserializing version variables from cache file", () => info); + } + + + [Test] + public void CacheFileExistsInMemory() + { + var cache = new ConcurrentDictionary(); + var versionAndBranchFinder = new ExecuteCore(this.fileSystem, cache.GetOrAdd); + + var info = RepositoryScope(versionAndBranchFinder, (fixture, vv) => + { + vv = versionAndBranchFinder.ExecuteGitVersion(null, null, null, null, false, fixture.RepositoryPath, null); + vv.AssemblySemVer.ShouldBe("0.1.0.0"); + }); + + info.ShouldContain("yml not found", () => info); + info.ShouldNotContain("Deserializing version variables from cache file", () => info); + } + + + [Test] + public void CacheFileIsMissing() + { + var info = RepositoryScope(); + info.ShouldContain("yml not found", () => info); + } + + + string RepositoryScope(ExecuteCore executeCore = null, Action fixtureAction = null) + { + var infoBuilder = new StringBuilder(); + Action infoLogger = s => { infoBuilder.AppendLine(s); }; + executeCore = executeCore ?? new ExecuteCore(this.fileSystem); + + Logger.SetLoggers(infoLogger, s => { }, s => { }); + + using (var fixture = new EmptyRepositoryFixture(new Config())) + { + fixture.Repository.MakeACommit(); + var vv = executeCore.ExecuteGitVersion(null, null, null, null, false, fixture.RepositoryPath, null); + + vv.AssemblySemVer.ShouldBe("0.1.0.0"); + vv.FileName.ShouldNotBeNullOrEmpty(); + + if (fixtureAction != null) + { + fixtureAction(fixture, vv); + } + } + + return infoBuilder.ToString(); + } +} \ No newline at end of file diff --git a/src/GitVersionCore.Tests/GitDirFinderTests.cs b/src/GitVersionCore.Tests/FileSystemTests.cs similarity index 63% rename from src/GitVersionCore.Tests/GitDirFinderTests.cs rename to src/GitVersionCore.Tests/FileSystemTests.cs index acae8f587d..4d7e8f7de6 100644 --- a/src/GitVersionCore.Tests/GitDirFinderTests.cs +++ b/src/GitVersionCore.Tests/FileSystemTests.cs @@ -1,11 +1,13 @@ using System; using System.IO; using GitVersion; +using GitVersion.Helpers; + using LibGit2Sharp; using NUnit.Framework; [TestFixture] -public class GitDirFinderTests +public class FileSystemTests { string workDirectory; string gitDirectory; @@ -15,8 +17,7 @@ public void CreateTemporaryRepository() { workDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - gitDirectory = Repository.Init(workDirectory) - .TrimEnd(new[] { Path.DirectorySeparatorChar }); + gitDirectory = Repository.Init(workDirectory); Assert.NotNull(gitDirectory); } @@ -30,26 +31,26 @@ public void Cleanup() [Test] public void From_WorkingDirectory() { - Assert.AreEqual(gitDirectory, GitDirFinder.TreeWalkForDotGitDir(workDirectory)); + Assert.AreEqual(gitDirectory, Repository.Discover(workDirectory)); } [Test] public void From_WorkingDirectory_Parent() { var parentDirectory = Directory.GetParent(workDirectory).FullName; - Assert.Null(GitDirFinder.TreeWalkForDotGitDir(parentDirectory)); + Assert.Null(Repository.Discover(parentDirectory)); } [Test] public void From_GitDirectory() { - Assert.AreEqual(gitDirectory, GitDirFinder.TreeWalkForDotGitDir(gitDirectory)); + Assert.AreEqual(gitDirectory, Repository.Discover(gitDirectory)); } [Test] public void From_RefsDirectory() { var refsDirectory = Path.Combine(gitDirectory, "refs"); - Assert.AreEqual(gitDirectory, GitDirFinder.TreeWalkForDotGitDir(refsDirectory)); + Assert.AreEqual(gitDirectory, Repository.Discover(refsDirectory)); } } diff --git a/src/GitVersionCore.Tests/Fixtures/RemoteRepositoryFixture.cs b/src/GitVersionCore.Tests/Fixtures/RemoteRepositoryFixture.cs index 73c96dc4eb..ce53cb1e8c 100644 --- a/src/GitVersionCore.Tests/Fixtures/RemoteRepositoryFixture.cs +++ b/src/GitVersionCore.Tests/Fixtures/RemoteRepositoryFixture.cs @@ -1,5 +1,7 @@ using System; using GitVersion; +using GitVersion.Helpers; + using LibGit2Sharp; public class RemoteRepositoryFixture : RepositoryFixtureBase diff --git a/src/GitVersionCore.Tests/GitPreparerTests.cs b/src/GitVersionCore.Tests/GitPreparerTests.cs index 706156fc27..ff9b344e1c 100644 --- a/src/GitVersionCore.Tests/GitPreparerTests.cs +++ b/src/GitVersionCore.Tests/GitPreparerTests.cs @@ -2,6 +2,8 @@ using System.IO; using System.Linq; using GitVersion; +using GitVersion.Helpers; + using LibGit2Sharp; using NUnit.Framework; using Shouldly; diff --git a/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj b/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj index e3ab9742b7..22607d952f 100644 --- a/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj +++ b/src/GitVersionCore.Tests/GitVersionCore.Tests.csproj @@ -72,6 +72,10 @@ ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll True + + ..\packages\NSubstitute.1.9.2.0\lib\net45\NSubstitute.dll + True + ..\packages\NUnitTestAdapter.2.0.0\lib\nunit.core.dll True @@ -124,7 +128,7 @@ - + @@ -174,6 +178,7 @@ + diff --git a/src/GitVersionCore.Tests/TestFileSystem.cs b/src/GitVersionCore.Tests/TestFileSystem.cs index dba500611c..50b4dcde16 100644 --- a/src/GitVersionCore.Tests/TestFileSystem.cs +++ b/src/GitVersionCore.Tests/TestFileSystem.cs @@ -1,52 +1,97 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text; + using GitVersion.Helpers; +using LibGit2Sharp; + public class TestFileSystem : IFileSystem { Dictionary fileSystem = new Dictionary(); + public void Copy(string @from, string to, bool overwrite) { throw new NotImplementedException(); } + public void Move(string @from, string to) { throw new NotImplementedException(); } + public bool Exists(string file) { - return fileSystem.ContainsKey(file); + return this.fileSystem.ContainsKey(file); } + public void Delete(string path) { throw new NotImplementedException(); } + public string ReadAllText(string path) { - return fileSystem[path]; + return this.fileSystem[path]; } + public void WriteAllText(string file, string fileContents) { - if (fileSystem.ContainsKey(file)) - fileSystem[file] = fileContents; + if (this.fileSystem.ContainsKey(file)) + { + this.fileSystem[file] = fileContents; + } else - fileSystem.Add(file, fileContents); + { + this.fileSystem.Add(file, fileContents); + } } + public IEnumerable DirectoryGetFiles(string directory, string searchPattern, SearchOption searchOption) { throw new NotImplementedException(); } + public Stream OpenWrite(string path) { return new TestStream(path, this); } + + + public Stream OpenRead(string path) + { + if (this.fileSystem.ContainsKey(path)) + { + var content = this.fileSystem[path]; + return new MemoryStream(Encoding.UTF8.GetBytes(content)); + } + + throw new FileNotFoundException("File not found.", path); + } + + + public void CreateDirectory(string path) + { + } + + + public long GetLastDirectoryWrite(string path) + { + return 1; + } + + + public IRepository GetRepository(string gitDirectory) + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/src/GitVersionCore.Tests/packages.config b/src/GitVersionCore.Tests/packages.config index 94bf961fe7..2b351bce70 100644 --- a/src/GitVersionCore.Tests/packages.config +++ b/src/GitVersionCore.Tests/packages.config @@ -7,6 +7,7 @@ + diff --git a/src/GitVersionCore/ExecuteCore.cs b/src/GitVersionCore/ExecuteCore.cs index 16389b46af..6d1cafc604 100644 --- a/src/GitVersionCore/ExecuteCore.cs +++ b/src/GitVersionCore/ExecuteCore.cs @@ -1,12 +1,164 @@ namespace GitVersion { using System; + using System.Collections.Generic; + using System.IO; using System.Linq; + using System.Security.Cryptography; + using System.Text; + using GitVersion.Helpers; - public static class ExecuteCore + using LibGit2Sharp; + + using YamlDotNet.Serialization; + + public class ExecuteCore { - public static VersionVariables ExecuteGitVersion(IFileSystem fileSystem, string targetUrl, string dynamicRepositoryLocation, Authentication authentication, string targetBranch, bool noFetch, string workingDirectory, string commitId) + readonly IFileSystem fileSystem; + readonly Func, VersionVariables> getOrAddFromCache; + + + public ExecuteCore(IFileSystem fileSystem, Func, VersionVariables> getOrAddFromCache = null) + { + if (fileSystem == null) + { + throw new ArgumentNullException("fileSystem"); + } + + this.getOrAddFromCache = getOrAddFromCache; + this.fileSystem = fileSystem; + } + + + public VersionVariables ExecuteGitVersion(string targetUrl, string dynamicRepositoryLocation, Authentication authentication, string targetBranch, bool noFetch, string workingDirectory, string commitId) + { + var gitDir = Repository.Discover(workingDirectory); + using (var repo = this.fileSystem.GetRepository(gitDir)) + { + // Maybe using timestamp in .git/refs directory is enough? + var ticks = this.fileSystem.GetLastDirectoryWrite(Path.Combine(gitDir, "refs")); + var key = string.Format("{0}:{1}:{2}:{3}", gitDir, repo.Head.CanonicalName, repo.Head.Tip.Sha, ticks); + + if (this.getOrAddFromCache != null) + { + return this.getOrAddFromCache(key, k => + { + Logger.WriteInfo("Version not in memory cache. Attempting to load version from disk cache."); + return LoadVersionVariablesFromDiskCache(key, gitDir, targetUrl, dynamicRepositoryLocation, authentication, targetBranch, noFetch, workingDirectory, commitId); + }); + } + + return LoadVersionVariablesFromDiskCache(key, gitDir, targetUrl, dynamicRepositoryLocation, authentication, targetBranch, noFetch, workingDirectory, commitId); + } + } + + + public bool TryGetVersion(string directory, out VersionVariables versionVariables, bool noFetch, Authentication authentication) + { + try + { + versionVariables = ExecuteGitVersion(null, null, authentication, null, noFetch, directory, null); + return true; + } + catch (Exception ex) + { + Logger.WriteWarning("Could not determine assembly version: " + ex); + versionVariables = null; + return false; + } + } + + + static string ResolveCurrentBranch(IBuildServer buildServer, string targetBranch) + { + if (buildServer == null) + { + return targetBranch; + } + + var currentBranch = buildServer.GetCurrentBranch() ?? targetBranch; + Logger.WriteInfo("Branch from build environment: " + currentBranch); + + return currentBranch; + } + + + VersionVariables LoadVersionVariablesFromDiskCache(string key, string gitDir, string targetUrl, string dynamicRepositoryLocation, Authentication authentication, string targetBranch, bool noFetch, string workingDirectory, string commitId) + { + using (Logger.IndentLog("Loading version variables from disk cache")) + { + string cacheKey; + using (var sha1 = SHA1.Create()) + { + // Make a shorter key by hashing, to avoid having to long cache filename. + cacheKey = BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(key))).Replace("-", ""); + } + + var cacheDir = Path.Combine(gitDir, "gitversion_cache"); + // If the cacheDir already exists, CreateDirectory just won't do anything (it won't fail). @asbjornu + this.fileSystem.CreateDirectory(cacheDir); + + var cacheFileName = string.Concat(Path.Combine(cacheDir, cacheKey), ".yml"); + VersionVariables vv = null; + if (this.fileSystem.Exists(cacheFileName)) + { + using (Logger.IndentLog("Deserializing version variables from cache file " + cacheFileName)) + { + try + { + vv = VersionVariables.FromFile(cacheFileName, fileSystem); + } + catch (Exception ex) + { + Logger.WriteWarning("Unable to read cache file " + cacheFileName + ", deleting it."); + Logger.WriteInfo(ex.ToString()); + try + { + this.fileSystem.Delete(cacheFileName); + } + catch (Exception deleteEx) + { + Logger.WriteWarning(string.Format("Unable to delete corrupted version cache file {0}. Got {1} exception.", cacheFileName, deleteEx.GetType().FullName)); + } + } + } + } + else + { + Logger.WriteInfo("Cache file " + cacheFileName + " not found."); + } + + if (vv == null) + { + vv = ExecuteInternal(targetUrl, dynamicRepositoryLocation, authentication, targetBranch, noFetch, workingDirectory, commitId); + vv.FileName = cacheFileName; + + using (var stream = fileSystem.OpenWrite(cacheFileName)) + { + using (var sw = new StreamWriter(stream)) + { + Dictionary dictionary; + using (Logger.IndentLog("Creating dictionary")) + { + dictionary = vv.ToDictionary(x => x.Key, x => x.Value); + } + + using (Logger.IndentLog("Storing version variables to cache file " + cacheFileName)) + { + var serializer = new Serializer(); + serializer.Serialize(sw, dictionary); + } + } + } + } + + return vv; + } + } + + + VersionVariables ExecuteInternal(string targetUrl, string dynamicRepositoryLocation, Authentication authentication, string targetBranch, bool noFetch, string workingDirectory, string commitId) { // Normalise if we are running on build server var gitPreparer = new GitPreparer(targetUrl, dynamicRepositoryLocation, authentication, noFetch, workingDirectory); @@ -27,24 +179,14 @@ public static VersionVariables ExecuteGitVersion(IFileSystem fileSystem, string var versionFinder = new GitVersionFinder(); var configuration = ConfigurationProvider.Provide(projectRoot, fileSystem); - using (var repo = RepositoryLoader.GetRepo(dotGitDirectory)) + using (var repo = this.fileSystem.GetRepository(dotGitDirectory)) { - var gitVersionContext = new GitVersionContext(repo, configuration, commitId: commitId); + var gitVersionContext = new GitVersionContext(repo, configuration, commitId : commitId); var semanticVersion = versionFinder.FindVersion(gitVersionContext); variables = VariableProvider.GetVariablesFor(semanticVersion, gitVersionContext.Configuration, gitVersionContext.IsCurrentCommitTagged); } return variables; } - - private static string ResolveCurrentBranch(IBuildServer buildServer, string targetBranch) - { - if (buildServer == null) return targetBranch; - - var currentBranch = buildServer.GetCurrentBranch() ?? targetBranch; - Logger.WriteInfo("Branch from build environment: " + currentBranch); - - return currentBranch; - } } } \ No newline at end of file diff --git a/src/GitVersionCore/GitDirFinder.cs b/src/GitVersionCore/GitDirFinder.cs deleted file mode 100644 index 9478cc8da8..0000000000 --- a/src/GitVersionCore/GitDirFinder.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace GitVersion -{ - using System.IO; - using LibGit2Sharp; - - public class GitDirFinder - { - public static string TreeWalkForDotGitDir(string currentDirectory) - { - var gitDirectory = Repository.Discover(currentDirectory); - - if (gitDirectory != null) - { - return gitDirectory.TrimEnd(Path.DirectorySeparatorChar); - } - - return null; - } - } -} \ No newline at end of file diff --git a/src/GitVersionCore/GitPreparer.cs b/src/GitVersionCore/GitPreparer.cs index afc0acc8c6..92d5ec7e14 100644 --- a/src/GitVersionCore/GitPreparer.cs +++ b/src/GitVersionCore/GitPreparer.cs @@ -3,15 +3,17 @@ namespace GitVersion using System; using System.IO; using System.Linq; + using LibGit2Sharp; public class GitPreparer { - string targetUrl; - string dynamicRepositoryLocation; Authentication authentication; + string dynamicRepositoryLocation; bool noFetch; string targetPath; + string targetUrl; + public GitPreparer(string targetUrl, string dynamicRepositoryLocation, Authentication authentication, bool noFetch, string targetPath) { @@ -22,6 +24,7 @@ public GitPreparer(string targetUrl, string dynamicRepositoryLocation, Authentic this.targetPath = targetPath; } + public bool IsDynamicGitRepository { get { return !string.IsNullOrWhiteSpace(DynamicGitRepositoryPath); } @@ -29,6 +32,7 @@ public bool IsDynamicGitRepository public string DynamicGitRepositoryPath { get; private set; } + public void Initialise(bool normaliseGitDirectory, string currentBranch) { if (string.IsNullOrWhiteSpace(targetUrl)) @@ -45,6 +49,7 @@ public void Initialise(bool normaliseGitDirectory, string currentBranch) DynamicGitRepositoryPath = CreateDynamicRepository(tempRepositoryPath, authentication, targetUrl, currentBranch, noFetch); } + static string CalculateTemporaryRepositoryPath(string targetUrl, string dynamicRepositoryLocation) { var userTemp = dynamicRepositoryLocation ?? Path.GetTempPath(); @@ -70,6 +75,7 @@ static string CalculateTemporaryRepositoryPath(string targetUrl, string dynamicR return possiblePath; } + static bool GitRepoHasMatchingRemote(string possiblePath, string targetUrl) { try @@ -83,25 +89,31 @@ static bool GitRepoHasMatchingRemote(string possiblePath, string targetUrl) { return false; } - } + public string GetDotGitDirectory() { if (IsDynamicGitRepository) + { return DynamicGitRepositoryPath; + } - return GitDirFinder.TreeWalkForDotGitDir(targetPath); + return Repository.Discover(this.targetPath); } + public string GetProjectRootDirectory() { if (IsDynamicGitRepository) + { return targetPath; + } - return Directory.GetParent(GitDirFinder.TreeWalkForDotGitDir(targetPath)).FullName; + return Directory.GetParent(Repository.Discover(this.targetPath)).FullName; } + static string CreateDynamicRepository(string targetPath, Authentication authentication, string repositoryUrl, string targetBranch, bool noFetch) { if (string.IsNullOrWhiteSpace(targetBranch)) @@ -127,7 +139,8 @@ static string CreateDynamicRepository(string targetPath, Authentication authenti return gitDirectory; } - private static void CloneRepository(string repositoryUrl, string gitDirectory, Authentication authentication) + + static void CloneRepository(string repositoryUrl, string gitDirectory, Authentication authentication) { Credentials credentials = null; if (!string.IsNullOrWhiteSpace(authentication.Username) && !string.IsNullOrWhiteSpace(authentication.Password)) @@ -146,11 +159,11 @@ private static void CloneRepository(string repositoryUrl, string gitDirectory, A try { Repository.Clone(repositoryUrl, gitDirectory, - new CloneOptions - { - Checkout = false, - CredentialsProvider = (url, usernameFromUrl, types) => credentials - }); + new CloneOptions + { + Checkout = false, + CredentialsProvider = (url, usernameFromUrl, types) => credentials + }); } catch (LibGit2SharpException ex) { @@ -167,7 +180,7 @@ private static void CloneRepository(string repositoryUrl, string gitDirectory, A { throw new Exception("Not found: The repository was not found"); } - + throw new Exception("There was an unknown problem with the Git repository you provided"); } } diff --git a/src/GitVersionCore/GitVersionCore.csproj b/src/GitVersionCore/GitVersionCore.csproj index e3b6a70db8..e6ad6f289a 100644 --- a/src/GitVersionCore/GitVersionCore.csproj +++ b/src/GitVersionCore/GitVersionCore.csproj @@ -140,7 +140,6 @@ - @@ -152,7 +151,6 @@ - diff --git a/src/GitVersionCore/Helpers/FileSystem.cs b/src/GitVersionCore/Helpers/FileSystem.cs index a92f5ea5bc..1a4b51a544 100644 --- a/src/GitVersionCore/Helpers/FileSystem.cs +++ b/src/GitVersionCore/Helpers/FileSystem.cs @@ -1,7 +1,11 @@ namespace GitVersion.Helpers { + using System; using System.Collections.Generic; using System.IO; + using System.Linq; + + using LibGit2Sharp; public class FileSystem : IFileSystem { @@ -10,39 +14,93 @@ public void Copy(string @from, string to, bool overwrite) File.Copy(from, to, overwrite); } + public void Move(string @from, string to) { File.Move(from, to); } + public bool Exists(string file) { return File.Exists(file); } + public void Delete(string path) { File.Delete(path); } + public string ReadAllText(string path) { return File.ReadAllText(path); } + public void WriteAllText(string file, string fileContents) { File.WriteAllText(file, fileContents); } + public IEnumerable DirectoryGetFiles(string directory, string searchPattern, SearchOption searchOption) { return Directory.GetFiles(directory, searchPattern, searchOption); } + public Stream OpenWrite(string path) { return File.OpenWrite(path); } + + + public Stream OpenRead(string path) + { + return File.OpenRead(path); + } + + + public void CreateDirectory(string path) + { + Directory.CreateDirectory(path); + } + + + public long GetLastDirectoryWrite(string path) + { + return new DirectoryInfo(path) + .GetDirectories("*.*", SearchOption.AllDirectories) + .Select(d => d.LastWriteTimeUtc) + .DefaultIfEmpty() + .Max() + .Ticks; + } + + + public IRepository GetRepository(string gitDirectory) + { + try + { + var repository = new Repository(gitDirectory); + + var branch = repository.Head; + if (branch.Tip == null) + { + throw new WarningException("No Tip found. Has repo been initialized?"); + } + return repository; + } + catch (Exception exception) + { + if (exception.Message.Contains("LibGit2Sharp.Core.NativeMethods") || exception.Message.Contains("FilePathMarshaler")) + { + throw new WarningException("Restart of the process may be required to load an updated version of LibGit2Sharp."); + } + throw; + } + } } } \ No newline at end of file diff --git a/src/GitVersionCore/Helpers/IFileSystem.cs b/src/GitVersionCore/Helpers/IFileSystem.cs index e7c3a0b769..524fd3d293 100644 --- a/src/GitVersionCore/Helpers/IFileSystem.cs +++ b/src/GitVersionCore/Helpers/IFileSystem.cs @@ -3,6 +3,8 @@ namespace GitVersion.Helpers using System.Collections.Generic; using System.IO; + using LibGit2Sharp; + public interface IFileSystem { void Copy(string from, string to, bool overwrite); @@ -13,5 +15,9 @@ public interface IFileSystem void WriteAllText(string file, string fileContents); IEnumerable DirectoryGetFiles(string directory, string searchPattern, SearchOption searchOption); Stream OpenWrite(string path); + Stream OpenRead(string path); + void CreateDirectory(string path); + long GetLastDirectoryWrite(string path); + IRepository GetRepository(string gitDirectory); } } \ No newline at end of file diff --git a/src/GitVersionCore/Logger.cs b/src/GitVersionCore/Logger.cs index d880b0f9cc..9fe8621741 100644 --- a/src/GitVersionCore/Logger.cs +++ b/src/GitVersionCore/Logger.cs @@ -9,16 +9,18 @@ public static class Logger static readonly Regex ObscurePasswordRegex = new Regex("(https?://)(.+)(:.+@)", RegexOptions.Compiled); static string indent = string.Empty; - public static Action WriteInfo { get; private set; } - public static Action WriteWarning { get; private set; } - public static Action WriteError { get; private set; } - static Logger() { Reset(); } + + public static Action WriteInfo { get; private set; } + public static Action WriteWarning { get; private set; } + public static Action WriteError { get; private set; } + + public static IDisposable IndentLog(string operationDescription) { var start = DateTime.Now; @@ -31,6 +33,7 @@ public static IDisposable IndentLog(string operationDescription) }); } + static Action ObscurePassword(Action info) { Action logAction = s => @@ -41,18 +44,36 @@ static Action ObscurePassword(Action info) return logAction; } + public static void SetLoggers(Action info, Action warn, Action error) { + if (info == null) + { + throw new ArgumentNullException("info"); + } + + if (warn == null) + { + throw new ArgumentNullException("warn"); + } + + if (error == null) + { + throw new ArgumentNullException("error"); + } + WriteInfo = LogMessage(ObscurePassword(info), "INFO"); WriteWarning = LogMessage(ObscurePassword(warn), "WARN"); WriteError = LogMessage(ObscurePassword(error), "ERROR"); } + static Action LogMessage(Action logAction, string level) { return s => logAction(string.Format(CultureInfo.InvariantCulture, "{0}{1} [{2:MM/dd/yy H:mm:ss:ff}] {3}", indent, level, DateTime.Now, s)); } + public static void Reset() { WriteInfo = s => { throw new Exception("Logger not defined."); }; @@ -60,15 +81,18 @@ public static void Reset() WriteError = s => { throw new Exception("Logger not defined."); }; } + class ActionDisposable : IDisposable { readonly Action action; + public ActionDisposable(Action action) { this.action = action; } + public void Dispose() { action(); diff --git a/src/GitVersionCore/OutputVariables/VersionVariables.cs b/src/GitVersionCore/OutputVariables/VersionVariables.cs index 8aec43c093..ebc0ab78fe 100644 --- a/src/GitVersionCore/OutputVariables/VersionVariables.cs +++ b/src/GitVersionCore/OutputVariables/VersionVariables.cs @@ -1,13 +1,39 @@ namespace GitVersion { + using System; using System.Collections; using System.Collections.Generic; + using System.IO; using System.Linq; + using GitVersion.Helpers; + + using YamlDotNet.Serialization; + public class VersionVariables : IEnumerable> { - public VersionVariables(string major, string minor, string patch, string buildMetaData, string buildMetaDataPadded, string fullBuildMetaData, string branchName, string sha, string majorMinorPatch, string semVer, string legacySemVer, string legacySemVerPadded, string fullSemVer, string assemblySemVer, string preReleaseTag, string preReleaseTagWithDash, string informationalVersion, - string commitDate, string nugetVersion, string nugetVersionV2, string commitsSinceVersionSource, string commitsSinceVersionSourcePadded) + public VersionVariables(string major, + string minor, + string patch, + string buildMetaData, + string buildMetaDataPadded, + string fullBuildMetaData, + string branchName, + string sha, + string majorMinorPatch, + string semVer, + string legacySemVer, + string legacySemVerPadded, + string fullSemVer, + string assemblySemVer, + string preReleaseTag, + string preReleaseTagWithDash, + string informationalVersion, + string commitDate, + string nugetVersion, + string nugetVersionV2, + string commitsSinceVersionSource, + string commitsSinceVersionSourcePadded) { Major = major; Minor = minor; @@ -33,6 +59,7 @@ public VersionVariables(string major, string minor, string patch, string buildMe CommitsSinceVersionSourcePadded = commitsSinceVersionSourcePadded; } + public string Major { get; private set; } public string Minor { get; private set; } public string Patch { get; private set; } @@ -55,33 +82,75 @@ public VersionVariables(string major, string minor, string patch, string buildMe public string CommitsSinceVersionSource { get; private set; } public string CommitsSinceVersionSourcePadded { get; private set; } + [ReflectionIgnore] public static IEnumerable AvailableVariables { - get { return typeof(VersionVariables).GetProperties().Select(p => p.Name).OrderBy(a => a); } + get + { + return typeof(VersionVariables) + .GetProperties() + .Where(p => !p.GetCustomAttributes(typeof(ReflectionIgnoreAttribute), false).Any()) + .Select(p => p.Name) + .OrderBy(a => a); + } } public string CommitDate { get; set; } + [ReflectionIgnore] + public string FileName { get; set; } + + [ReflectionIgnore] + public string this[string variable] + { + get { return (string)typeof(VersionVariables).GetProperty(variable).GetValue(this, null); } + } + + public IEnumerator> GetEnumerator() { var type = typeof(string); return typeof(VersionVariables) .GetProperties() - .Where(p => p.PropertyType == type && !p.GetIndexParameters().Any()) - .Select(p => new KeyValuePair(p.Name, (string) p.GetValue(this, null))) + .Where(p => p.PropertyType == type && !p.GetIndexParameters().Any() && !p.GetCustomAttributes(typeof(ReflectionIgnoreAttribute), false).Any()) + .Select(p => new KeyValuePair(p.Name, (string)p.GetValue(this, null))) .GetEnumerator(); } + IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } - public string this [string variable] + + public static VersionVariables FromDictionary(IEnumerable> properties) + { + var type = typeof(VersionVariables); + var ctor = type.GetConstructors().Single(); + var ctorArgs = ctor.GetParameters() + .Select(p => properties.Single(v => string.Equals(v.Key, p.Name, StringComparison.CurrentCultureIgnoreCase)).Value) + .Cast() + .ToArray(); + return (VersionVariables)Activator.CreateInstance(type, ctorArgs); + } + + + public static VersionVariables FromFile(string filePath, IFileSystem fileSystem) { - get { return (string) typeof(VersionVariables).GetProperty(variable).GetValue(this, null); } + using (var stream = fileSystem.OpenRead(filePath)) + { + using (var reader = new StreamReader(stream)) + { + var dictionary = new Deserializer().Deserialize>(reader); + var versionVariables = FromDictionary(dictionary); + versionVariables.FileName = filePath; + return versionVariables; + } + } } + public bool TryGetValue(string variable, out string variableValue) { if (ContainsKey(variable)) @@ -94,9 +163,15 @@ public bool TryGetValue(string variable, out string variableValue) return false; } + public bool ContainsKey(string variable) { return typeof(VersionVariables).GetProperty(variable) != null; } + + + sealed class ReflectionIgnoreAttribute : Attribute + { + } } } \ No newline at end of file diff --git a/src/GitVersionCore/RepositoryLoader.cs b/src/GitVersionCore/RepositoryLoader.cs deleted file mode 100644 index 41e0dfece2..0000000000 --- a/src/GitVersionCore/RepositoryLoader.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace GitVersion -{ - using System; - using LibGit2Sharp; - - public class RepositoryLoader - { - public static Repository GetRepo(string gitDirectory) - { - try - { - var repository = new Repository(gitDirectory); - - var branch = repository.Head; - if (branch.Tip == null) - { - throw new WarningException("No Tip found. Has repo been initialized?"); - } - return repository; - } - catch (Exception exception) - { - if (exception.Message.Contains("LibGit2Sharp.Core.NativeMethods") || exception.Message.Contains("FilePathMarshaler")) - { - throw new WarningException("Restart of the process may be required to load an updated version of LibGit2Sharp."); - } - throw; - } - } - } -} \ No newline at end of file diff --git a/src/GitVersionExe.Tests/ExecutionResults.cs b/src/GitVersionExe.Tests/ExecutionResults.cs index 450011df24..ca233858dd 100644 --- a/src/GitVersionExe.Tests/ExecutionResults.cs +++ b/src/GitVersionExe.Tests/ExecutionResults.cs @@ -22,13 +22,7 @@ public virtual VersionVariables OutputVariables get { var outputVariables = new JavaScriptSerializer().Deserialize>(Output); - var type = typeof(VersionVariables); - var ctor = type.GetConstructors().Single(); - var ctorArgs = ctor.GetParameters() - .Select(p => outputVariables.Single(v => v.Key.ToLower() == p.Name.ToLower()).Value) - .Cast() - .ToArray(); - return (VersionVariables) Activator.CreateInstance(type, ctorArgs); + return VersionVariables.FromDictionary(outputVariables); } } } \ No newline at end of file diff --git a/src/GitVersionExe/SpecifiedArgumentRunner.cs b/src/GitVersionExe/SpecifiedArgumentRunner.cs index 30324e4aae..a6e6dc8f98 100644 --- a/src/GitVersionExe/SpecifiedArgumentRunner.cs +++ b/src/GitVersionExe/SpecifiedArgumentRunner.cs @@ -1,13 +1,23 @@ namespace GitVersion { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; + using GitVersion.Helpers; class SpecifiedArgumentRunner { const string MsBuild = @"c:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe"; + static readonly ConcurrentDictionary versionCache; + + + static SpecifiedArgumentRunner() + { + versionCache = new ConcurrentDictionary(); + } + public static void Run(Arguments arguments, IFileSystem fileSystem) { @@ -19,7 +29,8 @@ public static void Run(Arguments arguments, IFileSystem fileSystem) var targetBranch = arguments.TargetBranch; var commitId = arguments.CommitId; - var variables = ExecuteCore.ExecuteGitVersion(fileSystem, targetUrl, dynamicRepositoryLocation, authentication, targetBranch, noFetch, targetPath, commitId); + var executeCore = new ExecuteCore(fileSystem, versionCache.GetOrAdd); + var variables = executeCore.ExecuteGitVersion(targetUrl, dynamicRepositoryLocation, authentication, targetBranch, noFetch, targetPath, commitId); if (arguments.Output == OutputType.BuildServer) { @@ -66,9 +77,13 @@ public static void Run(Arguments arguments, IFileSystem fileSystem) } } + static bool RunMsBuildIfNeeded(Arguments args, string workingDirectory, VersionVariables variables) { - if (string.IsNullOrEmpty(args.Proj)) return false; + if (string.IsNullOrEmpty(args.Proj)) + { + return false; + } Logger.WriteInfo(string.Format("Launching {0} \"{1}\" {2}", MsBuild, args.Proj, args.ProjArgs)); var results = ProcessHelper.Run( @@ -77,14 +92,20 @@ static bool RunMsBuildIfNeeded(Arguments args, string workingDirectory, VersionV GetEnvironmentalVariables(variables)); if (results != 0) + { throw new WarningException("MsBuild execution failed, non-zero return code"); + } return true; } + static bool RunExecCommandIfNeeded(Arguments args, string workingDirectory, VersionVariables variables) { - if (string.IsNullOrEmpty(args.Exec)) return false; + if (string.IsNullOrEmpty(args.Exec)) + { + return false; + } Logger.WriteInfo(string.Format("Launching {0} {1}", args.Exec, args.ExecArgs)); var results = ProcessHelper.Run( @@ -92,11 +113,14 @@ static bool RunExecCommandIfNeeded(Arguments args, string workingDirectory, Vers null, args.Exec, args.ExecArgs, workingDirectory, GetEnvironmentalVariables(variables)); if (results != 0) + { throw new WarningException(string.Format("Execution of {0} failed, non-zero return code", args.Exec)); + } return true; } + static KeyValuePair[] GetEnvironmentalVariables(VersionVariables variables) { return variables diff --git a/src/GitVersionTask.Tests/GetVersionTaskTests.cs b/src/GitVersionTask.Tests/GetVersionTaskTests.cs index 707f7b4eda..0030d56da0 100644 --- a/src/GitVersionTask.Tests/GetVersionTaskTests.cs +++ b/src/GitVersionTask.Tests/GetVersionTaskTests.cs @@ -16,10 +16,7 @@ public void OutputsShouldMatchVariableProvider() .Where(p => p.GetCustomAttributes(typeof(OutputAttribute), false).Any()) .Select(p => p.Name); - var variablesProperties = typeof(VersionVariables) - .GetProperties() - .Select(p => p.Name) - .Except(new[] { "AvailableVariables", "Item" }); + var variablesProperties = VersionVariables.AvailableVariables; taskProperties.ShouldBe(variablesProperties, ignoreOrder: true); } diff --git a/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs b/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs index 0c80458a56..22496879e7 100644 --- a/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs +++ b/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs @@ -1,37 +1,44 @@ using System; using System.IO; + +using GitVersion; + using LibGit2Sharp; + using NUnit.Framework; [TestFixture] public class GitVersionTaskDirectoryTests { - string workDirectory; + ExecuteCore executeCore; string gitDirectory; + string workDirectory; + [SetUp] public void CreateTemporaryRepository() { - workDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - - gitDirectory = Repository.Init(workDirectory) - .TrimEnd(new[] { Path.DirectorySeparatorChar }); - - Assert.NotNull(gitDirectory); + this.workDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + this.gitDirectory = Repository.Init(this.workDirectory) + .TrimEnd(Path.DirectorySeparatorChar); + this.executeCore = new ExecuteCore(new TestFileSystem()); + Assert.NotNull(this.gitDirectory); } + [TearDown] public void Cleanup() { - Directory.Delete(workDirectory, true); + Directory.Delete(this.workDirectory, true); } + [Test] public void Finds_GitDirectory() { try { - VersionAndBranchFinder.GetVersion(workDirectory, null, true, null); + this.executeCore.ExecuteGitVersion(null, null, null, null, true, this.workDirectory, null); } catch (Exception ex) { @@ -41,15 +48,16 @@ public void Finds_GitDirectory() } } + [Test] public void Finds_GitDirectory_In_Parent() { - var childDir = Path.Combine(workDirectory, "child"); + var childDir = Path.Combine(this.workDirectory, "child"); Directory.CreateDirectory(childDir); try { - VersionAndBranchFinder.GetVersion(childDir, null, true, null); + this.executeCore.ExecuteGitVersion(null, null, null, null, true, childDir, null); } catch (Exception ex) { @@ -58,4 +66,4 @@ public void Finds_GitDirectory_In_Parent() Assert.IsNotAssignableFrom(ex); } } -} +} \ No newline at end of file diff --git a/src/GitVersionTask.Tests/InvalidFileCheckerTests.cs b/src/GitVersionTask.Tests/InvalidFileCheckerTests.cs index 5681304ec5..4c719ae102 100644 --- a/src/GitVersionTask.Tests/InvalidFileCheckerTests.cs +++ b/src/GitVersionTask.Tests/InvalidFileCheckerTests.cs @@ -25,7 +25,14 @@ public void CreateTemporaryProject() [TearDown] public void Cleanup() { - Directory.Delete(projectDirectory, true); + try + { + Directory.Delete(projectDirectory, true); + } + catch (Exception exception) + { + Console.WriteLine(exception); + } } [Test] diff --git a/src/GitVersionTask/AssemblyInfo.cs b/src/GitVersionTask/AssemblyInfo.cs index 782d9b63f7..507682e593 100644 --- a/src/GitVersionTask/AssemblyInfo.cs +++ b/src/GitVersionTask/AssemblyInfo.cs @@ -1,6 +1,8 @@ using System.Reflection; +using System.Runtime.CompilerServices; [assembly: AssemblyTitle("GitVersionTask")] [assembly: AssemblyProduct("GitVersionTask")] [assembly: AssemblyVersion("1.0.0")] [assembly: AssemblyFileVersion("1.0.0")] +[assembly: InternalsVisibleTo("GitVersionTask.Tests")] \ No newline at end of file diff --git a/src/GitVersionTask/AssemblyInfoBuilder/UpdateAssemblyInfo.cs b/src/GitVersionTask/AssemblyInfoBuilder/UpdateAssemblyInfo.cs index 046f81c704..302fa5513d 100644 --- a/src/GitVersionTask/AssemblyInfoBuilder/UpdateAssemblyInfo.cs +++ b/src/GitVersionTask/AssemblyInfoBuilder/UpdateAssemblyInfo.cs @@ -3,14 +3,26 @@ using System; using System.IO; using System.Text; + using GitVersion; - using GitVersion.Helpers; + using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; - using Logger = GitVersion.Logger; - public class UpdateAssemblyInfo : Task + public class UpdateAssemblyInfo : GitVersionTaskBase { + TaskLogger logger; + + + public UpdateAssemblyInfo() + { + CompileFiles = new ITaskItem[] + { + }; + this.logger = new TaskLogger(this); + Logger.SetLoggers(this.LogInfo, this.LogWarning, s => this.LogError(s)); + } + + [Required] public string SolutionDirectory { get; set; } @@ -31,19 +43,6 @@ public class UpdateAssemblyInfo : Task public bool NoFetch { get; set; } - TaskLogger logger; - IFileSystem fileSystem; - - public UpdateAssemblyInfo() - { - CompileFiles = new ITaskItem[] { }; - logger = new TaskLogger(this); - fileSystem = new FileSystem(); - Logger.SetLoggers( - this.LogInfo, - this.LogWarning, - s => this.LogError(s)); - } public override bool Execute() { @@ -54,12 +53,12 @@ public override bool Execute() } catch (WarningException errorException) { - logger.LogWarning(errorException.Message); + this.logger.LogWarning(errorException.Message); return true; } catch (Exception exception) { - logger.LogError("Error occurred: " + exception); + this.logger.LogError("Error occurred: " + exception); return false; } finally @@ -68,20 +67,22 @@ public override bool Execute() } } - public void InnerExecute() + + void InnerExecute() { TempFileTracker.DeleteTempFiles(); InvalidFileChecker.CheckForInvalidFiles(CompileFiles, ProjectFile); VersionVariables versionVariables; - if (!VersionAndBranchFinder.TryGetVersion(SolutionDirectory, out versionVariables, NoFetch, new Authentication(), fileSystem)) + if (!ExecuteCore.TryGetVersion(SolutionDirectory, out versionVariables, NoFetch, new Authentication())) { return; } CreateTempAssemblyInfo(versionVariables); } + void CreateTempAssemblyInfo(VersionVariables versionVariables) { if (IntermediateOutputPath == null) @@ -105,7 +106,9 @@ void CreateTempAssemblyInfo(VersionVariables versionVariables) { var content = File.ReadAllText(AssemblyInfoTempFilePath, Encoding.UTF8).Trim(); if (string.Equals(assemblyInfo, content, StringComparison.Ordinal)) + { return; // nothign to do as the file matches what we'd create + } } } catch (Exception) diff --git a/src/GitVersionTask/CachedVersion.cs b/src/GitVersionTask/CachedVersion.cs deleted file mode 100644 index 75a35d22c8..0000000000 --- a/src/GitVersionTask/CachedVersion.cs +++ /dev/null @@ -1,7 +0,0 @@ -using GitVersion; - -public class CachedVersion -{ - public VersionVariables VersionVariables; - public long Timestamp; -} \ No newline at end of file diff --git a/src/GitVersionTask/DirectoryDateFinder.cs b/src/GitVersionTask/DirectoryDateFinder.cs deleted file mode 100644 index 0596269ba3..0000000000 --- a/src/GitVersionTask/DirectoryDateFinder.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.IO; -using System.Linq; - -public static class DirectoryDateFinder -{ - public static long GetLastDirectoryWrite(string path) - { - return new DirectoryInfo(path) - .GetDirectories("*.*", SearchOption.AllDirectories) - .Select(d => d.LastWriteTimeUtc) - .DefaultIfEmpty() - .Max() - .Ticks; - } -} \ No newline at end of file diff --git a/src/GitVersionTask/GetVersion.cs b/src/GitVersionTask/GetVersion.cs index 93c46d2044..781c1156b5 100644 --- a/src/GitVersionTask/GetVersion.cs +++ b/src/GitVersionTask/GetVersion.cs @@ -1,14 +1,23 @@ namespace GitVersionTask { using System; + using GitVersion; - using GitVersion.Helpers; + using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; - using Logger = GitVersion.Logger; - public class GetVersion : Task + public class GetVersion : GitVersionTaskBase { + TaskLogger logger; + + + public GetVersion() + { + this.logger = new TaskLogger(this); + Logger.SetLoggers(this.LogInfo, this.LogWarning, s => this.LogError(s)); + } + + [Required] public string SolutionDirectory { get; set; } @@ -80,18 +89,6 @@ public class GetVersion : Task [Output] public string CommitsSinceVersionSourcePadded { get; set; } - TaskLogger logger; - IFileSystem fileSystem; - - public GetVersion() - { - logger = new TaskLogger(this); - fileSystem = new FileSystem(); - Logger.SetLoggers( - this.LogInfo, - this.LogWarning, - s => this.LogError(s)); - } public override bool Execute() { @@ -99,7 +96,7 @@ public override bool Execute() { VersionVariables variables; - if (VersionAndBranchFinder.TryGetVersion(SolutionDirectory, out variables, NoFetch, new Authentication(), fileSystem)) + if (ExecuteCore.TryGetVersion(SolutionDirectory, out variables, NoFetch, new Authentication())) { var thisType = typeof(GetVersion); foreach (var variable in variables) @@ -111,12 +108,12 @@ public override bool Execute() } catch (WarningException errorException) { - logger.LogWarning(errorException.Message); + this.logger.LogWarning(errorException.Message); return true; } catch (Exception exception) { - logger.LogError("Error occurred: " + exception); + this.logger.LogError("Error occurred: " + exception); return false; } finally diff --git a/src/GitVersionTask/GitVersionTask.csproj b/src/GitVersionTask/GitVersionTask.csproj index 48c7a5a178..d80f2fb583 100644 --- a/src/GitVersionTask/GitVersionTask.csproj +++ b/src/GitVersionTask/GitVersionTask.csproj @@ -60,15 +60,13 @@ - - + - diff --git a/src/GitVersionTask/GitVersionTaskBase.cs b/src/GitVersionTask/GitVersionTaskBase.cs new file mode 100644 index 0000000000..2fedd58f9c --- /dev/null +++ b/src/GitVersionTask/GitVersionTaskBase.cs @@ -0,0 +1,34 @@ +namespace GitVersionTask +{ + using System.Collections.Concurrent; + + using GitVersion; + using GitVersion.Helpers; + + using Microsoft.Build.Utilities; + + public abstract class GitVersionTaskBase : Task + { + static readonly ConcurrentDictionary versionVariablesCache; + readonly ExecuteCore executeCore; + + + static GitVersionTaskBase() + { + versionVariablesCache = new ConcurrentDictionary(); + } + + + protected GitVersionTaskBase() + { + var fileSystem = new FileSystem(); + this.executeCore = new ExecuteCore(fileSystem, versionVariablesCache.GetOrAdd); + } + + + protected ExecuteCore ExecuteCore + { + get { return this.executeCore; } + } + } +} \ No newline at end of file diff --git a/src/GitVersionTask/VersionAndBranchFinder.cs b/src/GitVersionTask/VersionAndBranchFinder.cs deleted file mode 100644 index c9b7dc260f..0000000000 --- a/src/GitVersionTask/VersionAndBranchFinder.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Collections.Generic; -using GitVersion; -using GitVersion.Helpers; - -public static class VersionAndBranchFinder -{ - static Dictionary versionCacheVersions = new Dictionary(); - - public static bool TryGetVersion(string directory, out VersionVariables versionVariables, bool noFetch, Authentication authentication, IFileSystem fileSystem) - { - try - { - versionVariables = GetVersion(directory, authentication, noFetch, fileSystem); - return true; - } - catch (Exception ex) - { - Logger.WriteWarning("Could not determine assembly version: " + ex.Message); - versionVariables = null; - return false; - } - } - - public static VersionVariables GetVersion(string directory, Authentication authentication, bool noFetch, IFileSystem fileSystem) - { - var gitDir = GitDirFinder.TreeWalkForDotGitDir(directory); - using (var repo = RepositoryLoader.GetRepo(gitDir)) - { - var ticks = DirectoryDateFinder.GetLastDirectoryWrite(gitDir); - var key = string.Format("{0}:{1}:{2}",gitDir, repo.Head.CanonicalName, repo.Head.Tip.Sha); - - Logger.WriteInfo("CacheKey: " + key ); - CachedVersion result; - if (versionCacheVersions.TryGetValue(key, out result)) - { - if (result.Timestamp != ticks) - { - Logger.WriteInfo(string.Format("Change detected. Flushing cache. OldTimeStamp: {0}. NewTimeStamp: {1}", result.Timestamp, ticks)); - result.VersionVariables = ExecuteCore.ExecuteGitVersion(fileSystem, null, null, authentication, null, noFetch, directory, null); - result.Timestamp = ticks; - } - Logger.WriteInfo("Returning version from cache"); - return result.VersionVariables; - } - Logger.WriteInfo("Version not in cache. Calculating version."); - - return (versionCacheVersions[key] = new CachedVersion - { - VersionVariables = ExecuteCore.ExecuteGitVersion(fileSystem, null, null, authentication, null, noFetch, directory, null), - Timestamp = ticks - }).VersionVariables; - } - } -} diff --git a/src/GitVersionTask/WriteVersionInfoToBuildLog.cs b/src/GitVersionTask/WriteVersionInfoToBuildLog.cs index 262191a301..97e2cadbed 100644 --- a/src/GitVersionTask/WriteVersionInfoToBuildLog.cs +++ b/src/GitVersionTask/WriteVersionInfoToBuildLog.cs @@ -1,33 +1,30 @@ namespace GitVersionTask { - using GitVersion; - using GitVersion.Helpers; - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; using System; using System.Collections.Generic; - using Logger = GitVersion.Logger; - public class WriteVersionInfoToBuildLog : Task - { - [Required] - public string SolutionDirectory { get; set; } + using GitVersion; - public bool NoFetch { get; set; } + using Microsoft.Build.Framework; + + public class WriteVersionInfoToBuildLog : GitVersionTaskBase + { + readonly TaskLogger logger; - TaskLogger logger; - IFileSystem fileSystem; public WriteVersionInfoToBuildLog() { - logger = new TaskLogger(this); - fileSystem = new FileSystem(); - Logger.SetLoggers( - this.LogInfo, - this.LogWarning, - s => this.LogError(s)); + this.logger = new TaskLogger(this); + Logger.SetLoggers(this.LogInfo, this.LogWarning, s => this.LogError(s)); } + + [Required] + public string SolutionDirectory { get; set; } + + public bool NoFetch { get; set; } + + public override bool Execute() { try @@ -37,12 +34,12 @@ public override bool Execute() } catch (WarningException errorException) { - logger.LogWarning(errorException.Message); + this.logger.LogWarning(errorException.Message); return true; } catch (Exception exception) { - logger.LogError("Error occurred: " + exception); + this.logger.LogError("Error occurred: " + exception); return false; } finally @@ -51,27 +48,29 @@ public override bool Execute() } } - public void InnerExecute() + + void InnerExecute() { VersionVariables result; - if (!VersionAndBranchFinder.TryGetVersion(SolutionDirectory, out result, NoFetch, new Authentication(), fileSystem)) + if (!ExecuteCore.TryGetVersion(SolutionDirectory, out result, NoFetch, new Authentication())) { return; } - + WriteIntegrationParameters(BuildServerList.GetApplicableBuildServers(), result); } - public void WriteIntegrationParameters(IEnumerable applicableBuildServers, VersionVariables variables) + + void WriteIntegrationParameters(IEnumerable applicableBuildServers, VersionVariables variables) { foreach (var buildServer in applicableBuildServers) { - logger.LogInfo(string.Format("Executing GenerateSetVersionMessage for '{0}'.", buildServer.GetType().Name)); - logger.LogInfo(buildServer.GenerateSetVersionMessage(variables)); - logger.LogInfo(string.Format("Executing GenerateBuildLogOutput for '{0}'.", buildServer.GetType().Name)); + this.logger.LogInfo(string.Format("Executing GenerateSetVersionMessage for '{0}'.", buildServer.GetType().Name)); + this.logger.LogInfo(buildServer.GenerateSetVersionMessage(variables)); + this.logger.LogInfo(string.Format("Executing GenerateBuildLogOutput for '{0}'.", buildServer.GetType().Name)); foreach (var buildParameter in BuildOutputFormatter.GenerateBuildLogOutput(buildServer, variables)) { - logger.LogInfo(buildParameter); + this.logger.LogInfo(buildParameter); } } }