Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: CLI release channels #300

Merged
merged 18 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Snyk.Common/Settings/ISnykOptions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Snyk.Common.Authentication;
using Snyk.Common.Service;

namespace Snyk.Common.Settings
{
Expand Down Expand Up @@ -73,7 +73,9 @@ public interface ISnykOptions
/// Gets or sets the value of the CLI custom path. If empty, the default path from AppData would be used.
/// </summary>
string CliCustomPath { get; set; }

string CliReleaseChannel { get; set; }
string CliDownloadUrl { get; set; }
ISet<string> TrustedFolders { get; set; }
/// <summary>
/// Settings changed event.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ protected bool IsButtonAvailable()
{
ThreadHelper.ThrowIfNotOnUIThread();
var isLsReady = SnykVSPackage.Instance?.LanguageClientManager?.IsReady ?? false;
return SnykVSPackage.ServiceProvider.Options.ApiToken.IsValid()
&& SnykSolutionService.Instance.IsSolutionOpen() && isLsReady;
return SnykSolutionService.Instance.IsSolutionOpen() && isLsReady;
}

/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,7 @@ public static async Task InitializeAsync(AsyncPackage package)
public override async Task UpdateStateAsync()
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
var isLsReady = SnykVSPackage.Instance?.LanguageClientManager?.IsReady ?? false;

this.MenuCommand.Enabled = SnykVSPackage.ServiceProvider.Options.ApiToken.IsValid()
&& this.VsPackage.ToolWindowControl.IsTreeContentNotEmpty() && isLsReady;
this.MenuCommand.Enabled = this.VsPackage.ToolWindowControl.IsTreeContentNotEmpty();
}

/// <summary>
Expand Down
63 changes: 29 additions & 34 deletions Snyk.VisualStudio.Extension.2022/Download/SnykCliDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading.Tasks;
using Serilog;
using Snyk.Common;
using Snyk.Common.Settings;
using Snyk.VisualStudio.Extension.CLI;
using Snyk.VisualStudio.Extension.Language;
using Snyk.VisualStudio.Extension.Service;
Expand All @@ -16,26 +17,26 @@ namespace Snyk.VisualStudio.Extension.Download
/// </summary>
public class SnykCliDownloader
{
private const string BaseUrl = "https://downloads.snyk.io";
public const string DefaultBaseDownloadUrl = "https://downloads.snyk.io";
public const string DefaultReleaseChannel = "preview";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will switch to default stable before GA


private const string ReleaseChannel = "preview";
private const string LatestReleaseVersionUrl = BaseUrl + "/cli/" + ReleaseChannel + "/ls-protocol-version-" + LsConstants.ProtocolVersion;
private const string LatestReleaseDownloadUrl = BaseUrl + "/cli/{0}/" + SnykCli.CliFileName;
private const string LatestReleaseVersionUrlScheme = "{0}/cli/{1}/ls-protocol-version-" + LsConstants.ProtocolVersion;
private const string LatestReleaseDownloadUrlScheme = "{0}/cli/{1}/" + SnykCli.CliFileName;
private const string Sha256DownloadUrl = "{0}.sha256";

private const int FourDays = 4;

private static readonly ILogger Logger = LogManager.ForContext<SnykCliDownloader>();

private readonly ISnykOptions SnykOptions;
private readonly string currentCliVersion;

private string expectedSha;

/// <summary>
/// Initializes a new instance of the <see cref="SnykCliDownloader"/> class.
/// </summary>
/// <param name="currentCliVersion">Initial CLI version parameter.</param>
public SnykCliDownloader(string currentCliVersion) => this.currentCliVersion = currentCliVersion;
public SnykCliDownloader(ISnykOptions snykOptions, string currentVersion)
{
this.SnykOptions = snykOptions;
this.currentCliVersion = currentVersion;
}

/// <summary>
/// Callback on download finished event.
Expand Down Expand Up @@ -64,12 +65,15 @@ public LatestReleaseInfo GetLatestReleaseInfo()
{
Logger.Information("Get latest CLI release info");

string latestVersion = webClient.DownloadString(LatestReleaseVersionUrl).Replace("\n", string.Empty);
var latestReleaseVersionUrl = string.Format(LatestReleaseVersionUrlScheme, SnykOptions.CliDownloadUrl, SnykOptions.CliReleaseChannel);
var latestVersion = webClient.DownloadString(latestReleaseVersionUrl).Replace("\n", string.Empty);

var latestReleaseDownloadUrl = string.Format(LatestReleaseDownloadUrlScheme, SnykOptions.CliDownloadUrl, "v"+latestVersion);

return new LatestReleaseInfo
{
Version = latestVersion,
Url = string.Format(LatestReleaseDownloadUrl, "v"+latestVersion),
Version = "v" + latestVersion,
Url = latestReleaseDownloadUrl,
Name = "v" + latestVersion,
};
}
Expand Down Expand Up @@ -108,29 +112,27 @@ public string GetLatestCliSha(string cliDownloadUrl)
}
}

/// <summary>
/// Check is four days passed after lact check.
/// </summary>
/// <param name="lastCheckDate">Last check date value.</param>
/// <returns>True if four days passed after last check.</returns>
public bool IsFourDaysPassedAfterLastCheck(DateTime lastCheckDate)
=> (DateTime.Now - lastCheckDate).TotalDays > FourDays;

/// <summary>
/// Check is CLI download needed.
/// 1. If CLI file not exists.
/// 2. If new CLI release exists.
/// </summary>
/// <param name="lastCheckDate">Last check date.</param>
/// <param name="cliFileDestinationPath">Path to CLI file.</param>
/// <returns>True if CLI file not exists or new release exists.</returns>
public bool IsCliDownloadNeeded(DateTime lastCheckDate, string cliFileDestinationPath = null)
public bool IsCliDownloadNeeded(string cliFileDestinationPath = null)
{
if (!this.IsCliFileExists(cliFileDestinationPath) || this.IsCliUpdateExists(lastCheckDate))
try
{
return true;
if (!this.IsCliFileExists(cliFileDestinationPath) || this.IsNewVersionAvailable(this.currentCliVersion, this.GetLatestReleaseInfo().Version))
{
return true;
}
}
catch (Exception ex)
{
Logger.Error("Could not fetch latest CLI release info for provided version {Ex}", ex);
return false;
}

return false;
}

Expand All @@ -141,13 +143,6 @@ public bool IsCliDownloadNeeded(DateTime lastCheckDate, string cliFileDestinatio
/// <returns>True if CLI file not exists.</returns>
public bool IsCliFileExists(string cliFileDestinationPath = null) => File.Exists(cliFileDestinationPath);

/// <summary>
/// Is CLI update exists.
/// </summary>
/// <param name="lastCheckDate">Last check date.</param>
/// <returns>True if new version CLI exists</returns>
public bool IsCliUpdateExists(DateTime lastCheckDate) => this.IsNewVersionAvailable(this.currentCliVersion, this.GetLatestReleaseInfo().Version) && this.IsFourDaysPassedAfterLastCheck(lastCheckDate);

/// <summary>
/// Check is there a new version on the server and if there is, download it.
/// </summary>
Expand All @@ -164,7 +159,7 @@ public async Task AutoUpdateCliAsync(
{
var fileDestinationPath = GetCliFilePath(filePath);

var isCliDownloadNeeded = this.IsCliDownloadNeeded(lastCheckDate, fileDestinationPath);
var isCliDownloadNeeded = this.IsCliDownloadNeeded(fileDestinationPath);

if (isCliDownloadNeeded)
{
Expand Down
16 changes: 14 additions & 2 deletions Snyk.VisualStudio.Extension.2022/Language/SnykLanguageClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.LanguageServer.Client;
Expand Down Expand Up @@ -65,6 +66,7 @@ public object GetInitializationOptions()
SendErrorReports = "true",
ManageBinariesAutomatically = options.BinariesAutoUpdate.ToString(),
EnableTrustedFoldersFeature = "false",
TrustedFolders = options.TrustedFolders.ToList(),
IntegrationName = options.IntegrationName,
FilterSeverity = new FilterSeverityOptions
{
Expand Down Expand Up @@ -188,8 +190,18 @@ public async Task StopServerAsync()
{
if (StopAsync != null)
{
await StopAsync.InvokeAsync(this, EventArgs.Empty);
IsReady = false;
try
{
await StopAsync.InvokeAsync(this, EventArgs.Empty);
}
catch (Exception ex)
{
Logger.Error("Could not stop Language Server. {Ex}", ex);
}
finally
{
IsReady = false;
}
}
else
{
Expand Down
17 changes: 8 additions & 9 deletions Snyk.VisualStudio.Extension.2022/Service/SnykTasksService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -728,14 +728,13 @@ public bool ShouldDownloadCli()
{
var currentCliVersion = userSettingsStorageService.GetCurrentCliVersion();

var lastCliReleaseDate = userSettingsStorageService.GetCliReleaseLastCheckDate();

var cliDownloader = new SnykCliDownloader(currentCliVersion);
var options = this.serviceProvider.Options;
var cliDownloader = new SnykCliDownloader(options, currentCliVersion);

var downloadPath = this.serviceProvider.Options.CliCustomPath;
var downloadPath = options.CliCustomPath;
var fileDestinationPath = GetCliFilePath(downloadPath);

return cliDownloader.IsCliDownloadNeeded(lastCliReleaseDate, fileDestinationPath);
return cliDownloader.IsCliDownloadNeeded(fileDestinationPath);

}
catch (Exception)
Expand All @@ -759,13 +758,13 @@ private async Task DownloadAsync(CliDownloadFinishedCallback downloadFinishedCal
this.isCliDownloading = true;
try
{
string currentCliVersion = userSettingsStorageService.GetCurrentCliVersion();
var currentCliVersion = userSettingsStorageService.GetCurrentCliVersion();

DateTime lastCliReleaseDate = userSettingsStorageService.GetCliReleaseLastCheckDate();
var lastCliReleaseDate = userSettingsStorageService.GetCliReleaseLastCheckDate();

var cliDownloader = new SnykCliDownloader(currentCliVersion);
var cliDownloader = new SnykCliDownloader(this.serviceProvider.Options, currentCliVersion);

List<CliDownloadFinishedCallback> downloadFinishedCallbacks = new List<CliDownloadFinishedCallback>();
var downloadFinishedCallbacks = new List<CliDownloadFinishedCallback>();

if (downloadFinishedCallback != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,23 +112,28 @@ public int OnAfterOpenProject(IVsHierarchy vsHierarchy, int fAdded)
var languageClientManager = LanguageClientHelper.LanguageClientManager();
if (languageClientManager == null)
return VSConstants.S_OK;
if (languageClientManager.IsReady)

var isFolderTrusted = false;
ThreadHelper.JoinableTaskFactory.Run(async () =>
isFolderTrusted = await SnykVSPackage.ServiceProvider.TasksService.IsFolderTrustedAsync());
if (!isFolderTrusted)
{
languageClientManager.RestartServerAsync().FireAndForget();
// If folder was not trusted. Stop Language Server if running.
languageClientManager.StopServerAsync().FireAndForget();
return VSConstants.S_OK;
}

bool shouldDownloadCli;
try
{
shouldDownloadCli = SnykVSPackage.ServiceProvider.TasksService.ShouldDownloadCli();
}
finally
{
}

var shouldDownloadCli = SnykVSPackage.ServiceProvider.TasksService.ShouldDownloadCli();

if (shouldDownloadCli)
return VSConstants.S_OK;

if (languageClientManager.IsReady)
{
languageClientManager.RestartServerAsync().FireAndForget();
return VSConstants.S_OK;
}

languageClientManager.StartServerAsync(true).FireAndForget();
return VSConstants.S_OK;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
Expand Down Expand Up @@ -41,6 +42,17 @@ public class SnykGeneralOptionsDialogPage : DialogPage, ISnykOptions

private static readonly ILogger Logger = LogManager.ForContext<SnykGeneralOptionsDialogPage>();

public ISet<string> TrustedFolders
{
get => this.userStorageSettingsService.TrustedFolders;
set
{
if (this.userStorageSettingsService == null || this.userStorageSettingsService.TrustedFolders == value)
return;
this.userStorageSettingsService.TrustedFolders = value;
}
}

/// <inheritdoc/>
public event EventHandler<SnykSettingsChangedEventArgs> SettingsChanged;

Expand Down Expand Up @@ -261,9 +273,35 @@ public string CliCustomPath
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;
// TODO: Handle CLI Path Change
}
}
public string CliDownloadUrl
{
get => this.userStorageSettingsService.CliDownloadUrl;
set
{
if (this.userStorageSettingsService == null || this.userStorageSettingsService.CliDownloadUrl == value)
{
return;
}
this.userStorageSettingsService.CliDownloadUrl = value;
HandleCliCustomPathChange();
}
}

/// <summary>
/// Gets a value indicating whether General Settings control.
Expand All @@ -276,6 +314,33 @@ protected override void OnClosed(EventArgs e)
if (generalSettingsUserControl == null)
return;
ResetControlScrollSettings(generalSettingsUserControl);
HandleCliDownload();
}

private void HandleCliCustomPathChange()
{
var languageClientManager = LanguageClientHelper.LanguageClientManager();
if (languageClientManager == null)
return;

if (File.Exists(this.CliDownloadUrl))
{
ThreadHelper.JoinableTaskFactory.RunAsync(async()=> await languageClientManager.RestartServerAsync()).FireAndForget();
}
}

private void HandleCliDownload()
{
var releaseChannel = generalSettingsUserControl.GetReleaseChannel().Trim();
var downloadUrl = generalSettingsUserControl.GetCliDownloadUrl().Trim();
var autoScan = generalSettingsUserControl.GetAutoScanEnabled();
if (this.CliReleaseChannel != releaseChannel || this.CliDownloadUrl != downloadUrl || this.AutoScan != autoScan)
{
this.CliDownloadUrl = downloadUrl;
this.CliReleaseChannel = releaseChannel;
this.AutoScan = autoScan;
this.serviceProvider.TasksService.Download();
}
}

private void ResetControlScrollSettings(UserControl control)
Expand Down
Loading
Loading