Skip to content

Commit

Permalink
Add TransitionIssue method to ISonarQubeService (#5037)
Browse files Browse the repository at this point in the history
Fixes #5022
  • Loading branch information
georgii-borovinskikh-sonarsource authored Nov 23, 2023
1 parent f4c4957 commit b9f0674
Show file tree
Hide file tree
Showing 12 changed files with 520 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SonarQube.Client.Helpers;
using SonarQube.Client.Models;

namespace SonarQube.Client.Tests.Helpers;

[TestClass]
public class SonarQubeIssueTransitionExtensionsTests
{
[DataTestMethod]
[DataRow(SonarQubeIssueTransition.FalsePositive, "falsepositive")]
[DataRow(SonarQubeIssueTransition.WontFix, "wontfix")]
[DataRow(SonarQubeIssueTransition.Accept, "accept")]
public void TransitionToLowerCaseString_ConvertsEnumToLowerCaseString(SonarQubeIssueTransition transition, string expectedString)
{
transition.TransitionToLowerCaseString().Should().Be(expectedString);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ public void ConfigureSonarQube_Writes_Debug_Messages()
"Registered SonarQube.Client.Api.V10_2.SearchHotspotRequest for 10.2",
"Registered SonarQube.Client.Api.V10_2.GetTaintVulnerabilitiesWithCCTRequest for 10.2",
"Registered SonarQube.Client.Api.V10_2.GetRulesWithCCTRequest for 10.2",
"Registered SonarQube.Client.Api.V9_9.TransitionIssueRequestWithWontFix for 9.9",
"Registered SonarQube.Client.Api.V10_4.TransitionIssueRequestWithAccept for 10.4",
"Registered SonarQube.Client.Api.V9_9.CommentIssueRequest for 9.9"
};

DefaultConfiguration.ConfigureSonarQube(new RequestFactory(logger));
Expand Down Expand Up @@ -111,7 +114,9 @@ public void ConfigureSonarCloud_Writes_Debug_Messages()
"Registered SonarQube.Client.Api.V8_6.GetHotspotRequest",
"Registered SonarQube.Client.Api.V10_2.GetTaintVulnerabilitiesWithCCTRequest",
"Registered SonarQube.Client.Api.V7_20.GetExclusionsRequest",
"Registered SonarQube.Client.Api.V9_7.SearchHotspotRequest"
"Registered SonarQube.Client.Api.V9_7.SearchHotspotRequest",
"Registered SonarQube.Client.Api.V10_4.TransitionIssueRequestWithAccept",
"Registered SonarQube.Client.Api.V9_9.CommentIssueRequest"
};

DefaultConfiguration.ConfigureSonarCloud(new UnversionedRequestFactory(logger));
Expand Down Expand Up @@ -149,6 +154,8 @@ public void ConfigureSonarQube_CheckAllRequestsImplemented()
testSubject.Create<IGetProjectBranchesRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<IGetExclusionsRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<IGetSonarLintEventStream>(serverInfo).Should().NotBeNull();
testSubject.Create<ITransitionIssueRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<ICommentIssueRequest>(serverInfo).Should().NotBeNull();
}

[TestMethod]
Expand Down Expand Up @@ -177,6 +184,8 @@ public void ConfigureSonarCloud_CheckAllRequestsImplemented()
testSubject.Create<IGetSourceCodeRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<IGetProjectBranchesRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<IGetExclusionsRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<ITransitionIssueRequest>(serverInfo).Should().NotBeNull();
testSubject.Create<ICommentIssueRequest>(serverInfo).Should().NotBeNull();
}

[TestMethod]
Expand Down
157 changes: 157 additions & 0 deletions src/SonarQube.Client.Tests/SonarQubeService_TransitionIssueAsync.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SonarQube.Client.Helpers;
using SonarQube.Client.Models;

namespace SonarQube.Client.Tests;

[TestClass]
public class SonarQubeService_TransitionIssueAsync : SonarQubeService_TestBase
{
[TestMethod]
public async Task TransitionIssue_FailedToTransition()
{
const string issueKey = "AW9mgJw6eFC3pGl94Wrf";
var transition = SonarQubeIssueTransition.FalsePositive;

await ConnectToSonarQube("10.4.0.0");

SetupRequest($"api/issues/do_transition?issue={issueKey}&transition={transition.TransitionToLowerCaseString()}",
"ignored",
HttpStatusCode.BadGateway);

var result = await service.TransitionIssueAsync(issueKey, SonarQubeIssueTransition.FalsePositive, "some text", CancellationToken.None);

result.Should().Be(SonarQubeIssueTransitionResult.FailedToTransition);
messageHandler.VerifyAll();
logger.ErrorMessages.Should().Contain("POST api/issues/do_transition request failed.");
logger.DebugMessages.Should().HaveCountGreaterThan(0);
}

[TestMethod]
public async Task TransitionIssue_InsufficientPermissions()
{
const string issueKey = "AW9mgJw6eFC3pGl94Wrf";
var transition = SonarQubeIssueTransition.FalsePositive;

await ConnectToSonarQube("10.4.0.0");

SetupRequest($"api/issues/do_transition?issue={issueKey}&transition={transition.TransitionToLowerCaseString()}",
"ignored",
HttpStatusCode.Forbidden);

var result = await service.TransitionIssueAsync(issueKey, SonarQubeIssueTransition.FalsePositive, "some text", CancellationToken.None);

result.Should().Be(SonarQubeIssueTransitionResult.InsufficientPermissions);
messageHandler.VerifyAll();
logger.WarningMessages.Should().Contain("Insufficient permission to transition the issue.");
}

[TestMethod]
public async Task TransitionIssue_CommentAdditionFailed()
{
const string issueKey = "AW9mgJw6eFC3pGl94Wrf";
const string optionalComment = "sometext";
var transition = SonarQubeIssueTransition.FalsePositive;

await ConnectToSonarQube("10.4.0.0");

SetupRequest($"api/issues/do_transition?issue={issueKey}&transition={transition.TransitionToLowerCaseString()}",
"ignored");
SetupRequest($"api/issues/add_comment?issue={issueKey}&text={optionalComment}",
"ignored",
HttpStatusCode.BadGateway);

var result = await service.TransitionIssueAsync(issueKey, SonarQubeIssueTransition.FalsePositive, optionalComment, CancellationToken.None);

result.Should().Be(SonarQubeIssueTransitionResult.CommentAdditionFailed);
messageHandler.VerifyAll();
logger.ErrorMessages.Should().Contain("POST api/issues/add_comment request failed.");
logger.DebugMessages.Should().HaveCountGreaterThan(0);
}

[TestMethod]
public async Task TransitionIssue_NoComment_NoServerRequest()
{
const string issueKey = "AW9mgJw6eFC3pGl94Wrf";
const string optionalComment = null;
var transition = SonarQubeIssueTransition.FalsePositive;

await ConnectToSonarQube("10.4.0.0");

SetupRequest($"api/issues/do_transition?issue={issueKey}&transition={transition.TransitionToLowerCaseString()}",
"ignored");

var result = await service.TransitionIssueAsync(issueKey, SonarQubeIssueTransition.FalsePositive, optionalComment, CancellationToken.None);

result.Should().Be(SonarQubeIssueTransitionResult.Success);
messageHandler.VerifyAll();
}

[DataTestMethod]
[DataRow("9.9.0.0", SonarQubeIssueTransition.FalsePositive, SonarQubeIssueTransitionResult.Success)]
[DataRow("10.2.0.0", SonarQubeIssueTransition.FalsePositive, SonarQubeIssueTransitionResult.Success)]
[DataRow("10.4.0.0", SonarQubeIssueTransition.FalsePositive, SonarQubeIssueTransitionResult.Success)]
[DataRow("9.9.0.0", SonarQubeIssueTransition.WontFix, SonarQubeIssueTransitionResult.Success)]
[DataRow("10.3.0.0", SonarQubeIssueTransition.WontFix, SonarQubeIssueTransitionResult.Success)]
[DataRow("10.4.0.0", SonarQubeIssueTransition.WontFix, SonarQubeIssueTransitionResult.FailedToTransition)]
[DataRow("10.6.0.0", SonarQubeIssueTransition.WontFix, SonarQubeIssueTransitionResult.FailedToTransition)]
[DataRow("9.9.0.0", SonarQubeIssueTransition.Accept, SonarQubeIssueTransitionResult.FailedToTransition)]
[DataRow("10.3.0.0", SonarQubeIssueTransition.Accept, SonarQubeIssueTransitionResult.FailedToTransition)]
[DataRow("10.4.0.0", SonarQubeIssueTransition.Accept, SonarQubeIssueTransitionResult.Success)]
[DataRow("10.6.0.0", SonarQubeIssueTransition.Accept, SonarQubeIssueTransitionResult.Success)]
public async Task TransitionIssue_SupportedTransitionsTest(string version, SonarQubeIssueTransition transition, SonarQubeIssueTransitionResult expectedResult)
{
const string issueKey = "AW9mgJw6eFC3pGl94Wrf";
const string optionalComment = "sometext";

await ConnectToSonarQube(version);

SetupRequest($"api/issues/do_transition?issue={issueKey}&transition={transition.TransitionToLowerCaseString()}",
"ignored");
SetupRequest($"api/issues/add_comment?issue={issueKey}&text={optionalComment}",
"ignored");

var result = await service.TransitionIssueAsync(issueKey, transition, optionalComment, CancellationToken.None);

result.Should().Be(expectedResult);
}

[TestMethod]
public void TransitionIssue_NotConnected()
{
// No calls to Connect
// No need to setup request, the operation should fail

Func<Task> action = async () => await service.TransitionIssueAsync("key", SonarQubeIssueTransition.Accept, "text", CancellationToken.None);

action.Should().ThrowExactly<InvalidOperationException>()
.WithMessage("This operation expects the service to be connected.");

logger.ErrorMessages.Should().Contain("The service is expected to be connected.");
}
}
9 changes: 7 additions & 2 deletions src/SonarQube.Client/Api/DefaultConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ public static RequestFactory ConfigureSonarQube(RequestFactory requestFactory)
.RegisterRequest<ISearchHotspotRequest, V9_7.SearchHotspotRequest>("9.7")
.RegisterRequest<ISearchHotspotRequest, V10_2.SearchHotspotRequest>("10.2")
.RegisterRequest<IGetTaintVulnerabilitiesRequest, V10_2.GetTaintVulnerabilitiesWithCCTRequest>("10.2")
.RegisterRequest<IGetRulesRequest, V10_2.GetRulesWithCCTRequest>("10.2");
.RegisterRequest<IGetRulesRequest, V10_2.GetRulesWithCCTRequest>("10.2")
.RegisterRequest<ITransitionIssueRequest, V9_9.TransitionIssueRequestWithWontFix>("9.9")
.RegisterRequest<ITransitionIssueRequest, V10_4.TransitionIssueRequestWithAccept>("10.4")
.RegisterRequest<ICommentIssueRequest, V9_9.CommentIssueRequest>("9.9");

return requestFactory;
}
Expand Down Expand Up @@ -90,7 +93,9 @@ public static UnversionedRequestFactory ConfigureSonarCloud(UnversionedRequestFa
.RegisterRequest<IGetHotspotRequest, V8_6.GetHotspotRequest>()
.RegisterRequest<IGetTaintVulnerabilitiesRequest, V10_2.GetTaintVulnerabilitiesWithCCTRequest>()
.RegisterRequest<IGetExclusionsRequest, V7_20.GetExclusionsRequest>()
.RegisterRequest<ISearchHotspotRequest, V9_7.SearchHotspotRequest>();
.RegisterRequest<ISearchHotspotRequest, V9_7.SearchHotspotRequest>()
.RegisterRequest<ITransitionIssueRequest, V10_4.TransitionIssueRequestWithAccept>()
.RegisterRequest<ICommentIssueRequest, V9_9.CommentIssueRequest>();

return requestFactory;
}
Expand Down
30 changes: 30 additions & 0 deletions src/SonarQube.Client/Api/ICommentIssueRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarQube.Client.Requests;

namespace SonarQube.Client.Api
{
public interface ICommentIssueRequest : IRequest<bool>
{
string IssueKey { get; set; }
string Text { get; set; }
}
}
31 changes: 31 additions & 0 deletions src/SonarQube.Client/Api/ITransitionIssueRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using SonarQube.Client.Models;
using SonarQube.Client.Requests;

namespace SonarQube.Client.Api
{
public interface ITransitionIssueRequest : IRequest<SonarQubeIssueTransitionResult>
{
string IssueKey { get; set; }
SonarQubeIssueTransition Transition { get; set; }
}
}
36 changes: 36 additions & 0 deletions src/SonarQube.Client/Api/V10_4/TransitionIssueRequestWithAccept.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* SonarLint for Visual Studio
* Copyright (C) 2016-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

using System.Collections.Generic;
using SonarQube.Client.Api.V9_9;
using SonarQube.Client.Models;

namespace SonarQube.Client.Api.V10_4
{
public class TransitionIssueRequestWithAccept : TransitionIssueRequestWithWontFix
{
protected override List<SonarQubeIssueTransition> SupportedTransitions { get; } =
new List<SonarQubeIssueTransition>
{
SonarQubeIssueTransition.FalsePositive,
SonarQubeIssueTransition.Accept
};
}
}
Loading

0 comments on commit b9f0674

Please sign in to comment.