<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>VSTS on But it works on my PC!</title>
    <link>https://blog.richardfennell.net/tags/vsts/</link>
    <description>Recent content in VSTS on But it works on my PC!</description>
    <image>
      <title>But it works on my PC!</title>
      <url>https://blog.richardfennell.net/images/papermod-cover.png</url>
      <link>https://blog.richardfennell.net/images/papermod-cover.png</link>
    </image>
    <generator>Hugo -- 0.147.0</generator>
    <language>en</language>
    <lastBuildDate>Thu, 07 Apr 2022 12:06:53 +0000</lastBuildDate>
    <atom:link href="https://blog.richardfennell.net/tags/vsts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Fix for Azure DevOps deployment to an environment stuck in &#34;Job is pending&#34; state</title>
      <link>https://blog.richardfennell.net/posts/fixe-for-azure-devops-deployment-to-an-environment-stuck-in-job-is-pending-state/</link>
      <pubDate>Thu, 07 Apr 2022 12:06:53 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/fixe-for-azure-devops-deployment-to-an-environment-stuck-in-job-is-pending-state/</guid>
      <description>&lt;h2 id=&#34;issue&#34;&gt;Issue&lt;/h2&gt;
&lt;p&gt;I had an Azure DevOps YAML based pipeline that had been working but was now getting stuck with the message &amp;ldquo;Job is pending&amp;hellip;&amp;rdquo; when trying to start a stage in which there is a deployment to an &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments&#34;&gt;environment&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Looking at the logs and Azure DevOps UI it was not obvious what the issue was.&lt;/p&gt;
&lt;h2 id=&#34;solution&#34;&gt;Solution&lt;/h2&gt;
&lt;p&gt;Turns out it was due to &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/process/approvals?view=azure-devops&amp;amp;tabs=check-pass&#34;&gt;environment checks and approvals&lt;/a&gt;. There was a branch policy on the environment. This was set to only allow use of Azure DevOps Templates on a given branch. The edit that had been done to the YAML meant it was trying to extend a template in a branch that was not in the approved list.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="issue">Issue</h2>
<p>I had an Azure DevOps YAML based pipeline that had been working but was now getting stuck with the message &ldquo;Job is pending&hellip;&rdquo; when trying to start a stage in which there is a deployment to an <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments">environment</a>.</p>
<p>Looking at the logs and Azure DevOps UI it was not obvious what the issue was.</p>
<h2 id="solution">Solution</h2>
<p>Turns out it was due to <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/approvals?view=azure-devops&amp;tabs=check-pass">environment checks and approvals</a>. There was a branch policy on the environment. This was set to only allow use of Azure DevOps Templates on a given branch. The edit that had been done to the YAML meant it was trying to extend a template in a branch that was not in the approved list.</p>
<p>As soon as the working branch was added to the proved list it all worked as expected.</p>
<p>So if you see &ldquo;Job is pending&rdquo; errors with no obvious reason, check the environment approvals and checks. Remember, any issues with these don&rsquo;t show up in the build log</p>
]]></content:encoded>
    </item>
    <item>
      <title>A workaround for not being able to access custom variables via stagedependencies if they are set in deployment jobs in Azure DevOps Pipelines</title>
      <link>https://blog.richardfennell.net/posts/a-workaround-for-not-being-able-to-access-custom-variables-via-stagedependencies-if-they-are-set-in-deployment-jobs-in-azure-devops-pipelines/</link>
      <pubDate>Sat, 19 Feb 2022 16:37:19 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/a-workaround-for-not-being-able-to-access-custom-variables-via-stagedependencies-if-they-are-set-in-deployment-jobs-in-azure-devops-pipelines/</guid>
      <description>&lt;p&gt;I have blogged in the past ( &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2020/11/27/getting-confused-over-azure-devops-pipeline-variable-evaluation/&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2022/01/10/using-azure-devops-stage-dependency-variables-with-conditional-stage-and-job-execution/&#34;&gt;here&lt;/a&gt;) about the complexities and possible areas of confusion with different types of Azure DevOps pipeline variables. I have also &lt;a href=&#34;https://developercommunity.visualstudio.com/t/unable-to-retrieve-stage-result-from-stagedependen/1064759#T-N1130023&#34;&gt;seen issues raised&lt;/a&gt; over how to access custom variables across jobs and stages. Safe to say, this is an area where it is really easy to get it wrong and end up with a null value.&lt;/p&gt;
&lt;p&gt;I have recently come across another edge case to add to the list of gotchas.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have blogged in the past ( <a href="https://blogs.blackmarble.co.uk/rfennell/2020/11/27/getting-confused-over-azure-devops-pipeline-variable-evaluation/">here</a> and <a href="https://blogs.blackmarble.co.uk/rfennell/2022/01/10/using-azure-devops-stage-dependency-variables-with-conditional-stage-and-job-execution/">here</a>) about the complexities and possible areas of confusion with different types of Azure DevOps pipeline variables. I have also <a href="https://developercommunity.visualstudio.com/t/unable-to-retrieve-stage-result-from-stagedependen/1064759#T-N1130023">seen issues raised</a> over how to access custom variables across jobs and stages. Safe to say, this is an area where it is really easy to get it wrong and end up with a null value.</p>
<p>I have recently come across another edge case to add to the list of gotchas.</p>
<p>It seems you cannot use <strong>stagedependencies</strong> to access a variable declared in a <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/deployment-jobs?view=azure-devops">deployment job</a> i.e. when you are using an <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments?view=azure-devops">environment</a> to get approval for a release.</p>
<p>The workaround is to add a job that is dependent on the deployment and set the custom variable within it. This variable can be accessed by a later stage as shown below</p>
<pre tabindex="0"><code>- stage: S1
  jobs:
  - deployment: D1
    strategy:
      runOnce:
        deploy:
          steps:
              - checkout: none
              - bash: echo &#34;Can&#39;t access the variable if set in here&#34;
  - job: J1
    dependsOn:
      D1
    steps:
      - checkout: none
      - bash: echo &#34;##vso[task.setvariable variable=myvar;isOutput=true]True&#34; 
        name: BashStep

- stage: S2
  condition: always()

  dependsOn: 
   - S1
  jobs:
   - job: Use_Variable
     variables: # add an alias for the var
       myvar: $[stagedependencies.S1.J1.outputs[&#39;BashStep.myvar&#39;]]
        steps:
          - checkout: none
          - dash: echo &#34;Script gets run when myvar is true&#34;
            condition: eq (variables[&#39;myvar&#39;],&#39;True&#39;)
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Using Azure DevOps Stage Dependency Variables with Conditional Stage and Job Execution</title>
      <link>https://blog.richardfennell.net/posts/using-azure-devops-stage-dependency-variables-with-conditional-stage-and-job-execution/</link>
      <pubDate>Mon, 10 Jan 2022 13:16:46 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/using-azure-devops-stage-dependency-variables-with-conditional-stage-and-job-execution/</guid>
      <description>&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://blog.richardfennell.net/wp-content/uploads/sites/2/2022/01/image-1-1024x446.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;I have been doing some work with Azure DevOps multi-stage YAML pipelines using stage dependency variables and conditions. They can get confusing quickly, you need one syntax in one place and another elsewhere.&lt;/p&gt;
&lt;p&gt;So, here are a few things I have learnt&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;what-are-stage-dependency-variables&#34;&gt;What are stage dependency variables?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;amp;tabs=yaml#specify-dependencies&#34;&gt;Stage Dependencies&lt;/a&gt; are the way you define which stage follows another in a multi-stage YAML pipeline. This is as opposed to just relying on the order they appear in the YAML file, the default order. Hence, they are critical to creating complex pipelines.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><img loading="lazy" src="/wp-content/uploads/sites/2/2022/01/image-1-1024x446.png"></p>
<p>I have been doing some work with Azure DevOps multi-stage YAML pipelines using stage dependency variables and conditions. They can get confusing quickly, you need one syntax in one place and another elsewhere.</p>
<p>So, here are a few things I have learnt&hellip;</p>
<h2 id="what-are-stage-dependency-variables">What are stage dependency variables?</h2>
<p><a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;tabs=yaml#specify-dependencies">Stage Dependencies</a> are the way you define which stage follows another in a multi-stage YAML pipeline. This is as opposed to just relying on the order they appear in the YAML file, the default order. Hence, they are critical to creating complex pipelines.</p>
<p><a href="https://developercommunity.visualstudio.com/t/unable-to-retrieve-stage-result-from-stagedependen/1064759">Stage Dependency variables</a> are the way you can pass variables from one stage to another. Special handling is required, as you can’t just use the ordinary <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&amp;tabs=yaml%2Cbatch#use-output-variables-from-tasks">output variables</a> (which are in effect environment variables on the agent) as you might within a job as there is no guarantee the stages and jobs are running on the same agent.</p>
<p>For stage dependency variables, is not how you create output variables, that does not differ from the standard manner, the difference is in how you retrieve them.</p>
<p><a href="https://gist.github.com/rfennell/b57db0c2e4e3bae1968a4908b0df3595">In my sample</a>, I used a BASH script to set the output variable based on a parameter passed into the pipeline, but you can create output variables using scripts or tasks</p>
<pre tabindex="0"><code> - stage: SetupStage
    displayName: &#39;Setup Stage&#39;
    jobs:
      - job: SetupJob
        displayName: &#39;Setup Job&#39;
        steps:
          - checkout: none
          - bash:  |
              set -e # need to avoid trailing &#34; being added to the variable https://github.com/microsoft/azure-pipelines-tasks/issues/10331
              echo &#34;##vso[task.setvariable variable=MyVar;isOutput=true]${{parameters.value}}&#34;
            name: SetupStep
            displayName: &#39;Setup Step&#39; 
</code></pre><h2 id="possible-ways-to-access-a-stage-dependency-variable">Possible ways to access a stage dependency variable</h2>
<p>There are two basic ways to access stage dependency variables, both using array objects</p>
<pre tabindex="0"><code>stageDependencies.STAGENAME.JOBNAME.outputs[&#39;STEPNAME.VARNAME&#39;]
dependencies.STAGENAME.outputs[&#39;JOBNAME.STEPNAME.VARNAME&#39;]
</code></pre><p>Which one you use, in which place, and whether via a local alias is the complexity</p>
<h2 id="how-to-access-a-stage-dependency-in-a-script">How to access a stage dependency in a script?</h2>
<p>To access a stage dependency variable in a script, or a task, there are two key requirements</p>
<ul>
<li>The stage containing the consuming job and hence script/task, must be set as dependant on the stage that created the output variable</li>
<li>You have to declare a local alias for the value in the <strong>stageDependencies</strong> array within the consuming stage. This local alias will be used as the local name by scripts and tasks</li>
</ul>
<p>Once this is configured you can access the variable like any other local YAML variable</p>
<pre tabindex="0"><code> - stage: Show_With_Dependancy
    displayName: ‘Show Stage With dependancy’
    dependsOn:
      - SetupStage
    variables:
      localMyVarViaStageDependancies : $[stageDependencies.SetupStage.SetupJob.outputs[‘SetupStep.MyVar’]]
    jobs:
      - job: Job
        displayName: ‘Show Job With dependancy’
        steps:
        - bash: |
              echo “localMyVarViaStageDependancies - $(localMyVarViaStageDependancies)” 
</code></pre><p><strong>Tip:</strong> If you are having a problem with the value not being set for a stage dependency variable look in the pipeline execution log, at the job level, and check the ‘Job preparation parameters’ section to see what is being evaluated. This will show if you are using the wrong array object, or have a typo, as any incorrect declarations evaluate as null</p>
<p><img loading="lazy" src="/wp-content/uploads/sites/2/2022/01/image.png"></p>
<h2 id="how-to-use-a-stage-dependency-as-a-stage-condition">How to use a stage dependency as a stage condition</h2>
<p>You can use stage dependency variables as controlling conditions for running a stage. In this use-case you use the <strong>dependencies</strong> array and not the <strong>stagedependencies</strong> used when aliasing variables.</p>
<pre tabindex="0"><code> - stage: Show_With_Dependancy_Condition
    condition: and (succeeded(), eq (dependencies.SetupStage.outputs[&#39;SetupJob.SetupStep.MyVar&#39;], &#39;True&#39;))
    displayName: &#39;Show Stage With dependancy Condition&#39; 
</code></pre><p>From my experiments for this use-case, you don’t seem to need the <strong>DependsOn</strong> entry to decare the stage that exposed the output variable for this to work. So, this is very useful for complex pipelines where you want to skip a later stage based on a much earlier stage for which there is no direct dependency.</p>
<p>A side effect of using a stage condition is that many subsequent stages have to have their execution conditions edited as you cannot rely on the default completion stage state <strong>succeeded.</strong> This is because the prior stages could now be <strong>succeeded</strong> or <strong>skipped</strong>. Hence all following stages need to use the condition</p>
<pre tabindex="0"><code>condition: and( not(failed()), not(canceled()))
</code></pre><h2 id="how-to-use-a-stage-dependency-as-a-job-condition">How to use a stage dependency as a job condition</h2>
<p>To avoid the need to alter all the subsequent stage&rsquo;s execution conditions you can set a condition at the job or task level. Unlike setting the condition at that stage level, you have to create a local alias (see above) and check the condition on that</p>
<pre tabindex="0"><code> - stage: Show_With_Dependancy_Condition_Job
    displayName: &#39;Show Stage With dependancy Condition&#39;
    dependsOn:
      - SetupStage
    variables:
      localMyVarViaStageDependancies : $[stageDependencies.SetupStage.SetupJob.outputs[&#39;SetupStep.MyVar&#39;]]
    jobs:
      - job: Job
        condition: and (succeeded(),
          eq (variables.localMyVarViaStageDependancies, &#39;True&#39;))
        displayName: &#39;Show Job With dependancy&#39; 
</code></pre><p>This technique will work for both <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops&amp;tabs=yaml#types-of-jobs">Agent-based and Agent-Less (Server) jobs</a></p>
<p>A warning though, if your job makes use of an <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments?view=azure-devops">environment</a> with a manual approval, the environment approval check is evaluated before the job condition. This is probably not what you are after, so if using conditions with environments that use manual approvals then the condition is probably best set at the stage level, with the knock-on issues of states of subsequent stages as mentioned above.</p>
<p>An alternative, if you are just using the environment for manual approval, is to look at using an AgentLess job with <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/manual-validation?view=azure-devops&amp;tabs=yaml">a manual approval</a>. AgentLess job manual approvals are evaluated after the job condition, so do not suffer the same problem.</p>
<p>If you need to use a stage dependency variable in a later stage, as a job condition or script variable, but do not wish to add a direct dependency between the stages, you could consider ‘republishing’ the variable as an output of the intermedia stage(s)</p>
<pre tabindex="0"><code> - stage: Intermediate_Stage
    dependsOn:
      - SetUpStage
    variables:
      localMyVarViaStageDependancies : $[stageDependencies.SetupStage.SetupJob.outputs[&#39;SetupStep.MyVar&#39;]]
    jobs:
      - job: RepublishMyVar
       steps:
          - checkout: none
          - bash:  |
              set -e # need to avoid trailing &#34; being added to the variable https://github.com/microsoft/azure-pipelines-tasks/issues/10331
              echo &#34;##vso[task.setvariable variable=MyVar;isOutput=true]$( localMyVarViaStageDependancies)&#34;
            name: RepublishStep 
</code></pre><h2 id="summing-up">Summing Up</h2>
<p>So I hope this post will help you, and the future me, navigate the complexities of stage variables</p>
<p><a href="https://gist.github.com/rfennell/b57db0c2e4e3bae1968a4908b0df3595">You can find the YAML for the test harness I have been using in this GitHub GIST</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Porting my Visual Studio Parameters.xml Generator tool to Visual Studio 2022 Preview</title>
      <link>https://blog.richardfennell.net/posts/porting-my-visual-studio-parameters-xml-generator-tool-to-visual-studio-2022-preview/</link>
      <pubDate>Tue, 22 Jun 2021 11:08:10 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/porting-my-visual-studio-parameters-xml-generator-tool-to-visual-studio-2022-preview/</guid>
      <description>&lt;p&gt;As I am sure you are all aware the preview of &lt;a href=&#34;https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-1-now-available/&#34;&gt;Visual Studio 2022&lt;/a&gt; has just dropped, so it is time for me to update my Parameter.xml Generator Tool to support this new version of Visual Studio.&lt;/p&gt;
&lt;h2 id=&#34;but-what-does-my-extension-do&#34;&gt;But what does my extension do?&lt;/h2&gt;
&lt;p&gt;As the Marketplace description says&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;A tool to generate parameters.xml files for MSdeploy from the existing web.config file or from an app.config file for use with your own bespoke configuration transformation system.&lt;/em&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>As I am sure you are all aware the preview of <a href="https://devblogs.microsoft.com/visualstudio/visual-studio-2022-preview-1-now-available/">Visual Studio 2022</a> has just dropped, so it is time for me to update my Parameter.xml Generator Tool to support this new version of Visual Studio.</p>
<h2 id="but-what-does-my-extension-do">But what does my extension do?</h2>
<p>As the Marketplace description says&hellip;</p>
<p><em>A tool to generate parameters.xml files for MSdeploy from the existing web.config file or from an app.config file for use with your own bespoke configuration transformation system.</em></p>
<p><em>Once the VSIX package is installed, to use right-click on a web.config, or app.config, file in Solution Explorer and the parameters.xml file will be generated using the current web.config entries from for both <strong>configuration/applicationSettings</strong> and <strong>configuration/AppSettings</strong>. The values attributes will contain TAG style entries suitable for replacement at deployment time.</em></p>
<p>I_f the parameters.xml already exists in the folder (even if it is not a file in the project) you will be prompted before it is overwritten._</p>
<p>Currently the version in the Marketplace of <a href="https://marketplace.visualstudio.com/items?itemName=RichardFennellMVP.ParametersXmlGenerator">Parameter.xml Generator Tool supports Visual Studio 2015, 2017 &amp; 2019</a></p>
<h2 id="adding-visual-studio-2022-support">Adding Visual Studio 2022 Support</h2>
<p>The process to add 2022 support is more complicated than adding past new versions, where all that was usually required was an update to the manifest. This is due to the move to 64Bit.</p>
<p>Luckily the process <a href="https://docs.microsoft.com/en-gb/visualstudio/extensibility/migration/update-visual-studio-extension?view=vs-2022">is fairly well documented</a>, but of course I still had a few problems.</p>
<h3 id="msb4062-the-comparebuildtaskversion-task-could-not-be-loaded-from-the-assembly">MSB4062: The &ldquo;CompareBuildTaskVersion&rdquo; task could not be loaded from the assembly</h3>
<p>When I tried build the existing solution, without any changes, in Visual Studio 2022 I got the error</p>
<p><em>MSB4062: The &ldquo;CompareBuildTaskVersion&rdquo; task could not be loaded from the assembly D:myprojectpackagesMicrosoft.VSSDK.BuildTools.15.8.3253toolsVSSDKMicrosoft.VisualStudio.Sdk.BuildTasks.15.0.dll. Could not load file or assembly.</em></p>
<p>This was fixed by updating the package Microsoft.VSSDK.BuildTools from 15.1.192 to 16.9.1050.</p>
<h3 id="modernizing-the-existing-vsix-project">Modernizing the Existing VSIX project</h3>
<p>I did not modernize the existing VSIX project before I started the migration. When I clicked the <strong>Migrate packages.config to PackageReference….</strong> it said my project was not a suitable version. So I just moved to the next step.</p>
<h3 id="adding-link-files">Adding Link Files</h3>
<p>After creating the shared code project, that contains the bulk of the files, I needed to add links to some of the resources i.e. the license file, the package icon and .VSCT file.</p>
<p>When I tried add the link, I got an error in the form</p>
<p>_ Cannot add another link for the same file in another project_</p>
<p>I tried exiting Visual Studio, cleaning the solution, nothing helped. The solution was to edit the .CSPROJ file manually in a text editor e.g.</p>
<pre tabindex="0"><code> &lt;ItemGroup&gt;
    &lt;Content Include=&#34;ResourcesLicense.txt&#34;&gt;
      &lt;CopyToOutputDirectory&gt;Always&lt;/CopyToOutputDirectory&gt;
    &lt;Content Include=&#34;..ParametersXmlAddinSharedResourcesPackage.ico&#34;&gt;
      &lt;Link&gt;Package.ico&lt;/Link&gt;
      &lt;IncludeInVSIX&gt;true&lt;/IncludeInVSIX&gt;
    &lt;/Content&gt;
    &lt;Content Include=&#34;ResourcesPackage.ico&#34;&gt;
      &lt;CopyToOutputDirectory&gt;Always&lt;/CopyToOutputDirectory&gt;
    &lt;Content Include=&#34;..ParametersXmlAddinSharedResourcesLicense.txt&#34;&gt;
      &lt;Link&gt;License.txt&lt;/Link&gt;
      &lt;IncludeInVSIX&gt;true&lt;/IncludeInVSIX&gt;
    &lt;/Content&gt;
    &lt;EmbeddedResource Include=&#34;ResourcesParametersUppercaseTransform.xslt&#34; /&gt;
    &lt;VSCTCompile Include=&#34;..ParametersXmlAddinSharedParametersXmlAddin.vsct&#34;&gt;
      &lt;Link&gt;ParametersXmlAddin.vsct&lt;/Link&gt;
      &lt;ResourceName&gt;Menus.ctmenu&lt;/ResourceName&gt;
    &lt;/VSCTCompile&gt;
  &lt;/ItemGroup&gt;
</code></pre><h2 id="publishing-the-new-extension">Publishing the new Extension</h2>
<p>Once I had completed the migration steps, I had a pair of VSIX files. The previously existing one that supported Visual Studio 2015, 2017 &amp; 2019 and the new Visual Studio 2022 version.</p>
<p>The <a href="https://docs.microsoft.com/en-gb/visualstudio/extensibility/migration/update-visual-studio-extension?view=vs-2022#publish-your-extension">migration notes</a> say that in the future we will be able to upload both VSIX files to a single Marketplace entry and the Marketplace will sort out delivering the correct version.</p>
<p>Unfortunately, that feature is not available at present. So for now the new Visual Studio 2022 VSIX is published separately from the old one with a <a href="https://marketplace.visualstudio.com/items?itemName=RichardFennellMVP.ParametersXmlGeneratorDev17">preview flag</a>.</p>
<p>As soon as I can, I will merge the new VSIX into the old Marketpalce entry and removed the preview 2022 version of the VSIX</p>
]]></content:encoded>
    </item>
    <item>
      <title>Getting confused over Azure DevOps Pipeline variable evaluation</title>
      <link>https://blog.richardfennell.net/posts/getting-confused-over-azure-devops-pipeline-variable-evaluation/</link>
      <pubDate>Fri, 27 Nov 2020 15:50:49 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/getting-confused-over-azure-devops-pipeline-variable-evaluation/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The use of variables is important in Azure DevOps pipelines, especially when using YML templates. They allow a single pipeline to be used for multiple branches/configurations etc.&lt;/p&gt;
&lt;p&gt;The most common form of variables you see is are the &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&amp;amp;tabs=yaml&#34;&gt;predefined built in variables&lt;/a&gt; e.g. &lt;strong&gt;$(Build.BuildNumber)&lt;/strong&gt; and your own custom ones e.g. &lt;strong&gt;$(var)&lt;/strong&gt;. Usually the value of these variables are set before/as the build is run, as an input condition.&lt;/p&gt;
&lt;p&gt;But this is not the only way variables can be used. As noted in the &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&amp;amp;tabs=yaml%2Cbatch#understand-variable-syntax&#34;&gt;documentation&lt;/a&gt; there are different ways to access a variable&amp;hellip;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>The use of variables is important in Azure DevOps pipelines, especially when using YML templates. They allow a single pipeline to be used for multiple branches/configurations etc.</p>
<p>The most common form of variables you see is are the <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&amp;tabs=yaml">predefined built in variables</a> e.g. <strong>$(Build.BuildNumber)</strong> and your own custom ones e.g. <strong>$(var)</strong>. Usually the value of these variables are set before/as the build is run, as an input condition.</p>
<p>But this is not the only way variables can be used. As noted in the <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&amp;tabs=yaml%2Cbatch#understand-variable-syntax">documentation</a> there are different ways to access a variable&hellip;</p>
<blockquote>
<p>In a pipeline, template expression variables <strong>${{ variables.var }}</strong> get processed at compile time, before runtime starts. Macro syntax variables <strong>$(var)</strong> get processed during runtime before a task runs. Runtime expressions <strong>$[variables.var]</strong> also get processed during runtime but were designed for use with conditions and expressions.</p>
<p>Azure DevOps Documentation</p></blockquote>
<p>99% of the time I have been fine using just the <strong>$(var)</strong> syntax, but I recently was working on a case where this would not work for me.</p>
<h2 id="the-issue">The Issue</h2>
<p>I had a pipeline that made heavy use of <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops">YML templates</a> and <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#conditional-insertion">conditional task insertion</a> to include sets of task based upon the manually entered and pre-defined variables.</p>
<p>The problems that one of the tasks, used in a template, set a boolean output variable <strong>$(outVar)</strong> by calling</p>
<pre tabindex="0"><code>echo &#39;##vso\[task.setvariable variable=outvar;isOutput=true\]true&#39;
</code></pre><p>This task created the output variable could be accessed by other tasks as the variable <strong>$(mytask.outvar)</strong>, but it was set at runtime it not available at the time of the YML compilation.</p>
<p>This caused me a problem as it meant that it could not be used in the template&rsquo;s <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops#conditional-insertion">conditional task inclusion</a> blocks as it as not present art compile time when this code is evaluated e.g.</p>
<pre tabindex="0"><code>\- ${{ if eq(mytask.outvar, &#39;true&#39;) }} :
  # the task to run if the condition is met
  - task: Some.Task@1 
    ....
</code></pre><p>I tied referencing the variable using all forms of $ followed by brackets syntax I could think of, but it did not help.</p>
<p>The lesson here is that you cannot make a runtime value a compile time value by wishing it to change.</p>
<p>The only solution I could find was to make use of the runtime variable in a place where it can be resolved. If you wish to enable or disable a task based on the variable value then the only option is to use the <strong>condition</strong> parameter</p>
<pre tabindex="0"><code>  # the task to run if the condition is met
  - task: Some.Task@1 
    condition: and(succeeded(), eq(mytask.outvar, &#39;true&#39;))
    ....
</code></pre><p>The only downside of this way of working as opposed to the conditional insertion is that</p>
<ul>
<li>If you conditional insertion, non required tasks are never shown in the pipeline as they are not compiled into it</li>
<li>If using the condition property to exclude a task, it will still appear in the log, but it can be seen that it has not been run.</li>
</ul>
<p>So I got there in the end, it was just not as neat as I had hoped, but I do have a clearer understanding of compile and runtime variables in Azure DevOps YML</p>
]]></content:encoded>
    </item>
    <item>
      <title>Using the Post Build Cleanup Task from the Marketplace in YAML based Azure DevOps Pipelines</title>
      <link>https://blog.richardfennell.net/posts/using-the-post-build-cleanup-task-from-the-marketplace-in-yaml-based-azure-devops-pipelines/</link>
      <pubDate>Wed, 19 Aug 2020 14:58:39 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/using-the-post-build-cleanup-task-from-the-marketplace-in-yaml-based-azure-devops-pipelines/</guid>
      <description>&lt;p&gt;Disks filling up on our private Azure DevOps agents is a constant battle. We have maintenance jobs setup on the agent pools, to clean out old build working folders nightly, but these don’t run often enough. We need a clean out more than once a day due to the number and size of our builds. To address this, with UI based builds, we successfully used the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=mspremier.PostBuildCleanup&#34;&gt;Post Build Cleanup Extension&lt;/a&gt;. However since we have moved many of our builds to YAML we found it not working so well. Turned out the problem was due to the way got source code. The Post Build Cleanup task is intelligent, it does not just delete folders on demand. It check to see what the Get Source ‘Clean’ setting was when the repo was cloned and bases what it deletes on this value e.g. nothing, source, or everything. This behaviour is not that obvious. In a UI based builds it is easy to check this setting. You are always in the UI when editing the build. However, in YAML it is easy to forget the setting, as it is one of those few values that cannot be set in YAML. To make the post build cleanup task actually delete folders in a YAML pipeline you need to&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Disks filling up on our private Azure DevOps agents is a constant battle. We have maintenance jobs setup on the agent pools, to clean out old build working folders nightly, but these don’t run often enough. We need a clean out more than once a day due to the number and size of our builds. To address this, with UI based builds, we successfully used the <a href="https://marketplace.visualstudio.com/items?itemName=mspremier.PostBuildCleanup">Post Build Cleanup Extension</a>. However since we have moved many of our builds to YAML we found it not working so well. Turned out the problem was due to the way got source code. The Post Build Cleanup task is intelligent, it does not just delete folders on demand. It check to see what the Get Source ‘Clean’ setting was when the repo was cloned and bases what it deletes on this value e.g. nothing, source, or everything. This behaviour is not that obvious. In a UI based builds it is easy to check this setting. You are always in the UI when editing the build. However, in YAML it is easy to forget the setting, as it is one of those few values that cannot be set in YAML. To make the post build cleanup task actually delete folders in a YAML pipeline you need to</p>
<ol>
<li>Edit the pipeline</li>
<li>Click the ellipse menu top right</li>
<li>Pick Triggers</li>
<li>Pick YAML and select the ‘Get Source’ block</li>
<li>Make sure the ‘Clean’ setting is set to ‘true’ and the right set of items to delete are selected <em>– if this is not done the post clean up task does nothing</em><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/08/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/08/image_thumb.png" title="image"></a></li>
<li>You can then add the post build cleanup task the end of the steps</li>
</ol>
<pre tabindex="0"><code>steps:
  - script: echo This where you do stuff
  - task: mspremier.PostBuildCleanup.PostBuildCleanup-task.PostBuildCleanup@3
    displayName: &#39;Clean Agent Directories&#39;
    condition: always()


```Once this is done it behaves as expected
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Bringing Stage based release notes in Multi-Stage YAML to my Cross Platform Release Notes Exension</title>
      <link>https://blog.richardfennell.net/posts/bringing-stage-based-release-notes-in-multi-stage-yaml-to-my-cross-platform-release-notes-exension/</link>
      <pubDate>Mon, 06 Jul 2020 13:21:12 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/bringing-stage-based-release-notes-in-multi-stage-yaml-to-my-cross-platform-release-notes-exension/</guid>
      <description>&lt;p&gt;I have just released Version 3.1.7 of my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Azure DevOps Pipeline XplatGenerateReleaseNotes Extension&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This new version allows you to build release notes within a Multi-Stage YAML build since the last successful release to the current (or named) stage in the pipeline as opposed to just last fully successful build.&lt;/p&gt;
&lt;p&gt;This gives more feature parity with the older UI based Releases functionality.&lt;/p&gt;
&lt;p&gt;To enable this new feature you need to set the &lt;code&gt;checkStage: true&lt;/code&gt; flag and potentially the &lt;code&gt;overrideStageName: AnotherStage&lt;/code&gt; if you wish the comparison to compare against a stage other than the current one.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have just released Version 3.1.7 of my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Azure DevOps Pipeline XplatGenerateReleaseNotes Extension</a>.</p>
<p>This new version allows you to build release notes within a Multi-Stage YAML build since the last successful release to the current (or named) stage in the pipeline as opposed to just last fully successful build.</p>
<p>This gives more feature parity with the older UI based Releases functionality.</p>
<p>To enable this new feature you need to set the <code>checkStage: true</code> flag and potentially the <code>overrideStageName: AnotherStage</code> if you wish the comparison to compare against a stage other than the current one.</p>
<pre tabindex="0"><code>\- task: XplatGenerateReleaseNotes@3
  inputs:
    outputfile: &#39;$(Build.ArtifactStagingDirectory)releasenotes.md&#39;
    outputVariableName: &#39;outputvar&#39;
    templateLocation: &#39;InLine&#39;
    checkStage: true
    inlinetemplate: |
      # Notes for build 
      \*\*Build Number\*\*: {{buildDetails.id}}
      ...
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Getting started with Aggregator CLI for Azure DevOps Work Item Roll-up</title>
      <link>https://blog.richardfennell.net/posts/getting-started-with-aggregator-cli-for-azure-devops-work-item-roll-up/</link>
      <pubDate>Fri, 12 Jun 2020 17:23:40 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/getting-started-with-aggregator-cli-for-azure-devops-work-item-roll-up/</guid>
      <description>&lt;p&gt;&lt;em&gt;Updated 30/Sep/21 to reflect changes in the Aggregator CLI setup process&lt;/em&gt;
&lt;em&gt;Updated 27/Mar/22 to fix broken links&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;
&lt;p&gt;Back in the day I wrote a tool, &lt;a href=&#34;https://archive.codeplex.com/?p=tfsalertsdsl&#34;&gt;TFS Alerts DSL&lt;/a&gt;, to do Work Item roll-up for TFS. Overtime I updated this to support VSTS (as Azure DevOps was then called), it’s final version is still available in the Azure DevOps Marketplace as the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-ServiceHooks-DSL&#34;&gt;Azure DevOps Service Hooks DSL&lt;/a&gt;. So when I recently had a need for Work Item roll-up I did consider using my own tool, just for a short while. However, I quickly realised a much better option was to use the &lt;a href=&#34;https://github.com/tfsaggregator/aggregator-cli&#34;&gt;Aggregator CLI&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><em>Updated 30/Sep/21 to reflect changes in the Aggregator CLI setup process</em>
<em>Updated 27/Mar/22 to fix broken links</em></p>
<h2 id="background">Background</h2>
<p>Back in the day I wrote a tool, <a href="https://archive.codeplex.com/?p=tfsalertsdsl">TFS Alerts DSL</a>, to do Work Item roll-up for TFS. Overtime I updated this to support VSTS (as Azure DevOps was then called), it’s final version is still available in the Azure DevOps Marketplace as the <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-ServiceHooks-DSL">Azure DevOps Service Hooks DSL</a>. So when I recently had a need for Work Item roll-up I did consider using my own tool, just for a short while. However, I quickly realised a much better option was to use the <a href="https://github.com/tfsaggregator/aggregator-cli">Aggregator CLI</a>.</p>
<p>Aggregator CLI is a successor to the <a href="https://tfsaggregator.github.io/">TFS Aggregator Plug-in</a> and is a far more mature project than my tool and actively under development, allowing hosting as an Azure Function or a Docker container.</p>
<p>As I have found the Aggregator CLI a little hard to get started with, I thought this blog post was a good idea, so I don’t forget the details in the future.</p>
<h3 id="architecture">Architecture</h3>
<p>In this latest version of the Aggregator the functionality is delivered using Azure Functions, one per rule. <strong>Note:</strong> A docker container is an other option, but one I have not explored These Azure Functions are linked to Azure DevOps Service hook events. The command line tool setup process configures all of the parts required setting up Azure resources, Azure DevOps events and managing rules.</p>
<h3 id="preparation">Preparation</h3>
<ul>
<li>Download the latest release from <a href="https://github.com/tfsaggregator/aggregator-cli/releases">https://github.com/tfsaggregator/aggregator-cli/releases</a>, pick the version for the operating system you are planning to use to setup the tool.</li>
<li>Next you need to setup an Azure Service Principle App registration for the Aggregator and connect it to a Subscription</li>
</ul>
<ol>
<li>
<ol>
<li>Login to Azure <em>az login</em></li>
<li>Pick the correct subscription <em>az account set &ndash;subscription <ID></em></li>
<li>Create the service principle az ad sp create-for-rbac &ndash;name AggregatorServicePrincipal</li>
<li>From the root of the Azure Portal pick the Subscription you wish to create the Azure Functions in.</li>
<li>In the Access (IAM ) section grant the ‘contributor role’ for the subscription to the newly created Service Principle</li>
</ol>
</li>
</ol>
<h3 id="using-the-aggregator-cli">Using the Aggregator CLI</h3>
<p>At a command prompt we need to now start to use the tool to link up Azure Services and Azure DevOps</p>
<ul>
<li>
<p>First we log the CLI tool into Azure. You can find the values required from Azure Portal, in the Subscription overview and App Registration overview. You create a password from ‘client and secrets’ section for the App Registration. <em>.aggregator-cli.exe logon.azure -s <sub-id> -c <client-id> -t <tenant-id> -p <pwd></em></p>
</li>
<li>
<p>Next login to Azure DevOps, <a href="https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&amp;tabs=preview-page">create the PAT as detailed in the documentation</a> <em>.aggregator-cli.exe logon.ado -u</em> <a href="https://dev.azure.com/%3corg"><em>https://dev.azure.com/&lt;org</em></a><em>&gt; -mode PAT -t <pat></em></p>
</li>
<li>
<p>Now we can create the Instance of the Aggregator in  Azure <strong>Note:</strong> I had long delays and timeout problems here due to what turned out to be a  poor WIFI links. The strange thing was it was not obviously failing WIFI, but just unstable enough to cause issues. As soon as I swapped to Ethernet the problems went away. The basic form of the install command is as follows, this will create a new resource group in Azure and then the required Web App, Storage, Application Insights etc. As this is  done using an ARM template so it is idempotent i.e. it can re run as many times as you wish, it will just update the Azure services if they already exist. <em>.aggregator-cli.exe install.instance -verbose -n yourinstancename -l westeurope</em> If you do get problems, goto the Azure Portal, find th reosurce group and look at the deployment logs</p>
</li>
<li>
<p>When this completes, you can see the new resources in the Azure Portal, or check them with command line <em>.aggregator-cli.exe list.instances</em></p>
</li>
<li>
<p>You next need to register your rules. You can register as many as you wish. A few samples are provided in the <strong>test</strong> folder in the downloaded ZIP, these are good for a quick tests, thought you will usually create your own for production use. When you add a rule, behind the scenes this creates an Azure Function with the same name as the rule. <em>.aggregator-cli.exe add.rule -v -i yourinstancename -n test1 -file testtest1.rule</em></p>
</li>
<li>
<p>Finally you map a rule to some event in Azure DevOps instance <em>.aggregator-cli.exe map.rule -v -p yourproject -e workitem.updated -i yourinstancename -r test1</em></p>
</li>
</ul>
<p>Once all this done you should have a working system. If you are using the the test rules the quickest option to see it is working is to</p>
<ol>
<li>Go into the Azure Portal</li>
<li>Find the created Resource Group</li>
<li>Pick the App Service for the Azure Functions</li>
<li>Pick the Function for the rule under test</li>
<li>Pick the Monitor</li>
<li>Pick Logs</li>
<li>Open Live Metric</li>
<li>You should see log entries when you perform the event on a work item you mapped to the function.</li>
</ol>
<p>An alternative is to look in the AppInsights Logs or live telemetry. So I hope this helps my future self remember how get this tool setup quickly</p>
]]></content:encoded>
    </item>
    <item>
      <title>How to do local template development for my Cross platform Release notes task</title>
      <link>https://blog.richardfennell.net/posts/how-to-do-local-template-development-for-my-cross-platform-release-notes-task/</link>
      <pubDate>Wed, 10 Jun 2020 14:01:01 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/how-to-do-local-template-development-for-my-cross-platform-release-notes-task/</guid>
      <description>&lt;p&gt;The testing cycle for &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Release Notes Templates&lt;/a&gt; can be slow, requiring a build and release cycle. To try to speed this process for users I have created a local test harness that allows the same calls to be made from a development machine as would be made within a build or release.&lt;/p&gt;
&lt;p&gt;However, running this is not as simple was you might expect so please read the instruction before proceeding.&lt;/p&gt;
&lt;h3 id=&#34;setup-and-build&#34;&gt;Setup and Build&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/rfennell/AzurePipelines&#34;&gt;Clone the repo&lt;/a&gt; contain the Azure DevOps Extension.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The testing cycle for <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Release Notes Templates</a> can be slow, requiring a build and release cycle. To try to speed this process for users I have created a local test harness that allows the same calls to be made from a development machine as would be made within a build or release.</p>
<p>However, running this is not as simple was you might expect so please read the instruction before proceeding.</p>
<h3 id="setup-and-build">Setup and Build</h3>
<ol>
<li>
<p><a href="https://github.com/rfennell/AzurePipelines">Clone the repo</a> contain the Azure DevOps Extension.</p>
</li>
<li>
<p>Change to the folder</p>
<p>_<repo root>ExtensionsXplatGenerateReleaseNotesV2testconsole</p>
<p>_</p>
</li>
<li>
<p>Build the tool using NPM (this does assume <a href="https://nodejs.org/en/download/_">Node</a> is already installed)</p>
<p>_npm install<br>
npm run build</p>
<p>_</p>
</li>
</ol>
<h3 id="running-the-tool">Running the Tool</h3>
<p>The task the testconsole runs takes many parameters, and reads runtime Azure DevOps environment variable. These have to be passing into the local tester. Given the number, and the fact that most probably won&rsquo;t need to be altered, they are provided in settings JSON file. Samples are provided for a build and a release. For details on these parameters see the <a href="https://github.com/rfennell/AzurePipelines/wiki/GenerateReleaseNotes---Node-based-Cross-Platform-Task">task documentation</a></p>
<p>The only values not stored in the JSON files are the PATs required to access the REST API. This reduces the chance of them being copied onto source control by mistake.</p>
<p>Two PATs are potentially used.</p>
<ul>
<li>Azure DevOps PAT (Required) - within a build or release this is automatically picked up. For this tool it must be provided</li>
<li>GitHub PAT - this is an optional parameter for the task, you only need to provide it if working with private GitHub repos as your code store. So usually this can be ignored.</li>
</ul>
<h3 id="test-template-generation-for-a-build">Test Template Generation for a Build</h3>
<p>To run the tool against a build</p>
<ol>
<li>
<p>In the settings file make sure the TeamFoundationCollectionUri, TeamProject and BuildID are set to the build you wish to run against, and that the ReleaseID is empty.</p>
</li>
<li>
<p>Run the command</p>
<p>_node .GenerateReleaseNotesConsoleTester.js build-settings.json <your-Azure-DevOps-PAT> &lt;Optional: your GitHub PAT&gt;</p>
<p>_</p>
</li>
<li>
<p>Assuming you are using the sample settings you should get an output.md file with your release notes.</p>
</li>
</ol>
<h3 id="test-template-generation-for-a-release">Test Template Generation for a Release</h3>
<p>To run the tool against a release is but more complex. This is because the logic looks back to see the most recent successful run. So if your release ran to completion you will get no notes as there has been no changes it it is the last successful release.</p>
<p>You have two options</p>
<ul>
<li>Allow a release  to trigger, but cancel it. You can then use its ReleaseID to compare with the last release</li>
<li>Add a stage to your release this is skipped, only run on a manual request and use this as the comparison stage to look for difference</li>
</ul>
<h3 id="to-run-the-tool">To run the tool</h3>
<ol>
<li>
<p>In the settings file make sure the TeamFoundationCollectionUri, TeamProject, BuildID, EnvironmentName (as stage in your process), ReleaseID and releaseDefinitionId are set for the release you wish to run against.</p>
</li>
<li>
<p>Run the command</p>
<p>_node .GenerateReleaseNotesConsoleTester.js release-settings.json <your-Azure-DevOps-PAT> &lt;Optional: yourGitHub PAT&gt;</p>
<p>_</p>
</li>
<li>
<p>Assuming you are using the sample settings you should get an output.md file with your release notes.</p>
</li>
</ol>
<p>Hope you find it useful</p>
]]></content:encoded>
    </item>
    <item>
      <title>New feature for Cross Platform Release notes - get parent and child work items</title>
      <link>https://blog.richardfennell.net/posts/new-feature-for-cross-platform-release-notes-get-parent-and-child-work-items/</link>
      <pubDate>Sat, 06 Jun 2020 17:44:02 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/new-feature-for-cross-platform-release-notes-get-parent-and-child-work-items/</guid>
      <description>&lt;p&gt;I have added another new feature to my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Cross Platform release note generator&lt;/a&gt;. Now, when using Handlebars based templates you can optionally get the parent or child work items for any work item associated with build/release&lt;/p&gt;
&lt;p&gt;To enable the feature, as it is off by default, you need to set the  &lt;strong&gt;getParentsAndChildren: true&lt;/strong&gt; parameter for the task, either in YAML or in the handlebars section of the configuration.&lt;/p&gt;
&lt;p&gt;This will add an extra array that the template can access &lt;strong&gt;relatedWorkItems&lt;/strong&gt;. This contains all the work items associated with the build/release plus their direct parents and children. This can then be accessed in the template&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have added another new feature to my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform release note generator</a>. Now, when using Handlebars based templates you can optionally get the parent or child work items for any work item associated with build/release</p>
<p>To enable the feature, as it is off by default, you need to set the  <strong>getParentsAndChildren: true</strong> parameter for the task, either in YAML or in the handlebars section of the configuration.</p>
<p>This will add an extra array that the template can access <strong>relatedWorkItems</strong>. This contains all the work items associated with the build/release plus their direct parents and children. This can then be accessed in the template</p>
<pre tabindex="0"><code>{{#forEach this.workItems}}

{{#if isFirst}}### WorkItems {{/if}}

\* \*\*{{this.id}}\*\*  {{lookup this.fields &#39;System.Title&#39;}}

\- \*\*WIT\*\* {{lookup this.fields &#39;System.WorkItemType&#39;}} 

\- \*\*Tags\*\* {{lookup this.fields &#39;System.Tags&#39;}}

\- \*\*Assigned\*\* {{#with (lookup this.fields &#39;System.AssignedTo&#39;)}} {{displayName}} {{/with}}

\- \*\*Description\*\* {{{lookup this.fields &#39;System.Description&#39;}}}

\- \*\*Parents\*\*

{{#forEach this.relations}}

{{#if (contains this.attributes.name &#39;Parent&#39;)}}

{{#with (lookup\_a\_work\_item ../../relatedWorkItems  this.url)}}

      - {{this.id}} - {{lookup this.fields &#39;System.Title&#39;}} 

{{/with}}

{{/if}}

{{/forEach}} 

\- \*\*Children\*\*

{{#forEach this.relations}}

{{#if (contains this.attributes.name &#39;Child&#39;)}}

{{#with (lookup\_a\_work\_item ../../relatedWorkItems  this.url)}}

      - {{this.id}} - {{lookup this.fields &#39;System.Title&#39;}} 

{{/with}}

{{/if}}

{{/forEach}} 

{{/forEach}} 
</code></pre><p>This is a complex way to present the extra work items, but very flexible.</p>
<p>Hope people find the new feature useful.</p>
]]></content:encoded>
    </item>
    <item>
      <title>And another new feature for my Cross Platform Release Notes Azure DevOps Task - commit/changeset file details</title>
      <link>https://blog.richardfennell.net/posts/and-another-new-feature-for-my-cross-platform-release-notes-azure-devops-task-commit-changeset-file-details/</link>
      <pubDate>Wed, 20 May 2020 20:15:47 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/and-another-new-feature-for-my-cross-platform-release-notes-azure-devops-task-commit-changeset-file-details/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2020/03/11/a-major-new-feature-for-my-cross-platform-release-notes-azure-devops-pipelines-extension-handlebars-templating-support/&#34;&gt;addition of Handlebars based templating&lt;/a&gt; for my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Cross Platform Release Notes Task&lt;/a&gt; has certainly made it much easier to release new features. The legacy templating model it seem is what had been holding development back.&lt;/p&gt;
&lt;p&gt;In the past month or so I have added support for generating release notes based on PRs and Tests. I am now happy to say I have just added support for the actual files associated with a commit or changeset.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The <a href="https://blogs.blackmarble.co.uk/rfennell/2020/03/11/a-major-new-feature-for-my-cross-platform-release-notes-azure-devops-pipelines-extension-handlebars-templating-support/">addition of Handlebars based templating</a> for my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Task</a> has certainly made it much easier to release new features. The legacy templating model it seem is what had been holding development back.</p>
<p>In the past month or so I have added support for generating release notes based on PRs and Tests. I am now happy to say I have just added support for the actual files associated with a commit or changeset.</p>
<p>Enriching the commit/changeset data with the details of the files edited has been a repeated request over the years. The basic commit/changeset object only detailed the commit message and the author. With this new release of my task there is now a .<strong>changes</strong> property on the <strong>commit</strong> objects that exposes the details of the actual files in the commit/changeset.</p>
<p>This is used in Handlebars based template as follows</p>
<pre tabindex="0"><code># Global list of CS ({{commits.length}})
{{#forEach commits}}
{{#if isFirst}}### Associated commits{{/if}}
* ** ID{{this.id}}** 
   -  **Message:** {{this.message}}
   -  **Commited by:** {{this.author.displayName}} 
   -  **FileCount:** {{this.changes.length}} 
{{#forEach this.changes}}
      -  **File path (use this for TFVC or TfsGit):** {{this.item.path}}  
      -  **File filename (using this for GitHub):** {{this.filename}}  
      -  **this will show all the properties available for file):** {{json this}}  
{{/forEach}}. 
{{/forEach}}
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Another feature for my Cross Platform Release Notes Azure DevOps Extension&amp;ndash;access to test results</title>
      <link>https://blog.richardfennell.net/posts/another-feature-for-my-cross-platform-release-notes-azure-devops-extension-access-to-test-results/</link>
      <pubDate>Mon, 18 May 2020 13:20:16 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/another-feature-for-my-cross-platform-release-notes-azure-devops-extension-access-to-test-results/</guid>
      <description>&lt;p&gt;Over the weekend I got another new feature for my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Cross Platform Release Notes Azure DevOps Extension&lt;/a&gt; working. The test results associated with build artefacts or releases are now exposed to Handlebars based templates.&lt;/p&gt;
&lt;p&gt;The new objects you can access are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In builds&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tests – all the test run as part of current build&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In releases&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tests – all the test run as part of any current build artefacts or previous to the running of the release notes task within a release environment&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Over the weekend I got another new feature for my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Azure DevOps Extension</a> working. The test results associated with build artefacts or releases are now exposed to Handlebars based templates.</p>
<p>The new objects you can access are:</p>
<ul>
<li>
<p>In builds</p>
</li>
<li>
<p>tests – all the test run as part of current build</p>
</li>
<li>
<p>In releases</p>
</li>
<li>
<p>tests – all the test run as part of any current build artefacts or previous to the running of the release notes task within a release environment</p>
</li>
<li>
<p>releaseTests – all the test run within a release environment</p>
</li>
<li>
<p>builds.test - all the test run as part of any build artefacts group by build artefact</p>
</li>
</ul>
<p>These can be used as follows in a release template</p>
<pre tabindex="0"><code>\# Builds with associated WI/CS/Tests ({{builds.length}})

{{#forEach builds}}

{{#if isFirst}}## Builds {{/if}}

##  Build {{this.build.buildNumber}}

{{#forEach this.commits}}

{{#if isFirst}}### Commits {{/if}}

\- CS {{this.id}}

{{/forEach}}

{{#forEach this.workitems}}

{{#if isFirst}}### Workitems {{/if}}

\- WI {{this.id}}

{{/forEach}} 

{{#forEach this.tests}}

{{#if isFirst}}### Tests {{/if}}

\- Test {{this.id}} 

\-  Name: {{this.testCase.name}}

\-  Outcome: {{this.outcome}}

{{/forEach}} 

{{/forEach}}

  

\# Global list of tests ({{tests.length}})

{{#forEach tests}}

{{#if isFirst}}### Tests {{/if}}

\* \*\* ID{{this.id}}\*\* 

\-  Name: {{this.testCase.name}}

\-  Outcome: {{this.outcome}}

{{/forEach}}

  
</code></pre><p>For more details see the <a href="https://github.com/rfennell/AzurePipelines/wiki/GenerateReleaseNotes---Node-based-Cross-Platform-Task">documentation in the WIKI</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Announcing the deprecation of my Azure DevOps Pester Extension as it has been migrated to the Pester Project and republished under a new ID</title>
      <link>https://blog.richardfennell.net/posts/announcing-the-deprecation-of-my-azure-devops-pester-extension-as-it-has-been-migrated-to-the-pester-project-and-republished-under-a-new-id/</link>
      <pubDate>Sun, 03 May 2020 13:14:05 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/announcing-the-deprecation-of-my-azure-devops-pester-extension-as-it-has-been-migrated-to-the-pester-project-and-republished-under-a-new-id/</guid>
      <description>&lt;p&gt;Back in early 2016 I wrote an &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-PesterRunner-Task&#34;&gt;Azure DevOps Extension to wrapper Pester&lt;/a&gt;, the Powershell unit testing tool. Over the years I updated it, and then passed the support of it over to someone who knows much more about Powershell and Pester than I &lt;a href=&#34;https://github.com/ChrisLGardner&#34;&gt;Chris Gardner&lt;/a&gt; who continued to develop it.&lt;/p&gt;
&lt;p&gt;With the advent of cross-platform Powershell Core we realized that the current extension implementation had a fundamental limitation. Azure DevOps Tasks can only be executed by the agent using the Windows version of Powershell or Node. There is no option for execution by Powershell Core, and probably never will be. As Pester is now supported by Powershell Core this was a serious limitation.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Back in early 2016 I wrote an <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-PesterRunner-Task">Azure DevOps Extension to wrapper Pester</a>, the Powershell unit testing tool. Over the years I updated it, and then passed the support of it over to someone who knows much more about Powershell and Pester than I <a href="https://github.com/ChrisLGardner">Chris Gardner</a> who continued to develop it.</p>
<p>With the advent of cross-platform Powershell Core we realized that the current extension implementation had a fundamental limitation. Azure DevOps Tasks can only be executed by the agent using the Windows version of Powershell or Node. There is no option for execution by Powershell Core, and probably never will be. As Pester is now supported by Powershell Core this was a serious limitation.</p>
<p>To get around this problem <a href="https://blogs.blackmarble.co.uk/rfennell/2019/12/28/a-technique-for-porting-powershell-based-azure-devops-extensions-to-node-so-they-can-be-run-cross-platform-without-a-complete-re-write/">I wrote a Node wrapper</a> to allow the existing Powershell task to be executed using Node, by running a Node script then shelling out to Powershell or Powershell Core. A technique I have since used to make other extensions of mine cross-platform</p>
<p>Around this time we started to discuss whether my <a href="https://github.com/rfennell/AzurePipelines">GitHub repo</a> was really the best home for this Pester extension, and in the decided that this major update to provide cross-platform support was a good point to move it a new home under the ownership of <a href="https://github.com/pester">Pester Project</a>.</p>
<p>So, given all that history, I am really pleased to say that I am deprecating my Pester Extension and adding instructions that though my extension is not going away and will continue to work as it currently does, it will not be updated again and all users should consider swapping over to the <a href="https://marketplace.visualstudio.com/items?itemName=Pester.PesterRunner">new cross-platform version of the extension</a> that is the next generation of same code base but now owned and maintained by the Pester project (well still Chris in reality).</p>
<p>Unfortunately, Azure DevOps provides no way to migrate ownership of an extension. So to swap to the new version will require some work. If you are using YAML the conversion is only a case of changing the task name/id. If you are using the UI based builds or release you need to add the new task and do some copy typing of parameters. The good news is that all the parameter options remain the same so it should be a quick job.</p>
<p>Also please note that any outstanding issues, not fixed in the new release, have been migrated over to the extensions now home, they have not been forgotten.</p>
<p>So hope you all like the new enhanced version of the Pester Extension and thanks to Chris for sorting the migration and all his work support it.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Fix for &amp;lsquo;System.BadImageFormatException&amp;rsquo; when running x64 based tests inside a Azure DevOps Release</title>
      <link>https://blog.richardfennell.net/posts/fix-for-system-badimageformatexception-when-running-x64-based-tests-inside-a-azure-devops-release/</link>
      <pubDate>Thu, 23 Apr 2020 10:05:35 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/fix-for-system-badimageformatexception-when-running-x64-based-tests-inside-a-azure-devops-release/</guid>
      <description>&lt;p&gt;&lt;em&gt;This is one of those blog posts I write to remind my future self how I fixed a problem.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&#34;the-problem&#34;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;I have a release that installs VSTest and runs some integration tests that target .NET 4.6 x64. All these tests worked fine in Visual Studio. However, I got the following errors for all tests when they were run in a release&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2020-04-23T09:30:38.7544708Z vstest.console.exe &amp;#34;C:agent\_workr1aPaymentServicesdroptestartifactsPaymentService.IntegrationTests.dll&amp;#34;

2020-04-23T09:30:38.7545688Z /Settings:&amp;#34;C:agent\_work\_tempuxykzf03ik2.tmp.runsettings&amp;#34;

2020-04-23T09:30:38.7545808Z /Logger:&amp;#34;trx&amp;#34;

2020-04-23T09:30:38.7545937Z /TestAdapterPath:&amp;#34;C:agent\_workr1aPaymentServicesdroptestartifacts&amp;#34;

2020-04-23T09:30:39.2634578Z Starting test execution, please wait...

2020-04-23T09:30:39.4783658Z A total of 1 test files matched the specified pattern.

2020-04-23T09:30:40.8660112Z   X Can\_Get\_MIDs \[521ms\]

2020-04-23T09:30:40.8684249Z   Error Message:

2020-04-23T09:30:40.8684441Z    Test method PaymentServices.IntegrationTests.ControllerMIDTests.Can\_Get\_MIDs threw exception: 

2020-04-23T09:30:40.8684574Z System.BadImageFormatException: Could not load file or assembly &amp;#39;PaymentServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&amp;#39; or one of its dependencies. An attempt was made to load a program with an incorrect format.

2020-04-23T09:30:40.8684766Z   Stack Trace:

2020-04-23T09:30:40.8684881Z       at PaymentServices.IntegrationTests.ControllerMIDTests.Can\_Get\_MIDs()

…

2020-04-23T09:30:40.9038788Z Results File: C:agent\_work\_tempTestResultssvc-devops\_SVRHQAPP027\_2020-04-23\_10\_30\_40.trx

2020-04-23T09:30:40.9080344Z Total tests: 22

2020-04-23T09:30:40.9082348Z      Failed: 22

2020-04-23T09:30:40.9134858Z ##\[error\]Test Run Failed.
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;solution&#34;&gt;Solution&lt;/h3&gt;
&lt;p&gt;I needed to tell &lt;strong&gt;vstest.console.exe&lt;/strong&gt; to run x64 as opposed to it’s default of x32. This can be done with a command line override &lt;strong&gt;–platform:x64&lt;/strong&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><em>This is one of those blog posts I write to remind my future self how I fixed a problem.</em></p>
<h3 id="the-problem">The Problem</h3>
<p>I have a release that installs VSTest and runs some integration tests that target .NET 4.6 x64. All these tests worked fine in Visual Studio. However, I got the following errors for all tests when they were run in a release</p>
<pre tabindex="0"><code>2020-04-23T09:30:38.7544708Z vstest.console.exe &#34;C:agent\_workr1aPaymentServicesdroptestartifactsPaymentService.IntegrationTests.dll&#34;

2020-04-23T09:30:38.7545688Z /Settings:&#34;C:agent\_work\_tempuxykzf03ik2.tmp.runsettings&#34;

2020-04-23T09:30:38.7545808Z /Logger:&#34;trx&#34;

2020-04-23T09:30:38.7545937Z /TestAdapterPath:&#34;C:agent\_workr1aPaymentServicesdroptestartifacts&#34;

2020-04-23T09:30:39.2634578Z Starting test execution, please wait...

2020-04-23T09:30:39.4783658Z A total of 1 test files matched the specified pattern.

2020-04-23T09:30:40.8660112Z   X Can\_Get\_MIDs \[521ms\]

2020-04-23T09:30:40.8684249Z   Error Message:

2020-04-23T09:30:40.8684441Z    Test method PaymentServices.IntegrationTests.ControllerMIDTests.Can\_Get\_MIDs threw exception: 

2020-04-23T09:30:40.8684574Z System.BadImageFormatException: Could not load file or assembly &#39;PaymentServices, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&#39; or one of its dependencies. An attempt was made to load a program with an incorrect format.

2020-04-23T09:30:40.8684766Z   Stack Trace:

2020-04-23T09:30:40.8684881Z       at PaymentServices.IntegrationTests.ControllerMIDTests.Can\_Get\_MIDs()

…

2020-04-23T09:30:40.9038788Z Results File: C:agent\_work\_tempTestResultssvc-devops\_SVRHQAPP027\_2020-04-23\_10\_30\_40.trx

2020-04-23T09:30:40.9080344Z Total tests: 22

2020-04-23T09:30:40.9082348Z      Failed: 22

2020-04-23T09:30:40.9134858Z ##\[error\]Test Run Failed.
</code></pre><h3 id="solution">Solution</h3>
<p>I needed to tell <strong>vstest.console.exe</strong> to run x64 as opposed to it’s default of x32. This can be done with a command line override <strong>–platform:x64</strong></p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/04/image-1.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/04/image_thumb-1.png" title="image"></a></p>
]]></content:encoded>
    </item>
    <item>
      <title>I decided to create a video of my blog post on Multistage YAML pipelines</title>
      <link>https://blog.richardfennell.net/posts/i-decided-to-create-a-video-of-my-blog-post-on-multistage-yaml-pipelines/</link>
      <pubDate>Wed, 22 Apr 2020 11:42:48 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/i-decided-to-create-a-video-of-my-blog-post-on-multistage-yaml-pipelines/</guid>
      <description>&lt;p&gt;I decided to create a video of my blog post ‘&lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2020/04/07/swapping-my-azure-devops-pipeline-extensions-release-process-to-use-multistage-yaml-pipelines/&#34;&gt;Swapping my Azure DevOps Pipeline Extensions release process to use Multistage YAML pipelines’&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;[iframe width=&amp;ldquo;560&amp;rdquo; height=&amp;ldquo;315&amp;rdquo; src=&amp;ldquo;&lt;a href=&#34;https://www.youtube.com/embed/WMQ0G9eXczE%22&#34;&gt;https://www.youtube.com/embed/WMQ0G9eXczE&#34;&lt;/a&gt; frameborder=&amp;ldquo;0&amp;rdquo; allowfullscreen=&amp;rdquo;&amp;quot; allow=&amp;ldquo;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&amp;rdquo;]&lt;/p&gt;
&lt;p&gt;The video up on &lt;a href=&#34;https://bit.ly/MigratetoYAML&#34;&gt;YouTube&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I decided to create a video of my blog post ‘<a href="https://blogs.blackmarble.co.uk/rfennell/2020/04/07/swapping-my-azure-devops-pipeline-extensions-release-process-to-use-multistage-yaml-pipelines/">Swapping my Azure DevOps Pipeline Extensions release process to use Multistage YAML pipelines’</a>.</p>
<p>[iframe width=&ldquo;560&rdquo; height=&ldquo;315&rdquo; src=&ldquo;<a href="https://www.youtube.com/embed/WMQ0G9eXczE%22">https://www.youtube.com/embed/WMQ0G9eXczE"</a> frameborder=&ldquo;0&rdquo; allowfullscreen=&rdquo;&quot; allow=&ldquo;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&rdquo;]</p>
<p>The video up on <a href="https://bit.ly/MigratetoYAML">YouTube</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>And more  enriching the data available in my Azure DevOps Pipelines Cross Platform Release Notes Task</title>
      <link>https://blog.richardfennell.net/posts/and-more-enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/</link>
      <pubDate>Tue, 21 Apr 2020 16:42:46 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/and-more-enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/</guid>
      <description>&lt;p&gt;I have today released another enrichment to the dataset available in my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Cross Platform Release Notes Azure Pipeline Task&lt;/a&gt;. It now returns an extra array of data that links work items and commits to build artifacts.&lt;/p&gt;
&lt;p&gt;So your reporting objects are:&lt;/p&gt;
&lt;h3 id=&#34;array-objects&#34;&gt;Array Objects&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;workItems – the array of all work item associated with the release&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;commits – the array of all commits associated with the release&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;pullRequests - the array of all PRs referenced by the commits in the release&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have today released another enrichment to the dataset available in my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Azure Pipeline Task</a>. It now returns an extra array of data that links work items and commits to build artifacts.</p>
<p>So your reporting objects are:</p>
<h3 id="array-objects">Array Objects</h3>
<ul>
<li>
<p>workItems – the array of all work item associated with the release</p>
</li>
<li>
<p>commits – the array of all commits associated with the release</p>
</li>
<li>
<p>pullRequests - the array of all PRs referenced by the commits in the release</p>
</li>
<li>
<p><strong>The new one</strong> - builds - the array of the build artifacts that CS and WI are associated with. Note that this is a object with three properties</p>
</li>
<li>
<p>build - the build details</p>
</li>
<li>
<p>commits - the commits associated with this build</p>
</li>
<li>
<p>workitems - the work items associated with the build</p>
</li>
</ul>
<h3 id="release-objects-only-available-in-a-release">Release objects (only available in a release)</h3>
<ul>
<li>releaseDetails – the release details of the release that the task was triggered for.</li>
<li>compareReleaseDetails - the the previous successful release that comparisons are being made against</li>
</ul>
<h3 id="build-objects">Build objects</h3>
<ul>
<li>buildDetails – if running in a build, the build details of the build that the task is running in. If running in a release it is the build that triggered the release.</li>
</ul>
<p><strong>Note:</strong> To dump all possible values use the form {{json propertyToDump}} this runs a custom Handlebars extension to do the expansion</p>
<p>It is important to realised that these arrays are only available using the Handlebars form of templating. You can find sample <a href="https://github.com/rfennell/AzurePipelines/tree/master/SampleTemplates/XplatGenerateReleaseNotes%20%28Node%20based%29/Version%202/Handlbars">here</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Further enriching the data available in my Azure DevOps Pipelines Cross Platform Release Notes Task</title>
      <link>https://blog.richardfennell.net/posts/further-enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/</link>
      <pubDate>Wed, 15 Apr 2020 16:01:57 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/further-enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/</guid>
      <description>&lt;p&gt;I recently post about &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2020/04/04/enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/&#34;&gt;Enriching the data available in my Azure DevOps Pipelines Cross Platform Release Notes Task&lt;/a&gt; by adding Pull Request information. Well, that first release was fairly limited only working for PR validation builds, so I have made more improvements and shipped a newer version.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;task&lt;/a&gt; now will, as well as checking for PR build trigger, try to associate the commits associated with a build/release pipeline to any completed PRs in the repo. This is done using the Last Merge Commit ID, and from my tests seems to work for the various types of PR e.g. squash, merge, rebased and semi-linear.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I recently post about <a href="https://blogs.blackmarble.co.uk/rfennell/2020/04/04/enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/">Enriching the data available in my Azure DevOps Pipelines Cross Platform Release Notes Task</a> by adding Pull Request information. Well, that first release was fairly limited only working for PR validation builds, so I have made more improvements and shipped a newer version.</p>
<p>The <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">task</a> now will, as well as checking for PR build trigger, try to associate the commits associated with a build/release pipeline to any completed PRs in the repo. This is done using the Last Merge Commit ID, and from my tests seems to work for the various types of PR e.g. squash, merge, rebased and semi-linear.</p>
<p>The resultant set of PRs are made available to the release notes template processor as an array. However, there is a difference between the existing arrays for Work Items and Commits and the new one for Pull requests. The new one is only available if you are using the <a href="https://blogs.blackmarble.co.uk/rfennell/2020/03/11/a-major-new-feature-for-my-cross-platform-release-notes-azure-devops-pipelines-extension-handlebars-templating-support/">new Handlebars based templating mode</a>.</p>
<p>You would add a block in the general form….</p>
<pre tabindex="0"><code>{{#forEach pullRequests}}  
{{#if isFirst}}### Associated Pull Requests (only shown if  PR) {{/if}}  
\*  \*\*PR {{this.id}}\*\*  {{this.title}}  
{{/forEach}}
</code></pre><pre tabindex="0"><code>
The reason I have chosen to only support Handlebars is it make the development so much easier and provides a more flexible solution, given all the Handlebar helpers available. I think this might be the first tentative step towards deprecating my legacy templating solution in favour of only shipping Handlebars support.
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Swapping my Azure DevOps Pipeline Extensions release process to use Multistage YAML pipelines</title>
      <link>https://blog.richardfennell.net/posts/swapping-my-azure-devops-pipeline-extensions-release-process-to-use-multistage-yaml-pipelines/</link>
      <pubDate>Tue, 07 Apr 2020 10:55:34 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/swapping-my-azure-devops-pipeline-extensions-release-process-to-use-multistage-yaml-pipelines/</guid>
      <description>&lt;p&gt;In the past I have &lt;a href=&#34;https://github.com/rfennell/AzurePipelines/wiki/Outlining-my-Azure-DevOps-CI-CD-Process-using-UI-based-tools&#34;&gt;documented the build and release process I use for my Azure DevOps Pipeline Extensions&lt;/a&gt; and also detailed how I have started &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2019/04/26/migrating-a-gui-based-build-to-yaml-in-azure-devops-pipelines/&#34;&gt;to move the build phases to YAML&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Well now I consider that &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;amp;tabs=yaml&#34;&gt;multistage YAML pipelines&lt;/a&gt; are mature enough to allow me to do my whole release pipeline in YAML, hence this post.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/04/image.png&#34;&gt;&lt;img alt=&#34;image&#34; loading=&#34;lazy&#34; src=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/04/image_thumb.png&#34; title=&#34;image&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;My pipeline performs a number of stages, &lt;a href=&#34;https://github.com/rfennell/AzurePipelines/blob/master/Extensions/ArtifactDescription/azure-pipelines.yml&#34;&gt;you can find a sample pipeline here&lt;/a&gt;. Note that I have made every effort to extract variables into variable groups to aid reuse of the pipeline definition. I have added documentation as to where variable are stored and what they are used for.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In the past I have <a href="https://github.com/rfennell/AzurePipelines/wiki/Outlining-my-Azure-DevOps-CI-CD-Process-using-UI-based-tools">documented the build and release process I use for my Azure DevOps Pipeline Extensions</a> and also detailed how I have started <a href="https://blogs.blackmarble.co.uk/rfennell/2019/04/26/migrating-a-gui-based-build-to-yaml-in-azure-devops-pipelines/">to move the build phases to YAML</a>.</p>
<p>Well now I consider that <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;tabs=yaml">multistage YAML pipelines</a> are mature enough to allow me to do my whole release pipeline in YAML, hence this post.</p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/04/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/04/image_thumb.png" title="image"></a></p>
<p>My pipeline performs a number of stages, <a href="https://github.com/rfennell/AzurePipelines/blob/master/Extensions/ArtifactDescription/azure-pipelines.yml">you can find a sample pipeline here</a>. Note that I have made every effort to extract variables into variable groups to aid reuse of the pipeline definition. I have added documentation as to where variable are stored and what they are used for.</p>
<p>The stages are as follows</p>
<h3 id="build">Build</h3>
<p>The build phase does the following</p>
<ul>
<li>
<p>Updates all the TASK.JSON files so that the help text has the correct version number</p>
</li>
<li>
<p>Calls a <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops">YAML template</a> (<a href="https://github.com/rfennell/AzurePipelines/blob/master/YAMLTemplates/build-node-task.yml">build-Node-task</a>) that performs all the tasks to transpile a TypeScript based task – if my extension contained multiple tasks this template would be called a number of time</p>
</li>
<li>
<p>Get NPM packages</p>
</li>
<li>
<p>Run <a href="https://marketplace.visualstudio.com/items?itemName=Snyk.snyk-security-scan">Snyk</a> to check for vulnerabilities – if any vulnerabilities are found the build fails</p>
</li>
<li>
<p>Lint and Transpile the TypeScript – if any issue are found the build fails</p>
</li>
<li>
<p>Run any Unit test and publish results – if any test fail the build fails</p>
</li>
<li>
<p>Package up the task (remove dev dependencies)</p>
</li>
<li>
<p>Download the TFX client</p>
</li>
<li>
<p>Package up the Extension VSIX package and publish as a pipeline artifact.</p>
</li>
</ul>
<h3 id="private">Private</h3>
<p>The private phase does the following</p>
<ul>
<li>
<p>Using another YAML template (<a href="https://github.com/rfennell/AzurePipelines/blob/master/YAMLTemplates/publish-extension.yml">publish-extension</a>) publish the extension to the <a href="https://marketplace.visualstudio.com/search?term=fennell&amp;target=AzureDevOps&amp;category=Azure%20Pipelines&amp;sortBy=Relevance">Azure DevOps Marketplace</a>, but with flags so it is private and only assessible to my account for testing</p>
</li>
<li>
<p>Download the TFX client</p>
</li>
<li>
<p>Publishes the Extension to the Marketplace</p>
</li>
</ul>
<p>This phase is done as a <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/deployment-jobs?view=azure-devops">deployment job</a> and is linked to an environment,. However, there are no special approval requirements are set on this environment. This is because I am happy for the release to be done to the private instance assuming the build phase complete without error.</p>
<h3 id="test">Test</h3>
<p>This is where the pipeline gets interesting. The test phase does the following</p>
<ul>
<li>Runs any integration tests. These could be anything dependant on the extension being deployed. Unfortunately there is no option at present in multistage pipeline for a manual task to say ‘do the manual tests’, but you could simulate similar by sending an email or the like.</li>
</ul>
<p>The clever bit here is that I don’t want this stage to run until the new private version of the extension has been published and is available; there can be a delay between TFX saying the extension is published and it being downloadable by an agent. This can cause a problem in that you think you are running tests against a different version of the extension to one you have. To get around this problem I have implemented a <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/approvals?view=azure-devops&amp;tabs=check-pass">check on the environment</a> this stage’s deployment job is linked to. This check runs an Azure Function to check the version of the extension in the Marketplace. This is <a href="https://blogs.blackmarble.co.uk/rfennell/2018/03/20/using-vsts-gates-to-help-improve-my-deployment-pipeline-of-vsts-extensions-to-the-visual-studio-marketplace/">exactly the same Azure Function I already used in my UI based pipelines to perform the same job</a>.</p>
<p>The only issue here is that this Azure Function is used as an exit gate in my UI based pipelines; to not allow the pipeline to exit the private stage until the extension is publish. I cannot do this in a multistage YAML pipeline as environment checks are only done on entry to the environment. This means I have had to use an extra Test stage to associate the entry check with. This was setup as follows</p>
<ul>
<li>
<p>Create a new environment</p>
</li>
<li>
<p>Click the ellipse (…) and pick ‘approvals and checks’</p>
</li>
<li>
<p>Add a new Azure Function check</p>
</li>
<li>
<p>Provide the details, documented in my <a href="https://blogs.blackmarble.co.uk/rfennell/2018/03/20/using-vsts-gates-to-help-improve-my-deployment-pipeline-of-vsts-extensions-to-the-visual-studio-marketplace/">previous post</a>, to link to your Azure Function. Note that you can, in the ’control options’ section of the configuration, link to a variable group. This is a good place to store all the values, you need to provide</p>
</li>
<li>
<p>URL of the Azure Function</p>
</li>
<li>
<p>Key to us the function</p>
</li>
<li>
<p>The function header</p>
</li>
<li>
<p>The body – this one is interesting. You need to provide the build number and the GUID of a task in the extension for my Azure Function. It would be really good if both of these could be picked up from the pipeline trying to use the environment. This would allow a single ‘test’ environment to be created for use by all my extensions, in the same way there are only a single ‘private’ and ‘public’ environment. However, there is a problem, the build number is picked up OK, but as far as I can see I cannot access custom pipeline variables, so cannot get the task GUID I need dynamically. I assume this is because this environment entry check is run outside of the pipeline. The only solution  can find is to place the task GUID as a hard coded value in the check declaration (or I suppose in the variable group). The downside of this is it means I have to have an environment dedicated to each extension, each with a different task GUID. Not perfect, but not too much of a problem</p>
</li>
<li>
<p>In the Advanced check the check logic</p>
</li>
<li>
<p>In control options link to the variable group contain any variables used.</p>
</li>
</ul>
<h3 id="documentation">Documentation</h3>
<p>The documentation stage again uses a template (<a href="https://github.com/rfennell/AzurePipelines/blob/master/YAMLTemplates/generate-wiki-docs.yml">generate-wiki-docs</a>) and does the following</p>
<ul>
<li>Use the extension and task manifest files to generate YAML usage documentation <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-YAMLGenerator">using one of my tasks</a></li>
<li>Uploads the extension readme file to a WIKI <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-WIKIUpdater-Tasks">using another of my tasks</a></li>
<li>Uploads the extension YAML usage file to a WIKI</li>
</ul>
<h3 id="public">Public</h3>
<p>The public stage is also a deployment job and linked to an environment. This environment has an approval set so I have to approve any release of the public version of the extension.</p>
<p>As well as doing the same as private stage this stage does the following</p>
<ul>
<li>Same a private stage</li>
<li>Send a Tweet saying I have release a new version of the extension using my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-ArtifactDescription-Tasks">Artifact Description</a> extension to get the text of the PR</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-BuildUpdating-Tasks">Update the pipelines minor build number variable</a> to make sure then I next release I have a higher build number</li>
</ul>
<h3 id="summary">Summary</h3>
<p>It took a bit of trial and error to get this going, but I think I have a good solution now. The fact that the bulk of the work is done using shared templates means I should get good reuse of the work I have done. I am sure I will be able to improve the template as time goes on but it is a good start</p>
]]></content:encoded>
    </item>
    <item>
      <title>My Azure DevOps Pipeline is not triggering on a GitHub Pull request - fixed</title>
      <link>https://blog.richardfennell.net/posts/my-azure-devops-pipeline-is-not-triggering-on-a-github-pull-request-fixed/</link>
      <pubDate>Tue, 07 Apr 2020 09:41:06 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/my-azure-devops-pipeline-is-not-triggering-on-a-github-pull-request-fixed/</guid>
      <description>&lt;p&gt;I have recently hit a problem that some of my Azure DevOps YAML pipelines, that I use to build my Azure DevOps Pipeline Extensions, are not triggering on a new PR being created on GitHub.&lt;/p&gt;
&lt;p&gt;I did not get to the bottom of why this is happening, but I found a fix.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check and of make a note of any UI declared variables in your Azure DevOps YAML Pipeline that is not triggering&lt;/li&gt;
&lt;li&gt;Delete the pipeline&lt;/li&gt;
&lt;li&gt;Re-add the pipeline, linking to the YAML file hosted on GitHub. You might be asked to re-authorise the link between Azure DevOps Pipelines and GitHub.&lt;/li&gt;
&lt;li&gt;Re-enter any variables that are declared via the Pipelines UI and save the changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Your pipeline should start to be triggered again&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have recently hit a problem that some of my Azure DevOps YAML pipelines, that I use to build my Azure DevOps Pipeline Extensions, are not triggering on a new PR being created on GitHub.</p>
<p>I did not get to the bottom of why this is happening, but I found a fix.</p>
<ul>
<li>Check and of make a note of any UI declared variables in your Azure DevOps YAML Pipeline that is not triggering</li>
<li>Delete the pipeline</li>
<li>Re-add the pipeline, linking to the YAML file hosted on GitHub. You might be asked to re-authorise the link between Azure DevOps Pipelines and GitHub.</li>
<li>Re-enter any variables that are declared via the Pipelines UI and save the changes</li>
</ul>
<p>Your pipeline should start to be triggered again</p>
]]></content:encoded>
    </item>
    <item>
      <title>Enriching the data available in my Azure DevOps Pipelines Cross Platform Release Notes Task</title>
      <link>https://blog.richardfennell.net/posts/enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/</link>
      <pubDate>Sat, 04 Apr 2020 12:06:01 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/enriching-the-data-available-in-my-azure-devops-pipelines-cross-platform-release-notes-task/</guid>
      <description>&lt;p&gt;A common request for my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Generate Release Notes Tasks&lt;/a&gt; is to enrich the data available beyond basic build, work item and commit/changeset details. I have resisted these requests as it felt like a never ending journey to start. However, I have now relented and added the option to see any pull request information available.&lt;/p&gt;
&lt;p&gt;This feature is limited, you obviously have to be using artifacts that linked to a Git repo, and also the Git repo have to on an Azure DevOps hosted repository. This won’t meet everyone’s needs but it is a start.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A common request for my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Generate Release Notes Tasks</a> is to enrich the data available beyond basic build, work item and commit/changeset details. I have resisted these requests as it felt like a never ending journey to start. However, I have now relented and added the option to see any pull request information available.</p>
<p>This feature is limited, you obviously have to be using artifacts that linked to a Git repo, and also the Git repo have to on an Azure DevOps hosted repository. This won’t meet everyone’s needs but it is a start.</p>
<h3 id="what-was-already-available">What was already available</h3>
<p>Turns out there was already a means to get a limited set of PR details from a build. You used the form</p>
<pre tabindex="0"><code>\*\*Build Trigger PR Number\*\*: ${buildDetails.triggerInfo\[&#39;pr.number&#39;\]}
</code></pre><p>or in handlebars format</p>
<pre tabindex="0"><code>\*\*Build Trigger PR Number\*\*: {{lookup buildDetails.triggerInfo &#39;pr.number&#39;}} 
</code></pre><h3 id="the-improvements">The improvements</h3>
<p>That said I have improved the options. There is now a new `prDetails` object available to the template.</p>
<p>If you use the dump option</p>
<pre tabindex="0"><code>${JSON.stringify(prDetails)}      
</code></pre><p>You can see the fields available</p>
<pre tabindex="0"><code>{  
     &#34;repository&#34;: {  
         &#34;id&#34;: &#34;bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59&#34;,  
         &#34;name&#34;: &#34;VSTSBuildTaskValidation&#34;,  
         &#34;url&#34;: &#34;[https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/\_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59&#34;](https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59&#34;),  
         &#34;project&#34;: {  
             &#34;id&#34;: &#34;670b3a60-2021-47ab-a88b-d76ebd888a2f&#34;,  
             &#34;name&#34;: &#34;GitHub&#34;,  
             &#34;description&#34;: &#34;A container for GitHub CI/CD processes&#34;,  
             &#34;url&#34;: &#34;[https://richardfennell.visualstudio.com/\_apis/projects/670b3a60-2021-47ab-a88b-d76ebd888a2f&#34;](https://richardfennell.visualstudio.com/_apis/projects/670b3a60-2021-47ab-a88b-d76ebd888a2f&#34;),  
             &#34;state&#34;: &#34;wellFormed&#34;,  
             &#34;revision&#34;: 411511726,  
             &#34;visibility&#34;: 2,  
             &#34;lastUpdateTime&#34;: &#34;2019-10-10T20:35:51.85Z&#34;  
         },  
         &#34;size&#34;: 9373557,  
         &#34;remoteUrl&#34;: &#34;[https://richardfennell.visualstudio.com/DefaultCollection/GitHub/\_git/VSTSBuildTaskValidation&#34;](https://richardfennell.visualstudio.com/DefaultCollection/GitHub/_git/VSTSBuildTaskValidation&#34;),  
         &#34;sshUrl&#34;: &#34;richardfennell@vs-ssh.visualstudio.com:v3/richardfennell/GitHub/VSTSBuildTaskValidation&#34;,  
         &#34;webUrl&#34;: &#34;[https://richardfennell.visualstudio.com/DefaultCollection/GitHub/\_git/VSTSBuildTaskValidation&#34;](https://richardfennell.visualstudio.com/DefaultCollection/GitHub/_git/VSTSBuildTaskValidation&#34;)  
     },  
     &#34;pullRequestId&#34;: 4,  
     &#34;codeReviewId&#34;: 4,  
     &#34;status&#34;: 1,  
     &#34;createdBy&#34;: {  
         &#34;displayName&#34;: &#34;Richard Fennell (Work MSA)&#34;,  
         &#34;url&#34;: &#34;[https://spsprodeus24.vssps.visualstudio.com/Ac0efb61e-a937-42a0-9658-649757d55d46/\_apis/Identities/b1fce0e9-fbf4-4202-bc09-a290def3e98b&#34;](https://spsprodeus24.vssps.visualstudio.com/Ac0efb61e-a937-42a0-9658-649757d55d46/_apis/Identities/b1fce0e9-fbf4-4202-bc09-a290def3e98b&#34;),  
         &#34;\_links&#34;: {  
             &#34;avatar&#34;: {  
                 &#34;href&#34;: &#34;[https://richardfennell.visualstudio.com/\_apis/GraphProfile/MemberAvatars/aad.NzQzY2UyODUtN2Q0Ny03YjNkLTk0ZGUtN2Q0YjA1ZGE5NDdj&#34;](https://richardfennell.visualstudio.com/_apis/GraphProfile/MemberAvatars/aad.NzQzY2UyODUtN2Q0Ny03YjNkLTk0ZGUtN2Q0YjA1ZGE5NDdj&#34;)  
             }  
         },  
         &#34;id&#34;: &#34;b1fce0e9-fbf4-4202-bc09-a290def3e98b&#34;,  
         &#34;uniqueName&#34;: &#34;bm-richard.fennell@outlook.com&#34;,  
         &#34;imageUrl&#34;: &#34;[https://richardfennell.visualstudio.com/\_api/\_common/identityImage?id=b1fce0e9-fbf4-4202-bc09-a290def3e98b&#34;](https://richardfennell.visualstudio.com/_api/_common/identityImage?id=b1fce0e9-fbf4-4202-bc09-a290def3e98b&#34;),  
         &#34;descriptor&#34;: &#34;aad.NzQzY2UyODUtN2Q0Ny03YjNkLTk0ZGUtN2Q0YjA1ZGE5NDdj&#34;  
     },  
     &#34;creationDate&#34;: &#34;2020-04-04T10:44:59.566Z&#34;,  
     &#34;title&#34;: &#34;Added test.txt&#34;,  
     &#34;description&#34;: &#34;Added test.txt&#34;,  
     &#34;sourceRefName&#34;: &#34;refs/heads/branch2&#34;,  
     &#34;targetRefName&#34;: &#34;refs/heads/master&#34;,  
     &#34;mergeStatus&#34;: 3,  
     &#34;isDraft&#34;: false,  
     &#34;mergeId&#34;: &#34;f76a6556-8b4f-44eb-945a-9350124f067b&#34;,  
     &#34;lastMergeSourceCommit&#34;: {  
         &#34;commitId&#34;: &#34;f43fa4de163c3ee0b4f17b72a659eac0d307deb8&#34;,  
         &#34;url&#34;: &#34;[https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/\_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/commits/f43fa4de163c3ee0b4f17b72a659eac0d307deb8&#34;](https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/commits/f43fa4de163c3ee0b4f17b72a659eac0d307deb8&#34;)  
     },  
     &#34;lastMergeTargetCommit&#34;: {  
         &#34;commitId&#34;: &#34;829ab2326201c7a5d439771eef5a57f58f94897d&#34;,  
         &#34;url&#34;: &#34;[https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/\_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/commits/829ab2326201c7a5d439771eef5a57f58f94897d&#34;](https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/commits/829ab2326201c7a5d439771eef5a57f58f94897d&#34;)  
     },  
     &#34;lastMergeCommit&#34;: {  
         &#34;commitId&#34;: &#34;53f393cae4ee3b901bb69858c4ee86cc8b466d6f&#34;,  
         &#34;author&#34;: {  
             &#34;name&#34;: &#34;Richard Fennell (Work MSA)&#34;,  
             &#34;email&#34;: &#34;bm-richard.fennell@outlook.com&#34;,  
             &#34;date&#34;: &#34;2020-04-04T10:44:59.000Z&#34;  
         },  
         &#34;committer&#34;: {  
             &#34;name&#34;: &#34;Richard Fennell (Work MSA)&#34;,  
             &#34;email&#34;: &#34;bm-richard.fennell@outlook.com&#34;,  
             &#34;date&#34;: &#34;2020-04-04T10:44:59.000Z&#34;  
         },  
         &#34;comment&#34;: &#34;Merge pull request 4 from branch2 into master&#34;,  
         &#34;url&#34;: &#34;[https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/\_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/commits/53f393cae4ee3b901bb69858c4ee86cc8b466d6f&#34;](https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/commits/53f393cae4ee3b901bb69858c4ee86cc8b466d6f&#34;)  
     },  
     &#34;reviewers&#34;: \[\],  
     &#34;url&#34;: &#34;[https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/\_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/pullRequests/4&#34;](https://richardfennell.visualstudio.com/670b3a60-2021-47ab-a88b-d76ebd888a2f/_apis/git/repositories/bebd0ae2-405d-4c0a-b9c5-36ea94c1bf59/pullRequests/4&#34;),  
     &#34;supportsIterations&#34;: true,  
     &#34;artifactId&#34;: &#34;vstfs:///Git/PullRequestId/670b3a60-2021-47ab-a88b-d76ebd888a2f%2fbebd0ae2-405d-4c0a-b9c5-36ea94c1bf59%2f4&#34;  
}  

```In templates this new object could be is used  
</code></pre><p>**PR Title **: ${prDetails.title}</p>
<pre tabindex="0"><code>or in handlebars format.
</code></pre><p>**PR Details**: {{prDetails.title}}</p>
<pre tabindex="0"><code>
It will be interesting to here feedback from the real world as opposed to test harnesses
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Experiences setting up Azure Active Directory single sign-on (SSO) integration with GitHub Enterprise</title>
      <link>https://blog.richardfennell.net/posts/experiences-setting-up-azure-active-directory-single-sign-on-sso-integration-with-github-enterprise/</link>
      <pubDate>Mon, 30 Mar 2020 16:29:34 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/experiences-setting-up-azure-active-directory-single-sign-on-sso-integration-with-github-enterprise/</guid>
      <description>&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;
&lt;p&gt;GitHub is a great system for individuals and OSS communities for both public and private project. However, corporate customers commonly want more control over their system than the standard GitHub offering. It is for this reason GitHub offers  &lt;a href=&#34;https://github.com/enterprise&#34;&gt;GitHub Enterprise&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For most corporates, the essential feature that GitHub Enterprise offers is the use Single Sign On (SSO) i.e. allowing users to login to GitHub using their corporate directory accounts.&lt;/p&gt;
&lt;p&gt;I wanted to see how easy this was to setup when you are using Azure Active Directory (AAD).&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="background">Background</h3>
<p>GitHub is a great system for individuals and OSS communities for both public and private project. However, corporate customers commonly want more control over their system than the standard GitHub offering. It is for this reason GitHub offers  <a href="https://github.com/enterprise">GitHub Enterprise</a>.</p>
<p>For most corporates, the essential feature that GitHub Enterprise offers is the use Single Sign On (SSO) i.e. allowing users to login to GitHub using their corporate directory accounts.</p>
<p>I wanted to see how easy this was to setup when you are using Azure Active Directory (AAD).</p>
<p>Luckily there is a <a href="https://docs.microsoft.com/en-us/azure/active-directory/saas-apps/github-tutorial">step by step tutorial from Microsoft</a> on how to set this up. Though, I would say that though detailed this tutorial has a strange structure in that it shows the default values not the correct values. Hence, the tutorial requires close reading, don’t just look at the pictures!</p>
<p>Even with close reading, I still hit a problem, all of my own making, as I went through this tutorial.</p>
<h3 id="the-issue--a-stray--in-a-url">The Issue – a stray / in a URL</h3>
<p>I entered all the AAD URLs and certs as instructed (or so I thought) by the tutorial into the Security page of GitHub Enterprise.</p>
<p>When I pressed the ‘Validate’ button in GitHub, to test the SSO settings, I got an error</p>
<p><em>‘The client has not listed any permissions for &lsquo;AAD Graph&rsquo; in the requested permissions in the client&rsquo;s application registration’</em></p>
<p>This sent me shown a rabbit hole looking at user permissions. That wasted a lot of time.</p>
<p>However, it turns out the issue was that I had a // in a URL when it should have been a  /. This was because I had made a cut and paste error when editing the tutorial’s sample URL and adding my organisation details.</p>
<p>Once I fixed this typo the validation worked, I was able to complete the setup and then I could to invite my AAD users to my GitHub Enterprise organisation.</p>
<h3 id="summary">Summary</h3>
<p>So the summary is, if you follow the tutorial setting up SSO from AAD to GitHub Enterprise is easy enough to do, just be careful of over the detail.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A major new feature for my Cross-platform Release Notes Azure DevOps Pipelines Extension&amp;ndash;Handlebars Templating Support</title>
      <link>https://blog.richardfennell.net/posts/a-major-new-feature-for-my-cross-platform-release-notes-azure-devops-pipelines-extension-handlebars-templating-support/</link>
      <pubDate>Wed, 11 Mar 2020 11:48:39 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/a-major-new-feature-for-my-cross-platform-release-notes-azure-devops-pipelines-extension-handlebars-templating-support/</guid>
      <description>&lt;p&gt;I recently got a very interesting PR for my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Cross-platform Release Notes Azure DevOps Pipelines Extension&lt;/a&gt; from &lt;a href=&#34;https://github.com/KennethScott&#34;&gt;Kenneth Scott&lt;/a&gt;. He had added a new templating engine to the task, &lt;a href=&#34;https://handlebarsjs.com/&#34;&gt;Handlebars&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previous to this PR the templating in the task was done with a line by line evaluation of a template that used my own mark-up. This method worked but has limitations, mostly due to the line by line evaluation model.  With the Kenneth’s PR the option was added to write your templates in Handlebars, or stay with my previous templating engine.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I recently got a very interesting PR for my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross-platform Release Notes Azure DevOps Pipelines Extension</a> from <a href="https://github.com/KennethScott">Kenneth Scott</a>. He had added a new templating engine to the task, <a href="https://handlebarsjs.com/">Handlebars</a>.</p>
<p>Previous to this PR the templating in the task was done with a line by line evaluation of a template that used my own mark-up. This method worked but has limitations, mostly due to the line by line evaluation model.  With the Kenneth’s PR the option was added to write your templates in Handlebars, or stay with my previous templating engine.</p>
<h3 id="using-handlebars">Using Handlebars</h3>
<p>If you use Handlebars, the template becomes something like</p>
<pre tabindex="0"><code>\## Notes for release  {{releaseDetails.releaseDefinition.name}}    
\*\*Release Number\*\*  : {{releaseDetails.name}}
\*\*Release completed\*\* : {{releaseDetails.modifiedOn}}     
\*\*Build Number\*\*: {{buildDetails.id}}
\*\*Compared Release Number\*\*  : {{compareReleaseDetails.name}}    

### Associated Work Items ({{workItems.length}})
{{#each workItems}}
\*  \*\*{{this.id}}\*\*  {{lookup this.fields &#39;System.Title&#39;}}
   - \*\*WIT\*\* {{lookup this.fields &#39;System.WorkItemType&#39;}} 
   - \*\*Tags\*\* {{lookup this.fields &#39;System.Tags&#39;}}
{{/each}}

### Associated commits ({{commits.length}})
{{#each commits}}
\* \*\* ID{{this.id}}\*\* 
   -  \*\*Message:\*\* {{this.message}}
   -  \*\*Commited by:\*\* {{this.author.displayName}} 
{{/each}}
</code></pre><p>The whole template is evaluated by the Handlebars engine using its own mark-up to provide a means for looping across arrays and the like.</p>
<p>This seemed a great enhancement to the task. However, we soon realised that it could be better. Handlebars is extensible, so why not allow the extensibility to be used?</p>
<h3 id="using-handlebars-extensions">Using Handlebars Extensions</h3>
<p>I have added extensibility in two ways. Firstly I have also added support for the common <a href="https://github.com/helpers/handlebars-helpers">Handlebar-Helpers</a> extensions, this added over 150 helpers. These are just accessed in a template as follows</p>
<pre tabindex="0"><code>\## To confirm the handbars-helpers is work
The year is {{year}} 
We can capitalize &#34;foo bar baz&#34; {{capitalizeAll &#34;foo bar baz&#34;}}
</code></pre><p>I have also added the ability to provide a block of JavaScript as a task parameter is that is loaded as a custom Handlebars extension. So if you add the following block in the tasks <strong>customHandlebarsExtensionCode</strong> parameter.</p>
<pre tabindex="0"><code>module.exports = {foo: function () {return &#39;Returns foo&#39;;}};
</code></pre><p>You can access in the templates as</p>
<pre tabindex="0"><code>\## To confirm our custom extension works
We can call our custom extension {{foo}}
</code></pre><p>It will be interesting to see how popular this alternative way of templating will be.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Where did all my test results go?</title>
      <link>https://blog.richardfennell.net/posts/where-did-all-my-test-results-go/</link>
      <pubDate>Thu, 05 Mar 2020 13:57:27 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/where-did-all-my-test-results-go/</guid>
      <description>&lt;h3 id=&#34;problem&#34;&gt;Problem&lt;/h3&gt;
&lt;p&gt;I recently tripped myself up whist adding SonarQube analysis to a rather complex Azure DevOps build.&lt;/p&gt;
&lt;p&gt;The build has two VsTest steps, both were using the same folder for their test result files. When the first VsTest task ran it created the expected .TRX and .COVERAGE files and then published its results to Azure DevOps, but when the second VsTest task ran it over wrote this folder, deleting the files already present, before it generated and published it results.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="problem">Problem</h3>
<p>I recently tripped myself up whist adding SonarQube analysis to a rather complex Azure DevOps build.</p>
<p>The build has two VsTest steps, both were using the same folder for their test result files. When the first VsTest task ran it created the expected .TRX and .COVERAGE files and then published its results to Azure DevOps, but when the second VsTest task ran it over wrote this folder, deleting the files already present, before it generated and published it results.</p>
<p>This meant that the build itself had all the test results published, but when SonarQube looked for the files for analysis only the second set of test were present, so its analysis was incorrect.</p>
<h3 id="solution">Solution</h3>
<p>The solution was easy, use different folders for each set of test results.</p>
<p>This gave me a build, the key items are shown below, where one VsTest step does not overwrite the previous results before they can be processed by any 3rd party tasks such as SonarQube.</p>
<pre tabindex="0"><code>steps:  
- task: SonarSource.sonarqube.15B84CA1-B62F-4A2A-A403-89B77A063157.SonarQubePrepare@4  
   displayName: &#39;Prepare analysis on SonarQube&#39;  
   inputs:  
     SonarQube: Sonarqube  
     projectKey: &#39;Services&#39;  
     projectName: &#39;Services&#39;  
     projectVersion: &#39;$(major).$(minor)&#39;  
     extraProperties: |  
      # Additional properties that will be passed to the scanner,   
      sonar.cs.vscoveragexml.reportsPaths=$(System.DefaultWorkingDirectory)/\*\*/\*.coveragexml  
      sonar.cs.vstest.reportsPaths=$(System.DefaultWorkingDirectory)/\*\*/\*.trx

  

… other build steps

  

\- task: VSTest@2  
   displayName: &#39;VsTest – Internal Services&#39;  
   inputs:  
     testAssemblyVer2: |  
      \*\*\*.unittests.dll  
      !\*\*obj\*\*  
     searchFolder: &#39;$(System.DefaultWorkingDirectory)/src/Services&#39;  
     resultsFolder: &#39;$(System.DefaultWorkingDirectory)TestResultsServices&#39;  
     overrideTestrunParameters: &#39;-DeploymentEnabled false&#39;  
     codeCoverageEnabled: true  
     testRunTitle: &#39;Services Unit Tests&#39;  
     diagnosticsEnabled: True  
   continueOnError: true

\- task: VSTest@2  
   displayName: &#39;VsTest - External&#39;  
   inputs:  
     testAssemblyVer2: |  
      \*\*\*.unittests.dll  
      !\*\*obj\*\*  
     searchFolder: &#39;$(System.DefaultWorkingDirectory)/src/ExternalServices&#39;  
     resultsFolder: &#39;$(System.DefaultWorkingDirectory)TestResultsExternalServices&#39;  
     vsTestVersion: 15.0  
     codeCoverageEnabled: true  
     testRunTitle: &#39;External Services Unit Tests&#39;  
     diagnosticsEnabled: True  
   continueOnError: true  

\- task: BlackMarble.CodeCoverage-Format-Convertor-Private.CodeCoverageFormatConvertor.CodeCoverage-Format-Convertor@1  
   displayName: &#39;CodeCoverage Format Convertor&#39;  
   inputs:  
     ProjectDirectory: &#39;$(System.DefaultWorkingDirectory)&#39;  

\- task: SonarSource.sonarqube.6D01813A-9589-4B15-8491-8164AEB38055.SonarQubeAnalyze@4  
   displayName: &#39;Run Code Analysis&#39;

\- task: SonarSource.sonarqube.291ed61f-1ee4-45d3-b1b0-bf822d9095ef.SonarQubePublish@4  
   displayName: &#39;Publish Quality Gate Result&#39;  
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>You need to pass a GitHub PAT to create Azure DevOps Agent Images using Packer</title>
      <link>https://blog.richardfennell.net/posts/you-need-to-pass-a-github-pat-to-create-azure-devops-agent-images-using-packer/</link>
      <pubDate>Mon, 02 Mar 2020 11:52:03 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/you-need-to-pass-a-github-pat-to-create-azure-devops-agent-images-using-packer/</guid>
      <description>&lt;p&gt;I wrote recently about &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2019/12/21/creating-hyper-v-hosted-azure-devops-private-agents-based-on-the-same-vm-images-as-used-by-microsoft-for-their-hosted-agents/&#34;&gt;Creating Hyper-V hosted Azure DevOps Private Agents based on the same VM images as used by Microsoft for their Hosted Agent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As discussed in that post, using this model you will recreate your build agent VMs on a regular basis, as opposed to patching them. When I came to do this recently I found that the Packer image generation was failing with errors related to accessing packages.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I wrote recently about <a href="https://blogs.blackmarble.co.uk/rfennell/2019/12/21/creating-hyper-v-hosted-azure-devops-private-agents-based-on-the-same-vm-images-as-used-by-microsoft-for-their-hosted-agents/">Creating Hyper-V hosted Azure DevOps Private Agents based on the same VM images as used by Microsoft for their Hosted Agent</a>.</p>
<p>As discussed in that post, using this model you will recreate your build agent VMs on a regular basis, as opposed to patching them. When I came to do this recently I found that the Packer image generation was failing with errors related to accessing packages.</p>
<p>Initially, I did not read the error message too closely and just assumed it was an intermittent issue as I had found you sometime get random timeouts with this process. However, when the problem did not go away after repeated retries I realised I had a more fundamental problem, so read the log properly!</p>
<p>Turns out the issue is you now have to pass a GitHub PAT token that has at least read access to the packages feed to allow Packer to authenticate with GitHub to read packages.</p>
<p>The process to create the required PAT is as follows</p>
<ol>
<li>In a browser login to GitHub</li>
<li>Click your profile (top right)</li>
<li>Select Settings</li>
<li>Pick Developer Settings</li>
<li>Pick Personal Access Tokens and create a new one that has <strong>read:packages</strong> enabled</li>
</ol>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/03/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2020/03/image_thumb.png" title="image"></a></p>
<p>Once created, this PAT needs to be passed into Packer. If using the settings JSON file this is just another variable</p>
<pre tabindex="0"><code>{
&#34;client\_id&#34;: &#34;Azure Client ID&#34;,
&#34;client\_secret&#34;: &#34;Client Secret&#34;,
&#34;tenant\_id&#34;: &#34;Azure Tenant ID&#34;,
&#34;subscription\_id&#34;: &#34;Azure Sub ID&#34;,
&#34;object\_id&#34;: &#34;The object ID for the AAD SP&#34;,
&#34;location&#34;: &#34;Azure location to use&#34;,
&#34;resource\_group&#34;: &#34;Name of resource group that contains Storage Account&#34;,
&#34;storage\_account&#34;: &#34;Name of the storage account&#34;,
&#34;ssh\_password&#34;: A password&#34;,
&#34;install\_password&#34;: &#34;A password&#34;,
&#34;commit\_url&#34;: &#34;A url to to be save in a text file on the VHD, usually the URL if commit VHD based on&#34;,

&#34;github\_feed\_token&#34;: &#34;A PAT&#34;

}  
</code></pre><p>If you are running Packer within a build pipeline, as the other blog post discusses, then the PAT will be another build variable.</p>
<p>Once this change was made I was able to get Packer to run to completion, as expected.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Creating Hyper-V hosted Azure DevOps Private Agents based on the same VM images as used by Microsoft for their Hosted Agents</title>
      <link>https://blog.richardfennell.net/posts/creating-hyper-v-hosted-azure-devops-private-agents-based-on-the-same-vm-images-as-used-by-microsoft-for-their-hosted-agents/</link>
      <pubDate>Sat, 21 Dec 2019 15:36:00 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/creating-hyper-v-hosted-azure-devops-private-agents-based-on-the-same-vm-images-as-used-by-microsoft-for-their-hosted-agents/</guid>
      <description>&lt;h3 id=&#34;introduction&#34;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;There are times when you need to run Private Azure DevOps agents as opposed to using one of the hosted ones provided by Microsoft. This could be for a variety of reasons, including needing to access resources inside your corporate network or needing to have a special hardware specification or set of software installed on the agent.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/12/image.png&#34;&gt;&lt;img alt=&#34;image&#34; loading=&#34;lazy&#34; src=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/12/image_thumb.png&#34; title=&#34;image&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If using such private agents, you really need to have an easy way to provision them. This is so that all your agents are standardised and easily re-creatable. Firstly you don’t want build agents with software on them you can’t remember installing or patching. This is just another form of the “works on one developer’s machine but not another” problem. Also if you have the means to replace the agents very regularly and reliably you can avoid the need to patch them; you can just replace them with newer VMs created off latest patched base Operating System images and software releases.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="introduction">Introduction</h3>
<p>There are times when you need to run Private Azure DevOps agents as opposed to using one of the hosted ones provided by Microsoft. This could be for a variety of reasons, including needing to access resources inside your corporate network or needing to have a special hardware specification or set of software installed on the agent.</p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/12/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/12/image_thumb.png" title="image"></a></p>
<p>If using such private agents, you really need to have an easy way to provision them. This is so that all your agents are standardised and easily re-creatable. Firstly you don’t want build agents with software on them you can’t remember installing or patching. This is just another form of the “works on one developer’s machine but not another” problem. Also if you have the means to replace the agents very regularly and reliably you can avoid the need to patch them; you can just replace them with newer VMs created off latest patched base Operating System images and software releases.</p>
<p>Microsoft uses <a href="https://packer.io/">Packer</a> to build the VM images into Azure Storage. Luckily, Microsoft have open sourced their build tooling process and configuration, you can find the resources on <a href="https://github.com/actions/virtual-environments">GitHub</a>. </p>
<p>A fellow MVP, Wouter de Kort, has done an <a href="https://wouterdekort.com/2018/02/25/build-your-own-hosted-vsts-agent-cloud-part-1-build/">excellent series of posts</a> on how to use these Packer tools to build your own Azure hosted Private Agents.</p>
<p>I don’t propose to go over that again. In this post, I will discuss what needs to be done to use these tools to create private agents on your own Hyper-V hardware.</p>
<p>By this point you are probably thinking ‘could this be done with containers? They are designed to allow the easy provisioning of things like agents’.</p>
<p>Well, the answer is yes that is an option. Microsoft provides both container and VM based agents and have only recently split the <a href="https://github.com/microsoft/azure-pipelines-agent">repo</a> to separate the container creation logic from the VM creation logic. The container logic remains in the <a href="https://github.com/microsoft/azure-pipelines-agent">old GitHub home</a>. However, in this post I am focusing on VMs, so will be working against the <a href="https://github.com/microsoft/azure-pipelines-agent">new home for the VM logic</a>.</p>
<h3 id="preparation--getting-ready-to-run-packer">Preparation – Getting Ready to run Packer</h3>
<h4 id="copy-the-microsoft-repo">Copy the Microsoft Repo</h4>
<p>Microsoft’s needs are not ours, we wanted to make some small changes to the way that Packer builds VMs. The key changes are:</p>
<ul>
<li>We want to add some scripts to the repo to help automate our process.</li>
<li>We don’t, at this time, make much use of Docker, so don’t bother to pre-cache the Docker images in the agent. This speeds up the image generation and keeps the VMs VHD smaller.</li>
</ul>
<p>The way we manage these changes is to <a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/import-git-repository?view=azure-devops">import</a> the Microsoft repo into our Azure DevOps Services instance. We can keep our copy <a href="https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork">up to date</a> by setting an upstream remote reference and from time to time merging in Microsoft’s changes, but more on that later.</p>
<p>All our are changes are done on our own long living-branch, we PR any revisions we make into this long lived branch.</p>
<p>The aim is to not alter the main Microsoft Packer JSON definition as sorting out a three way merge if both theirs and our versions of the main JSON file are updated is harder than I like. Rather if we don’t want a feature installed we add <em>’return $true’</em> at the start of the PowerShell script that installs the feature, thus allowing Packer to call the script, but skip the actions in the script without the need to edit the controlling JSON file.</p>
<p>This way of working allows us to update the master branch from the upstream repo to get the Microsoft changes, and then to regularly rebase our changes onto the updated master.</p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/12/image-1.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/12/image_thumb-1.png" title="image"></a></p>
<h4 id="a-local-test-of-packer">A local test of Packer</h4>
<p>It is a good idea to test out the Packer build from a development PC to make sure you have all the Azure settings correct. This is done using a command along the lines of</p>
<pre tabindex="0"><code>packer.exe&#34; build -var-file=&#34;azurepackersettings.json&#34;  -on-error=ask &#34;Windows2016-Azure.json&#34;
</code></pre><p>Where the <em>‘windows2016-azure.json’</em> is the Packer definition and the ‘<em>azurepackersettings.json’</em> the user configurations containing the following values. See the <a href="https://www.packer.io/docs/builders/azure-arm.html">Packer documentation for more details</a></p>
<pre tabindex="0"><code>{
&#34;client\_id&#34;: &#34;Azure Client ID&#34;,
&#34;client\_secret&#34;: &#34;Client Secret&#34;,
&#34;tenant\_id&#34;: &#34;Azure Tenant ID&#34;,
&#34;subscription\_id&#34;: &#34;Azure Sub ID&#34;,
&#34;object\_id&#34;: &#34;The object ID for the AAD SP&#34;,
&#34;location&#34;: &#34;Azure location to use&#34;,
&#34;resource\_group&#34;: &#34;Name of resource group that contains Storage Account&#34;,
&#34;storage\_account&#34;: &#34;Name of the storage account&#34;,
&#34;ssh\_password&#34;: A password&#34;,
&#34;install\_password&#34;: &#34;A password&#34;,
&#34;commit\_url&#34;: &#34;A url to to be save in a text file on the VHD, usually the URL if commit VHD based on&#34;
}
</code></pre><p>If all goes well you should end up with a SysPrep’d VHD in your storage account after a few hours.</p>
<p><strong>Note:</strong> You might wonder why we don’t try to build the VM locally straight onto our Hyper-V infrastructure. Packer does have a <a href="https://www.packer.io/docs/builders/hyperv-iso.html">Hyper-V ISO builder</a> but I could not get it working. Firstly finding an up to date patched Operative System ISO is not that easy and I wanted to avoid having to run Windows Update as this really slows the creation process . Also the process kept stalling as it could not seem to get a WinRM session, when I looked this seemed to be <a href="https://github.com/taliesins/packer-baseboxes/issues/16">something to do with Hyper-V Vnet switches</a>. In the end, I decided it was easier just to build to Azure storage. This also had the advantage of requiring fewer changes to the Microsoft Packer definitions, so making keeping our branch up to date easier.</p>
<h3 id="pipeline-process--preparation-stages"><em>Pipeline Process – Preparation Stages</em></h3>
<p>The key aim was to automate the updating of the build images. So we aimed to do all the work required inside an <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;tabs=yaml">Azure DevOps multistage pipeline</a>. How you might choose to implement such a pipeline will depend on your needs, but I suspect it will follow a similar flow to ours.</p>
<ol>
<li>Generate a Packer VHD</li>
<li>Copy the VHD locally</li>
<li>Create a new agent VM from the VHD</li>
<li>Repeat step 3. a few times</li>
</ol>
<p>There is a ‘what comes first the chicken or the egg’ question here. How do we create the agent to run the agent creation on?</p>
<p>In our case, we have a special manually created agent that is run on the Hyper-V host that the new agents will be created on. This has some special configuration which I will discuss further below.</p>
<h4 id="stage-1--update-our-repo">Stage 1 – Update our repo</h4>
<p>As the pipeline has a source of our copy of the repo (and targets our branch), the pipeline will automatically get the latest version of our Packer configuration source in our repo. However, there is a very good chance Microsoft will have updated their upstream repo. We could of course manually update our repo as mentioned above and we do do this from time to time. However, just to make sure we are up to date, the pipeline also does a fetch, merge and rebases our branch on its local copy. To do this it does the following</p>
<ol>
<li>Adds the Microsoft repo as an upstream remote</li>
<li>Fetches the latest upstream/master changes and merges them onto origin/master</li>
<li>Rebases our working branch onto the updated origin/master</li>
</ol>
<p>Assuming this all works, and we have not messed up a commit so causing a 3-way merge that blocks the scripts, we should have all Microsoft’s latest settings e.g packages, base images etc. plus our customisation.</p>
<h4 id="stage-2--run-packer">Stage 2 – Run Packer</h4>
<p>Next, we need to run Packer to generate the VHD. Luckily there is <a href="https://marketplace.visualstudio.com/items?itemName=riezebosch.Packer">a Packer extension in the Marketplace</a>. This provides two tasks we use</p>
<ol>
<li>Installs the Packer executable</li>
<li>Run Packer passing in all the values, stored securely as Azure DevOps pipeline variables, as used in the <em>azurepackersettings.json</em> file for a local test plus the details of an Azure subscription.</li>
</ol>
<p>Being run within a pipeline has no effect on performance, so this stage is still slow, taking hours. However, once it is completed we don’t need to run it again so we have this stage set for conditional execution based on a pipeline variable so we can skip the step if it has already completed. Very useful for testing.</p>
<h4 id="stage-3--copy-the-vhd-to-a-local-file-share">Stage 3 – Copy the VHD to a Local File Share</h4>
<p>As we are building local private agents we need the VHD file stored locally i.e. copied down to a local UNC share. This is done with some PowerShell that runs the <a href="https://docs.microsoft.com/en-us/cli/azure/?view=azure-cli-latest">Azure CLI</a>. It finds the newest VHD in the Azure Storage account and copies it locally, we do assume we are the only thing creating VHDs in the storage account and that the previous stage has just completed.</p>
<p>Again this is slow, it can take many hours depending on how fast your internet connection is. Once the VHD file is downloaded, we create a metadata file contains the name of profile it can be used with e.g. for a VS2017 or VS2019 agent and a calculated VHD file checksum, more details on both of these below.</p>
<p>Now again, as this stage is slow, and once it is completed we don’t need to run it again, we have conditional execution based on a second build variable so we can skip the step if it is not needed.</p>
<p>If all runs Ok, then at this point we have a local copy of a SysPre’d VHD. This can be considered the preparation phase over. These stages need to be completed only once for any given generation of an agent.</p>
<h3 id="pipeline-process--deployment-stages"><em>Pipeline Process –</em> Deployment Stages</h3>
<p>At this point we now have a SysPre’d VHD, but we don’t want to have to generate each agent by hand completing the post SysPrep mini setup and installing the Azure DevOps Agent.</p>
<p>To automate this configuration process we use <a href="https://github.com/VirtualEngine/Lability">Lability</a>. This is a PowerShell tool that wrappers PowerShell’s <a href="https://docs.microsoft.com/en-us/powershell/scripting/dsc/overview/overview?view=powershell-6">Desired State Configuration (DSC)</a>. Our usage of Lability and the wrapper scripts we use are</p>
<p>discussed in <a href="https://blogs.blackmarble.co.uk/rhepworth/2017/03/02/define-once-deploy-everywhere-sort-of/">this post</a> by a colleague and fellow MVP Rik Hepworth. However, the short summary is that Lability allows you to create an ‘environment’ which can include one or more VMs. In our case, we have a single VM in our environment so the terms are interchangeable in this post.</p>
<p>Each VM in an environment is based on one or more master disk images. Each instance of a VM uses its own Hyper-V diff disk off their master disk, thus greatly reducing the disk space required. This is very useful when adding multiple virtually identical agent VMs to a single Hyper-V host.</p>
<p>A Lability environment allows us to have a definition of what a build VM is i.e. what is its base VHD image, how much memory does it have, are there any extra disks, how many of CPU cores does it have, this list goes on. Also, it allows us to install software, in our case the Azure DevOps agent.</p>
<p>All the Lability definitions are stored in a separate Git repo. We have to make sure the current Lability definitions are already installed along with the Lability tools on the Azure DevOps agent that will be running these stages of the deployment pipeline. We do this by hand  on our one ‘special agent’ but it could be automated.</p>
<p>Remember, in our case, this ‘special agent’ is actually domain-joined, unlike all the agents we are about to create, and running on the Hyper-V host where we will be deploying the new VMs. As it is domain joined it can get to the previously downloaded Sysprep’d VHD and metadata file on a network UNC share. We are not too worried over the ‘effort’ keeping the Lability definitions update as they very rarely change, all changes tend to be in the Packer generated base VHD.</p>
<p>It should be remembered that this part of the deployment is a repeatable process, but we don’t just want to keep registering more and more agents. Before we add a new generation agent we want to remove an old generation one. Hence, cycling old agents out of the system, keeping things tidy.</p>
<p>We have experimented with naming of Lability environments to make it easier to keep things tidy. Currently, we provide two parameters into our Lability configuration</p>
<ul>
<li>Prefix – A short-code to identify the role of the agent we use e.g. ‘B’ for generic build agents and ‘BT’ for ones with the base features plus BizTalk</li>
<li>Index – This number is used for two jobs, the first is to identify the environment in a set of environments of the same Prefix. It is also used to work out which Hyper-V VNet the new environment should be attached to on the Hyper-V host. Lability automatically deals with the creation of these VNets if not present.</li>
</ul>
<p>So for on our system, for example, a VM will end up with a name in the form <em>B1BMAgent2019</em>, this means</p>
<ul>
<li>B - It is a generic agent</li>
<li>1 – It is on the subnet 192.168.254.0, and is the first of the B group of agents</li>
<li>BMAgent2019 – It is based on our VS2019 VHD image</li>
</ul>
<p><strong>Note:</strong> Also when an Azure DevOps Agent is registered with Azure DevOps, we also append a random number, based on the time, to the end of the agent name in Azure DevOps. This allows two VMs with the same prefix and index, but on different Hyper-V hosts, to be registered at the same time, or to have multiple agents on the same VM. In reality, we have not used this feature. We have ended up using unique prefix and index across agent our estate with a single agent per VM. </p>
<h4 id="stage-4--disable-the-old-agent-then-remove-it">Stage 4 – Disable the old agent then remove it</h4>
<p>The first deployment step is done with a PowerShell script. We check to see if there is an agent registered with the current Prefix and Index. If there is we disable it via the Azure DevOps Rest API. This will not stop the current build but will stop the agent picking up a new one when the current one completes.</p>
<p>Once the agent is disabled we keep polling it, via the API, until we see it go idle. Once the agent is idle we can use the Azure DevOps API to delete the agent’s registration on Azure DevOps.</p>
<script src="https://gist.github.com/rfennell/fcf23a63d19d76a71ead4ec58096d44f.js"></script>
<h4 id="stage-5--remove-the-old-environment">Stage 5 – Remove the old Environment</h4>
<p>Once the agent is no longer registered with Azure DevOps we can then remove the environment running the agent. This is a Lability command that we wrapper in PowerShell scripts</p>
<script src="https://gist.github.com/rfennell/d558549b853297db5a1ea904b39cc566.js"></script>
<p>This completely removes the Hyper-V VM and its diff disks that store its data, a very tidy process.</p>
<h4 id="stage-6--update-lability-settings">Stage 6 – Update Lability Settings</h4>
<p>I said previously that we rarely need to update the Lability definitions. There is one exception, that is the reference to the base VHD. We need to update this to point to the copy of the Packer generated SysPrep’d VHD on the local UNC file share.</p>
<p>We use another PowerShell script to handle this. It scans the UNC share for metadata files to find the one containing the request media type e.g. VS2017 or VS2019 (we only keep one of each type there). It then registers this VHD in Lability using the VHD file path and the previously calculated checksum. Lability uses the checksum to work out if the file has been updated.</p>
<script src="https://gist.github.com/rfennell/f1a0240639e3064f266de0d41f46aaf7.js"></script>
<h4 id="stage-7---deploy-new-environment">Stage 7 - Deploy New Environment</h4>
<p>So all we have to do at this point is request Lability to create a new environment based on the variable parameters we pass in i.e. environment definition, prefix and any override parameters (the Azure DevOps Agent configuration) into a wrapper script.</p>
<script src="https://gist.github.com/rfennell/fb19cb0cd4c6dbd32d041b020a237093.js"></script>
<p>When this script is run, it triggers Lability to create a new VM using an environment configuration.</p>
<script src="https://gist.github.com/rfennell/70f4013a09e9c111d766861f01878b83.js"></script>
<p>Lability’s first step is to create the VNet if not already present.</p>
<p>It then checks, using the checksum, if the base Sysprep’d VHD has been copied to the Hyper-V host. If it has not been copied it is done before continuing. This can take a while but is only done once.</p>
<p>Next, the environment (our agent VM) is created, firstly the VM settings are set e.g. CPU &amp; Memory and then the Windows mini setup is handled by DSC. This sets the following</p>
<ul>
<li>Administrator user Account and Password</li>
<li>Networking, here we have to rename an Ethernet adapter. We have seen the name of the first Ethernet change across different versions of the Packer image, so to make our lives easier we rename the primary adaptor connected to the VNet to a known value.</li>
<li>Swap Disk, set this allow the Operating System to manage this as the default on the Packer image is to use a dedicated drive D: which we don’t have.</li>
<li>Create a dedicated drive E: for the agent.</li>
<li>Download, install and configure the Azure DevOps agent</li>
</ul>
<p>DSC handles any reboots required.</p>
<p>After a few minutes, you should see a new registered agent in the requested Azure DevOps Agent Pool.</p>
<h4 id="stage-8--add-capabilities">Stage 8 – Add Capabilities</h4>
<p>Our builds make use of Azure DevOps <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents?view=azure-devops&amp;tabs=browser#capabilities">user capabilities</a> to target them to the correct type of agent. We use an yet another PowerShell script that waits until the new agent been registered and then it adds our custom capabilities from a comma-separated string parameter.</p>
<script src="https://gist.github.com/rfennell/7bb96ce9de54425bed083919945bd615.js"></script>
<p>A little tip here. A side effect of our Lability configuration is that all the agents have the same machine name. This can make finding the host they are on awkward, especially if you have a few Hyper-V hosts. So to address this problem we add a capability of the Hyper-V hosts name, this is purely to make finding the VM easier if we have to.</p>
<h4 id="stage-9--copy-capabilities">Stage  9 – Copy Capabilities</h4>
<p>We have seen that some of the Azure DevOps tasks we use have demands that are not met by the System Capabilities. The classic is a task requiring a value for the capability ‘java’ or ‘jdk’ when  the one that is present on the agent is ‘JAVA_HOME’.</p>
<p>To address this, as opposed to adding our own capability which might not point to the correct location, is to copy an existing capability that has the correct value. Again this is done with a PowerShell script that takes as string parameter</p>
<script src="https://gist.github.com/rfennell/bec7899a85f5079aadde4b405d515934.js"></script>
<h3 id="so-what-do-we-end-up-with">So what do we end up with?</h3>
<p>When all this completes we have a running private agent that has all the features of the Microsoft hosted ones. As Microsoft adds new functionality or patch their agent images, as long as we regenerate our Packer images, we get the same features.</p>
<p>At this point in time, we have chosen to add any extra software we require after the end of this process, as opposed to within it. In our case, this is basically either BizTalk 2013 and BizTalk 2016 on a single agent in our pool. Again we do this with a series of scripts, but manually run this time. We would like to fully automate the process, but BizTalk does not lend itself to easy installation automation. So, after a good bit of experimentation, we decided the best option for now, was to keep our basic build process as close to the Microsoft Packer images as possible to minimise merge issues, and worry about BizTalk later. As we only have one BizTalk 2013 and one 2016 agent the cost of manually finishing off was not too high.</p>
<h3 id="where-do-we-go-from-here">Where do we go from here?</h3>
<p>We now have a process that is automated end to end. However, it can be ‘a little brittle’, but as all the stages tidy up after themselves rerunning jobs is not an issue other than in the time cost.</p>
<p>We still have not decided on a final workflow for the replacement of agent. At this time we use manual approvals before deploying an agent. I am sure this will change as we allow this process to mature.</p>
<p>It is a good starting point.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Major enhancements to my Azure DevOps Cross Platform Release Notes Extension</title>
      <link>https://blog.richardfennell.net/posts/major-enhancements-to-my-azure-devops-cross-platform-release-notes-extension/</link>
      <pubDate>Wed, 04 Dec 2019 10:16:19 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/major-enhancements-to-my-azure-devops-cross-platform-release-notes-extension/</guid>
      <description>&lt;p&gt;Over the past few days I have published two major enhancements to my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Azure DevOps Cross Platform Release Notes Extension&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;added-support-for-builds&#34;&gt;Added Support for Builds&lt;/h3&gt;
&lt;p&gt;Prior to version 2.17.x this extension could only be used in Releases. This was because it used Release specific calls provided in the Microsoft API to work out the work items and changesets/commits associated with the Release. This is unlike my older &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-GenerateReleaseNotes-Task&#34;&gt;PowerShell based Release Notes Extension&lt;/a&gt; which was initially developed for Builds and only later enhanced to  work in Releases, but achieved this using my own logic to iterate across Builds associated with Releases to work out the associations. With the advent of &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;amp;tabs=yaml&#34;&gt;YAML multistage Pipelines&lt;/a&gt; the difference between a Build and a Release is blurring, so I thought it high time to add Build support to my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;Cross Platform Release Notes Extension&lt;/a&gt;. Which it now does.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Over the past few days I have published two major enhancements to my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Azure DevOps Cross Platform Release Notes Extension</a>.</p>
<h3 id="added-support-for-builds">Added Support for Builds</h3>
<p>Prior to version 2.17.x this extension could only be used in Releases. This was because it used Release specific calls provided in the Microsoft API to work out the work items and changesets/commits associated with the Release. This is unlike my older <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-GenerateReleaseNotes-Task">PowerShell based Release Notes Extension</a> which was initially developed for Builds and only later enhanced to  work in Releases, but achieved this using my own logic to iterate across Builds associated with Releases to work out the associations. With the advent of <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/stages?view=azure-devops&amp;tabs=yaml">YAML multistage Pipelines</a> the difference between a Build and a Release is blurring, so I thought it high time to add Build support to my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Extension</a>. Which it now does.</p>
<h3 id="adding-tag-filters">Adding Tag Filters</h3>
<p>In the <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Extension</a> you have been able to filter the work items returned in a generated document for a good while, but the filter was limited to a logical AND i.e. if the filter was</p>
<blockquote>
<p>@@WILOOP:TAG1:TAG2@@</p></blockquote>
<p>All work items matched would have to have both the TAG1 and TAG2 set Since 2.18.x there is now the option of a logic AND or an OR.</p>
<ul>
<li>@@WILOOP:TAG1:TAG2@@ matches work items that have all tags (legacy behaviour for backward compatibility)</li>
<li>@@WILOOP[ALL]:TAG1:TAG2@@ matches work items that have all tags</li>
<li>@@WILOOP[ANY]:TAG1:TAG2@@ matches work items that any of the tags</li>
</ul>
<p><em>Update 5th Dec</em> In 2.19.x there is also the option to filter on any field in a work item as well as tags</p>
<ul>
<li>@@WILOOP[ALL]:System.Title=This is a title:TAG 1@@</li>
</ul>
<p><a href="https://github.com/rfennell/AzurePipelines/wiki/GenerateReleaseNotes---Node-based-Cross-Platform-Task">For more details see the extension’s WIKI page</a></p>
<h3 id="futures">Futures</h3>
<p>My plan is to at some point deprecate my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-GenerateReleaseNotes-Task">PowerShell based Release Notes Extension</a>. I have updated the documentation for this older extension state as much and to recommend the use of the newer <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Extension</a>. At this time there is now little that this older extension can do that cannot be done by my newer <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">Cross Platform Release Notes Extension</a>. Moving to it I think makes sense for everyone for the…</p>
<ul>
<li>Cross platform support</li>
<li>Use of the same means to find the associated items as the Microsoft UI to avoid confusion</li>
<li>Enhanced work item filtering</li>
</ul>
<p>Lets see of the new features and updated advisory documentation effect the tow extension relative download statistics</p>
]]></content:encoded>
    </item>
    <item>
      <title>Cannot queue a new build on Azure DevOps Server 2019.1 due to the way a SQL cluster was setup</title>
      <link>https://blog.richardfennell.net/posts/cannot-queue-a-new-build-on-azure-devops-server-2019-1-due-to-the-way-a-sql-cluster-was-setup/</link>
      <pubDate>Thu, 17 Oct 2019 19:24:13 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/cannot-queue-a-new-build-on-azure-devops-server-2019-1-due-to-the-way-a-sql-cluster-was-setup/</guid>
      <description>&lt;p&gt;I have recently been doing a TFS 2015 to Azure DevOps Server 2019.1 upgrade for a client. The first for a while, I have been working with Azure DevOps Service mostly of late. Anyway I saw an issue I had never seen before with any version of TFS, and I could find no information on the Internet.&lt;/p&gt;
&lt;h3 id=&#34;the-problem&#34;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;The error occurred when I tried to queue a new build after the upgrade, the build instantly failed with the error&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have recently been doing a TFS 2015 to Azure DevOps Server 2019.1 upgrade for a client. The first for a while, I have been working with Azure DevOps Service mostly of late. Anyway I saw an issue I had never seen before with any version of TFS, and I could find no information on the Internet.</p>
<h3 id="the-problem">The Problem</h3>
<p>The error occurred when I tried to queue a new build after the upgrade, the build instantly failed with the error</p>
<p><em>‘The module being executed is not trusted, Either the owner of the database of the module need to be granted authenticate permission, or the module needs to be digitally signed. Warning: Null value is eliminated by an aggregate or other SET operation, The statement has been terminated’.</em></p>
<h3 id="the-solution">The Solution</h3>
<p>It turns out the issue was the the client was using a enterprise wide SQL cluster to host the <em>tfs_</em> databases. After the Azure DevOps upgrade the DBAs has enabled a trigger based logging system to monitor the databases and this was causing the error.</p>
<p>As soon as this logging was switched off everything worked as expected.</p>
<p>I would not recommend using such a logging tool for any ‘out the box’ database for a product such as TFS/Azure DevOps Server where the DBA team don’t own the database schema’s changes, as these databases will only occur if the product is upgraded</p>
]]></content:encoded>
    </item>
    <item>
      <title>Strange issue with multiple calls to the same REST WebClient in PowerShell</title>
      <link>https://blog.richardfennell.net/posts/strange-issue-with-multiple-calls-to-the-same-rest-webclient-in-powershell/</link>
      <pubDate>Thu, 29 Aug 2019 11:56:05 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/strange-issue-with-multiple-calls-to-the-same-rest-webclient-in-powershell/</guid>
      <description>&lt;p&gt;Hit a strange problem today trying to do a simple Work Item update via the Azure DevOps REST API.&lt;/p&gt;
&lt;p&gt;To do a &lt;a href=&#34;https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/work%20items/update?view=azure-devops-rest-5.1&#34;&gt;WI update you need to call the REST API&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using the verb PATCH&lt;/li&gt;
&lt;li&gt;With the Header “Content-Type” set to “application/json-patch+json”&lt;/li&gt;
&lt;li&gt;Include in the Body the current WI update revision (to make sure you are updating the current version)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the first step is to get the current WI values to find the current revision.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Hit a strange problem today trying to do a simple Work Item update via the Azure DevOps REST API.</p>
<p>To do a <a href="https://docs.microsoft.com/en-us/rest/api/azure/devops/wit/work%20items/update?view=azure-devops-rest-5.1">WI update you need to call the REST API</a></p>
<ul>
<li>Using the verb PATCH</li>
<li>With the Header “Content-Type” set to “application/json-patch+json”</li>
<li>Include in the Body the current WI update revision (to make sure you are updating the current version)</li>
</ul>
<p>So the first step is to get the current WI values to find the current revision.</p>
<p>So my update logic was along the lines of</p>
<ol>
<li>Create new WebClient with the Header “Content-Type” set to “application/json-patch+json”</li>
<li>Do a Get call to API to get the current work item</li>
<li>Build the update payload with my updated fields and the current revision.</li>
<li>Do a PATCH call to API using the client created in step 1 to update the current work item</li>
</ol>
<p>Problem was at Step 4 I got a 400 error. A general error, not too helpful</p>
<p>After much debugging I spotted the issue was that after Step 2. my WebClient’s Headers had changed, I had lost the content type – no idea why.</p>
<p>It all started to work if I recreated my WebClient after Step 2, so something like (in PowrShell)</p>
<pre tabindex="0"><code>Function Get-WebClient

{

param  
(

&gt; \[string\]$pat,  
&gt; \[string\]$ContentType = &#34;application/json&#34;

)

&gt; $wc = New-Object System.Net.WebClient  
&gt; $pair = &#34;:${password}&#34;  
&gt; $bytes = \[System.Text.Encoding\]::ASCII.GetBytes($pair)  
&gt; $base64 = \[System.Convert\]::ToBase64String($bytes)  
&gt; $wc.Headers.Add(“Authorization”,&#34;Basic $base64&#34;)  
&gt; $wc.Headers\[&#34;Content-Type&#34;\] = $ContentType  
&gt; $wc

}

  
</code></pre><p>function Update-WorkItemTitle {</p>
<p>param</p>
<p>(</p>
<blockquote>
<p>$baseUri ,<br>
$teamproject,<br>
$workItemID,<br>
$pat,<br>
$title</p></blockquote>
<p>)</p>
<blockquote>
<p>$wc = Get-WebClient -pat $pat -ContentType &ldquo;application/json-patch+json&rdquo;<br>
$uri = &ldquo;$($baseUri)/$teamproject/_apis/wit/workitems/$($workItemID)?api-version=5.1&rdquo;</p></blockquote>
<blockquote>
<p># you can only update a work item if you also pass in the rev, this makes sure you are updating lastest version<br>
$jsondata = $wc.DownloadString($uri) | ConvertFrom-Json</p></blockquote>
<blockquote>
<p>$wc = Get-WebClient -pat $pat -ContentType &ldquo;application/json-patch+json&rdquo;</p></blockquote>
<blockquote>
<p>$data = @(<br>
@{<br>
            op    = &ldquo;test&rdquo;;<br>
            path  = &ldquo;/rev&rdquo;;<br>
            value = $jsondata.Rev<br>
},<br>
@{<br>
            op    = &ldquo;add&rdquo;;<br>
            path  = &ldquo;/fields/System.Title&rdquo;;<br>
            value = $title<br>
}<br>
) | ConvertTo-Json</p></blockquote>
<blockquote>
<p>$jsondata = $wc.UploadString($uri, &ldquo;PATCH&rdquo;, $data) | ConvertFrom-Json<br>
$jsondata</p></blockquote>
<p>}</p>
<pre tabindex="0"><code></code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Authentication loops swapping organisations in Azure DevOps</title>
      <link>https://blog.richardfennell.net/posts/authentication-loops-swapping-organisations-in-azure-devops/</link>
      <pubDate>Tue, 13 Aug 2019 11:04:36 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/authentication-loops-swapping-organisations-in-azure-devops/</guid>
      <description>&lt;p&gt;I have recently been getting a problem swapping between different organisations in Azure DevOps. It happens when I swap between Black Mable ones and customer ones, where each is back by different Azure Active Directory (AAD) but I am using the same credentials; because I am either a member of that AAD or a guest.&lt;/p&gt;
&lt;p&gt;The problem is I get into an authentication loop. It happens to be in Chrome, but you might find the same problem in other browsers.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have recently been getting a problem swapping between different organisations in Azure DevOps. It happens when I swap between Black Mable ones and customer ones, where each is back by different Azure Active Directory (AAD) but I am using the same credentials; because I am either a member of that AAD or a guest.</p>
<p>The problem is I get into an authentication loop. It happens to be in Chrome, but you might find the same problem in other browsers.</p>
<p>It seems to be a recent issue, maybe related to MFA changes in AAD?</p>
<p>I used to be re-promoted for my ID when I swapped organisations in a browser tab, but not asked for further authentication</p>
<p>However, now the following happens</p>
<ul>
<li>I login to an organisation without a problem e.g <a href="https://dev.azure.com/someorg">https://dev.azure.com/someorg</a> using ID, password and MFA</li>
<li>In the same browser window, when I connect to another organisation e.g. <a href="https://dev.azure.com/someotherorg">https://dev.azure.com/someotherorg</a> </li>
<li>I am asked to pick an account, then there is the MFA challenge, but then go back to the login</li>
<li>…. and repeat.</li>
</ul>
<p>The fix is to go in the browser tab to <a href="https://dev.azure.com">https://dev.azure.com</a>. As you are already authenticated you will be able to sign out, then all is OK, you can login again.</p>
<p>The other options is to make even more use of <a href="https://support.google.com/chrome/answer/2364824?co=GENIE.Platform%3DDesktop&amp;hl=en">Chrome People</a>; one ‘person’ per customer, as opposed to my current usage on one ‘person’ per ID</p>
]]></content:encoded>
    </item>
    <item>
      <title>You can&amp;rsquo;t use Azure DevOps Pipeline Gates to check services behind a firewall</title>
      <link>https://blog.richardfennell.net/posts/you-cant-use-azure-devops-pipeline-gates-to-check-services-behind-a-firewall/</link>
      <pubDate>Thu, 25 Jul 2019 19:55:52 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/you-cant-use-azure-devops-pipeline-gates-to-check-services-behind-a-firewall/</guid>
      <description>&lt;p&gt;I have recently be working on a release pipeline that deploys to a server behind a corporate firewall. This is done using an &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents?view=azure-devops&#34;&gt;Azure DevOps private build agent&lt;/a&gt; and works fine.&lt;/p&gt;
&lt;p&gt;As the service is a basic REST service and takes a bit of time to start-up I though a &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/release/approvals/gates?view=azure-devops&#34;&gt;gate&lt;/a&gt; was a perfect way to pause the release pipeline until service was ready for the automated tests.&lt;/p&gt;
&lt;p&gt;However, I hit a problem, the gates always failed as the internal server could not be resolved.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I have recently be working on a release pipeline that deploys to a server behind a corporate firewall. This is done using an <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents?view=azure-devops">Azure DevOps private build agent</a> and works fine.</p>
<p>As the service is a basic REST service and takes a bit of time to start-up I though a <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/release/approvals/gates?view=azure-devops">gate</a> was a perfect way to pause the release pipeline until service was ready for the automated tests.</p>
<p>However, I hit a problem, the gates always failed as the internal server could not be resolved.</p>
<p>After a bit of thought I realised why. Gates as actual <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/process/phases?view=azure-devops&amp;tabs=yaml">agentless</a> tasks, they don’t run on the agent but on the server, so are outside the firewall. They could never connect to the private service without ports being opened, which was never going to happen.</p>
<p>So at this point in time I can’t use gates on this pipeline. Any similar logic to do the same job would have to be developed as scripts I can run on an agent.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Azure DevOps Repos branch build policies not triggering when expected in PRs  - Solved</title>
      <link>https://blog.richardfennell.net/posts/azure-devops-repos-branch-build-policies-not-triggering-when-expected-in-prs-solved/</link>
      <pubDate>Thu, 23 May 2019 15:01:36 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/azure-devops-repos-branch-build-policies-not-triggering-when-expected-in-prs-solved/</guid>
      <description>&lt;p&gt;I recently hit a problem with builds triggered by &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&#34;&gt;branch policies in Azure DevOps Repos&lt;/a&gt;. With the help of Microsoft I found out the problem and I thought it worth writing up uncase others hit the issue.&lt;/p&gt;
&lt;h3 id=&#34;setup&#34;&gt;Setup&lt;/h3&gt;
&lt;h4 id=&#34;folders&#34;&gt;Folders&lt;/h4&gt;
&lt;p&gt;Assume you have a Git repo with source for the UI, backend Services and common code in sub folders&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;/ [root]&lt;br&gt;
     UI&lt;br&gt;
     Services&lt;br&gt;
     Common&lt;/p&gt;&lt;/blockquote&gt;
&lt;h4 id=&#34;branch-policies&#34;&gt;Branch Policies&lt;/h4&gt;
&lt;p&gt;On the Master branch there are a policies of running&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I recently hit a problem with builds triggered by <a href="https://docs.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops">branch policies in Azure DevOps Repos</a>. With the help of Microsoft I found out the problem and I thought it worth writing up uncase others hit the issue.</p>
<h3 id="setup">Setup</h3>
<h4 id="folders">Folders</h4>
<p>Assume you have a Git repo with source for the UI, backend Services and common code in sub folders</p>
<blockquote>
<p>/ [root]<br>
     UI<br>
     Services<br>
     Common</p></blockquote>
<h4 id="branch-policies">Branch Policies</h4>
<p>On the Master branch there are a policies of running</p>
<ul>
<li>one build for anything in the UI folder/project or common folder/project</li>
<li>and a different build for anything in the Services folder/project or common folder/project</li>
</ul>
<p>These build were filtered by path using the filters</p>
<blockquote>
<p>/UX; /Common<br>
/Services; /Common</p></blockquote>
<h3 id="the-issue">The Issue</h3>
<p>I discovered the problem by doing the following</p>
<ul>
<li>Create a PR for some work that effects the UI project</li>
<li>As expected the UI build triggers</li>
<li>Update the PR with a second commit for the Services code</li>
<li>The Service build is <strong>not</strong> triggered</li>
</ul>
<h3 id="the-solution">The Solution</h3>
<p>The fix was simple it turns out. Remove the spaces from the filter paths so they become</p>
<blockquote>
<p>/UX;/Common<br>
/Services;/Common</p></blockquote>
<p>Once this was done the builds triggered as expected.</p>
<p>Thanks again to the Azure DevOps Product Group for the help</p>
]]></content:encoded>
    </item>
    <item>
      <title>Migrating a GUI based build to YAML in Azure DevOps Pipelines</title>
      <link>https://blog.richardfennell.net/posts/migrating-a-gui-based-build-to-yaml-in-azure-devops-pipelines/</link>
      <pubDate>Fri, 26 Apr 2019 14:02:57 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/migrating-a-gui-based-build-to-yaml-in-azure-devops-pipelines/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;p&gt;I use Azure DevOps Pipelines for the build and release of my Azure DevOps Pipeline extensions, &lt;a href=&#34;https://github.com/rfennell/AzurePipelines/wiki/Outlining-my-VSTS-CI&#34;&gt;I previously detailed my process here&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;For a good few months now &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline?view=azure-devops&amp;amp;tabs=tfs-2018-2&#34;&gt;YAML builds&lt;/a&gt; have been available. These provide the key advantage that the build is defined in a YAML text file that is stored with your product’s source code, thus allowing you to more easily track build changes. Also bulk editing becomes easier as a simple text editor can be used.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="introduction">Introduction</h2>
<p>I use Azure DevOps Pipelines for the build and release of my Azure DevOps Pipeline extensions, <a href="https://github.com/rfennell/AzurePipelines/wiki/Outlining-my-VSTS-CI">I previously detailed my process here</a> .</p>
<p>For a good few months now <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/create-first-pipeline?view=azure-devops&amp;tabs=tfs-2018-2">YAML builds</a> have been available. These provide the key advantage that the build is defined in a YAML text file that is stored with your product’s source code, thus allowing you to more easily track build changes. Also bulk editing becomes easier as a simple text editor can be used.</p>
<p>I have been putting off moving my current GUI based builds for as there is a bit of work, this post document then step.</p>
<h2 id="process">Process</h2>
<h3 id="getting-the-old-build-content">Getting the old build content</h3>
<p>First I created a new branch in my local copy of my GitHub repo that stores the source for my extensions</p>
<p>I then created an empty file <strong>azure-pipelines-build.yaml</strong> the same folder as the root of the extension I was replacing the build for. I created the empty text file. I did this as the current create new build UI allows you to pick a file or a create one, but if you create one it gives you no control as to where or how it is named</p>
<p>In you existing build I then clicked the pipeline level ‘View YAML’</p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/04/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2019/04/image_thumb.png" title="image"></a> </p>
<p><strong>Note:</strong>  Initially I found this link disabled, but if you click around the UI, into the task details, variables etc, it eventually becomes enabled. I have no idea why.</p>
<p>Copy this YAML into you newly created <strong>azure-pipelines-build.yaml</strong> file, committed the file and pushed it GitHub as the new branch.</p>
<h3 id="creating-the-yaml-build">Creating the YAML build</h3>
<p>I then created a new YAML based build, picking in my case GitHub as the source host, the correct branch, and correct file.</p>
<p>This YAML contains the  core of what is needed, but the build was missing some some items such as triggers, build number and variable.</p>
<p>I added</p>
<ul>
<li>the name (build number)</li>
<li>the PR triggers to the YAML</li>
</ul>
<p>to the .YAML file, but decided to declare my variables as they contained secrets within the build definition in Azure DevOps.</p>
<p><a href="https://github.com/rfennell/AzurePipelines/blob/master/Extensions/DevTestLab/azure-pipelines-build.yml">The final YAML file was can be viewed here</a></p>
<h3 id="what-i-fixed-in-passing">What I fixed in passing</h3>
<p>In the past I used to package up my extensions twice, once packaged as private (for testing) and once as public. This was due to the limitation of the Azure DevOps Marketplace and the release tasks I was using at the time. Whilst passing a took the chance to change to only building the public VSIX package, but updated my release pipeline process to dynamically inject the settings for private testing. This was done using the newer <a href="https://marketplace.visualstudio.com/items?itemName=ms-devlabs.vsts-developer-tools-build-tasks&amp;targetId=e59fd111-3faf-4b90-be81-9def48f2947b&amp;utm_source=vstsproduct&amp;utm_medium=ExtHubManageList">Azure DevOps Extensions Tasks</a>.</p>
<p>As I side note I had to upgrade to these newer release tasks anyway as the older ones had ceased to work due to using old API calls</p>
<h3 id="swapping-in-the-new-build-into-the-release-process">Swapping in the new build into the release process</h3>
<p>To replace the old GUI build with the new YAML build I did the following</p>
<ul>
<li>Renamed my old GUI build and disabled this (the disable is vital else it continues to be triggered by the GitHub PRs, even if the triggers are removed in the build)</li>
<li>Renamed my new YAML build to the old GUI build name (not vital, but it felt neater)</li>
<li>Updated my release pipeline to pick the new YAML build as opposed to the old GUI build. Even though the names were the same, their internal IDs are not, so this needs to be swapped. I made sure my ‘source alias’ did not change, so I did not have to make other changes to my release pipeline. </li>
</ul>
<p>Once this was done I triggered a new GitHub PR and everything worked as expects.</p>
<h2 id="what-next">What Next</h2>
<p>I have kept the old build about just in case there is a problem I have not spotted, but I intend to delete this soon.</p>
<p>I now need to make the same changes for all my other build. The only difference for from this process will be for builds that make use of Task Groups, such as all those for Node based extensions. Task Groups cannot be exported as YAML at this time, so I will have to manually rebuilding these steps in a text editor. So more prone to human error, but I think it needs to be done.</p>
<p>So a nice back burner project. I will probably update them as release new versions of extensions.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Programmatically adding User Capabilities to Azure DevOps Agents</title>
      <link>https://blog.richardfennell.net/posts/programmatically-adding-user-capabilities-to-azure-devops-agents/</link>
      <pubDate>Thu, 06 Dec 2018 14:56:58 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/programmatically-adding-user-capabilities-to-azure-devops-agents/</guid>
      <description>&lt;p&gt;I am automating the process by which we keep our build agent up to date. The basic process is to use a fork of the standard Microsoft Azure DevOps Pipeline agent that has the additional code included we need, &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2018/02/27/building-private-vsts-build-agents-using-the-microsoft-packer-based-agent-image-creation-model/&#34;&gt;notably Biztalk&lt;/a&gt;. Once I have the Packer created VM up and running, I need to install the agent. This is well document, just run _.config.cmd –help _for details. However, there is no option to add user capabilities to the agent. I know I could set them via environment variables, but I don’t want the same user capabilities on each agent on a VM (we use multiple agents on a single VM). There was no documented Azure DevOps API I could find to add capabilities, but a bit of hacking around with Chrome Dev tools and Postman got me a solution, which I have provided a&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I am automating the process by which we keep our build agent up to date. The basic process is to use a fork of the standard Microsoft Azure DevOps Pipeline agent that has the additional code included we need, <a href="https://blogs.blackmarble.co.uk/rfennell/2018/02/27/building-private-vsts-build-agents-using-the-microsoft-packer-based-agent-image-creation-model/">notably Biztalk</a>. Once I have the Packer created VM up and running, I need to install the agent. This is well document, just run _.config.cmd –help _for details. However, there is no option to add user capabilities to the agent. I know I could set them via environment variables, but I don’t want the same user capabilities on each agent on a VM (we use multiple agents on a single VM). There was no documented Azure DevOps API I could find to add capabilities, but a bit of hacking around with Chrome Dev tools and Postman got me a solution, which I have provided a</p>
<script src="https://gist.github.com/rfennell/13b014fc816822cc9007ae26cc2cb43f.js"></script>
]]></content:encoded>
    </item>
    <item>
      <title>Azure Pipeline YAML support on VSCode</title>
      <link>https://blog.richardfennell.net/posts/azure-pipeline-yaml-support-on-vscode/</link>
      <pubDate>Thu, 06 Dec 2018 12:45:48 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/azure-pipeline-yaml-support-on-vscode/</guid>
      <description>&lt;p&gt;A major problem when moving from the graphic editing of Azure Pipeline builds to YAML has been the difficulty in knowing the options available, and of course making typos.&lt;/p&gt;
&lt;p&gt;Microsoft have just released a VSCode extension to help address this problem – it is called &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=ms-azure-devops.azure-pipelines&#34;&gt;Azure Pipelines&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://pbs.twimg.com/media/Dtm59RqWoAEE1qA.jpg&#34;&gt;&lt;/p&gt;
&lt;p&gt;I have yet to give it a really good workout, but first impressions are good.&lt;/p&gt;
&lt;p&gt;It does not remove the need for good documentation of task options, there is a need for my &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2018/10/25/yaml-documentation-for-my-azure-pipeline-tasks-and-how-i-generated-it/&#34;&gt;script to generate YAML documentation from a task.json file&lt;/a&gt;, but anything extra to ease editing helps.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>A major problem when moving from the graphic editing of Azure Pipeline builds to YAML has been the difficulty in knowing the options available, and of course making typos.</p>
<p>Microsoft have just released a VSCode extension to help address this problem – it is called <a href="https://marketplace.visualstudio.com/items?itemName=ms-azure-devops.azure-pipelines">Azure Pipelines</a></p>
<p><img loading="lazy" src="https://pbs.twimg.com/media/Dtm59RqWoAEE1qA.jpg"></p>
<p>I have yet to give it a really good workout, but first impressions are good.</p>
<p>It does not remove the need for good documentation of task options, there is a need for my <a href="https://blogs.blackmarble.co.uk/rfennell/2018/10/25/yaml-documentation-for-my-azure-pipeline-tasks-and-how-i-generated-it/">script to generate YAML documentation from a task.json file</a>, but anything extra to ease editing helps.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Keeping Azure DevOps organisations inherited process templates in sync</title>
      <link>https://blog.richardfennell.net/posts/keeping-azure-devops-organisations-inherited-process-templates-in-sync/</link>
      <pubDate>Thu, 29 Nov 2018 17:27:00 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/keeping-azure-devops-organisations-inherited-process-templates-in-sync/</guid>
      <description>&lt;h3 id=&#34;the-problem&#34;&gt;The problem&lt;/h3&gt;
&lt;p&gt;If you are like me for historic reasons you have multiple Azure DevOps organisations (instances) backed by the same Azure Active Directory (AAD). In my case for example: one was created when Azure DevOps was first released as &lt;em&gt;TFSPreview.com&lt;/em&gt; and another is from our migration from on-prem TFS using the &lt;a href=&#34;https://azure.microsoft.com/en-us/services/devops/migrate/&#34;&gt;DB Migration Tools&lt;/a&gt; method; and I have others. I make active use of all of these for different purposes, though one is primary with the majority of work done on it, and so I want to make sure the &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/organizations/settings/work/manage-process?view=vsts&amp;amp;tabs=new-nav&#34;&gt;inherited process templates&lt;/a&gt; are the same on each of them. Using the primary organisation as the master customisation. &lt;strong&gt;Note&lt;/strong&gt; I have already &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/reference/on-premises-xml-process-model?view=vsts&#34;&gt;converted all my old on-premises XML process models&lt;/a&gt; to inherited process templates. There is no out the box way to do keep processes in syncs, but it is possible using a few tools. The main one is the &lt;a href=&#34;https://github.com/Microsoft/process-migrator&#34;&gt;Microsoft Process Migrator for Node&lt;/a&gt; on GitHub.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="the-problem">The problem</h3>
<p>If you are like me for historic reasons you have multiple Azure DevOps organisations (instances) backed by the same Azure Active Directory (AAD). In my case for example: one was created when Azure DevOps was first released as <em>TFSPreview.com</em> and another is from our migration from on-prem TFS using the <a href="https://azure.microsoft.com/en-us/services/devops/migrate/">DB Migration Tools</a> method; and I have others. I make active use of all of these for different purposes, though one is primary with the majority of work done on it, and so I want to make sure the <a href="https://docs.microsoft.com/en-us/azure/devops/organizations/settings/work/manage-process?view=vsts&amp;tabs=new-nav">inherited process templates</a> are the same on each of them. Using the primary organisation as the master customisation. <strong>Note</strong> I have already <a href="https://docs.microsoft.com/en-us/azure/devops/reference/on-premises-xml-process-model?view=vsts">converted all my old on-premises XML process models</a> to inherited process templates. There is no out the box way to do keep processes in syncs, but it is possible using a few tools. The main one is the <a href="https://github.com/Microsoft/process-migrator">Microsoft Process Migrator for Node</a> on GitHub.</p>
<h3 id="the-solution">The Solution</h3>
<p>Firstly I cloned the Microsoft Process Migrator and built it as per the instructions on the repo. I created a config file and then ran the tool. On one organisation it ran fine. However on another I had errors like: [ERROR] [2018-11-26T14:35:44.880Z] Process import validation failed. Process with same name already exists on target account. <em>[ERROR] [2018-11-26T14:39:54.206Z] Import failed, see log file for details. Create field &lsquo;Location&rsquo; failed, see log for details</em> This was because I had in the past manually duplicated the inherited process template onto this organisation, so there was a process with the same name and fields of the same names. The first error was easy to fix, import the template with a new (temporary) name. The second is more problematic. I had two choice</p>
<ul>
<li>A manual fix</li>
<li>An automated fix using <a href="https://marketplace.visualstudio.com/items?itemName=nkdagility.vsts-sync-migration">Migration Tools for Azure DevOps</a> from <a href="https://marketplace.visualstudio.com/publishers/nkdagility">Martin Hinshelwood</a></li>
</ul>
<p>As I only had a few duplicated unused fields on a single organisation I picked the former. If I had many organisations to sort out I would picked the latter. So my process ended up being</p>
<ol>
<li>Run the Microsoft Process Migrator to migrate ‘My Process’ on the source organisation to ‘My Process 1’ on the target organisation</li>
<li>It gave an error, providing the name of the duplicated field</li>
<li>I checked on the target organisation using a work item query that the field was empty or only had defaulted data (if it had not been I would have used Martin’s tool to migrate the data to a temporary field and then deleted the problem field, moving the data back to the correct field from the temporary field when the import of the process template was completed)</li>
<li>I deleted the field from the work item type that referenced it</li>
<li>I deleted the field</li>
<li>I deleted the process template ‘My Process 1’, a failed import leaves a half created process</li>
<li>I went back to step 1 and repeated until the import completed without error</li>
<li>I tested my migrated inherited process was OK</li>
<li>On the target organisation I then renamed ‘My Process’ to ‘My Process – Old’</li>
<li>I then renamed ‘My Process 1’ to ‘My Process’</li>
<li>In my case I also made ‘My Process’ as the default, you might not do this if another process is the default, but step 13 does require the process template is not the default</li>
<li>I moved all the team projects using the process template now called ‘My Process – Old’ to ‘My Process’</li>
<li>I was then able to delete the process template ‘My Process – Old’ as it has no associated team projects and was not the default</li>
</ol>
<p>As I customise my primary organisation’s process templates I can repeat this process to keep the processes in sync between organisations.  Note that in future migrations I won’t have to do steps 2..6 as there are no manually created duplicated fields. So it should be more straight forward. So a valid solution until any similar functionality is built into Azure DevOps, and there is no sign of that on the roadmap.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Azure DevOps Services &amp;amp; Server Alerts DSL - an alternative to TFS Aggregator?</title>
      <link>https://blog.richardfennell.net/posts/azure-devops-services-server-alerts-dsl-an-alternative-to-tfs-aggregator/</link>
      <pubDate>Tue, 30 Oct 2018 21:10:59 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/azure-devops-services-server-alerts-dsl-an-alternative-to-tfs-aggregator/</guid>
      <description>&lt;p&gt;Whilst listening to a recent  &lt;a href=&#34;http://www.radiotfs.com/Show/167/TasksandReleaseGateswithJesseHouwing&#34;&gt;Radio TFS&lt;/a&gt; it was mentioned that &lt;a href=&#34;https://tfsaggregator.github.io/&#34;&gt;TFS Aggregator&lt;/a&gt; uses the C# SOAP based Azure DevOps APIs; hence needed a major re-write as these &lt;a href=&#34;https://blogs.msdn.microsoft.com/devops/2018/05/21/announcing-the-deprecation-of-the-wit-and-test-client-om-at-jan-1-2020-2/&#34;&gt;APIs are being deprecated.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Did you know that there was a REST API alternative to TFS Aggregator?&lt;/p&gt;
&lt;p&gt;My &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-ServiceHooks-DSL#overview&#34;&gt;Azure DevOps Services &amp;amp; Server Alerts DSL&lt;/a&gt; is out there, and has been for a while, but I don’t think used by many people. It aims to do the same as TFS Aggregator, but is based around Python scripting.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Whilst listening to a recent  <a href="http://www.radiotfs.com/Show/167/TasksandReleaseGateswithJesseHouwing">Radio TFS</a> it was mentioned that <a href="https://tfsaggregator.github.io/">TFS Aggregator</a> uses the C# SOAP based Azure DevOps APIs; hence needed a major re-write as these <a href="https://blogs.msdn.microsoft.com/devops/2018/05/21/announcing-the-deprecation-of-the-wit-and-test-client-om-at-jan-1-2020-2/">APIs are being deprecated.</a></p>
<p>Did you know that there was a REST API alternative to TFS Aggregator?</p>
<p>My <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-ServiceHooks-DSL#overview">Azure DevOps Services &amp; Server Alerts DSL</a> is out there, and has been for a while, but I don’t think used by many people. It aims to do the same as TFS Aggregator, but is based around Python scripting.</p>
<p>However, I do have to say it is more limited in flexibility as it has only been developed for my (and a few of my clients needs), but its an alternative that is based on the REST APIs. </p>
<p>Scripts are of the following form, this one changes the state of a work item if all it children are done</p>
<pre tabindex="0"><code>import sys
# Expect 2 args the event type and a value unique ID for the wi
if sys.argv\[0\] == &#34;workitem.updated&#34; : 
    wi = GetWorkItem(int(sys.argv\[1\]))
    parentwi = GetParentWorkItem(wi)
    if parentwi == None:
        LogInfoMessage(&#34;Work item &#39;&#34; + str(wi.id) + &#34;&#39; has no parent&#34;)
    else:
        LogInfoMessage(&#34;Work item &#39;&#34; + str(wi.id) + &#34;&#39; has parent &#39;&#34; + str(parentwi.id) + &#34;&#39;&#34;)

        results = \[c for c in GetChildWorkItems(parentwi) if c\[&#34;fields&#34;\]\[&#34;System.State&#34;\] != &#34;Done&#34;\]
        if  len(results) == 0 :
            LogInfoMessage(&#34;All child work items are &#39;Done&#39;&#34;)
            parentwi\[&#34;fields&#34;\]\[&#34;System.State&#34;\] = &#34;Done&#34;
            UpdateWorkItem(parentwi)
            msg = &#34;Work item &#39;&#34; + str(parentwi.id) + &#34;&#39; has been set as &#39;Done&#39; as all its child work items are done&#34;
            SendEmail(&#34;richard@blackmarble.co.uk&#34;,&#34;Work item &#39;&#34; + str(parentwi.id) + &#34;&#39; has been updated&#34;, msg)
            LogInfoMessage(msg)
        else:
            LogInfoMessage(&#34;Not all child work items are &#39;Done&#39;&#34;)
else:
	LogErrorMessage(&#34;Was not expecting to get here&#34;)
	LogErrorMessage(sys.argv)
</code></pre><p>I have recently done a fairly major update to the project. The key changes are:</p>
<ul>
<li>
<p>Rename of project, repo, and namespaces to reflect Azure DevOps (the namespace change is a breaking change for existing users)</p>
</li>
<li>
<p>The scripts that are run can now be</p>
</li>
<li>
<p>A fixed file name for the web instance running the service</p>
</li>
<li>
<p>Based on the event type sent to the service</p>
</li>
<li>
<p>Use the subscription ID, thus allowing many scripts (new)</p>
</li>
<li>
<p>A single instance of the web site running the events processor can now handle calls from many Azure DevOps instances.</p>
</li>
<li>
<p>Improved installation process on Azure (well at least tried to make the documentation clearer and sort out a couple of MSDeploy issues)</p>
</li>
</ul>
<p>Full details are on the project can be seen on the solutions <a href="https://github.com/rfennell/VSTSServiceHookDsl/wiki">WIKI</a>, maybe you will find it of use. Let me know if the documentation is good enough</p>
]]></content:encoded>
    </item>
    <item>
      <title>YAML documentation for my Azure Pipeline Tasks (and how I generated it)</title>
      <link>https://blog.richardfennell.net/posts/yaml-documentation-for-my-azure-pipeline-tasks-and-how-i-generated-it/</link>
      <pubDate>Thu, 25 Oct 2018 16:42:27 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/yaml-documentation-for-my-azure-pipeline-tasks-and-how-i-generated-it/</guid>
      <description>&lt;p&gt;There is a general move in &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?toc=/azure/devops/pipelines/toc.json&amp;amp;bc=/azure/devops/boards/pipelines/breadcrumb/toc.json&amp;amp;view=vsts&#34;&gt;Azure DevOps Pipelines&lt;/a&gt; to using &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started-yaml?view=vsts&#34;&gt;YAML&lt;/a&gt;, as opposed to the designer, to define your pipelines. This is particularly enforced when using them via the new &lt;a href=&#34;https://github.com/marketplace/azure-pipelines&#34;&gt;GitHub Marketplace Azure Pipelines&lt;/a&gt; method where YAML appears to be the only option.&lt;/p&gt;
&lt;p&gt;This has shown up a hole in my &lt;a href=&#34;https://github.com/rfennell/AzurePipelines/wiki&#34;&gt;Pipeline Tasks documentation&lt;/a&gt;, I had nothing on YAML!&lt;/p&gt;
&lt;p&gt;So I have added a YAML usage page for each set of tasks in each of my extensions e.g &lt;a href=&#34;https://github.com/rfennell/AzurePipelines/wiki/File-Copier-Tasks-YAML&#34;&gt;the file utilities tasks&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>There is a general move in <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?toc=/azure/devops/pipelines/toc.json&amp;bc=/azure/devops/boards/pipelines/breadcrumb/toc.json&amp;view=vsts">Azure DevOps Pipelines</a> to using <a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/get-started-yaml?view=vsts">YAML</a>, as opposed to the designer, to define your pipelines. This is particularly enforced when using them via the new <a href="https://github.com/marketplace/azure-pipelines">GitHub Marketplace Azure Pipelines</a> method where YAML appears to be the only option.</p>
<p>This has shown up a hole in my <a href="https://github.com/rfennell/AzurePipelines/wiki">Pipeline Tasks documentation</a>, I had nothing on YAML!</p>
<p>So I have added a YAML usage page for each set of tasks in each of my extensions e.g <a href="https://github.com/rfennell/AzurePipelines/wiki/File-Copier-Tasks-YAML">the file utilities tasks</a>.</p>
<p>Now, as are most developers, I am lazy. I was not going to type all that information. So I wrote a <a href="https://github.com/rfennell/AzurePipelines/blob/master/scripts/Generate-YAMLDocumation.ps1">script</a> to generate the markdown from respective <strong>task.json</strong> files in the repo. Now this script will need some work for others to use as it relies on some special handling due to quirks of my directory structure, but I hope it will be of use to others.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Microsoft post root cause analysis on recent Azure DevOps Issues</title>
      <link>https://blog.richardfennell.net/posts/microsoft-post-root-cause-analysis-on-recent-azure-devops-issues/</link>
      <pubDate>Wed, 17 Oct 2018 10:34:32 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/microsoft-post-root-cause-analysis-on-recent-azure-devops-issues/</guid>
      <description>&lt;p&gt;Azure DevOps has had some serious issue over the past couple of weeks with availability here in Europe.&lt;/p&gt;
&lt;p&gt;A really good open and detailed &lt;a href=&#34;https://blogs.msdn.microsoft.com/vsoservice/?p=17665&#34;&gt;root cause analysis has just been posted&lt;/a&gt; by the Azure DevOps team at Microsoft. It also covers the mitigations they are putting place to make sure this same issues do not occur again.&lt;/p&gt;
&lt;p&gt;We all have to remember that the cloud is not magic. Cloud service providers will have problems like any on-premise services; but trying to hide them does nothing to build confidence. So I for one applaud posts like this. I just wish all cloud service providers were as open when problem occur.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Azure DevOps has had some serious issue over the past couple of weeks with availability here in Europe.</p>
<p>A really good open and detailed <a href="https://blogs.msdn.microsoft.com/vsoservice/?p=17665">root cause analysis has just been posted</a> by the Azure DevOps team at Microsoft. It also covers the mitigations they are putting place to make sure this same issues do not occur again.</p>
<p>We all have to remember that the cloud is not magic. Cloud service providers will have problems like any on-premise services; but trying to hide them does nothing to build confidence. So I for one applaud posts like this. I just wish all cloud service providers were as open when problem occur.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Using Paths in PR Triggers on an Azure DevOps Pipelines Builds</title>
      <link>https://blog.richardfennell.net/posts/using-paths-in-pr-triggers-on-an-azure-devops-pipelines-builds/</link>
      <pubDate>Tue, 02 Oct 2018 19:49:08 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/using-paths-in-pr-triggers-on-an-azure-devops-pipelines-builds/</guid>
      <description>&lt;p&gt;When I started creating OSS extensions for Azure DevOps Pipelines (starting on TFSPreview, then VSO, then VSTS and now named Azure DevOps) I made the mistake of putting all my extensions in a single GitHub repo. I thought this would make life easier, I was wrong, it should have been a repo per extension.&lt;/p&gt;
&lt;p&gt;I have considered splitting the GitHub repo, but as a number of people have forked it, over 100 at the last count, I did not want to start a chain of chaos for loads of people.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>When I started creating OSS extensions for Azure DevOps Pipelines (starting on TFSPreview, then VSO, then VSTS and now named Azure DevOps) I made the mistake of putting all my extensions in a single GitHub repo. I thought this would make life easier, I was wrong, it should have been a repo per extension.</p>
<p>I have considered splitting the GitHub repo, but as a number of people have forked it, over 100 at the last count, I did not want to start a chain of chaos for loads of people.</p>
<p>This initial choice has meant that until very recently I could not use the Pull Request triggers in Azure DevOps Pipelines against my GitHub repo. This was because all builds associated with the repo triggered on any extension PR. So, I had to trigger builds manually, providing the branch name by hand. A bit of a pain, and prone to error.</p>
<p>I am pleased to say that with the roll out of <a href="https://docs.microsoft.com/en-us/azure/devops/release-notes/2018/sprint-140-update">Sprint 140</a> we now get the option to add a path filter to PR triggers on builds linked to GitHub repo; something we have had for Azure DevOps hosted Git repos since <a href="https://docs.microsoft.com/en-us/azure/devops/release-notes/2017/nov-28-vsts">Sprint 126</a>.</p>
<p>So now my <a href="https://blogs.blackmarble.co.uk/rfennell/2018/03/20/using-vsts-gates-to-help-improve-my-deployment-pipeline-of-vsts-extensions-to-the-visual-studio-marketplace/">release process</a> is improved. If I add a path filter as shown below, my build and hence release process trigger on a PR just as I need.</p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/10/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/10/image_thumb.png" title="image"></a></p>
<p>It is just a shame that the GitHub PR only checks the build, not the whole release, before saying all is OK. Hope we see linking to complete Azure DevOps Pipelines in the future.</p>
]]></content:encoded>
    </item>
    <item>
      <title>TFS 2018 Update 3 Released</title>
      <link>https://blog.richardfennell.net/posts/tfs-2018-update-3-released/</link>
      <pubDate>Mon, 17 Sep 2018 13:15:07 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/tfs-2018-update-3-released/</guid>
      <description>&lt;p&gt;Whilst I was off work last week TFS 2018 Update 3 was released. As stated in the &lt;a href=&#34;https://docs.microsoft.com/en-us/visualstudio/releasenotes/tfs2018-update3&#34;&gt;2018.3 release notes&lt;/a&gt; this is the final bug fix update release of TFS 2018.&lt;/p&gt;
&lt;p&gt;The next major release of TFS will not be named TFS 2019 as you might have expected, but will use the new name of &lt;a href=&#34;https://azure.microsoft.com/en-us/blog/introducing-azure-devops/&#34;&gt;Azure DevOps Server&lt;/a&gt;. You can see the features planned for this next release in the &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/devops/release-notes/&#34;&gt;Azure DevOps Features Timeline&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Whilst I was off work last week TFS 2018 Update 3 was released. As stated in the <a href="https://docs.microsoft.com/en-us/visualstudio/releasenotes/tfs2018-update3">2018.3 release notes</a> this is the final bug fix update release of TFS 2018.</p>
<p>The next major release of TFS will not be named TFS 2019 as you might have expected, but will use the new name of <a href="https://azure.microsoft.com/en-us/blog/introducing-azure-devops/">Azure DevOps Server</a>. You can see the features planned for this next release in the <a href="https://docs.microsoft.com/en-us/azure/devops/release-notes/">Azure DevOps Features Timeline</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Postmortem published by the Microsoft VSTS Team on last week&#39;s Azure outage</title>
      <link>https://blog.richardfennell.net/posts/postmortem-published-by-the-microsoft-vsts-team-on-last-weeks-azure-outage/</link>
      <pubDate>Tue, 11 Sep 2018 07:40:58 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/postmortem-published-by-the-microsoft-vsts-team-on-last-weeks-azure-outage/</guid>
      <description>&lt;p&gt;The Azure DevOps (VSTS) team have published the &lt;a href=&#34;https://blogs.msdn.microsoft.com/vsoservice/?p=17485&#34;&gt;promised postmortem&lt;/a&gt; on the outage on the 4th of September. It gives good detail on what actually happened to the South Central Azure Datacenter and how it effected VSTS (as it was then called). More interestingly it provides a discussion of mitigations they plan to put in place to stop a single datacentre failure having such a serious effect in the future. Great openness as always from the team&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The Azure DevOps (VSTS) team have published the <a href="https://blogs.msdn.microsoft.com/vsoservice/?p=17485">promised postmortem</a> on the outage on the 4th of September. It gives good detail on what actually happened to the South Central Azure Datacenter and how it effected VSTS (as it was then called). More interestingly it provides a discussion of mitigations they plan to put in place to stop a single datacentre failure having such a serious effect in the future. Great openness as always from the team</p>
]]></content:encoded>
    </item>
    <item>
      <title>VSTS becomes Azure DevOps</title>
      <link>https://blog.richardfennell.net/posts/vsts-becomes-azure-devops/</link>
      <pubDate>Mon, 10 Sep 2018 15:49:11 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/vsts-becomes-azure-devops/</guid>
      <description>&lt;p&gt;Today Microsoft made a big announcement, VSTS is now Azure DevOps. The big change is they have split VSTS into 5 services you can use together or independently, including Azure Pipelines for CI/CD - free for open source and available in the GitHub CI marketplace. An important thing to note is that &lt;strong&gt;IT IS NOT JUST FOR AZURE.&lt;/strong&gt; Don&amp;rsquo;t be afraid of the name. There a wide range of connectors to other cloud providers such as AWS and Google Cloud, as will as many other DevOps tools &lt;a href=&#34;https://azure.microsoft.com/en-us/blog/introducing-azure-devops/&#34;&gt;Learn more at have a look at the official post&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today Microsoft made a big announcement, VSTS is now Azure DevOps. The big change is they have split VSTS into 5 services you can use together or independently, including Azure Pipelines for CI/CD - free for open source and available in the GitHub CI marketplace. An important thing to note is that <strong>IT IS NOT JUST FOR AZURE.</strong> Don&rsquo;t be afraid of the name. There a wide range of connectors to other cloud providers such as AWS and Google Cloud, as will as many other DevOps tools <a href="https://azure.microsoft.com/en-us/blog/introducing-azure-devops/">Learn more at have a look at the official post</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Videos do not play in VSTS WIKI via relative links - workaround</title>
      <link>https://blog.richardfennell.net/posts/videos-do-not-play-in-vsts-wiki-via-relative-links-workaround/</link>
      <pubDate>Fri, 31 Aug 2018 12:01:54 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/videos-do-not-play-in-vsts-wiki-via-relative-links-workaround/</guid>
      <description>&lt;h3 id=&#34;the-problem&#34;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;https://docs.microsoft.com/en-us/vsts/project/wiki/markdown-guidance?view=vsts&#34;&gt;documentation&lt;/a&gt; for the VSTS WIKI suggests you can embed a video in a VSTS WIKI using the markdown/HTML```
&lt;video src=&#34;\_media/vstswiki\_mid.mp4&#34; width=400 controls&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Problem is that this does not seem to work, the MP4 just does not appear, you get an empty video player. However, if you swap to a full URL it does work e.g.&lt;/code&gt;
&lt;video src=&#34;https://sec.ch9.ms/ch9/7247/7c8ddc1a-348b-4ba9-ab61-51fded6e7247/vstswiki\_high.mp4&#34; width=400 controls&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-This&#34; data-lang=&#34;This&#34;&gt;
### The Workaround

The workaround is to either place the MP4 file in some URL accessible location e.g. some Azure web space (not really addressing the problem), or more usefully use the [VSTS API to get the file](https://docs.microsoft.com/en-us/rest/api/vsts/git/items/get?view=vsts-rest-4.1) out the repo that backs the WIKI. The format of the HTML tag becomes```
&amp;lt;video src=&amp;#34;https://vstsinstance.visualstudio.com/MyTeamProject/\_apis/git/repositories/MyTeamProject.wiki/Items?path=\_media%2Fvstswiki\_high.mp4 width=400&amp;#34; controls&amp;gt;
&amp;lt;/video&amp;gt;
```This will get the current version of the file on default branch, you can add extra parameters to to specify versions and branches if required as per the [API documentation](https://docs.microsoft.com/en-us/rest/api/vsts/git/?view=vsts-rest-4.1). So not a perfect solution as you have to think about branches and versions, they are not handled automatically, but at least it does work
&lt;/code&gt;&lt;/pre&gt;</description>
      <content:encoded><![CDATA[<h3 id="the-problem">The Problem</h3>
<p>The <a href="https://docs.microsoft.com/en-us/vsts/project/wiki/markdown-guidance?view=vsts">documentation</a> for the VSTS WIKI suggests you can embed a video in a VSTS WIKI using the markdown/HTML```
<video src="\_media/vstswiki\_mid.mp4" width=400 controls>
</video></p>
<p><code>Problem is that this does not seem to work, the MP4 just does not appear, you get an empty video player. However, if you swap to a full URL it does work e.g.</code>
<video src="https://sec.ch9.ms/ch9/7247/7c8ddc1a-348b-4ba9-ab61-51fded6e7247/vstswiki\_high.mp4" width=400 controls>
</video></p>
<pre tabindex="0"><code class="language-This" data-lang="This">
### The Workaround

The workaround is to either place the MP4 file in some URL accessible location e.g. some Azure web space (not really addressing the problem), or more usefully use the [VSTS API to get the file](https://docs.microsoft.com/en-us/rest/api/vsts/git/items/get?view=vsts-rest-4.1) out the repo that backs the WIKI. The format of the HTML tag becomes```
&lt;video src=&#34;https://vstsinstance.visualstudio.com/MyTeamProject/\_apis/git/repositories/MyTeamProject.wiki/Items?path=\_media%2Fvstswiki\_high.mp4 width=400&#34; controls&gt;
&lt;/video&gt;
```This will get the current version of the file on default branch, you can add extra parameters to to specify versions and branches if required as per the [API documentation](https://docs.microsoft.com/en-us/rest/api/vsts/git/?view=vsts-rest-4.1). So not a perfect solution as you have to think about branches and versions, they are not handled automatically, but at least it does work
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Registering an agent with VSTS and getting the message &amp;quot;Agent pool not found&amp;quot;</title>
      <link>https://blog.richardfennell.net/posts/registering-an-agent-with-vsts-and-getting-the-message-agent-pool-not-found/</link>
      <pubDate>Thu, 16 Aug 2018 20:58:06 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/registering-an-agent-with-vsts-and-getting-the-message-agent-pool-not-found/</guid>
      <description>&lt;p&gt;When you want to register a build agent with VSTS, you use the VSTS instance’s URL and a user’s Personal Access Token (PAT). Whilst doing this today I connected to the VSTS instance OK but got the error &amp;ldquo;Agent pool not found&amp;rdquo;.when I was asked to pick the agent pool to add the new agent to.&lt;/p&gt;
&lt;p&gt;As the user who’s PAT I was using was a Build Administrator I was a bit confused, but then I remembered to check their user access level. It was set to Stakeholder, once this was changed to Basic I was able to register the agent without use.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>When you want to register a build agent with VSTS, you use the VSTS instance’s URL and a user’s Personal Access Token (PAT). Whilst doing this today I connected to the VSTS instance OK but got the error &ldquo;Agent pool not found&rdquo;.when I was asked to pick the agent pool to add the new agent to.</p>
<p>As the user who’s PAT I was using was a Build Administrator I was a bit confused, but then I remembered to check their user access level. It was set to Stakeholder, once this was changed to Basic I was able to register the agent without use.</p>
<p>Also, so as to not use up a Basic license, when I did not need to, I swapped the user back to being a Stakeholder once the agent was registered. This can be done as the token used for the actual build is not the one used to register it, but one assigned at build time by VSTS.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Experiences migrating TFS XML Team Project Templates to Inherited Team Project Templates</title>
      <link>https://blog.richardfennell.net/posts/experiences-migrating-tfs-xml-team-project-templates-to-inherited-team-project-templates/</link>
      <pubDate>Thu, 02 Aug 2018 20:20:30 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/experiences-migrating-tfs-xml-team-project-templates-to-inherited-team-project-templates/</guid>
      <description>&lt;p&gt;You have always been able to customise your Team Projects in TFS, &lt;a href=&#34;https://docs.microsoft.com/en-us/vsts/work/customize/reference/process-templates/customize-process?view=vsts&#34;&gt;by editing a host of XML files&lt;/a&gt;, but it was not a pleasant experience. In VSTS a far more pleasant to use web based &lt;a href=&#34;https://docs.microsoft.com/en-us/vsts/organizations/settings/work/customize-process?view=vsts&#34;&gt;inherited customisation model&lt;/a&gt; was added, much to, I think, most administrators relief.&lt;/p&gt;
&lt;p&gt;If you used the &lt;a href=&#34;https://docs.microsoft.com/en-us/vsts/articles/migration-overview?view=vsts&#34;&gt;TFS DB migration service&lt;/a&gt; you ended up with a VSTS instance full of the the XML style team projects, and you were stuck there, with no way to change these to the new inherited mode, that is until now as &lt;a href=&#34;https://blogs.msdn.microsoft.com/devops/2018/07/06/moving-from-hosted-xml-to-inheritance/&#34;&gt;Microsoft have released to preview a conversion tool&lt;/a&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>You have always been able to customise your Team Projects in TFS, <a href="https://docs.microsoft.com/en-us/vsts/work/customize/reference/process-templates/customize-process?view=vsts">by editing a host of XML files</a>, but it was not a pleasant experience. In VSTS a far more pleasant to use web based <a href="https://docs.microsoft.com/en-us/vsts/organizations/settings/work/customize-process?view=vsts">inherited customisation model</a> was added, much to, I think, most administrators relief.</p>
<p>If you used the <a href="https://docs.microsoft.com/en-us/vsts/articles/migration-overview?view=vsts">TFS DB migration service</a> you ended up with a VSTS instance full of the the XML style team projects, and you were stuck there, with no way to change these to the new inherited mode, that is until now as <a href="https://blogs.msdn.microsoft.com/devops/2018/07/06/moving-from-hosted-xml-to-inheritance/">Microsoft have released to preview a conversion tool</a>.</p>
<p>I have been trying this tool to migrate all our active XML based team projects to Inherited equivalents, and it has worked very well for me, but I have to say, we don’t have any hugely complex customisations, so your mileage may vary depending on how much you modified your XML based team project templates.</p>
<p>However, I wanted to go further than the basic process as <a href="https://blogs.msdn.microsoft.com/devops/2018/07/06/moving-from-hosted-xml-to-inheritance/">documented</a></p>
<p>Since moving to VSTS all our new team project have been created  using an inherited template based on Scrum. I wanted to move all our active XML based team project to this standardised template. This took a little extra work.</p>
<p>The basic process is easy as to change Inherited Process you</p>
<ol>
<li>In the instance admin page <code>https://\[instance\].visualstudio.com/\_settings/process</code> pick the target template</li>
<li>Click on the ellipse (…) and pick ‘Change team project to use ….’</li>
<li>Pick the team project you wish to migrate and you are done</li>
</ol>
<p><strong>REMEMBER</strong>: A really nice touch (with XML and Inherited templates) is that you can just switch back if you don’t like the result, no data is lost when you swap templates, but some of it might be hidden as fields are not shown on the new work item types.</p>
<p>The problem I had was that our old XML based team project templates had different customisation to our current inherited standard. To address this I needed to</p>
<ul>
<li>Adding a few fields to our standard inherited template based on Scrum, for critical legacy customisations</li>
<li>In one case a work item types in use in the XML template had no match in our current template. In this case I changed the work item type to it’s equivalent (we had used a variety of ‘flavours of PBI’ so this was not a major problem), adding a tag to the work items to they could be identified, then deleting the offending work item type.</li>
<li>I could conceive of a need for more complex remapping for work item types and fields, but I was able to avoid this.</li>
</ul>
<p>So once done, I was then able to migrate all the team project to my target process template.</p>
<p>So a very nice experience, and one that now means we can make sure all our team projects use the same set of customisation. No longer do we need to worry about customising in XML and Inherited models.</p>
]]></content:encoded>
    </item>
    <item>
      <title>A workaround for the error &amp;lsquo;TF14061: The workspace ws_1_18;Project Collection Build Service does not exist&amp;rsquo; when mapping a TFVC workspace</title>
      <link>https://blog.richardfennell.net/posts/a-workaround-for-the-error-tf14061-the-workspace-ws_1_18project-collection-build-service-does-not-exist-when-mapping-a-tfvc-workspace/</link>
      <pubDate>Wed, 30 May 2018 12:17:30 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/a-workaround-for-the-error-tf14061-the-workspace-ws_1_18project-collection-build-service-does-not-exist-when-mapping-a-tfvc-workspace/</guid>
      <description>&lt;p&gt;Whilst writing some training material for VSTS I hit a problem creating a TFVC workspace. I was using VS2017, linking a TFVC Repo to a local folder. I was connecting to the VSTS instance using an MSA.&lt;/p&gt;
&lt;p&gt;In Team Explorer, when I came to do a ‘Map &amp;amp; Get’ to map the source locations I got a ‘TF14061: The workspace ws_1_18;Project Collection Build Service does not exist’ error&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/05/image.png&#34;&gt;&lt;img alt=&#34;image&#34; loading=&#34;lazy&#34; src=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/05/image_thumb.png&#34; title=&#34;image&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Strange error, which I could see no obvious reason for. Turns out the work around was just to press the ‘Advanced’ link/button and accept the defaults&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Whilst writing some training material for VSTS I hit a problem creating a TFVC workspace. I was using VS2017, linking a TFVC Repo to a local folder. I was connecting to the VSTS instance using an MSA.</p>
<p>In Team Explorer, when I came to do a ‘Map &amp; Get’ to map the source locations I got a ‘TF14061: The workspace ws_1_18;Project Collection Build Service does not exist’ error</p>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/05/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/05/image_thumb.png" title="image"></a></p>
<p>Strange error, which I could see no obvious reason for. Turns out the work around was just to press the ‘Advanced’ link/button and accept the defaults</p>
]]></content:encoded>
    </item>
    <item>
      <title>Making sure when you use VSTS build numbers to version Android Packages they can be uploaded to the Google Play Store</title>
      <link>https://blog.richardfennell.net/posts/making-sure-when-you-use-vsts-build-numbers-to-version-android-packages-they-can-be-uploaded-to-the-google-play-store/</link>
      <pubDate>Sat, 12 May 2018 15:13:38 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/making-sure-when-you-use-vsts-build-numbers-to-version-android-packages-they-can-be-uploaded-to-the-google-play-store/</guid>
      <description>&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;
&lt;p&gt;I have a &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task&#34;&gt;VSTS build extension that can apply a VSTS generated build number to Android APK packages&lt;/a&gt;. This takes a VSTS build number and generates, and applies, the Version Name (a string) and Version Code (an integer) to the APK file manifest.&lt;/p&gt;
&lt;p&gt;The default parameters mean that the behaviour of this task is to assume (using a regular expression) the VSTS build number has at least three fields &lt;strong&gt;major.minor.patch&lt;/strong&gt; e.g. 1.2.3, and uses the 1.2 as the Version Name and the 3 as the Version Code.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="background">Background</h3>
<p>I have a <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task">VSTS build extension that can apply a VSTS generated build number to Android APK packages</a>. This takes a VSTS build number and generates, and applies, the Version Name (a string) and Version Code (an integer) to the APK file manifest.</p>
<p>The default parameters mean that the behaviour of this task is to assume (using a regular expression) the VSTS build number has at least three fields <strong>major.minor.patch</strong> e.g. 1.2.3, and uses the 1.2 as the Version Name and the 3 as the Version Code.</p>
<p>Now, it is important to note that the Version Code must be a integer between 1 and 2100000000 and for the <a href="https://developer.android.com/studio/publish/versioning">Google Play Store it must be incrementing between versions</a>.</p>
<p>So maybe these default parameter values for this task are not the best options?</p>
<h3 id="the-problem-the-way-we-use-the-task">The problem the way we use the task</h3>
<p>When we use the Android Manifest Versioning task for our <a href="http://tuserv.com/">tuServ Android packages</a> we use different parameter values, but we recently found these values still cause a problem.</p>
<p>Our VSTS build generates  build numbers with four parts <strong>$(Major).$(Minor).$(Year:yy)$(DayOfYear).$(rev:r)</strong></p>
<ul>
<li>$(Major) – set as a VSTS variable e.g. 1</li>
<li>$(Minor) – set as a VSTS variable e.g. 2</li>
<li>$(Year:yy)$(DayOfYear) – the day for the year e.g. 18101</li>
<li>$(rev:r) – the build count for the build definition for the day e.g. 1</li>
</ul>
<p>So we end up with build numbers in the form 1.2.18101.1</p>
<p>The Android version task is set in the build to make</p>
<ul>
<li>the Version Number {1}.{2}.{3}.{4}  - 1.2.18101.1</li>
<li>the Version Code {1}{2}{3}{4} – 12181011</li>
</ul>
<p>The problem is if we do more than 9 builds in a day, which is likely due to our continuous integration process, and release one of the later builds to the Google Play store, then the next day any build with a lower revision than 9 cannot be released to the store as its Version Code is lower than the previously published one e.g.</p>
<ul>
<li>day 1 the published build is 1.2.18101.11 so the Version Code is 121810111</li>
<li>day 2 the published build is 1.2.18102.1 so the Version Code is 12181021</li>
</ul>
<p>So the second Version Code is 10x smaller, hence the package cannot be published.</p>
<h3 id="the-solution">The Solution</h3>
<p>The answer in the end was straightforward and found by one of our engineers <a href="https://twitter.com/sarkimedes">Peter (@sarkimedes)</a>. It was to change the final block of the VSTS build number to <strong>$(rev:rrr)</strong>, as detailed in the <a href="https://docs.microsoft.com/en-us/vsts/build-release/concepts/definitions/build/options?view=vsts">VSTS documentation</a>. Thus zero padding the revision from .1 to .001. This allows up to 1000 builds per day before the problem of altering the Version Code order of magnitude problem occurs. Obviously, if you think you might do more than 1000 internal builds in a day you could zero pack as many digits as you want.</p>
<p>So using the new build version number</p>
<ul>
<li>day 1 the published build is 1.2.18101.011 so the Version Code is 1218101011</li>
<li>day 2 the published build is 1.2.18102.001 so the Version Code is 1218102001</li>
</ul>
<p>So a nice fix without any need to alter the Android Manifest Versioning task’s code. However, changing the default Version Code parameter to {1}{2}{3} is probably advisable.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Major new release of my VSTS Cross Platform Extension to build Release Notes</title>
      <link>https://blog.richardfennell.net/posts/major-new-release-of-my-vsts-cross-platform-extension-to-build-release-notes/</link>
      <pubDate>Fri, 27 Apr 2018 13:18:31 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/major-new-release-of-my-vsts-cross-platform-extension-to-build-release-notes/</guid>
      <description>&lt;p&gt;Today I have released a major new release, V2, of my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes&#34;&gt;VSTS Cross Platform Extension to build release notes&lt;/a&gt;. This new version is all down to the efforts of &lt;a href=&#34;https://github.com/gregpakes&#34;&gt;Greg Pakes&lt;/a&gt; who has completely re-written the task to use newer VSTS APIs.&lt;/p&gt;
&lt;p&gt;A minor issue is that this re-write has introduced a couple of breaking changes, as detailed below and on the &lt;a href=&#34;https://github.com/rfennell/vNextBuild/wiki/GenerateReleaseNotes---Node-based-Cross-Platform-Task&#34;&gt;project wiki&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;oAuth script access has to be enabled on the agent running the task&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/04/image.png&#34;&gt;&lt;img alt=&#34;image&#34; loading=&#34;lazy&#34; src=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/04/image_thumb.png&#34; title=&#34;image&#34;&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Today I have released a major new release, V2, of my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-XplatGenerateReleaseNotes">VSTS Cross Platform Extension to build release notes</a>. This new version is all down to the efforts of <a href="https://github.com/gregpakes">Greg Pakes</a> who has completely re-written the task to use newer VSTS APIs.</p>
<p>A minor issue is that this re-write has introduced a couple of breaking changes, as detailed below and on the <a href="https://github.com/rfennell/vNextBuild/wiki/GenerateReleaseNotes---Node-based-Cross-Platform-Task">project wiki</a></p>
<ul>
<li>oAuth script access has to be enabled on the agent running the task</li>
</ul>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/04/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/04/image_thumb.png" title="image"></a></p>
<ul>
<li>There are minor changes in the template format, but for the good, as it means both TFVC and GIT based releases now use a common template format. Samples can be found in the <a href="https://github.com/rfennell/vNextBuild/tree/master/SampleTemplates/XplatGenerateReleaseNotes%20%28Node%20based%29">project repo</a></li>
</ul>
<p>Because of the breaking changes, we made the decision to release both V1 and V2 of the task in the same extension package, so not forcing anyone to update unless they wish to. A technique I have not tried before, but seems to work well in testing.</p>
<p>Hope people still find the task of use and thanks again to Greg for all the work on the extension</p>
]]></content:encoded>
    </item>
    <item>
      <title>Backing up your TFVC and Git Source from VSTS</title>
      <link>https://blog.richardfennell.net/posts/backing-up-your-tfvc-and-git-source-from-vsts/</link>
      <pubDate>Fri, 20 Apr 2018 12:49:08 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/backing-up-your-tfvc-and-git-source-from-vsts/</guid>
      <description>&lt;h3 id=&#34;the-issue&#34;&gt;The Issue&lt;/h3&gt;
&lt;p&gt;Azure is a highly resilient service, and &lt;a href=&#34;https://azure.microsoft.com/en-gb/support/legal/sla/visual-studio-team-services/v1_2/&#34;&gt;VSTS has excellent SLAs&lt;/a&gt;. However, a question that is often asked is ‘How do I backup my VSTS instance?’. The simple answer is you don’t. Microsoft handle keeping the instance up, patched and serviceable. Hence, there is no built in means for you to get a local copy of all your source code, work items or CI/CD definitions. &lt;a href=&#34;https://visualstudio.uservoice.com/forums/330519-visual-studio-team-services/suggestions/5339461-provide-a-backup-service-for-visual-studio-team-se&#34;&gt;Though there have been requests for such a service&lt;/a&gt;. This can be an issue for some organisations, particularly for source control, where there can be a need to have a way to keep a private copy of source code for escrow, DR or similar purposes.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="the-issue">The Issue</h3>
<p>Azure is a highly resilient service, and <a href="https://azure.microsoft.com/en-gb/support/legal/sla/visual-studio-team-services/v1_2/">VSTS has excellent SLAs</a>. However, a question that is often asked is ‘How do I backup my VSTS instance?’. The simple answer is you don’t. Microsoft handle keeping the instance up, patched and serviceable. Hence, there is no built in means for you to get a local copy of all your source code, work items or CI/CD definitions. <a href="https://visualstudio.uservoice.com/forums/330519-visual-studio-team-services/suggestions/5339461-provide-a-backup-service-for-visual-studio-team-se">Though there have been requests for such a service</a>. This can be an issue for some organisations, particularly for source control, where there can be a need to have a way to keep a private copy of source code for escrow, DR or similar purposes.</p>
<h3 id="a-solution">A Solution</h3>
<p>To address this issue I decided to write a <a href="https://gist.github.com/rfennell/dc9e49a40d98d77c26698574d298dc53">PowerShell script</a> to download all the GIT and TFVC source in a VSTS instance. The following tactics were used</p>
<ul>
<li>Using the REST API to download each project’s TFVC code as a ZIP file. The use of a ZIP file avoids any long file path issues, a common problem with larger Visual Studio solutions with complex names</li>
<li>Clone each Git repo. I could download single Git branches as ZIP files via the API as per TFVC, but this seemed a poorer solution given how important branches are in Git.</li>
</ul>
<p>So that the process was run on regular basis I designed it to be run within a VSTS build. Again here I had choices:</p>
<ul>
<li>To pass in a Personal Access Token (PAT) to provide access rights to read the required source to be backed up. This has the advantage the script can be run inside or outside of a VSTS build. It also means that a single VSTS build can backup other VSTS instances as long as it has a suitable PAT for access</li>
<li>To use the <a href="https://stackoverflow.com/questions/38670306/executing-git-commands-inside-a-build-job-in-visual-studio-team-services-was-vs">System Token already available to the build agent</a>. This makes the script very neat, and PATs won’t expire, but means it only works within a VSTS build, and can only backup the VSTS instance the build is running on.</li>
</ul>
<p>I chose the former, so a single scheduled build could backup all my VSTS instances by running the script a number of time with different parameters</p>
<script src="https://gist.github.com/rfennell/dc9e49a40d98d77c26698574d298dc53.js"></script>
<p>To use this script you just pass in</p>
<ul>
<li>
<p>The name of the instance to backup</p>
</li>
<li>
<p>A valid PAT for the named instance</p>
</li>
<li>
<p>The path to backup too, which can be a UNC share assuming the build agent has rights to the location</p>
</li>
</ul>
<h3 id="whats-next">What’s Next</h3>
<p>The obvious next step is to convert the PowerShell script to be a VSTS Extension, at this point it would make sense to make it optional to use a provided PAT or the System Access Token. Also I could add code to allow a number of multiple cycling backups to be taken e.g. keep the last 3 backups These are maybe something for the future, but they don’t really seems a good return in investment at this time to package up a working script as an extensions just for a single VSTS instance.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Opps, I made that test VSTS extension public by mistake, what do I do now?</title>
      <link>https://blog.richardfennell.net/posts/opps-i-made-that-test-vsts-extension-public-by-mistake-what-do-i-do-now/</link>
      <pubDate>Sat, 14 Apr 2018 13:50:55 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/opps-i-made-that-test-vsts-extension-public-by-mistake-what-do-i-do-now/</guid>
      <description>&lt;p&gt;I recently, whilst changing a &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/09/major-update-to-my-cicd-process-for-vsts-extensions/&#34;&gt;CI/CD release pipeline&lt;/a&gt;, updated what was previously a private version of a VSTS extension in the &lt;a href=&#34;https://marketplace.visualstudio.com/&#34;&gt;VSTS Marketplace&lt;/a&gt; with a version of the VSIX package set to be public.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note, in my CI/CD process I have a private and public version of each extension (set of tasks), the former is used for functional testing within the CD process, the latter is the one everyone can see&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;So, this meant I had two public versions of the same extension, confusing.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I recently, whilst changing a <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/09/major-update-to-my-cicd-process-for-vsts-extensions/">CI/CD release pipeline</a>, updated what was previously a private version of a VSTS extension in the <a href="https://marketplace.visualstudio.com/">VSTS Marketplace</a> with a version of the VSIX package set to be public.</p>
<p><em>Note, in my CI/CD process I have a private and public version of each extension (set of tasks), the former is used for functional testing within the CD process, the latter is the one everyone can see</em>.</p>
<p>So, this meant I had two public versions of the same extension, confusing.</p>
<p>Turns out you can’t change a public extension back to be private, either via the UI or by uploading a corrected VSIX. Also you can’t delete any public extension that has ever been downloaded, and my previously private one had been downloaded once, by me for testing.</p>
<p>So my only option was to un-publish the previously private extension so only the correct version was visible in the public marketplace.</p>
<p>This meant I had to also alter my CI/CD process to change the extensionID of my private extension so I could publish a new private version of the extension.</p>
<p>Luckily, as all the GUIDs for the tasks within the extension did not change once I had installed the new version of the extension I had mispublished in my test VSTS instance my pipeline still worked.</p>
<p>Only downside is I am left with an un-publish ‘dead’ version listed in my private view of the marketplace. This is not a problem, just does not look ‘neat and tidy’</p>
]]></content:encoded>
    </item>
    <item>
      <title>Using VSTS Gates to help improve my deployment pipeline of VSTS Extensions to the Visual Studio Marketplace</title>
      <link>https://blog.richardfennell.net/posts/using-vsts-gates-to-help-improve-my-deployment-pipeline-of-vsts-extensions-to-the-visual-studio-marketplace/</link>
      <pubDate>Tue, 20 Mar 2018 11:30:43 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/using-vsts-gates-to-help-improve-my-deployment-pipeline-of-vsts-extensions-to-the-visual-studio-marketplace/</guid>
      <description>&lt;p&gt;My existing &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/09/major-update-to-my-cicd-process-for-vsts-extensions/&#34;&gt;VSTS CI/CD process&lt;/a&gt; has a problem that the deployment of a VSTS extension, from the moment it is uploaded to when it’s tasks are available to a build agent, is not instantiation. The process can potentially take a few minutes to roll out. The problem this delay causes is a perfect candidate for using &lt;a href=&#34;https://docs.microsoft.com/en-us/vsts/build-release/concepts/definitions/release/approvals/gates&#34;&gt;VSTS Release Gates&lt;/a&gt;; using the gate to make sure the expected version of a task is available to an agent before running the next stage of the CD pipeline e.g waiting after deploying a private build of an extension before trying to run functional tests. The problem is how to achieve this with the current VSTS gate options?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>My existing <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/09/major-update-to-my-cicd-process-for-vsts-extensions/">VSTS CI/CD process</a> has a problem that the deployment of a VSTS extension, from the moment it is uploaded to when it’s tasks are available to a build agent, is not instantiation. The process can potentially take a few minutes to roll out. The problem this delay causes is a perfect candidate for using <a href="https://docs.microsoft.com/en-us/vsts/build-release/concepts/definitions/release/approvals/gates">VSTS Release Gates</a>; using the gate to make sure the expected version of a task is available to an agent before running the next stage of the CD pipeline e.g waiting after deploying a private build of an extension before trying to run functional tests. The problem is how to achieve this with the current VSTS gate options?</p>
<h3 id="what-did-not-work">What did not work</h3>
<p>My first thought was to use the <a href="https://docs.microsoft.com/en-us/vsts/build-release/tasks/utility/http-rest-api">Invoke HTTP REST API gate</a>, calling the VSTS API <strong>https://<your vsts instance name>.visualstudio.com/_apis/distributedtask/tasks/<GUID of Task>.</strong> This API call returns a block of JSON containing details about the deployed task visible to the specified VSTS instance. In theory you can parse this data with a <a href="http://goessner.net/articles/JsonPath/">JSONPATH</a> query in the gates success criteria parameter to make sure the correct version of the task is deployed e.g. <strong>eq($.value[?(@.name == &ldquo;BuildRetensionTask&rdquo;)].contributionVersion, &ldquo;1.2.3&rdquo;)</strong> However, there is a problem. At this time the Invoke HTTP REST API gate task does not support the <strong>==</strong> equality operator in it’s success criteria field. I understand this will be addressed in the future, but the fact it is currently missing is a block to my current needs. Next I thought I could write a custom VSTS gate. These are basically ‘run on server’ tasks with a suitably crafted JSON manifest. The problem here is that this type of task does not allow any code (Node.JS or PowerShell) to be run. They only have a limited capability to invoke HTTP APIs or write messages to service bus. So I could not implement the code I needed to process the API response. So another dead end.</p>
<h3 id="what-did-work">What did work</h3>
<p>The answer, after a suggestion from the VSTS Release Management team at Microsoft, was to try the <a href="https://docs.microsoft.com/en-us/vsts/build-release/tasks/utility/azure-function">Azure Function gate</a>. To do this I created <a href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function">a new Azure Function</a>. I did this using the Azure Portal, picking the consumption billing model, C# and securing the function with a function key, basically the default options. I then added <a href="https://github.com/rfennell/vNextBuild/blob/master/AzureFunctions/VSTSExtensionGate/run.csx">the C# function code (stored in GitHub)</a>, to my newly created Azure Function. This function code takes</p>
<ul>
<li>The name of the VSTS instance</li>
<li>A personal access token (PAT) to access the VSTS instance</li>
<li>The GUID of the task to check for</li>
<li>And the version to check for</li>
</ul>
<p>It then returns a JSON block with true or false based on whether the required task version can be found. If any of the parameters are invalid an API error is returned By passing in this set of arguments my idea was that a single Azure Function could be used to check for the deployment of all my tasks. <strong>Note:</strong> Now I do realise I could also create a release pipeline for the Azure Function, but I chose to just create it via the Azure Portal. I know this is not best practice, but this was just a proof of concept. As usual the danger here is that this proof of concept might be one of those that is too useful and lives forever!</p>
<h3 id="to-use-the-azure-function">To use the Azure Function</h3>
<p>Using the Azure function is simple</p>
<ul>
<li>
<ul>
<li>Added an Azure Function <a href="https://docs.microsoft.com/en-us/vsts/build-release/concepts/definitions/release/approvals/gates">gate to a VSTS release</a></li>
<li>Set the <strong>URL</strong> parameter for the Azure Function. This value can be found from the Azure Portal. Note that you don’t need the Function Code query parameter in the URL as this is provided with the next gate parameter. I chose to use a <a href="https://docs.microsoft.com/en-us/vsts/build-release/concepts/library/variable-groups">variable group variable</a> for this parameter so it was easy to reuse between many CD pipelines</li>
<li>Set the <strong>Function Key</strong> parameter for the Azure Function, again you get this from the Azure Portal. This time I used a secure variable group variable</li>
<li>Set the <strong>Method</strong> parameter to POST</li>
<li>Set the <strong>Header</strong> content type as JSON</li>
</ul>
</li>
</ul>
<pre tabindex="0"><code>{
      &#34;Content-Type&#34;: &#34;application/json&#34;
}
</code></pre><ul>
<li>
<ul>
<li>Set the <strong>Body</strong> to contain the details of the VSTS instance and Task to check. This time I used a mixture of variable group variables, release specific variables (the GUID) and environment build/release variables. The key here is I got the version from the primary release artifact <strong>$(BUILD.BUILDNUMBER)</strong> so the correct version of the tasks is tested for automatically</li>
</ul>
</li>
</ul>
<pre tabindex="0"><code>{
     &#34;instance&#34;: &#34;$(instance)&#34;,
     &#34;pat&#34;: &#34;$(pat)&#34;,
     &#34;taskguid&#34;: &#34;$(taskGuid)&#34;,
     &#34;version&#34;: &#34;$(BUILD.BUILDNUMBER)&#34;
}
</code></pre><ul>
<li>Finally set  the <strong>Advanced/Completion Event</strong> to ApiResponse with the success criteria of```
eq(root[&lsquo;Deployed&rsquo;], &rsquo;true&rsquo;)
<pre tabindex="0"><code></code></pre></li>
</ul>
<p>Once this was done I was able to use the Azure function as a VSTS gate as required</p>
<h3 id="image"><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/03/image-1.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/03/image_thumb-1.png" title="image"></a></h3>
<h3 id="summary">Summary</h3>
<p>So I now have a gate that makes sure that for a given VSTS instance a task of a given version has been deployed. If you need this functionality all you need to do is create your own Azure Function instance, drop in <a href="https://github.com/rfennell/vNextBuild/blob/master/AzureFunctions/VSTSExtensionGate/run.csx">my code</a> and configure the VSTS gate appropriately. When equality == operator becomes available for JSONPATH in the REST API Gate I might consider a swap back to a basic REST call, it is less complex to setup, but we shall see. The Azure function model does appear to work well</p>
]]></content:encoded>
    </item>
    <item>
      <title>Building private VSTS build agents using the Microsoft Packer based agent image creation model</title>
      <link>https://blog.richardfennell.net/posts/building-private-vsts-build-agents-using-the-microsoft-packer-based-agent-image-creation-model/</link>
      <pubDate>Tue, 27 Feb 2018 18:48:32 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/building-private-vsts-build-agents-using-the-microsoft-packer-based-agent-image-creation-model/</guid>
      <description>&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;
&lt;p&gt;Having automated builds is essential to any good development process. Irrespective of the build engine in use, VSTS, Jenkins etc. you need to have a means to create the VMs that are running the builds.&lt;/p&gt;
&lt;p&gt;You can of course do this by hand, but in many ways you are just extending the old ‘it works on my PC – the developer can build it only on their own PC’ problem i.e. it is hard to be sure what version of tools are in use. This is made worse by the fact it is too tempting for someone to remote onto the build VM to update some SDK or tool without anyone else’s knowledge.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="background">Background</h3>
<p>Having automated builds is essential to any good development process. Irrespective of the build engine in use, VSTS, Jenkins etc. you need to have a means to create the VMs that are running the builds.</p>
<p>You can of course do this by hand, but in many ways you are just extending the old ‘it works on my PC – the developer can build it only on their own PC’ problem i.e. it is hard to be sure what version of tools are in use. This is made worse by the fact it is too tempting for someone to remote onto the build VM to update some SDK or tool without anyone else’s knowledge.</p>
<p>In an endeavour to address this problem we need a means to create our build VMs in a consistent standardised manner i.e a configuration as code model.</p>
<p><a href="https://blogs.blackmarble.co.uk/rhepworth/2017/03/02/define-once-deploy-everywhere-sort-of/">At Black Marble we have been using Lability</a> to build our lab environments and there is no reason we could not use the same system to create our VSTS build agent VMs</p>
<ul>
<li>Creating base VHDs disk images with patched copies of Windows installed (which we update on a regular basis)</li>
<li>Use <a href="https://github.com/VirtualEngine/Lability">Lability</a> to provision all the required tools – this would need to include all the associated reboots these installers would require. Noting that rebooting and restarting at the correct place, for non DSC based resources, is not Lability’s strongest feature i.e. you have to do all the work in custom code</li>
</ul>
<p>However, there is an alternative. Microsoft have made their <a href="https://www.packer.io/">Packer</a> based method of creating VSTS Azure hosted agents available on <a href="https://github.com/Microsoft/vsts-image-generation">GitHub</a>. Hence, it made sense to me to base our build agent creation system on this standardised image; thus allowing easier migration of builds between private and hosted build agent pools whether in the cloud or on premises, due to the fact they had the same tools installed.</p>
<h3 id="the-basic-process">The Basic Process</h3>
<p>To enable this way of working I <a href="https://github.com/blackmarble/vsts-image-generation">forked the Microsoft repo</a> and modified the Packer JSON configuration file to build Hyper-V based images as opposed to Azure ones. I aimed to make as few changes as possible to ease the process of keeping my forked repo in sync with future changes to the Microsoft standard build agent. In effect replacing the <strong>builder</strong> section of the packer configuration and leaving the <strong>providers</strong> unaltered</p>
<p>So, in doing this I learnt a few things</p>
<h3 id="which-iso-to-use">Which ISO to use?</h3>
<p>Make sure you use a current Operating System ISO. First it save time as it is already patched; but more importantly the provider scripts in the Microsoft configuration assume certain Windows features are available for installation (Containers with Docker support specifically) that were not present on the 2016 RTM ISO</p>
<h3 id="building-an-answeriso">Building an Answer.ISO</h3>
<p>In the <a href="https://www.packer.io/docs/builders/hyperv-iso.html">sample I found</a> for the Packer <strong>hyperv-iso</strong> builder the <strong>AutoUnattended.XML</strong> answers file is provided on an ISO (as opposed to a virtual floppy as floppies are not support on Gen2 HyperV VMs). This means when you edit the answers file you need to rebuild the ISO prior to running Packer.</p>
<p>The sample script to do this has lines to ‘Enable UEFI and disable Non EUFI’; I found that if these lines of PowerShell were run the answers file was ignored on the ISO. I had to comment them out. It seems an <strong>AutoUnattended.XML</strong> answers file edited in VSCode is the correct encoding by default.</p>
<p>I also found that if I ran the PowerShell script to create the ISO from within VSCode’s integrated terminal the ISO builder <strong>mkisofs.exe</strong> failed with an internal error. However, it worked fine from a default PowerShell windows.</p>
<h3 id="installing-the-net-35-feature">Installing the .NET 3.5 Feature</h3>
<p>When a provider tried to install the .NET 3.5 feature using the command</p>
<p><strong>Install-WindowsFeature -Name NET-Framework-Features -IncludeAllSubFeature</strong></p>
<p>it failed.</p>
<p>Seems this is a bug in Windows 2016 and the workaround is to specify the –Source location on the install media</p>
<p><strong>Install-WindowsFeature -Name NET-Framework-Features -IncludeAllSubFeature -Source &ldquo;D:sourcessxs&rdquo;</strong></p>
<p>Once the script was modified in this manner it ran without error</p>
<h3 id="well-how-long-does-it-take">Well how long does it take?</h3>
<p>The Packer process is slow, Microsoft say for an Azure VM it can take up to over 8 hours. A HyperV VM is no faster.</p>
<p>I also found the process a bit brittle. I had to restart the process a good few times as….</p>
<ul>
<li>I ran out of disk space (no unsurprising this broke the process)</li>
<li>The new VM did not get a DHCP assigned IP address when connected to the network via the HyperV Default Switch. A reboot of my HyperV host PC fixed this.</li>
<li>Packer decided the VM had rebooted when it had not – usually due to a slow install of some feature or network issues</li>
<li>My Laptop went to sleep and caused one of the above problems</li>
</ul>
<h3 id="so-i-have-a-sysprepd-vhd-now-what-do-i-do-with-it-now">So I have a SysPrep’d VHD now what do I do with it now?</h3>
<p>At this point I have options of what to do with this new exported HyperV image. I could manually create build agent VM instances.</p>
<p>However, it appeals to me to use this new VHD as a based image for Lability, replacing our default ‘empty patched Operating System’ image creation system, so I have a nice consistent way to provision VMs onto our Hyper-V servers.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Versioning your ARM templates within a VSTS CI/CD pipeline with Semantic Versioning</title>
      <link>https://blog.richardfennell.net/posts/versioning-your-arm-templates-within-a-vsts-ci-cd-pipeline-with-semantic-versioning/</link>
      <pubDate>Sat, 03 Feb 2018 15:23:59 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/versioning-your-arm-templates-within-a-vsts-ci-cd-pipeline-with-semantic-versioning/</guid>
      <description>&lt;p&gt;I wrote a post recently &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2018/01/22/versioning-your-arm-templates-within-a-vsts-ci-cd-pipeline/&#34;&gt;Versioning your ARM templates within a VSTS CI/CD pipeline&lt;/a&gt;. I realised since writing it that it does not address the issue of if you wish to version your ARM Templates using &lt;a href=&#34;https://semver.org/&#34;&gt;Semantic Versioning&lt;/a&gt;. My JSON versioning task I used did not support the option of not extracting a numeric version number e.g. 1.2.3.4 from a VSTS build number. To address this limitation I have modified &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task&#34;&gt;my Version JSON file task&lt;/a&gt; to address. This change to my task allows it to be used with the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=gittools.gitversion#overview&#34;&gt;GitVersion VSTS task&lt;/a&gt; to manage the semantic versioning. For more details on &lt;a href=&#34;http://gitversion.readthedocs.io/en/latest/&#34;&gt;GitVersion see the project documentation&lt;/a&gt;. Hence, I my now able to generate a version number using GitVersion and pass this in to the versioning task directly using a build variable.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I wrote a post recently <a href="https://blogs.blackmarble.co.uk/rfennell/2018/01/22/versioning-your-arm-templates-within-a-vsts-ci-cd-pipeline/">Versioning your ARM templates within a VSTS CI/CD pipeline</a>. I realised since writing it that it does not address the issue of if you wish to version your ARM Templates using <a href="https://semver.org/">Semantic Versioning</a>. My JSON versioning task I used did not support the option of not extracting a numeric version number e.g. 1.2.3.4 from a VSTS build number. To address this limitation I have modified <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task">my Version JSON file task</a> to address. This change to my task allows it to be used with the <a href="https://marketplace.visualstudio.com/items?itemName=gittools.gitversion#overview">GitVersion VSTS task</a> to manage the semantic versioning. For more details on <a href="http://gitversion.readthedocs.io/en/latest/">GitVersion see the project documentation</a>. Hence, I my now able to generate a version number using GitVersion and pass this in to the versioning task directly using a build variable.</p>
<ul>
<li>Add the GitVersion task at the start of the build, with its default parameters</li>
<li>Add my JSON versioning task with default parameters apart from
<ul>
<li><strong>Version Number</strong> set to <strong>$(GitVersion.SemVer)</strong></li>
<li><strong>Use Version Number without Processing (Advanced)</strong> checked</li>
<li><strong>Filename Pattern (Advanced)</strong> set to <strong>azuredeploy.json</strong></li>
<li><strong>Field to update (Advanced)</strong> set to <strong>contentVersion</strong></li>
</ul>
</li>
</ul>
<p><a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/02/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/02/image_thumb.png" title="image"></a> In the logs you see output similar to the following```
Source Directory: E:Build2_work361s
Filename Pattern: azuredeploy.json
Version Number/Build Number: 0.1.0-unstable.843
Use Build Number Directly: true
Version Filter to extract build number: d+.d+.d+.d+
Version Format for JSON File: {1}.{2}.{3}
Field to update (all if empty): contentVersion
Output: Version Number Parameter Name: OutputedVersion
Using the provided build number without any further processing
JSON Version Name will be: 0.1.0-unstable.843
Will apply 0.1.0-unstable.843 to 12 files.
Updating the field &lsquo;contentVersion&rsquo; version
Existing Tag: contentVersion&quot;: &ldquo;1.0.0.0&rdquo;
Replacement Tag: contentVersion&quot;: &ldquo;0.1.0-unstable.843&rdquo;
…</p>
<pre tabindex="0"><code></code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Creating test data for my Generate Release Notes Extension for use in CI/CD process</title>
      <link>https://blog.richardfennell.net/posts/creating-test-data-for-my-generate-release-notes-extension-for-use-in-ci-cd-process/</link>
      <pubDate>Fri, 19 Jan 2018 20:13:38 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/creating-test-data-for-my-generate-release-notes-extension-for-use-in-ci-cd-process/</guid>
      <description>&lt;p&gt;As part of the continued improvement to my CI/CD process I needed to provide a means so that whenever I test my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-GenerateReleaseNotes-Task&#34;&gt;Generate Release Notes Task&lt;/a&gt;, within it’s CI/CD process, new commits and work item associations are made. This is required because the task only picks up new commits and work items since the last successful running of a given build. So if the last release of the task extension was successful then the next set of tests have no associations to go in the release notes, not exactly exercising all the code paths! In the past I added this test data by hand, a new manual commit to the repo prior to a release; but why have a dog and bark yourself? Better to automate the process. This can done using a PowerShell file, run inline or stored in the builds source repo and run within a VSTS build. The code is shown below, you can pass in the required parameters, but I set sensible default for my purposes&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>As part of the continued improvement to my CI/CD process I needed to provide a means so that whenever I test my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-GenerateReleaseNotes-Task">Generate Release Notes Task</a>, within it’s CI/CD process, new commits and work item associations are made. This is required because the task only picks up new commits and work items since the last successful running of a given build. So if the last release of the task extension was successful then the next set of tests have no associations to go in the release notes, not exactly exercising all the code paths! In the past I added this test data by hand, a new manual commit to the repo prior to a release; but why have a dog and bark yourself? Better to automate the process. This can done using a PowerShell file, run inline or stored in the builds source repo and run within a VSTS build. The code is shown below, you can pass in the required parameters, but I set sensible default for my purposes</p>
<script src="https://gist.github.com/rfennell/2cc36232158518b3b36866bfd321644d.js"></script>
<p>For this PowerShell code to work you do need make some security changes to allow the build agent service user to write to the Git repo. <a href="https://docs.microsoft.com/en-gb/vsts/build-release/actions/scripts/git-commands">This is documented by Microsoft</a>. The PowerShell task to run this code is placed in a build as the only task <a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/01/image.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/01/image_thumb.png" title="image"></a> This build is then triggered as part of the release process <a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/01/image-1.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2018/01/image_thumb-1.png" title="image"></a> Note that the triggering of this build has to be such that it runs on a non-blocking build agent <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/">as discussed in my previous posts</a>. In my case I trigger the build to add the extra commits and work items just before triggering the validation build on my private Azure hosted agent. Now, there is no reason you can’t just run the PowerShell directly within the release if you wanted to. I chose to use a build so that the build could be reused between different VSTS extension CI/CD pipelines; remember I have two Generate Release Note Extensions, PowerShell and NodeJS Based. So another step to fully automating the whole release process.</p>
]]></content:encoded>
    </item>
    <item>
      <title>How I fixed my problem that my VSTS Build Extension was too big to upload to the Marketplace</title>
      <link>https://blog.richardfennell.net/posts/how-i-fixed-my-problem-that-my-vsts-build-extension-was-too-big-to-upload-to-the-marketplace/</link>
      <pubDate>Fri, 05 Jan 2018 14:48:33 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/how-i-fixed-my-problem-that-my-vsts-build-extension-was-too-big-to-upload-to-the-marketplace/</guid>
      <description>&lt;p&gt;Whist adding a couple of new tasks to my &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task&#34;&gt;VSTS Manifest Versioning Extension&lt;/a&gt; I hit the problem that VSIX package became too big to upload to the Marketplace. The error I saw in my CI/CD VSTS pipeline was```
##vso[task.logissue type=error;]error:
Failed Request: Bad Request(400) -
The extension package size &amp;lsquo;23255292 bytes&amp;rsquo; exceeds the
maximum package size &amp;lsquo;20971520 bytes&amp;rsquo;&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-This&#34; data-lang=&#34;This&#34;&gt;
1.  They get a list of files
2.  Extract a version number from the build number
3.  Then apply this to one or more files in a product/task specific manner

there has been some cut and paste coding. This means that I have NPM modules in the tasks **package.json** file that were not needed for a given task. I could manually address this but there is an NPM module to help, DepCheck. First install the [DepCheck](https://www.npmjs.com/package/depcheck) module```
npm install depcheck –g
```then run **depcheck** from the command line whist within your task’s folder. This returns a list of modules listed in the **package.json** that are not referenced in the code files. These can then be removed from the **package.json.**  e.g. I saw```
Unused dependencies
\* @types/node
\* @types/q
\* Buffer
\* fs
\* request
\* tsd
Unused devDependencies
\* @types/chai
\* @types/mocha
\* @types/node
\* mocha-junit-reporter
\* ts-loader
\* ts-node
\* typings
```The important ones to focus on are the first block (non-development references), as these are the ones that are packaged with the production code in the VSIX; I was already pruning the **node\_module** folder of development dependencies prior to creating the VSIX to remove devDependancies using the command```
npm prune –production
```I did find some of the listed modules strange, as I knew they really were needed and a quick test of removing them did show the code failed if they were missing. These are what [depchecks documentation calls false alerts](https://www.npmjs.com/package/depcheck). I found I could remove the **@type/xxx** and **tsd** references, which were the big ones, that are only needed in development when working in TypeScript. Once these were removed for all four of my NodeJS based tasks my VSIX dropped in size from 22Mb to 7Mb. So problem solved.
&lt;/code&gt;&lt;/pre&gt;</description>
      <content:encoded><![CDATA[<p>Whist adding a couple of new tasks to my <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task">VSTS Manifest Versioning Extension</a> I hit the problem that VSIX package became too big to upload to the Marketplace. The error I saw in my CI/CD VSTS pipeline was```
##vso[task.logissue type=error;]error:
Failed Request: Bad Request(400) -
The extension package size &lsquo;23255292 bytes&rsquo; exceeds the
maximum package size &lsquo;20971520 bytes&rsquo;</p>
<pre tabindex="0"><code class="language-This" data-lang="This">
1.  They get a list of files
2.  Extract a version number from the build number
3.  Then apply this to one or more files in a product/task specific manner

there has been some cut and paste coding. This means that I have NPM modules in the tasks **package.json** file that were not needed for a given task. I could manually address this but there is an NPM module to help, DepCheck. First install the [DepCheck](https://www.npmjs.com/package/depcheck) module```
npm install depcheck –g
```then run **depcheck** from the command line whist within your task’s folder. This returns a list of modules listed in the **package.json** that are not referenced in the code files. These can then be removed from the **package.json.**  e.g. I saw```
Unused dependencies
\* @types/node
\* @types/q
\* Buffer
\* fs
\* request
\* tsd
Unused devDependencies
\* @types/chai
\* @types/mocha
\* @types/node
\* mocha-junit-reporter
\* ts-loader
\* ts-node
\* typings
```The important ones to focus on are the first block (non-development references), as these are the ones that are packaged with the production code in the VSIX; I was already pruning the **node\_module** folder of development dependencies prior to creating the VSIX to remove devDependancies using the command```
npm prune –production
```I did find some of the listed modules strange, as I knew they really were needed and a quick test of removing them did show the code failed if they were missing. These are what [depchecks documentation calls false alerts](https://www.npmjs.com/package/depcheck). I found I could remove the **@type/xxx** and **tsd** references, which were the big ones, that are only needed in development when working in TypeScript. Once these were removed for all four of my NodeJS based tasks my VSIX dropped in size from 22Mb to 7Mb. So problem solved.
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Added a new JSON version task to my VSTS Version Extension</title>
      <link>https://blog.richardfennell.net/posts/added-a-new-json-version-task-to-my-vsts-version-extension/</link>
      <pubDate>Fri, 05 Jan 2018 11:04:21 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/added-a-new-json-version-task-to-my-vsts-version-extension/</guid>
      <description>&lt;p&gt;In response to requests on the VSTS Marketplace I have added a pair of tasks to added/edit entries in a .JSON format files.&lt;/p&gt;
&lt;p&gt;The first is for adding a version to a file like a package.json file e.g.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;{  
&amp;#34;name&amp;#34;: &amp;#34;myapp&amp;#34;,  
&amp;#34;version&amp;#34;: &amp;#34;1.0.0&amp;#34;,  
&amp;#34;license&amp;#34;: &amp;#34;MIT&amp;#34;  
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second is designed for angular environment.ts file e.g.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;export const environment = {  
production: true,  
version: &amp;#39;1.0.0.0&amp;#39;  
};
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But I bet people find other uses, they always do.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>In response to requests on the VSTS Marketplace I have added a pair of tasks to added/edit entries in a .JSON format files.</p>
<p>The first is for adding a version to a file like a package.json file e.g.</p>
<pre tabindex="0"><code>{  
&#34;name&#34;: &#34;myapp&#34;,  
&#34;version&#34;: &#34;1.0.0&#34;,  
&#34;license&#34;: &#34;MIT&#34;  
}
</code></pre><p>The second is designed for angular environment.ts file e.g.</p>
<pre tabindex="0"><code>export const environment = {  
production: true,  
version: &#39;1.0.0.0&#39;  
};
</code></pre><p>But I bet people find other uses, they always do.</p>
<p>You can find the extension in the <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-Versioning-Task">marketplace</a>, you need 1.31.x or later to see the new versioner tasks</p>
]]></content:encoded>
    </item>
    <item>
      <title>Announcing a new VSTS Extension for Starting and Stopping Azure DevTest Labs VMs</title>
      <link>https://blog.richardfennell.net/posts/announcing-a-new-vsts-extension-for-starting-and-stopping-azure-devtest-labs-vms/</link>
      <pubDate>Thu, 30 Nov 2017 12:13:05 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/announcing-a-new-vsts-extension-for-starting-and-stopping-azure-devtest-labs-vms/</guid>
      <description>&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;
&lt;p&gt;I have &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-%3Cpre.vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/&#34;&gt;recently been posting&lt;/a&gt; on using Azure to host private VSTS build/release agents to avoid agent queue deadlocking issues with more complex release pipelines. One of the areas discussed is reducing cost of running a private agent in Azure by only running the private agent within a limited time range, when you guess it might be needed. I have done this using DevTest Labs &lt;a href=&#34;https://azure.microsoft.com/en-gb/updates/azure-devtest-labs-schedule-vm-auto-start/&#34;&gt;Auto Start&lt;/a&gt; and &lt;a href=&#34;https://azure.microsoft.com/en-gb/updates/azure-devtest-labs-set-auto-shutdown-for-a-single-lab-vm/&#34;&gt;Auto Stop&lt;/a&gt; features. This works, but is it not better to only start the agent VM when it is actually really needed, not when you guess it might be? I need this private agent only when working on my VSTS extensions, not something I do everyday. Why waste CPU cycles that are never used?&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h3 id="background">Background</h3>
<p>I have <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-%3Cpre.vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/">recently been posting</a> on using Azure to host private VSTS build/release agents to avoid agent queue deadlocking issues with more complex release pipelines. One of the areas discussed is reducing cost of running a private agent in Azure by only running the private agent within a limited time range, when you guess it might be needed. I have done this using DevTest Labs <a href="https://azure.microsoft.com/en-gb/updates/azure-devtest-labs-schedule-vm-auto-start/">Auto Start</a> and <a href="https://azure.microsoft.com/en-gb/updates/azure-devtest-labs-set-auto-shutdown-for-a-single-lab-vm/">Auto Stop</a> features. This works, but is it not better to only start the agent VM when it is actually really needed, not when you guess it might be? I need this private agent only when working on my VSTS extensions, not something I do everyday. Why waste CPU cycles that are never used?</p>
<h3 id="new-vsts-extension">New VSTS Extension</h3>
<p>I had expected there would already be a VSTS  extension to Start and Stop DevTest Lab VMs, but the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuredevtestlabs.tasks">Microsoft provided extension for DevTest Labs</a> only provides tasks for the creation and deletion of VMs within a lab. So I am pleased to announce the release of my new <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-DevTestLab">DevTest Labs VSTS Extension</a> to fill this gap, adding tasks to start and stop a DevTest Lab VM on demand from within a build or a release. My Usage I have been able to use the tasks in this extension to start my private Azure hosted agent only when I need it for functional tests within a release. However, they could equally be used for a variety of different testing scenarios where any form of pre-built/configured VMs needs to be started or stopped as opposed to slower processes of creating/deploying a new deployment of a DevTest lab VM. In may case I added an extra agent phases to my release pipeline to start the VM prior to it being needed. <a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2017/11/image-2.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2017/11/image_thumb-2.png" title="image"></a> I could also have used another agent phase to stop the VM once the tests were completed. However, I made the call to leave the VM running and let DevTest Labs’ Auto Stop shut it down at the end of the day. The reason for this is that VM start up and shutdown is still fairly slow, a minute or two, and I often find I need to run a set of function tests a few times during my development cycle; so it is a bit more efficient to leave the VM running until the end of the day. Only taking the start-up cost once. You may have course have different needs, hence providing both the Start and Stop Tasks</p>
<h3 id="development">Development</h3>
<p>This new extension aims to act as a supplement to the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azuredevtestlabs.tasks">Microsoft provided Azure DevTest Lab Extension</a>. Hence to make development and adoption easier, it uses exactly the same <a href="https://github.com/Azure/azure-devtestlab/tree/master/VstsTasks">source code structure</a> and task parameters as the Microsoft provided extension. The task parameters being:</p>
<ul>
<li><strong>Azure RM Subscription</strong> - Azure Resource Manager subscription to configure before running.</li>
<li><strong>Source Lab VM ID</strong> - Resource ID of the source lab VM. The source lab VM must be in the selected lab, as the custom image will be created using its VHD file. You can use any variable such as <em>$(labVMId)</em>, the output of calling Create Azure DevTest Labs VM, that contains a value in the form <em>/subscriptions/{subId}/resourceGroups/{rgName}/providers/Microsoft.DevTestLab/labs/{labName}/virtualMachines/{vmName}</em>.</li>
</ul>
<p>The issue I had was that the DevTest Labs PowerShell API did not provide a command to start or stop a VM in a lab. I needed to load the Azure PowerShell library to use the <strong>Invoke-AzureRmResourceAction</strong>  command. This requires you first call <strong>Login-AzureRmAccount</strong> to authenticate prior to calling the actual <strong>Invoke-AzureRmResourceAction</strong> required. This required a bit of extra code to get and reuse the AzureRM endpoint to find the authentication details.```
# Get the parameters
$ConnectedServiceName = Get-VstsInput -Name &ldquo;ConnectedServiceName&rdquo;</p>
<h1 id="get-the-end-point-from-the-name-passed-as-a-parameter">Get the end point from the name passed as a parameter</h1>
<p>$Endpoint = Get-VstsEndpoint -Name $ConnectedServiceName -Require</p>
<h1 id="get-the-authentication-details">Get the authentication details</h1>
<p>$clientID = $Endpoint.Auth.parameters.serviceprincipalid
$key = $Endpoint.Auth.parameters.serviceprincipalkey
$tenantId = $Endpoint.Auth.parameters.tenantid
$SecurePassword = $key | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $clientID, $SecurePassword</p>
<h1 id="authenticate">Authenticate</h1>
<p>Login-AzureRmAccount -Credential $cred -TenantId $tenantId -ServicePrincipal
<code>Important to note that for this code to work you have to set the task’s **task.json** to run **PowerShell3** and package the Powershell VSTS API module in with the task.</code>
&ldquo;execution&rdquo;: {
&ldquo;PowerShell3&rdquo;: {
&ldquo;target&rdquo;: &ldquo;$(currentDirectory)\StartVM.ps1&rdquo;,
&ldquo;argumentFormat&rdquo;: &ldquo;&rdquo;,
&ldquo;workingDirectory&rdquo;: &ldquo;$(currentDirectory)&rdquo;
    }
  }</p>
<pre tabindex="0"><code class="language-If" data-lang="If">
### In Summary

I have certainly found this extension useful, and I have leant more that I had expect I would about VSTS endpoints and Azure authentication. Hope it is useful to you too.
</code></pre>]]></content:encoded>
    </item>
    <item>
      <title>Creating a VSTS build agent on an Azure DevLabs Windows Server VM with no GUI  - Using Artifacts</title>
      <link>https://blog.richardfennell.net/posts/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui-using-artifacts/</link>
      <pubDate>Tue, 28 Nov 2017 20:34:10 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui-using-artifacts/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/&#34;&gt;In my last post I discussed creating a private VSTS build agent within an Azure DevTest Lab on a VM with no GUI&lt;/a&gt;. It was pointed out to me today, by &lt;a href=&#34;https://blogs.blackmarble.co.uk/rhepworth&#34;&gt;Rik Hepworth&lt;/a&gt;, that I had overlooked an obvious alternative way to get the VSTS agent onto the VM i.e. not having to use a series of commands at an RDP connected command prompt. The alternative I missed is to use a DevTest Lab Artifact; in fact there is such an artifact available within the standard set in DevTest Labs. You just provide a few parameters and you are good to go. &lt;a href=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2017/11/image-1.png&#34;&gt;&lt;img alt=&#34;image&#34; loading=&#34;lazy&#34; src=&#34;https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2017/11/image_thumb-1.png&#34; title=&#34;image&#34;&gt;&lt;/a&gt; Well you should be good to go, but there is an issue. The PowerShell used to extract the downloaded Build Agent ZIP file does not work on a non-UI based Windows VM. &lt;a href=&#34;http://www.codewrecks.com/blog/index.php/2016/05/27/avoid-using-shell-command-in-powershell-scipts/&#34;&gt;The basic issue here is discussed in this post by my fellow ALM MVP Ricci Gian Maria&lt;/a&gt;. Luckily the fix is simple; I just used the same code to do the extraction of the ZIP file that I used in my &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/&#34;&gt;previous post&lt;/a&gt;. I have submitted this fix as a &lt;a href=&#34;https://github.com/Azure/azure-devtestlab/pull/319&#34;&gt;Pull Request to the DevTest Lab Team&lt;/a&gt; so hopefully the standard repository will have the fix soon and you won’t need to do a fork to create a private artifacts repo as I have. &lt;strong&gt;Update 1st December 2017&lt;/strong&gt; The &lt;a href=&#34;https://github.com/Azure/azure-devtestlab/pull/319&#34;&gt;Pull Request to the DevTest Lab Team&lt;/a&gt; with the fixed code has been accepted and the fix is now in the master branch of the public artifact repo, so automatically available to all&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/">In my last post I discussed creating a private VSTS build agent within an Azure DevTest Lab on a VM with no GUI</a>. It was pointed out to me today, by <a href="https://blogs.blackmarble.co.uk/rhepworth">Rik Hepworth</a>, that I had overlooked an obvious alternative way to get the VSTS agent onto the VM i.e. not having to use a series of commands at an RDP connected command prompt. The alternative I missed is to use a DevTest Lab Artifact; in fact there is such an artifact available within the standard set in DevTest Labs. You just provide a few parameters and you are good to go. <a href="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2017/11/image-1.png"><img alt="image" loading="lazy" src="https://blogs.blackmarble.co.uk/wp-content/uploads/sites/2/2017/11/image_thumb-1.png" title="image"></a> Well you should be good to go, but there is an issue. The PowerShell used to extract the downloaded Build Agent ZIP file does not work on a non-UI based Windows VM. <a href="http://www.codewrecks.com/blog/index.php/2016/05/27/avoid-using-shell-command-in-powershell-scipts/">The basic issue here is discussed in this post by my fellow ALM MVP Ricci Gian Maria</a>. Luckily the fix is simple; I just used the same code to do the extraction of the ZIP file that I used in my <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/23/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/">previous post</a>. I have submitted this fix as a <a href="https://github.com/Azure/azure-devtestlab/pull/319">Pull Request to the DevTest Lab Team</a> so hopefully the standard repository will have the fix soon and you won’t need to do a fork to create a private artifacts repo as I have. <strong>Update 1st December 2017</strong> The <a href="https://github.com/Azure/azure-devtestlab/pull/319">Pull Request to the DevTest Lab Team</a> with the fixed code has been accepted and the fix is now in the master branch of the public artifact repo, so automatically available to all</p>
]]></content:encoded>
    </item>
    <item>
      <title>Creating a VSTS build agent on an Azure DevLabs Windows Server VM with no GUI</title>
      <link>https://blog.richardfennell.net/posts/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/</link>
      <pubDate>Thu, 23 Nov 2017 12:38:48 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Updates&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;28th Nov 2017&lt;/strong&gt;: Also see this second post &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/28/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui-using-artifacts/&#34;&gt;Creating a VSTS build agent on an Azure DevLabs Windows Server VM with no GUI - Using Artifacts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;30th Nov 2017&lt;/strong&gt;: Also see associated post &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/30/announcing-a-new-vsts-extension-for-starting-and-stopping-azure-devtest-labs-vms/&#34;&gt;Announcing a new VSTS Extension for Starting and Stopping Azure DevTest Labs VMs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;As I &lt;a href=&#34;https://blogs.blackmarble.co.uk/rfennell/2017/11/09/major-update-to-my-cicd-process-for-vsts-extensions/&#34;&gt;posted recently&lt;/a&gt; I have been trying to add more functional tests to the VSTS based release CI/CD pipeline for my &lt;a href=&#34;https://marketplace.visualstudio.com/search?term=fennell&amp;amp;target=VSTS&amp;amp;category=All%20categories&amp;amp;sortBy=Relevance&#34;&gt;VSTS Extensions&lt;/a&gt;, and as I noted depending on how you want to run your tests e.g. trigger sub-builds, you can end up with scheduling deadlocks where a single build agent is scheduling the release and trying to run a new build. The answer is to use a second build agent in a different agent pool e.g. if the release is running on the Hosted build agent use a private build agent for the sub-build, or of course just pay for more hosted build instances. The problem with a private build agent is where to run it. As my extensions are a personal project I don’t have a corporate Hyper-V server to run any extra private agents on, as I would have for an company projects. My MVP MSDN Azure benefits are the obvious answer, but I want any agents to be cheap to run, so I don’t burn through all my MSDN credits for a single build agent. To this end I created a Windows Server 2016 VM in &lt;a href=&#34;https://azure.microsoft.com/en-gb/services/devtest-lab/&#34;&gt;DevLabs&lt;/a&gt; (I prefer to create my VMs in DevLabs as it makes it easier tidying up of my Azure account) using an A0 sizing VM. This is tiny so cheap; I don’t intend to ever do a build on this agent, just schedule releases, so need to install few if any tools, so the size should not be an issue. To further reduce costs I used the auto start and stop features on the VM so it is only running during the hours I might be working. So I get an admittedly slow and limited private build agent but for less that $10 a month. As the VM is small it makes sense to not run a GUI. This means when you RDP to the new VM you just get a command prompt. So how do you get the agent onto the VM and setup? You can’t just open a browser to VSTS or cut and paste a file via RDP, and I wanted to avoid the complexity of having to open up PowerShell remoting on the VM. The process I used was as follows:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>Updates</strong></p>
<ul>
<li><strong>28th Nov 2017</strong>: Also see this second post <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/28/creating-a-vsts-build-agent-on-an-azure-devlabs-windows-server-vm-with-no-gui-using-artifacts/">Creating a VSTS build agent on an Azure DevLabs Windows Server VM with no GUI - Using Artifacts</a></li>
<li><strong>30th Nov 2017</strong>: Also see associated post <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/30/announcing-a-new-vsts-extension-for-starting-and-stopping-azure-devtest-labs-vms/">Announcing a new VSTS Extension for Starting and Stopping Azure DevTest Labs VMs</a></li>
</ul>
<hr>
<p>As I <a href="https://blogs.blackmarble.co.uk/rfennell/2017/11/09/major-update-to-my-cicd-process-for-vsts-extensions/">posted recently</a> I have been trying to add more functional tests to the VSTS based release CI/CD pipeline for my <a href="https://marketplace.visualstudio.com/search?term=fennell&amp;target=VSTS&amp;category=All%20categories&amp;sortBy=Relevance">VSTS Extensions</a>, and as I noted depending on how you want to run your tests e.g. trigger sub-builds, you can end up with scheduling deadlocks where a single build agent is scheduling the release and trying to run a new build. The answer is to use a second build agent in a different agent pool e.g. if the release is running on the Hosted build agent use a private build agent for the sub-build, or of course just pay for more hosted build instances. The problem with a private build agent is where to run it. As my extensions are a personal project I don’t have a corporate Hyper-V server to run any extra private agents on, as I would have for an company projects. My MVP MSDN Azure benefits are the obvious answer, but I want any agents to be cheap to run, so I don’t burn through all my MSDN credits for a single build agent. To this end I created a Windows Server 2016 VM in <a href="https://azure.microsoft.com/en-gb/services/devtest-lab/">DevLabs</a> (I prefer to create my VMs in DevLabs as it makes it easier tidying up of my Azure account) using an A0 sizing VM. This is tiny so cheap; I don’t intend to ever do a build on this agent, just schedule releases, so need to install few if any tools, so the size should not be an issue. To further reduce costs I used the auto start and stop features on the VM so it is only running during the hours I might be working. So I get an admittedly slow and limited private build agent but for less that $10 a month. As the VM is small it makes sense to not run a GUI. This means when you RDP to the new VM you just get a command prompt. So how do you get the agent onto the VM and setup? You can’t just open a browser to VSTS or cut and paste a file via RDP, and I wanted to avoid the complexity of having to open up PowerShell remoting on the VM. The process I used was as follows:</p>
<ol>
<li>In VSTS I created a new Agent Pool for my Azure hosted build agents</li>
<li>In the Azure portal, DevLabs I created a new Windows Server 2016 (1709) VM</li>
<li>I then RDP’d to my new Azure VM, in the open Command Prompt I ran PowerShell <strong>powershell</strong></li>
<li>As I was in my users home directory, I  cd’d into the <strong>downloads</strong> folder <strong>cd downloads</strong></li>
<li>I then ran the following PowerShell command to download the agent (you can get the current URI for the agent from your VSTS Agent Pool ‘Download Agent’ feature, but an old version will do as it will auto update. <strong>invoke-webrequest -UseBasicParsing -uri <a href="https://github.com/Microsoft/vsts-agent/releases/download/v2.124.0/vsts-agent-win7-x64-2.124.0.zip">https://github.com/Microsoft/vsts-agent/releases/download/v2.124.0/vsts-agent-win7-x64-2.124.0.zip</a> -OutFile vsts-agent-win7-x64-2.124.0.zip</strong></li>
<li>You can then follow the standard agent setup instructions from the VSTS Agent Pool ‘Download Agent’ feature <strong>mkdir agent ; cd agent PS Add-Type -AssemblyName System.IO.Compression.FileSystem ; [System.IO.Compression.ZipFile]::ExtractToDirectory(&quot;$HOMEDownloadsvsts-agent-win7-x64-2.124.0.zip&quot;, &ldquo;$PWD&rdquo;)</strong></li>
<li>I then configured the agent to run as a service, I exited back to the command prompt to do this this, so the commands were <strong>exit config.cmd</strong></li>
</ol>
<p>I now had an other build agent pool to use in my CI/CD pipelines at a reasonable cost, and the performance was not too bad either.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Future of Reporting on VSTS with VSTS Analytics</title>
      <link>https://blog.richardfennell.net/posts/future-of-reporting-on-vsts-with-vsts-analytics/</link>
      <pubDate>Thu, 16 Nov 2017 10:25:38 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/future-of-reporting-on-vsts-with-vsts-analytics/</guid>
      <description>&lt;p&gt;Reporting has always been important for software development, simply put the ability to know what has been done, and what remains to be done. For many teams the out the box reporting within TFS/VSTS dashboards has been enough e.g. sprint burndowns and kanban charts etc. Also TFS has always had SQL Reporting Services (SSRS) to provide rich reporting on a whole host of areas; though in my experience few clients use the out the box reports or customise their own reports. The lack of SSRS based reporting on VSTS has been a blocking limitation for some clients, preventing their move to VSTS. Also irrespective of peoples past use of custom reports, most people would like an easier way, than SSRS, to produce custom reports and charts. So enter &lt;a href=&#34;http://aka.ms/VSTSAnalytics&#34;&gt;VSTS Analytics&lt;/a&gt; Microsoft’s new free reporting option for VSTS that provide a host of reporting options for dashboards, Power BI and OData. For a great introduction have a look at Gregg Boer’s Channel9 video &lt;a href=&#34;https://channel9.msdn.com/Events/connect/2017/T251&#34;&gt;Visual Studio Team Services Reporting: Dashboards, Power BI, and OData&lt;/a&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Reporting has always been important for software development, simply put the ability to know what has been done, and what remains to be done. For many teams the out the box reporting within TFS/VSTS dashboards has been enough e.g. sprint burndowns and kanban charts etc. Also TFS has always had SQL Reporting Services (SSRS) to provide rich reporting on a whole host of areas; though in my experience few clients use the out the box reports or customise their own reports. The lack of SSRS based reporting on VSTS has been a blocking limitation for some clients, preventing their move to VSTS. Also irrespective of peoples past use of custom reports, most people would like an easier way, than SSRS, to produce custom reports and charts. So enter <a href="http://aka.ms/VSTSAnalytics">VSTS Analytics</a> Microsoft’s new free reporting option for VSTS that provide a host of reporting options for dashboards, Power BI and OData. For a great introduction have a look at Gregg Boer’s Channel9 video <a href="https://channel9.msdn.com/Events/connect/2017/T251">Visual Studio Team Services Reporting: Dashboards, Power BI, and OData</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>Options migrating TFS to VSTS</title>
      <link>https://blog.richardfennell.net/posts/options-migrating-tfs-to-vsts/</link>
      <pubDate>Wed, 10 May 2017 14:11:00 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/options-migrating-tfs-to-vsts/</guid>
      <description>&lt;p&gt;I did an event yesterday on using the &lt;a href=&#34;https://www.visualstudio.com/en-us/articles/adopting-vsts&#34;&gt;TFS Database Import Service&lt;/a&gt; to do migrations from on premises TFS to VSTS. During the presentation I discussed some of the other migration options available. Not everyone needs a high fidelity migration, bring everything over. Some teams may want to just bring over their current source or just a subset of their source. Maybe they are making a major change in work practices and want to start anew on VSTS. To try to give an idea of the options I have produced this flow chart to help with the choices&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I did an event yesterday on using the <a href="https://www.visualstudio.com/en-us/articles/adopting-vsts">TFS Database Import Service</a> to do migrations from on premises TFS to VSTS. During the presentation I discussed some of the other migration options available. Not everyone needs a high fidelity migration, bring everything over. Some teams may want to just bring over their current source or just a subset of their source. Maybe they are making a major change in work practices and want to start anew on VSTS. To try to give an idea of the options I have produced this flow chart to help with the choices</p>
<p><img alt="image" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb_341.png" title="image"></p>
<p><a href="/files/TFS-Migrate-Choices.pdf">Click for a PDF version</a>  </p>
<p>It mentions a few 3rd party tools in the flowchart, so here are some useful links</p>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=Willy-PSchaub.TeamFoundationServerIntegrationToolsMarch2012Relea">TFS Integration Platform</a> – can in theory move source and work items – but really try not to use it!</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=nkdagility.vsts-sync-migration">VSTS Sync Migration Tools</a> –  moves Work items</li>
<li><a href="http://www.timelymigration.com/">Timely Migration</a> – moves TFVC source (commercial product)</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=vs-publisher-1455028.OpsHubVisualStudioOnlineMigrationUtility">OpsHub</a> – moves Team Projects (free &amp; commercial versions)</li>
<li><a href="https://github.com/git-tfs/git-tfs">Git TFS</a> – move TFVC into Git</li>
<li><a href="https://www.visualstudio.com/en-us/docs/work/office/bulk-add-modify-work-items-excel">TFS Office Integration</a> – moves work items via Excel</li>
<li><a href="https://www.visualstudio.com/en-us/articles/adopting-vsts">TFS Database Import Service</a> – the full fidelity service</li>
</ul>
<p>Also, if you find yourself in the orange box at the bottom and don’t want to use the <a href="https://www.visualstudio.com/en-us/articles/adopting-vsts">TFS Database Import Service</a> for some reason, <a href="https://www.microsoft.com/en-gb/developers/articles/week02mar2014/migrating-a-tfs-tfvc-based-team-project-to-a-git-team-project-retaining-as-much-source-and-work-item-history-as-possible/">have a look at this post I did on Microsoft’s UK Developers site</a>. It might give you some ideas</p>
]]></content:encoded>
    </item>
    <item>
      <title>Putting a release process around my VSTS extension development</title>
      <link>https://blog.richardfennell.net/posts/putting-a-release-process-around-my-vsts-extension-development/</link>
      <pubDate>Fri, 06 May 2016 12:17:00 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/putting-a-release-process-around-my-vsts-extension-development/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Updated: 5th Aug 2016 added notes in PublisherID&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;  I have been developing a few VSTS/TFS build related extensions and have published a few in the &lt;a href=&#34;https://marketplace.visualstudio.com/search?term=fennell&amp;amp;target=VSTS&amp;amp;sortBy=Relevance&#34;&gt;VSTS marketplace&lt;/a&gt;. This has all been a somewhat manual process, a mixture of Gulp and PowerShell has helped a bit, but I decided it was time to try to do a more formal approach. To do this I have used &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=jessehouwing.jessehouwing-vsts-extension-tasks&#34;&gt;Jesse Houwing’s VSTS Extension Tasks&lt;/a&gt;. Even with this set of tasks I am not sure what I have is ‘best practice’, but it does work. The doubt is due to the way the marketplace handles revisions and preview flags. What I have works for me, but ‘your mileage may differ’&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>Updated: 5th Aug 2016 added notes in PublisherID</strong></p>
<hr>
<p>  I have been developing a few VSTS/TFS build related extensions and have published a few in the <a href="https://marketplace.visualstudio.com/search?term=fennell&amp;target=VSTS&amp;sortBy=Relevance">VSTS marketplace</a>. This has all been a somewhat manual process, a mixture of Gulp and PowerShell has helped a bit, but I decided it was time to try to do a more formal approach. To do this I have used <a href="https://marketplace.visualstudio.com/items?itemName=jessehouwing.jessehouwing-vsts-extension-tasks">Jesse Houwing’s VSTS Extension Tasks</a>. Even with this set of tasks I am not sure what I have is ‘best practice’, but it does work. The doubt is due to the way the marketplace handles revisions and preview flags. What I have works for me, but ‘your mileage may differ’</p>
<h3 id="my-workflow">My Workflow</h3>
<p>The core of my workflow is that I am building the VSIX package twice, once as a private package and the other as a public one. They both contain the same code and have the same version number, they differ in only visibility flags I am not using a the preview flag options at all. I have found they do not really help me. My workflow is to build the private package, upload it and test it by sharing it with a test VSTS instance. if all is good publish the matched public package on the marketplace. In this model there is no need to use a preview, it just adds complexity I don’t need. This may not be true for everyone.</p>
<h3 id="build">Build</h3>
<p>The build’s job is to take the code, set the version number and package it into multiple VSIX package.</p>
<ol>
<li>First I have the vNext build get my source from my GitHub repo.</li>
<li>I add two build variables <strong>$(Major)</strong> and <strong>$(Minor)</strong> that I use to manually manage my version number</li>
<li>I set my build number format to <strong>$(Major).$(Minor).$(rev:r)</strong>, so the final .number is incremented until I choose to increment the major or minor version.</li>
<li>I then use one of Jesse’s tasks to package the extension multiple times using the <strong>extension tag</strong> model parameter. Each different package step uses different <strong>Visibility</strong> settings (circled in red). I also set the version, using the override options, to the <strong>$(Build.BuildNumber)</strong> (circled in green)<a href="/wp-content/uploads/sites/2/historic/image_304.png"><img alt="image" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb_300.png" title="image"></a></li>
<li>**[Updated Aug 2016] **Set the PublisherID and ExtensionID on the tasks, using a pair of build variables is a good idea here to avoid entering strings twice. It is important thay the PublisherID is entered with the correct case - it is case sensitive within the marketplace. Strange things happend of the PublisherID in a VSIX package differ from the one registered on the marketplace</li>
<li>As I am using the VSTS hosted build agent I also need to make sure I check the <strong>install Tfx-cli</strong> in the global setting section</li>
<li>I then add a second identical publish task, but this time there is no tag set and the visibility is set to public.</li>
<li>Finally I use a ‘publish build artifacts’ task to copy the VSIX packages to a drop location</li>
</ol>
<h3 id="release">Release</h3>
<p>So now I have multiple VSIX packages I can use the same family of tasks to create a release pipeline. I create a new release linked to be a Continuous Deployment of the previously created build and set its release name format to <strong>Release-$(Build.BuildNumber)</strong> My first environment uses three tasks, all using the option - to work from a VSIX package. <strong>Note</strong> In all cases I am using the VSIX path in the format <strong>$(System.DefaultWorkingDirectory)/GenerateReleaseNotes.Master/vsix/<package name>-<tag>-$(Build.BuildNumber).vsix</strong>. I am including the build number variable in the path as I chose to put all the packages in a single folder, so path wildcards are not an option as the task would not know which package to use unless I alter my build to put one VSIX package per folder. My tasks for the first environment are</p>
<ol>
<li>Publish VSTS Extension – using my private package so it is added as a private package to the marketplace</li>
<li>Share VSTS Extension – to my test VSTS account</li>
<li>Install VSTS Extension – to my test VSTS account</li>
</ol>
<p><em>For details in the usage of these tasks and setting up the link to the VSTS Marketplace</em> <a href="https://github.com/jessehouwing/vsts-extension-tasks/wiki"><em>see Jesse’s wiki</em></a> If I only intend a extension to ever be private this is enough. However I want to make mine public so I add a second environment that has manual pre-approval (so I have to confirm the public release) This environment only needs single task</p>
<ol>
<li>Publish VSTS Extension – using my public package so it is added as a public package to the marketplace</li>
</ol>
<p>I can of course add other tasks to this environment maybe send a Tweet or email to publicise the new version’s release</p>
<h3 id="summary">Summary</h3>
<p>So now I have a formal way to release my extensions. The dual packaging model means I can publish two different versions at the same time one privately and the other public <a href="/wp-content/uploads/sites/2/historic/image_305.png"><img alt="image" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb_301.png" title="image"></a> It is now just a case of moving all my extensions over to the new model. Though I am still interested to hear what other people view are? Does this seem a reasonable process flow?</p>
]]></content:encoded>
    </item>
    <item>
      <title>Running Pester PowerShell tests in the VSTS hosted build service</title>
      <link>https://blog.richardfennell.net/posts/running-pester-powershell-tests-in-the-vsts-hosted-build-service/</link>
      <pubDate>Sun, 21 Feb 2016 23:43:00 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/running-pester-powershell-tests-in-the-vsts-hosted-build-service/</guid>
      <description>&lt;p&gt;**Updated 22 Mar 2016 **This task is available in the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-PesterRunner-Task&#34;&gt;VSTS Marketplace&lt;/a&gt; If you are using &lt;a href=&#34;https://github.com/pester/Pester/wiki&#34;&gt;Pester&lt;/a&gt; to unit test your PowerShell code then there is a good chance you will want to include it in your automated build process. To do this, you need to get Pester installed on your build machine. The usual options would be&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manual install from &lt;a href=&#34;https://github.com/pester/Pester&#34;&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Install via &lt;a href=&#34;https://chocolatey.org/packages/pester&#34;&gt;Chocolaty&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Install via &lt;a href=&#34;https://www.nuget.org/packages/Pester/&#34;&gt;Nuget&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you own the build agent VM then any of these options are good, you can even write the NuGet restore into your build process itself. However there is a problem, both the first two options need administrative access as they put the Pester module in the &lt;strong&gt;$PSModules&lt;/strong&gt; folder (under ‘Program Files’); so these can’t be used on VSTS’s hosted build system, where your are not an administrator So this means you are left with copying the module (and associated functions folder) to some local working folder and running it manually; but do you really want to have to store the Pester module in your source repo? My solution was to write a vNext build tasks to deploy the Pester files and run the Pester tests. &lt;a href=&#34;https://blog.richardfennell.net/wp-content/uploads/sites/2/historic/image_thumb[12].png&#34;&gt;&lt;img alt=&#34;image_thumb[12]&#34; loading=&#34;lazy&#34; src=&#34;https://blog.richardfennell.net/wp-content/uploads/sites/2/historic/image_thumb[12]_thumb.png&#34; title=&#34;image_thumb[12]&#34;&gt;&lt;/a&gt; The task takes two parameters&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>**Updated 22 Mar 2016 **This task is available in the <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-PesterRunner-Task">VSTS Marketplace</a> If you are using <a href="https://github.com/pester/Pester/wiki">Pester</a> to unit test your PowerShell code then there is a good chance you will want to include it in your automated build process. To do this, you need to get Pester installed on your build machine. The usual options would be</p>
<ul>
<li>Manual install from <a href="https://github.com/pester/Pester">GitHub</a></li>
<li>Install via <a href="https://chocolatey.org/packages/pester">Chocolaty</a></li>
<li>Install via <a href="https://www.nuget.org/packages/Pester/">Nuget</a></li>
</ul>
<p>If you own the build agent VM then any of these options are good, you can even write the NuGet restore into your build process itself. However there is a problem, both the first two options need administrative access as they put the Pester module in the <strong>$PSModules</strong> folder (under ‘Program Files’); so these can’t be used on VSTS’s hosted build system, where your are not an administrator So this means you are left with copying the module (and associated functions folder) to some local working folder and running it manually; but do you really want to have to store the Pester module in your source repo? My solution was to write a vNext build tasks to deploy the Pester files and run the Pester tests. <a href="/wp-content/uploads/sites/2/historic/image_thumb[12].png"><img alt="image_thumb[12]" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb[12]_thumb.png" title="image_thumb[12]"></a> The task takes two parameters</p>
<ul>
<li>The root folder to look for test scripts with the naming convention  <strong>*.tests.ps1</strong>. Defaults to <strong>$(Build.SourcesDirectory)*</strong></li>
<li>The results file name, defaults to <strong>$(Build.SourcesDirectory)Test-Pester.XML</strong></li>
</ul>
<p>The Pester task does not in itself upload the test results, it just throws and error if tests fails. It relies on the standard test results upload task. Add this task and set</p>
<ul>
<li>it to look for nUnit format files</li>
<li>it already defaults to the correct file name pattern.</li>
<li>IMPORTANT: As the Pester task will stop the build on an error you need to set the ‘Always run’ to make sure the results are published.</li>
</ul>
<p><a href="/wp-content/uploads/sites/2/historic/image_thumb[11].png"><img alt="image_thumb[11]" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb[11]_thumb.png" title="image_thumb[11]"></a> Once all this is added to your build you can see your Pester test results in the build summary <a href="/wp-content/uploads/sites/2/historic/image_thumb[10].png"><img alt="image_thumb[10]" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb[10]_thumb.png" title="image_thumb[10]"></a> <a href="/wp-content/uploads/sites/2/historic/image_thumb[14].png"><img alt="image_thumb[14]" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb[14]_thumb.png" title="image_thumb[14]"></a> You can find the task in my <a href="https://github.com/rfennell/vNextBuild">vNextBuild repo</a></p>
]]></content:encoded>
    </item>
    <item>
      <title>A VSTS vNext build task to run StyleCop</title>
      <link>https://blog.richardfennell.net/posts/a-vsts-vnext-build-task-to-run-stylecop/</link>
      <pubDate>Sat, 06 Feb 2016 18:51:00 +0000</pubDate>
      <guid>https://blog.richardfennell.net/posts/a-vsts-vnext-build-task-to-run-stylecop/</guid>
      <description>&lt;p&gt;&lt;strong&gt;Updated 22 Mar 2016&lt;/strong&gt; This tasks is available in the &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-StyleCop-Task&#34;&gt;VSTS Marketplace&lt;/a&gt; I have &lt;a href=&#34;https://blog.richardfennell.net/blogs/rfennell/post/2015/04/03/Running-StyleCop-from-the-command-line-and-in-a-TFS-2015-vNext-build.aspx&#34;&gt;previously posted&lt;/a&gt; on how a PowerShell script can be used to run StyleCop as part of vNext VSTS/TFS build. Now I have more experience with vNext tasks it seemed a good time to convert this PowerShell script into a true task that can deploy StyleCop and making it far easier to expose the various parameters StyleCop allows. To this end I have written a new StyleCop task that can be found in my &lt;a href=&#34;https://github.com/rfennell/vNextBuild&#34;&gt;vNext Build Repo&lt;/a&gt;, this has been built to use the &lt;a href=&#34;https://stylecop.codeplex.com/&#34;&gt;4.7.49.0 release of StyleCop&lt;/a&gt; (so you don’t need to install StyleCop in the build machine, so it works well on VSTS). To use this task:&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>Updated 22 Mar 2016</strong> This tasks is available in the <a href="https://marketplace.visualstudio.com/items?itemName=richardfennellBM.BM-VSTS-StyleCop-Task">VSTS Marketplace</a> I have <a href="/blogs/rfennell/post/2015/04/03/Running-StyleCop-from-the-command-line-and-in-a-TFS-2015-vNext-build.aspx">previously posted</a> on how a PowerShell script can be used to run StyleCop as part of vNext VSTS/TFS build. Now I have more experience with vNext tasks it seemed a good time to convert this PowerShell script into a true task that can deploy StyleCop and making it far easier to expose the various parameters StyleCop allows. To this end I have written a new StyleCop task that can be found in my <a href="https://github.com/rfennell/vNextBuild">vNext Build Repo</a>, this has been built to use the <a href="https://stylecop.codeplex.com/">4.7.49.0 release of StyleCop</a> (so you don’t need to install StyleCop in the build machine, so it works well on VSTS). To use this task:</p>
<ol>
<li>Clone the repo</li>
<li><a href="https://github.com/rfennell/vNextBuild/wiki/Build-Tasks">Build the tasks using Gulp</a></li>
<li><a href="https://github.com/rfennell/vNextBuild/wiki/Build-Tasks">Upload the task</a> you require to your VSTS or TFS instance</li>
</ol>
<p>Once this is done you can add the task to your build. You probably won’t need to set any parameters as long as you have <strong>settings.stylecop</strong> files to define your StyleCop ruleset in the same folders as your <strong>.CSPROJ</strong> files (or are happy default rulesets). If you do want to set parameters your options are:</p>
<ul>
<li>TreatStyleCopViolationsErrorsAsWarnings - Treat StyleCop violations errors as warnings, if set to False any StyleCop violations will cause the build to fail (default false).</li>
</ul>
<p>And on the advanced panel</p>
<ul>
<li>MaximumViolationCount - Maximum violations before analysis stops (default 1000)</li>
<li>ShowOutput - Sets the flag so StyleCop scanner outputs progress to the console (default false)</li>
<li>CacheResults - Cache analysis results for reuse (default false)</li>
<li>ForceFullAnalysis - Force complete re-analysis (default true)</li>
<li>AdditionalAddInPath - Path to any custom rule sets folder, the directory cannot be a sub directory of current directory at runtime as this is automatically scanned. This folder must contain your custom DLL and the Stylecop.dll and Stylecop.csharp.cs else you will get load errors</li>
<li>SettingsFile - Path to single settings files to use for all analysis (as opposed to <strong>settings.stylecop</strong> files in project folders)</li>
</ul>
<p>  <a href="/wp-content/uploads/sites/2/historic/image_288.png%22"><img alt="image" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb_284.png" title="image"></a>   When you run the build with the new task you should expect to see a summary of the StyleCop run on the right <a href="/wp-content/uploads/sites/2/historic/image_289.png"><img alt="image" loading="lazy" src="/wp-content/uploads/sites/2/historic/image_thumb_285.png" title="image"></a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
