diff --git a/src/Cake.AzureDevOps.Tests/Boards/WorkItemTracking/AzureDevOpsWorkItemTrackingSettingsTests.cs b/src/Cake.AzureDevOps.Tests/Boards/WorkItemTracking/AzureDevOpsWorkItemTrackingSettingsTests.cs
new file mode 100644
index 00000000..3d52d67e
--- /dev/null
+++ b/src/Cake.AzureDevOps.Tests/Boards/WorkItemTracking/AzureDevOpsWorkItemTrackingSettingsTests.cs
@@ -0,0 +1,684 @@
+namespace Cake.AzureDevOps.Tests.Boards.WorkItemTracking
+{
+ using System;
+ using Cake.AzureDevOps.Authentication;
+ using Cake.AzureDevOps.Boards.WorkItemTracking;
+ using Shouldly;
+ using Xunit;
+
+ public sealed class AzureDevOpsWorkItemTrackingSettingsTests
+ {
+ public sealed class TheCtorForProjectGuid
+ {
+ [Fact]
+ public void Should_Throw_If_CollectionUrl_Is_Null()
+ {
+ // Given
+ Uri collectionUrl = null;
+ var projectGuid = Guid.NewGuid();
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials));
+
+ // Then
+ result.IsArgumentNullException("collectionUrl");
+ }
+
+ [Fact]
+ public void Should_Throw_If_ProjectGuid_Is_Empty()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.Empty;
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials));
+
+ // Then
+ result.IsArgumentOutOfRangeException("projectGuid");
+ }
+
+ [Fact]
+ public void Should_Throw_If_Credentials_Are_Null()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.NewGuid();
+ IAzureDevOpsCredentials credentials = null;
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials));
+
+ // Then
+ result.IsArgumentNullException("credentials");
+ }
+
+ [Fact]
+ public void Should_Set_Collection_Url()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.NewGuid();
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials);
+
+ // Then
+ result.CollectionUrl.ShouldBe(collectionUrl);
+ }
+
+ [Fact]
+ public void Should_Set_ProjectGuid()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.NewGuid();
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials);
+
+ // Then
+ result.ProjectGuid.ShouldBe(projectGuid);
+ }
+
+ [Fact]
+ public void Should_Set_Credentials()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.NewGuid();
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials);
+
+ // Then
+ result.Credentials.ShouldBe(credentials);
+ }
+ }
+
+ public sealed class TheCtorForProjectName
+ {
+ [Fact]
+ public void Should_Throw_If_CollectionUrl_Is_Null()
+ {
+ // Given
+ Uri collectionUrl = null;
+ var projectName = "MyProject";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials));
+
+ // Then
+ result.IsArgumentNullException("collectionUrl");
+ }
+
+ [Fact]
+ public void Should_Throw_If_ProjectName_Is_Null()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ string projectName = null;
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials));
+
+ // Then
+ result.IsArgumentNullException("projectName");
+ }
+
+ [Fact]
+ public void Should_Throw_If_ProjectName_Is_Empty()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = string.Empty;
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials));
+
+ // Then
+ result.IsArgumentOutOfRangeException("projectName");
+ }
+
+ [Fact]
+ public void Should_Throw_If_ProjectName_Is_WhiteSpace()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = " ";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials));
+
+ // Then
+ result.IsArgumentOutOfRangeException("projectName");
+ }
+
+ [Fact]
+ public void Should_Throw_If_Credentials_Are_Null()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = "MyProject";
+ IAzureDevOpsCredentials credentials = null;
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials));
+
+ // Then
+ result.IsArgumentNullException("credentials");
+ }
+
+ [Fact]
+ public void Should_Set_Collection_Url()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = "MyProject";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials);
+
+ // Then
+ result.CollectionUrl.ShouldBe(collectionUrl);
+ }
+
+ [Fact]
+ public void Should_Set_ProjectName()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = "MyProject";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials);
+
+ // Then
+ result.ProjectName.ShouldBe(projectName);
+ }
+
+ [Fact]
+ public void Should_Set_Credentials()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = "MyProject";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials);
+
+ // Then
+ result.Credentials.ShouldBe(credentials);
+ }
+ }
+
+ public sealed class TheCtorForSettings
+ {
+ [Fact]
+ public void Should_Throw_If_Settings_Are_Null()
+ {
+ // Given
+ AzureDevOpsWorkItemTrackingSettings settings = null;
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(settings));
+
+ // Then
+ result.IsArgumentNullException("settings");
+ }
+
+ [Fact]
+ public void Should_Set_Collection_Url()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.NewGuid();
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+ var settings = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials);
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(settings);
+
+ // Then
+ result.CollectionUrl.ShouldBe(collectionUrl);
+ }
+
+ [Fact]
+ public void Should_Set_ProjectGuid()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectGuid = Guid.NewGuid();
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+ var settings = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectGuid, credentials);
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(settings);
+
+ // Then
+ result.ProjectGuid.ShouldBe(projectGuid);
+ }
+
+ [Fact]
+ public void Should_Set_ProjectName()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = "MyProject";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+ var settings = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials);
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(settings);
+
+ // Then
+ result.ProjectName.ShouldBe(projectName);
+ }
+
+ [Fact]
+ public void Should_Set_Credentials()
+ {
+ // Given
+ var collectionUrl = new Uri("http://example.com/collection");
+ var projectName = "MyProject";
+ var credentials = AuthenticationProvider.AuthenticationNtlm();
+ var settings = new AzureDevOpsWorkItemTrackingSettings(collectionUrl, projectName, credentials);
+
+ // When
+ var result = new AzureDevOpsWorkItemTrackingSettings(settings);
+
+ // Then
+ result.Credentials.ShouldBe(credentials);
+ }
+ }
+
+ public sealed class TheCtorForEnvironmentVariables : IDisposable
+ {
+ private readonly string originalCollectionUrl;
+ private readonly string originalProjectName;
+
+ public TheCtorForEnvironmentVariables()
+ {
+ this.originalCollectionUrl = Environment.GetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI");
+ this.originalProjectName = Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECT");
+ }
+
+ [Fact]
+ public void Should_Throw_If_Credentials_Are_Null()
+ {
+ // Given
+ IAzureDevOpsCredentials creds = null;
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsArgumentNullException("credentials");
+ }
+
+ [Fact]
+ public void Should_Throw_If_Collection_Url_Env_Var_Is_Not_Set()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", null);
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Collection_Url_Env_Var_Is_Empty()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", string.Empty);
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Collection_Url_Env_Var_Is_WhiteSpace()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", " ");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Project_Name_Env_Var_Is_Not_Set()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", null);
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Project_Name_Env_Var_Is_Empty()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", string.Empty);
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Project_Name_Env_Var_Is_WhiteSpace()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", " ");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Set_Collection_Url()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+
+ // When
+ var settings = new AzureDevOpsWorkItemTrackingSettings(creds);
+
+ // Then
+ settings.CollectionUrl.ToString().ShouldBe(new Uri("https://example.com/collection").ToString());
+ }
+
+ [Fact]
+ public void Should_Set_Project_Name()
+ {
+ // Given
+ var projectName = "MyProject";
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", projectName);
+
+ // When
+ var settings = new AzureDevOpsWorkItemTrackingSettings(creds);
+
+ // Then
+ settings.ProjectName.ShouldBe(projectName);
+ }
+
+ [Fact]
+ public void Should_Set_Credentials()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+
+ // When
+ var settings = new AzureDevOpsWorkItemTrackingSettings(creds);
+
+ // Then
+ settings.Credentials.ShouldBe(creds);
+ }
+
+ public void Dispose()
+ {
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", this.originalCollectionUrl);
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", this.originalProjectName);
+ }
+ }
+
+ public sealed class TheUsingAzurePipelinesOAuthTokenMethod : IDisposable
+ {
+ private readonly string originalCollectionUrl;
+ private readonly string originalProjectName;
+ private readonly string originalAccessToken;
+
+ public TheUsingAzurePipelinesOAuthTokenMethod()
+ {
+ this.originalCollectionUrl = Environment.GetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI");
+ this.originalProjectName = Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECT");
+ this.originalAccessToken = Environment.GetEnvironmentVariable("SYSTEM_ACCESSTOKEN");
+ }
+
+ [Fact]
+ public void Should_Throw_If_Collection_Url_Env_Var_Is_Not_Set()
+ {
+ // Given
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", null);
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var result = Record.Exception(() => AzureDevOpsWorkItemTrackingSettings.UsingAzurePipelinesOAuthToken());
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Collection_Url_Env_Var_Is_Empty()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", string.Empty);
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Collection_Url_Env_Var_Is_WhiteSpace()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", " ");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Project_Name_Env_Var_Is_Not_Set()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", null);
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Project_Name_Env_Var_Is_Empty()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", string.Empty);
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_Project_Name_Env_Var_Is_WhiteSpace()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", " ");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var result = Record.Exception(() => new AzureDevOpsWorkItemTrackingSettings(creds));
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_System_Access_Token_Env_Var_Is_Not_Set_With_OAuthToken()
+ {
+ // Given
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", null);
+
+ // When
+ var result = Record.Exception(() => AzureDevOpsWorkItemTrackingSettings.UsingAzurePipelinesOAuthToken());
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_System_Access_Token_Env_Var_Is_Empty_With_OAuthToken()
+ {
+ // Given
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", string.Empty);
+
+ // When
+ var result = Record.Exception(() => AzureDevOpsWorkItemTrackingSettings.UsingAzurePipelinesOAuthToken());
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Throw_If_System_Access_Token_Env_Var_Is_WhiteSpace_With_OAuthToken()
+ {
+ // Given
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", " ");
+
+ // When
+ var result = Record.Exception(() => AzureDevOpsWorkItemTrackingSettings.UsingAzurePipelinesOAuthToken());
+
+ // Then
+ result.IsInvalidOperationException();
+ }
+
+ [Fact]
+ public void Should_Set_Collection_Url()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var settings = new AzureDevOpsWorkItemTrackingSettings(creds);
+
+ // Then
+ settings.CollectionUrl.ToString().ShouldBe(new Uri("https://example.com/collection").ToString());
+ }
+
+ [Fact]
+ public void Should_Set_Project_Name()
+ {
+ // Given
+ var projectName = "MyProject";
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", projectName);
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var settings = new AzureDevOpsWorkItemTrackingSettings(creds);
+
+ // Then
+ settings.ProjectName.ShouldBe(projectName);
+ }
+
+ [Fact]
+ public void Should_Set_Credentials()
+ {
+ // Given
+ var creds = new AzureDevOpsNtlmCredentials();
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", "https://example.com/collection");
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", "MyProject");
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", "foo");
+
+ // When
+ var settings = new AzureDevOpsWorkItemTrackingSettings(creds);
+
+ // Then
+ settings.Credentials.ShouldBe(creds);
+ }
+
+ public void Dispose()
+ {
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMFOUNDATIONCOLLECTIONURI", this.originalCollectionUrl);
+ Environment.SetEnvironmentVariable("SYSTEM_TEAMPROJECT", this.originalProjectName);
+ Environment.SetEnvironmentVariable("SYSTEM_ACCESSTOKEN", this.originalAccessToken);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cake.AzureDevOps/AzureDevOpsAliases.WorkItemTracking.cs b/src/Cake.AzureDevOps/AzureDevOpsAliases.WorkItemTracking.cs
index a00367ea..728e30f3 100644
--- a/src/Cake.AzureDevOps/AzureDevOpsAliases.WorkItemTracking.cs
+++ b/src/Cake.AzureDevOps/AzureDevOpsAliases.WorkItemTracking.cs
@@ -61,7 +61,7 @@ public static AzureDevOpsWorkItem AzureDevOpsWorkItem(
/// Make sure the build has the 'Allow Scripts to access OAuth token' option enabled.
///
/// The context.
- /// ID of the work witem.
+ /// ID of the work item.
///
/// Get an Azure DevOps work item:
///
@@ -129,5 +129,68 @@ public static AzureDevOpsWorkItem AzureDevOpsWorkItemUsingAzurePipelinesOAuthTok
return AzureDevOpsWorkItem(context, settings);
}
+
+ ///
+ /// Gets an Azure DevOps work item tracking using the specified settings.
+ ///
+ /// The context.
+ /// Settings for getting the work item tracking.
+ ///
+ /// Get a work item from Azure DevOps Server:
+ ///
+ ///
+ ///
+ ///
+ /// Description of the work item tracking.
+ [CakeMethodAlias]
+ [CakeAliasCategory("Azure Boards")]
+ [CakeNamespaceImport("Cake.AzureDevOps.Boards.WorkItemTracking")]
+ public static AzureDevOpsWorkItemTracking AzureDevOpsWorkItemTracking(
+ this ICakeContext context,
+ AzureDevOpsWorkItemTrackingSettings settings)
+ {
+ context.NotNull(nameof(context));
+ settings.NotNull(nameof(settings));
+
+ return new AzureDevOpsWorkItemTracking(context.Log, settings, new WorkItemTrackingClientFactory());
+ }
+
+ ///
+ /// Gets the description of a specific work item tracking the access token provided by Azure Pipelines.
+ /// Make sure the build has the 'Allow Scripts to access OAuth token' option enabled.
+ ///
+ /// The context.
+ ///
+ /// Get an Azure DevOps work item tracking:
+ ///
+ ///
+ ///
+ ///
+ /// Description of the work item tracking.
+ [CakeMethodAlias]
+ [CakeAliasCategory("Azure Boards")]
+ [CakeNamespaceImport("Cake.AzureDevOps.Boards.WorkItemTracking")]
+ public static AzureDevOpsWorkItemTracking AzureDevOpsWorkItemTrackingUsingAzurePipelinesOAuthToken(
+ this ICakeContext context)
+ {
+ context.NotNull(nameof(context));
+
+ var settings = AzureDevOpsWorkItemTrackingSettings.UsingAzurePipelinesOAuthToken();
+
+ return AzureDevOpsWorkItemTracking(context, settings);
+ }
}
}
\ No newline at end of file
diff --git a/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItem.cs b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItem.cs
index 219e061c..66bbda34 100644
--- a/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItem.cs
+++ b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItem.cs
@@ -2,8 +2,6 @@
{
using System;
using System.Collections.Generic;
- using System.Linq;
- using Cake.AzureDevOps.Authentication;
using Cake.Core.Diagnostics;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
@@ -36,15 +34,17 @@ public AzureDevOpsWorkItem(ICakeLog log, AzureDevOpsWorkItemSettings settings)
/// The Cake log context.
/// Settings for accessing AzureDevOps.
/// The work item.
- internal AzureDevOpsWorkItem(ICakeLog log, AzureDevOpsWorkItemSettings settings, WorkItem workItem)
+ /// A factory to communicate with work item tracking client.
+ internal AzureDevOpsWorkItem(ICakeLog log, AzureDevOpsWorkItemSettings settings, WorkItem workItem, IWorkItemTrackingClientFactory workItemTrackingClientFactory)
{
log.NotNull(nameof(log));
settings.NotNull(nameof(settings));
workItem.NotNull(nameof(workItem));
+ workItemTrackingClientFactory.NotNull(nameof(workItemTrackingClientFactory));
this.log = log;
this.workItem = workItem;
- this.workItemTrackingClientFactory = new WorkItemTrackingClientFactory();
+ this.workItemTrackingClientFactory = workItemTrackingClientFactory;
this.settings = settings;
}
@@ -137,11 +137,6 @@ internal AzureDevOpsWorkItem(
///
public bool HasWorkItemLoaded => this.workItem != null;
- ///
- /// Gets the URL for accessing the web portal of the Azure DevOps collection.
- ///
- public Uri CollectionUrl => this.settings.CollectionUrl;
-
///
/// Gets the ID of the work item.
/// Returns 0 if no work item could be found and
diff --git a/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemSettings.cs b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemSettings.cs
index dd835a9e..c3d1e665 100644
--- a/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemSettings.cs
+++ b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemSettings.cs
@@ -81,6 +81,16 @@ public AzureDevOpsWorkItemSettings(int workItemId, IAzureDevOpsCredentials crede
this.WorkItemId = workItemId;
}
+ ///
+ /// Initializes a new instance of the class
+ /// based on the instance of a class.
+ ///
+ /// Settings containing the parameters.
+ public AzureDevOpsWorkItemSettings(AzureDevOpsWorkItemTrackingSettings settings)
+ : base(settings)
+ {
+ }
+
///
/// Gets the ID of the work item.
///
diff --git a/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemTracking.cs b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemTracking.cs
new file mode 100644
index 00000000..5ca0f856
--- /dev/null
+++ b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemTracking.cs
@@ -0,0 +1,85 @@
+namespace Cake.AzureDevOps.Boards.WorkItemTracking
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using Cake.Core.Diagnostics;
+
+ ///
+ /// Class to work with work item tracking.
+ ///
+ public sealed class AzureDevOpsWorkItemTracking
+ {
+ private readonly ICakeLog log;
+ private readonly AzureDevOpsWorkItemTrackingSettings settings;
+ private readonly IWorkItemTrackingClientFactory workItemTrackingClientFactory;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Cake log context.
+ /// Settings for accessing AzureDevOps.
+ public AzureDevOpsWorkItemTracking(ICakeLog log, AzureDevOpsWorkItemTrackingSettings settings)
+ : this(log, settings, new WorkItemTrackingClientFactory())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Cake log context.
+ /// Settings for accessing AzureDevOps.
+ /// A factory to communicate with work item tracking client.
+ internal AzureDevOpsWorkItemTracking(
+ ICakeLog log,
+ AzureDevOpsWorkItemTrackingSettings settings,
+ IWorkItemTrackingClientFactory workItemTrackingClientFactory)
+ {
+ log.NotNull(nameof(log));
+ settings.NotNull(nameof(settings));
+ workItemTrackingClientFactory.NotNull(nameof(workItemTrackingClientFactory));
+
+ this.log = log;
+ this.workItemTrackingClientFactory = workItemTrackingClientFactory;
+ this.settings = settings;
+ }
+
+ ///
+ /// Gets the specified work items (Maximum 200).
+ ///
+ /// List of work item ids.
+ /// The work items defined by the ids.
+ public IEnumerable GetWorkItems(IEnumerable workItemIds)
+ {
+ using (var workItemTrackingClient = this.workItemTrackingClientFactory.CreateWorkItemTrackingClient(this.settings.CollectionUrl, this.settings.Credentials))
+ {
+ return
+ workItemTrackingClient
+ .GetWorkItemsAsync(workItemIds, expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations)
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult()
+ .Select(x => new AzureDevOpsWorkItem(this.log, new AzureDevOpsWorkItemSettings(this.settings), x, this.workItemTrackingClientFactory));
+ }
+ }
+
+ ///
+ /// Gets the specified work item.
+ ///
+ /// The ID of the work item.
+ /// The work item specified by the ID.
+ public AzureDevOpsWorkItem GetWorkItem(int workItemId)
+ {
+ using (var workItemTrackingClient = this.workItemTrackingClientFactory.CreateWorkItemTrackingClient(this.settings.CollectionUrl, this.settings.Credentials))
+ {
+ var workItem =
+ workItemTrackingClient
+ .GetWorkItemAsync(workItemId, expand: Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItemExpand.Relations)
+ .ConfigureAwait(false)
+ .GetAwaiter()
+ .GetResult();
+
+ return new AzureDevOpsWorkItem(this.log, new AzureDevOpsWorkItemSettings(this.settings), workItem, this.workItemTrackingClientFactory);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemTrackingSettings.cs b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemTrackingSettings.cs
new file mode 100644
index 00000000..9037e146
--- /dev/null
+++ b/src/Cake.AzureDevOps/Boards/WorkItemTracking/AzureDevOpsWorkItemTrackingSettings.cs
@@ -0,0 +1,65 @@
+namespace Cake.AzureDevOps.Boards.WorkItemTracking
+{
+ using System;
+ using Cake.AzureDevOps.Authentication;
+
+ ///
+ /// Settings for aliases handling for workitem tracking.
+ ///
+ public class AzureDevOpsWorkItemTrackingSettings : BaseAzureDevOpsProjectSettings
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Full URL of the Azure DevOps collection,
+ /// eg. http://myserver:8080/defaultcollection
.
+ /// ID of the project.
+ /// Credentials to use to authenticate against Azure DevOps.
+ public AzureDevOpsWorkItemTrackingSettings(Uri collectionUrl, Guid projectGuid, IAzureDevOpsCredentials credentials)
+ : base(collectionUrl, projectGuid, credentials)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Full URL of the Azure DevOps collection,
+ /// eg. http://myserver:8080/defaultcollection
.
+ /// Name of the project.
+ /// Credentials to use to authenticate against Azure DevOps.
+ public AzureDevOpsWorkItemTrackingSettings(Uri collectionUrl, string projectName, IAzureDevOpsCredentials credentials)
+ : base(collectionUrl, projectName, credentials)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ /// based on the instance of a class.
+ ///
+ /// Settings containing the parameters.
+ public AzureDevOpsWorkItemTrackingSettings(AzureDevOpsWorkItemTrackingSettings settings)
+ : base(settings)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class using environment variables
+ /// as set by an Azure Pipelines build.
+ ///
+ /// Credentials to use to authenticate against Azure DevOps.
+ public AzureDevOpsWorkItemTrackingSettings(IAzureDevOpsCredentials credentials)
+ : base(credentials)
+ {
+ }
+
+ ///
+ /// Constructs the settings object for a specific work item using the access token provided by Azure Pipelines.
+ ///
+ /// The instance of class.
+ public static AzureDevOpsWorkItemTrackingSettings UsingAzurePipelinesOAuthToken()
+ {
+ var accessToken = EnvironmentVariableHelper.GetSystemAccessToken();
+ return new AzureDevOpsWorkItemTrackingSettings(new AzureDevOpsOAuthCredentials(accessToken));
+ }
+ }
+}