diff --git a/.github/workflows/build-vsix.yml b/.github/workflows/build-vsix.yml index 052e258..e27756e 100644 --- a/.github/workflows/build-vsix.yml +++ b/.github/workflows/build-vsix.yml @@ -22,7 +22,7 @@ jobs: ref: ${{ inputs.ref }} - name: Setup MSBuild - uses: microsoft/setup-msbuild@v1 + uses: microsoft/setup-msbuild@v2 with: vs-version: 'latest' diff --git a/JFrogVSExtension/JFrogVSExtension.csproj b/JFrogVSExtension/JFrogVSExtension.csproj index 6c669c7..acb0538 100644 --- a/JFrogVSExtension/JFrogVSExtension.csproj +++ b/JFrogVSExtension/JFrogVSExtension.csproj @@ -59,8 +59,8 @@ prompt 2 - false - false + false + false false @@ -238,10 +238,10 @@ 17.1.32210.191 - 17.1.32210.191 + 17.12.40391 - 16.10.10 + 17.7.47 runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -249,7 +249,7 @@ 17.1.32210.191 - 17.1.4054 + 17.12.2069 runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/JFrogVSExtension/MainPanelControl.xaml b/JFrogVSExtension/MainPanelControl.xaml index b288f61..b2576f3 100644 --- a/JFrogVSExtension/MainPanelControl.xaml +++ b/JFrogVSExtension/MainPanelControl.xaml @@ -86,14 +86,13 @@ - - + diff --git a/JFrogVSExtension/MainPanelControl.xaml.cs b/JFrogVSExtension/MainPanelControl.xaml.cs index 2f9c13a..4ba6f66 100644 --- a/JFrogVSExtension/MainPanelControl.xaml.cs +++ b/JFrogVSExtension/MainPanelControl.xaml.cs @@ -125,15 +125,12 @@ private void Details_Loaded(object sender, RoutedEventArgs e) { } -#pragma warning disable VSTHRD100 // Avoid async void methods - Signature expected by event handler. - private async void Tree_Loaded(object sender, RoutedEventArgs e) -#pragma warning restore VSTHRD100 // Avoid async void methods + private void Tree_Loaded(object sender, RoutedEventArgs e) { if (isAllFilterChecked) { InitCheckbox(); } - await ((MainViewModel)this.DataContext).LoadAsync(); } private void InitCheckbox() @@ -151,9 +148,8 @@ public async Task LoadAsync() { if (isAllFilterChecked) { - InitCheckbox(); + await Task.Run(() => InitCheckbox()); } - await ((MainViewModel)this.DataContext).LoadAsync(); } public async Task CloseAsync() diff --git a/JFrogVSExtension/UI/MainPanel/MainPanelPackage.cs b/JFrogVSExtension/UI/MainPanel/MainPanelPackage.cs index 50aa574..f96b172 100644 --- a/JFrogVSExtension/UI/MainPanel/MainPanelPackage.cs +++ b/JFrogVSExtension/UI/MainPanel/MainPanelPackage.cs @@ -92,6 +92,7 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke protected override void Dispose(bool disposing) { + ThreadHelper.ThrowIfNotOnUIThread(); if (_solutionEventsCookie != 0) { _solution.UnadviseSolutionEvents(_solutionEventsCookie); @@ -143,11 +144,6 @@ public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded) public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution) { - MainPanel mainPanel = MainPanel.GetInstance(); - if (mainPanel != null) - { - _ = mainPanel.LoadAsync(); - } return VSConstants.S_OK; } diff --git a/JFrogVSExtension/UI/Panel/ComponentsIssueDetails/ComponentsIssueDetails.xaml b/JFrogVSExtension/UI/Panel/ComponentsIssueDetails/ComponentsIssueDetails.xaml index 233e05f..b578f06 100644 --- a/JFrogVSExtension/UI/Panel/ComponentsIssueDetails/ComponentsIssueDetails.xaml +++ b/JFrogVSExtension/UI/Panel/ComponentsIssueDetails/ComponentsIssueDetails.xaml @@ -28,11 +28,11 @@ HorizontalAlignment="Left" VerticalAlignment="Top" MinWidth="75" - MaxWidth="1000" + MaxWidth="2000" HorizontalScrollBarVisibility="Auto" + VerticalScrollBarVisibility="Auto" Background="Transparent" - BorderThickness="0" - Margin="0" + BorderThickness="0" HorizontalGridLinesBrush="Transparent" VerticalGridLinesBrush="Transparent" RowHeaderWidth="0"> @@ -55,7 +55,7 @@ - + @@ -77,7 +77,7 @@ - + - + - + - + + + + - + - + diff --git a/JFrogVSExtension/UI/Panel/Tree/TreeViewModel.cs b/JFrogVSExtension/UI/Panel/Tree/TreeViewModel.cs index cee119d..3b57b1c 100644 --- a/JFrogVSExtension/UI/Panel/Tree/TreeViewModel.cs +++ b/JFrogVSExtension/UI/Panel/Tree/TreeViewModel.cs @@ -29,6 +29,8 @@ class TreeViewModel : BaseViewModel public ObservableCollection IssueDetails { get; set; } public Component SelectedComponent { get; set; } public Boolean EnableRefreshButton { get; set; } + + public string ScanStatus { get; set; } public string SelectedKey { get { return selectedKey; } @@ -53,6 +55,7 @@ public string SelectedKey public TreeViewModel() { this.EnableRefreshButton = true; + ScanStatus = ""; // Default value } #endregion @@ -85,7 +88,7 @@ public async Task LoadAsync(RefreshType refreshType, HashSet severitie // 4. Get response and build the dependencies tree. // Running CLI - this is the returned output. - String returnedText = await Task.Run(() => Util.GetCLIOutputAsync("rt nuget-deps-tree",solutionDir)); + String returnedText = await Util.GetCLIOutputAsync("rt nuget-deps-tree",solutionDir); // Load projects from output. Project[] nugetProjects = Util.LoadNugetProjects(returnedText); diff --git a/JFrogVSExtension/Utils/ScanManager/ScanManager.cs b/JFrogVSExtension/Utils/ScanManager/ScanManager.cs index 631996d..01d8e31 100644 --- a/JFrogVSExtension/Utils/ScanManager/ScanManager.cs +++ b/JFrogVSExtension/Utils/ScanManager/ScanManager.cs @@ -46,7 +46,7 @@ private async Task ConfigCLIAsync(string xrayUrl, string artifactoryUrl, string public async Task PreformScanAsync(List workingDirs) { var workingDirsString = workingDirs.Count() > 1 ? string.Join(", ", workingDirs) : workingDirs.First(); - var cliAuditCommand = $"audit --format=\"json\" --server-id=\"{CliServerId}\" --licenses --fail=\"false\" --working-dirs=\"{workingDirsString}\""; + var cliAuditCommand = $"audit --sca --format=\"json\" --server-id=\"{CliServerId}\" --licenses --fail=\"false\" --working-dirs=\"{workingDirsString}\""; switch (Policy) { @@ -57,7 +57,7 @@ public async Task PreformScanAsync(List workingDirs) cliAuditCommand += $" --watches=\"{watches}\""; break; } - return await Util.GetCLIOutputAsync(cliAuditCommand, workingDirs.First(), false, cliEnv); + return await Util.GetCLIOutputAsync(cliAuditCommand, workingDirs.First(), false, cliEnv); } } } diff --git a/JFrogVSExtension/Utils/Util.cs b/JFrogVSExtension/Utils/Util.cs index d5cd568..80b1810 100644 --- a/JFrogVSExtension/Utils/Util.cs +++ b/JFrogVSExtension/Utils/Util.cs @@ -1,6 +1,8 @@ using JFrogVSExtension.Data; using JFrogVSExtension.Logger; using JFrogVSExtension.Xray; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Threading; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -54,6 +56,7 @@ private static Project LoadNpmProject(string packageJsonPath) var npmProjectTree = GetProcessOutputAsync("cmd.exe", "/C npm ls --json --all --long --package-lock-only", fileInfo.DirectoryName); var npmProj = JsonConvert.DeserializeObject(npmProjectTree.Result); + var project = new Project() { name = $"{npmProj.name}:{npmProj.version}", @@ -109,46 +112,54 @@ public static async Task GetCLIOutputAsync(string command, string workin public static async Task GetProcessOutputAsync(string pathToExe, string command, string workingDir = "", bool configCommand = false, Dictionary envVars = null) { - //Create process - Process pProcess = new Process(); - - // strCommand is path and file name of command to run - pProcess.StartInfo.FileName = pathToExe; - - // strCommandParameters are parameters to pass to program - // Here we will run the nuget command for the cli - pProcess.StartInfo.Arguments = command; - // Avoid printing commands with credentials - var commandString = configCommand ? "config command" : command; - - pProcess.StartInfo.UseShellExecute = false; - pProcess.StartInfo.CreateNoWindow = true; - // Set output of program to be written to process output stream - pProcess.StartInfo.RedirectStandardOutput = true; - pProcess.StartInfo.RedirectStandardError = true; - pProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; - pProcess.StartInfo.WorkingDirectory = workingDir; - if (envVars != null) + return await Task.Run(async () => { - foreach (var envVar in envVars) + //Create process + Process pProcess = new Process + { + StartInfo = new ProcessStartInfo + { + // strCommand is path and file name of command to run + FileName = pathToExe, + // strCommandParameters are parameters to pass to program + // Here we will run the nuget command for the cli + Arguments = command, + UseShellExecute = false, + // Set output of program to be written to process output stream + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = workingDir + } + }; + + // Avoid printing commands with credentials + var commandString = configCommand ? "config command" : command; + + if (envVars != null) { - pProcess.StartInfo.EnvironmentVariables[envVar.Key] = envVar.Value; + foreach (var envVar in envVars) + { + pProcess.StartInfo.EnvironmentVariables[envVar.Key] = envVar.Value; + } } - } - StringBuilder strOutput = new StringBuilder(); - StringBuilder error = new StringBuilder(); + StringBuilder strOutput = new StringBuilder(); + StringBuilder error = new StringBuilder(); + + // Saving the response from the CLI to a StringBuilder. + + var tcsOutput = new TaskCompletionSource(); + var tcsError = new TaskCompletionSource(); + - // Saving the response from the CLI to a StringBuilder. - using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false)) - using (AutoResetEvent errorWaitHandle = new AutoResetEvent(false)) - { // Get program output // The json returned from the CLI pProcess.OutputDataReceived += (sender, e) => { if (e.Data == null) { - outputWaitHandle.Set(); + tcsOutput.SetResult(true); } else { @@ -159,7 +170,7 @@ public static async Task GetProcessOutputAsync(string pathToExe, string { if (e.Data == null) { - errorWaitHandle.Set(); + tcsError.SetResult(true); } else { @@ -172,11 +183,11 @@ public static async Task GetProcessOutputAsync(string pathToExe, string pProcess.BeginOutputReadLine(); pProcess.BeginErrorReadLine(); // Waits for maximal 1 hour - pProcess.WaitForExit(60*60*1000); + pProcess.WaitForExit(60 * 60 * 1000); - // Wait for the entire output to be written - if (outputWaitHandle.WaitOne(1) && - errorWaitHandle.WaitOne(1)) + + // Wait for the entire output to be written + if (tcsOutput.Task.IsCompleted && tcsError.Task.IsCompleted) { // Process completed. Check process.ExitCode here. if (pProcess.ExitCode != 0) @@ -198,7 +209,7 @@ public static async Task GetProcessOutputAsync(string pathToExe, string await OutputLog.ShowMessageAsync("Process timeout"); throw new IOException($"Process timeout, {pathToExe} {commandString}"); } - } + }); } private static string GetAssemblyLocalPathFrom(Type type)