{"id":2968,"date":"2019-09-23T10:19:28","date_gmt":"2019-09-22T22:19:28","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2968"},"modified":"2019-09-23T10:19:37","modified_gmt":"2019-09-22T22:19:37","slug":"azure-devops-github-github","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2968\/","title":{"rendered":"Azure DevOps + GitHub = GitHub++"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>\n<p><a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\">In my post yesterday I talked about how <\/a><strong><a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\">Azure DevOps<\/a><\/strong><a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\"> and <\/a><strong><a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\">GitHub<\/a><\/strong><a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\"> needn&#8217;t be an either\/or decision<\/a>.  This was based on little more than having explored how to make the two work together.  Today I&#8217;ve spent a whole day working with the two and have a couple more concrete things to say about the experience.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"has-drop-cap\">First, it really is as simple to connect the two systems together as I think it is possible for it to be.  Once you have authenticated <strong>GitHub<\/strong> to <strong>Azure DevOps<\/strong>, you are good to go and the level of integration is both deep and subtle.<\/p>\n\n\n\n<p>One of the first things I noticed was a new check mark against each commit in my <strong>GitHub<\/strong> repository commit history&#8230;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" loading=\"lazy\" width=\"640\" height=\"694\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.46.21.png?resize=640%2C694&#038;ssl=1\" alt=\"\" class=\"wp-image-2969\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.46.21.png?resize=945%2C1024&amp;ssl=1 945w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.46.21.png?resize=277%2C300&amp;ssl=1 277w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.46.21.png?resize=768%2C833&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.46.21.png?resize=240%2C260&amp;ssl=1 240w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.46.21.png?w=976&amp;ssl=1 976w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>At first I wasn&#8217;t sure what this was until I realised the correlation between those check-marks and the state of my <strong>Azure DevOps<\/strong> build following each commit and push.<\/p>\n\n\n\n<p>Not only is <strong>Azure DevOps<\/strong> aware of the commit and triggering the build, but it then calls back to <strong>GitHub<\/strong> to let it know the outcome of that build.  Bear in mind that my build pipeline includes running tests so a &#8220;bad build&#8221; may not necessarily be a broken build in the sense of &#8220;does not compile&#8221; but may be that I&#8217;ve broken some tests.<\/p>\n\n\n\n<p>The next thing I learned was that the <strong>Pull Request<\/strong> workflow in <strong>GitHub<\/strong> had some strange consequences for <strong>Azure DevOps<\/strong> build pipelines.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-drop-cap\">You may remember that I am using <strong>GitVersion<\/strong> to automatically derive a <a href=\"https:\/\/semver.org\/\">Semantic Version<\/a> for my builds (and, consequently, releases).  This was working smoothly for my Azure hosted repos and pipelines.  Builds triggered on my <strong>develop<\/strong> branch were tagged with a <strong>beta<\/strong> pre-release tag and an incrementing build number (actually, a commit count).  Then when I completed a pull request to <strong>master<\/strong>, my <strong>master<\/strong> build would be given the corresponding release version:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">         (develop) -> 1.0.0-beta.1\n       [2 commits]\n         (develop) -> 1.0.0-beta.3\n       [5 commits]\n         (develop) -> 1.0.0-beta.8\n    [PR to master]\n          (master) -> 1.0.0<\/pre>\n\n\n\n<p>But with the repo hosted in <strong>GitHub<\/strong> and starting a PR from there, suddenly I started seeing a new build being triggered which was being tagged with a <strong>PullRequest<\/strong> label:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">         (develop) -> 1.0.0-beta.1\n         (develop) -> 1.0.0-beta.3\n         (develop) -> 1.0.0-beta.8\n               (2) -> 1.0.0-PullRequest.2<\/pre>\n\n\n\n<p>More perplexing still, the branch that this build (let&#8217;s call it the &#8220;<em>PR build<\/em>&#8220;) claimed to have been triggered on was not the <strong>master<\/strong> branch, nor <strong>develop<\/strong>, but simply &#8220;N&#8221;, where &#8220;N&#8221; seemed to correspond to the PR number in the repo (i.e. 1, 2, 3 etc).<\/p>\n\n\n\n<p>Worse, since my PR&#8217;s were essentially nominal &#8211; assigned to me, reviewed by me and confirmed by me &#8211; they were quickly followed by the merge to<strong> master<\/strong> when the PR was completed.  The build on the <strong>master<\/strong> branch that this triggered (let&#8217;s call this the &#8220;<em>merge build<\/em>&#8220;) for some reason was not queued behind the PR build but <em>ran in parallel<\/em> and was failing as a result.<\/p>\n\n\n\n<p class=\"has-background has-light-green-cyan-background-color\">Overnight it dawned on me that the explanation for this is that I have two build machines in my pool.  On the free pricing tier of Azure DevOps only one parallel job is allowed, but I can have as many build agents as I like. The second job was being sent to my second build machine, but this was not setup for Delphi builds or GitVersion.  I had forgotten to include the <code>Delphi<\/code> <code>demand<\/code> to my build pipeline which would have stopped this from happening.  Of course, if I also set that second machine up for Delphi builds as well it will double my build throughput capacity!  [<em>Yes, do <strong>that<\/strong>! &#8211; Ed<\/em>]<\/p>\n\n\n\n<p class=\"has-drop-cap\">The <a href=\"https:\/\/gitversion.readthedocs.io\/en\/v3.6.5\/configuration\/\">default <\/a><strong><a href=\"https:\/\/gitversion.readthedocs.io\/en\/v3.6.5\/configuration\/\">GitVersion<\/a><\/strong><a href=\"https:\/\/gitversion.readthedocs.io\/en\/v3.6.5\/configuration\/\"> configuration<\/a> is setup to add that <strong>PullRequest<\/strong> pre-release tag to PR builds, so that explained where the that was coming from.  Fixing this was not my priority.  My concern was to stop those PR builds in the first place!  Or rather, to have them occur at an appropriate time.  With the <strong>GitHub<\/strong> workflow, commits occurring as part of a PR are applied on the source branch which in my case was <strong>develop<\/strong> and this branch was <em>already<\/em> setup to trigger builds on any commit.<\/p>\n\n\n\n<p>After a bit more digging through the documentation I discovered that when connecting to <strong>GitHub<\/strong> (or other external repos) <strong>Azure DevOps<\/strong> pipelines have <em><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/build\/triggers?view=azure-devops&amp;tabs=yaml#pr-triggers\">another<\/a><\/em><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/build\/triggers?view=azure-devops&amp;tabs=yaml#pr-triggers\"> trigger mechanism, specific to PR&#8217;s<\/a>.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color\">This is one issue I have with configuration as code.  It&#8217;s great when you <em>know<\/em> all the things that can be configured in that plain ol&#8217; text file in front of you, but there&#8217;s nothing there to help you identify what <em>can be<\/em> configured, other than documentation.  This places you at the mercy of the documentation authors (often not the same people creating the software itself).  If they are not great at making the product discoverable through the documentation then you haven&#8217;t got a hope or a prayer!  Surely this is at least one reason that the GUI was invented in the first place ?  To help guide and assist users through the business of getting value from software.  But I digress.<\/p>\n\n\n\n<p>Back to my build pipeline PR triggers.  By default (i.e. if not otherwise specified) these are configured to trigger on <em>every<\/em> PR commit.  So all I needed to do was change this (i.e. introduce some additional configuration) to only trigger on the branches that I expected to use for PR&#8217;s.  Fortunately this was simple enough and simply required me to add a new section to my build pipeline, to supplement the existing triggers:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\">trigger:\n- develop*\n- feature*\n- master\n\npr:\n  branches:\n    include:\n      - develop*\n      - feature*<\/code><\/pre>\n\n\n\n<p>This ensures that my builds are now only triggered by PR commits on <strong>develop<\/strong> and <strong>feature<\/strong> branches.  The existing CI triggers take care of direct commits to all branches and merges to <strong>master<\/strong>.<\/p>\n\n\n\n<p>Following that diversion I then started to notice another aspect of the integration between the two systems as it related to the PR workflow.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-drop-cap\">When creating a new PR in <strong>GitHub<\/strong>, part of the PR UI provides information on &#8220;checks&#8221; that are performed to validate the PR.  Up to this point in <strong>GitHub<\/strong> those checks in my case had been confined to ensuring that the branches involved in the PR could be successfully merged and had no conflicts (with a conflict resolution UX if there were).<\/p>\n\n\n\n<p>A new check now was appearing however:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" loading=\"lazy\" width=\"640\" height=\"257\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?resize=640%2C257&#038;ssl=1\" alt=\"\" class=\"wp-image-2971\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?resize=1024%2C411&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?resize=300%2C120&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?resize=768%2C308&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?resize=380%2C152&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?w=1550&amp;ssl=1 1550w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-22-at-18.39.27.png?w=1280&amp;ssl=1 1280w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/figure>\n\n\n\n<p>The icon was the first clue as to what this was&#8230; the <strong>GitHub<\/strong> PR process had triggered a build and was now awaiting its outcome!  Not only are build outcomes for each commit communicated between Azure DevOps and GitHub, but GitHub even knows when those builds are happening!<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color\">Incidentally, you don&#8217;t have to wait for the builds to complete nor does this check even have to pass for you to proceed with the PR, if you wish.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>I am sure I will discover more integrations between <strong>Azure DevOps<\/strong> and <strong>GitHub<\/strong> as I continue my journey with these two.<\/p>\n\n\n\n<p>Do you use <strong>GitHub<\/strong> ?  Do you use it in conjunction with <strong>Azure DevOps<\/strong> ?  What do you like about these two services, separately or combined ?<\/p>\n\n\n\n<p>Let me know in the comments.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">5<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> A look at some of the integrations that &#8220;just work&#8221; when you combine Azure DevOps and GitHub<\/p>\n","protected":false},"author":2,"featured_media":2973,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[324,322,323,321,341],"tags":[342,326,327,329,337,343],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/azure-devopsgithub.png?fit=1024%2C341&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-LS","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2950,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\/","url_meta":{"origin":2968,"position":0},"title":"Azure DevOps &#8211; Great, But I Use GitHub!","date":"22 Sep 2019","format":false,"excerpt":"If you were thinking that Azure DevOps has nothing to offer if your code is in github, think again!","rel":"","context":"In &quot;Azure DevOps&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/github-512.png?fit=512%2C512&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2919,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2919\/","url_meta":{"origin":2968,"position":1},"title":"Azure DevOps &#8211; Now You Too Can Use My Template(s)","date":"14 Sep 2019","format":false,"excerpt":"Learn how you too can use my Delphi build template in your own Azure DevOps pipelines, and a sneak preview of something special coming soon...","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/github-512.png?fit=512%2C512&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2936,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2936\/","url_meta":{"origin":2968,"position":2},"title":"Azure DevOps &#8211; Iterative Insertion Fixed!","date":"19 Sep 2019","format":false,"excerpt":"I figured out the iterative insertion problem and my build pipeline is now TIGHT! Fixing it was super-easy in fact, barely an inconvenience.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/pipelines-hero-code-1024x256.jpg?fit=1024%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2659,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2659\/","url_meta":{"origin":2968,"position":3},"title":"Azure DevOps and Delphi &#8211; Build Agents","date":"06 Sep 2019","format":false,"excerpt":"The first in a series of posts exploring build and test automation for Delphi projects using Azure DevOps.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/pipelines-hero-1-1024x256.jpg?fit=1024%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2861,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2861\/","url_meta":{"origin":2968,"position":4},"title":"Azure DevOps &#8211; Building Some Code","date":"09 Sep 2019","format":false,"excerpt":"In this post we create a (very!) simple project, build it using Delphi (7) and run it. All with Azure DevOps.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/pipelines-hero-code-1024x256.jpg?fit=1024%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2878,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2878\/","url_meta":{"origin":2968,"position":5},"title":"Azure DevOps &#8211; Template for Builds + Running Tests and Capturing Results","date":"12 Sep 2019","format":false,"excerpt":"A more complete build script, re-usable in the form of a template, that caters for different Delphi versions, combined with a demonstration of running unit tests and capturing results for reporting and analysis in Azure DevOps Pipelines.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-12-at-14.25.20.jpg?fit=386%2C386&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2968"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2968"}],"version-history":[{"count":3,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2968\/revisions"}],"predecessor-version":[{"id":2974,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2968\/revisions\/2974"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/2973"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2968"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2968"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2968"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}