{"id":2659,"date":"2019-09-06T15:15:07","date_gmt":"2019-09-06T03:15:07","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2659"},"modified":"2019-09-06T15:36:53","modified_gmt":"2019-09-06T03:36:53","slug":"azure-devops-and-delphi-build-agents","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2659\/","title":{"rendered":"Azure DevOps and Delphi &#8211; Build Agents"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span><p>I recently returned to Delphi for the first time in years, to work on a project that I&#8217;ve had at the back of my mind for a long time and whose time I thought had come. Before I get into that though, I decided to bring the old and new together for this project, using Azure DevOps to host the code and provide build and test automation.<\/p>\n<p><!--more--><\/p>\n<p>In Azure DevOps you can run your build processes on Microsoft hosted servers.&nbsp; This is very convenient but comes with some drawbacks not least of which is that those hosted build servers only support the build tools that Microsoft feel worth making available.<\/p>\n<p>Delphi isn&#8217;t one of them (at least not at time of writing).<\/p>\n<p>Fortunately you can connect your own build machine to the Azure DevOps infrastructure very simply by installing an incredibly simple piece of software on it called an &#8220;Agent&#8221;.<\/p>\n<p><strong>Note:<\/strong> <em>Azure DevOps also supports using containers for builds which could conceivably have been used but was not the object of this exercise.&nbsp; If you&#8217;re interested in that approach, <a href=\"https:\/\/medium.com\/@brentrobinson5\/containerised-ci-cd-pipelines-with-azure-devops-74064c679f20\">this article may be of interest<\/a>.<\/em><\/p>\n<p>On a self-hosted build machine, the agent serves two purposes:<\/p>\n<ol>\n<li>First, it identifies your build machine capabilities to Azure DevOps.&nbsp; This enables Azure DevOps to send your machine only those build tasks that your build machine is capable of.&nbsp; If you don&#8217;t have an Android SDK installed then you won&#8217;t be sent Android builds, for example.<\/li>\n<li>Second it polls for build tasks that it can run for you, executes those tasks and communicates the results (and potentially resulting artefacts) back to the Azure DevOps service.<\/li>\n<\/ol>\n<p>For the first part, there are capabilities that are defined by Azure DevOps to identify things such as MSBuild or Visual Studio, Java and Android SDK&#8217;s, Xcode (your build machine may be a Mac) etc etc.<\/p>\n<p>These capabilities are identified automatically when you configure the agent software on your build machine by scanning for known software on the machine.&nbsp; In addition you can define your own capabilities, things that the agent does not know to look for itself.&nbsp; Delphi falls into that camp.<\/p>\n<p>But we&#8217;ll get into that later.&nbsp; Let&#8217;s get started.<\/p>\n<p>First, I&#8217;m assuming you already have an Azure DevOps account (its free!) but if you don&#8217;t <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/user-guide\/sign-up-invite-teammates?view=azure-devops\">go ahead and sign up now<\/a>.&nbsp; I&#8217;ll wait here&#8230;<\/p>\n<p>Back?&nbsp; Cool.&nbsp; \ud83d\ude42<\/p>\n<h3>Enrolling a New Agent<\/h3>\n<p>On your Azure DevOps organization landing page, go to <strong>Organization Settings<\/strong>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2664\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-13.58.45.png?resize=640%2C328&#038;ssl=1\" alt=\"\" width=\"640\" height=\"328\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-13.58.45.png?w=1175&amp;ssl=1 1175w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-13.58.45.png?resize=300%2C154&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-13.58.45.png?resize=768%2C393&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-13.58.45.png?resize=1024%2C525&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-13.58.45.png?resize=380%2C195&amp;ssl=1 380w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/p>\n<p>Then navigate to the <strong>Agent Pools<\/strong> settings in the <strong>Pipelines<\/strong> section.&nbsp; Here you will see a pool already exists for builds to run on the hosted infrastructure (the <strong>Azure Pipelines<\/strong> pool).<\/p>\n<p>Add a new pool using the <strong>Add Pool<\/strong> button (top right) and name it however you wish.&nbsp; I have two build machines that I&#8217;m using in my <em>den<\/em> at home, so I added a pool called <strong>The Den<\/strong>:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-2665 size-full\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.02.47.png?resize=640%2C500&#038;ssl=1\" alt=\"\" width=\"640\" height=\"500\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.02.47.png?w=1227&amp;ssl=1 1227w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.02.47.png?resize=300%2C234&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.02.47.png?resize=768%2C600&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.02.47.png?resize=1024%2C800&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.02.47.png?resize=333%2C260&amp;ssl=1 333w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/p>\n<p>With the pool created, you can now select that pool to see all the agents in that pool.&nbsp; The default view actually shows the history of jobs run on those agents, but since there are no agents there are no jobs either.<\/p>\n<p>Either way, we use the <strong>New Agent<\/strong> button to add a new agent.<\/p>\n<p>Actually, we don&#8217;t.<\/p>\n<p>When you select <strong>New Agent<\/strong> what you actually get is a dialog with a link to download the agent software for the detected browser OS &#8211; you can change this if (e.g. like me) you&#8217;re using a Mac but intending to setup a Windows build machine:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2680\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.28.34.png?resize=640%2C674&#038;ssl=1\" alt=\"\" width=\"640\" height=\"674\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.28.34.png?w=789&amp;ssl=1 789w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.28.34.png?resize=285%2C300&amp;ssl=1 285w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.28.34.png?resize=768%2C809&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.28.34.png?resize=247%2C260&amp;ssl=1 247w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/p>\n<p>Everything you need to get your agent up and running is in this one dialog and the links it provides.&nbsp; It really is straightforward.&nbsp; The most important step is creating the PAT (Personal Access Token) which is used to configure the agent and needs the scope <strong>Agent Pools (Read &amp; Manage)<\/strong>.<\/p>\n<p>This is only used when setting up the agent so you don&#8217;t need to worry about keeping it around afterward.&nbsp; You also need a PAT when removing an agent, but it doesn&#8217;t need to be the same PAT used to configure the agent; you can create these PAT&#8217;s and revoke them when you&#8217;re done with them instead of worrying about how to manage them.<\/p>\n<p>When the agent is configured you will be asked for the pool the agent should be part of, a name for the agent (which will default to the system\/host name) and whether you want to run it as a service (<strong>Yes<\/strong> is a good answer if you want your build machine to auto-connect to the pool after a restart, for example).&nbsp; You will also need to identify an account for the agent to run under, though a default is provided if you don&#8217;t want to have to think too much).<\/p>\n<p>Finally, you will need to specify a folder where work files are downloaded and acted upon by the tasks sent to your agent.<\/p>\n<p>Oh, and all of this has to be done in an elevated command prompt.<\/p>\n<p>Once all of this has been done and assuming everything has gone smoothly, your agent will now be registered with your pool:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2681\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.44.52.png?resize=640%2C174&#038;ssl=1\" alt=\"\" width=\"640\" height=\"174\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.44.52.png?w=1226&amp;ssl=1 1226w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.44.52.png?resize=300%2C82&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.44.52.png?resize=768%2C209&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.44.52.png?resize=1024%2C279&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.44.52.png?resize=380%2C104&amp;ssl=1 380w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/p>\n<p>As you can see, my build machine is an Intel NUC, unimaginatively named <strong>NUC<\/strong>.&nbsp; And we can see that everything so far is working as Azure DevOps is both aware of the machine (so the machine can talk to the service &#8211; it has to, to have been able to register) and Azure DevOps has determined that the machine is online (so the agent service on the machine is contactable).<\/p>\n<p>Great, but so far this machine isn&#8217;t capable of very much.&nbsp; Well, actually it is.<\/p>\n<p>I already had <strong>Visual Studio 2017<\/strong> installed on this machine along with <strong>JDK<\/strong> and the <strong>Android SDK<\/strong>.&nbsp; All of this, along with a bunch of other things were detected by the auto-scan performed by the agent config which we can see by selecting the agent and then browsing the detected capabilities.<\/p>\n<p>There are way too many capabilities to show here, but I&#8217;ve highlighted some of the more interesting ones.<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.50.27.png?ssl=1\"><img decoding=\"async\" loading=\"lazy\" class=\"alignleft wp-image-2682 size-thumbnail\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.50.27.png?resize=150%2C150&#038;ssl=1\" alt=\"\" width=\"150\" height=\"150\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.50.27.png?resize=150%2C150&amp;ssl=1 150w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.50.27.png?zoom=2&amp;resize=150%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.50.27.png?zoom=3&amp;resize=150%2C150&amp;ssl=1 450w\" sizes=\"(max-width: 150px) 100vw, 150px\" data-recalc-dims=\"1\" \/><\/a>You can click to view the larger image if you&#8217;re interested.&nbsp; A key thing to note with these capabilities is that they are not just a yes\/no indicator but have a value associated with them which could be useful to any task which relies on these capabilities.<\/p>\n<p>For example, the <strong>JAVA<\/strong> capability not only identifies that the Java Runtime is present on the machine, but also identifies the <em>path<\/em> to the installed runtime.&nbsp; Similarly all of the different .NET framework version paths are identified along with each version as a distinct capability.<\/p>\n<p>But no Delphi.<\/p>\n<p>I can assure you that Delphi is on this machine however.&nbsp; In fact, every version from Delphi 7 thru XE4 (except 2005 and 2006).&nbsp; All of these versions are present in a folder <strong>c:\\dcc<\/strong> on the machine:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter wp-image-2684 size-full\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.59.51.png?resize=640%2C461&#038;ssl=1\" alt=\"\" width=\"640\" height=\"461\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.59.51.png?w=742&amp;ssl=1 742w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.59.51.png?resize=300%2C216&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-14.59.51.png?resize=361%2C260&amp;ssl=1 361w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/p>\n<p>These are not full installs but just enough needed to run command line compiles.&nbsp; That is, the <strong>bin<\/strong> and <strong>lib<\/strong> folders, donated from my Delphi development VM where I do have these versions fully installed.<\/p>\n<p>So I&#8217;m going to add some user defined capabilities to my agent, to identify these locations and the presence of Delphi on this machine:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-2685\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-15.07.01.png?resize=640%2C498&#038;ssl=1\" alt=\"\" width=\"640\" height=\"498\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-15.07.01.png?w=985&amp;ssl=1 985w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-15.07.01.png?resize=300%2C234&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-15.07.01.png?resize=768%2C598&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-06-at-15.07.01.png?resize=334%2C260&amp;ssl=1 334w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/p>\n<p>It doesn&#8217;t matter what I call these capabilities (as long as they aren&#8217;t confused with any system defined capabilities).&nbsp; Nor does it matter what value I give them.&nbsp; At least not yet.<\/p>\n<p>It <em>will<\/em> matter when we come to make use of these capabilities later, but for now these are having no effect what-so-ever.&nbsp; Azure DevOps could care less about these capabilities &#8211; it still has no idea what to do with them.&nbsp; That&#8217;s up to us.<\/p>\n<h3>Testing The Agent<\/h3>\n<p>To test the agent we will need some code to build and something to tell the agent how to build it.<\/p>\n<p>We&#8217;ll do that in the next post.<\/p>\n\n\n<p><\/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\">6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> The first in a series of posts exploring build and test automation for Delphi projects using Azure DevOps.<\/p>\n","protected":false},"author":2,"featured_media":2689,"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":false,"jetpack_social_options":[]},"categories":[324,322,323,4,321],"tags":[325,326,251,327,292,328],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/pipelines-hero-1-1024x256.jpg?fit=1024%2C256&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-GT","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2861,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2861\/","url_meta":{"origin":2659,"position":0},"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":2919,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2919\/","url_meta":{"origin":2659,"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":2968,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2968\/","url_meta":{"origin":2659,"position":2},"title":"Azure DevOps + GitHub = GitHub++","date":"23 Sep 2019","format":false,"excerpt":"A look at some of the integrations that \"just work\" when you combine Azure DevOps and GitHub","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/azure-devopsgithub.png?fit=1024%2C341&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2936,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2936\/","url_meta":{"origin":2659,"position":3},"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":2878,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2878\/","url_meta":{"origin":2659,"position":4},"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":[]},{"id":2950,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2950\/","url_meta":{"origin":2659,"position":5},"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":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2659"}],"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=2659"}],"version-history":[{"count":10,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2659\/revisions"}],"predecessor-version":[{"id":2690,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2659\/revisions\/2690"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/2689"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2659"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}