Skip to content

Commit b64def1

Browse files
authored
Merge pull request #244 from phlorian/feature/gh-243
(GH-243) Add test runs and test results to build
2 parents bbe3e18 + 147219e commit b64def1

File tree

6 files changed

+149
-0
lines changed

6 files changed

+149
-0
lines changed

src/Cake.AzureDevOps/Cake.AzureDevOps.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
<TfmSpecificPackageFile Include="$(OutputPath)\**\Microsoft.TeamFoundation.SourceControl.WebApi.dll">
7676
<PackagePath>lib\$(TargetFramework)\</PackagePath>
7777
</TfmSpecificPackageFile>
78+
<TfmSpecificPackageFile Include="$(OutputPath)\**\Microsoft.TeamFoundation.TestManagement.WebApi.dll">
79+
<PackagePath>lib\$(TargetFramework)\</PackagePath>
80+
</TfmSpecificPackageFile>
7881
<TfmSpecificPackageFile Include="$(OutputPath)\**\Microsoft.VisualStudio.Services.Client.Interactive.dll">
7982
<PackagePath>lib\$(TargetFramework)\</PackagePath>
8083
</TfmSpecificPackageFile>

src/Cake.AzureDevOps/Pipelines/AzureDevOpsBuild.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6+
using System.Threading.Tasks;
67
using Cake.AzureDevOps.Authentication;
78
using Cake.Core.Diagnostics;
89
using Microsoft.TeamFoundation.Build.WebApi;
10+
using Microsoft.TeamFoundation.TestManagement.WebApi;
911

1012
/// <summary>
1113
/// Class for writing issues to Azure DevOps pull requests.
@@ -16,6 +18,7 @@ public sealed class AzureDevOpsBuild
1618
private readonly IAzureDevOpsCredentials credentials;
1719
private readonly bool throwExceptionIfBuildCouldNotBeFound;
1820
private readonly IBuildClientFactory buildClientFactory;
21+
private readonly ITestManagementClientFactory testClientFactory;
1922
private readonly Build build;
2023

2124
/// <summary>
@@ -45,6 +48,7 @@ internal AzureDevOpsBuild(ICakeLog log, AzureDevOpsBuildsSettings settings, Buil
4548
this.log = log;
4649
this.build = build;
4750
this.buildClientFactory = new BuildClientFactory();
51+
this.testClientFactory = new TestManagementClientFactory();
4852
this.credentials = settings.Credentials;
4953
this.CollectionUrl = settings.CollectionUrl;
5054
}
@@ -65,6 +69,7 @@ internal AzureDevOpsBuild(ICakeLog log, AzureDevOpsBuildSettings settings, IBuil
6569

6670
this.log = log;
6771
this.buildClientFactory = buildClientFactory;
72+
this.testClientFactory = new TestManagementClientFactory();
6873
this.credentials = settings.Credentials;
6974
this.CollectionUrl = settings.CollectionUrl;
7075
this.throwExceptionIfBuildCouldNotBeFound = settings.ThrowExceptionIfBuildCouldNotBeFound;
@@ -401,6 +406,62 @@ public IEnumerable<AzureDevOpsBuildArtifact> GetArtifacts()
401406
}
402407
}
403408

409+
/// <summary>
410+
/// Gets the test run ID's of a build.
411+
/// </summary>
412+
/// <returns>A list of RunIDs as int.</returns>
413+
public IEnumerable<AzureDevOpsTestRun> GetTestRuns()
414+
{
415+
if (!this.ValidateBuild())
416+
{
417+
return new List<AzureDevOpsTestRun>();
418+
}
419+
420+
using (var testClient = this.testClientFactory.CreateTestManagementClient(this.CollectionUrl, this.credentials.ToVssCredentials()))
421+
{
422+
return
423+
testClient
424+
.GetTestResultDetailsForBuildAsync(this.ProjectId, this.build.Id)
425+
.GetAwaiter()
426+
.GetResult()
427+
.ResultsForGroup
428+
.SelectMany(testResultGroup => testResultGroup.Results).ToList()
429+
.GroupBy(testResult => testResult.TestRun.Id)
430+
.Select(runGroup => int.Parse(runGroup.Key))
431+
.Select(runId =>
432+
new AzureDevOpsTestRun
433+
{
434+
RunId = runId,
435+
TestResults =
436+
this.GetTestResults(testClient, runId)
437+
.GetAwaiter()
438+
.GetResult(),
439+
});
440+
}
441+
}
442+
443+
/// <summary>
444+
/// Gets the test runs of this build.
445+
/// </summary>
446+
/// <param name="testClient">Instance of a <see cref="TestManagementHttpClient"/> class.</param>
447+
/// <param name="runId">Id of the test run.</param>
448+
/// <returns>The test results for a build or an empty list if no build could be found and
449+
/// <see cref="AzureDevOpsBuildSettings.ThrowExceptionIfBuildCouldNotBeFound"/> is set to <c>false</c>.</returns>
450+
/// <exception cref="AzureDevOpsBuildNotFoundException">If build could not be found and
451+
/// <see cref="AzureDevOpsBuildSettings.ThrowExceptionIfBuildCouldNotBeFound"/> is set to <c>true</c>.</exception>
452+
private async Task<IEnumerable<AzureDevOpsTestResult>> GetTestResults(TestManagementHttpClient testClient, int runId)
453+
{
454+
return
455+
(await testClient.GetTestResultsAsync(this.ProjectId, runId).ConfigureAwait(false))
456+
.Select(test =>
457+
new AzureDevOpsTestResult
458+
{
459+
AutomatedTestName = test.AutomatedTestName,
460+
Outcome = test.Outcome,
461+
ErrorMessage = test.ErrorMessage,
462+
});
463+
}
464+
404465
/// <summary>
405466
/// Validates if a build could be found.
406467
/// Depending on <see cref="AzureDevOpsBuildSettings.ThrowExceptionIfBuildCouldNotBeFound"/>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace Cake.AzureDevOps.Pipelines
2+
{
3+
using System.Collections.Generic;
4+
5+
/// <summary>
6+
/// Represents a test result associated with a <see cref="AzureDevOpsTestRun" />.
7+
/// </summary>
8+
public class AzureDevOpsTestResult
9+
{
10+
/// <summary>
11+
/// Gets the automated test name.
12+
/// </summary>
13+
public string AutomatedTestName { get; internal set; }
14+
15+
/// <summary>
16+
/// Gets the outcome of the test.
17+
/// </summary>
18+
public string Outcome { get; internal set; }
19+
20+
/// <summary>
21+
/// Gets the message of the test.
22+
/// </summary>
23+
public string ErrorMessage { get; internal set; }
24+
}
25+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace Cake.AzureDevOps.Pipelines
2+
{
3+
using System.Collections.Generic;
4+
5+
/// <summary>
6+
/// Represents a test run associated with a <see cref="AzureDevOpsBuild" />.
7+
/// </summary>
8+
public class AzureDevOpsTestRun
9+
{
10+
/// <summary>
11+
/// Gets the name of the test run.
12+
/// </summary>
13+
public int RunId { get; internal set; }
14+
15+
/// <summary>
16+
/// Gets the test results of a test run.
17+
/// </summary>
18+
public IEnumerable<AzureDevOpsTestResult> TestResults { get; internal set; }
19+
}
20+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
namespace Cake.AzureDevOps
2+
{
3+
using System;
4+
using Cake.AzureDevOps.Authentication;
5+
using Microsoft.TeamFoundation.Build.WebApi;
6+
using Microsoft.TeamFoundation.TestManagement.WebApi;
7+
using Microsoft.VisualStudio.Services.Common;
8+
using Microsoft.VisualStudio.Services.Identity;
9+
10+
/// <summary>
11+
/// The interface for a Git client factory.
12+
/// </summary>
13+
internal interface ITestManagementClientFactory
14+
{
15+
/// <summary>
16+
/// Creates the instance of the <see cref="TestManagementHttpClient"/> class.
17+
/// </summary>
18+
/// <param name="collectionUrl">The URL of the Azure DevOps team project collection.</param>
19+
/// <param name="credentials">The credentials to connect to Azure DevOps.</param>
20+
/// <returns>The instance of <see cref="TestManagementHttpClient"/> class.</returns>
21+
TestManagementHttpClient CreateTestManagementClient(Uri collectionUrl, VssCredentials credentials);
22+
}
23+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace Cake.AzureDevOps
2+
{
3+
using System;
4+
using Microsoft.TeamFoundation.TestManagement.WebApi;
5+
using Microsoft.VisualStudio.Services.Common;
6+
7+
/// <inheritdoc />
8+
internal class TestManagementClientFactory : ITestManagementClientFactory
9+
{
10+
/// <inheritdoc />
11+
public TestManagementHttpClient CreateTestManagementClient(Uri collectionUrl, VssCredentials credentials)
12+
{
13+
TestManagementHttpClient testClient = new TestManagementHttpClient(collectionUrl, credentials);
14+
return testClient;
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)