From 02de1153c1d1310933f0472c6411cfc7c426208f Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Thu, 21 Jan 2016 18:51:56 +0000 Subject: [PATCH 01/12] Adding a menu item that displays a form and check that it works. --- Backup/BuildMonitor.sln | 43 ++++ .../BuildMonitorPackage.cs | 231 ++++++++++++++++++ .../BuildMonitorPackage.csproj | 181 ++++++++++++++ .../DataAdjusterWithLogging.cs | 17 ++ .../BuildMonitorPackage/GlobalSuppressions.cs | 11 + Backup/BuildMonitorPackage/Guids.cs | 15 ++ Backup/BuildMonitorPackage/Key.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 36 +++ .../BuildMonitorPackage/Resources.Designer.cs | 63 +++++ Backup/BuildMonitorPackage/Resources.resx | 129 ++++++++++ .../BuildMonitorPackage/Resources/Package.ico | Bin 0 -> 2998 bytes Backup/BuildMonitorPackage/Settings.cs | 35 +++ Backup/BuildMonitorPackage/VSPackage.resx | 140 +++++++++++ Backup/BuildMonitorPackage/license.txt | 13 + .../source.extension.vsixmanifest | 27 ++ BuildMonitor.sln | 8 +- BuildMonitor/BuildMonitor.csproj | 3 +- BuildMonitor/cedd.snk | Bin 0 -> 596 bytes BuildMonitorPackage/AnalyseBuildTimes.xaml | 10 + BuildMonitorPackage/AnalyseBuildTimes.xaml.cs | 27 ++ .../AnalyseBuildTimesCommand.cs | 109 +++++++++ BuildMonitorPackage/BuildMonitorPackage.cs | 2 + .../BuildMonitorPackage.csproj | 120 ++++++++- BuildMonitorPackage/BuildMonitorPackage.vsct | 96 ++++++++ BuildMonitorPackage/Resources.Designer.cs | 2 +- .../Resources/AnalyseBuildTimesCommand.png | Bin 0 -> 1172 bytes BuildMonitorPackage/packages.config | 22 ++ UpgradeLog.htm | Bin 0 -> 54472 bytes 28 files changed, 1322 insertions(+), 18 deletions(-) create mode 100644 Backup/BuildMonitor.sln create mode 100644 Backup/BuildMonitorPackage/BuildMonitorPackage.cs create mode 100644 Backup/BuildMonitorPackage/BuildMonitorPackage.csproj create mode 100644 Backup/BuildMonitorPackage/DataAdjusterWithLogging.cs create mode 100644 Backup/BuildMonitorPackage/GlobalSuppressions.cs create mode 100644 Backup/BuildMonitorPackage/Guids.cs create mode 100644 Backup/BuildMonitorPackage/Key.snk create mode 100644 Backup/BuildMonitorPackage/Properties/AssemblyInfo.cs create mode 100644 Backup/BuildMonitorPackage/Resources.Designer.cs create mode 100644 Backup/BuildMonitorPackage/Resources.resx create mode 100644 Backup/BuildMonitorPackage/Resources/Package.ico create mode 100644 Backup/BuildMonitorPackage/Settings.cs create mode 100644 Backup/BuildMonitorPackage/VSPackage.resx create mode 100644 Backup/BuildMonitorPackage/license.txt create mode 100644 Backup/BuildMonitorPackage/source.extension.vsixmanifest create mode 100644 BuildMonitor/cedd.snk create mode 100644 BuildMonitorPackage/AnalyseBuildTimes.xaml create mode 100644 BuildMonitorPackage/AnalyseBuildTimes.xaml.cs create mode 100644 BuildMonitorPackage/AnalyseBuildTimesCommand.cs create mode 100644 BuildMonitorPackage/BuildMonitorPackage.vsct create mode 100644 BuildMonitorPackage/Resources/AnalyseBuildTimesCommand.png create mode 100644 BuildMonitorPackage/packages.config create mode 100644 UpgradeLog.htm diff --git a/Backup/BuildMonitor.sln b/Backup/BuildMonitor.sln new file mode 100644 index 0000000..18202dc --- /dev/null +++ b/Backup/BuildMonitor.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{4FDB4354-8389-4675-ACED-6CA6DF570561}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildMonitor", "BuildMonitor\BuildMonitor.csproj", "{700A9D28-E9DE-428B-A8F2-B40BAF4A3E87}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildMonitor.UnitTests", "BuildMonitor.UnitTests\BuildMonitor.UnitTests.csproj", "{4107248F-F2FC-4152-816B-E8633C4913F5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{68E63FC4-249A-4EFE-A8D8-5154DA8E3415}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildMonitorPackage", "BuildMonitorPackage\BuildMonitorPackage.csproj", "{F1623C5E-614B-435B-B625-AC534EF3920F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {700A9D28-E9DE-428B-A8F2-B40BAF4A3E87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {700A9D28-E9DE-428B-A8F2-B40BAF4A3E87}.Debug|Any CPU.Build.0 = Debug|Any CPU + {700A9D28-E9DE-428B-A8F2-B40BAF4A3E87}.Release|Any CPU.ActiveCfg = Release|Any CPU + {700A9D28-E9DE-428B-A8F2-B40BAF4A3E87}.Release|Any CPU.Build.0 = Release|Any CPU + {4107248F-F2FC-4152-816B-E8633C4913F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4107248F-F2FC-4152-816B-E8633C4913F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4107248F-F2FC-4152-816B-E8633C4913F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4107248F-F2FC-4152-816B-E8633C4913F5}.Release|Any CPU.Build.0 = Release|Any CPU + {F1623C5E-614B-435B-B625-AC534EF3920F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1623C5E-614B-435B-B625-AC534EF3920F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1623C5E-614B-435B-B625-AC534EF3920F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1623C5E-614B-435B-B625-AC534EF3920F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4107248F-F2FC-4152-816B-E8633C4913F5} = {68E63FC4-249A-4EFE-A8D8-5154DA8E3415} + EndGlobalSection +EndGlobal diff --git a/Backup/BuildMonitorPackage/BuildMonitorPackage.cs b/Backup/BuildMonitorPackage/BuildMonitorPackage.cs new file mode 100644 index 0000000..e3bb449 --- /dev/null +++ b/Backup/BuildMonitorPackage/BuildMonitorPackage.cs @@ -0,0 +1,231 @@ +using System; +using System.ComponentModel.Design; +using System.Runtime.InteropServices; +using BuildMonitor; +using BuildMonitor.Domain; +using BuildMonitor.UI; +using EnvDTE; +using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.Shell; +using Constants = EnvDTE.Constants; + +namespace BuildMonitorPackage +{ + [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] + [Guid(GuidList.guidBuildMonitorPackagePkgString)] + [PackageRegistration(UseManagedResourcesOnly = true)] + [ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")] + sealed class BuildMonitorPackage : Package, IVsUpdateSolutionEvents2 + { + private DTE dte; + private readonly Monitor monitor; + private readonly DataAdjusterWithLogging dataAdjuster; + private BuildMonitor.Domain.Solution solution; + + private IVsSolutionBuildManager2 sbm; + private uint updateSolutionEventsCookie; + private OutputWindowPane outputWindowPane; + private SolutionEvents events; + private IVsSolution2 vsSolution; + + public BuildMonitorPackage() + { + Settings.CreateApplicationFolderIfNotExist(); + + var factory = new BuildFactory(); + var repository = new BuildRepository(Settings.RepositoryPath); + + monitor = new Monitor(factory, repository); + dataAdjuster = new DataAdjusterWithLogging(repository, PrintLine); + } + + protected override void Initialize() + { + base.Initialize(); + + //if invalid data, adjust it + dataAdjuster.Adjust(); + + // Get solution build manager + sbm = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolutionBuildManager)) as IVsSolutionBuildManager2; + if (sbm != null) + { + sbm.AdviseUpdateSolutionEvents(this, out updateSolutionEventsCookie); + } + + // Must hold a reference to the solution events object or the events wont fire, garbage collection related + events = GetDTE().Events.SolutionEvents; + events.Opened += Solution_Opened; + + PrintLine("Build monitor initialized"); + PrintLine("Path to persist data: {0}", Settings.RepositoryPath); + + monitor.SolutionBuildFinished = b => + { + Print("[{0}] Time Elapsed: {1} \t\t", b.SessionBuildCount, b.SolutionBuildTime.ToTime()); + PrintLine("Session build time: {0}\n", b.SessionMillisecondsElapsed.ToTime()); + }; + + monitor.ProjectBuildFinished = b => PrintLine(" - {0}\t-- {1} --", b.MillisecondsElapsed.ToTime(), b.ProjectName); + } + + private void Solution_Opened() + { + solution = new BuildMonitor.Domain.Solution { Name = GetSolutionName() }; + PrintLine("\nSolution loaded: \t{0}", solution.Name); + PrintLine("{0}", 60.Times("-")); + } + + #region Print to output window pane + + private OutputWindowPane GetOutputWindowPane() + { + if (outputWindowPane == null) + { + var outputWindow = (OutputWindow)GetDTE().Windows.Item(Constants.vsWindowKindOutput).Object; + outputWindowPane = outputWindow.OutputWindowPanes.Add("Build monitor"); + } + return outputWindowPane; + } + + private void Print(string format, params object[] args) + { + GetOutputWindowPane().OutputString(string.Format(format, args)); + } + + private void PrintLine(string format, params object[] args) + { + Print(format + Environment.NewLine, args); + } + + #endregion + + #region Get objects from vs + + private DTE GetDTE() + { + if (dte == null) + { + var serviceContainer = this as IServiceContainer; + dte = serviceContainer.GetService(typeof(SDTE)) as DTE; + } + return dte; + } + + private void SetVsSolution() + { + if (vsSolution == null) + vsSolution = ServiceProvider.GlobalProvider.GetService(typeof(SVsSolution)) as IVsSolution2; + } + + private string GetSolutionName() + { + SetVsSolution(); + object solutionName; + vsSolution.GetProperty((int)__VSPROPID.VSPROPID_SolutionBaseName, out solutionName); + return (string)solutionName; + } + + private IProject GetProject(IVsHierarchy pHierProj) + { + object n; + pHierProj.GetProperty((uint)VSConstants.VSITEMID.Root, (int)__VSHPROPID.VSHPROPID_Name, out n); + var name = n as string; + + Guid id; + vsSolution.GetGuidOfProject(pHierProj, out id); + + return new BuildMonitor.Domain.Project { Name = name, Id = id }; + } + + #endregion + + int IVsUpdateSolutionEvents.UpdateSolution_Begin(ref int pfCancelUpdate) + { + // This method is called when the entire solution starts to build. + monitor.SolutionBuildStart(solution); + + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents2.UpdateProjectCfg_Begin(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, ref int pfCancel) + { + // This method is called when a specific project begins building. + var project = GetProject(pHierProj); + monitor.ProjectBuildStart(project); + + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents2.UpdateProjectCfg_Done(IVsHierarchy pHierProj, IVsCfg pCfgProj, IVsCfg pCfgSln, uint dwAction, int fSuccess, int fCancel) + { + // This method is called when a specific project finishes building. + var project = GetProject(pHierProj); + monitor.ProjectBuildStop(project); + + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents.UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) + { + // This method is called when the entire solution is done building. + monitor.SolutionBuildStop(); + + return VSConstants.S_OK; + } + + #region empty impl. of solution events interface + + int IVsUpdateSolutionEvents2.UpdateSolution_StartUpdate(ref int pfCancelUpdate) + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents2.UpdateSolution_Cancel() + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents2.OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents2.UpdateSolution_Begin(ref int pfCancelUpdate) + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents2.UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand) + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents.UpdateSolution_StartUpdate(ref int pfCancelUpdate) + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents.UpdateSolution_Cancel() + { + return VSConstants.S_OK; + } + + int IVsUpdateSolutionEvents.OnActiveProjectCfgChange(IVsHierarchy pIVsHierarchy) + { + return VSConstants.S_OK; + } + + #endregion + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + // Unadvise all events + if (sbm != null && updateSolutionEventsCookie != 0) + sbm.UnadviseUpdateSolutionEvents(updateSolutionEventsCookie); + } + } +} \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/BuildMonitorPackage.csproj b/Backup/BuildMonitorPackage/BuildMonitorPackage.csproj new file mode 100644 index 0000000..a358092 --- /dev/null +++ b/Backup/BuildMonitorPackage/BuildMonitorPackage.csproj @@ -0,0 +1,181 @@ + + + + 12.0 + 11.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + + 4.0 + + + + Debug + AnyCPU + 2.0 + {F1623C5E-614B-435B-B625-AC534EF3920F} + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + BuildMonitorPackage + BuildMonitorPackage + True + Key.snk + v4.5 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + + + + + + + + + + true + + + + + + + + + + + + + + + + {80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2} + 8 + 0 + 0 + primary + False + False + + + {26AD1324-4B7C-44BC-84F8-B86AED45729F} + 10 + 0 + 0 + primary + False + False + + + {1A31287A-4D7D-413E-8E32-3B374931BD89} + 8 + 0 + 0 + primary + False + False + + + {2CE2370E-D744-4936-A090-3FFFE667B0E1} + 9 + 0 + 0 + primary + False + False + + + {1CBA492E-7263-47BB-87FE-639000619B15} + 8 + 0 + 0 + primary + False + False + + + {00020430-0000-0000-C000-000000000046} + 2 + 0 + 0 + primary + False + False + + + + + + + True + True + Resources.resx + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + true + VSPackage + + + + + Designer + + + + + + + + Always + true + + + + + + {700a9d28-e9de-428b-a8f2-b40baf4a3e87} + BuildMonitor + + + + true + + + + + \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/DataAdjusterWithLogging.cs b/Backup/BuildMonitorPackage/DataAdjusterWithLogging.cs new file mode 100644 index 0000000..92a3789 --- /dev/null +++ b/Backup/BuildMonitorPackage/DataAdjusterWithLogging.cs @@ -0,0 +1,17 @@ +using BuildMonitor.Domain; +using BuildMonitor.LocalData; + +namespace BuildMonitorPackage +{ + public class DataAdjusterWithLogging : DataAdjuster + { + public delegate void LogAction(string s, params object[] args); + + public DataAdjusterWithLogging(IBuildRepository repository, LogAction log) : base(repository) + { + OnFoundInvalidData = data => log("-- Found invalid json-data in file: {0}", data.Source); + OnFixedInvalidData = () => log("-- Successfully converted invalid json data to valid"); + OnCouldNotConvertData = e => log("-- Could not convert json-data : {0}", e.Message); + } + } +} \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/GlobalSuppressions.cs b/Backup/BuildMonitorPackage/GlobalSuppressions.cs new file mode 100644 index 0000000..a893f9d --- /dev/null +++ b/Backup/BuildMonitorPackage/GlobalSuppressions.cs @@ -0,0 +1,11 @@ +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. Project-level +// suppressions either have no target or are given a specific target +// and scoped to a namespace, type, member, etc. +// +// To add a suppression to this file, right-click the message in the +// Error List, point to "Suppress Message(s)", and click "In Project +// Suppression File". You do not need to add suppressions to this +// file manually. + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")] diff --git a/Backup/BuildMonitorPackage/Guids.cs b/Backup/BuildMonitorPackage/Guids.cs new file mode 100644 index 0000000..80b5b9c --- /dev/null +++ b/Backup/BuildMonitorPackage/Guids.cs @@ -0,0 +1,15 @@ +// Guids.cs +// MUST match guids.h + +using System; + +namespace BuildMonitorPackage +{ + static class GuidList + { + public const string guidBuildMonitorPackagePkgString = "d350a95e-5d09-4b5d-9075-0a5f7bb6b1dc"; + public const string guidBuildMonitorPackageCmdSetString = "ec1339d5-c4f2-44de-9908-af4b79ce6f74"; + + public static readonly Guid guidBuildMonitorPackageCmdSet = new Guid(guidBuildMonitorPackageCmdSetString); + }; +} \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/Key.snk b/Backup/BuildMonitorPackage/Key.snk new file mode 100644 index 0000000000000000000000000000000000000000..0a721d8b4f5954ab8d3f100eb25bfdee97be8e22 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097Zx2)cqBnTQ(lU4@%Uz@{66Kw z@Lqt}W)6M1SMekjTTg=%&lvU2a<*y)2{ z%A0rUB(AuCkgxYWvnOaji|M>Yb~hA{8Gl&@9XaEc4K71ckY)^?8PC*(+aKvW+d$<}i@?J=84Av{It z=V|aS27GxWqGfQd>Y*@VG(BM$b0^QLK^8^>=wq=*6>1c9j*XrS(fVXc85XF?{D{g) z0T0`wY@WH~5CX(g7D81)R$#x{w4Y66yfobYZLE0U3HeqDoq zKpk9O?~609-{ttJfgfGltq=}{SD}<6@r&Wy#l3n95Pl=K5>E+kNoIvQsnVDjZ~J|P iBK8YLPVx%(J7Y$Y!is-m=>zabENc;S#uAAe7o61n`6E{V literal 0 HcmV?d00001 diff --git a/Backup/BuildMonitorPackage/Properties/AssemblyInfo.cs b/Backup/BuildMonitorPackage/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0f12b42 --- /dev/null +++ b/Backup/BuildMonitorPackage/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System; +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BuildMonitorPackage")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Daniel Vinntreus")] +[assembly: AssemblyProduct("BuildMonitorPackage")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: CLSCompliant(false)] +[assembly: NeutralResourcesLanguage("en-US")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + + + diff --git a/Backup/BuildMonitorPackage/Resources.Designer.cs b/Backup/BuildMonitorPackage/Resources.Designer.cs new file mode 100644 index 0000000..abbe023 --- /dev/null +++ b/Backup/BuildMonitorPackage/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.34003 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace BuildMonitorPackage { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BuildMonitorPackage.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Backup/BuildMonitorPackage/Resources.resx b/Backup/BuildMonitorPackage/Resources.resx new file mode 100644 index 0000000..891c592 --- /dev/null +++ b/Backup/BuildMonitorPackage/Resources.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/Resources/Package.ico b/Backup/BuildMonitorPackage/Resources/Package.ico new file mode 100644 index 0000000000000000000000000000000000000000..449296f495af26f2b41bb1626a28de7432145472 GIT binary patch literal 2998 zcmeHJIc@?$5G;1VEan=&z(kgxVUhCya&kft2^&G^5AXoz*K%ZEh6^mKRC)SN;9Ie2I^4EsEuJm3ak4(0(K0-)vtx2mz-v5Du5+`|?E{2~nF zj-DY~i1~a@z`8H2Rm8@RN^*7j%+?3;*Is5r;m32z^?Gs%|GV@5y&h|~@doa#jn6yX zPm+(*yf56oD($=C(DJ(6=%K6Llfe5Uo;dPV7%T5PITm!!YhANqXLaS`0ufOBi8crP zkWX22ZGmf>3$1+|+x>UW$1lsro%1<*HCnUTM61<8yWK{o(?Pe}#b7YNXf(oPGQo5@ z#cVdiVzIz-xkMC2Sglrgd0u0)* + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + BuildMonitorPackage + + + Monitor builds in Visual Studio. + + + Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/license.txt b/Backup/BuildMonitorPackage/license.txt new file mode 100644 index 0000000..426c72c --- /dev/null +++ b/Backup/BuildMonitorPackage/license.txt @@ -0,0 +1,13 @@ +Copyright 2012 Daniel Vinntreus + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/Backup/BuildMonitorPackage/source.extension.vsixmanifest b/Backup/BuildMonitorPackage/source.extension.vsixmanifest new file mode 100644 index 0000000..b232ae7 --- /dev/null +++ b/Backup/BuildMonitorPackage/source.extension.vsixmanifest @@ -0,0 +1,27 @@ + + + + + Build Monitor + Measure how long it takes to build your solution and individual projects in Visual Studio. + http://visualstudiogallery.msdn.microsoft.com/b0c87e47-f4ee-4935-9a59-f2c81ce692ab + license.txt + Build, Monitor, Build Monitor, Build times + + + + + + + + + + + + + + + + + + diff --git a/BuildMonitor.sln b/BuildMonitor.sln index 18202dc..c1c3d94 100644 --- a/BuildMonitor.sln +++ b/BuildMonitor.sln @@ -1,18 +1,20 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{4FDB4354-8389-4675-ACED-6CA6DF570561}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.exe = .nuget\NuGet.exe .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{68E63FC4-249A-4EFE-A8D8-5154DA8E3415}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildMonitor", "BuildMonitor\BuildMonitor.csproj", "{700A9D28-E9DE-428B-A8F2-B40BAF4A3E87}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildMonitor.UnitTests", "BuildMonitor.UnitTests\BuildMonitor.UnitTests.csproj", "{4107248F-F2FC-4152-816B-E8633C4913F5}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{68E63FC4-249A-4EFE-A8D8-5154DA8E3415}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildMonitorPackage", "BuildMonitorPackage\BuildMonitorPackage.csproj", "{F1623C5E-614B-435B-B625-AC534EF3920F}" EndProject Global diff --git a/BuildMonitor/BuildMonitor.csproj b/BuildMonitor/BuildMonitor.csproj index f8916ed..ca41ac7 100644 --- a/BuildMonitor/BuildMonitor.csproj +++ b/BuildMonitor/BuildMonitor.csproj @@ -35,7 +35,7 @@ true - key.pfx + cedd.snk @@ -71,6 +71,7 @@ + diff --git a/BuildMonitor/cedd.snk b/BuildMonitor/cedd.snk new file mode 100644 index 0000000000000000000000000000000000000000..2a530fd4cc4735404a73dfd68a8e61d846184195 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa500977%L0b8_KOEOh&eDQVC8^%(Y7@nGo)N5L znAzOf#K0Q_o)6bma9SWfw$@}W(~79-zt6Vg{+Cv2m2_gqv2Q;{*j*osc*Dfk7Pfq8g<97)UEwQk?ngxe~?Cmz&G4%sYtgem2 zCAefa2gc31E9xI6t%I*1KjE2w=`X?iQQpu>Qd}6TPLA{=Rnn~QsnG#+T|QVs+L%Gf z?F4g`6EewSu=n4>-d1A-A%~Z^{PnQpeE*X@(iyqR4v4!cHGjOYW8veE$hkhFpU7{W z6%?FfAdhfZlNvL3Cg0yTm&$LF^*w2H){99BD)NyuBAeK;v=5$_!&G}1^-!qI^ZiR;&jXL2DIDj@b`>aXT`BPZ literal 0 HcmV?d00001 diff --git a/BuildMonitorPackage/AnalyseBuildTimes.xaml b/BuildMonitorPackage/AnalyseBuildTimes.xaml new file mode 100644 index 0000000..355ff57 --- /dev/null +++ b/BuildMonitorPackage/AnalyseBuildTimes.xaml @@ -0,0 +1,10 @@ + + + diff --git a/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs b/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs new file mode 100644 index 0000000..f535b1b --- /dev/null +++ b/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace BuildMonitorPackage +{ + /// + /// Interaction logic for AnalyseBuildTimes.xaml + /// + public partial class AnalyseBuildTimes : Window + { + public AnalyseBuildTimes() + { + InitializeComponent(); + } + } +} diff --git a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs new file mode 100644 index 0000000..08b63fb --- /dev/null +++ b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +// +// Copyright (c) RESGROUP. All rights reserved. +// +//------------------------------------------------------------------------------ + +using System; +using System.ComponentModel.Design; +using System.Globalization; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; + +namespace BuildMonitorPackage +{ + /// + /// Command handler + /// + internal sealed class AnalyseBuildTimesCommand + { + /// + /// Command ID. + /// + public const int CommandId = 4130; + + /// + /// Command menu group (command set GUID). + /// + public static readonly Guid CommandSet = new Guid("6dc18c9d-0c60-4346-93be-acb15e591bf5"); + + /// + /// VS Package that provides this command, not null. + /// + private readonly Package package; + + /// + /// Initializes a new instance of the class. + /// Adds our command handlers for menu (commands must exist in the command table file) + /// + /// Owner package, not null. + private AnalyseBuildTimesCommand(Package package) + { + if (package == null) + { + throw new ArgumentNullException("package"); + } + + this.package = package; + + OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService; + if (commandService != null) + { + var menuCommandID = new CommandID(CommandSet, CommandId); + var menuItem = new MenuCommand(this.MenuItemCallback, menuCommandID); + commandService.AddCommand(menuItem); + } + } + + /// + /// Gets the instance of the command. + /// + public static AnalyseBuildTimesCommand Instance + { + get; + private set; + } + + /// + /// Gets the service provider from the owner package. + /// + private IServiceProvider ServiceProvider + { + get + { + return this.package; + } + } + + /// + /// Initializes the singleton instance of the command. + /// + /// Owner package, not null. + public static void Initialize(Package package) + { + Instance = new AnalyseBuildTimesCommand(package); + } + + /// + /// This function is the callback used to execute the command when the menu item is clicked. + /// See the constructor to see how the menu item is associated with this function using + /// OleMenuCommandService service and MenuCommand class. + /// + /// Event sender. + /// Event args. + private void MenuItemCallback(object sender, EventArgs e) + { + string message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.GetType().FullName); + string title = "AnalyseBuildTimesCommand"; + + // Show a message box to prove we were here + VsShellUtilities.ShowMessageBox( + this.ServiceProvider, + message, + title, + OLEMSGICON.OLEMSGICON_INFO, + OLEMSGBUTTON.OLEMSGBUTTON_OK, + OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); + } + } +} diff --git a/BuildMonitorPackage/BuildMonitorPackage.cs b/BuildMonitorPackage/BuildMonitorPackage.cs index e3bb449..3cb8579 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.cs +++ b/BuildMonitorPackage/BuildMonitorPackage.cs @@ -16,6 +16,7 @@ namespace BuildMonitorPackage [Guid(GuidList.guidBuildMonitorPackagePkgString)] [PackageRegistration(UseManagedResourcesOnly = true)] [ProvideAutoLoad("{f1536ef8-92ec-443c-9ed7-fdadf150da82}")] + [ProvideMenuResource("Menus.ctmenu", 1)] sealed class BuildMonitorPackage : Package, IVsUpdateSolutionEvents2 { private DTE dte; @@ -68,6 +69,7 @@ protected override void Initialize() }; monitor.ProjectBuildFinished = b => PrintLine(" - {0}\t-- {1} --", b.MillisecondsElapsed.ToTime(), b.ProjectName); + AnalyseBuildTimesCommand.Initialize(this); } private void Solution_Opened() diff --git a/BuildMonitorPackage/BuildMonitorPackage.csproj b/BuildMonitorPackage/BuildMonitorPackage.csproj index a358092..86e5aa0 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.csproj +++ b/BuildMonitorPackage/BuildMonitorPackage.csproj @@ -1,7 +1,8 @@  + - 12.0 + 14.0 11.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) @@ -9,6 +10,8 @@ 4.0 + + @@ -44,26 +47,94 @@ true + - - - - - - - true - - - - - + + ..\packages\Microsoft.VisualStudio.Imaging.14.0.23107\lib\net45\Microsoft.VisualStudio.Imaging.dll + True + + + ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.14.0.14.0.23107\lib\Microsoft.VisualStudio.Shell.14.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.0.23107\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll + True + + + True + ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30319\lib\Microsoft.VisualStudio.Shell.Interop.10.0.dll + True + + + True + ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61030\lib\Microsoft.VisualStudio.Shell.Interop.11.0.dll + True + + + True + ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30110\lib\Microsoft.VisualStudio.Shell.Interop.12.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll + True + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll + True + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Threading.14.0.50702\lib\net45\Microsoft.VisualStudio.Threading.dll + True + + + ..\packages\Microsoft.VisualStudio.Utilities.14.0.23107\lib\net45\Microsoft.VisualStudio.Utilities.dll + True + + + ..\packages\Microsoft.VisualStudio.Validation.14.0.50702\lib\net45\Microsoft.VisualStudio.Validation.dll + True + + + + + @@ -122,6 +193,10 @@ + + AnalyseBuildTimes.xaml + + @@ -146,6 +221,7 @@ + Designer @@ -154,10 +230,14 @@ + + Menus.ctmenu + Always true + @@ -166,11 +246,25 @@ BuildMonitor + + + Designer + MSBuild:Compile + + true + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BuildMonitorPackage/Resources.Designer.cs b/BuildMonitorPackage/Resources.Designer.cs index abbe023..c61ed81 100644 --- a/BuildMonitorPackage/Resources.Designer.cs +++ b/BuildMonitorPackage/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/BuildMonitorPackage/Resources/AnalyseBuildTimesCommand.png b/BuildMonitorPackage/Resources/AnalyseBuildTimesCommand.png new file mode 100644 index 0000000000000000000000000000000000000000..b22d975cbf00eda60e37587614e0677d0bfb525d GIT binary patch literal 1172 zcmV;F1Z(?=P)AHIP00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGqB>(^xB>_oNB=7(L1Sv^GK~z{r&6rO} zR8bVhMO+m@n`n^>S1nuxLD3=*TeOfsmlen?+6F={#2~abZOoueAZTJ(h!8>v{t3;> za?E)|5DA$%%#4KTQ&4A9oX&T-XSj3Ub>17D7(e)!JLjHr)!%vdzW1y+tlHh(J<9H6 zC)uRE&VI~3rPB^9A}Xs7r5JEE`&%NBp!)jyJP!>G(f0N>8gX8yD`m6Unw_1U4t9(0 z`^R-SPl)q;AA1VsnwSfU>5DfL{NbJ}g%6z=Y!y2`Ha4b!&wZSu_228{Z}{|MX*t&j zZo(SpokR_TtlRpvN}qckDl^<=y9pd?++5B0pB~($m6=KGCJ#9-DB`AjX=;A-hyG_1 zN-BV`t*0W3!CXzHQVMc9m8MO9D`43PoZE#OT-5;IfBKm6Z09Y^y}%qG^SC?X#c8;% zmPW2zAT)v-cn0$>D6qi4bZ1++_WElMyK_xfRaTMM6*J>-K>W+fd8@3$k!07x#Wsa& zh6e@)sHdmL2_OEsyh5>94C^nU#%=(NtDNIFl9sXrroHe%Qf zR#RHk57Kf$F@4Ym6oL;2B#=yiGL}!B8j$3hx#l>m9^&~A$eWpY>x2()toyQ7R+pg( zF;^30j9tL+`*eCvE-0oC(tt4duu~>1a~uXx^37ax999qU{L_hv32JL=bHaz`K$0hxe2L3grw7Dy*V%vN z@pF89A^<;=&QMcR6D=$(V6A3ds#K@}eDzQ1v^=?>zyKfhChP(p#i(@(kW64QmQS4) zkXbK z3DUMSq1eYz6R-(fVy2zqKPCsu9LuLp3rKRrQR_M8gpZvtIXRj8-rL(t$z&3146={t za`hC1ryCPE8iCz_=YDAha^&$-WCO9ipLYNow%GtP4m$-%g{;#8a^T^2W)0ic`s=u3>eS(!53jy;Ap}TwK(!j{X4>h0jPj$#%z}oK71%7O)%j{Z2*9CjSurx-l4;Lit}qY m*JGpEo(&`nZYkjtQN=$$-bTw6(Xv|r0000 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UpgradeLog.htm b/UpgradeLog.htm new file mode 100644 index 0000000000000000000000000000000000000000..dbe46688fac9e1fcc27446d7a11f20e82f0e4a0e GIT binary patch literal 54472 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 R$@BO>wMkM=v1I#{`+wd+hKK+F literal 0 HcmV?d00001 From 72ece4650074f358b5f70cab4b8903448e785bbf Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Thu, 21 Jan 2016 19:29:11 +0000 Subject: [PATCH 02/12] Add a simple test to get the total build time for a single solution build --- .../BuildMonitor.UnitTests.csproj | 6 +++ .../LocalData/AnalyseBuildTimes.cs | 37 ++++++++++++++ .../LocalData/AnalyseBuildTimesTests.cs | 48 +++++++++++++++++++ BuildMonitor.UnitTests/packages.config | 1 + .../BuildMonitorPackage.csproj | 1 + 5 files changed, 93 insertions(+) create mode 100644 BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs create mode 100644 BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs diff --git a/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj b/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj index 9c7cd44..e8e9c4d 100644 --- a/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj +++ b/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj @@ -32,6 +32,10 @@ 4 + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll + True + ..\packages\NUnit.2.6.2\lib\nunit.framework.dll @@ -41,6 +45,8 @@ + + diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs new file mode 100644 index 0000000..2a55ac5 --- /dev/null +++ b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs @@ -0,0 +1,37 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BuildMonitor.UnitTests.LocalData +{ + public struct SolutionName + { + public string Name; + } + + public struct SolutionTimes + { + public int Time; + public SolutionName Solution; + public string Name { get { return Solution.Name; } } + } + + public class AnalyseBuildTimes + { + private string json; + + public TimeSpan Total { get; protected set; } + + public AnalyseBuildTimes(string json) + { + this.json = json; + + var d = JsonConvert.DeserializeObject>(json); + //var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; + //jsonSerializerSettings.Converters.Add(new IsoDateTimeConverter()); + + Total = TimeSpan.FromMilliseconds(d.Sum(s => s.Time)); + } + } +} \ No newline at end of file diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs new file mode 100644 index 0000000..842ea04 --- /dev/null +++ b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using BuildMonitor.LocalData; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Linq; + +namespace BuildMonitor.UnitTests.LocalData +{ + [TestFixture] + public class AnalyseBuildTimesTests + { + [TestCase(19366)] + [TestCase(0)] + [TestCase(395)] + public void OneBuildTimeTotal(int SingleBuildTimeInMilliseconds) + { + var json = @"[{ + 'Start': '2016 - 01 - 21T18: 53:33.1003757 + 00:00', + 'Time': " + SingleBuildTimeInMilliseconds.ToString() + @", + 'Solution': { + 'Name': 'BuildMonitor' + }, + 'Projects': [{ + 'Start': '2016-01-21T18:53:33.6172723+00:00', + 'Time': 2, + 'Project': { + 'Name': 'BuildMonitor', + 'Id': '700a9d28-e9de-428b-a8f2-b40baf4a3e87' + } + }] +}]"; + + var calculated = new AnalyseBuildTimes(json).Total; + + Assert.That(calculated == TimeSpan.FromMilliseconds(SingleBuildTimeInMilliseconds)); + } + + // add multiple builds + // add multiple solutions and per solution breakdown + // add multiple builds over multiple months per month and per solution breakdown + + } +} diff --git a/BuildMonitor.UnitTests/packages.config b/BuildMonitor.UnitTests/packages.config index 62adf5a..09bcfd1 100644 --- a/BuildMonitor.UnitTests/packages.config +++ b/BuildMonitor.UnitTests/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/BuildMonitorPackage/BuildMonitorPackage.csproj b/BuildMonitorPackage/BuildMonitorPackage.csproj index 86e5aa0..202f497 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.csproj +++ b/BuildMonitorPackage/BuildMonitorPackage.csproj @@ -232,6 +232,7 @@ Menus.ctmenu + Designer Always From a2e9c838aa9e377af2170af6d3e4c43995971c81 Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Tue, 26 Jan 2016 15:34:20 +0000 Subject: [PATCH 03/12] Add tests for calculating build time per solution and per solution month --- .../BuildMonitor.UnitTests.csproj | 5 - .../LocalData/AnalyseBuildTimes.cs | 37 ----- .../LocalData/AnalyseBuildTimesTests.cs | 153 +++++++++++++++--- BuildMonitor/BuildMonitor.csproj | 6 + BuildMonitor/LocalData/AnalyseBuildTimes.cs | 53 ++++++ BuildMonitor/LocalData/BuildTimes.cs | 33 ++++ BuildMonitor/LocalData/IBuildTimes.cs | 17 ++ BuildMonitor/LocalData/JSONSolutionName.cs | 13 ++ BuildMonitor/LocalData/JSONSolutionTimes.cs | 16 ++ BuildMonitor/LocalData/SolutionMonth.cs | 15 ++ 10 files changed, 286 insertions(+), 62 deletions(-) delete mode 100644 BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs create mode 100644 BuildMonitor/LocalData/AnalyseBuildTimes.cs create mode 100644 BuildMonitor/LocalData/BuildTimes.cs create mode 100644 BuildMonitor/LocalData/IBuildTimes.cs create mode 100644 BuildMonitor/LocalData/JSONSolutionName.cs create mode 100644 BuildMonitor/LocalData/JSONSolutionTimes.cs create mode 100644 BuildMonitor/LocalData/SolutionMonth.cs diff --git a/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj b/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj index e8e9c4d..da9a4d6 100644 --- a/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj +++ b/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj @@ -32,10 +32,6 @@ 4 - - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - True - ..\packages\NUnit.2.6.2\lib\nunit.framework.dll @@ -45,7 +41,6 @@ - diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs deleted file mode 100644 index 2a55ac5..0000000 --- a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimes.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace BuildMonitor.UnitTests.LocalData -{ - public struct SolutionName - { - public string Name; - } - - public struct SolutionTimes - { - public int Time; - public SolutionName Solution; - public string Name { get { return Solution.Name; } } - } - - public class AnalyseBuildTimes - { - private string json; - - public TimeSpan Total { get; protected set; } - - public AnalyseBuildTimes(string json) - { - this.json = json; - - var d = JsonConvert.DeserializeObject>(json); - //var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; - //jsonSerializerSettings.Converters.Add(new IsoDateTimeConverter()); - - Total = TimeSpan.FromMilliseconds(d.Sum(s => s.Time)); - } - } -} \ No newline at end of file diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs index 842ea04..91610d7 100644 --- a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs +++ b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs @@ -5,44 +5,157 @@ using System.Threading.Tasks; using NUnit.Framework; using BuildMonitor.LocalData; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Linq; namespace BuildMonitor.UnitTests.LocalData { + internal struct SolutionBuildTime + { + public string Solution { get; set; } + public DateTime BuildDateTime { get; set; } + public int BuildTimeInMilliseconds { get; set; } + } + + internal struct SolutionMonth + { + public string Solution { get; set; } + public int Year { get; set; } + public int Month { get; set; } + } + [TestFixture] public class AnalyseBuildTimesTests { [TestCase(19366)] - [TestCase(0)] + [TestCase(1)] [TestCase(395)] - public void OneBuildTimeTotal(int SingleBuildTimeInMilliseconds) - { - var json = @"[{ - 'Start': '2016 - 01 - 21T18: 53:33.1003757 + 00:00', - 'Time': " + SingleBuildTimeInMilliseconds.ToString() + @", - 'Solution': { - 'Name': 'BuildMonitor' - }, + public void OneBuildTimeTotal(int singleBuildTimeInMilliseconds) + { + var json = CreateBuildsJSON(CreateBuildJSON(singleBuildTimeInMilliseconds)); + + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + Assert.That(buildTimes.Total == TimeSpan.FromMilliseconds(singleBuildTimeInMilliseconds)); + } + + [TestCase(1, 2)] + [TestCase(21341, 123642, 21389734)] + [TestCase(543, 0, 34534567)] + public void MultipleBuildsSameSolution(params int[] buildTimeInMilliseconds) + { + var json = CreateBuildsJSON(buildTimeInMilliseconds.Select(b => CreateBuildJSON(timeInMilliseconds: b))); + + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + Assert.That(buildTimes.Total == TimeSpan.FromMilliseconds(buildTimeInMilliseconds.Sum())); + } + + // Add a testcasesource here if more test cases are wanted + [Test] + public void MultipleBuildsMultipleSolutions() + { + var solutionbuilds = CreateBuilds( + CreateBuild("BuildMonitor", 1) + , CreateBuild("Cedd", 2) + , CreateBuild("BuildMonitor", 982734789) + , CreateBuild("Cedd", 83468) + ); + + var json = CreateBuildsJSON(solutionbuilds.Select(b => CreateBuildJSON(timeInMilliseconds: b.BuildTimeInMilliseconds, solutionName: b.Solution))); + + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + foreach (var solution in solutionbuilds.Select(s => s.Solution).Distinct()) + Assert.That(buildTimes.Solution(solution) == TimeSpan.FromMilliseconds(solutionbuilds.Where(s => s.Solution == solution).Sum(s => s.BuildTimeInMilliseconds))); + } + + // Add a testcasesource here if more test cases are wanted + [Test] + public void MultipleBuildsMultipleMonthsMultipleSolutions() + { + var solutionbuilds = CreateBuilds( + CreateBuild("BuildMonitor", 1, JANUARY1()) + , CreateBuild("Cedd", 2, JANUARY31()) + , CreateBuild("BuildMonitor", 982734789, FEBRUARY()) + , CreateBuild("Cedd", 83468, MARCH()) + ); + + var json = CreateBuildsJSON(solutionbuilds.Select(b => CreateBuildJSON(timeInMilliseconds: b.BuildTimeInMilliseconds, solutionName: b.Solution, start: b.BuildDateTime))); + + //act + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + // assert + var solutionMonths = solutionbuilds.Select(s => new SolutionMonth() { Solution = s.Solution, Month = s.BuildDateTime.Month, Year = s.BuildDateTime.Year }).Distinct(); + foreach (var solutionMonth in solutionMonths) + Assert.That(buildTimes.SolutionMonth(solutionMonth.Solution, solutionMonth.Month, solutionMonth.Year) == TimeSpan.FromMilliseconds(solutionbuilds.Where(s => s.Solution == solutionMonth.Solution && s.BuildDateTime.Month == solutionMonth.Month && s.BuildDateTime.Year == solutionMonth.Year).Sum(s => s.BuildTimeInMilliseconds))); + } + + private static string CreateBuildsJSON(string build) + { + return CreateBuildsJSON(new List() { build }); + } + + private static string CreateBuildsJSON(IEnumerable builds) + { + return "[" + string.Join("\n,\n", builds) + "]"; + } + + private static string CreateBuildJSON(int timeInMilliseconds, string solutionName = "blah", DateTime start = new DateTime()) + { + return @"{ + 'Start': '" + start.ToString() + @"', + 'Time': " + timeInMilliseconds.ToString() + @", + 'Solution': { + 'Name': '" + solutionName + @"' + }, 'Projects': [{ 'Start': '2016-01-21T18:53:33.6172723+00:00', 'Time': 2, 'Project': { - 'Name': 'BuildMonitor', + 'Name': 'blah', 'Id': '700a9d28-e9de-428b-a8f2-b40baf4a3e87' } + }, + { + 'Start': '2016-01-22T18:53:33.6172723+00:00', + 'Time': 4, + 'Project': { + 'Name': 'blah2', + 'Id': '700a9d28-e9de-428b-a8f2-b40baf4a3e88' + } }] -}]"; +}"; + } + + private static IEnumerable CreateBuilds(params SolutionBuildTime[] solutionBuildTimes) + { + return solutionBuildTimes; + } - var calculated = new AnalyseBuildTimes(json).Total; + private static SolutionBuildTime CreateBuild(string solution, int buildTimeInMilliseconds, DateTime buildDateTime = new DateTime()) + { + return new SolutionBuildTime() { Solution = "BuildMonitor", BuildTimeInMilliseconds = 1, BuildDateTime = buildDateTime }; + } - Assert.That(calculated == TimeSpan.FromMilliseconds(SingleBuildTimeInMilliseconds)); + private DateTime MARCH() + { + return new DateTime(2000, 3, 1); } - // add multiple builds - // add multiple solutions and per solution breakdown - // add multiple builds over multiple months per month and per solution breakdown + private DateTime FEBRUARY() + { + return new DateTime(2000, 2, 1); + } + + private DateTime JANUARY1() + { + return new DateTime(2000, 1, 1); + } + + private DateTime JANUARY31() + { + return new DateTime(2000, 1, 31); + } } -} +} \ No newline at end of file diff --git a/BuildMonitor/BuildMonitor.csproj b/BuildMonitor/BuildMonitor.csproj index ca41ac7..ff6d1e1 100644 --- a/BuildMonitor/BuildMonitor.csproj +++ b/BuildMonitor/BuildMonitor.csproj @@ -62,9 +62,15 @@ + + + + + + diff --git a/BuildMonitor/LocalData/AnalyseBuildTimes.cs b/BuildMonitor/LocalData/AnalyseBuildTimes.cs new file mode 100644 index 0000000..b76b54e --- /dev/null +++ b/BuildMonitor/LocalData/AnalyseBuildTimes.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BuildMonitor.LocalData +{ + public class AnalyseBuildTimes + { + public IBuildTimes Calculate(string json) + { + var solutionMonths = new Dictionary(); + var solutions = new Dictionary(); + int total = 0; + + foreach (var jsonSolutionBuildTime in ReadJSON(json)) + { + UpdateSolutionMonths(jsonSolutionBuildTime, solutionMonths); + UpdateSolutions(jsonSolutionBuildTime, solutions); + total += jsonSolutionBuildTime.Time; + } + + return new BuildTimes(TimeSpan.FromMilliseconds(total), solutions, solutionMonths); + } + + private static IEnumerable ReadJSON(string json) + { + var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; + jsonSerializerSettings.Converters.Add(new IsoDateTimeConverter()); + var jsonSolutionBuildTimes = JsonConvert.DeserializeObject>(json, jsonSerializerSettings); + return jsonSolutionBuildTimes; + } + + private void UpdateSolutions(JSONSolutionTimes jsonSolutionBuildTime, Dictionary solutions) + { + if (solutions.ContainsKey(jsonSolutionBuildTime.Name)) + solutions[jsonSolutionBuildTime.Name] = solutions[jsonSolutionBuildTime.Name] + TimeSpan.FromMilliseconds(jsonSolutionBuildTime.Time); + else + solutions.Add(jsonSolutionBuildTime.Name, TimeSpan.FromMilliseconds(jsonSolutionBuildTime.Time)); + } + + private void UpdateSolutionMonths(JSONSolutionTimes jsonSolutionBuildTime, Dictionary solutionMonths) + { + var solutionMonth = new SolutionMonth() { Solution = jsonSolutionBuildTime.Name, Month = jsonSolutionBuildTime.Start.Month, Year = jsonSolutionBuildTime.Start.Year }; + + if (solutionMonths.ContainsKey(solutionMonth)) + solutionMonths[solutionMonth] = solutionMonths[solutionMonth] + TimeSpan.FromMilliseconds(jsonSolutionBuildTime.Time); + else + solutionMonths.Add(solutionMonth, TimeSpan.FromMilliseconds(jsonSolutionBuildTime.Time)); + } + } +} \ No newline at end of file diff --git a/BuildMonitor/LocalData/BuildTimes.cs b/BuildMonitor/LocalData/BuildTimes.cs new file mode 100644 index 0000000..eb6c303 --- /dev/null +++ b/BuildMonitor/LocalData/BuildTimes.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BuildMonitor.LocalData +{ + internal class BuildTimes : IBuildTimes + { + public TimeSpan Total { get; protected set; } + + public TimeSpan SolutionMonth(string solution, int month, int year) + { + return solutionMonths[new SolutionMonth() { Solution = solution, Month = month, Year = year }]; + } + + public TimeSpan Solution(string solution) + { + return solutions[solution]; + } + + private Dictionary solutionMonths; + private Dictionary solutions; + + public BuildTimes(TimeSpan total, Dictionary solutions, Dictionary solutionMonths) + { + Total = total; + this.solutions = solutions; + this.solutionMonths = solutionMonths; + } + } +} diff --git a/BuildMonitor/LocalData/IBuildTimes.cs b/BuildMonitor/LocalData/IBuildTimes.cs new file mode 100644 index 0000000..63b7d4f --- /dev/null +++ b/BuildMonitor/LocalData/IBuildTimes.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BuildMonitor.LocalData +{ + public interface IBuildTimes + { + TimeSpan Total { get; } + + TimeSpan SolutionMonth(string solution, int month, int year); + + TimeSpan Solution(string solution); + } +} diff --git a/BuildMonitor/LocalData/JSONSolutionName.cs b/BuildMonitor/LocalData/JSONSolutionName.cs new file mode 100644 index 0000000..b9689ae --- /dev/null +++ b/BuildMonitor/LocalData/JSONSolutionName.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BuildMonitor.LocalData +{ + internal struct JSONSolutionName + { + public string Name; + } +} diff --git a/BuildMonitor/LocalData/JSONSolutionTimes.cs b/BuildMonitor/LocalData/JSONSolutionTimes.cs new file mode 100644 index 0000000..8a93bad --- /dev/null +++ b/BuildMonitor/LocalData/JSONSolutionTimes.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BuildMonitor.LocalData +{ + internal struct JSONSolutionTimes + { + public int Time; + public DateTime Start; + public JSONSolutionName Solution; + public string Name { get { return Solution.Name; } } + } +} diff --git a/BuildMonitor/LocalData/SolutionMonth.cs b/BuildMonitor/LocalData/SolutionMonth.cs new file mode 100644 index 0000000..76bf71b --- /dev/null +++ b/BuildMonitor/LocalData/SolutionMonth.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BuildMonitor.LocalData +{ + internal struct SolutionMonth + { + public string Solution { get; set; } + public int Year { get; set; } + public int Month { get; set; } + } +} From 386206086daefa64be5a60fe9b866ea44ca8902d Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Thu, 28 Jan 2016 17:25:16 +0000 Subject: [PATCH 04/12] Write build times out to the ressoftware database --- BuildMonitorPackage/BuildMonitorPackage.cs | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/BuildMonitorPackage/BuildMonitorPackage.cs b/BuildMonitorPackage/BuildMonitorPackage.cs index 3cb8579..cc1ca29 100644 --- a/BuildMonitorPackage/BuildMonitorPackage.cs +++ b/BuildMonitorPackage/BuildMonitorPackage.cs @@ -9,6 +9,10 @@ using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell; using Constants = EnvDTE.Constants; +using System.Data.SqlClient; +using System.Data; +using System.Security.Principal; +using System.Threading.Tasks; namespace BuildMonitorPackage { @@ -66,12 +70,32 @@ protected override void Initialize() { Print("[{0}] Time Elapsed: {1} \t\t", b.SessionBuildCount, b.SolutionBuildTime.ToTime()); PrintLine("Session build time: {0}\n", b.SessionMillisecondsElapsed.ToTime()); + System.Threading.Tasks.Task.Factory.StartNew(() => SaveToDatabase(b)); }; monitor.ProjectBuildFinished = b => PrintLine(" - {0}\t-- {1} --", b.MillisecondsElapsed.ToTime(), b.ProjectName); AnalyseBuildTimesCommand.Initialize(this); } + private void SaveToDatabase(SolutionBuildData b) + { + try + { + var conn = new SqlConnection("Server=kl-sql-001;DataBase=RESSoftware;Integrated Security=SSPI"); + conn.Open(); + SqlCommand cmd = new SqlCommand("dbo.AddBuildTime", conn); + cmd.Parameters.AddWithValue("SolutionName", b.SolutionName); + cmd.Parameters.AddWithValue("BuildDateTime", DateTime.Now); + cmd.Parameters.AddWithValue("TimeInMilliseconds", b.SolutionBuildTime); + cmd.Parameters.AddWithValue("NT4Name", WindowsIdentity.GetCurrent().Name); + cmd.CommandType = CommandType.StoredProcedure; + cmd.ExecuteNonQuery(); + if (conn != null) conn.Close(); + } + catch // ignore exceptions, its not a big problem if we can't log the build time + { } + } + private void Solution_Opened() { solution = new BuildMonitor.Domain.Solution { Name = GetSolutionName() }; From 5d126da950fe1bc5c1c4cb141b9b38a6fd14d6f2 Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Fri, 29 Jan 2016 18:02:44 +0000 Subject: [PATCH 05/12] Updating version number --- BuildMonitorPackage/Properties/AssemblyInfo.cs | 4 ++-- BuildMonitorPackage/source.extension.vsixmanifest | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BuildMonitorPackage/Properties/AssemblyInfo.cs b/BuildMonitorPackage/Properties/AssemblyInfo.cs index 0f12b42..41bc1a1 100644 --- a/BuildMonitorPackage/Properties/AssemblyInfo.cs +++ b/BuildMonitorPackage/Properties/AssemblyInfo.cs @@ -29,8 +29,8 @@ // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.5.0.0")] +[assembly: AssemblyFileVersion("1.5.0.0")] diff --git a/BuildMonitorPackage/source.extension.vsixmanifest b/BuildMonitorPackage/source.extension.vsixmanifest index b232ae7..475b36e 100644 --- a/BuildMonitorPackage/source.extension.vsixmanifest +++ b/BuildMonitorPackage/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Build Monitor Measure how long it takes to build your solution and individual projects in Visual Studio. http://visualstudiogallery.msdn.microsoft.com/b0c87e47-f4ee-4935-9a59-f2c81ce692ab From e4391cc9aa2ca5a6ecb6e191cc39ec53e4c3d1d6 Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Fri, 29 Jan 2016 18:09:24 +0000 Subject: [PATCH 06/12] Add tests / functionality to provide a list of available solutionmonths --- .../LocalData/AnalyseBuildTimesTests.cs | 63 +++++++++++++------ BuildMonitor/LocalData/AnalyseBuildTimes.cs | 2 +- BuildMonitor/LocalData/BuildTimes.cs | 13 +++- BuildMonitor/LocalData/IBuildTimes.cs | 2 + BuildMonitor/LocalData/SolutionMonth.cs | 42 +++++++++++-- BuildMonitor/Properties/AssemblyInfo.cs | 6 +- 6 files changed, 100 insertions(+), 28 deletions(-) diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs index 91610d7..dff4c6f 100644 --- a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs +++ b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using NUnit.Framework; using BuildMonitor.LocalData; +using System.Collections; namespace BuildMonitor.UnitTests.LocalData { @@ -15,22 +16,43 @@ internal struct SolutionBuildTime public int BuildTimeInMilliseconds { get; set; } } - internal struct SolutionMonth - { - public string Solution { get; set; } - public int Year { get; set; } - public int Month { get; set; } - } - [TestFixture] public class AnalyseBuildTimesTests { + [Test] + public void AvailableMonths() + { + var solutionbuilds = CreateBuilds( + CreateBuild(buildDateTime: JANUARY1()) + , CreateBuild(buildDateTime: JANUARY31()) + , CreateBuild(buildDateTime: MARCH()) + ); + + var json = CreateBuildsJSON(solutionbuilds); + + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + var expected = CreateSolutionMonths(CreateSolutionMonth(JANUARY1()), CreateSolutionMonth(MARCH())); + + CollectionAssert.AreEqual(expected, buildTimes.SolutionMonths); + } + + private IEnumerable CreateSolutionMonths(params SolutionMonth[] solutionMonths) + { + return solutionMonths; + } + + private SolutionMonth CreateSolutionMonth(DateTime dateTime) + { + return new SolutionMonth("", dateTime.Year, dateTime.Month); + } + [TestCase(19366)] [TestCase(1)] [TestCase(395)] public void OneBuildTimeTotal(int singleBuildTimeInMilliseconds) { - var json = CreateBuildsJSON(CreateBuildJSON(singleBuildTimeInMilliseconds)); + var json = CreateBuildsJSON(CreateBuildJSON(CreateBuild(buildTimeInMilliseconds: singleBuildTimeInMilliseconds))); var buildTimes = new AnalyseBuildTimes().Calculate(json); @@ -42,7 +64,7 @@ public void OneBuildTimeTotal(int singleBuildTimeInMilliseconds) [TestCase(543, 0, 34534567)] public void MultipleBuildsSameSolution(params int[] buildTimeInMilliseconds) { - var json = CreateBuildsJSON(buildTimeInMilliseconds.Select(b => CreateBuildJSON(timeInMilliseconds: b))); + var json = CreateBuildsJSON(buildTimeInMilliseconds.Select(b => CreateBuild(buildTimeInMilliseconds: b))); var buildTimes = new AnalyseBuildTimes().Calculate(json); @@ -60,7 +82,7 @@ public void MultipleBuildsMultipleSolutions() , CreateBuild("Cedd", 83468) ); - var json = CreateBuildsJSON(solutionbuilds.Select(b => CreateBuildJSON(timeInMilliseconds: b.BuildTimeInMilliseconds, solutionName: b.Solution))); + var json = CreateBuildsJSON(solutionbuilds); var buildTimes = new AnalyseBuildTimes().Calculate(json); @@ -79,13 +101,13 @@ public void MultipleBuildsMultipleMonthsMultipleSolutions() , CreateBuild("Cedd", 83468, MARCH()) ); - var json = CreateBuildsJSON(solutionbuilds.Select(b => CreateBuildJSON(timeInMilliseconds: b.BuildTimeInMilliseconds, solutionName: b.Solution, start: b.BuildDateTime))); + var json = CreateBuildsJSON(solutionbuilds); //act var buildTimes = new AnalyseBuildTimes().Calculate(json); // assert - var solutionMonths = solutionbuilds.Select(s => new SolutionMonth() { Solution = s.Solution, Month = s.BuildDateTime.Month, Year = s.BuildDateTime.Year }).Distinct(); + var solutionMonths = solutionbuilds.Select(s => new SolutionMonth(solution: s.Solution, month: s.BuildDateTime.Month, year: s.BuildDateTime.Year)).Distinct(); foreach (var solutionMonth in solutionMonths) Assert.That(buildTimes.SolutionMonth(solutionMonth.Solution, solutionMonth.Month, solutionMonth.Year) == TimeSpan.FromMilliseconds(solutionbuilds.Where(s => s.Solution == solutionMonth.Solution && s.BuildDateTime.Month == solutionMonth.Month && s.BuildDateTime.Year == solutionMonth.Year).Sum(s => s.BuildTimeInMilliseconds))); } @@ -100,13 +122,18 @@ private static string CreateBuildsJSON(IEnumerable builds) return "[" + string.Join("\n,\n", builds) + "]"; } - private static string CreateBuildJSON(int timeInMilliseconds, string solutionName = "blah", DateTime start = new DateTime()) + private static string CreateBuildsJSON(IEnumerable solutionbuilds) + { + return CreateBuildsJSON(solutionbuilds.Select(b => CreateBuildJSON(b))); + } + + private static string CreateBuildJSON(SolutionBuildTime build) { return @"{ - 'Start': '" + start.ToString() + @"', - 'Time': " + timeInMilliseconds.ToString() + @", + 'Start': '" + build.BuildDateTime.ToString() + @"', + 'Time': " + build.BuildTimeInMilliseconds.ToString() + @", 'Solution': { - 'Name': '" + solutionName + @"' + 'Name': '" + build.Solution + @"' }, 'Projects': [{ 'Start': '2016-01-21T18:53:33.6172723+00:00', @@ -132,9 +159,9 @@ private static IEnumerable CreateBuilds(params SolutionBuildT return solutionBuildTimes; } - private static SolutionBuildTime CreateBuild(string solution, int buildTimeInMilliseconds, DateTime buildDateTime = new DateTime()) + private static SolutionBuildTime CreateBuild(string solution = "", int buildTimeInMilliseconds = 0, DateTime buildDateTime = new DateTime()) { - return new SolutionBuildTime() { Solution = "BuildMonitor", BuildTimeInMilliseconds = 1, BuildDateTime = buildDateTime }; + return new SolutionBuildTime() { Solution = solution, BuildTimeInMilliseconds = buildTimeInMilliseconds, BuildDateTime = buildDateTime }; } private DateTime MARCH() diff --git a/BuildMonitor/LocalData/AnalyseBuildTimes.cs b/BuildMonitor/LocalData/AnalyseBuildTimes.cs index b76b54e..a3a05c8 100644 --- a/BuildMonitor/LocalData/AnalyseBuildTimes.cs +++ b/BuildMonitor/LocalData/AnalyseBuildTimes.cs @@ -42,7 +42,7 @@ private void UpdateSolutions(JSONSolutionTimes jsonSolutionBuildTime, Dictionary private void UpdateSolutionMonths(JSONSolutionTimes jsonSolutionBuildTime, Dictionary solutionMonths) { - var solutionMonth = new SolutionMonth() { Solution = jsonSolutionBuildTime.Name, Month = jsonSolutionBuildTime.Start.Month, Year = jsonSolutionBuildTime.Start.Year }; + var solutionMonth = new SolutionMonth( solution: jsonSolutionBuildTime.Name, month: jsonSolutionBuildTime.Start.Month, year: jsonSolutionBuildTime.Start.Year ); if (solutionMonths.ContainsKey(solutionMonth)) solutionMonths[solutionMonth] = solutionMonths[solutionMonth] + TimeSpan.FromMilliseconds(jsonSolutionBuildTime.Time); diff --git a/BuildMonitor/LocalData/BuildTimes.cs b/BuildMonitor/LocalData/BuildTimes.cs index eb6c303..ea745d9 100644 --- a/BuildMonitor/LocalData/BuildTimes.cs +++ b/BuildMonitor/LocalData/BuildTimes.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; @@ -10,14 +11,22 @@ internal class BuildTimes : IBuildTimes { public TimeSpan Total { get; protected set; } + public IEnumerable SolutionMonths + { + get + { + return this.solutionMonths.Keys; + } + } + public TimeSpan SolutionMonth(string solution, int month, int year) { - return solutionMonths[new SolutionMonth() { Solution = solution, Month = month, Year = year }]; + return this.solutionMonths[new SolutionMonth(solution: solution, month: month, year: year )]; } public TimeSpan Solution(string solution) { - return solutions[solution]; + return this.solutions[solution]; } private Dictionary solutionMonths; diff --git a/BuildMonitor/LocalData/IBuildTimes.cs b/BuildMonitor/LocalData/IBuildTimes.cs index 63b7d4f..bd28b33 100644 --- a/BuildMonitor/LocalData/IBuildTimes.cs +++ b/BuildMonitor/LocalData/IBuildTimes.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,6 +10,7 @@ namespace BuildMonitor.LocalData public interface IBuildTimes { TimeSpan Total { get; } + IEnumerable SolutionMonths { get; } TimeSpan SolutionMonth(string solution, int month, int year); diff --git a/BuildMonitor/LocalData/SolutionMonth.cs b/BuildMonitor/LocalData/SolutionMonth.cs index 76bf71b..2d9a4af 100644 --- a/BuildMonitor/LocalData/SolutionMonth.cs +++ b/BuildMonitor/LocalData/SolutionMonth.cs @@ -6,10 +6,44 @@ namespace BuildMonitor.LocalData { - internal struct SolutionMonth + public class SolutionMonth { - public string Solution { get; set; } - public int Year { get; set; } - public int Month { get; set; } + private readonly string solution; + private readonly int year; + private readonly int month; + + public SolutionMonth(string solution, int year, int month) + { + this.solution = solution; + this.year = year; + this.month = month; + } + + public string Solution { get { return this.solution; } } + public int Year { get { return this.year; } } + public int Month { get { return this.month; } } + + public override bool Equals(object obj) + { + if (!(obj is SolutionMonth)) + return base.Equals(obj); + + var other = (obj as SolutionMonth); + + return (Solution == other.Solution && Year == other.Year && Month == other.Month); + } + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + // Suitable nullity checks etc, of course :) + hash = hash * 23 + Solution.GetHashCode(); + hash = hash * 23 + Year.GetHashCode(); + hash = hash * 23 + Month.GetHashCode(); + return hash; + } + } } } diff --git a/BuildMonitor/Properties/AssemblyInfo.cs b/BuildMonitor/Properties/AssemblyInfo.cs index c6b0fac..ab4bb43 100644 --- a/BuildMonitor/Properties/AssemblyInfo.cs +++ b/BuildMonitor/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BuildMonitor")] -[assembly: AssemblyCopyright("Copyright © 2013")] +[assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.5.0.0")] +[assembly: AssemblyFileVersion("1.5.0.0")] From b24df799266b8a1bdc6ac0845cee4629de725940 Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Fri, 5 Feb 2016 18:25:36 +0000 Subject: [PATCH 07/12] Add test and code for availablesolutions --- .../LocalData/AnalyseBuildTimesTests.cs | 35 +++++++++++++++---- BuildMonitor/LocalData/BuildTimes.cs | 10 +++++- BuildMonitor/LocalData/IBuildTimes.cs | 3 +- BuildMonitor/LocalData/SolutionMonth.cs | 2 +- 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs index dff4c6f..45900f5 100644 --- a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs +++ b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs @@ -34,17 +34,28 @@ public void AvailableMonths() var expected = CreateSolutionMonths(CreateSolutionMonth(JANUARY1()), CreateSolutionMonth(MARCH())); - CollectionAssert.AreEqual(expected, buildTimes.SolutionMonths); + CollectionAssert.AreEqual(expected, buildTimes.AvailableMonths); } - private IEnumerable CreateSolutionMonths(params SolutionMonth[] solutionMonths) + [Test] + public void AvailableSolutions() { - return solutionMonths; - } + const string CEDD = "Cedd"; + const string BUILDMONITOR = "BuildMonitor"; - private SolutionMonth CreateSolutionMonth(DateTime dateTime) - { - return new SolutionMonth("", dateTime.Year, dateTime.Month); + var solutionbuilds = CreateBuilds( + CreateBuild(solution: CEDD) + , CreateBuild(solution: BUILDMONITOR) + , CreateBuild(solution: CEDD) + ); + + var json = CreateBuildsJSON(solutionbuilds); + + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + var expected = CreateSolutionMonths(new SolutionMonth(solution: CEDD), new SolutionMonth(solution: BUILDMONITOR)); + + CollectionAssert.AreEqual(expected, buildTimes.AvailableSolutions); } [TestCase(19366)] @@ -164,6 +175,16 @@ private static IEnumerable CreateBuilds(params SolutionBuildT return new SolutionBuildTime() { Solution = solution, BuildTimeInMilliseconds = buildTimeInMilliseconds, BuildDateTime = buildDateTime }; } + private IEnumerable CreateSolutionMonths(params SolutionMonth[] solutionMonths) + { + return solutionMonths; + } + + private SolutionMonth CreateSolutionMonth(DateTime dateTime) + { + return new SolutionMonth("", dateTime.Year, dateTime.Month); + } + private DateTime MARCH() { return new DateTime(2000, 3, 1); diff --git a/BuildMonitor/LocalData/BuildTimes.cs b/BuildMonitor/LocalData/BuildTimes.cs index ea745d9..9eafe4d 100644 --- a/BuildMonitor/LocalData/BuildTimes.cs +++ b/BuildMonitor/LocalData/BuildTimes.cs @@ -11,7 +11,7 @@ internal class BuildTimes : IBuildTimes { public TimeSpan Total { get; protected set; } - public IEnumerable SolutionMonths + public IEnumerable AvailableMonths { get { @@ -19,6 +19,14 @@ public IEnumerable SolutionMonths } } + public IEnumerable AvailableSolutions + { + get + { + return this.solutions.Keys; + } + } + public TimeSpan SolutionMonth(string solution, int month, int year) { return this.solutionMonths[new SolutionMonth(solution: solution, month: month, year: year )]; diff --git a/BuildMonitor/LocalData/IBuildTimes.cs b/BuildMonitor/LocalData/IBuildTimes.cs index bd28b33..15abf0a 100644 --- a/BuildMonitor/LocalData/IBuildTimes.cs +++ b/BuildMonitor/LocalData/IBuildTimes.cs @@ -10,7 +10,8 @@ namespace BuildMonitor.LocalData public interface IBuildTimes { TimeSpan Total { get; } - IEnumerable SolutionMonths { get; } + IEnumerable AvailableMonths { get; } + IEnumerable AvailableSolutions { get; } TimeSpan SolutionMonth(string solution, int month, int year); diff --git a/BuildMonitor/LocalData/SolutionMonth.cs b/BuildMonitor/LocalData/SolutionMonth.cs index 2d9a4af..146936f 100644 --- a/BuildMonitor/LocalData/SolutionMonth.cs +++ b/BuildMonitor/LocalData/SolutionMonth.cs @@ -12,7 +12,7 @@ public class SolutionMonth private readonly int year; private readonly int month; - public SolutionMonth(string solution, int year, int month) + public SolutionMonth(string solution = "", int year = 0, int month = 0) { this.solution = solution; this.year = year; From e206a589733203f79af6afeb299b2a6ea341ea72 Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Wed, 2 Mar 2016 18:28:10 +0000 Subject: [PATCH 08/12] Start adding form to show breakdown of buildtime for solution by month, add some tests based on the problems encountered --- .../BuildMonitor.UnitTests.csproj | 1 + .../LocalData/AnalyseBuildTimesTests.cs | 18 +++++++- .../LocalData/BuildTimesTests.cs | 22 +++++++++ BuildMonitor/LocalData/AnalyseBuildTimes.cs | 2 +- BuildMonitor/LocalData/BuildTimes.cs | 6 ++- BuildMonitor/LocalData/SolutionMonth.cs | 2 +- BuildMonitorPackage/AnalyseBuildTimes.xaml | 2 +- .../AnalyseBuildTimesCommand.cs | 45 +++++++++++++++++++ 8 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 BuildMonitor.UnitTests/LocalData/BuildTimesTests.cs diff --git a/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj b/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj index da9a4d6..fb9120e 100644 --- a/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj +++ b/BuildMonitor.UnitTests/BuildMonitor.UnitTests.csproj @@ -42,6 +42,7 @@ + diff --git a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs index 45900f5..d4f1429 100644 --- a/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs +++ b/BuildMonitor.UnitTests/LocalData/AnalyseBuildTimesTests.cs @@ -19,6 +19,22 @@ internal struct SolutionBuildTime [TestFixture] public class AnalyseBuildTimesTests { + [Test] + public void IgnoreNullSolutionNames() + { + const string json = +@"[{ + 'Start': '2016-01-22T18:53:33.6172723+00:00', + 'Time': 2, + 'Solution': { + } +}]"; + + var buildTimes = new AnalyseBuildTimes().Calculate(json); + + Assert.AreEqual(0, buildTimes.AvailableSolutions.Count()); + } + [Test] public void AvailableMonths() { @@ -53,7 +69,7 @@ public void AvailableSolutions() var buildTimes = new AnalyseBuildTimes().Calculate(json); - var expected = CreateSolutionMonths(new SolutionMonth(solution: CEDD), new SolutionMonth(solution: BUILDMONITOR)); + var expected = new List() { CEDD, BUILDMONITOR }; CollectionAssert.AreEqual(expected, buildTimes.AvailableSolutions); } diff --git a/BuildMonitor.UnitTests/LocalData/BuildTimesTests.cs b/BuildMonitor.UnitTests/LocalData/BuildTimesTests.cs new file mode 100644 index 0000000..0afe816 --- /dev/null +++ b/BuildMonitor.UnitTests/LocalData/BuildTimesTests.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using NUnit.Framework; +using BuildMonitor.LocalData; + +namespace BuildMonitor.UnitTests.LocalData +{ + [TestFixture] + public class BuildTimesTests + { + [Test] + public void ReturnZeroForMissingMonth() + { + var buildTimes = new BuildTimes(TimeSpan.FromSeconds(0), new Dictionary(), new Dictionary()); + + Assert.AreEqual(TimeSpan.FromSeconds(0), buildTimes.SolutionMonth("", 0, 0)); + } + } +} diff --git a/BuildMonitor/LocalData/AnalyseBuildTimes.cs b/BuildMonitor/LocalData/AnalyseBuildTimes.cs index a3a05c8..30c3e5f 100644 --- a/BuildMonitor/LocalData/AnalyseBuildTimes.cs +++ b/BuildMonitor/LocalData/AnalyseBuildTimes.cs @@ -29,7 +29,7 @@ private static IEnumerable ReadJSON(string json) var jsonSerializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; jsonSerializerSettings.Converters.Add(new IsoDateTimeConverter()); var jsonSolutionBuildTimes = JsonConvert.DeserializeObject>(json, jsonSerializerSettings); - return jsonSolutionBuildTimes; + return jsonSolutionBuildTimes.Where(b => b.Name != null); } private void UpdateSolutions(JSONSolutionTimes jsonSolutionBuildTime, Dictionary solutions) diff --git a/BuildMonitor/LocalData/BuildTimes.cs b/BuildMonitor/LocalData/BuildTimes.cs index 9eafe4d..c4f4568 100644 --- a/BuildMonitor/LocalData/BuildTimes.cs +++ b/BuildMonitor/LocalData/BuildTimes.cs @@ -7,7 +7,7 @@ namespace BuildMonitor.LocalData { - internal class BuildTimes : IBuildTimes + public class BuildTimes : IBuildTimes { public TimeSpan Total { get; protected set; } @@ -29,7 +29,9 @@ public IEnumerable AvailableSolutions public TimeSpan SolutionMonth(string solution, int month, int year) { - return this.solutionMonths[new SolutionMonth(solution: solution, month: month, year: year )]; + var solutionMonth = new SolutionMonth(solution: solution, month: month, year: year); + + return this.solutionMonths.ContainsKey(solutionMonth) ? this.solutionMonths[solutionMonth] : TimeSpan.FromSeconds(0); } public TimeSpan Solution(string solution) diff --git a/BuildMonitor/LocalData/SolutionMonth.cs b/BuildMonitor/LocalData/SolutionMonth.cs index 146936f..e5d2c64 100644 --- a/BuildMonitor/LocalData/SolutionMonth.cs +++ b/BuildMonitor/LocalData/SolutionMonth.cs @@ -14,7 +14,7 @@ public class SolutionMonth public SolutionMonth(string solution = "", int year = 0, int month = 0) { - this.solution = solution; + this.solution = solution ?? ""; this.year = year; this.month = month; } diff --git a/BuildMonitorPackage/AnalyseBuildTimes.xaml b/BuildMonitorPackage/AnalyseBuildTimes.xaml index 355ff57..94992d7 100644 --- a/BuildMonitorPackage/AnalyseBuildTimes.xaml +++ b/BuildMonitorPackage/AnalyseBuildTimes.xaml @@ -6,5 +6,5 @@ xmlns:local="clr-namespace:BuildMonitorPackage" mc:Ignorable="d" Title="AnalyseBuildTimes" Height="300" Width="300"> - + diff --git a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs index 08b63fb..caa2570 100644 --- a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs +++ b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs @@ -9,6 +9,14 @@ using System.Globalization; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; +using System.IO; +using BuildMonitor.LocalData; +using System.Data; +using System.Collections.Generic; +using System.Dynamic; +using System.Linq; +using System.Windows.Controls; +using System.Windows.Data; namespace BuildMonitorPackage { @@ -93,6 +101,43 @@ public static void Initialize(Package package) /// Event args. private void MenuItemCallback(object sender, EventArgs e) { + + IBuildTimes buildTimes = new BuildMonitor.LocalData.AnalyseBuildTimes().Calculate(File.ReadAllText(Settings.RepositoryPath)); + + var data = new List(); + + foreach (var solution in buildTimes.AvailableSolutions) + { + dynamic row = new ExpandoObject(); + var p = row as IDictionary; + foreach (var month in buildTimes.AvailableMonths) + { + p[$"{month.Month} {month.Year}"] = buildTimes.SolutionMonth(solution, month.Month, month.Year); + } + + data.Add(row); + } + var form = new AnalyseBuildTimes(); + + form.dataGrid.ItemsSource = data; + + var rows = data.OfType>(); + var columns = rows.SelectMany(d => d.Keys).Distinct(StringComparer.OrdinalIgnoreCase); + + foreach (string text in columns) + { + // now set up a column and binding for each property + var column = new DataGridTextColumn + { + Header = text, + Binding = new Binding(text) + }; + + form.dataGrid.Columns.Add(column); + } + + form.ShowDialog(); + string message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.GetType().FullName); string title = "AnalyseBuildTimesCommand"; From ce87379c4a727f548ba62830c5203e037b74bc6a Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Wed, 2 Mar 2016 19:23:52 +0000 Subject: [PATCH 09/12] move ui code in to window and calculation ish code in to calculator --- BuildMonitor/BuildMonitor.csproj | 1 + BuildMonitor/LocalData/BuildTimes.cs | 41 +++++++++++++--- BuildMonitor/LocalData/IBuildTimes.cs | 5 +- BuildMonitorPackage/AnalyseBuildTimes.xaml | 2 +- BuildMonitorPackage/AnalyseBuildTimes.xaml.cs | 23 +++++++++ .../AnalyseBuildTimesCommand.cs | 47 +------------------ 6 files changed, 63 insertions(+), 56 deletions(-) diff --git a/BuildMonitor/BuildMonitor.csproj b/BuildMonitor/BuildMonitor.csproj index ff6d1e1..7e3ef91 100644 --- a/BuildMonitor/BuildMonitor.csproj +++ b/BuildMonitor/BuildMonitor.csproj @@ -38,6 +38,7 @@ cedd.snk + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll diff --git a/BuildMonitor/LocalData/BuildTimes.cs b/BuildMonitor/LocalData/BuildTimes.cs index c4f4568..b8b2c60 100644 --- a/BuildMonitor/LocalData/BuildTimes.cs +++ b/BuildMonitor/LocalData/BuildTimes.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Dynamic; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,6 +10,13 @@ namespace BuildMonitor.LocalData { public class BuildTimes : IBuildTimes { + public BuildTimes(TimeSpan total, Dictionary solutions, Dictionary solutionMonths) + { + Total = total; + this.solutions = solutions; + this.solutionMonths = solutionMonths; + } + public TimeSpan Total { get; protected set; } public IEnumerable AvailableMonths @@ -39,14 +47,33 @@ public TimeSpan Solution(string solution) return this.solutions[solution]; } - private Dictionary solutionMonths; - private Dictionary solutions; - - public BuildTimes(TimeSpan total, Dictionary solutions, Dictionary solutionMonths) + // this is for the UI, in MVC land it would be a ViewModel, but that seems a bit excessive here. + public IEnumerable SolutionMonthTable() { - Total = total; - this.solutions = solutions; - this.solutionMonths = solutionMonths; + var table = new List(); + + foreach (var solution in AvailableSolutions) + { + dynamic row = new ExpandoObject(); + var p = row as IDictionary; + p["Solution"] = solution; + foreach (var month in AvailableMonths) + { + var buildTime = SolutionMonth(solution, month.Month, month.Year); + + if (buildTime == TimeSpan.FromSeconds(0)) + p[$"{month.Month} {month.Year}"] = ""; + else + p[$"{month.Month} {month.Year}"] = $@"{buildTime:hh\:mm\:ss}"; + } + + table.Add(row); + } + + return table; } + + private Dictionary solutionMonths; + private Dictionary solutions; } } diff --git a/BuildMonitor/LocalData/IBuildTimes.cs b/BuildMonitor/LocalData/IBuildTimes.cs index 15abf0a..5f5fc9a 100644 --- a/BuildMonitor/LocalData/IBuildTimes.cs +++ b/BuildMonitor/LocalData/IBuildTimes.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Dynamic; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -9,12 +10,12 @@ namespace BuildMonitor.LocalData { public interface IBuildTimes { + IEnumerable SolutionMonthTable(); + TimeSpan Total { get; } IEnumerable AvailableMonths { get; } IEnumerable AvailableSolutions { get; } - TimeSpan SolutionMonth(string solution, int month, int year); - TimeSpan Solution(string solution); } } diff --git a/BuildMonitorPackage/AnalyseBuildTimes.xaml b/BuildMonitorPackage/AnalyseBuildTimes.xaml index 94992d7..86ecc4d 100644 --- a/BuildMonitorPackage/AnalyseBuildTimes.xaml +++ b/BuildMonitorPackage/AnalyseBuildTimes.xaml @@ -6,5 +6,5 @@ xmlns:local="clr-namespace:BuildMonitorPackage" mc:Ignorable="d" Title="AnalyseBuildTimes" Height="300" Width="300"> - + diff --git a/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs b/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs index f535b1b..89b419f 100644 --- a/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs +++ b/BuildMonitorPackage/AnalyseBuildTimes.xaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Dynamic; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -23,5 +24,27 @@ public AnalyseBuildTimes() { InitializeComponent(); } + + public AnalyseBuildTimes(IEnumerable solutionMonthTable) : this() + { + // you would have thought it would be easier to show a grid of data in 2016 ... + solutionMonthDataGrid.ItemsSource = solutionMonthTable; + + var rows = solutionMonthTable.OfType>(); + var columns = rows.SelectMany(d => d.Keys).Distinct(StringComparer.OrdinalIgnoreCase); + + foreach (string text in columns) + { + // now set up a column and binding for each property + var column = new DataGridTextColumn + { + Header = text, + Binding = new Binding(text) + }; + + solutionMonthDataGrid.Columns.Add(column); + } + + } } } diff --git a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs index caa2570..307e86e 100644 --- a/BuildMonitorPackage/AnalyseBuildTimesCommand.cs +++ b/BuildMonitorPackage/AnalyseBuildTimesCommand.cs @@ -101,54 +101,9 @@ public static void Initialize(Package package) /// Event args. private void MenuItemCallback(object sender, EventArgs e) { - - IBuildTimes buildTimes = new BuildMonitor.LocalData.AnalyseBuildTimes().Calculate(File.ReadAllText(Settings.RepositoryPath)); - - var data = new List(); - - foreach (var solution in buildTimes.AvailableSolutions) - { - dynamic row = new ExpandoObject(); - var p = row as IDictionary; - foreach (var month in buildTimes.AvailableMonths) - { - p[$"{month.Month} {month.Year}"] = buildTimes.SolutionMonth(solution, month.Month, month.Year); - } - - data.Add(row); - } - var form = new AnalyseBuildTimes(); - - form.dataGrid.ItemsSource = data; - - var rows = data.OfType>(); - var columns = rows.SelectMany(d => d.Keys).Distinct(StringComparer.OrdinalIgnoreCase); - - foreach (string text in columns) - { - // now set up a column and binding for each property - var column = new DataGridTextColumn - { - Header = text, - Binding = new Binding(text) - }; - - form.dataGrid.Columns.Add(column); - } + var form = new AnalyseBuildTimes(new BuildMonitor.LocalData.AnalyseBuildTimes().Calculate(File.ReadAllText(Settings.RepositoryPath)).SolutionMonthTable()); form.ShowDialog(); - - string message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.GetType().FullName); - string title = "AnalyseBuildTimesCommand"; - - // Show a message box to prove we were here - VsShellUtilities.ShowMessageBox( - this.ServiceProvider, - message, - title, - OLEMSGICON.OLEMSGICON_INFO, - OLEMSGBUTTON.OLEMSGBUTTON_OK, - OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST); } } } From 7aab5c0ba74f0968753a3e68abebf150aa273528 Mon Sep 17 00:00:00 2001 From: Cedd Burge Date: Wed, 2 Mar 2016 19:48:27 +0000 Subject: [PATCH 10/12] Making the UI look a bit more acceptable --- BuildMonitor/LocalData/BuildTimes.cs | 4 ++-- BuildMonitor/LocalData/IBuildTimes.cs | 1 + BuildMonitorPackage/AnalyseBuildTimes.xaml | 8 ++++++-- BuildMonitorPackage/AnalyseBuildTimes.xaml.cs | 9 +++++++-- BuildMonitorPackage/BuildMonitorPackage.vsct | 2 +- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/BuildMonitor/LocalData/BuildTimes.cs b/BuildMonitor/LocalData/BuildTimes.cs index b8b2c60..bcd0304 100644 --- a/BuildMonitor/LocalData/BuildTimes.cs +++ b/BuildMonitor/LocalData/BuildTimes.cs @@ -62,9 +62,9 @@ public IEnumerable SolutionMonthTable() var buildTime = SolutionMonth(solution, month.Month, month.Year); if (buildTime == TimeSpan.FromSeconds(0)) - p[$"{month.Month} {month.Year}"] = ""; + p[$"{month.Month:mmm} {month.Year}"] = ""; else - p[$"{month.Month} {month.Year}"] = $@"{buildTime:hh\:mm\:ss}"; + p[$"{month.Month:mmm} {month.Year}"] = $@"{buildTime:hh\:mm\:ss}"; } table.Add(row); diff --git a/BuildMonitor/LocalData/IBuildTimes.cs b/BuildMonitor/LocalData/IBuildTimes.cs index 5f5fc9a..5d9cdad 100644 --- a/BuildMonitor/LocalData/IBuildTimes.cs +++ b/BuildMonitor/LocalData/IBuildTimes.cs @@ -12,6 +12,7 @@ public interface IBuildTimes { IEnumerable SolutionMonthTable(); + // these are only used in testing, but I can't think of a good way to take them out of the interface and keep the rest of the code ok. TimeSpan Total { get; } IEnumerable AvailableMonths { get; } IEnumerable AvailableSolutions { get; } diff --git a/BuildMonitorPackage/AnalyseBuildTimes.xaml b/BuildMonitorPackage/AnalyseBuildTimes.xaml index 86ecc4d..712c8e3 100644 --- a/BuildMonitorPackage/AnalyseBuildTimes.xaml +++ b/BuildMonitorPackage/AnalyseBuildTimes.xaml @@ -5,6 +5,10 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:BuildMonitorPackage" mc:Ignorable="d" - Title="AnalyseBuildTimes" Height="300" Width="300"> - + Title="AnalyseBuildTimes" Height="500" Width="756"> + +