{"id":3000,"date":"2019-10-08T12:33:11","date_gmt":"2019-10-08T00:33:11","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=3000"},"modified":"2019-10-11T09:35:51","modified_gmt":"2019-10-10T21:35:51","slug":"versioninfo-and-semantic-versioning","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/3000\/","title":{"rendered":"VersionInfo and Semantic Versioning"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">8<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>\n<p>A key step in the evolution of <strong>duget<\/strong> is an auto-update mechanism for the <strong>duget<\/strong> client itself.  Going hand-in-hand with that is a need for reliable identification of the version of the client in use and any newer versions that may be available.  In taking this step I have run into a minor problem caused by <a href=\"https:\/\/binary-studio.com\/2017\/08\/18\/software-versioning-windows-net\/\">the constraints<\/a> in place for <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/menurc\/versioninfo-resource\">VERSIONINFO<\/a> resources of Windows executables.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>For <strong>duget<\/strong> packages themselves I have adopted <a href=\"https:\/\/semver.org\/\">Semantic Versioning<\/a>, but the more traditional Windows version numbers in a <code>VERSIONINFO<\/code> resource  has a number of restrictions which make them incompatible with the <strong>Semantic Version<\/strong> scheme (as <a href=\"https:\/\/binary-studio.com\/2017\/08\/18\/software-versioning-windows-net\/\">discussed in some depth in this article<\/a>).<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color\">These constraints extend also (with some variations) to Assembly versioning and MSI installers, so this is not solely a &#8216;legacy&#8217; problem. <\/p>\n\n\n\n<p>Put simply, a <strong>VERSIONINFO<\/strong> version number is limited to an entirely numeric format with four components to the version.  There is no <em>formal<\/em> specification for what these four values represent, only different conventions, but for the purposes of this post we&#8217;ll use:<\/p>\n\n\n\n<p><code>Major.Minor.Revision.Build<\/code><\/p>\n\n\n\n<p>Each of these values is limited to a maximum value as follows:<\/p>\n\n\n\n<p><code>255.255.65534.65534<\/code><\/p>\n\n\n\n<p>Semantic Versioning by contrast supports only three numeric components, referred to as:<\/p>\n\n\n\n<p><code>Major.Minor.Patch<\/code><\/p>\n\n\n\n<p>Semantic Versioning also caters for zero or more alpha-numeric <strong>identifiers<\/strong> and a further zero or more items of <strong>build meta-data<\/strong>.<\/p>\n\n\n\n<p><code>Major.Minor.Patch-&lt;identifiers&gt;+&lt;build meta-data&gt;<\/code><\/p>\n\n\n\n<p><strong>Identifiers<\/strong> are used to identify pre-release versions and are significant in determining version precedence.  <strong>Build Meta-Data<\/strong> is entirely documentary in nature and plays no part in version precedence.<\/p>\n\n\n\n<p class=\"has-background has-light-green-cyan-background-color\">I am not currently generating or using <strong>Build Meta-Data<\/strong> at all so we won&#8217;t be mentioning that again in this post.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-drop-cap\">As <a href=\"https:\/\/www.deltics.co.nz\/blog\/?s=gitversion\">mentioned in earlier posts<\/a>, I am using <strong>GitVersion<\/strong> to automatically derive a <strong>Semantic Version<\/strong> for my packages based on a combination of a specified version in a <code>GitVersion.yml<\/code> configuration in each project combined with the branch and commit history in the repository at the time of the build.<\/p>\n\n\n\n<p>For <strong>duget<\/strong> packages this works well as the <strong>Semantic Version<\/strong> is simply recorded as meta-data in the <code>.duspec<\/code> manifest for the package, which is a simple JSON file, as well as in the filename of the package itself.<\/p>\n\n\n\n<p>When building an executable ideally the <strong>Semantic Version<\/strong> would carry forward into the <strong>VERSIONINFO<\/strong> of the <em>exe<\/em> produced by the build.  But this is where we run into a problem.<\/p>\n\n\n\n<p>A pre-release build of the <strong>duget<\/strong> <em>exe<\/em> might have a <strong>Semantic Version<\/strong> similar to:<\/p>\n\n\n\n<p><code>0.1.0-alpha.15<\/code><\/p>\n\n\n\n<p>The first three fields are no problem as we can simply use these for <code>Major.Minor.Revision<\/code>.  But there is no way to represent the alpha-numeric pre-release identifier in the numeric <code>Build<\/code> field of a <strong>VERSIONINFO<\/strong> version number.<\/p>\n\n\n\n<p>What to do ?<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Option #1: Ignore the Label ?<\/h4>\n\n\n\n<p>Could we simply ignore the <code>alpha<\/code> label in the pre-release identifier, retain only the build number (the <code>.15<\/code> part of the identifier) and use this for the <code>Build<\/code> of the <strong>VERSIONFINO<\/strong> ?  This would mean that our pre-release <strong>VERSIONINFO<\/strong> for <code>0.1.0-alpha.15<\/code>would be:<\/p>\n\n\n\n<p><code>0.1.0.15<\/code><\/p>\n\n\n\n<p>The problem with this is that once the <code>0.1.0<\/code> is released, that pre-release identifier is dropped.  For <strong>Semantic Versioning<\/strong> this is handled by the rules of precedence which state that a version with an identifier has <em>lower precedence<\/em> than the same version with <em>no<\/em> identifiers.<\/p>\n\n\n\n<p>That is, <code>0.1.0<\/code> is a <em>more current <\/em>version than <code>0.1.0-alpha.15<\/code>.  This is fine as the pre-release label clearly identifies it as such.  The <code>alpha.15<\/code> build of <code>0.1.0<\/code> is not yet the released version of <code>0.1.0<\/code>.  This makes perfect sense.<\/p>\n\n\n\n<p>But applying the same reasoning to a label-less <strong>VERSIONINFO<\/strong> equivalent leads to the clearly counter-intuitive outcome that <code>0.1.0<\/code> is a <em>more current<\/em> version than <code>0.1.0.15<\/code>!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Option #2: Subvert Expectations<\/h4>\n\n\n\n<p>This isn&#8217;t so much a second option as a way of lending legitimacy to the first (or trying to).<\/p>\n\n\n\n<p>If <code>0.1.0-beta.15<\/code> is a pre-release version then we could take the position that it is a pre-release not of <code>0.1.0<\/code> but of some later, future version as yet to be decided.  That is, the next release version might be <code>0.1.1<\/code> and so <code>0.1.0.15<\/code> is a valid <em>earlier<\/em> version, identified as a pre-release by the non-zero <code>Build<\/code> field.  All release versions would have a <code>Build<\/code> of <code>0<\/code>.  Any version with a non-zero <code>Build<\/code> number is a pre-release of some future version.<\/p>\n\n\n\n<p>This has some obvious drawbacks, not least of which is the fact that there is no way to tell from <code>0.1.0.15<\/code> alone which subsequent version it is a pre-release version of.  It might be <code>0.1.1<\/code> or <code>0.2.0<\/code> or even <code>1.0.0<\/code> etc.<\/p>\n\n\n\n<p>No, that&#8217;s not going to fly.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Option #3: Use StringFileInfo for Semantic Version<\/h4>\n\n\n\n<p>Anyone intimately familiar with the <strong>VERSIONINFO<\/strong> resource will have noticed that I have so far not mentioned the <em>FileVersion<\/em> and <em>ProductVersion<\/em> values held in the <strong>StringFileInfo<\/strong> block, maintained in addition to the <em>FILEVERSION<\/em> and <em>PRODUCTVERSION<\/em> numeric fields. <\/p>\n\n\n\n<p>These are simple string values (<em>promising!<\/em>) and <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows\/win32\/menurc\/versioninfo-resource\">the Microsoft documentation<\/a> clearly states (with an example provided of &#8220;5.00.RC2&#8221;) that both of these can hold any arbitrary string!  Unfortunately, when examining the version properties of a file in <strong>Windows Explorer<\/strong>, either the <strong>Windows Explorer<\/strong> dialog is using the <em>FILEVERSION<\/em> value in preference over the <em>FileVersion<\/em> string, or the <em>FILEVERSION<\/em> value actually ignores any non-numeric content that you try to put in this field.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color\">I really should check which it is, just to be sure, but the fact remains that what people will see when they inspect the <strong>Details<\/strong> of the file in <strong>Windows Explorer<\/strong> is not particularly helpful in this case.<\/p>\n\n\n\n<p>That is, a subtle attempt to reformat the version into a format &#8216;compatible&#8217; with the 4-dotted fields expected in a <strong>VERSIONINFO<\/strong>, e.g:<\/p>\n\n\n\n<p><code>VALUE &quot;FileVersion&quot;, &quot;0.1.0.beta-15&quot;<\/code><\/p>\n\n\n\n<p>Results in an actual <em>File Version<\/em> value of&#8230; <code>0.1.0.15<\/code> being displayed.  <\/p>\n\n\n\n<p>The good news is that the <em>ProductVersion<\/em> property <em>does<\/em> display any arbitrary string provided.<\/p>\n\n\n\n<p>This led me to the approach I eventually adopted. <\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-drop-cap\">In short, I decided that <strong>Semantic Versioning<\/strong> would be retained and maintained in the <em>ProductVersion<\/em> string but not <em>FileVersion<\/em>.  I still needed (or rather, &#8216;wanted&#8217;) a unique, incrementing version that I could use in the other version fields that would not be confusing.<\/p>\n\n\n\n<p>Remember that the &#8216;build number&#8217; derived from the <strong>GitVersion<\/strong> applies only to <em>pre-release<\/em> builds which presents two problems with using that.<\/p>\n\n\n\n<ol><li>It will reset when the <em>major<\/em>, <em>minor<\/em> or <em>patch<\/em> numbers are incremented<\/li><li>It does not get derived <em>at all<\/em> for <em>release<\/em> builds<\/li><\/ol>\n\n\n\n<p>What I wanted was a constantly increasing number that would be reliably and consistently generated regardless of the branch on which the build was being performed (be it a pre-release build or <em>master<\/em> release build).<\/p>\n\n\n\n<p>However, assuming that this value would be used in either the <code>Revision<\/code> or <code>Build<\/code> fields of the <strong>VERSIONINFO<\/strong> it also could not exceed the value 65534.<\/p>\n\n\n\n<p>I eventually settled on using not one but <strong><em>two<\/em><\/strong> such numbers.<\/p>\n\n\n\n<p>Since only the <code>Major<\/code> and <code>Minor<\/code> fields are strictly in &#8216;common&#8217; between <strong>Semantic Version<\/strong> and <strong>VERSIONINFO<\/strong> I decided that these would also be <em>the only values carried forward<\/em> from the <strong>Semantic Version<\/strong> into the <strong>VERSIONINFO<\/strong>.  I would derive the <code>Revision<\/code> and <code>Build<\/code> values <em>independently<\/em> of the <code>Major<\/code> and <code>Minor<\/code> version. using a constantly incrementing scheme.<\/p>\n\n\n\n<p>There are numerous solutions to the constantly incrementing build number problem for <strong>Azure DevOps<\/strong>.  The approach I decided to use is derived from a value that increases intrinsically and inevitably over time:  <em>Time itself<\/em>.<\/p>\n\n\n\n<p>For <code>Revision<\/code> I would use a <em>days<\/em> counter.  That is, this field will identify <em>the date<\/em> on which the build was produced, calculated as the number of days since <em>1st Jan 2000<\/em>.  Why that date ?  Why not ?  \ud83d\ude42<\/p>\n\n\n\n<p>For <code>Build<\/code> I would use a <em>second<\/em> counter.  That is, this field identifies the <em>time of day<\/em> at which the build was produced.  But since there are 86400 seconds in a day, this number is actually divided by 2 in order to remain within the 65534 limit of the field.<\/p>\n\n\n\n<p class=\"has-background has-luminous-vivid-amber-background-color\">This gives me a &#8216;resolution&#8217; for my builds of only 2 seconds, but I don&#8217;t anticipate ever having a problem caused by my builds completing in under 2 seconds!  The days calculation gives me ~160 years in which to figure out a solution to the problem of that number &#8216;running out&#8217;, which should be enough time I think.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p class=\"has-drop-cap\">Now all that remains is to get this into my build pipeline.  Bearing in mind that I am using the command line compiler in my builds, the trick of referencing a <code>.rc<\/code> file and having the compiler automatically invoke the resource compiler to produce a <code>.res<\/code> file won&#8217;t work.  Even if it did, the header files necessary for compiling a <strong>VERSIONINFO<\/strong> resource are not provided with <strong>Delphi<\/strong>.<\/p>\n\n\n\n<p>Fortunately my self-hosted build machine already has a <strong>Windows 10 SDK<\/strong> installed, so I can use the resource compiler from that directly.<\/p>\n\n\n\n<p>In my project <code>.dpr<\/code> I reference a <code>versioninfo.res<\/code>file.  A version of this file is maintained in the repository with properties that identify any build as a &#8220;Development&#8221; version.<\/p>\n\n\n\n<p>This isn&#8217;t perfect.  Ideally it would at least also identify the build as a development build of the <code>Major<\/code> and <code>Minor<\/code> version from the <code>GitVersion.yml<\/code> configuration.  This is something I may turn my attention to at some point, if it becomes a problem.  But until then there are bigger fish to fry.<\/p>\n\n\n\n<p>Alongside the <code>versioninfo.res<\/code> file is a <code>versioninfo.rc<\/code> file.  This is the <strong>VERSIONINFO<\/strong> resource script containing <em>most<\/em> of the meta-data needed for the version info itself:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-c\">\/\/\n\/\/ Include the necessary resources\n\/\/\n#include &lt;winver.h&gt;\n#include &lt;versioninfo.h&gt;\n\n#define VER_FILENAME     &quot;duget.exe&quot;\n#define VER_PRODUCTNAME  &quot;Duget Package Manager for Delphi&quot;\n#define VER_INTERNALNAME &quot;Duget CLI&quot;\n#define VER_COMPANYNAME  &quot;Deltics (Jolyon Direnko-Smith)&quot;\n#define VER_COMMENTS     &quot;For more information visit https:\/\/duget.org&quot;\n#define VER_DESCRIPTION  &quot;Duget CLI Client Executable&quot;\n#define VER_COPYRIGHT    &quot;(c)2019 Jolyon Direnko-Smith&quot;\n\n#ifdef RC_INVOKED\n\tVS_VERSION_INFO VERSIONINFO\n\tFILEVERSION             VER_MAJOR,VER_MINOR,VER_TIMESTAMP_DAYS,VER_TIMESTAMP_SECONDS\n\tPRODUCTVERSION          VER_MAJOR,VER_MINOR,0,0\n\tFILEFLAGSMASK           VS_FFI_FILEFLAGSMASK\n\tFILEFLAGS               0\n\tFILEOS                  VOS_NT\n\tFILETYPE                VFT_APP\n\tFILESUBTYPE             0\n\tBEGIN\n\t\tBLOCK &quot;StringFileInfo&quot;\n\t\tBEGIN\n\t\t\tBLOCK &quot;040904B0&quot;\n\t        BEGIN\n\t\t\tVALUE &quot;Comments&quot;,         VER_COMMENTS\n\t\t\tVALUE &quot;CompanyName&quot;,      VER_COMPANYNAME\n\t\t\tVALUE &quot;FileDescription&quot;,  VER_DESCRIPTION\n\t\t\tVALUE &quot;FileVersion&quot;,      VER_FILEVERSION\n\t\t\tVALUE &quot;InternalName&quot;,     VER_INTERNALNAME\n\t\t\tVALUE &quot;LegalCopyright&quot;,   VER_COPYRIGHT\n\t\t\tVALUE &quot;OriginalFilename&quot;, VER_FILENAME\n\t\t\tVALUE &quot;ProductName&quot;,      VER_PRODUCTNAME\n\t\t\tVALUE &quot;ProductVersion&quot;,\t  VER_PRODUCTVERSION\n\t\t\tEND\n\t\tEND\n\t\tBLOCK &quot;VarFileInfo&quot;\n\t\tBEGIN\n\t\t\tVALUE &quot;Translation&quot;, 0x0409,1200\n\t\tEND\n\tEND\n#endif<\/code><\/pre>\n\n\n\n<p>Some key information is missing however, and this is expected to be provided in the <code>versioninfo.h<\/code> file that is <code>#included<\/code> at the top of the file.  This file is created at build time by the build pipeline:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\">steps:\n- template: gitversion.yml@templates\n\n- powershell: |\n    $baseDate = [datetime]&quot;01\/01\/2000&quot;\n    $baseTime = [datetime]&quot;00:00:00&quot;\n    $now = Get-Date\n\n    $daysInterval = New-TimeSpan -Start $baseDate -End $now\n    $secsInterval = New-TimeSpan -Start $baseTime -End $now\n    $days = $daysInterval.Days\n    $secs = [int]($secsInterval.TotalSeconds \/ 2)\n\n    $verMajor = $ENV:GitVersionMajor\n    $verMinor = $ENV:GitVersionMinor\n    $gitVersion = $ENV:GitVersion\n\n    Remove-Item versioninfo.h | Out-Null\n    New-Item versioninfo.h -ItemType file | Out-Null\n    Add-Content versioninfo.h &quot;#define VER_MAJOR $verMajor&quot;\n    Add-Content versioninfo.h &quot;#define VER_MINOR $verMinor&quot;\n    Add-Content versioninfo.h &quot;#define VER_TIMESTAMP_DAYS    $days&quot;\n    Add-Content versioninfo.h &quot;#define VER_TIMESTAMP_SECONDS $secs&quot;\n    Add-Content versioninfo.h &quot;#define VER_FILEVERSION    &quot;&quot;$verMajor.$verMinor.$days.$secs&quot;&quot;&quot;\n    Add-Content versioninfo.h &quot;#define VER_PRODUCTVERSION &quot;&quot;$gitVersion&quot;&quot;&quot;\n    type versioninfo.h\n\n    $ENV:Path += &#039;;c:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.17134.0\\x86&#039;\n    $include  = &#039;c:\\program files (x86)\\Windows Kits\\10\\Include\\10.0.17134.0\\um;&#039;\n    $include += &#039;c:\\program files (x86)\\Windows Kits\\10\\Include\\10.0.17134.0\\shared&#039;\n\n    $cmd = &#039;rc -i&quot;&#039; + $include + &#039;&quot; versioninfo.rc&#039;\n    Write-Host &quot;:&gt;&quot; + $cmd\n    Invoke-Expression $cmd\n  displayName: Calculate and Update VersionInfo<\/code><\/pre>\n\n\n\n<p>The pipeline first performs the <strong>GitVersion<\/strong> templated task to derive the necessary version information from the <strong>GitVersion<\/strong> configuration and commit history.<\/p>\n\n\n\n<p>This has been updated recently to yield more information now than <em>just<\/em> the semantic version.  Component values of that version information are now also set in environment variables which we can see the subsequent <strong>PowerShell<\/strong> script then uses to construct the content of the <code>versioninfo.h<\/code> header file.<\/p>\n\n\n\n<p>This <code>versioninfo.h<\/code> file is first deleted (a development version is present in the repo so we can be certain that it will exist and need to be deleted as part of a build).  Once the header file has been created as required, we emit it to the console to help identify and problems in the process when reviewing the build logs.<\/p>\n\n\n\n<p>There is then a bit of minor house-keeping needed to prepare for the invocation of the <strong>Windows SDK <\/strong>resource compiler which produces the <code>versioninfo.res<\/code> file referenced in the project itself.<\/p>\n\n\n\n<p>Once successfully compiled, the startup code of the <strong>duget<\/strong> executable is then able to extract it&#8217;s own version info.  When <strong>duget<\/strong> commands are performed this startup code identifies <strong>duget<\/strong> in the console with output similar to:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Duget Package Manager 0.1.0-alpha.15\nBuild 0.1.7217.23479 (For more information visit https:\/\/duget.org)\n(c)2019 Jolyon Direnko-Smith<\/pre>\n\n\n\n<p>Internally, the <em>ProductVersion<\/em> <em>string<\/em> provides the semantic, human meaningful version of the product whilst the <em>PRODUCTVERSION<\/em> identifies the <code>Major.Minor<\/code> version of the product without any <code>Revision.Build<\/code> info (both zeroed since they are not relevant to the <em>product<\/em> version).<\/p>\n\n\n\n<p>The <em>FILEVERSION<\/em> and <em>FileVersion<\/em> <em>string<\/em> values <strong>both<\/strong> identify the detailed build version complete with date and time of the specific build that produced this <em>exe<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>How do you manage version info in your automated builds ?  What do you think of this approach ?<\/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\">8<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> How to make Semantic Version make sense in a VERSIONINFO world without Semantic Versioning.<\/p>\n","protected":false},"author":2,"featured_media":3005,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"VERSIONINFO and Semantic Versioning - Squaring that particular circle needn't be difficult.","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[324,322,323,4,321,346],"tags":[342,327,329,344,347,343],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/bart-simpson-generator-1.png?fit=1024%2C343&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-Mo","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2985,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2985\/","url_meta":{"origin":3000,"position":0},"title":"Duget &#8211; RESTORE, UPDATE and What&#8217;s Next ?","date":"26 Sep 2019","format":false,"excerpt":"Wrapping up this short series on duget, discussing RESTORE and UPDATE, arguably most important and useful commands in the duget repertoire.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/duget-warriors.png?fit=929%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2979,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2979\/","url_meta":{"origin":3000,"position":1},"title":"Duget Package Manager for Delphi","date":"24 Sep 2019","format":false,"excerpt":"An overview of the the duget package manager, outlining the current state of this project and the first in a quick-fire series to explore the key features.","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/duget-warriors.png?fit=929%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2983,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2983\/","url_meta":{"origin":3000,"position":2},"title":"Duget &#8211; PUSH-ing Packages","date":"25 Sep 2019","format":false,"excerpt":"We now know a little more about this duget thing, and have seen how to create a package. But a package cannot be consumed 'in situ' - it must be made available via a feed. Which brings us to the PUSH command.NOTE: Don\u2019t worry, I have my priorities straight. This\u2026","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/duget-warriors.png?fit=929%2C256&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":2936,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2936\/","url_meta":{"origin":3000,"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":2919,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2919\/","url_meta":{"origin":3000,"position":4},"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":2931,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/2931\/","url_meta":{"origin":3000,"position":5},"title":"&#8216;Sorry, this script is too long&#8230;&#8217;","date":"18 Sep 2019","format":false,"excerpt":"An object lesson on the importance of defensive programming and providing helpful error messages to your users.","rel":"","context":"In &quot;Azure DevOps&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Mark_Twain_life_1900s.jpg?fit=883%2C331&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/3000"}],"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=3000"}],"version-history":[{"count":4,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/3000\/revisions"}],"predecessor-version":[{"id":3015,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/3000\/revisions\/3015"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/3005"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=3000"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=3000"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=3000"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}