Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 27 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,33 @@ TfsBuildResultPublisher allows you to create a Fake build, and publish test resu
/buildnumber:"MyApplication_Daily_1.0"

Options:
-c, --collection=VALUE The collection
-p, --project=VALUE The team project
-b, --builddefinition=VALUE The build definition
-n, --buildnumber=VALUE The build number to assign the build\
-s, --status=VALUE Status of the build (Succeeded, Failed, Stopped, PartiallySucceeded, default: Succeeded)
-f, --flavor=VALUE Flavor of the build (to track test results against, default: Debug)
-l, --platform=VALUE Platform of the build (to track test results against, AnyCPU)
-t, --target=VALUE Target of the build (shown on build report, default: default)
--localpath=VALUE Local path of solution file. (default: Solutio n.sln)
--serverpath=VALUE Version Control path for solution file. (e.g. $/Solution.sln)
--droplocation=VALUE Location where builds are dropped (default: \\server\drops\)
--buildlog=VALUE Location of build log file. (e.g. \\server\folder\build.log)
--testResults=VALUE Test results file to publish (*.trx, requires MSTest installed)
--create Should the build definition be created if it does not exist
--trigger Instead of creating a manual build, we should trigger the build
--keepForever Does the build participates in the retention policy of the build definition or to keep the build forever
--buildController=VALUE The name of the build controller to use when creating the build definition (default, first controller)
--publishTestRun Creates a test run in Test Manager (requires tcm.exe installed)
--fixTestIds If the .trx file comes from VSTest.Console.exe, the testId's will not be recognised by Test Runs (for associated automation)
--testSuiteId=VALUE The Test Suite to publish the results of the test run to [tcm /suiteId]
--testConfigid=VALUE The Test Configuration to publish the results of the test run to [tcm /configId]
--testRunTitle=VALUE The title of the test run [tcm /title]
--testRunResultOwner=VALUE The result owner of the test run [tcm /resultOwner]
-c, --collection=VALUE The collection
-p, --project=VALUE The team project
-b, --builddefinition=VALUE The build definition
-n, --buildnumber=VALUE The build number to assign the build\
-s, --status=VALUE Status of the build (Succeeded, Failed, Stopped, PartiallySucceeded, default: Succeeded)
-f, --flavor=VALUE Flavor of the build (to track test results against, default: Debug)
-l, --platform=VALUE Platform of the build (to track test results against, AnyCPU)
-t, --target=VALUE Target of the build (shown on build report, default: default)
--localpath=VALUE Local path of solution file. (default: Solutio n.sln)
--serverpath=VALUE Version Control path for solution file. (e.g. $/Solution.sln)
--droplocation=VALUE Location where builds are dropped (default: \\server\drops\)
--buildlog=VALUE Location of build log file. (e.g. \\server\folder\build.log)
--testResults=VALUE Test results file to publish (*.trx, requires MSTest installed)
--create Should the build definition be created if it does not exist
--trigger Instead of creating a manual build, we should trigger the build
--keepForever Does the build participates in the retention policy of the build definition or to keep the build forever
--buildController=VALUE The name of the build controller to use when creating the build definition (default, first controller)
--publishTestRun Creates a test run in Test Manager (requires tcm.exe installed)
--fixTestIds If the .trx file comes from VSTest.Console.exe, the testId's will not be recognised by Test Runs (for associated automation)
--testSuiteId=VALUE The Test Suite to publish the results of the test run to [tcm /suiteId]
--testConfigid=VALUE The Test Configuration to publish the results of the test run to [tcm /configId]
--testRunTitle=VALUE The title of the test run [tcm /title]
--testRunResultOwner=VALUE The result owner of the test run [tcm /resultOwner]
--changeSets=VALUE The changeset Id's to associate the build with (value is comma delimited: 1,2,3)
--workItems=VALUE The workiem Id's to associate the build with (value is comma delimited: 1,2,3)
--autoAssocChangesetWorkItems=VALUE Whether to auto-associate changeset workitems to the build (true if a value is present)
--buildQueueDisabled=VALUE Whether the build definition's queue is created disabled (true if a value is present)

## References
**Original Blog post:** [http://blogs.msdn.com/b/jpricket/archive/2010/02/23/creating-fake-builds-in-tfs-build-2010.aspx](http://blogs.msdn.com/b/jpricket/archive/2010/02/23/creating-fake-builds-in-tfs-build-2010.aspx)
Expand Down
3 changes: 2 additions & 1 deletion TfsCreateBuild/BuildCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public int Execute(string[] args)
configuration.BuildStatus, configuration.Collection, configuration.BuildLog, configuration.DropPath, configuration.BuildFlavor,
configuration.LocalPath, configuration.BuildPlatform, configuration.BuildTarget, configuration.Project, configuration.BuildDefinition,
configuration.CreateBuildDefinitionIfNotExists, configuration.BuildController, configuration.BuildNumber, configuration.ServerPath,
configuration.KeepForever);
configuration.KeepForever, configuration.AssociatedChangesetIds, configuration.AssociatedWorkitemIds, configuration.AutoIncludeChangesetWorkItems,
configuration.BuildQueueDisabled);
}

if (!string.IsNullOrEmpty(configuration.TestResults) && File.Exists(configuration.TestResults))
Expand Down
5 changes: 4 additions & 1 deletion TfsCreateBuild/BuildTestResultPublisher.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;

namespace TfsBuildResultPublisher
{
Expand All @@ -10,10 +11,12 @@ public bool PublishTestResultsToBuild(string collection, string testResultsFile,
{
var paths = new[]
{
@"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\MSTest.exe",
@"C:\Program Files\Microsoft Visual Studio 14.0\Common7\IDE\MSTest.exe",
@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\MSTest.exe",
@"C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\MSTest.exe"
};
var msTest = File.Exists(paths[0]) ? paths[0] : paths[1];
var msTest = paths.FirstOrDefault(File.Exists);
const string argsFormat = "/publish:\"{0}\" /publishresultsfile:\"{1}\" /teamproject:\"{2}\" /publishbuild:\"{3}\" /platform:\"{4}\" /flavor:\"{5}\"";
var args = string.Format(argsFormat, collection, testResultsFile, project, buildNumber, buildPlatform, buildFlavour);
string stdOut;
Expand Down
4 changes: 4 additions & 0 deletions TfsCreateBuild/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,9 @@ public class Configuration
public string TeamCityPassword { get; set; }
public bool TriggerBuild { get; set; }
public bool KeepForever { get; set; }
public int[] AssociatedChangesetIds { get; set; }
public int[] AssociatedWorkitemIds { get; set; }
public bool AutoIncludeChangesetWorkItems { get; set; }
public bool BuildQueueDisabled { get; set; }
}
}
4 changes: 4 additions & 0 deletions TfsCreateBuild/ConfigurationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public bool TryProvide(string[] args, out Configuration configuration)
{"testConfigid=", @"The Test Configuration to publish the results of the test run to [tcm /configId]", v => localConfiguration.TestConfigId = int.Parse(v)},
{"testRunTitle=", @"The title of the test run [tcm /title]", v => localConfiguration.TestRunTitle = v},
{"testRunResultOwner=", @"The result owner of the test run [tcm /resultOwner]", v => localConfiguration.TestRunResultOwner = v},
{"changeSets=", @"The changeset Id's to associate the build with", v => localConfiguration.AssociatedChangesetIds = Array.ConvertAll(v.Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries), int.Parse)},
{"workItems=", @"The workiem Id's to associate the build with", v => localConfiguration.AssociatedWorkitemIds = Array.ConvertAll(v.Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries), int.Parse)},
{"autoAssocChangesetWorkItems=", @"Whether to auto-associate changeset workitems to the build", v => localConfiguration.AutoIncludeChangesetWorkItems = (v !=null)},
{"buildQueueDisabled=", @"Whether the build definition's queue is disabled", v => localConfiguration.BuildQueueDisabled = (v !=null)},
};

try
Expand Down
2 changes: 1 addition & 1 deletion TfsCreateBuild/ITfsManualBuildCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
{
public interface ITfsManualBuildCreator
{
void CreateManualBuild(string buildStatus, string collection, string buildLog, string dropPath, string buildFlavour, string localPath, string buildPlatform, string buildTarget, string project, string buildDefinition, bool createBuildDefinitionIfNotExists, string buildController, string buildNumber, string serverPath, bool keepForever);
void CreateManualBuild(string buildStatus, string collection, string buildLog, string dropPath, string buildFlavour, string localPath, string buildPlatform, string buildTarget, string project, string buildDefinition, bool createBuildDefinitionIfNotExists, string buildController, string buildNumber, string serverPath, bool keepForever, int[] associatedChangesetIds, int[] associatedWorkitemIds, bool autoIncludeChangesetWorkItems, bool buildQueueDisabled);
}
}
7 changes: 6 additions & 1 deletion TfsCreateBuild/TfsBuildResultPublisher.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@
</Reference>
<Reference Include="Microsoft.TeamFoundation.TestManagement.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.TeamFoundation.TestManagement.Common, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.TeamFoundation.VersionControl.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.TeamFoundation.WorkItemTracking.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Microsoft.TeamFoundation.WorkItemTracking.Common, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="NDesk.Options">
<HintPath>..\packages\NDesk.Options.0.2.1\lib\NDesk.Options.dll</HintPath>
</Reference>
Expand Down Expand Up @@ -102,7 +105,9 @@
<Compile Include="TrxFileCorrector.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="app.config">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
<None Include="TfsCreateBuild.nuspec">
<SubType>Designer</SubType>
Expand Down
42 changes: 35 additions & 7 deletions TfsCreateBuild/TfsManualBuildCreator.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace TfsBuildResultPublisher
{
public class TfsManualBuildCreator : ITfsManualBuildCreator
{
public void CreateManualBuild(string buildStatus, string collection, string buildLog, string dropPath, string buildFlavour, string localPath, string buildPlatform, string buildTarget, string project, string buildDefinition, bool createBuildDefinitionIfNotExists, string buildController, string buildNumber, string serverPath, bool keepForever)
public void CreateManualBuild(string buildStatus, string collection, string buildLog, string dropPath, string buildFlavour, string localPath, string buildPlatform, string buildTarget, string project, string buildDefinition, bool createBuildDefinitionIfNotExists, string buildController, string buildNumber, string serverPath, bool keepForever, int[] associatedChangesetIds, int[] associatedWorkitemIds, bool autoIncludeChangesetWorkItems, bool buildQueueDisabled)
{
// Get the TeamFoundation Server
var tfsCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(collection));
Expand All @@ -17,7 +20,7 @@ public void CreateManualBuild(string buildStatus, string collection, string buil

// Create a fake definition
var definition = CreateOrGetBuildDefinition(buildServer, project, buildDefinition, createBuildDefinitionIfNotExists,
buildController, dropPath);
buildController, dropPath, buildQueueDisabled);

// Create the build detail object
var buildDetail = definition.CreateManualBuild(buildNumber);
Expand All @@ -32,6 +35,31 @@ public void CreateManualBuild(string buildStatus, string collection, string buil
if (!string.IsNullOrEmpty(buildLog))
buildDetail.LogLocation = buildLog;

WorkItem[] workItems = {};
if (associatedChangesetIds != null)
{
var service = tfsCollection.GetService<VersionControlServer>();
var changesets = associatedChangesetIds.Select(changesetId => service.GetChangeset(changesetId, false, false)).ToArray();
buildProjectNode.Node.Children.AddAssociatedChangesets(changesets);

if (autoIncludeChangesetWorkItems)
workItems = workItems.Concat(changesets.SelectMany(c => c.WorkItems)).ToArray();
}

if (associatedWorkitemIds != null)
{
var service = tfsCollection.GetService<WorkItemStore>();
workItems = workItems.Concat(associatedWorkitemIds.Select(id => service.GetWorkItem(id))).ToArray();
}

buildProjectNode.Node.Children.AddAssociatedWorkItems(workItems);
const string integrationBuild = "Integration Build";
foreach (var wi in workItems.Where(wi => wi.Fields.Contains(integrationBuild)))
{
wi.Fields[integrationBuild].Value = definition.Name + "/" + buildDetail.BuildNumber;
wi.Save();
}

buildProjectNode.Save();

// Complete the build by setting the status to succeeded
Expand All @@ -42,8 +70,8 @@ public void CreateManualBuild(string buildStatus, string collection, string buil
private IBuildDefinition CreateOrGetBuildDefinition(
IBuildServer buildServer,
string project, string buildDefinition,
bool createBuildDefinitionIfNotExists,
string buildController, string dropLocation)
bool createBuildDefinitionIfNotExists,
string buildController, string dropLocation, bool buildQueueDisabled)
{
try
{
Expand All @@ -56,10 +84,10 @@ private IBuildDefinition CreateOrGetBuildDefinition(
}

Console.WriteLine("'{0}' does not exist, trying to create build definition", buildDefinition);
return CreateBuildDefinition(buildServer, buildController, project, dropLocation, buildDefinition);
return CreateBuildDefinition(buildServer, buildController, project, dropLocation, buildDefinition, buildQueueDisabled);
}

private IBuildDefinition CreateBuildDefinition(IBuildServer buildServer, string buildController, string project, string dropLocation, string buildDefinition)
private IBuildDefinition CreateBuildDefinition(IBuildServer buildServer, string buildController, string project, string dropLocation, string buildDefinition, bool buildQueueDisabled)
{
var controller = GetBuildController(buildServer, buildController);

Expand All @@ -72,7 +100,7 @@ private IBuildDefinition CreateBuildDefinition(IBuildServer buildServer, string
definition.BuildController = controller;
definition.DefaultDropLocation = dropLocation;
definition.Description = "Fake build definition used to create fake builds.";
definition.QueueStatus = DefinitionQueueStatus.Enabled;
definition.QueueStatus = buildQueueDisabled ? DefinitionQueueStatus.Disabled : DefinitionQueueStatus.Enabled;
definition.Workspace.AddMapping("$/", "c:\\fake", WorkspaceMappingType.Map);
definition.Process = processTemplate;
definition.Save();
Expand Down
45 changes: 44 additions & 1 deletion TfsCreateBuild/app.config
Original file line number Diff line number Diff line change
@@ -1,3 +1,46 @@
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<!-- Uncomment to re-bind to the TFS 2013 libraries
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.TeamFoundation.Client" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.TeamFoundation.Build.Client" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.TeamFoundation.VersionControl.Client" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.TeamFoundation.WorkItemTracking.Client" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.TeamFoundation.Build.Common" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.TeamFoundation.WorkItemTracking.Common" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
-->
</configuration>