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)); + } + } +}