From 15b1b108961f3a75669a6545188c7ff484f5dd33 Mon Sep 17 00:00:00 2001 From: Abdelrahman Shawki Hassan Date: Mon, 16 Dec 2024 13:00:09 +0100 Subject: [PATCH] refactor: separate options model from page (#331) * refactor: separate options model from page * fix: scrollbar in settings dialog * fix: tests * chore: update readme * fix: attempt to only use nuget locked mode * chore: remove redundant access modifiers --- .github/workflows/build-project.yml | 5 +- .github/workflows/security-scan-upload.yml | 2 +- README.md | 2 +- .../SnykLanguageClientCustomTarget.cs | 4 +- .../Service/ISnykServiceProvider.cs | 1 + .../Service/SnykService.cs | 2 + .../Service/SnykTasksService.cs | 2 +- .../Settings/ISnykGeneralOptionsDialogPage.cs | 12 + .../Settings/ISnykOptions.cs | 34 +- .../Settings/SnykGeneralOptionsDialogPage.cs | 468 ++---------------- ...SnykGeneralSettingsUserControl.Designer.cs | 32 +- .../SnykGeneralSettingsUserControl.cs | 142 +++--- .../SnykGeneralSettingsUserControl.resx | 16 +- .../Settings/SnykOptions.cs | 363 ++++++++++++++ .../Settings/SnykSolutionOptionsDialogPage.cs | 10 +- ...SnykSolutionOptionsUserControl.Designer.cs | 21 +- .../SnykSolutionOptionsUserControl.cs | 4 +- .../Snyk.VisualStudio.Extension.2022.csproj | 2 + .../SnykVSPackage.cs | 25 +- .../UI/Toolwindow/MessagePanel.xaml.cs | 4 +- .../Toolwindow/SnykToolWindowControl.xaml.cs | 2 +- .../SnykLanguageClientCustomTargetTests.cs | 11 +- ...nsDialogPageTest.cs => SnykOptionsTest.cs} | 27 +- 23 files changed, 604 insertions(+), 587 deletions(-) create mode 100644 Snyk.VisualStudio.Extension.2022/Settings/ISnykGeneralOptionsDialogPage.cs create mode 100644 Snyk.VisualStudio.Extension.2022/Settings/SnykOptions.cs rename Snyk.VisualStudio.Extension.Tests/{GeneralOptionsDialogPageTest.cs => SnykOptionsTest.cs} (76%) diff --git a/.github/workflows/build-project.yml b/.github/workflows/build-project.yml index d1cb4bed3..c01810af3 100644 --- a/.github/workflows/build-project.yml +++ b/.github/workflows/build-project.yml @@ -68,12 +68,9 @@ jobs: with: vs-version: '[17.0, )' - - name: Restore NuGet packages - run: nuget restore ${{ inputs.solution-file-path }} - - name: Build run: | - msbuild ${{ inputs.solution-file-path }} /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /v:m + msbuild ${{ inputs.solution-file-path }} /p:configuration=Release /p:DeployExtension=false /p:ZipPackageCompressionLevel=normal /t:restore /p:RestoreLockedMode=true /v:m shell: powershell - name: Upload build artifacts diff --git a/.github/workflows/security-scan-upload.yml b/.github/workflows/security-scan-upload.yml index 32ef7bf0c..0cc2c00ac 100644 --- a/.github/workflows/security-scan-upload.yml +++ b/.github/workflows/security-scan-upload.yml @@ -14,7 +14,7 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 - name: Restore dependencies - run: dotnet restore /home/runner/work/snyk-visual-studio-plugin/snyk-visual-studio-plugin + run: dotnet restore /home/runner/work/snyk-visual-studio-plugin/snyk-visual-studio-plugin --locked-mode - name: Run snyk monitor uses: snyk/actions/dotnet@master continue-on-error: true diff --git a/README.md b/README.md index 5edd9c614..843a73268 100644 --- a/README.md +++ b/README.md @@ -48,4 +48,4 @@ Continue by following the instructions in the other Visual Studio extension docs For troubleshooting and known issues, see [Troubleshooting and known issues with Visual Studio extension](https://docs.snyk.io/scm-ide-and-ci-cd-integrations/snyk-ide-plugins-and-extensions/visual-studio-extension/troubleshooting-and-known-issues-with-visual-studio-extension). -If you need help, submit a request to [Snyk Support](https://support.snyk.io/hc/en-us/requests/new). +If you need help, submit a request to [Snyk Support](https://support.snyk.io). diff --git a/Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClientCustomTarget.cs b/Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClientCustomTarget.cs index 564ecdeea..99d4d9aeb 100644 --- a/Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClientCustomTarget.cs +++ b/Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClientCustomTarget.cs @@ -116,7 +116,7 @@ public async Task OnHasAuthenticated(JToken arg) { if (arg?["token"] == null) { - await serviceProvider.Options.HandleFailedAuthentication("Authentication failed"); + await serviceProvider.GeneralOptionsDialogPage.HandleFailedAuthentication("Authentication failed"); return; } @@ -134,7 +134,7 @@ public async Task OnHasAuthenticated(JToken arg) serviceProvider.Options.ApiToken = new AuthenticationToken(serviceProvider.Options.AuthenticationMethod, token); - await serviceProvider.Options.HandleAuthenticationSuccess(token, apiUrl); + await serviceProvider.GeneralOptionsDialogPage.HandleAuthenticationSuccess(token, apiUrl); serviceProvider.FeatureFlagService.RefreshAsync(SnykVSPackage.Instance.DisposalToken).FireAndForget(); if (serviceProvider.Options.AutoScan) diff --git a/Snyk.VisualStudio.Extension.2022/Service/ISnykServiceProvider.cs b/Snyk.VisualStudio.Extension.2022/Service/ISnykServiceProvider.cs index 96541f420..41fcb0790 100644 --- a/Snyk.VisualStudio.Extension.2022/Service/ISnykServiceProvider.cs +++ b/Snyk.VisualStudio.Extension.2022/Service/ISnykServiceProvider.cs @@ -46,6 +46,7 @@ public interface ISnykServiceProvider /// Gets (Settings) implementation instance. /// ISnykOptions Options { get; } + ISnykGeneralOptionsDialogPage GeneralOptionsDialogPage { get; } /// /// Gets Visual Studio Settiings Manager instance. diff --git a/Snyk.VisualStudio.Extension.2022/Service/SnykService.cs b/Snyk.VisualStudio.Extension.2022/Service/SnykService.cs index 53705e9e1..3112722f0 100644 --- a/Snyk.VisualStudio.Extension.2022/Service/SnykService.cs +++ b/Snyk.VisualStudio.Extension.2022/Service/SnykService.cs @@ -59,6 +59,8 @@ public SnykService(IAsyncServiceProvider serviceProvider, string vsVersion = "") /// public ISnykOptions Options => this.Package.Options; + public ISnykGeneralOptionsDialogPage GeneralOptionsDialogPage => this.Package.SnykGeneralOptionsDialogPage; + /// /// Gets solution service. /// diff --git a/Snyk.VisualStudio.Extension.2022/Service/SnykTasksService.cs b/Snyk.VisualStudio.Extension.2022/Service/SnykTasksService.cs index 08def074a..a51b638ad 100644 --- a/Snyk.VisualStudio.Extension.2022/Service/SnykTasksService.cs +++ b/Snyk.VisualStudio.Extension.2022/Service/SnykTasksService.cs @@ -306,7 +306,7 @@ public async Task IsFolderTrustedAsync() try { this.serviceProvider.WorkspaceTrustService.AddFolderToTrusted(solutionFolderPath); - this.serviceProvider.Options.FireSettingsChangedEvent(); + this.serviceProvider.Options.InvokeSettingsChangedEvent(); Logger.Information("Workspace folder was trusted: {SolutionFolderPath}", solutionFolderPath); return true; } diff --git a/Snyk.VisualStudio.Extension.2022/Settings/ISnykGeneralOptionsDialogPage.cs b/Snyk.VisualStudio.Extension.2022/Settings/ISnykGeneralOptionsDialogPage.cs new file mode 100644 index 000000000..3f5a06065 --- /dev/null +++ b/Snyk.VisualStudio.Extension.2022/Settings/ISnykGeneralOptionsDialogPage.cs @@ -0,0 +1,12 @@ +using Snyk.VisualStudio.Extension.Service; +using System.Threading.Tasks; + +namespace Snyk.VisualStudio.Extension.Settings; + +public interface ISnykGeneralOptionsDialogPage +{ + void Initialize(ISnykServiceProvider provider); + Task HandleAuthenticationSuccess(string token, string apiUrl); + Task HandleFailedAuthentication(string errorMessage); + void Authenticate(); +} \ No newline at end of file diff --git a/Snyk.VisualStudio.Extension.2022/Settings/ISnykOptions.cs b/Snyk.VisualStudio.Extension.2022/Settings/ISnykOptions.cs index 38db1f5ec..fe1e05c76 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/ISnykOptions.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/ISnykOptions.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using Snyk.VisualStudio.Extension.Authentication; using Snyk.VisualStudio.Extension.Language; -using Snyk.VisualStudio.Extension.Service; namespace Snyk.VisualStudio.Extension.Settings { @@ -12,7 +11,6 @@ namespace Snyk.VisualStudio.Extension.Settings /// public interface ISnykOptions { - void Initialize(ISnykServiceProvider provider); string Application { get; set; } string ApplicationVersion { get; set; } string IntegrationName { get; } @@ -24,8 +22,8 @@ public interface ISnykOptions bool AutoScan { get; set; } bool ConsistentIgnoresEnabled { get; set; } - public bool OpenIssuesEnabled { get; set; } - public bool IgnoredIssuesEnabled { get; set; } + bool OpenIssuesEnabled { get; set; } + bool IgnoredIssuesEnabled { get; set; } /// /// Gets or sets a value indicating whether Snyk user API token. @@ -35,7 +33,7 @@ public interface ISnykOptions /// /// Gets Value of Authentication Token Type. /// - AuthenticationType AuthenticationMethod { get; } + AuthenticationType AuthenticationMethod { get; set; } /// /// Gets or sets a value indicating whether CLI custom endpoint parameter. @@ -60,18 +58,18 @@ public interface ISnykOptions /// /// Gets a value indicating whether is Oss scan enabled. /// - bool OssEnabled { get; } - bool IacEnabled { get; } + bool OssEnabled { get; set; } + bool IacEnabled { get; set; } /// /// Gets a value indicating whether is Oss scan enabled. /// - bool SnykCodeSecurityEnabled { get; } + bool SnykCodeSecurityEnabled { get; set; } /// /// Gets a value indicating whether is Oss scan enabled. /// - bool SnykCodeQualityEnabled { get; } + bool SnykCodeQualityEnabled { get; set; } /// /// Gets or sets a value indicating whether the CLI should be automatically updated. @@ -86,8 +84,8 @@ public interface ISnykOptions string CliDownloadUrl { get; set; } ISet TrustedFolders { get; set; } - public bool EnableDeltaFindings { get; set; } - public List FolderConfigs { get; set; } + bool EnableDeltaFindings { get; set; } + List FolderConfigs { get; set; } /// /// Settings changed event. @@ -108,18 +106,10 @@ public interface ISnykOptions /// representing the asynchronous operation. Task IsScanAllProjectsAsync(); - /// - /// Attempts to pull the token from the CLI config storage, and validates the token. - /// If the token is invalid, attempts to run the authentication command. - /// - /// Returns true if authenticated successfully, or if a valid token was loaded from storage. - void Authenticate(); - public string CurrentCliVersion { get; set; } - + string CurrentCliVersion { get; set; } SastSettings SastSettings { get; set; } bool AnalyticsPluginInstalledSent { get; set; } - Task HandleAuthenticationSuccess(string token, string apiUrl); - Task HandleFailedAuthentication(string errorMessage); - void FireSettingsChangedEvent(); + void InvokeSettingsChangedEvent(); + void SaveSettings(); } } \ No newline at end of file diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralOptionsDialogPage.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralOptionsDialogPage.cs index de0918a2a..625862459 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralOptionsDialogPage.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralOptionsDialogPage.cs @@ -1,12 +1,12 @@ using System; -using System.Collections.Generic; +using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; using System.Threading.Tasks; +using System.Windows.Controls; using System.Windows.Forms; using Microsoft.VisualStudio.Shell; using Serilog; -using Snyk.VisualStudio.Extension.Authentication; using Snyk.VisualStudio.Extension.CLI; using Snyk.VisualStudio.Extension.Language; using Snyk.VisualStudio.Extension.Service; @@ -18,192 +18,46 @@ namespace Snyk.VisualStudio.Extension.Settings /// [Guid("d45468c1-33d2-4dca-9780-68abaedf95e7")] [ComVisible(true)] - public class SnykGeneralOptionsDialogPage : DialogPage, ISnykOptions + public class SnykGeneralOptionsDialogPage : DialogPage, ISnykGeneralOptionsDialogPage { - public string Application { get; set; } - public string ApplicationVersion { get; set; } - public string IntegrationName { get; } = SnykExtension.IntegrationName; - public string IntegrationVersion { get; } = SnykExtension.Version; - public string IntegrationEnvironment { get; set; } - public string IntegrationEnvironmentVersion { get; set;} - - public string DeviceId - { - get => this.userStorageSettingsService.DeviceId; - set => this.userStorageSettingsService.DeviceId = value; - } - private ISnykServiceProvider serviceProvider; - - private IUserStorageSettingsService userStorageSettingsService; - private SnykGeneralSettingsUserControl generalSettingsUserControl; - private static readonly ILogger Logger = LogManager.ForContext(); - public ISet TrustedFolders - { - get => this.userStorageSettingsService.TrustedFolders; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.TrustedFolders == value) - return; - this.userStorageSettingsService.TrustedFolders = value; - } - } - - public bool EnableDeltaFindings - { - get => this.userStorageSettingsService.EnableDeltaFindings; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.EnableDeltaFindings == value) - return; - this.userStorageSettingsService.EnableDeltaFindings = value; - userStorageSettingsService.SaveSettings(); - } - } - - public List FolderConfigs - { - get => this.userStorageSettingsService.FolderConfigs; - set - { - if (this.userStorageSettingsService == null) - return; - this.userStorageSettingsService.FolderConfigs = value; - userStorageSettingsService.SaveSettings(); - FireSettingsChangedEvent(); - } - } - - /// - public event EventHandler SettingsChanged; - - /// - /// Gets a value indicating whether service provider. - /// - 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 + protected override void OnActivate(CancelEventArgs e) { - get => this.userStorageSettingsService.IgnoredIssuesEnabled; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.IgnoredIssuesEnabled == value) - return; - this.userStorageSettingsService.IgnoredIssuesEnabled = value; - } - } + base.OnActivate(e); - /// - /// Gets or sets a value indicating whether API token. - /// - public AuthenticationToken ApiToken - { - get => CreateAuthenticationToken(this.userStorageSettingsService.Token); - set - { - var tokenAsString = value.ToString(); - if (this.userStorageSettingsService == null || this.userStorageSettingsService.Token == tokenAsString) - return; - this.userStorageSettingsService.Token = tokenAsString; - userStorageSettingsService.SaveSettings(); - FireSettingsChangedEvent(); - } - } - - public AuthenticationType AuthenticationMethod - { - get => this.userStorageSettingsService.AuthenticationMethod; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.AuthenticationMethod == value) - return; - this.userStorageSettingsService.AuthenticationMethod = value; - this.GeneralSettingsUserControl.InvalidateApiToken(); - ApiToken = AuthenticationToken.EmptyToken; - userStorageSettingsService.SaveSettings(); - FireSettingsChangedEvent(); - } + ResetScrollbarSettings(); } - public bool AutoScan - { - get => this.userStorageSettingsService.AutoScan; - set - { - if (this.userStorageSettingsService == null) - return; - this.userStorageSettingsService.AutoScan = value; - } - } - - private AuthenticationToken CreateAuthenticationToken(string token) + protected override void OnClosed(EventArgs e) { - var tokenObj = new AuthenticationToken(this.AuthenticationMethod, token); - return tokenObj; + ResetScrollbarSettings(); } - /// - /// Gets or sets a value indicating whether Custom endpoint. - /// - public string CustomEndpoint + private void ResetScrollbarSettings() { - get => this.userStorageSettingsService.CustomEndpoint; - set - { - if (!Uri.IsWellFormedUriString(value, UriKind.Absolute)) - { - Logger.Warning("Custom endpoint value is not a well-formed URI. Setting custom endpoint to empty string"); - value = string.Empty; - } - - var newApiEndpoint = ApiEndpointResolver.TranslateOldApiToNewApiEndpoint(value); - if (this.userStorageSettingsService == null || this.userStorageSettingsService.CustomEndpoint == newApiEndpoint) - { - return; - } + if (this.generalSettingsUserControl == null) + return; - this.userStorageSettingsService.CustomEndpoint = newApiEndpoint; - ApiToken = AuthenticationToken.EmptyToken; - userStorageSettingsService.SaveSettings(); - FireSettingsChangedEvent(); - } + // Reset the scroll position + this.generalSettingsUserControl.GetPanel().AutoScrollPosition = new System.Drawing.Point(0, 0); + this.generalSettingsUserControl.GetPanel().Top = 0; + this.generalSettingsUserControl.Top = 0; + // Force a refresh if needed + this.generalSettingsUserControl.Invalidate(true); + this.generalSettingsUserControl.Update(); } - /// - public string SnykCodeSettingsUrl => $"{this.GetBaseAppUrl()}/manage/snyk-code"; - - private SastSettings sastSettings; - public SastSettings SastSettings + public void Initialize(ISnykServiceProvider provider) { - get => this.sastSettings; - - set - { - this.sastSettings = value; - } + this.serviceProvider = provider; + this.SnykOptions = provider.Options; + SnykOptions.SettingsChanged += SnykGeneralOptionsDialogPage_SettingsChanged; } - public bool AnalyticsPluginInstalledSent - { - get => this.userStorageSettingsService.AnalyticsPluginInstalledSent; - set => this.userStorageSettingsService.AnalyticsPluginInstalledSent = value; - } + public ISnykOptions SnykOptions { get; set; } public async Task HandleAuthenticationSuccess(string token, string apiUrl) { @@ -214,183 +68,27 @@ public async Task HandleFailedAuthentication(string errorMessage) { await this.GeneralSettingsUserControl.HandleFailedAuthentication(errorMessage); } - /// - /// Gets or sets a value indicating whether organization. - /// - public string Organization - { - get => this.userStorageSettingsService.Organization; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.Organization == value) - { - return; - } - this.userStorageSettingsService.Organization = value; - userStorageSettingsService.SaveSettings(); - FireSettingsChangedEvent(); - } - } - - /// - /// Gets or sets a value indicating whether ignore unknown CA. - /// - public bool IgnoreUnknownCA - { - get => this.userStorageSettingsService.IgnoreUnknownCa; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.IgnoreUnknownCa == value) - { - return; - } - this.userStorageSettingsService.IgnoreUnknownCa = value; - userStorageSettingsService.SaveSettings(); - FireSettingsChangedEvent(); - } - } - - /// - public bool OssEnabled - { - get => this.userStorageSettingsService.OssEnabled; - set - { - if (this.userStorageSettingsService == null || userStorageSettingsService.OssEnabled == value) - { - return; - } - - this.userStorageSettingsService.OssEnabled = value; - } - } - - public bool IacEnabled - { - get => this.userStorageSettingsService.IacEnabled; - set - { - if (this.userStorageSettingsService == null || userStorageSettingsService.IacEnabled == value) - { - return; - } - - this.userStorageSettingsService.IacEnabled = value; - } - } - - /// - public bool SnykCodeSecurityEnabled - { - get => this.userStorageSettingsService.SnykCodeSecurityEnabled; - set - { - if (this.userStorageSettingsService == null || userStorageSettingsService.SnykCodeSecurityEnabled == value) - { - return; - } - - this.userStorageSettingsService.SnykCodeSecurityEnabled = value; - } - } - - /// - public bool SnykCodeQualityEnabled - { - get => this.userStorageSettingsService.SnykCodeQualityEnabled; - set - { - if (this.userStorageSettingsService == null || userStorageSettingsService.SnykCodeQualityEnabled == value) - { - return; - } - - this.userStorageSettingsService.SnykCodeQualityEnabled = value; - } - } - - public bool BinariesAutoUpdate - { - get => this.userStorageSettingsService.BinariesAutoUpdate; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.BinariesAutoUpdate == value) - { - return; - } - this.userStorageSettingsService.BinariesAutoUpdate = value; - } - } - public string CliCustomPath - { - get => this.userStorageSettingsService.CliCustomPath; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliCustomPath == value) - { - return; - } - this.userStorageSettingsService.CliCustomPath = value; - } - } + protected override IWin32Window Window => GeneralSettingsUserControl; - public string CliReleaseChannel - { - get => this.userStorageSettingsService.CliReleaseChannel; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliReleaseChannel == value) - { - return; - } - this.userStorageSettingsService.CliReleaseChannel = value; - } - } - public string CliDownloadUrl + public SnykGeneralSettingsUserControl GeneralSettingsUserControl { - get => this.userStorageSettingsService.CliDownloadUrl; - set - { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliDownloadUrl == value) - { - return; - } - this.userStorageSettingsService.CliDownloadUrl = value; - } - } - - public string CurrentCliVersion - { - get => this.userStorageSettingsService.CurrentCliVersion; - set + get { - if (this.userStorageSettingsService == null || this.userStorageSettingsService.CurrentCliVersion == value) + if (generalSettingsUserControl == null) { - return; + generalSettingsUserControl = new SnykGeneralSettingsUserControl(serviceProvider); } - this.userStorageSettingsService.CurrentCliVersion = value; + return generalSettingsUserControl; } } - /// - /// Gets a value indicating whether General Settings control. - /// - protected override IWin32Window Window => this.GeneralSettingsUserControl; - // This method is used when the user clicks "Ok" public override void SaveSettingsToStorage() { HandleCliDownload(); - this.userStorageSettingsService?.SaveSettings(); - this.FireSettingsChangedEvent(); - } - - protected override void OnClosed(EventArgs e) - { - if (generalSettingsUserControl == null) - return; - ResetControlScrollSettings(generalSettingsUserControl); + this.SnykOptions.SaveSettings(); + this.SnykOptions.InvokeSettingsChangedEvent(); } private void HandleCliDownload() @@ -400,94 +98,43 @@ private void HandleCliDownload() var manageBinariesAutomatically = generalSettingsUserControl.GetManageBinariesAutomatically(); if (!manageBinariesAutomatically) { - this.userStorageSettingsService.CurrentCliVersion = string.Empty; - this.BinariesAutoUpdate = false; + this.SnykOptions.CurrentCliVersion = string.Empty; + this.SnykOptions.BinariesAutoUpdate = false; serviceProvider.TasksService.CancelDownloadTask(); // Language Server restart will happen on DownloadCancelled Event. return; } - if (this.CliReleaseChannel != releaseChannel || this.CliDownloadUrl != downloadUrl || this.BinariesAutoUpdate != manageBinariesAutomatically) + if (this.SnykOptions.CliReleaseChannel != releaseChannel || this.SnykOptions.CliDownloadUrl != downloadUrl || this.SnykOptions.BinariesAutoUpdate != manageBinariesAutomatically) { - this.CliDownloadUrl = downloadUrl; - this.CliReleaseChannel = releaseChannel; - this.BinariesAutoUpdate = manageBinariesAutomatically; + this.SnykOptions.CliDownloadUrl = downloadUrl; + this.SnykOptions.CliReleaseChannel = releaseChannel; + this.SnykOptions.BinariesAutoUpdate = manageBinariesAutomatically; serviceProvider.TasksService.CancelDownloadTask(); this.serviceProvider.TasksService.Download(); } } - private void ResetControlScrollSettings(UserControl control) - { - control.VerticalScroll.Value = 0; - control.HorizontalScroll.Value = 0; - control.AutoScroll = true; - } - - private SnykGeneralSettingsUserControl GeneralSettingsUserControl - { - get - { - if (this.generalSettingsUserControl == null) - { - this.generalSettingsUserControl = new SnykGeneralSettingsUserControl() - { - OptionsDialogPage = this, - }; - - this.generalSettingsUserControl.Initialize(); - } - - return this.generalSettingsUserControl; - } - } - - /// - /// Gets a value indicating whether additional options. - /// Get this data using . - /// - /// representing the asynchronous operation. - public async Task GetAdditionalOptionsAsync() => await this.serviceProvider.UserStorageSettingsService.GetAdditionalOptionsAsync(); - - /// - /// Gets a value indicating whether is scan all projects enabled via . - /// Get this data using . - /// - /// representing the asynchronous operation. - public async Task IsScanAllProjectsAsync() => await this.userStorageSettingsService.GetIsAllProjectsEnabledAsync(); - - /// - /// Initialize . - /// - /// Snyk service provider. - public void Initialize(ISnykServiceProvider provider) - { - this.serviceProvider = provider; - SettingsChanged += SnykGeneralOptionsDialogPage_SettingsChanged; - this.userStorageSettingsService = this.serviceProvider.UserStorageSettingsService; - } - private void SnykGeneralOptionsDialogPage_SettingsChanged(object sender, SnykSettingsChangedEventArgs e) { ThreadHelper.JoinableTaskFactory.RunAsync(async () => { if (LanguageClientHelper.IsLanguageServerReady()) { - await ServiceProvider.LanguageClientManager.DidChangeConfigurationAsync(SnykVSPackage + await serviceProvider.LanguageClientManager.DidChangeConfigurationAsync(SnykVSPackage .Instance.DisposalToken); - if (AutoScan) - await ServiceProvider.LanguageClientManager.InvokeWorkspaceScanAsync(SnykVSPackage + if (this.SnykOptions.AutoScan) + await serviceProvider.LanguageClientManager.InvokeWorkspaceScanAsync(SnykVSPackage .Instance.DisposalToken); } }).FireAndForget(); } - /// public void Authenticate() { Logger.Information("Enter Authenticate method"); - if (!SnykCli.IsCliFileFound(this.CliCustomPath)) + if (!SnykCli.IsCliFileFound(this.SnykOptions.CliCustomPath)) { - ThrowFileNotFoundException(); + throw new FileNotFoundException("CLI not found"); } try { @@ -496,16 +143,16 @@ public void Authenticate() Logger.Error("Language Server is not initialized yet."); return; } - if (ApiToken.IsValid()) + if (this.SnykOptions.ApiToken.IsValid()) return; - + Logger.Information("Api token is invalid. Attempting to authenticate via snyk auth"); ThreadHelper.JoinableTaskFactory.RunAsync(async () => { - await ServiceProvider.LanguageClientManager.InvokeLogout(SnykVSPackage.Instance + await serviceProvider.LanguageClientManager.InvokeLogout(SnykVSPackage.Instance .DisposalToken); - await ServiceProvider.LanguageClientManager.InvokeLogin(SnykVSPackage.Instance + await serviceProvider.LanguageClientManager.InvokeLogin(SnykVSPackage.Instance .DisposalToken); }).FireAndForget(); @@ -521,28 +168,5 @@ await ServiceProvider.LanguageClientManager.InvokeLogin(SnykVSPackage.Instance } } - public void FireSettingsChangedEvent() => this.SettingsChanged?.Invoke(this, new SnykSettingsChangedEventArgs()); - - public string GetCustomApiEndpoint() - { - return string.IsNullOrEmpty(CustomEndpoint) ? ApiEndpointResolver.DefaultApiEndpoint : ApiEndpointResolver.TranslateOldApiToNewApiEndpoint(CustomEndpoint); - } - - public string GetBaseAppUrl() - { - if (string.IsNullOrEmpty(CustomEndpoint)) - return ApiEndpointResolver.DefaultAppEndpoint; - - var result = ApiEndpointResolver.GetCustomEndpointUrlFromSnykApi(GetCustomApiEndpoint(), "app"); - - return string.IsNullOrEmpty(result) ? ApiEndpointResolver.DefaultAppEndpoint : result; - } - - private void ThrowFileNotFoundException() - { - const string cliNotFound = "CLI not found"; - Logger.Information(cliNotFound); - throw new FileNotFoundException(cliNotFound); - } } } diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.Designer.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.Designer.cs index b4fbf67e2..0de34f581 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.Designer.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.Designer.cs @@ -86,12 +86,14 @@ private void InitializeComponent() this.cliReleaseChannelLabel = new System.Windows.Forms.Label(); this.cliBaseDownloadUrl = new System.Windows.Forms.Label(); this.cliDownloadUrlTextBox = new System.Windows.Forms.TextBox(); + this.mainPanel = new System.Windows.Forms.Panel(); ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit(); this.generalSettingsGroupBox.SuspendLayout(); this.productSelectionGroupBox.SuspendLayout(); this.ignoreGroupbox.SuspendLayout(); this.userExperienceGroupBox.SuspendLayout(); this.ExecutablesGroupBox.SuspendLayout(); + this.mainPanel.SuspendLayout(); this.SuspendLayout(); // // customEndpointTextBox @@ -234,7 +236,7 @@ private void InitializeComponent() this.generalSettingsGroupBox.Controls.Add(this.organizationLabel); this.generalSettingsGroupBox.Controls.Add(this.ignoreUnknownCACheckBox); this.generalSettingsGroupBox.Controls.Add(this.organizationTextBox); - this.generalSettingsGroupBox.Location = new System.Drawing.Point(13, 12); + this.generalSettingsGroupBox.Location = new System.Drawing.Point(29, 10); this.generalSettingsGroupBox.Margin = new System.Windows.Forms.Padding(11, 10, 11, 10); this.generalSettingsGroupBox.Name = "generalSettingsGroupBox"; this.generalSettingsGroupBox.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2); @@ -391,7 +393,7 @@ private void InitializeComponent() this.productSelectionGroupBox.Controls.Add(this.codeQualityEnabledCheckBox); this.productSelectionGroupBox.Controls.Add(this.ossEnabledCheckBox); this.productSelectionGroupBox.Controls.Add(this.codeSecurityEnabledCheckBox); - this.productSelectionGroupBox.Location = new System.Drawing.Point(13, 711); + this.productSelectionGroupBox.Location = new System.Drawing.Point(29, 709); this.productSelectionGroupBox.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.productSelectionGroupBox.Name = "productSelectionGroupBox"; this.productSelectionGroupBox.Padding = new System.Windows.Forms.Padding(11, 10, 11, 10); @@ -571,7 +573,7 @@ private void InitializeComponent() // userExperienceGroupBox // this.userExperienceGroupBox.Controls.Add(this.autoScanCheckBox); - this.userExperienceGroupBox.Location = new System.Drawing.Point(13, 957); + this.userExperienceGroupBox.Location = new System.Drawing.Point(29, 955); this.userExperienceGroupBox.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.userExperienceGroupBox.Name = "userExperienceGroupBox"; this.userExperienceGroupBox.Padding = new System.Windows.Forms.Padding(11, 10, 11, 10); @@ -627,7 +629,7 @@ private void InitializeComponent() this.ExecutablesGroupBox.Controls.Add(this.CliPathBrowseButton); this.ExecutablesGroupBox.Controls.Add(this.ManageBinariesAutomaticallyCheckbox); this.ExecutablesGroupBox.Controls.Add(this.CliPathTextBox); - this.ExecutablesGroupBox.Location = new System.Drawing.Point(13, 428); + this.ExecutablesGroupBox.Location = new System.Drawing.Point(29, 426); this.ExecutablesGroupBox.Margin = new System.Windows.Forms.Padding(4); this.ExecutablesGroupBox.Name = "ExecutablesGroupBox"; this.ExecutablesGroupBox.Padding = new System.Windows.Forms.Padding(4); @@ -683,15 +685,25 @@ private void InitializeComponent() this.cliDownloadUrlTextBox.Size = new System.Drawing.Size(399, 22); this.cliDownloadUrlTextBox.TabIndex = 21; // + // mainPanel + // + this.mainPanel.AutoScroll = true; + this.mainPanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.mainPanel.Controls.Add(this.generalSettingsGroupBox); + this.mainPanel.Controls.Add(this.ExecutablesGroupBox); + this.mainPanel.Controls.Add(this.productSelectionGroupBox); + this.mainPanel.Controls.Add(this.userExperienceGroupBox); + this.mainPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.mainPanel.Location = new System.Drawing.Point(0, 0); + this.mainPanel.Name = "mainPanel"; + this.mainPanel.Size = new System.Drawing.Size(1060, 1041); + this.mainPanel.TabIndex = 20; + // // SnykGeneralSettingsUserControl // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoScroll = true; - this.Controls.Add(this.ExecutablesGroupBox); - this.Controls.Add(this.userExperienceGroupBox); - this.Controls.Add(this.productSelectionGroupBox); - this.Controls.Add(this.generalSettingsGroupBox); + this.Controls.Add(this.mainPanel); this.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.MinimumSize = new System.Drawing.Size(1060, 923); this.Name = "SnykGeneralSettingsUserControl"; @@ -707,6 +719,7 @@ private void InitializeComponent() this.userExperienceGroupBox.PerformLayout(); this.ExecutablesGroupBox.ResumeLayout(false); this.ExecutablesGroupBox.PerformLayout(); + this.mainPanel.ResumeLayout(false); this.ResumeLayout(false); } @@ -765,5 +778,6 @@ private void InitializeComponent() private Label label3; private ComboBox cbDelta; private Label label4; + private Panel mainPanel; } } diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.cs index cfd02ea63..0c4eb93e6 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; @@ -25,39 +24,40 @@ namespace Snyk.VisualStudio.Extension.Settings /// public partial class SnykGeneralSettingsUserControl : UserControl { - private static readonly ILogger logger = LogManager.ForContext(); + private readonly ISnykServiceProvider serviceProvider; + private static readonly ILogger Logger = LogManager.ForContext(); /// /// Instance of SnykGeneralOptionsDialogPage. /// - [SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:FieldsMustBePrivate", Justification = "Reviewed.")] - internal SnykGeneralOptionsDialogPage OptionsDialogPage; + private readonly ISnykOptions snykOptions; private static readonly int TwoSecondsDelay = 2000; - private static readonly int MaxSastRequestAttempts = 20; + private const int MaxSastRequestAttempts = 20; - private Timer snykCodeEnableTimer = new Timer(); + private readonly Timer snykCodeEnableTimer = new Timer(); /// /// Initializes a new instance of the class. /// - /// Snyk API service instance. - public SnykGeneralSettingsUserControl() + /// + public SnykGeneralSettingsUserControl(ISnykServiceProvider serviceProvider) { + this.serviceProvider = serviceProvider; + snykOptions = this.serviceProvider.Options; this.InitializeComponent(); + this.Initialize(); } - - private ISnykServiceProvider ServiceProvider => this.OptionsDialogPage.ServiceProvider; - + /// /// Initialize elements and actions. /// - public void Initialize() + private void Initialize() { - logger.Information("Enter Initialize method"); + Logger.Information("Enter Initialize method"); this.UpdateViewFromOptionsDialog(); - this.OptionsDialogPage.SettingsChanged += this.OptionsDialogPageOnSettingsChanged; + snykOptions.SettingsChanged += this.OptionsDialogPageOnSettingsChanged; this.Load += this.SnykGeneralSettingsUserControl_Load; if (LanguageClientHelper.LanguageClientManager() != null) @@ -65,8 +65,8 @@ public void Initialize() LanguageClientHelper.LanguageClientManager().OnLanguageClientNotInitializedAsync += OnOnLanguageClientNotInitializedAsync; LanguageClientHelper.LanguageClientManager().OnLanguageServerReadyAsync += OnOnLanguageServerReadyAsync; } - this.ServiceProvider.ToolWindow.Show(); - logger.Information("Leave Initialize method"); + this.serviceProvider.ToolWindow.Show(); + Logger.Information("Leave Initialize method"); } private async Task OnOnLanguageServerReadyAsync(object sender, SnykLanguageServerEventArgs args) @@ -84,21 +84,21 @@ private async Task OnOnLanguageClientNotInitializedAsync(object sender, SnykLang private void UpdateViewFromOptionsDialog() { this.authenticateButton.Enabled = LanguageClientHelper.IsLanguageServerReady(); - this.customEndpointTextBox.Text = this.OptionsDialogPage.CustomEndpoint; - this.organizationTextBox.Text = this.OptionsDialogPage.Organization; - this.ignoreUnknownCACheckBox.Checked = this.OptionsDialogPage.IgnoreUnknownCA; - this.ossEnabledCheckBox.Checked = this.OptionsDialogPage.OssEnabled; - this.iacEnabledCheckbox.Checked = this.OptionsDialogPage.IacEnabled; - this.ManageBinariesAutomaticallyCheckbox.Checked = this.OptionsDialogPage.BinariesAutoUpdate; - this.autoScanCheckBox.Checked = this.OptionsDialogPage.AutoScan; - this.cliDownloadUrlTextBox.Text = this.OptionsDialogPage.CliDownloadUrl; - this.tokenTextBox.Text = this.OptionsDialogPage.ApiToken.ToString(); - this.cbIgnoredIssues.Checked = this.OptionsDialogPage.IgnoredIssuesEnabled; - this.cbOpenIssues.Checked = this.OptionsDialogPage.OpenIssuesEnabled; - - var cliPath = string.IsNullOrEmpty(this.OptionsDialogPage.CliCustomPath) + this.customEndpointTextBox.Text = snykOptions.CustomEndpoint; + this.organizationTextBox.Text = snykOptions.Organization; + this.ignoreUnknownCACheckBox.Checked = snykOptions.IgnoreUnknownCA; + this.ossEnabledCheckBox.Checked = snykOptions.OssEnabled; + this.iacEnabledCheckbox.Checked = snykOptions.IacEnabled; + this.ManageBinariesAutomaticallyCheckbox.Checked = snykOptions.BinariesAutoUpdate; + this.autoScanCheckBox.Checked = snykOptions.AutoScan; + this.cliDownloadUrlTextBox.Text = snykOptions.CliDownloadUrl; + this.tokenTextBox.Text = snykOptions.ApiToken.ToString(); + this.cbIgnoredIssues.Checked = snykOptions.IgnoredIssuesEnabled; + this.cbOpenIssues.Checked = snykOptions.OpenIssuesEnabled; + + var cliPath = string.IsNullOrEmpty(snykOptions.CliCustomPath) ? SnykCli.GetSnykCliDefaultPath() - : this.OptionsDialogPage.CliCustomPath; + : snykOptions.CliCustomPath; this.CliPathTextBox.Text = cliPath; if (releaseChannel.DataSource == null) @@ -118,11 +118,12 @@ private void UpdateViewFromOptionsDialog() this.authType.ValueMember = "Value"; } - this.releaseChannel.SelectedItem = this.OptionsDialogPage.CliReleaseChannel; - this.authType.SelectedValue = this.OptionsDialogPage.AuthenticationMethod; - this.cbDelta.SelectedItem = this.OptionsDialogPage.EnableDeltaFindings ? "Net new issues" : "All issues"; + this.releaseChannel.SelectedItem = snykOptions.CliReleaseChannel; + this.authType.SelectedValue = snykOptions.AuthenticationMethod; + this.cbDelta.SelectedItem = snykOptions.EnableDeltaFindings ? "Net new issues" : "All issues"; } + private IEnumerable AuthenticationMethodList() { return Enum.GetValues(typeof(AuthenticationType)) @@ -138,9 +139,9 @@ private IEnumerable AuthenticationMethodList() private IEnumerable ReleaseChannelList() { var defaultList = new List() { "stable", "rc", "preview" }; - if (!defaultList.Contains(this.OptionsDialogPage.CliReleaseChannel)) + if (!defaultList.Contains(snykOptions.CliReleaseChannel)) { - defaultList.Add(this.OptionsDialogPage.CliReleaseChannel); + defaultList.Add(snykOptions.CliReleaseChannel); } return defaultList; } @@ -160,7 +161,7 @@ private void OptionsDialogPageOnSettingsChanged(object sender, SnykSettingsChang public async Task HandleAuthenticationSuccess(string apiToken, string apiUrl) { - logger.Information("Enter authenticate successCallback"); + Logger.Information("Enter authenticate successCallback"); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); AuthDialogWindow.Instance.Hide(); @@ -188,7 +189,7 @@ public async Task HandleAuthenticationSuccess(string apiToken, string apiUrl) })); } - await this.ServiceProvider.ToolWindow.UpdateScreenStateAsync(); + await this.serviceProvider.ToolWindow.UpdateScreenStateAsync(); } public void InvalidateApiToken() @@ -197,13 +198,13 @@ public void InvalidateApiToken() if(LanguageClientHelper.IsLanguageServerReady()) ThreadHelper.JoinableTaskFactory.RunAsync(async () => { - await ServiceProvider.LanguageClientManager.InvokeLogout(SnykVSPackage.Instance.DisposalToken); + await serviceProvider.LanguageClientManager.InvokeLogout(SnykVSPackage.Instance.DisposalToken); }).FireAndForget(); } public async Task HandleFailedAuthentication(string errorMessage) { - logger.Information("Enter authenticate errorCallback"); + Logger.Information("Enter authenticate errorCallback"); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); AuthDialogWindow.Instance.Hide(); @@ -215,11 +216,11 @@ public async Task HandleFailedAuthentication(string errorMessage) Path = string.Empty, }; - this.ServiceProvider.TasksService.FireOssError(ossError); + this.serviceProvider.TasksService.FireOssError(ossError); - this.ServiceProvider.ToolWindow.Show(); + this.serviceProvider.ToolWindow.Show(); - await this.ServiceProvider.ToolWindow.UpdateScreenStateAsync(); + await this.serviceProvider.ToolWindow.UpdateScreenStateAsync(); } private void AuthenticateButton_Click(object sender, EventArgs eventArgs) => ThreadHelper.JoinableTaskFactory @@ -227,20 +228,19 @@ private void AuthenticateButton_Click(object sender, EventArgs eventArgs) => Thr private async Task AuthenticateButtonClickAsync() { - logger.Information("Enter authenticateButton_Click method"); - logger.Information("Start run task"); + Logger.Information("Enter authenticateButton_Click method"); + Logger.Information("Start run task"); await TaskScheduler.Default; - var serviceProvider = this.ServiceProvider; if (SnykCli.IsCliFileFound(serviceProvider.Options.CliCustomPath)) { - serviceProvider.Options.Authenticate(); + serviceProvider.GeneralOptionsDialogPage.Authenticate(); } else { - logger.Information("CLI doesn't exists. Download CLI before get Api token"); - await serviceProvider.TasksService.DownloadAsync(() => this.OptionsDialogPage.Authenticate()); + Logger.Information("CLI doesn't exists. Download CLI before get Api token"); + await serviceProvider.TasksService.DownloadAsync(serviceProvider.GeneralOptionsDialogPage.Authenticate); } } @@ -250,7 +250,7 @@ private void TokenTextBox_TextChanged(object sender, EventArgs e) { if (this.ValidateChildren(ValidationConstraints.Enabled)) { - this.OptionsDialogPage.ApiToken = new AuthenticationToken(this.OptionsDialogPage.AuthenticationMethod, this.tokenTextBox.Text); + snykOptions.ApiToken = new AuthenticationToken(snykOptions.AuthenticationMethod, this.tokenTextBox.Text); } } @@ -258,19 +258,19 @@ private void CustomEndpointTextBox_LostFocus(object sender, EventArgs e) { if (this.ValidateChildren(ValidationConstraints.Enabled)) { - this.OptionsDialogPage.CustomEndpoint = this.customEndpointTextBox.Text; + snykOptions.CustomEndpoint = this.customEndpointTextBox.Text; } } private void IgnoreUnknownCACheckBox_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.IgnoreUnknownCA = this.ignoreUnknownCACheckBox.Checked; + snykOptions.IgnoreUnknownCA = this.ignoreUnknownCACheckBox.Checked; } private void TokenTextBox_Validating(object sender, CancelEventArgs cancelEventArgs) => ThreadHelper.JoinableTaskFactory.RunAsync(async () => { - await this.ServiceProvider.ToolWindow.UpdateScreenStateAsync(); + await this.serviceProvider.ToolWindow.UpdateScreenStateAsync(); if (string.IsNullOrEmpty(this.tokenTextBox.Text)) { @@ -332,10 +332,10 @@ private void CheckForIgnores() { ThreadHelper.JoinableTaskFactory.RunAsync(async () => { - if (!OptionsDialogPage.ConsistentIgnoresEnabled && LanguageClientHelper.IsLanguageServerReady()) - await ServiceProvider.FeatureFlagService.RefreshAsync(SnykVSPackage.Instance.DisposalToken); + if (!snykOptions.ConsistentIgnoresEnabled && LanguageClientHelper.IsLanguageServerReady()) + await serviceProvider.FeatureFlagService.RefreshAsync(SnykVSPackage.Instance.DisposalToken); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); - this.ignoreGroupbox.Visible = this.OptionsDialogPage.ConsistentIgnoresEnabled; + this.ignoreGroupbox.Visible = snykOptions.ConsistentIgnoresEnabled; }).FireAndForget(); } private void StartSastEnablementCheckLoop() @@ -356,7 +356,7 @@ private void StartSastEnablementCheckLoop() try { if (!LanguageClientHelper.IsLanguageServerReady()) return; - var sastSettings = await this.ServiceProvider.LanguageClientManager.InvokeGetSastEnabled(SnykVSPackage.Instance.DisposalToken); + var sastSettings = await this.serviceProvider.LanguageClientManager.InvokeGetSastEnabled(SnykVSPackage.Instance.DisposalToken); bool snykCodeEnabled = sastSettings != null ? sastSettings.SnykCodeEnabled : false; @@ -407,21 +407,21 @@ private void HandleSastError(Exception e) private void OssEnabledCheckBox_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.OssEnabled = this.ossEnabledCheckBox.Checked; + snykOptions.OssEnabled = this.ossEnabledCheckBox.Checked; } private void CodeSecurityEnabledCheckBox_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.SnykCodeSecurityEnabled = this.codeSecurityEnabledCheckBox.Checked; + snykOptions.SnykCodeSecurityEnabled = this.codeSecurityEnabledCheckBox.Checked; } private void CodeQualityEnabledCheckBox_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.SnykCodeQualityEnabled = this.codeQualityEnabledCheckBox.Checked; + snykOptions.SnykCodeQualityEnabled = this.codeQualityEnabledCheckBox.Checked; } private void SnykCodeSettingsLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - => Process.Start(this.OptionsDialogPage.SnykCodeSettingsUrl); + => Process.Start(snykOptions.SnykCodeSettingsUrl); private void CheckAgainLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { @@ -445,8 +445,8 @@ private void CliPathBrowseButton_Click(object sender, EventArgs e) private void SetCliCustomPathValue(string selectedCliPath) { - this.OptionsDialogPage.CliCustomPath = selectedCliPath; - this.CliPathTextBox.Text = string.IsNullOrEmpty(this.OptionsDialogPage.CliCustomPath) + snykOptions.CliCustomPath = selectedCliPath; + this.CliPathTextBox.Text = string.IsNullOrEmpty(snykOptions.CliCustomPath) ? SnykCli.GetSnykCliDefaultPath() : selectedCliPath; } @@ -458,17 +458,18 @@ private void ClearCliCustomPathButton_Click(object sender, EventArgs e) private void authType_SelectionChangeCommitted(object sender, EventArgs e) { - this.OptionsDialogPage.AuthenticationMethod = (AuthenticationType)authType.SelectedValue; + snykOptions.AuthenticationMethod = (AuthenticationType)authType.SelectedValue; + InvalidateApiToken(); } private void autoScanCheckBox_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.AutoScan = autoScanCheckBox.Checked; + snykOptions.AutoScan = autoScanCheckBox.Checked; } private void iacEnabledCheckbox_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.IacEnabled = iacEnabledCheckbox.Checked; + snykOptions.IacEnabled = iacEnabledCheckbox.Checked; } public string GetReleaseChannel() @@ -494,19 +495,24 @@ private void ReleaseChannelLink_LinkClicked(object sender, LinkLabelLinkClickedE private void cbOpenIssues_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.OpenIssuesEnabled = this.cbOpenIssues.Checked; + snykOptions.OpenIssuesEnabled = this.cbOpenIssues.Checked; } private void cbIgnoredIssues_CheckedChanged(object sender, EventArgs e) { - this.OptionsDialogPage.IgnoredIssuesEnabled = this.cbIgnoredIssues.Checked; + snykOptions.IgnoredIssuesEnabled = this.cbIgnoredIssues.Checked; } private void cbDelta_SelectionChangeCommitted(object sender, EventArgs e) { if (this.cbDelta.SelectedItem == null) return; var enableDelta = this.cbDelta.SelectedItem.ToString() == "Net new issues"; - this.OptionsDialogPage.EnableDeltaFindings = enableDelta; + snykOptions.EnableDeltaFindings = enableDelta; + } + + public Panel GetPanel() + { + return this.mainPanel; } } } diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.resx b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.resx index 86b2d89c1..e89510c3e 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.resx +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykGeneralSettingsUserControl.resx @@ -133,6 +133,9 @@ 140, 17 + + 477, 17 + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO @@ -142,8 +145,8 @@ jZZtldeAJuTjx7SYAQYQKn7xnCU8ABJO2R9gGis+AAAAAElFTkSuQmCC - - 477, 17 + + 270, 17 @@ -154,9 +157,6 @@ jZZtldeAJuTjx7SYAQYQKn7xnCU8ABJO2R9gGis+AAAAAElFTkSuQmCC - - 270, 17 - iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO @@ -166,6 +166,12 @@ jZZtldeAJuTjx7SYAQYQKn7xnCU8ABJO2R9gGis+AAAAAElFTkSuQmCC + + 270, 17 + + + 477, 17 + 680, 17 diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykOptions.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykOptions.cs new file mode 100644 index 000000000..6be2f72b4 --- /dev/null +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykOptions.cs @@ -0,0 +1,363 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Serilog; +using Snyk.VisualStudio.Extension.Authentication; +using Snyk.VisualStudio.Extension.Language; +using Snyk.VisualStudio.Extension.Service; + +namespace Snyk.VisualStudio.Extension.Settings +{ + public class SnykOptions : ISnykOptions + { + private readonly ISnykServiceProvider serviceProvider; + private readonly IUserStorageSettingsService userStorageSettingsService; + private static readonly ILogger Logger = LogManager.ForContext(); + + public SnykOptions(ISnykServiceProvider provider) + { + this.serviceProvider = provider; + this.userStorageSettingsService = this.serviceProvider.UserStorageSettingsService; + } + + public string Application { get; set; } + public string ApplicationVersion { get; set; } + public string IntegrationName { get; } = SnykExtension.IntegrationName; + public string IntegrationVersion { get; } = SnykExtension.Version; + public string IntegrationEnvironment { get; set; } + public string IntegrationEnvironmentVersion { get; set; } + + public string DeviceId + { + get => this.userStorageSettingsService.DeviceId; + set => this.userStorageSettingsService.DeviceId = value; + } + + public bool AutoScan + { + get => this.userStorageSettingsService.AutoScan; + set + { + if (this.userStorageSettingsService == null) + return; + this.userStorageSettingsService.AutoScan = value; + } + } + + 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; + } + } + + public AuthenticationToken ApiToken + { + get => new AuthenticationToken(this.AuthenticationMethod, this.userStorageSettingsService.Token); + set + { + var tokenAsString = value.ToString(); + if (this.userStorageSettingsService == null || this.userStorageSettingsService.Token == tokenAsString) + return; + this.userStorageSettingsService.Token = tokenAsString; + userStorageSettingsService.SaveSettings(); + InvokeSettingsChangedEvent(); + } + } + + public AuthenticationType AuthenticationMethod + { + get => this.userStorageSettingsService.AuthenticationMethod; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.AuthenticationMethod == value) + return; + this.userStorageSettingsService.AuthenticationMethod = value; + ApiToken = AuthenticationToken.EmptyToken; + userStorageSettingsService.SaveSettings(); + InvokeSettingsChangedEvent(); + } + } + public string CustomEndpoint + { + get => this.userStorageSettingsService.CustomEndpoint; + set + { + if (!Uri.IsWellFormedUriString(value, UriKind.Absolute)) + { + Logger.Warning("Custom endpoint value is not a well-formed URI. Setting custom endpoint to empty string"); + value = string.Empty; + } + + var newApiEndpoint = ApiEndpointResolver.TranslateOldApiToNewApiEndpoint(value); + if (this.userStorageSettingsService == null || this.userStorageSettingsService.CustomEndpoint == newApiEndpoint) + { + return; + } + + this.userStorageSettingsService.CustomEndpoint = newApiEndpoint; + ApiToken = AuthenticationToken.EmptyToken; + userStorageSettingsService.SaveSettings(); + InvokeSettingsChangedEvent(); + } + } + public string SnykCodeSettingsUrl => $"{this.GetBaseAppUrl()}/manage/snyk-code"; + + /// + /// Gets or sets a value indicating whether organization. + /// + public string Organization + { + get => this.userStorageSettingsService.Organization; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.Organization == value) + { + return; + } + this.userStorageSettingsService.Organization = value; + userStorageSettingsService.SaveSettings(); + InvokeSettingsChangedEvent(); + } + } + /// + /// Gets or sets a value indicating whether ignore unknown CA. + /// + public bool IgnoreUnknownCA + { + get => this.userStorageSettingsService.IgnoreUnknownCa; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.IgnoreUnknownCa == value) + { + return; + } + this.userStorageSettingsService.IgnoreUnknownCa = value; + userStorageSettingsService.SaveSettings(); + InvokeSettingsChangedEvent(); + } + } + /// + public bool OssEnabled + { + get => this.userStorageSettingsService.OssEnabled; + set + { + if (this.userStorageSettingsService == null || userStorageSettingsService.OssEnabled == value) + { + return; + } + + this.userStorageSettingsService.OssEnabled = value; + } + } + + public bool IacEnabled + { + get => this.userStorageSettingsService.IacEnabled; + set + { + if (this.userStorageSettingsService == null || userStorageSettingsService.IacEnabled == value) + { + return; + } + + this.userStorageSettingsService.IacEnabled = value; + } + } + public bool SnykCodeSecurityEnabled + { + get => this.userStorageSettingsService.SnykCodeSecurityEnabled; + set + { + if (this.userStorageSettingsService == null || userStorageSettingsService.SnykCodeSecurityEnabled == value) + { + return; + } + + this.userStorageSettingsService.SnykCodeSecurityEnabled = value; + } + } + + /// + public bool SnykCodeQualityEnabled + { + get => this.userStorageSettingsService.SnykCodeQualityEnabled; + set + { + if (this.userStorageSettingsService == null || userStorageSettingsService.SnykCodeQualityEnabled == value) + { + return; + } + + this.userStorageSettingsService.SnykCodeQualityEnabled = value; + } + } + + public bool BinariesAutoUpdate + { + get => this.userStorageSettingsService.BinariesAutoUpdate; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.BinariesAutoUpdate == value) + { + return; + } + this.userStorageSettingsService.BinariesAutoUpdate = value; + } + } + + public string CliCustomPath + { + get => this.userStorageSettingsService.CliCustomPath; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliCustomPath == value) + { + return; + } + this.userStorageSettingsService.CliCustomPath = value; + } + } + + public string CliReleaseChannel + { + get => this.userStorageSettingsService.CliReleaseChannel; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliReleaseChannel == value) + { + return; + } + this.userStorageSettingsService.CliReleaseChannel = value; + } + } + public string CliDownloadUrl + { + get => this.userStorageSettingsService.CliDownloadUrl; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliDownloadUrl == value) + { + return; + } + this.userStorageSettingsService.CliDownloadUrl = value; + } + } + + public ISet TrustedFolders + { + get => this.userStorageSettingsService.TrustedFolders; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.TrustedFolders == value) + return; + this.userStorageSettingsService.TrustedFolders = value; + } + } + + public bool EnableDeltaFindings + { + get => this.userStorageSettingsService.EnableDeltaFindings; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.EnableDeltaFindings == value) + return; + this.userStorageSettingsService.EnableDeltaFindings = value; + userStorageSettingsService.SaveSettings(); + } + } + + public List FolderConfigs + { + get => this.userStorageSettingsService.FolderConfigs; + set + { + if (this.userStorageSettingsService == null) + return; + this.userStorageSettingsService.FolderConfigs = value; + userStorageSettingsService.SaveSettings(); + this.SettingsChanged?.Invoke(this, new SnykSettingsChangedEventArgs()); + } + } + + public event EventHandler SettingsChanged; + + /// + /// Gets a value indicating whether additional options. + /// Get this data using . + /// + /// representing the asynchronous operation. + public async Task GetAdditionalOptionsAsync() => await this.serviceProvider.UserStorageSettingsService.GetAdditionalOptionsAsync(); + + /// + /// Gets a value indicating whether is scan all projects enabled via . + /// Get this data using . + /// + /// representing the asynchronous operation. + public async Task IsScanAllProjectsAsync() => await this.userStorageSettingsService.GetIsAllProjectsEnabledAsync(); + + + public string CurrentCliVersion + { + get => this.userStorageSettingsService.CurrentCliVersion; + set + { + if (this.userStorageSettingsService == null || this.userStorageSettingsService.CurrentCliVersion == value) + { + return; + } + this.userStorageSettingsService.CurrentCliVersion = value; + } + } + + public SastSettings SastSettings { get; set; } + + public bool AnalyticsPluginInstalledSent + { + get => this.userStorageSettingsService.AnalyticsPluginInstalledSent; + set => this.userStorageSettingsService.AnalyticsPluginInstalledSent = value; + } + + public void InvokeSettingsChangedEvent() + { + this.SettingsChanged?.Invoke(this, new SnykSettingsChangedEventArgs()); + } + + public string GetCustomApiEndpoint() + { + return string.IsNullOrEmpty(CustomEndpoint) ? ApiEndpointResolver.DefaultApiEndpoint : ApiEndpointResolver.TranslateOldApiToNewApiEndpoint(CustomEndpoint); + } + + public string GetBaseAppUrl() + { + if (string.IsNullOrEmpty(CustomEndpoint)) + return ApiEndpointResolver.DefaultAppEndpoint; + + var result = ApiEndpointResolver.GetCustomEndpointUrlFromSnykApi(GetCustomApiEndpoint(), "app"); + + return string.IsNullOrEmpty(result) ? ApiEndpointResolver.DefaultAppEndpoint : result; + } + + public void SaveSettings() + { + this.userStorageSettingsService.SaveSettings(); + } + } +} diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsDialogPage.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsDialogPage.cs index 0c09273e5..1bda1a112 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsDialogPage.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsDialogPage.cs @@ -1,9 +1,9 @@ -namespace Snyk.VisualStudio.Extension.Settings -{ - using System.Runtime.InteropServices; - using System.Windows.Forms; - using Microsoft.VisualStudio.Shell; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using Microsoft.VisualStudio.Shell; +namespace Snyk.VisualStudio.Extension.Settings +{ /// /// Snyk dialog page for project Options. /// diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.Designer.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.Designer.cs index 3c46e581c..2c7ff8ffb 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.Designer.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.Designer.cs @@ -39,12 +39,11 @@ private void InitializeComponent() // this.additionalOptionsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.additionalOptionsTextBox.Location = new System.Drawing.Point(13, 22); - this.additionalOptionsTextBox.Margin = new System.Windows.Forms.Padding(4); + this.additionalOptionsTextBox.Location = new System.Drawing.Point(9, 14); this.additionalOptionsTextBox.Multiline = true; this.additionalOptionsTextBox.Name = "additionalOptionsTextBox"; this.additionalOptionsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; - this.additionalOptionsTextBox.Size = new System.Drawing.Size(1220, 223); + this.additionalOptionsTextBox.Size = new System.Drawing.Size(725, 144); this.additionalOptionsTextBox.TabIndex = 0; this.additionalOptionsTextBox.TextChanged += new System.EventHandler(this.AdditionalOptionsTextBox_TextChanged); // @@ -53,9 +52,10 @@ private void InitializeComponent() this.allProjectsCheckBox.AutoSize = true; this.allProjectsCheckBox.Checked = true; this.allProjectsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; - this.allProjectsCheckBox.Location = new System.Drawing.Point(13, 253); + this.allProjectsCheckBox.Location = new System.Drawing.Point(9, 162); + this.allProjectsCheckBox.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); this.allProjectsCheckBox.Name = "allProjectsCheckBox"; - this.allProjectsCheckBox.Size = new System.Drawing.Size(407, 29); + this.allProjectsCheckBox.Size = new System.Drawing.Size(253, 20); this.allProjectsCheckBox.TabIndex = 1; this.allProjectsCheckBox.Text = "Scan all projects (--all-projects option)"; this.allProjectsCheckBox.UseVisualStyleBackColor = true; @@ -65,17 +65,16 @@ private void InitializeComponent() // this.errorProvider.ContainerControl = this; // - // SnykProjectOptionsUserControl + // SnykSolutionOptionsUserControl // - this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.Controls.Add(this.allProjectsCheckBox); this.Controls.Add(this.additionalOptionsTextBox); - this.Margin = new System.Windows.Forms.Padding(4); - this.Name = "SnykProjectOptionsUserControl"; - this.Padding = new System.Windows.Forms.Padding(7, 6, 7, 6); - this.Size = new System.Drawing.Size(1274, 509); + this.Name = "SnykSolutionOptionsUserControl"; + this.Padding = new System.Windows.Forms.Padding(5, 4, 5, 4); + this.Size = new System.Drawing.Size(1175, 326); this.Load += new System.EventHandler(this.SnykProjectOptionsUserControl_Load); ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit(); this.ResumeLayout(false); diff --git a/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.cs b/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.cs index a69304438..2d6ba8a08 100644 --- a/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.cs +++ b/Snyk.VisualStudio.Extension.2022/Settings/SnykSolutionOptionsUserControl.cs @@ -47,7 +47,7 @@ private void AdditionalOptionsTextBox_TextChanged(object sender, EventArgs e) { if (this.serviceProvider.SolutionService.IsSolutionOpen()) { - string additionalOptions = this.additionalOptionsTextBox.Text.ToString(); + string additionalOptions = this.additionalOptionsTextBox.Text; this.userStorageSettingsService.SaveAdditionalOptionsAsync(additionalOptions).FireAndForget(); @@ -59,7 +59,7 @@ private void AllProjectsCheckBox_CheckedChanged(object sender, EventArgs e) { if (this.serviceProvider.SolutionService.IsSolutionOpen()) { - this.userStorageSettingsService.SaveIsAllProjectsScanEnabledAsync(this.allProjectsCheckBox.Checked).FireAndForget(); ; + this.userStorageSettingsService.SaveIsAllProjectsScanEnabledAsync(this.allProjectsCheckBox.Checked).FireAndForget(); this.CheckOptionConflicts(); } diff --git a/Snyk.VisualStudio.Extension.2022/Snyk.VisualStudio.Extension.2022.csproj b/Snyk.VisualStudio.Extension.2022/Snyk.VisualStudio.Extension.2022.csproj index c7378dbdb..cd30bc4d9 100644 --- a/Snyk.VisualStudio.Extension.2022/Snyk.VisualStudio.Extension.2022.csproj +++ b/Snyk.VisualStudio.Extension.2022/Snyk.VisualStudio.Extension.2022.csproj @@ -148,6 +148,7 @@ + @@ -159,6 +160,7 @@ SnykGeneralSettingsUserControl.cs + diff --git a/Snyk.VisualStudio.Extension.2022/SnykVSPackage.cs b/Snyk.VisualStudio.Extension.2022/SnykVSPackage.cs index 0ad0205b3..0f0d93b54 100644 --- a/Snyk.VisualStudio.Extension.2022/SnykVSPackage.cs +++ b/Snyk.VisualStudio.Extension.2022/SnykVSPackage.cs @@ -99,6 +99,7 @@ public void SetServiceProvider(ISnykServiceProvider serviceProvider) /// Gets the Options /// public ISnykOptions Options { get; private set; } + public ISnykGeneralOptionsDialogPage SnykGeneralOptionsDialogPage { get; private set; } /// /// Gets instance. @@ -279,17 +280,7 @@ private async Task InitializeGeneralOptionsAsync() { Logger.Information( "Call GetDialogPage to create. await JoinableTaskFactory.SwitchToMainThreadAsync()."); - - await JoinableTaskFactory.SwitchToMainThreadAsync(); - - Logger.Information("GeneralOptionsDialogPage not created yet. Call GetDialogPage to create."); - - Options = - (SnykGeneralOptionsDialogPage) GetDialogPage(typeof(SnykGeneralOptionsDialogPage)); - - Logger.Information("Call generalOptionsDialogPage.Initialize()"); - - Options.Initialize(this.serviceProvider); + Options = new SnykOptions(this.serviceProvider); var readableVsVersion = await this.GetReadableVsVersionAsync(); var vsMajorMinorVersion = await this.GetVsMajorMinorVersionAsync(); Options.Application = readableVsVersion; @@ -297,6 +288,18 @@ private async Task InitializeGeneralOptionsAsync() Options.IntegrationEnvironment = readableVsVersion; Options.IntegrationEnvironmentVersion = vsMajorMinorVersion; } + + if (SnykGeneralOptionsDialogPage == null) + { + await JoinableTaskFactory.SwitchToMainThreadAsync(); + + Logger.Information("GeneralOptionsDialogPage not created yet. Call GetDialogPage to create."); + + SnykGeneralOptionsDialogPage = + (SnykGeneralOptionsDialogPage)GetDialogPage(typeof(SnykGeneralOptionsDialogPage)); + Logger.Information("Call generalOptionsDialogPage.Initialize()"); + SnykGeneralOptionsDialogPage.Initialize(this.serviceProvider); + } } private async Task GetVsVersionAsync() diff --git a/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/MessagePanel.xaml.cs b/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/MessagePanel.xaml.cs index 4a76492f8..bef305cf6 100644 --- a/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/MessagePanel.xaml.cs +++ b/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/MessagePanel.xaml.cs @@ -138,7 +138,7 @@ private async Task RunTestCodeNowAsync() try { this.ServiceProvider.WorkspaceTrustService.AddFolderToTrusted(solutionFolderPath); - this.ServiceProvider.Options.FireSettingsChangedEvent(); + this.ServiceProvider.Options.InvokeSettingsChangedEvent(); Logger.Information("Workspace folder was trusted: {SolutionFolderPath}", solutionFolderPath); } catch (ArgumentException ex) @@ -150,7 +150,7 @@ private async Task RunTestCodeNowAsync() try { - this.ServiceProvider.Options.Authenticate(); + this.ServiceProvider.GeneralOptionsDialogPage.Authenticate(); } catch (FileNotFoundException) { diff --git a/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/SnykToolWindowControl.xaml.cs b/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/SnykToolWindowControl.xaml.cs index 83e7b197a..c920a09d2 100644 --- a/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/SnykToolWindowControl.xaml.cs +++ b/Snyk.VisualStudio.Extension.2022/UI/Toolwindow/SnykToolWindowControl.xaml.cs @@ -748,7 +748,7 @@ private void VulnerabilitiesTree_SelectetVulnerabilityChanged(object sender, Rou new BranchSelectorDialogWindow(serviceProvider).ShowDialog(); return; } - catch (Exception ex) + catch (Exception) { } diff --git a/Snyk.VisualStudio.Extension.Tests/Language/SnykLanguageClientCustomTargetTests.cs b/Snyk.VisualStudio.Extension.Tests/Language/SnykLanguageClientCustomTargetTests.cs index 3cb87b60a..9d68a4e63 100644 --- a/Snyk.VisualStudio.Extension.Tests/Language/SnykLanguageClientCustomTargetTests.cs +++ b/Snyk.VisualStudio.Extension.Tests/Language/SnykLanguageClientCustomTargetTests.cs @@ -19,6 +19,7 @@ public class SnykLanguageClientCustomTargetTests : PackageBaseTest private readonly Mock optionsMock; private readonly Mock userStorageSettingsServiceMock; private readonly Mock languageClientManagerMock; + private readonly Mock generalSettingsPageMock; private readonly SnykLanguageClientCustomTarget cut; public SnykLanguageClientCustomTargetTests(GlobalServiceProvider gsp) : base(gsp) @@ -26,6 +27,7 @@ public SnykLanguageClientCustomTargetTests(GlobalServiceProvider gsp) : base(gsp var serviceProviderMock = new Mock(); tasksServiceMock = new Mock(); optionsMock = new Mock(); + generalSettingsPageMock = new Mock(); userStorageSettingsServiceMock = new Mock(); languageClientManagerMock = new Mock(); @@ -36,6 +38,7 @@ public SnykLanguageClientCustomTargetTests(GlobalServiceProvider gsp) : base(gsp serviceProviderMock.SetupGet(sp => sp.TasksService).Returns(tasksServiceMock.Object); serviceProviderMock.SetupGet(sp => sp.Options).Returns(optionsMock.Object); + serviceProviderMock.SetupGet(sp => sp.GeneralOptionsDialogPage).Returns(generalSettingsPageMock.Object); serviceProviderMock.SetupGet(sp => sp.UserStorageSettingsService).Returns(userStorageSettingsServiceMock.Object); serviceProviderMock.SetupGet(sp => sp.FeatureFlagService).Returns(featureFlagServiceMock.Object); serviceProviderMock.SetupGet(sp => sp.LanguageClientManager).Returns(languageClientManagerMock.Object); @@ -112,13 +115,13 @@ public async Task OnHasAuthenticated_ShouldHandleFailedAuthentication_WhenTokenI { // Arrange var arg = JObject.Parse("{}"); - optionsMock.Setup(o => o.HandleFailedAuthentication(It.IsAny())).Returns(Task.CompletedTask); + generalSettingsPageMock.Setup(o => o.HandleFailedAuthentication(It.IsAny())).Returns(Task.CompletedTask); // Act await cut.OnHasAuthenticated(arg); // Assert - optionsMock.Verify(o => o.HandleFailedAuthentication("Authentication failed"), Times.Once); + generalSettingsPageMock.Verify(o => o.HandleFailedAuthentication("Authentication failed"), Times.Once); } [Fact] @@ -126,7 +129,7 @@ public async Task OnHasAuthenticated_ShouldHandleAuthenticationSuccess_WhenToken { // Arrange var arg = JObject.Parse("{'token':'test-token','apiUrl':'https://api.snyk.io'}"); - optionsMock.Setup(o => o.HandleAuthenticationSuccess("test-token", "https://api.snyk.io")).Returns(Task.CompletedTask); + generalSettingsPageMock.Setup(o => o.HandleAuthenticationSuccess("test-token", "https://api.snyk.io")).Returns(Task.CompletedTask); optionsMock.SetupGet(o => o.AuthenticationMethod).Returns(AuthenticationType.OAuth); // Act @@ -135,7 +138,7 @@ public async Task OnHasAuthenticated_ShouldHandleAuthenticationSuccess_WhenToken // Assert optionsMock.VerifySet(o => o.CustomEndpoint = "https://api.snyk.io"); optionsMock.VerifySet(o => o.ApiToken = It.Is(t => t.Type == AuthenticationType.OAuth && t.ToString() == "test-token")); - optionsMock.Verify(o => o.HandleAuthenticationSuccess("test-token", "https://api.snyk.io"), Times.Once); + generalSettingsPageMock.Verify(o => o.HandleAuthenticationSuccess("test-token", "https://api.snyk.io"), Times.Once); } [Fact] diff --git a/Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPageTest.cs b/Snyk.VisualStudio.Extension.Tests/SnykOptionsTest.cs similarity index 76% rename from Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPageTest.cs rename to Snyk.VisualStudio.Extension.Tests/SnykOptionsTest.cs index e9f6d5723..f3af7bc62 100644 --- a/Snyk.VisualStudio.Extension.Tests/GeneralOptionsDialogPageTest.cs +++ b/Snyk.VisualStudio.Extension.Tests/SnykOptionsTest.cs @@ -8,18 +8,19 @@ namespace Snyk.VisualStudio.Extension.Tests { [Collection(MockedVS.Collection)] - public class GeneralOptionsDialogPageTest + public class SnykOptionsTest { - private ISnykServiceProvider serviceProvider; - public GeneralOptionsDialogPageTest(GlobalServiceProvider sp) + private readonly SnykOptions cut; + public SnykOptionsTest(GlobalServiceProvider sp) { sp.Reset(); var serviceProviderMock = new Mock(); var snykSolutionService = new SnykSolutionService(); serviceProviderMock.Setup(x => x.SolutionService).Returns(snykSolutionService); - serviceProvider = serviceProviderMock.Object; + var serviceProvider = serviceProviderMock.Object; var settingsFilePath = Path.Combine(SnykExtension.GetExtensionDirectoryPath(), "settings.json"); serviceProviderMock.Setup(x => x.UserStorageSettingsService).Returns(new SnykUserStorageSettingsService(settingsFilePath, serviceProvider)); + cut = new SnykOptions(serviceProvider); } [Theory] @@ -38,10 +39,8 @@ public GeneralOptionsDialogPageTest(GlobalServiceProvider sp) [InlineData("https://api.eu.snyk.io", "https://app.eu.snyk.io/manage/snyk-code")] public void SnykCodeSettingsUrl(string endpoint, string expected) { - var optionsDialogPage = new SnykGeneralOptionsDialogPage(); - optionsDialogPage.Initialize(this.serviceProvider); - optionsDialogPage.CustomEndpoint = endpoint; - Assert.Equal(expected, optionsDialogPage.SnykCodeSettingsUrl); + cut.CustomEndpoint = endpoint; + Assert.Equal(expected, cut.SnykCodeSettingsUrl); } [Theory] @@ -56,10 +55,8 @@ public void SnykCodeSettingsUrl(string endpoint, string expected) [InlineData("https://api.eu.snyk.io", "https://api.eu.snyk.io")] public void TransformApiToNewSchema(string endpoint, string expected) { - var optionsDialogPage = new SnykGeneralOptionsDialogPage(); - optionsDialogPage.Initialize(this.serviceProvider); - optionsDialogPage.CustomEndpoint = endpoint; - Assert.Equal(expected, optionsDialogPage.GetCustomApiEndpoint()); + cut.CustomEndpoint = endpoint; + Assert.Equal(expected, cut.GetCustomApiEndpoint()); } [Theory] @@ -73,10 +70,8 @@ public void TransformApiToNewSchema(string endpoint, string expected) [InlineData("https://api.eu.snyk.io", "https://app.eu.snyk.io")] public void GetBaseAppUrl(string endpoint, string expected) { - var optionsDialogPage = new SnykGeneralOptionsDialogPage(); - optionsDialogPage.Initialize(this.serviceProvider); - optionsDialogPage.CustomEndpoint = endpoint; - Assert.Equal(expected, optionsDialogPage.GetBaseAppUrl()); + cut.CustomEndpoint = endpoint; + Assert.Equal(expected, cut.GetBaseAppUrl()); } } } \ No newline at end of file