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

Linter ViewExtension #11634

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ceec5d6
Initial commit
SHKnudsen Apr 13, 2021
0057e7a
Move event subscription to extension base class + add property change…
SHKnudsen Apr 13, 2021
668f4f9
comment updates
SHKnudsen Apr 15, 2021
b69a7e9
Update LinterExtensionBase.cs
SHKnudsen Apr 15, 2021
a1ad8c5
Update InputNodesNotAllowedRule.cs
SHKnudsen Apr 15, 2021
8ba184d
Add Deactivate method to linterExtensionBase + LinterManager tests
SHKnudsen Apr 19, 2021
c4c8286
comment updates
SHKnudsen Apr 19, 2021
d7c9537
Initial commit
SHKnudsen Apr 20, 2021
1a58f63
Add issues count to WorkspaceSaving
SHKnudsen Apr 20, 2021
d0bc4c7
add scrollviewer
SHKnudsen Apr 20, 2021
3a6f7af
Dispose LinterManager
SHKnudsen Apr 20, 2021
60fb830
Merge branch 'Linter-manager' into LinterViewExtension
SHKnudsen Apr 20, 2021
55ea85f
Make concrete issues internal
SHKnudsen Apr 20, 2021
45edd6c
summaries on IRuleIssue
SHKnudsen Apr 20, 2021
aa58d7c
comment updates
SHKnudsen Apr 22, 2021
aee31ed
Update severity code icon
SHKnudsen Apr 25, 2021
fafba10
Serialize linter manager to dyn file
SHKnudsen Apr 27, 2021
cdf0c59
clear ruleEvaluationResults on workspace change
SHKnudsen Apr 28, 2021
960c5b2
Remove test extension
SHKnudsen Apr 28, 2021
f0790d9
Show names instead of GUIDs
SHKnudsen Apr 28, 2021
c89c476
add help doc
SHKnudsen Apr 28, 2021
558f05d
clean up
SHKnudsen Apr 28, 2021
e7f2ff8
Handle GraphRuleEvaluationResults nodeIds changes
SHKnudsen Apr 28, 2021
f6bd740
Update LintingViewExtension.csproj
SHKnudsen Apr 28, 2021
4549903
Update LintingViewExtension.csproj
SHKnudsen Apr 28, 2021
145a9c7
Update SerializationConverters.cs
SHKnudsen Apr 29, 2021
c33a4da
Fix failing serialization test
SHKnudsen Apr 29, 2021
470207b
comment updates
SHKnudsen Apr 30, 2021
45c8332
revert changes to test file
SHKnudsen Apr 30, 2021
5304a08
fix available linters binding
SHKnudsen May 4, 2021
93018d3
Merge branch 'Linter-manager' into LinterViewExtension
SHKnudsen May 4, 2021
17e9217
add rules back in test ext
SHKnudsen May 4, 2021
f0bec8c
Merge branch 'AGD-2060-Linting-API' into LinterViewExtension
SHKnudsen May 4, 2021
69d7bf0
comment updates
SHKnudsen May 5, 2021
4cc514a
remove output path
SHKnudsen May 5, 2021
a731f6c
Update LinterManagerTests.cs
SHKnudsen May 6, 2021
c7e3c19
comment updates
SHKnudsen May 6, 2021
902243a
hide LinterViewExtension and LinterExtensionBase
SHKnudsen May 7, 2021
cbe848c
Update LinterViewModel.cs
SHKnudsen May 7, 2021
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
4 changes: 2 additions & 2 deletions src/AssemblySharedInfoGenerator/AssemblySharedInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
// to distinguish one build from another. AssemblyFileVersion is specified
// in AssemblyVersionInfo.cs so that it can be easily incremented by the
// automated build process.
[assembly: AssemblyVersion("2.11.0.3355")]
[assembly: AssemblyVersion("2.12.0.4643")]


// By default, the "Product version" shown in the file properties window is
Expand All @@ -64,4 +64,4 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("2.11.0.3355")]
[assembly: AssemblyFileVersion("2.12.0.4643")]
22 changes: 22 additions & 0 deletions src/Dynamo.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NodeAutoCompleteViewExtensi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md2Html", "Tools\Md2Html\Md2Html.csproj", "{0893F745-CB1A-427A-8E87-CA927273039A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestLinterExtension", "TestLinterExtension\TestLinterExtension.csproj", "{74A99E4A-671E-4B99-B8E9-602AE5A86323}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LintingViewExtension", "LintingViewExtension\LintingViewExtension.csproj", "{C86F9058-229D-40A9-95D5-D6F081AA9230}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -869,6 +873,22 @@ Global
{0893F745-CB1A-427A-8E87-CA927273039A}.Release|Any CPU.Build.0 = Release|Any CPU
{0893F745-CB1A-427A-8E87-CA927273039A}.Release|x64.ActiveCfg = Release|Any CPU
{0893F745-CB1A-427A-8E87-CA927273039A}.Release|x64.Build.0 = Release|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Debug|x64.ActiveCfg = Debug|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Debug|x64.Build.0 = Debug|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Release|Any CPU.Build.0 = Release|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Release|x64.ActiveCfg = Release|Any CPU
{74A99E4A-671E-4B99-B8E9-602AE5A86323}.Release|x64.Build.0 = Release|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|x64.ActiveCfg = Debug|x64
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Debug|x64.Build.0 = Debug|x64
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|Any CPU.Build.0 = Release|Any CPU
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|x64.ActiveCfg = Release|x64
{C86F9058-229D-40A9-95D5-D6F081AA9230}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -946,6 +966,8 @@ Global
{10AF430D-0D3A-49CE-A63D-848912959745} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{51511AFD-F326-4995-8E27-5D711419EF6F} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{0893F745-CB1A-427A-8E87-CA927273039A} = {D114C59C-CF66-4CC2-980F-9301FB4EA4E1}
{74A99E4A-671E-4B99-B8E9-602AE5A86323} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{C86F9058-229D-40A9-95D5-D6F081AA9230} = {88D45B00-E564-41DB-B57C-9509646CAA49}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {89CB19C6-BF0A-4E6A-BFDA-79D143EAB59D}
Expand Down
11 changes: 11 additions & 0 deletions src/DynamoCore/DynamoCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ limitations under the License.
<Compile Include="Exceptions\LibraryLoadFailedException.cs" />
<Compile Include="Extensions\ExtensionData.cs" />
<Compile Include="Extensions\IExtensionStorageAccess.cs" />
<Compile Include="Extensions\LinterExtensionBase.cs" />
<Compile Include="Graph\Workspaces\PackageDependencyInfo.cs" />
<Compile Include="Graph\Nodes\NodeOutputData.cs" />
<Compile Include="Graph\Nodes\NodeInputData.cs" />
Expand All @@ -130,6 +131,16 @@ limitations under the License.
<Compile Include="Graph\Workspaces\SerializationExtensions.cs" />
<Compile Include="Graph\Workspaces\UndoRedo.cs" />
<Compile Include="Extensions\IServiceManager.cs" />
<Compile Include="Linting\Interfaces\RuleEvaluationStatusEnum.cs" />
<Compile Include="Linting\Interfaces\IRuleEvaluationResult.cs" />
<Compile Include="Linting\Interfaces\SeverityCodesEnum.cs" />
<Compile Include="Linting\LinterExtensionDescriptor.cs" />
<Compile Include="Linting\LinterManager.cs" />
<Compile Include="Linting\Rules\GraphLinterRule.cs" />
<Compile Include="Linting\Rules\GraphRuleEvaluationResult.cs" />
<Compile Include="Linting\Rules\LinterRule.cs" />
<Compile Include="Linting\Rules\NodeLinterRule.cs" />
<Compile Include="Linting\Rules\NodeRuleEvaluationResult.cs" />
<Compile Include="Logging\AnalyticsService.cs" />
<Compile Include="Logging\DynamoAnalyticsClient.cs" />
<Compile Include="Logging\IAnalyticsSession.cs" />
Expand Down
274 changes: 274 additions & 0 deletions src/DynamoCore/Extensions/LinterExtensionBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Dynamo.Graph.Nodes;
using Dynamo.Graph.Workspaces;
using Dynamo.Linting;
using Dynamo.Linting.Rules;

namespace Dynamo.Extensions
{
/// <summary>
/// Base class for all LinterExtensions
/// </summary>
public abstract class LinterExtensionBase : IExtension
{
private const string NODE_ADDED_PROPERTY = "NodeAdded";
private const string NODE_REMOVED_PROPERTY = "NodeRemoved";

#region Private/Internal properties
private HashSet<LinterRule> linterRules = new HashSet<LinterRule>();
private LinterManager linterManager;
private WorkspaceModel currentWorkspace;

internal ReadyParams ReadyParamsRef { get; set; }

internal bool IsActive => this.linterManager?.IsExtensionActive(UniqueId) ?? false;

internal LinterExtensionDescriptor ExtensionDescriptor { get; private set; }
#endregion

#region Public properties

///<inheritdoc/>
public abstract string UniqueId { get; }

///<inheritdoc/>
public abstract string Name { get; }

/// <summary>
/// Collection of the rules in this extension
/// </summary>
public HashSet<LinterRule> LinterRules => linterRules;

#endregion

#region Internal methods

/// <summary>
/// Add a LinterRule
/// </summary>
/// <param name="linterRule"></param>
public void AddLinterRule(LinterRule linterRule)
{
linterRules.Add(linterRule);
}

/// <summary>
/// Remove a LinterRule
/// </summary>
/// <param name="linterRule"></param>
public void RemoveLinterRule(LinterRule linterRule)
{
if (linterRules.Contains(linterRule))
linterRules.Remove(linterRule);
}

/// <summary>
/// Activate this linter by subscribing the workspace and initializing its rules
/// </summary>
internal void Activate()
{
if (IsActive)
return;

ReadyParamsRef.CurrentWorkspaceChanged += OnCurrentWorkspaceChanged;
OnCurrentWorkspaceChanged(ReadyParamsRef.CurrentWorkspaceModel);
this.InitializeRules();
}

/// <summary>
/// Deactivates this extension by unsubscribing all its events
/// </summary>
internal void Deactivate()
{
ReadyParamsRef.CurrentWorkspaceChanged -= OnCurrentWorkspaceChanged;
UnsubscribeGraphEvents(currentWorkspace);
}

#endregion

internal void InitializeBase(LinterManager linterManager)
{
this.linterManager = linterManager;
}

private void EvaluateGraphRules(NodeModel modifiedNode, string changedProperty)
{
if (!IsActive)
return;

var graphRules = linterRules.
Where(x => x is GraphLinterRule).
Cast<GraphLinterRule>().
ToList();

if (graphRules is null)
return;

foreach (var rule in graphRules)
{
if (changedProperty != NODE_ADDED_PROPERTY &&
changedProperty != NODE_REMOVED_PROPERTY &&
!rule.EvaluationTriggerEvents.Contains(changedProperty))
continue;

rule.Evaluate(currentWorkspace, modifiedNode);
}
}

private void EvaluateNodeRules(NodeModel modifiedNode, string changedProperty)
{
if (!IsActive)
return;

var nodeRules = linterRules.
Where(x => x is NodeLinterRule).
Cast<NodeLinterRule>().
ToList();

if (nodeRules is null)
return;

foreach (var rule in nodeRules)
{
if (changedProperty != NODE_ADDED_PROPERTY && !rule.EvaluationTriggerEvents.Contains(changedProperty))
continue;

rule.Evaluate(modifiedNode);
}
}

private void InitializeRules()
{
if (!(ReadyParamsRef.CurrentWorkspaceModel is WorkspaceModel wm))
return;

foreach (var rule in LinterRules)
{
rule.InitializeBase(wm);
}
}

#region Extension Lifecycle

///<inheritdoc/>
public virtual void Ready(ReadyParams sp)
{
ReadyParamsRef = sp;
if (IsActive)
InitializeRules();
}

///<inheritdoc/>
public virtual void Startup(StartupParams sp)
{
ExtensionDescriptor = new LinterExtensionDescriptor(UniqueId, Name);
OnLinterExtensionReady();
}

///<inheritdoc/>
public abstract void Shutdown();

///<inheritdoc/>
public virtual void Dispose()
{
ReadyParamsRef.CurrentWorkspaceChanged -= OnCurrentWorkspaceChanged;
UnsubscribeGraphEvents(currentWorkspace);
}

#endregion

#region Events

/// <summary>
/// Represents the method that will handle rule evaluated related events.
/// </summary>
internal delegate void LinterExtensionReadyHandler(LinterExtensionDescriptor descriptor);

internal static event LinterExtensionReadyHandler LinterExtensionReady;

private void OnLinterExtensionReady()
{
LinterExtensionReady?.Invoke(ExtensionDescriptor);
}

private void OnCurrentWorkspaceChanged(IWorkspaceModel obj)
{
if (this.currentWorkspace != null)
UnsubscribeGraphEvents(this.currentWorkspace);

this.currentWorkspace = ReadyParamsRef.CurrentWorkspaceModel as WorkspaceModel;
this.SubscribeNodeEvents();
this.SubscribeGraphEvents();
}

private void SubscribeGraphEvents()
{
this.currentWorkspace.NodeRemoved += OnNodeRemoved;
this.currentWorkspace.NodeAdded += OnNodeAdded;
}


private void SubscribeNodeEvents()
{
foreach (var node in currentWorkspace.Nodes)
{
node.PropertyChanged += OnNodePropertyChanged;
}
}

private void UnsubscribeGraphEvents(WorkspaceModel workspaceModel)
{
workspaceModel.NodeRemoved -= OnNodeRemoved;
workspaceModel.NodeAdded -= OnNodeAdded;
workspaceModel.Nodes.
ToList().
ForEach(x => UnsubscribeNodeEvents(x));
}

private void UnsubscribeNodeEvents(NodeModel node)
{
node.PropertyChanged -= OnNodePropertyChanged;
}

private void OnNodeAdded(NodeModel node)
{
EvaluateGraphRules(node, NODE_ADDED_PROPERTY);
EvaluateNodeRules(node, NODE_ADDED_PROPERTY);
node.PropertyChanged += OnNodePropertyChanged;
}

private void OnNodePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
EvaluateNodeRules(sender as NodeModel, e.PropertyName);
EvaluateGraphRules(sender as NodeModel, e.PropertyName);

}

private void OnNodeRemoved(Graph.Nodes.NodeModel node)
{
EvaluateGraphRules(node, NODE_REMOVED_PROPERTY);

var nodeRules = LinterRules.
Where(x => x is NodeLinterRule).
Cast<NodeLinterRule>().
ToList();

if (nodeRules is null)
return;

foreach (var rule in nodeRules)
{
var result = new NodeRuleEvaluationResult(rule.Id, Linting.Interfaces.RuleEvaluationStatusEnum.Passed, node.GUID.ToString());
rule.OnRuleEvaluated(result);
}

UnsubscribeNodeEvents(node);
}
#endregion
}
}
21 changes: 21 additions & 0 deletions src/DynamoCore/Linting/Interfaces/IRuleEvaluationResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dynamo.Linting.Interfaces
{
public interface IRuleEvaluationResult
{
/// <summary>
/// Id of the rule that create this result
/// </summary>
string RuleId { get; }

/// <summary>
/// Status of the evaluation (Passed or Failed)
/// </summary>
RuleEvaluationStatusEnum Status { get; }
}
}
14 changes: 14 additions & 0 deletions src/DynamoCore/Linting/Interfaces/RuleEvaluationStatusEnum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Dynamo.Linting.Interfaces
{
public enum RuleEvaluationStatusEnum
{
Passed,
Failed
}
}
Loading