A workaround for the error ‘TF14061: The workspace ws_1_18;Project Collection Build Service does not exist’ when mapping a TFVC workspace

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.

In Team Explorer, when I came to do a ‘Map & Get’ to map the source locations I got a ‘TF14061: The workspace ws_1_18;Project Collection Build Service does not exist’ error

image

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

Making sure when you use VSTS build numbers to version Android Packages they can be uploaded to the Google Play Store

Background

I have a VSTS build extension that can apply a VSTS generated build number to Android APK packages. 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.

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 major.minor.patch e.g. 1.2.3, and uses the 1.2 as the Version Name and the 3 as the Version Code.

Now, it is important to note that the Version Code must be a integer between 1 and 2100000000 and for the Google Play Store it must be incrementing between versions.

So maybe these default parameter values for this task are not the best options?

The problem the way we use the task

When we use the Android Manifest Versioning task for our tuServ Android packages we use different parameter values, but we recently found these values still cause a problem.

Our VSTS build generates  build numbers with four parts $(Major).$(Minor).$(Year:yy)$(DayOfYear).$(rev:r)

  • $(Major) – set as a VSTS variable e.g. 1
  • $(Minor) – set as a VSTS variable e.g. 2
  • $(Year:yy)$(DayOfYear) – the day for the year e.g. 18101
  • $(rev:r) – the build count for the build definition for the day e.g. 1

So we end up with build numbers in the form 1.2.18101.1

The Android version task is set in the build to make

  • the Version Number {1}.{2}.{3}.{4}  – 1.2.18101.1
  • the Version Code {1}{2}{3}{4} – 12181011

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.

  • day 1 the published build is 1.2.18101.11 so the Version Code is 121810111
  • day 2 the published build is 1.2.18102.1 so the Version Code is
    12181021

So the second Version Code is 10x smaller, hence the package cannot be published.

The Solution

The answer in the end was straightforward and found by one of our engineers Peter (@sarkimedes). It was to change the final block of the VSTS build number to $(rev:rrr), as detailed in the VSTS documentation. 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.

So using the new build version number

  • day 1 the published build is 1.2.18101.011 so the Version Code is
    1218101011
  • day 2 the published build is 1.2.18102.001 so the Version Code is
    1218102001

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.

    Major new release of my VSTS Cross Platform Extension to build Release Notes

    Today I have released a major new release, V2, of my VSTS Cross Platform Extension to build release notes. This new version is all down to the efforts of Greg Pakes who has completely re-written the task to use newer VSTS APIs.

    A minor issue is that this re-write has introduced a couple of breaking changes, as detailed below and on the project wiki

    • oAuth script access has to be enabled on the agent running the task

    image

    • 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 project repo

    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.

    Hope people still find the task of use and thanks again to Greg for all the work on the extension

    Backing up your TFVC and Git Source from VSTS

    The Issue

    Azure is a highly resilient service, and VSTS has excellent SLAs. 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. Though there have been requests for such a service.

    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.

    A Solution

    To address this issue I decided to write a PowerShell script to download all the GIT and TFVC source in a VSTS instance. The following tactics were used

    • 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
    • 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.

    So that the process was run on regular basis I designed it to be run within a VSTS build. Again here I had choices:

    • 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
    • To use the System Token already available to the build agent. 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.

    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

    To use this script you just pass in

    • The name of the instance to backup
    • A valid PAT for the named instance
    • The path to backup too, which can be a UNC share assuming the build agent has rights to the location

    What’s Next

    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.

    Opps, I made that test VSTS extension public by mistake, what do I do now?

    I recently, whilst changing a CI/CD release pipeline, updated what was previously a private version of a VSTS extension in the VSTS Marketplace with a version of the VSIX package set to be public.

    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.

    So, this meant I had two public versions of the same extension, confusing.

    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.

    So my only option was to un-publish the previously private extension so only the correct version was visible in the public marketplace.

    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.

    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.

    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’

    Using VSTS Gates to help improve my deployment pipeline of VSTS Extensions to the Visual Studio Marketplace

    My existing VSTS CI/CD process 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 VSTS Release Gates; 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?

    What did not work

    My first thought was to use the Invoke HTTP REST API gate, calling the VSTS API https://<your vsts instance name>.visualstudio.com/_apis/distributedtask/tasks/<GUID of Task>. 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 JSONPATH query in the gates success criteria parameter to make sure the correct version of the task is deployed e.g. eq($.value[?(@.name == “BuildRetensionTask”)].contributionVersion, “1.2.3”)

    However, there is a problem. At this time the Invoke HTTP REST API gate task does not support the == 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.

    What did work

    The answer, after a suggestion from the VSTS Release Management team at Microsoft, was to try the Azure Function gate.

    To do this I created a new Azure Function. 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 the C# function code (stored in GitHub), to my newly created Azure Function. This function code takes

    • The name of the VSTS instance
    • A personal access token (PAT) to access the VSTS instance
    • The GUID of the task to check for
    • And the version to check for

    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.

    Note: 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!

    To use the Azure Function

    Using the Azure function is simple

      • Added an Azure Function gate to a VSTS release
      • Set the URL 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 variable group variable for this parameter so it was easy to reuse between many CD pipelines
      • Set the Function Key parameter for the Azure Function, again you get this from the Azure Portal. This time I used a secure variable group variable
      • Set the Method parameter to POST
      • Set the Header content type as JSON
    {
          "Content-Type": "application/json"
    }
      • Set the Body 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 $(BUILD.BUILDNUMBER) so the correct version of the tasks is tested for automatically
    {
         "instance": "$(instance)",
         "pat": "$(pat)",
         "taskguid": "$(taskGuid)",
         "version": "$(BUILD.BUILDNUMBER)"
    }
    • Finally set  the Advanced/Completion Event to ApiResponse with the success criteria of
      eq(root['Deployed'], 'true')

    Once this was done I was able to use the Azure function as a VSTS gate as required

    image

    Summary

    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 my code 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

    Building private VSTS build agents using the Microsoft Packer based agent image creation model

    Background

    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.

    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.

    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.

    At Black Marble we have been using Lability to build our lab environments and there is no reason we could not use the same system to create our VSTS build agent VMs

    • Creating base VHDs disk images with patched copies of Windows installed (which we update on a regular basis)
    • Use Lability 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

    However, there is an alternative. Microsoft have made their Packer based method of creating VSTS Azure hosted agents available on GitHub. 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.

    The Basic Process

    To enable this way of working I forked the Microsoft repo 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 builder section of the packer configuration and leaving the providers unaltered

    So, in doing this I learnt a few things

    Which ISO to use?

    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

    Building an Answer.ISO

    In the sample I found for the Packer hyperv-iso builder the AutoUnattended.XML 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.

    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 AutoUnattended.XML answers file edited in VSCode is the correct encoding by default.

    I also found that if I ran the PowerShell script to create the ISO from within VSCode’s integrated terminal the ISO builder mkisofs.exe failed with an internal error. However, it worked fine from a default PowerShell windows.

    Installing the .NET 3.5 Feature

    When a provider tried to install the .NET 3.5 feature using the command

    Install-WindowsFeature -Name NET-Framework-Features -IncludeAllSubFeature

    it failed.

    Seems this is a bug in Windows 2016 and the workaround is to specify the –Source location on the install media

    Install-WindowsFeature -Name NET-Framework-Features -IncludeAllSubFeature -Source “D:sourcessxs”

    Once the script was modified in this manner it ran without error

    Well how long does it take?

    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.

    I also found the process a bit brittle. I had to restart the process a good few times as….

    • I ran out of disk space (no unsurprising this broke the process)
    • 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.
    • Packer decided the VM had rebooted when it had not – usually due to a slow install of some feature or network issues
    • My Laptop went to sleep and caused one of the above problems

    So I have a SysPrep’d VHD now what do I do with it now?

    At this point I have options of what to do with this new exported HyperV image. I could manually create build agent VM instances.

    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.

    Versioning your ARM templates within a VSTS CI/CD pipeline with Semantic Versioning

    I wrote a post recently Versioning your ARM templates within a VSTS CI/CD pipeline. I realised since writing it that it does not address the issue of if you wish to version your ARM Templates using Semantic Versioning. 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 my Version JSON file task to address.

    This change to my task allows it to be used with the GitVersion VSTS task to manage the semantic versioning. For more details on GitVersion see the project documentation.

    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.

    • Add the GitVersion task at the start of the build, with its default parameters
    • Add my JSON versioning task with default parameters apart from
      • Version Number set to $(GitVersion.SemVer)
      • Use Version Number without Processing (Advanced) checked
      • Filename Pattern (Advanced) set to azuredeploy.json
      • Field to update (Advanced) set to contentVersion

    image

    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 'contentVersion' version
    Existing Tag: contentVersion": "1.0.0.0"
    Replacement Tag: contentVersion": "0.1.0-unstable.843"
    …
    

    Creating test data for my Generate Release Notes Extension for use in CI/CD process

    As part of the continued improvement to my CI/CD process I needed to provide a means so that whenever I test my Generate Release Notes Task, 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

    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. This is documented by Microsoft.

    The PowerShell task to run this code is placed in a build as the only task

    image

    This build is then triggered as part of the release process

    image

    Note that the triggering of this build has to be such that it runs on a non-blocking build agent as discussed in my previous posts. 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.

    How I fixed my problem that my VSTS Build Extension was too big to upload to the Marketplace

    Whist adding a couple of new tasks to my VSTS Manifest Versioning Extension 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 '23255292 bytes' exceeds the 
    maximum package size '20971520 bytes'

    This extension now contains  eleven tasks, four of which are now NodeJS based as opposed to PowerShell. The issue here is whereas PowerShell tasks are usually a file or two of code and maybe a PSM module; NodeJS based ones, as well as my logic, always have a Node_Modules folder full of NPM modules needed for production use. This fact had caused a good deal of bloat in the VSIX package.

    The solution was to address my poor management of NPM modules. As many of the versioning tasks are similar in logical structure i.e.

    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 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.

    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.