{"id":192,"date":"2010-06-21T01:10:14","date_gmt":"2010-06-21T07:10:14","guid":{"rendered":"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/2010\/06\/21\/extreme-ci-part-3-the-visual-studio-macro\/"},"modified":"2010-07-07T07:25:46","modified_gmt":"2010-07-07T13:25:46","slug":"extreme-ci-part-3-the-visual-studio-macro","status":"publish","type":"post","link":"http:\/\/architester.com\/blog\/2010\/06\/21\/extreme-ci-part-3-the-visual-studio-macro\/","title":{"rendered":"Extreme CI Part 3: The Visual Studio Macro."},"content":{"rendered":"<p><em>How I run a personal CI build every time I build my code in Visual Studio.<\/em><\/p>\n<h2>Summary<\/h2>\n<p>This week we\u00e2\u20ac\u2122ll finish the series by creating the Visual Studio macro that automatically runs the Personal CI process every time we build the code.<\/p>\n<h3>The Series<\/h3>\n<p>In this series I show you how to take continuous integration to the extreme by building a personal CI server that runs all your tests and adds a commit to source control every time you build in Visual Studio.<\/p>\n<ul>\n<li><a title=\"Extreme CI Part 1\" href=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/2010\/06\/13\/extreme-continuous-integration-a-personal-ci-build-for-visual-studio-part-1\/\" target=\"_self\">Extreme CI Part 1 \u00e2\u20ac\u201c Overview<\/a><\/li>\n<li><a title=\"Extreme CI Part 2\" href=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/2010\/06\/20\/extreme-ci-part-2-setting-up-git-for-a-personal-ci\/\" target=\"_self\">Extreme CI Part 2 \u00e2\u20ac\u201c Setting Up Git<\/a><\/li>\n<li><strong>Extreme CI Part 3 \u00e2\u20ac\u201c The Visual Studio Macro<\/strong> <strong><em>(you are here)<\/em><\/strong><\/li>\n<\/ul>\n<h2>Setting Up the External Command in Visual Studio<\/h2>\n<p>Last week we created a batch file to commit and push our changes to the CI server. Now we need to execute that batch file from within Visual Studio. We\u00e2\u20ac\u2122ll do it using an external command. To set up the external command in Visual Studio:<\/p>\n<ol>\n<li>Select <strong>Tools \u00e2\u20ac\u201c&gt; External Tools\u00e2\u20ac\u00a6<\/strong> from within Visual Studio. <em>I am using Visual Studio 2008, for 2010, it may be a bit different. <\/em><\/li>\n<li>When the \u00e2\u20ac\u0153External Tools\u00e2\u20ac\u009d dialog shows, click \u00e2\u20ac\u0153<strong>Add<\/strong>\u00e2\u20ac\u009d and fill in the following:\n<ul>\n<li><em>Title:<\/em> Commit and Push to Personal CI<\/li>\n<li><em>Command:<\/em> $(SolutionDir)\\..\\CommitAndPushToPersonalCI.bat<\/li>\n<li><em>Initial directory:<\/em> $(SolutionDir)\\..\\<\/li>\n<li><em>Use Output window:<\/em> checked<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>When you are done, the dialog should look like this:<\/p>\n<p><a href=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image4.png\"><img loading=\"lazy\" decoding=\"async\" style=\"display: inline; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image_thumb4.png\" border=\"0\" alt=\"image\" width=\"335\" height=\"345\" \/><\/a><\/p>\n<p>Let me clarify a few things.<\/p>\n<h5>Why did we use $(SolutionDir)\\..\\?<\/h5>\n<p>The $(SolutionDir) is the directory containing the current solution, so when I am specifying $(SolutionDir)\\..\\, I am specifying the parent directory of the solution\u00e2\u20ac\u2122s directory. This is because I have the following folder structure.<\/p>\n<pre>  +-MyProject  &lt;-- Root of Git Repository\r\n    +-src      &lt;-- Solution Location\r\n    +-lib<\/pre>\n<p>I want to commit and push from the root of my repository so that anything I have added to the lib or any other folders will be commited. However, my solution is in the src folder, which is one level deeper than I want to commit from. You may need to adjust your settings based on your project structure.<\/p>\n<h5>What\u00e2\u20ac\u2122s up with the Use Output window setting?<\/h5>\n<p>Checking the \u00e2\u20ac\u0153Use Output window\u00e2\u20ac\u009d option redirects the console output of the batch file to the output window in Visual Studio.<\/p>\n<p>Ok, let\u00e2\u20ac\u2122s move on.<\/p>\n<p>Now your tools menu should contain the new command and look like this.<\/p>\n<p><a href=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image5.png\"><img loading=\"lazy\" decoding=\"async\" style=\"display: inline; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image_thumb5.png\" border=\"0\" alt=\"image\" width=\"274\" height=\"409\" \/><\/a><\/p>\n<p>And when running your custom command, its results appear in the output window.<\/p>\n<p><a href=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image6.png\"><img loading=\"lazy\" decoding=\"async\" style=\"display: inline; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image_thumb6.png\" border=\"0\" alt=\"image\" width=\"686\" height=\"280\" \/><\/a><\/p>\n<p>Now lets take the final step and create the Visual Studio macro that runs this every time we build.<\/p>\n<h2>Create the Visual Studio Macro<\/h2>\n<p>To create the macro, we need to open up the Macros IDE.<\/p>\n<p>Select <strong>Tools \u00e2\u20ac\u201c&gt; Macros \u00e2\u20ac\u201c&gt; Macros IDE\u00e2\u20ac\u00a6 <\/strong>from within Visual Studio, or press Alt+F11. The Macros IDE will launch.<\/p>\n<p><a href=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image7.png\"><img loading=\"lazy\" decoding=\"async\" style=\"display: inline; border-width: 0px;\" title=\"image\" src=\"https:\/\/www.chrisedwards.dreamhosters.com\/blog\/wp-content\/uploads\/2010\/06\/image_thumb7.png\" border=\"0\" alt=\"image\" width=\"648\" height=\"361\" \/><\/a><\/p>\n<p>Open the <em>EnvironmentEvents<\/em> module under the <em>MyMacros<\/em> project. It should look like the screenshot above. Take the following code and insert it after the automatically generated code, and before the End Module.<\/p>\n<p><a href=\"file:\/\/\/C:\/Documents%20and%20Settings\/Administrator\/Local%20Settings\/Temp\/WindowsLiveWriter-429641856\/supfiles13ECBD1\/image21.png\"><\/a><\/p>\n<pre class=\"vb\">Dim BuildWasSuccessful As Boolean\r\nDim BuildingSolution As Boolean\r\nDim RestrictToSolutionName As String\r\nDim PersonalCICommandName As String\r\n\r\nPrivate Sub BuildEvents_OnBuildBegin(ByVal Scope As EnvDTE.vsBuildScope, ByVal Action As EnvDTE.vsBuildAction) Handles BuildEvents.OnBuildBegin\r\n\r\n    'Initialize variables when the build starts.\r\n    BuildWasSuccessful = True\r\n    BuildingSolution = True\r\n\r\n    'Only commit to personal CI for the specified solution name.\r\n    RestrictToSolutionName = \"MyProject\"\r\n\r\n    'Name of the external Personal CI command.\r\n    PersonalCICommandName = \"Tools.ExternalCommand3\"\r\n\r\nEnd Sub\r\n\r\nPrivate Sub BuildEvents_OnBuildDone(ByVal Scope As EnvDTE.vsBuildScope, ByVal Action As EnvDTE.vsBuildAction) Handles BuildEvents.OnBuildDone\r\n\r\n    'Don't run it if we just did a clean, since its not a build.\r\n    If Action = vsBuildAction.vsBuildActionClean Then\r\n        BuildingSolution = False\r\n        Exit Sub\r\n    End If\r\n\r\n    'Only run autocommit if the build succeeded.\r\n    If BuildWasSuccessful And DTE.Solution.FullName.Contains(RestrictToSolutionName) Then\r\n        'Run the command to autocommit to git.\r\n        DTE.ExecuteCommand(PersonalCICommandName)\r\n    End If\r\n\r\n    BuildingSolution = False\r\n\r\nEnd Sub\r\n\r\nPrivate Sub BuildEvents_OnBuildProjConfigDone(ByVal Project As String, ByVal ProjectConfig As String, ByVal Platform As String, ByVal SolutionConfig As String, ByVal Success As Boolean) Handles BuildEvents.OnBuildProjConfigDone\r\n\r\n    If Success = False Then\r\n        'Set the build to failed.\r\n        BuildWasSuccessful = False\r\n\r\n        'The build failed...cancel any further builds.\r\n        DTE.ExecuteCommand(\"Build.Cancel\")\r\n    End If\r\n\r\n    'Only commit project level builds if we are not building the whole solution\r\n    If Success = True And BuildingSolution = False And DTE.Solution.FullName.Contains(RestrictToSolutionName) Then\r\n        'Run the command to autocommit to git.\r\n        DTE.ExecuteCommand(PersonalCICommandName)\r\n    End If\r\n\r\nEnd Sub<\/pre>\n<p>To get it to work with your project, you need to change two variables: RestrictToSolutionName and PersonalCICommandName.<\/p>\n<p><em>RestrictToSolutionName<\/em><\/p>\n<p>This value is used to restrict the personal CI process to one solution. If it executes on a solution that is not set up properly, it will fail. If you want to use this script for multiple solutions, you will need to change it. If you do, send me a copy and I\u00e2\u20ac\u2122ll update this post and give you the credit.<\/p>\n<p><em>PersonalCICommandName<\/em><\/p>\n<p>This is the name of the ExternalCommand you created in visual studio. It is tricky to get the right name because it depends upon the number of external commands you have. It does not use the name you gave it. Pity.<\/p>\n<p>The command names are in the form \u00e2\u20ac\u0153Tools.ExternalCommand<em>N<\/em>\u00e2\u20ac\u009d where <em>N<\/em> is a number. One way to determine the name is to look at your Tools menu and see what position that command is in. In the case of our example, it is the third custom tool in the tools menu, so it is \u00e2\u20ac\u0153Tools.ExternalCommand3\u00e2\u20ac\u009d. If that doesn\u00e2\u20ac\u2122t work, you can create a custom toolbar and add the external commands to it one at a time. When you view the toolbar, you will see the real name of the command and can determine which is yours.<\/p>\n<h2>One More Thing<\/h2>\n<p>Once you set those properties and save the script, try building your project. It should automatically commit the code and push it up to the CI repository.<\/p>\n<p>Now all you have to do it hook up a CI Server to it. I leave that as an exercise to you. It is beyond the scope of this article. But, you\u00e2\u20ac\u2122re a good developer. You\u00e2\u20ac\u2122ve setup a CI server before, haven\u00e2\u20ac\u2122t you?<\/p>\n<h2>Challenge<\/h2>\n<p>I pray this series has helped you tighten up your feedback loop so that when tests fail, you know\u00e2\u20ac\u00a6fast. My challenge to you is, how can we tighten it up even further? I am open to suggestions.<\/p>\n<p>-Chris<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How I run a personal CI build every time I build my code in Visual Studio. Summary This week we\u00e2\u20ac\u2122ll finish the series by creating the Visual Studio macro that automatically runs the Personal CI process every time we build the code. The Series In this series I show you how to take continuous integration [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,4,32,8,33],"tags":[79,76,82,71,83],"class_list":["post-192","post","type-post","status-publish","format-standard","hentry","category-net","category-agile","category-continuous-integration","category-testing","category-visual-studio","tag-net","tag-agile","tag-continuous-integration","tag-testing","tag-visual-studio"],"aioseo_notices":[],"_links":{"self":[{"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/posts\/192","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/comments?post=192"}],"version-history":[{"count":8,"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/posts\/192\/revisions"}],"predecessor-version":[{"id":218,"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/posts\/192\/revisions\/218"}],"wp:attachment":[{"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/media?parent=192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/categories?post=192"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/architester.com\/blog\/wp-json\/wp\/v2\/tags?post=192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}