diff --git a/src/SonarQube.Client.Tests/CallRealServerTestHarness.cs b/src/SonarQube.Client.Tests/CallRealServerTestHarness.cs deleted file mode 100644 index 0640c69b7b..0000000000 --- a/src/SonarQube.Client.Tests/CallRealServerTestHarness.cs +++ /dev/null @@ -1,103 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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.Net.Http; -using System.Security; -using SonarQube.Client.Models; -using SonarQube.Client.Tests.Infra; - -// Dummy tests. These exist to make it easy to make real SonarQube/SonarCloud -// calls during development -// -// Usage: -// * uncomment the [TestClass] attribute -// * if calling SonarCloud, set a valid SonarCloud token - -namespace SonarQube.Client.Tests -{ - //[TestClass] - public class CallRealServerTestHarness - { - [TestMethod] - public async Task Call_Real_SonarQube() - { - var url = new Uri("http://localhost:9000"); - - string userName = "admin"; - var password = new SecureString(); - password.AppendChar('a'); - password.AppendChar('d'); - password.AppendChar('m'); - password.AppendChar('i'); - password.AppendChar('n'); - - var connInfo = new ConnectionInformation(url, MockBasicAuthCredentials(userName, password)); - - var service = new SonarQubeService(new HttpClientHandler(), "agent", new TestLogger()); - try - { - await service.ConnectAsync(connInfo, CancellationToken.None); - - // Example - string fileKey = "junk:MyClass.cs"; - var result = await service.GetSourceCodeAsync(fileKey, CancellationToken.None); - result.Should().NotBeNullOrEmpty(); - } - finally - { - service.Disconnect(); - } - } - - [TestMethod] - public async Task Call_Real_SonarCloud() - { - // TODO: set to a valid SonarCloud token but make sure you don't check it in... - string validSonarCloudToken = "DO NOT CHECK IN A REAL TOKEN"; - - var url = ConnectionInformation.FixedSonarCloudUri; - var password = new SecureString(); - var connInfo = new ConnectionInformation(url, MockBasicAuthCredentials(validSonarCloudToken, password)); - - var service = new SonarQubeService(new HttpClientHandler(), "agent", new TestLogger()); - try - { - await service.ConnectAsync(connInfo, CancellationToken.None); - - // Example - var fileKey = "vuln:Tools/Orchard/Logger.cs"; - var result = await service.GetSourceCodeAsync(fileKey, CancellationToken.None); - result.Should().NotBeNullOrEmpty(); - } - finally - { - service.Disconnect(); - } - } - - private static IUsernameAndPasswordCredentials MockBasicAuthCredentials(string userName, SecureString password) - { - var mock = Substitute.For(); - mock.UserName.Returns(userName); - mock.Password.Returns(password); - return mock; - } - } -} diff --git a/src/SonarQube.Client.Tests/Helpers/SecondaryLocationHashUpdaterTests.cs b/src/SonarQube.Client.Tests/Helpers/SecondaryLocationHashUpdaterTests.cs deleted file mode 100644 index 896619f73d..0000000000 --- a/src/SonarQube.Client.Tests/Helpers/SecondaryLocationHashUpdaterTests.cs +++ /dev/null @@ -1,168 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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.Linq; -using System.Threading; -using System.Threading.Tasks; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using SonarQube.Client.Models; - -namespace SonarQube.Client.Helpers.Tests -{ - [TestClass] - public class SecondaryLocationHashUpdaterTests - { - private const string PrimaryIssueHash = "the primary issue hash should not be affected"; - - [TestMethod] - public async Task Populate_NoIssues_NoOp() - { - var serviceMock = new Mock(); - - var testSubject = new SecondaryLocationHashUpdater(); - await testSubject.UpdateHashesAsync(Array.Empty(), serviceMock.Object, CancellationToken.None); - - serviceMock.Invocations.Count.Should().Be(0); - } - - [TestMethod] - public async Task Populate_NoSecondaryLocations_NoOp() - { - var serviceMock = new Mock(); - var issues = new[] - { - CreateIssue("project1:key1", AddFlow()), - CreateIssue("project2:key2" /* no flows */) - }; - - var testSubject = new SecondaryLocationHashUpdater(); - await testSubject.UpdateHashesAsync(issues, serviceMock.Object, CancellationToken.None); - - serviceMock.Invocations.Count.Should().Be(0); - } - - [TestMethod] - public async Task Populate_HasSecondaryLocations_UniqueModulesFetched() - { - var issues = new[] - { - CreateIssue("primary_only_should_not_be_fetched_1", - AddFlow( - CreateLocation("duplicate"), - CreateLocation("duplicate"), - CreateLocation("unique1"), - CreateLocation("unique2") - )), - CreateIssue("unique2", - AddFlow( - CreateLocation("unique3") - )), - CreateIssue("primary_only_should_not_be_fetched_2", - AddFlow( - CreateLocation("unique4") - )) - }; - - // Only expecting the unique set of secondary locations to be requested - var serviceMock = new Mock(); - AddSourceFile(serviceMock, "duplicate"); - AddSourceFile(serviceMock, "unique1"); - AddSourceFile(serviceMock, "unique2"); - AddSourceFile(serviceMock, "unique3"); - AddSourceFile(serviceMock, "unique4"); - - var testSubject = new SecondaryLocationHashUpdater(); - await testSubject.UpdateHashesAsync(issues, serviceMock.Object, CancellationToken.None); - - serviceMock.VerifyAll(); - serviceMock.VerifyNoOtherCalls(); - } - - [TestMethod] - public async Task Populate_HasSecondaryLocations_ExpectedHashesSet() - { - const string line1Contents = "line one contents"; - const string line2Contents = " line two XXX "; - const string line3Contents = " LINE THREE!\"£$% "; - - var file1Contents = $"{line1Contents}\n{line2Contents}\nfoo foo foo"; - - var file2Contents = $"111\n222\n{line3Contents}"; - - var calcMock = new Mock(); - SetupHash(calcMock, line1Contents, "expected line 1 hash"); - SetupHash(calcMock, line2Contents, "expected line 2 hash"); - SetupHash(calcMock, line3Contents, "expected line 3 hash"); - - var issues = new[] - { - CreateIssue("primary_only_should_not_be_fetched_1", - AddFlow( - CreateLocation("file1", startLine: 1), - CreateLocation("file1", startLine: 2) - )), - CreateIssue("primary_only_should_not_be_fetched_2", - AddFlow( - CreateLocation("file2", startLine: 4), // beyond the end of the file -> should be ignored - CreateLocation("file2", startLine: 3) - )) - }; - - var serviceMock = new Mock(); - AddSourceFile(serviceMock, "file1", file1Contents); - AddSourceFile(serviceMock, "file2", file2Contents); - - var testSubject = new SecondaryLocationHashUpdater(calcMock.Object); - - // Act - await testSubject.UpdateHashesAsync(issues, serviceMock.Object, CancellationToken.None); - - issues[0].Hash.Should().Be(PrimaryIssueHash); - issues[1].Hash.Should().Be(PrimaryIssueHash); - - issues[0].Flows[0].Locations[0].Hash.Should().Be("expected line 1 hash"); - issues[0].Flows[0].Locations[1].Hash.Should().Be("expected line 2 hash"); - - issues[1].Flows[0].Locations[0].Hash.Should().Be(null); - issues[1].Flows[0].Locations[1].Hash.Should().Be("expected line 3 hash"); - } - - private static SonarQubeIssue CreateIssue(string moduleKey, params IssueFlow[] flows) => - new SonarQubeIssue("any", "any", PrimaryIssueHash, "any", moduleKey, "any", true, - SonarQubeIssueSeverity.Blocker, DateTimeOffset.Now, DateTimeOffset.Now, null, flows.ToList()); - - private static IssueFlow AddFlow(params IssueLocation[] locations) => - new IssueFlow(locations.ToList()); - - private static IssueLocation CreateLocation(string moduleKey, int startLine = 1) => - new IssueLocation("any", moduleKey, - new IssueTextRange(startLine, int.MaxValue, int.MaxValue, int.MaxValue), - "any"); - - private static void AddSourceFile(Mock serviceMock, string moduleKey, string data = "") => - serviceMock.Setup(x => x.GetSourceCodeAsync(moduleKey, It.IsAny())).Returns(Task.FromResult(data)); - - private static void SetupHash(Mock calcMock, string input, string hashToReturn) => - calcMock.Setup(x => x.Calculate(input)).Returns(hashToReturn); - } -} diff --git a/src/SonarQube.Client.Tests/Requests/DefaultConfiguration_Configure_Tests.cs b/src/SonarQube.Client.Tests/Requests/DefaultConfiguration_Configure_Tests.cs index 90162354a9..82917e1f80 100644 --- a/src/SonarQube.Client.Tests/Requests/DefaultConfiguration_Configure_Tests.cs +++ b/src/SonarQube.Client.Tests/Requests/DefaultConfiguration_Configure_Tests.cs @@ -39,7 +39,6 @@ public void ConfigureSonarQube_Writes_Debug_Messages() "Registered SonarQube.Client.Api.V2_10.GetVersionRequest for 2.1", "Registered SonarQube.Client.Api.V2_60.GetPropertiesRequest for 2.6", "Registered SonarQube.Client.Api.V3_30.ValidateCredentialsRequest for 3.3", - "Registered SonarQube.Client.Api.V5_00.GetSourceCodeRequest for 5.0", "Registered SonarQube.Client.Api.V5_10.GetIssuesRequest for 5.1", "Registered SonarQube.Client.Api.V5_10.GetLanguagesRequest for 5.1", "Registered SonarQube.Client.Api.V5_20.GetQualityProfileChangeLogRequest for 5.2", @@ -88,7 +87,6 @@ public void ConfigureSonarCloud_Writes_Debug_Messages() { "Registered SonarQube.Client.Api.V2_10.GetVersionRequest", "Registered SonarQube.Client.Api.V3_30.ValidateCredentialsRequest", - "Registered SonarQube.Client.Api.V5_00.GetSourceCodeRequest", "Registered SonarQube.Client.Api.V5_10.GetLanguagesRequest", "Registered SonarQube.Client.Api.V5_40.GetModulesRequest", "Registered SonarQube.Client.Api.V10_2.GetRulesWithCCTRequest", @@ -141,7 +139,6 @@ public void ConfigureSonarQube_CheckAllRequestsImplemented() testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); - testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); @@ -172,7 +169,6 @@ public void ConfigureSonarCloud_CheckAllRequestsImplemented() testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); - testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); testSubject.Create(serverInfo).Should().NotBeNull(); diff --git a/src/SonarQube.Client.Tests/SonarQubeService_GetProjectDashboardUrl_Disconnect.cs b/src/SonarQube.Client.Tests/SonarQubeService_GetProjectDashboardUrl_Disconnect.cs index 3f22f78640..63e9130415 100644 --- a/src/SonarQube.Client.Tests/SonarQubeService_GetProjectDashboardUrl_Disconnect.cs +++ b/src/SonarQube.Client.Tests/SonarQubeService_GetProjectDashboardUrl_Disconnect.cs @@ -46,13 +46,13 @@ public async Task GetProjectDashboardUrl_DisconnectedInTheMiddle_NoException() protected internal override SonarQubeService CreateTestSubject() { - return new DisconnectingService(messageHandler.Object, UserAgent, logger, requestFactorySelector, secondaryIssueHashUpdater.Object); + return new DisconnectingService(messageHandler.Object, UserAgent, logger, requestFactorySelector); } internal class DisconnectingService : SonarQubeService { - internal DisconnectingService(HttpMessageHandler messageHandler, string userAgent, ILogger logger, IRequestFactorySelector requestFactorySelector, ISecondaryIssueHashUpdater secondaryIssueHashUpdater) - : base(messageHandler, userAgent, logger, requestFactorySelector, secondaryIssueHashUpdater, null) + internal DisconnectingService(HttpMessageHandler messageHandler, string userAgent, ILogger logger, IRequestFactorySelector requestFactorySelector) + : base(messageHandler, userAgent, logger, requestFactorySelector, null) { } diff --git a/src/SonarQube.Client.Tests/SonarQubeService_GetSourceCodeAsync.cs b/src/SonarQube.Client.Tests/SonarQubeService_GetSourceCodeAsync.cs deleted file mode 100644 index 37d56546f8..0000000000 --- a/src/SonarQube.Client.Tests/SonarQubeService_GetSourceCodeAsync.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace SonarQube.Client.Tests -{ - [TestClass] - public class SonarQubeService_GetSourceCodeAsync : SonarQubeService_TestBase - { - [TestMethod] - public async Task Get_V5_0_ExampleFromSonarQube() - { - await ConnectToSonarQube("5.0.0.0"); - - const string sourceCode = @"a -b - -ccc"; - - SetupRequest("api/sources/raw?key=my_project%3Asrc%2Ffoo%2FBar.php", - sourceCode); - - var result = await service.GetSourceCodeAsync("my_project:src/foo/Bar.php", CancellationToken.None); - - messageHandler.VerifyAll(); - - result.Should().Be(sourceCode); - } - - [TestMethod] - public async Task Get_NotFound() - { - await ConnectToSonarQube(); - - SetupRequest("api/sources/raw?key=missing", "", HttpStatusCode.NotFound); - - Func> func = async () => - await service.GetSourceCodeAsync("missing", CancellationToken.None); - - func.Should().ThrowExactly().And - .Message.Should().Be("Response status code does not indicate success: 404 (Not Found)."); - - messageHandler.VerifyAll(); - } - - [TestMethod] - public void Get_NotConnected() - { - // No calls to Connect - // No need to setup request, the operation should fail - - Func> func = async () => - await service.GetSourceCodeAsync("any", CancellationToken.None); - - func.Should().ThrowExactly().And - .Message.Should().Be("This operation expects the service to be connected."); - - logger.ErrorMessages.Should().Contain("The service is expected to be connected."); - } - } -} diff --git a/src/SonarQube.Client.Tests/SonarQubeService_GetViewHotspotUrl_Disconnect.cs b/src/SonarQube.Client.Tests/SonarQubeService_GetViewHotspotUrl_Disconnect.cs index 878aa1ef08..e764657449 100644 --- a/src/SonarQube.Client.Tests/SonarQubeService_GetViewHotspotUrl_Disconnect.cs +++ b/src/SonarQube.Client.Tests/SonarQubeService_GetViewHotspotUrl_Disconnect.cs @@ -46,13 +46,13 @@ public async Task GetViewHotspotUrl_DisconnectedInTheMiddle_NoException() protected internal override SonarQubeService CreateTestSubject() { - return new DisconnectingService(messageHandler.Object, UserAgent, logger, requestFactorySelector, secondaryIssueHashUpdater.Object); + return new DisconnectingService(messageHandler.Object, UserAgent, logger, requestFactorySelector); } internal class DisconnectingService : SonarQubeService { - internal DisconnectingService(HttpMessageHandler messageHandler, string userAgent, ILogger logger, IRequestFactorySelector requestFactorySelector, ISecondaryIssueHashUpdater secondaryIssueHashUpdater) - : base(messageHandler, userAgent, logger, requestFactorySelector, secondaryIssueHashUpdater, null) + internal DisconnectingService(HttpMessageHandler messageHandler, string userAgent, ILogger logger, IRequestFactorySelector requestFactorySelector) + : base(messageHandler, userAgent, logger, requestFactorySelector, null) { } diff --git a/src/SonarQube.Client.Tests/SonarQubeService_Miscellaneous.cs b/src/SonarQube.Client.Tests/SonarQubeService_Miscellaneous.cs index a283d28d96..aa7514c349 100644 --- a/src/SonarQube.Client.Tests/SonarQubeService_Miscellaneous.cs +++ b/src/SonarQube.Client.Tests/SonarQubeService_Miscellaneous.cs @@ -82,7 +82,7 @@ public async Task SonarQubeService_UsesFactorySelector(string serverUrl, bool is var selectorMock = new Mock(); selectorMock.Setup(x => x.Select(isSonarCloud, logger)).Returns(requestFactoryMock.Object); - var testSubject = new SonarQubeService(Mock.Of(), "user-agent", logger, selectorMock.Object, Mock.Of(), null); + var testSubject = new SonarQubeService(Mock.Of(), "user-agent", logger, selectorMock.Object, null); await testSubject.ConnectAsync(connectionInfo, CancellationToken.None); selectorMock.Verify(x => x.Select(isSonarCloud, logger), Times.Once); @@ -109,7 +109,7 @@ public async Task SonarQubeService_FactorySelector_RequestsNewFactoryOnEachConne selectorMock.Setup(x => x.Select(false /* isSonarCloud */, logger)).Returns(qubeFactoryMock.Object); selectorMock.Setup(x => x.Select(true /* isSonarCloud */, logger)).Returns(cloudFactoryMock.Object); - var testSubject = new SonarQubeService(Mock.Of(), "user-agent", logger, selectorMock.Object, Mock.Of(), null); + var testSubject = new SonarQubeService(Mock.Of(), "user-agent", logger, selectorMock.Object, null); // 1. Connect to SonarQube await testSubject.ConnectAsync(sonarQubeConnectionInfo, CancellationToken.None); diff --git a/src/SonarQube.Client.Tests/SonarQubeService_TestBase.cs b/src/SonarQube.Client.Tests/SonarQubeService_TestBase.cs index 9b8034b51f..4cab45566a 100644 --- a/src/SonarQube.Client.Tests/SonarQubeService_TestBase.cs +++ b/src/SonarQube.Client.Tests/SonarQubeService_TestBase.cs @@ -40,7 +40,6 @@ public class SonarQubeService_TestBase protected TestLogger logger; // Note: can't be protected because the interfaces are internal - internal Mock secondaryIssueHashUpdater; internal IRequestFactorySelector requestFactorySelector; internal Mock sseStreamFactory; @@ -60,7 +59,6 @@ public void TestInitialize() messageHandler = new Mock(MockBehavior.Strict); requestFactorySelector = new RequestFactorySelector(); - secondaryIssueHashUpdater = new Mock(); sseStreamFactory = new Mock(); ResetService(); @@ -117,7 +115,7 @@ protected void ResetService() protected internal virtual SonarQubeService CreateTestSubject() { - return new SonarQubeService(messageHandler.Object, UserAgent, logger, requestFactorySelector, secondaryIssueHashUpdater.Object, sseStreamFactory.Object); + return new SonarQubeService(messageHandler.Object, UserAgent, logger, requestFactorySelector, sseStreamFactory.Object); } private static IUsernameAndPasswordCredentials MockBasicAuthCredentials(string userName, SecureString password) diff --git a/src/SonarQube.Client/Api/DefaultConfiguration.cs b/src/SonarQube.Client/Api/DefaultConfiguration.cs index 73af91114f..23d2b602a2 100644 --- a/src/SonarQube.Client/Api/DefaultConfiguration.cs +++ b/src/SonarQube.Client/Api/DefaultConfiguration.cs @@ -32,7 +32,6 @@ public static RequestFactory ConfigureSonarQube(RequestFactory requestFactory) .RegisterRequest("2.1") .RegisterRequest("2.6") .RegisterRequest("3.3") - .RegisterRequest("5.0") .RegisterRequest("5.1") .RegisterRequest("5.1") .RegisterRequest("5.2") @@ -71,7 +70,6 @@ public static UnversionedRequestFactory ConfigureSonarCloud(UnversionedRequestFa requestFactory .RegisterRequest() .RegisterRequest() - .RegisterRequest() .RegisterRequest() .RegisterRequest() .RegisterRequest() diff --git a/src/SonarQube.Client/Api/IGetSourceCodeRequest.cs b/src/SonarQube.Client/Api/IGetSourceCodeRequest.cs deleted file mode 100644 index 8bc826c1ea..0000000000 --- a/src/SonarQube.Client/Api/IGetSourceCodeRequest.cs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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 IGetSourceCodeRequest : IRequest - { - string FileKey { get; set; } - } -} diff --git a/src/SonarQube.Client/Api/V5_00/GetSourceCodeRequest.cs b/src/SonarQube.Client/Api/V5_00/GetSourceCodeRequest.cs deleted file mode 100644 index eaa59b1709..0000000000 --- a/src/SonarQube.Client/Api/V5_00/GetSourceCodeRequest.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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 Newtonsoft.Json; -using SonarQube.Client.Requests; - -namespace SonarQube.Client.Api.V5_00 -{ - public class GetSourceCodeRequest : RequestBase, IGetSourceCodeRequest - { - [JsonProperty("key")] - public string FileKey { get; set; } - - protected override string Path => "api/sources/raw"; - - protected override string ParseResponse(string response) - { - // Expecting the response to be the raw source code - return response; - } - } -} diff --git a/src/SonarQube.Client/Helpers/SecondaryLocationHashUpdater.cs b/src/SonarQube.Client/Helpers/SecondaryLocationHashUpdater.cs deleted file mode 100644 index c0cdc1b33c..0000000000 --- a/src/SonarQube.Client/Helpers/SecondaryLocationHashUpdater.cs +++ /dev/null @@ -1,141 +0,0 @@ -/* - * SonarLint for Visual Studio - * Copyright (C) 2016-2024 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 System.Diagnostics; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using SonarQube.Client.Models; - -namespace SonarQube.Client.Helpers -{ - /// - /// Sets the hashes for any secondary locations in the supplied list of issues - /// - /// - /// Currently secondary location hashes are not stored server-side, so we have to - /// calculate them ourselves. This means fetching the source code for each file - /// so we can get the line text and calculate the hash. - /// - internal interface ISecondaryIssueHashUpdater - { - Task UpdateHashesAsync(IEnumerable issues, - ISonarQubeService sonarQubeService, - CancellationToken cancellationToken); - } - - /// - /// This component does not have any mutable state, so it can safely handle multiple - /// concurrent calls. - /// - internal class SecondaryLocationHashUpdater : ISecondaryIssueHashUpdater - { - private readonly IChecksumCalculator checksumCalculator; - - public SecondaryLocationHashUpdater() - : this(new ChecksumCalculator()) - { - } - - internal /* for testing */ SecondaryLocationHashUpdater(IChecksumCalculator checksumCalculator) - { - this.checksumCalculator = checksumCalculator; - } - - public async Task UpdateHashesAsync(IEnumerable issues, - ISonarQubeService sonarQubeService, - CancellationToken cancellationToken) - { - var secondaryLocations = GetSecondaryLocations(issues); - if (!secondaryLocations.Any()) - { - // This will be the normal case: most issues don't have secondary locations - return; - } - - var uniqueKeys = GetUniqueSecondaryLocationKeys(secondaryLocations); - - var map = new ModuleKeyToSourceMap(); - foreach (var key in uniqueKeys) - { - var sourceCode = await sonarQubeService.GetSourceCodeAsync(key, cancellationToken); - Debug.Assert(sourceCode != null, "Not expecting the file contents to be null"); - map.AddSourceCode(key, sourceCode); - } - - foreach (var location in GetSecondaryLocations(issues)) - { - SetLineHash(map, location); - } - } - - private static IEnumerable GetSecondaryLocations(IEnumerable issues) => - issues.SelectMany( - issue => issue.Flows.SelectMany( - flow => flow.Locations)) - .ToArray(); - - private static IEnumerable GetUniqueSecondaryLocationKeys(IEnumerable locations) => - locations - .Select(loc => loc.ModuleKey) - .Distinct() - .ToArray(); - - private void SetLineHash(ModuleKeyToSourceMap map, IssueLocation location) - { - // Issue locations can span multiple lines, but only the first line is used - // when calculating the hash - var firstLineOfIssue = map.GetLineText(location.ModuleKey, location.TextRange.StartLine); - - if (firstLineOfIssue != null) - { - location.Hash = checksumCalculator.Calculate(firstLineOfIssue); - } - } - - /// - /// Provide a lookup from module key -> source code line - /// - private sealed class ModuleKeyToSourceMap - { - private readonly IDictionary keyToLinesMap = new Dictionary(); - - public void AddSourceCode(string moduleKey, string sourceCode) - { - keyToLinesMap.Add(moduleKey, sourceCode.Split('\n')); - } - - public string GetLineText(string moduleKey, int oneBasedLineNumber) - { - Debug.Assert(keyToLinesMap.ContainsKey(moduleKey), "Unexpected module key requested"); - - var lines = keyToLinesMap[moduleKey]; - - if (oneBasedLineNumber > lines.Length) - { - return null; - } - - return lines[oneBasedLineNumber - 1]; - } - } - } -} diff --git a/src/SonarQube.Client/ISonarQubeService.cs b/src/SonarQube.Client/ISonarQubeService.cs index 82156f3993..0b3312d390 100644 --- a/src/SonarQube.Client/ISonarQubeService.cs +++ b/src/SonarQube.Client/ISonarQubeService.cs @@ -138,12 +138,6 @@ Task> GetNotificationEventsAsync(string projectKey, /// The method does not check whether the project or hotspot exists or not Uri GetViewHotspotUrl(string projectKey, string hotspotKey); - /// - /// Returns the source code for the specified file - /// - /// e.g. my_project:src/foo/Bar.php - Task GetSourceCodeAsync(string fileKey, CancellationToken token); - /// /// Returns branch information for the specified project key /// diff --git a/src/SonarQube.Client/SonarQubeService.cs b/src/SonarQube.Client/SonarQubeService.cs index 1088ffef2a..c47a97dc98 100644 --- a/src/SonarQube.Client/SonarQubeService.cs +++ b/src/SonarQube.Client/SonarQubeService.cs @@ -37,7 +37,6 @@ public class SonarQubeService : ISonarQubeService, IDisposable private readonly string userAgent; private readonly ILogger logger; private readonly IRequestFactorySelector requestFactorySelector; - private readonly ISecondaryIssueHashUpdater secondaryIssueHashUpdater; private readonly ISSEStreamReaderFactory sseStreamReaderFactory; private const string MinSqVersionSupportingBearer = "10.4"; @@ -58,7 +57,7 @@ public async Task HasOrganizations(CancellationToken token) public ServerInfo GetServerInfo() => currentServerInfo; public SonarQubeService(HttpMessageHandler messageHandler, string userAgent, ILogger logger) - : this(messageHandler, userAgent, logger, new RequestFactorySelector(), new SecondaryLocationHashUpdater(), new SSEStreamReaderFactory(logger)) + : this(messageHandler, userAgent, logger, new RequestFactorySelector(), new SSEStreamReaderFactory(logger)) { } @@ -67,7 +66,6 @@ public SonarQubeService(HttpMessageHandler messageHandler, string userAgent, ILo string userAgent, ILogger logger, IRequestFactorySelector requestFactorySelector, - ISecondaryIssueHashUpdater secondaryIssueHashUpdater, ISSEStreamReaderFactory sseStreamReaderFactory) { if (messageHandler == null) @@ -87,7 +85,6 @@ public SonarQubeService(HttpMessageHandler messageHandler, string userAgent, ILo this.logger = logger; this.requestFactorySelector = requestFactorySelector; - this.secondaryIssueHashUpdater = secondaryIssueHashUpdater; this.sseStreamReaderFactory = sseStreamReaderFactory; } @@ -493,14 +490,6 @@ public Uri GetViewHotspotUrl(string projectKey, string hotspotKey) return new Uri(currentHttpClient.BaseAddress, string.Format(urlFormat, projectKey, hotspotKey)); } - public async Task GetSourceCodeAsync(string fileKey, CancellationToken token) => - await InvokeCheckedRequestAsync( - request => - { - request.FileKey = fileKey; - }, - token); - public async Task> GetProjectBranchesAsync(string projectKey, CancellationToken token) => await InvokeCheckedRequestAsync( request =>