TFS2015 vNext Build + PowerShell Customization -- Exception calling Save: TF215070: The build URI is not valid - powershell

Was previously using TFS2013 and XAML-based builds. Had created a number of custom tasks for the XAML builds in C#, including one to set the build number programmatically through the TFS .NET Client API libraries (not the REST API). Have now moved to TFS2015 and trying to move to vNext-based builds. Trying to convert our C#-based customizations to the new build process by re-coding as PowerShell scripts. I am trying to use the following script to programmatically set the build number (as we did previously via C#):
# Step 1: load the TFS assemblies
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Common")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")
# Step 2: get the collection
$collection=[Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)
# Step 3: get the build server
$buildServer=$collection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
# Step 4: get the details for the currently running build
$buildDetail = $buildServer.GetBuild($env:BUILD_BUILDURI)
# Step 5: update the build number
$buildDetail.BuildNumber = "1.2.3.4-MyBuild"
# Step 6: save the changes to the build details
$buildDetail.Save()
Everything seems to work just fine until step 6, when I try and save the change made to the buildDetail.BuildNumber. When the "Save()" method is called, the following error is generated:
Exception calling "Save" with "0" argument(s): "TF215070: The build URI vstfs:///Build/Build/40177 is not valid. Make sure that this build exists and has not been deleted.
As best I can tell, step 4 is returning an instance that implements the Microsoft.TeamFoundation.Build.Client.IBuildDetail interface (as I expected it would). Also, clearly the build URI is valid as it is specifically used to load the build information in that same step. Again, this logic mimics the same logic we use in our C#-based XAML customizations, just rewritten under PowerShell.
Searching the internet, I can find nothing related to this error and cannot figure out why I would be receiving it. I did find a (much more complex) version of what I am trying to do here: https://github.com/voice4net/build-scripts/blob/master/ApplyVersionFromSourceControl.ps1. While I haven't tried using this script directly, it appears to be doing basically the same thing and, presumably, worked for its author.
Is there anyone out there that can help me to understand this error, why I am getting it, and, ideally, how to fix it?
SIDE NOTE: This is not Microsoft's hosted TFS; this is a traditional TFS system that our company has installed internally.

It seems like you are trying to use the incorrect API to update your build number. You should be using the WebAPI/REST portion of the client DLLs.
That said I highly suggest you create a custom task in pure PowerShell or TypeScript in order to achieve your goal.
Here is an example of how to do so in TypeScript:
console.log(`##vso[build.updatebuildnumber]${newBuildNumber}`);
or in PowerShell:
Write-VstsUpdateBuildNumber -Value $newBuildNumber
You can check the reference here on how to create build tasks:
https://github.com/Microsoft/vsts-task-lib

The methods in the TFS SOAP object model (such as Microsoft.TeamFoundation.Build.Common) only apply to the XAML build system. You're targeting the wrong build system, which is why you're having problems.
Use the appropriate object model (either the REST APIs directly, or the C# REST API wrappers).

Related

Build code in vscode using external http server

Our code building process is done via an http server which starts the build process after receiving a project uuid from the build command. Once the server starts the compilation, GCC compatible output can be fetched from it.
Note: only my extension is aware of the project uuid which is different per workspace.
AFAIU I can implement it by:
programmatically adding a task which will call a script with the correct workspace uuid. Is this possible?
Having my extension manage the build process. This seems to be far from supported.
Bottom line, I'm trying to avoid asking the user to add anything to the configuration files and I want to completely manage the build process.
Thanks!
As I didn't find a suitable only vscode solution I did the following:
Defined a helper script which I executed as the task. The helper script was respojnsible for the communication against the HTTP server.
I registered the task using vscode.workspace.registerTaskProvider API, and made sure to register it only after figuring out the UUID.
Then in the task itself I executed the helper script.
(A nice task register example can be found here: https://github.com/Microsoft/vscode-extension-samples/tree/master/task-provider-sample)

vNext TFS 2015 QueryBuildDefinition function in powershell not finding my build definition

Trying to call the following within a PowerShell script which is called from a new vNext Build step:
$buildDef = $buildServer.QueryBuildDefinitions($project)
Would have thought that this would return all the build definitions in my project. It only returns my XAML definitions, not my new vNext Build Definitions.
Do I need to use a different function to do this?
Want to get the list of my changesets in the last build since the last good build.
Previously I would have done something like the following:
$workspace = $buildDef.Workspace.Mappings[0].ServerItem
and then passed this $workspace into the QueryHistory function.
The XAML build system (and basically everything else in the "old" TFS object model) uses a SOAP API. The SOAP API is slowly being replaced with a REST API, at least for newer things.
Thus, the task-based build system does not have a SOAP API. It has a REST API. You can access it from C# code either by querying the REST API directly or by using the Team Foundation Server Client NuGet package.

Accessing hidden teamcity artifacts

So, the key element here is hidden artefacts, also known as those that appear under .teamcity/ part of the build artifacts.
Some context:
We currently run dotCover over our NUnit Test step to report on our test coverage. This places a compilation of the results in a file named CoverageResults.xml under .teamcity/.NETCoverage/. This is the file I would like to accces so we can mine if for some data and send it to a gecko board.
Now, so far, we can successfully get at artifacts not in this part of the directory (such as the result of the build when we output it, etc) using the advised methodology. The problem only occurs when accessing this hidden directory.
The other odd things is the response: a 302 Temporarily Moved.
For reference, my link looks like: (in powershell btw)
"http://{0}:{1}#{2}/guestAuth/repository/download/{3}/.lastFinished/.teamcity/.NETCoverage/CoverageReport.xml" -f $serverURl, $gUName, $gPassword, $buildType
Does anyone have any advice on accessing hidden artifacts? Where else this data could be drawn from (we've found nothing on system variables for this)?
Note: We are already aware that these artifacts are not produced till the build step completes. We are doing this after the fact against a completed build, not during the Build Job itself.
If you add this in the Artifact Paths field it will attach the report as a build artifact once the build has completed
%system.teamcity.build.tempDir%\**\CoverageReport.xml
Hope this helps
Leaving the solution we came up with in case it can be help to anyone else:
In the end, we never got the nitty-gritty of the why but in short, using the in URL authentication with Powershell's Invoke-WebRequest does not work. It appears this is culled from the request created or some such but we went in another direction so I cannot comment much more on this.
What we did do was instead, use cURL. This does not do whatever Powershell does so we simply broke this down into two steps on the Team City Build. A command line step to use cURL to download the file and place it in a temporary directory and the a Powershell step afterwards to get the file and do what we wanted to do.

Incremental Build with MSBuild.exe

I'm building a Visual Studio 2010 solution through Python with a call to subprocess. When called directly from the command line it takes devenv.com ~15 seconds to start. But when called from Python this jumps up to ~1.5 minutes.
Naturally I'm hoping to remove that dead time from our build. So I decided to test out MSBuild.exe (from .NET 4). It looks like MSBuild.exe runs instantly. But... it seems to do a full build every time and not an incremental.
The command I'm using is
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" "C:\path\to\my\project.sln" /target:build /maxcpucount:8 /property:Configuration=Release
It seems like this should support an incremental build. But I've seen posts online indicating that msbuild may not be able to support a incremental build like this.
Is this possible? If so what am I doing wrong?
Update:
I've read into this a bit more. Based on
http://msdn.microsoft.com/en-us/library/ms171483.aspx
and
http://www.digitallycreated.net/Blog/67/incremental-builds-in-msbuild-and-how-to-avoid-breaking-them
It seems like I need the Input and Output properties set in my .vcxproj files. Checking out my files these are indeed missing.
When would they be generated? Most my .vcxproj files were converted over from Visual Studio 2008. But I also generated a new project which is missing the Input and Output properties as well.
Does VS2010 not create projects with these properties?
Update: We've since upgrade to VS 2013. Now msbuild supports incremental builds. Never got to the bottom of the VS 2010 issue.
I think that fact that Incremental builds are not supported is a false Statement from according to official sources,Managed Incremental Build this feature and was included in VS2010 SP1
We first introduced the managed incremental build feature in VS2008.
In VS2010, we were not able to re-implement the managed incremental
build feature with the build system moving to MSBuild. We received
strong customer requests for this feature. As a result, we
re-implemented this feature and it is included in VS2010 SP1.
Other Solutions I found on Web
Projects should build incrementally already (just make sure that you
do Build instead of Rebuild). The best way to check if incremental
building works is to run the build from the command line. The second
time you build it should take almost no time.
If things are still getting rebuilt, then perhaps you've modified
your projects in some way that's messing up with the build order.
Looking at the build logs (via the /v option) can help you poinpoint
what's going on.
Other reason which can cause problems with the incremental build is GenerateResource.TrackFileAccess PropertyThis API supports the .NET Framework infrastructure and is not intended to be used directly from your code.
Gets or sets a switch that specifies whether we should be tracking file access patterns.

Get Build Version in automated build deployment using TFS

I am deploying web application to azure using TFS CI automated build deployment.
In our config maintain build version like 2014.05.19.1 which is $(Date).$(rev) format.
All I want to update config each time build is deployed.For that I am passing value to 'BuildVersion' parameter in template to powershell script which actually performs publishing to azure.
I tried using $(Date:yyyyMMdd)$(Rev:.r) but it is considered string as it is.
I want to get current build version just like IBuildDetail.BuildNumber
within template.
My question is how to get the build version?
If you are using Invoke Process, instead of passing value for BuildVersion parameter you can directly use 'BuildDetail.BuildNumber' in parameters for process like
String.Format("-BuildNumber ""{0}""",BuildDetail.BuildNumber)
This would give the required build number.
If your PowerShell script is being executed from your TFS build, it should have access to the environment variables specific to the TFS context of the build. If that is the case, you actually don't need to pass the $(BuildVersion) parameter to the script, as it already is accessible to the PS script in the $env:TF_BUILD_BUILDNUMBER environment variable. Try testing something like $env:TF_BUILD_BUILDNUMBER | Out-File "D:\Dev\BuildNumber.txt" in your script. You should hopefully see the file containing your build number after running your build.
(I am assuming you are using a relatively new build process template...one that contains the "Post-Build script path" parameter, such as TfvcTemplate.12.xaml)
Hope this is helpful.
I would recommend that you use the right tool for the right job. The build system, is really only for building (compile & test). We have been using it for other things for years coz we did not have another integrated solution. However Microsoft recently bought InRelease and rebranded as Release Management for Visual Studio 2013. I have successfully integrated this with TFS 2012 as well.