{"id":2919,"date":"2019-09-14T12:16:06","date_gmt":"2019-09-14T00:16:06","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2919"},"modified":"2019-09-22T10:00:03","modified_gmt":"2019-09-21T22:00:03","slug":"azure-devops-now-you-too-can-use-my-templates","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2919\/","title":{"rendered":"Azure DevOps &#8211; Now You Too Can Use My Template(s)"},"content":{"rendered":"<span class=\"span-reading-time 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 class=\"wp-block-paragraph\">I&#8217;ve continued to enhance and refine my Delphi build template for Azure DevOps pipelines and am now hosting that in a new repository I&#8217;ve created on GitHub.  This means that anyone can now use this template in their own build pipelines.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s how.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">In <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2878\">the previous post on this subject<\/a>, the template I created was in the same repo as the build pipeline that consumed it.  This made it very simple to re-use within that repo, but things get a bit more complicated when sharing between\/across repos.  In particular, templates in <em>Azure<\/em> repos can only be shared with other repos <em>within the same <\/em><strong><em>Organization<\/em><\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">e.g. a build pipeline for a project in the <strong>ACME Organization<\/strong> may reference templates held in any other repo for any project <em>also in the <\/em><strong><em>ACME Organization<\/em><\/strong>.  But repos in projects that are part of the <strong><em>Spectre Organization<\/em><\/strong> cannot reference any of those <strong>ACME Organization<\/strong> templates.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Clear ?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In essence, it allows organizations to share templates among their own projects but not with other organizations.  Sharing templates privately in this way is of course a perfectly valid use case, but this doesn&#8217;t work for templates intended to be shared with a broader community. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Fortunately, Azure DevOps pipelines also support referencing templates hosted on repositories other than Azure DevOps itself.  The only slight catch is that this only works if those repos are on GitHub (also <a href=\"https:\/\/blogs.microsoft.com\/blog\/2018\/10\/26\/microsoft-completes-github-acquisition\/\">now Microsoft owned<\/a>, in case you missed <a href=\"https:\/\/blogs.microsoft.com\/blog\/2018\/10\/26\/microsoft-completes-github-acquisition\/\">that piece of news<\/a>).<\/p>\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">To do this, the first thing you need to do this is create a <strong>Service Connection<\/strong> in your Azure Project.  This will be used to authenticate any requests to obtain templates held in GitHub repos.  This is done in Project Settings, in the Service Connections area:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"428\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.24.54.png?resize=640%2C428&#038;ssl=1\" alt=\"\" class=\"wp-image-2920\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.24.54.png?resize=1024%2C684&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.24.54.png?resize=300%2C200&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.24.54.png?resize=768%2C513&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.24.54.png?resize=380%2C254&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.24.54.png?w=1183&amp;ssl=1 1183w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>GitHub<\/strong> is a specific service connection type recognised and supported by Azure DevOps.  When configuring the connection you need to specify a name and the authentication type.  I set mine up using a <strong>PAT<\/strong> (Personal Access Token).  The name is used in consuming pipelines so you&#8217;ll want to keep it short-ish, meaningful and memorable.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\">If you reference a template that in turn references other GitHub hosted templates then you may need additional Service Connections with names that satisfy the endpoints configured in those references.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To create the PAT itself you need to go to GitHub.  PAT&#8217;s are created and managed in the <strong>Developer Settings<\/strong> area of your GitHub profile:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"226\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?resize=640%2C226&#038;ssl=1\" alt=\"\" class=\"wp-image-2921\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?resize=1024%2C362&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?resize=300%2C106&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?resize=768%2C272&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?resize=380%2C134&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?w=1351&amp;ssl=1 1351w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-14-at-09.30.30.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Now we can create a build pipeline that references my GitHub repo.  Here&#8217;s an example:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">trigger:\n- develop\n- master\n\nresources:\n  repositories:\n    - repository: templates\n      type: github\n      name: deltics\/azure-pipeline-templates\n      endpoint: GitHubTemplates\n\npool:\n  name: &#039;The Den&#039;\n\nsteps:\n- template: delphi-build.yml@templates\n  parameters:\n    delphiVersion: 7\n    project: tests\\Tests\n    preBuildInline: duget restore --updateCfg\n    postBuildInline: .bin\\Tests -f=.results\\TestResults.xml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The most significant addition here compared to the earlier pipeline is the addition of the <code class=\"\" data-line=\"\">resources:<\/code> section.  This is where we identify any resource this pipeline needs.  A GitHub repo is one of those and needs to be added in a <code class=\"\" data-line=\"\">repositories:<\/code> section of the <strong>resources<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now, some of the names for the properties of a GitHub repository resource can be a little confusing, so bear with me&#8230;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code class=\"\" data-line=\"\">repository:<\/code> has a value which is the name by which this resource is referenced elsewhere in the pipeline.  In this case <strong>templates<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We then identify the type of repository, which is <strong>github<\/strong>.  For an Azure repo we would use <strong>git<\/strong>.  <em>(It seems to me that <\/em><strong><em>azure<\/em><\/strong><em> or <\/em><strong><em>azuregit<\/em><\/strong><em> would have been a better choice here, but Microsoft clearly don&#8217;t agree &#8211; Ed)<\/em>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code class=\"\" data-line=\"\">name:<\/code> for the repository identifies the GitHub repository itself, in the form <code class=\"\" data-line=\"\">&lt;account&gt;\/&lt;repo&gt;<\/code>.  My GitHub account is <strong>deltics<\/strong> and the repo I created to host my template(s) is <strong>azure-pipeline-templates<\/strong>.  Hence the &#8216;name&#8217; for this repository is <code class=\"\" data-line=\"\">deltics\/azure-pipeline-templates<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, the <code class=\"\" data-line=\"\">endpoint:<\/code> property identifies the <strong>Service Connection<\/strong> used to communicate with the GitHub repo.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\">There is an additional optional property which may be set including a <code class=\"\" data-line=\"\">ref:<\/code> property which can be used to &#8216;pin&#8217; the referenced template to a specific tagged version.  By default if no <code class=\"\" data-line=\"\">ref:<\/code> is specified, <code class=\"\" data-line=\"\">master\/HEAD<\/code> will be used (i.e. latest version). <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All of these properties, as well as other resource types, are explained further in <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/yaml-schema?view=azure-devops&amp;tabs=schema#repository-resource\">the Microsoft documentation<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The build step that consumes the template is also changed slightly from <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2878\">before<\/a>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">steps:\n- template: delphi-build.yml@templates\n  parameters:\n    delphiVersion: 7\n    project: tests\\Tests\n    preBuildInline: duget restore --updateCfg\n    postBuildInline: .bin\\Tests -f=.results\\TestResults.xml<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The template reference which previously simply referenced a path within the same repo, now identifies a file (<code class=\"\" data-line=\"\">delphi-build.yml<\/code>) within a named resource (<code class=\"\" data-line=\"\">@templates<\/code>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Everything else is just as before although much simplified in this case as a result of that <code class=\"\" data-line=\"\">preBuildInline:<\/code> property.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code class=\"\" data-line=\"\">preBuildInline<\/code> and <code class=\"\" data-line=\"\">postBuildInline<\/code> are some additional properties that I&#8217;ve added to my template.  These allow me to specify some Powershell script to be executed immediately <em>before<\/em> and immediately <em>after<\/em> the invocation of the compiler.  <code class=\"\" data-line=\"\">postBuildInline<\/code> will only be executed if the build is successful.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code class=\"\" data-line=\"\">postBuild<\/code> still exists and functions as before, running as a separate step after the successful completion of the build step.  I&#8217;ve also added <code class=\"\" data-line=\"\">preBuild<\/code> which is also a separate step which executes before the build step.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\">The key distinction between these <code class=\"\" data-line=\"\">Inline<\/code> parameters and the non-inline versions is that the inline parameters must be Powershell statements where-as the non-inline parameters are YAML steps which could be any valid build pipeline step, Powershell or otherwise. <\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">The overall build in this case is greatly simplified by the <code class=\"\" data-line=\"\">preBuildInline<\/code> command.  Where-as before I had a cumbersome step which manually constructed a search path and passed that in via parameters to the template, all of that work is replaced by a single command in the <code class=\"\" data-line=\"\">preBuildInline<\/code> script.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code class=\"\" data-line=\"\">duget restore<\/code> command constructs the required paths and the <code class=\"\" data-line=\"\">--updateCfg<\/code> switch additionally instructs the command to add those paths to any <code class=\"\" data-line=\"\">dcc32.cfg<\/code> or <code class=\"\" data-line=\"\">dcc64.cfg<\/code> that it may find.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\">This is why this command must be performed as an <code class=\"\" data-line=\"\">Inline<\/code> script.  It is only at the point, immediately before the compiler is invoked, that the build has created the initial dcc32\/dcc64 config file that this command can then update.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <code class=\"\" data-line=\"\">duget<\/code> command is an <strong>exe<\/strong> pre-installed on the build machine.  It doesn&#8217;t just work out the required paths, it also ensures that any dependencies that my project has are available for compilation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As I <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2878\">teased last time<\/a>, if you&#8217;re at all familiar with <strong><a href=\"https:\/\/www.nuget.org\/\">nuget<\/a><\/strong> then you already have a good idea of what <strong>duget<\/strong> is all about.  This is what I am busy working on right now and will talk more about where this project is at in future posts.<\/p>\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">For now however, the build template itself is available for use by anyone so inclined.  It doesn&#8217;t rely on or make direct use of <strong>duget<\/strong>.  Just follow the above steps to reference my GitHub repo, pull this template into your pipelines and you&#8217;re good to go.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Don&#8217;t forget, you will of course need <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2659\">a build agent connected to DevOps<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let me know how you get on using the template or, better yet, contribute to the template yourself!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Of particular interest would be testing for and supporting builds for FMX and non-Windows platforms.  These are not areas that I use Delphi for myself so wouldn&#8217;t be confident in tackling those aspects of the template.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enjoy! \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time 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>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&#8230;<\/p>\n","protected":false},"author":2,"featured_media":2922,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"Azure DevOps - Now You Too Can Use My Template(s).  This post also includes a sneak-peek at something I'm currently working which I'm very excited about!","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[324,322,323,4,321],"tags":[326,251,292,337,328],"class_list":["post-2919","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-automation","category-azure-devops","category-ci-cd","category-delphi","category-devops","tag-azure-devops","tag-build-automation","tag-delphi","tag-github","tag-pipelines"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/github-512.png?fit=512%2C512&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-L5","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2919","targetHints":{"allow":["GET"]}}],"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=2919"}],"version-history":[{"count":7,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2919\/revisions"}],"predecessor-version":[{"id":2930,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2919\/revisions\/2930"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/2922"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2919"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2919"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2919"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}