Skip to content

Commit

Permalink
fix: add new consistent ignores setting [IDE-723] (#322)
Browse files Browse the repository at this point in the history
* fix: add new consistent ignores setting [IDE-723]

---------

Co-authored-by: Abdelrahman Shawki Hassan <[email protected]>
Co-authored-by: Darius-Beniamin Zdroba <[email protected]>
  • Loading branch information
3 people authored Nov 14, 2024
1 parent 154647c commit 96ccf5d
Show file tree
Hide file tree
Showing 33 changed files with 642 additions and 482 deletions.
8 changes: 6 additions & 2 deletions Snyk.Common/Settings/ISnykOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ public interface ISnykOptions

string DeviceId { get; set; }
bool AutoScan { get; set; }

bool ConsistentIgnoresEnabled { get; set; }
public bool OpenIssuesEnabled { get; set; }
public bool IgnoredIssuesEnabled { get; set; }

/// <summary>
/// Gets or sets a value indicating whether Snyk user API token.
Expand Down Expand Up @@ -107,8 +111,8 @@ public interface ISnykOptions

SastSettings SastSettings { get; set; }
bool AnalyticsPluginInstalledSent { get; set; }
Task OnAuthenticationSuccessfulAsync(string token, string apiUrl);
Task OnAuthenticationFailedAsync(string errorMessage);
Task HandleAuthenticationSuccess(string token, string apiUrl);
Task HandleFailedAuthentication(string errorMessage);
void FireSettingsChangedEvent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ private async Task DownloadFileAsync(
string cliFileDestinationPath,
List<CliDownloadFinishedCallback> downloadFinishedCallbacks = null)
{
const int bufferSize = 8192;
const int bufferSize = 81920;

using (var client = new HttpClient())
{
Expand All @@ -275,7 +275,7 @@ private async Task DownloadFileAsync(

using (var fileStream = new FileStream(tempCliFile, FileMode.Create, FileAccess.Write, FileShare.ReadWrite, bufferSize, true))
{
using (Stream contentStream = await response.Content.ReadAsStreamAsync())
using (var contentStream = await response.Content.ReadAsStreamAsync())
{
var totalBytes = response.Content.Headers.ContentLength ?? long.MaxValue; // Avoid dividing by null when calculating progress
var totalRead = 0L;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Snyk.VisualStudio.Extension.Language;

public class FeatureFlagResponse
{
public bool Ok { get; set; }
public string UserMessage { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ public interface ILanguageClientManager
event AsyncEventHandler<SnykLanguageServerEventArgs> OnLanguageClientNotInitializedAsync;
void FireOnLanguageClientNotInitializedAsync();
Task InvokeReportAnalyticsAsync(IAbstractAnalyticsEvent analyticsEvent, CancellationToken cancellationToken);
Task<FeatureFlagResponse> InvokeGetFeatureFlagStatusAsync(string featureFlagName, CancellationToken cancellationToken);
}
}
37 changes: 32 additions & 5 deletions Snyk.VisualStudio.Extension.2022/Language/LsAnalysisResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,22 +127,49 @@ public class Issue
public bool IsNew { get; set; }
public IgnoreDetails IgnoreDetails { get; set; }
public AdditionalData AdditionalData { get; set; }
public string Product { get; set; }

public string GetDisplayTitle() => string.IsNullOrEmpty(this.Title) ? this.AdditionalData?.Message : this.Title;

public bool HasFix()
{
var hasAiFix = this.AdditionalData?.HasAIFix ?? false;
var isUpgradable = this.AdditionalData?.IsUpgradable ?? false;
return hasAiFix || isUpgradable;
}

public string GetDisplayTitleWithLineNumber()
{
var fixIcon = HasFix() ? "⚡" : "";

var ignoredPrefix = this.IsIgnored ? "[ Ignored ] " : "";
var line = "line " + this.Range?.End?.Line + ": " + this.GetDisplayTitle();
if (this.AdditionalData?.HasAIFix ?? false)

return fixIcon + ignoredPrefix + line;
}

public bool IsVisible(bool includeIgnoredIssues, bool includeOpenedIssues)
{
if (includeIgnoredIssues && includeOpenedIssues)
{
return true;
}
if (includeIgnoredIssues)
{
line = "⚡" + line;
return this.IsIgnored;
}
if (includeOpenedIssues)
{
return this.IsIgnored != true;
}

return line;
return false;
}

public string GetPackageNameTitle() => $"{this.AdditionalData?.PackageName}@{this.AdditionalData?.Version}: {this.Title}";
public string GetPackageNameTitle()
{
var fixIcon = HasFix() ? "⚡" : "";
return $"{fixIcon}{this.AdditionalData?.PackageName}@{this.AdditionalData?.Version}: {this.Title}";
}
}

public class LineData
Expand Down
5 changes: 4 additions & 1 deletion Snyk.VisualStudio.Extension.2022/Language/LsConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
public static class LsConstants
{
public const string ProtocolVersion = "16";
public const string ProtocolVersion = "17";

// Notifications
public const string SnykHasAuthenticated = "$/snyk.hasAuthenticated";
Expand All @@ -28,5 +28,8 @@ public static class LsConstants
public const string SnykGetFeatureFlagStatus = "snyk.getFeatureFlagStatus";
public const string SnykGenerateIssueDescription = "snyk.generateIssueDescription";
public const string SnykReportAnalytics = "snyk.reportAnalytics";

// Feature flags
public const string SnykConsistentIgnoresEnabled = "snykCodeConsistentIgnores";
}
}
18 changes: 13 additions & 5 deletions Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Threading;
Expand Down Expand Up @@ -124,7 +125,7 @@ public async Task<Connection> ActivateAsync(CancellationToken token)
// ReSharper disable once RedundantAssignment
var lsDebugLevel = await GetLsDebugLevelAsync(options);
#if DEBUG
lsDebugLevel = "trace";
lsDebugLevel = "debug";
#endif
var info = new ProcessStartInfo
{
Expand Down Expand Up @@ -405,15 +406,14 @@ public async Task<string> InvokeGenerateIssueDescriptionAsync(string issueId, Ca
return result;
}

public async Task<object> InvokeGetFeatureFlagStatus(string featureFlag, CancellationToken cancellationToken)
public async Task<FeatureFlagResponse> InvokeGetFeatureFlagStatusAsync(string featureFlag, CancellationToken cancellationToken)
{
var param = new LSP.ExecuteCommandParams
{
Command = LsConstants.SnykGetFeatureFlagStatus,
Arguments = new object[] { featureFlag }
};
var featureFlagStatus = await InvokeWithParametersAsync<object>(LsConstants.WorkspaceExecuteCommand, param, cancellationToken);
return featureFlagStatus;
return await InvokeWithParametersAsync<FeatureFlagResponse>(LsConstants.WorkspaceExecuteCommand, param, cancellationToken);
}

public async Task InvokeReportAnalyticsAsync(IAbstractAnalyticsEvent analyticsEvent, CancellationToken cancellationToken)
Expand Down Expand Up @@ -461,7 +461,15 @@ private async Task<T> InvokeAsync<T>(string request, CancellationToken t)
private async Task<T> InvokeWithParametersAsync<T>(string request, object parameters, CancellationToken t)
{
if (!IsReady) return default;
return await Rpc.InvokeWithParameterObjectAsync<T>(request, parameters, t).ConfigureAwait(false);
try
{
return await Rpc.InvokeWithParameterObjectAsync<T>(request, parameters, t).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.Error("{Ex}" ,ex);
return default;
}
}

private async Task NotifyWithParametersAsync(string request, object parameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualStudio.Shell;
using Newtonsoft.Json.Linq;
using Snyk.Common.Authentication;
using Snyk.VisualStudio.Extension.Extension;
Expand Down Expand Up @@ -50,25 +51,27 @@ public async Task OnPublishDiagnostics316(JToken arg)
}

var source = LspSourceToProduct(diagnosticsArray[0]["source"].ToString());
var dataList = diagnosticsArray.Where(x => x["data"] != null)
var issueList = diagnosticsArray.Where(x => x["data"] != null)
.Select(x =>
{
var issue = x["data"].TryParse<Issue>();
issue.Product = LspSourceToProduct(source);
if (issue.IsIgnored)
{
serviceProvider.Options.ConsistentIgnoresEnabled = true;
}
return issue;
});


switch (source)
{
case "code":
snykCodeIssueDictionary.TryAdd(parsedUri.UncAwareAbsolutePath(), dataList);
snykCodeIssueDictionary.TryAdd(parsedUri.UncAwareAbsolutePath(), issueList);
break;
case "oss":
snykOssIssueDictionary.TryAdd(parsedUri.UncAwareAbsolutePath(), dataList);
snykOssIssueDictionary.TryAdd(parsedUri.UncAwareAbsolutePath(), issueList);
break;
case "iac":
snykIaCIssueDictionary.TryAdd(parsedUri.UncAwareAbsolutePath(), dataList);
snykIaCIssueDictionary.TryAdd(parsedUri.UncAwareAbsolutePath(), issueList);
break;
default:
throw new InvalidProductTypeException();
Expand Down Expand Up @@ -112,7 +115,7 @@ public async Task OnHasAuthenticated(JToken arg)
{
if (arg?["token"] == null)
{
await serviceProvider.Options.OnAuthenticationFailedAsync("Authentication failed");
await serviceProvider.Options.HandleFailedAuthentication("Authentication failed");
return;
}

Expand All @@ -130,7 +133,9 @@ public async Task OnHasAuthenticated(JToken arg)

serviceProvider.Options.ApiToken = new AuthenticationToken(serviceProvider.Options.AuthenticationMethod, token);

await serviceProvider.Options.OnAuthenticationSuccessfulAsync(token, apiUrl);
await serviceProvider.Options.HandleAuthenticationSuccess(token, apiUrl);

FeatureFlagService.Instance.RefreshAsync().FireAndForget();

if (serviceProvider.Options.AutoScan)
{
Expand Down
55 changes: 55 additions & 0 deletions Snyk.VisualStudio.Extension.2022/Service/FeatureFlagService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Threading.Tasks;
using Serilog;
using Snyk.Common;
using Snyk.Common.Settings;
using Snyk.VisualStudio.Extension.Language;

namespace Snyk.VisualStudio.Extension.Service;

public class FeatureFlagService
{
private readonly ILanguageClientManager languageClient;
private readonly ISnykOptions settings;
private static readonly ILogger Logger = LogManager.ForContext<FeatureFlagService>();
private static FeatureFlagService instance;

public FeatureFlagService(ILanguageClientManager languageClient, ISnykOptions settings)
{
this.languageClient = languageClient;
this.settings = settings;
}

public static FeatureFlagService Instance => instance;

/// <summary>
/// Initialize service.
/// </summary>
/// <param name="languageClient"></param>
/// <param name="settings"></param>
/// <returns>Task.</returns>
public static FeatureFlagService Initialize(ILanguageClientManager languageClient, ISnykOptions settings)
{
if (instance != null)
return instance;

instance = new FeatureFlagService(languageClient, settings);

Logger.Information("FeatureFlagService initialized");
return instance;
}

public async Task RefreshAsync()
{
var result = await languageClient.InvokeGetFeatureFlagStatusAsync(LsConstants.SnykConsistentIgnoresEnabled, SnykVSPackage.Instance.DisposalToken);
if (result == null)
{
settings.ConsistentIgnoresEnabled = false;
return;
}
settings.ConsistentIgnoresEnabled = result.Ok;
if (!result.Ok)
{
if (!result.UserMessage.IsNullOrEmpty()) Logger.Error("feature flag not enabled: {UserMessage}", result.UserMessage);
}
}
}
1 change: 0 additions & 1 deletion Snyk.VisualStudio.Extension.2022/Service/SnykService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ public async Task InitializeAsync(CancellationToken cancellationToken)
this.dte = await this.serviceProvider.GetServiceAsync(typeof(DTE)) as DTE2;
await SnykSolutionService.Instance.InitializeAsync(this);


this.tasksService = SnykTasksService.Instance;
this.workspaceTrustService = new WorkspaceTrustService(this.UserStorageSettingsService);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,30 @@ public ISet<string> TrustedFolders
/// </summary>
public ISnykServiceProvider ServiceProvider => this.serviceProvider;

public bool ConsistentIgnoresEnabled { get; set; }

public bool OpenIssuesEnabled
{
get => this.userStorageSettingsService.OpenIssuesEnabled;
set
{
if (this.userStorageSettingsService == null || this.userStorageSettingsService.OpenIssuesEnabled == value)
return;
this.userStorageSettingsService.OpenIssuesEnabled = value;
}
}

public bool IgnoredIssuesEnabled
{
get => this.userStorageSettingsService.IgnoredIssuesEnabled;
set
{
if (this.userStorageSettingsService == null || this.userStorageSettingsService.IgnoredIssuesEnabled == value)
return;
this.userStorageSettingsService.IgnoredIssuesEnabled = value;
}
}

/// <summary>
/// Gets or sets a value indicating whether API token.
/// </summary>
Expand Down Expand Up @@ -159,14 +183,14 @@ public bool AnalyticsPluginInstalledSent
set => this.userStorageSettingsService.AnalyticsPluginInstalledSent = value;
}

public async Task OnAuthenticationSuccessfulAsync(string token, string apiUrl)
public async Task HandleAuthenticationSuccess(string token, string apiUrl)
{
await this.GeneralSettingsUserControl.OnAuthenticationSuccessfulAsync(token, apiUrl);
await this.GeneralSettingsUserControl.HandleAuthenticationSuccess(token, apiUrl);
}

public async Task OnAuthenticationFailedAsync(string errorMessage)
public async Task HandleFailedAuthentication(string errorMessage)
{
await this.GeneralSettingsUserControl.OnAuthenticationFailAsync(errorMessage);
await this.GeneralSettingsUserControl.HandleFailedAuthentication(errorMessage);
}
/// <summary>
/// Gets or sets a value indicating whether organization.
Expand Down
Loading

0 comments on commit 96ccf5d

Please sign in to comment.