Skip to content

Commit

Permalink
Merge pull request #1 from NikiforovAll/feature/serve-command
Browse files Browse the repository at this point in the history
feat: add serve command
  • Loading branch information
NikiforovAll authored Jul 28, 2024
2 parents 4203b84 + 5d2597e commit 27caab2
Show file tree
Hide file tree
Showing 38 changed files with 1,323 additions and 64 deletions.
23 changes: 23 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@
"stopAtEntry": false,
"console": "externalTerminal",
"env": {}
},
{
"name": "serve:debug",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/src/Dependify.Cli/bin/Debug/net8.0/Dependify.Cli.dll",
"args": ["serve", "C:\\Users\\Oleksii_Nikiforov\\dev\\dependify\\cap-aspire"],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "externalTerminal",
"env": {}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "C#: Web Debug",
"type": "dotnet",
"request": "launch",
"projectPath": "${workspaceFolder}/src/Web/Web.csproj"
}
]
}
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,26 @@ COMMANDS:
show <path> Shows the dependencies of a project or solution located in the specified path
```

## Example
## Usage

You can start dependify in `serve mode` and open the browser to navigate the generated graph.

```bash
dependify serve $dev/keycloak-authorization-services-dotnet/
```

You will see the following output in the terminal. Open <http:localhost:9999/> and browse the graph.

![serve-terminal](./assets/serve-terminal.png)

![serve-main-window](./assets/serve-main-window.png)

You can open the mermaid diagram right in the browser.

![serve-graph-view](./assets/serve-graph-view.png)


You can use the CLI for the automation or if you prefer the terminal.

```bash
dependify graph scan \
Expand Down Expand Up @@ -134,3 +153,7 @@ graph LR
`dotnet cake --target test`

`dotnet cake --target pack`

`dotnet tool install --global --add-source ./Artefacts Dependify.Cli --prerelease`

`dotnet tool uninstall Dependify.Cli -g`
3 changes: 3 additions & 0 deletions assets/serve-graph-view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/serve-main-window.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions assets/serve-terminal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions dependify.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{C3712305
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dependify.Core.Tests", "tests\Dependify.Core.Tests\Dependify.Core.Tests.csproj", "{A13ED5C9-227D-4C24-A04C-617A81878415}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{1358655A-56D9-45B8-80ED-758704415375}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -31,6 +33,10 @@ Global
{A13ED5C9-227D-4C24-A04C-617A81878415}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A13ED5C9-227D-4C24-A04C-617A81878415}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A13ED5C9-227D-4C24-A04C-617A81878415}.Release|Any CPU.Build.0 = Release|Any CPU
{1358655A-56D9-45B8-80ED-758704415375}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1358655A-56D9-45B8-80ED-758704415375}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1358655A-56D9-45B8-80ED-758704415375}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1358655A-56D9-45B8-80ED-758704415375}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -39,5 +45,6 @@ Global
{B9C749D5-B659-45C8-AAA5-D0B6FB99A9D0} = {6EFAF0C3-2695-4C03-AAB0-D982DA582BEB}
{C439C106-82A3-4303-A989-09A24E2FF221} = {6EFAF0C3-2695-4C03-AAB0-D982DA582BEB}
{A13ED5C9-227D-4C24-A04C-617A81878415} = {C3712305-26BF-4E1B-B7E3-2A603443E98F}
{1358655A-56D9-45B8-80ED-758704415375} = {6EFAF0C3-2695-4C03-AAB0-D982DA582BEB}
EndGlobalSection
EndGlobal
9 changes: 4 additions & 5 deletions src/Dependify.Cli/Commands/ScanCommand.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
namespace Dependify.Cli.Commands;

using Dependify.Cli;
using Dependify.Cli.Commands.Settings;
using Dependify.Cli.Formatters;
using Dependify.Core;
Expand Down Expand Up @@ -41,10 +40,10 @@ public override int Execute(CommandContext context, ScanCommandSettings settings
private void DisplayProjects(ScanCommandSettings settings, IEnumerable<Node> nodes)
{
var prefix = Utils.CalculateCommonPrefix(nodes);
var graph = Utils.DoSomeWork(
var graph = Cli.Utils.DoSomeWork(
ctx =>
{
Utils.SetDiagnosticSource(msBuildService, ctx);
Cli.Utils.SetDiagnosticSource(msBuildService, ctx);

return msBuildService.AnalyzeReferences(
nodes.OfType<ProjectReferenceNode>(),
Expand Down Expand Up @@ -78,10 +77,10 @@ int solutionCount

foreach (var solution in solutionNodes.Where(n => selectedSolutions.Contains(n.Id)))
{
var graph = Utils.DoSomeWork(
var graph = Cli.Utils.DoSomeWork(
ctx =>
{
Utils.SetDiagnosticSource(msBuildService, ctx);
Cli.Utils.SetDiagnosticSource(msBuildService, ctx);

return msBuildService.AnalyzeReferences(
solution,
Expand Down
142 changes: 142 additions & 0 deletions src/Dependify.Cli/Commands/ServeCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
namespace Dependify.Cli.Commands;

using System.Threading;
using Dependify.Cli.Commands.Settings;
using Dependify.Core;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

internal class ServeCommand() : AsyncCommand<ServeCommandSettings>
{
private const string Port = "9999";
private const string Host = $"http://localhost:{Port}";

public override async Task<int> ExecuteAsync(CommandContext context, ServeCommandSettings settings)
{
var isLoggingEnabled = settings.LogLevel.HasValue && settings.LogLevel.Value != LogLevel.None;

var directory = Path.GetDirectoryName($"{settings.Path.TrimEnd('/')}/").NormalizePath();

if (!Directory.Exists(directory))
{
AnsiConsole.MarkupLine($"[red]The specified path does not exist: {directory}[/]");

return 1;
}

await Web.Program.Run(
webBuilder: builder =>
{
builder
.WebHost.UseSetting(WebHostDefaults.ApplicationKey, "Dependify.Cli")
.UseSetting(WebHostDefaults.HttpPortsKey, Port);

builder.Services.AddSingleton<IFileProvider>(new PhysicalFileProvider(Path.GetFullPath(directory)));
builder.Services.AddSingleton<FileProviderProjectLocator>();
builder.Services.AddTransient<MsBuildService>();
builder.Services.AddSingleton<SolutionRegistry>();

builder.Services.AddHostedService(sp => new SolutionRegistryService(
sp.GetRequiredService<SolutionRegistry>(),
sp.GetRequiredService<IOptions<MsBuildConfig>>(),
new MsBuildServiceListener(
project => { },
project =>
{
if (!isLoggingEnabled)
{
AnsiConsole.MarkupLine($"[green] Loaded: [/] [grey]{project.ProjectFilePath}[/]");
}
}
),
isLoggingEnabled
));

builder.Services.Configure<MsBuildConfig>(config =>
{
config.IncludePackages = true;
config.FullScan = true;
config.Framework = settings.Framework;
});

builder.Services.AddLogging(l =>
{
l.ClearProviders().AddDebug();

if (isLoggingEnabled)
{
l.SetMinimumLevel(settings.LogLevel!.Value);
l.AddSimpleConsole();
}
});
},
webApp: app =>
{
app.Lifetime.ApplicationStarted.Register(() =>
{
if (!isLoggingEnabled)
{
AnsiConsole.Write(new FigletText("Dependify").LeftJustified().Color(Color.Olive));
AnsiConsole.MarkupLine(
$"{Environment.NewLine}{Environment.NewLine}Now listening on: [olive]{Host}[/]{Environment.NewLine}{Environment.NewLine}"
);
AnsiConsole.MarkupLine(
$"Serving files from: [green]{directory}[/]{Environment.NewLine}{Environment.NewLine}"
);
AnsiConsole.MarkupLine(
$"Press [yellow]Ctrl+C[/] to stop the server{Environment.NewLine}{Environment.NewLine}"
);
}
});

app.Lifetime.ApplicationStopped.Register(() =>
{
if (!isLoggingEnabled)
{
AnsiConsole.WriteLine();

var rule = new Rule("End of session...") { Style = Style.Parse("olive dim") };
AnsiConsole.Write(rule);
}
});
}
);

return 0;
}
}

internal class ServeCommandSettings : BaseAnalyzeCommandSettings { }

internal class SolutionRegistryService(
SolutionRegistry solutionRegistry,
IOptions<MsBuildConfig> msBuildConfig,
MsBuildServiceListener? listener,
bool isLoggingEnabled
) : BackgroundService
{
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
Task.Run(() =>
{
solutionRegistry.SetBuildServiceDiagnosticSource(listener);
solutionRegistry.LoadRegistry();
solutionRegistry.LoadSolutionsAsync(msBuildConfig.Value);
})
.ContinueWith(
_ =>
{
if (!isLoggingEnabled)
{
AnsiConsole.MarkupLine(
$"{Environment.NewLine}[olive]Loaded[/] [grey]{solutionRegistry.Solutions.Count()}[/] [olive]solutions[/]{Environment.NewLine}"
);
}
},
stoppingToken
);

return Task.CompletedTask;
}
}
11 changes: 5 additions & 6 deletions src/Dependify.Cli/Commands/ShowCommand.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
namespace Dependify.Cli.Commands;

using System.ComponentModel;
using Dependify.Cli;
using Dependify.Cli.Commands.Settings;
using Dependify.Cli.Formatters;
using Dependify.Core;
Expand Down Expand Up @@ -37,7 +36,7 @@ public override int Execute(CommandContext context, ShowCommandSettings settings

var selected = SelectNode(settings, nodes, nodesCount);

if (Utils.ShouldOutputTui(settings))
if (Cli.Utils.ShouldOutputTui(settings))
{
AnsiConsole.MarkupLine($"[green] Found: [/] [grey]{selected.Path}[/]");
}
Expand Down Expand Up @@ -204,10 +203,10 @@ private static DependencyGraph GetGraph(MsBuildService msBuildService, ShowComma
{
if (selected is SolutionReferenceNode solution)
{
return Utils.DoSomeWork(
return Cli.Utils.DoSomeWork(
ctx =>
{
Utils.SetDiagnosticSource(msBuildService, ctx);
Cli.Utils.SetDiagnosticSource(msBuildService, ctx);

return msBuildService.AnalyzeReferences(
solution,
Expand All @@ -220,10 +219,10 @@ private static DependencyGraph GetGraph(MsBuildService msBuildService, ShowComma
}
else if (selected is ProjectReferenceNode project)
{
return Utils.DoSomeWork(
return Cli.Utils.DoSomeWork(
ctx =>
{
Utils.SetDiagnosticSource(msBuildService, ctx);
Cli.Utils.SetDiagnosticSource(msBuildService, ctx);

return msBuildService.AnalyzeReferences(
project,
Expand Down
4 changes: 3 additions & 1 deletion src/Dependify.Cli/Dependify.Cli.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<OutputType>Exe</OutputType>
<AssemblyName>Dependify.Cli</AssemblyName>
<PackAsTool>true</PackAsTool>
<ToolName>dependify</ToolName>
<ToolCommandName>dependify</ToolCommandName>
<IsPackable>true</IsPackable>
</PropertyGroup>

<PropertyGroup Label="Package">
Expand Down Expand Up @@ -35,6 +36,7 @@

<ItemGroup>
<ProjectReference Include="..\Dependify.Core\Dependify.Core.csproj" />
<ProjectReference Include="..\Web\Web.csproj" />
</ItemGroup>

</Project>
3 changes: 2 additions & 1 deletion src/Dependify.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Dependify.Cli.Formatters;
using Dependify.Core;
using Microsoft.Extensions.Logging;

var app = new CommandApp(ConfigureServices(out var configuration));

Expand All @@ -20,6 +19,8 @@
}
);

config.AddCommand<ServeCommand>("serve");

#if DEBUG
config.PropagateExceptions();
config.ValidateExamples();
Expand Down
12 changes: 12 additions & 0 deletions src/Dependify.Cli/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"Development": {
"commandName": "Project",
"dotnetRunMessages": true,
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}
Loading

0 comments on commit 27caab2

Please sign in to comment.