Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 25 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj", "SimpleStateMachine.StructuralSearch.Action/"]
RUN dotnet restore "SimpleStateMachine.StructuralSearch.Action/SimpleStateMachine.StructuralSearch.Action.csproj"
COPY . .
WORKDIR "/src/SimpleStateMachine.StructuralSearch.Action"
RUN dotnet build "SimpleStateMachine.StructuralSearch.Action.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "SimpleStateMachine.StructuralSearch.Action.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "SimpleStateMachine.StructuralSearch.Action.dll"]
58 changes: 58 additions & 0 deletions SimpleStateMachine.StructuralSearch.Action/ActionInputs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using CommandLine;

namespace SimpleStateMachine.StructuralSearch.Action;

public class ActionInputs
{
string _repositoryName = null!;
string _branchName = null!;

public ActionInputs()
{
if (Environment.GetEnvironmentVariable("GREETINGS") is { Length: > 0 } greetings)
{
Console.WriteLine(greetings);
}
}

[Option('o', "owner",
Required = true,
HelpText = "The owner, for example: \"dotnet\". Assign from `github.repository_owner`.")]
public string Owner { get; set; } = null!;

[Option('n', "name",
Required = true,
HelpText = "The repository name, for example: \"samples\". Assign from `github.repository`.")]
public string Name
{
get => _repositoryName;
set => ParseAndAssign(value, str => _repositoryName = str);
}

[Option('b', "branch",
Required = true,
HelpText = "The branch name, for example: \"refs/heads/main\". Assign from `github.ref`.")]
public string Branch
{
get => _branchName;
set => ParseAndAssign(value, str => _branchName = str);
}

[Option('d', "dir",
Required = true,
HelpText = "The root directory to start recursive searching from.")]
public string Directory { get; set; } = null!;

[Option('w', "workspace",
Required = true,
HelpText = "The workspace directory, or repository root directory.")]
public string WorkspaceDirectory { get; set; } = null!;

static void ParseAndAssign(string? value, Action<string> assign)
{
if (value is { Length: > 0 } && assign is not null)
{
assign(value.Split("/")[^1]);
}
}
}
105 changes: 105 additions & 0 deletions SimpleStateMachine.StructuralSearch.Action/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System.Text;
using SimpleStateMachine.StructuralSearch.Action;
using System.Web;
using CommandLine;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileSystemGlobbing;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using static CommandLine.Parser;

using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((_, services) =>
{

})
.Build();

static TService Get<TService>(IHost host)
where TService : notnull =>
host.Services.GetRequiredService<TService>();

static async Task StartAnalysisAsync(ActionInputs inputs, IHost host)
{
// using ProjectWorkspace workspace = Get<ProjectWorkspace>(host);
using CancellationTokenSource tokenSource = new();

Console.CancelKeyPress += delegate { tokenSource.Cancel(); };

// var projectAnalyzer = Get<ProjectMetricDataAnalyzer>(host);

Matcher matcher = new();
matcher.AddIncludePatterns(new[] { "**/*.csproj", "**/*.vbproj" });

// Dictionary<string, CodeAnalysisMetricData> metricData = new(StringComparer.OrdinalIgnoreCase);
var projects = matcher.GetResultsInFullPath(inputs.Directory);

foreach (var project in projects)
{
// var metrics =
// await projectAnalyzer.AnalyzeAsync(
// workspace, project, tokenSource.Token);
//
// foreach (var (path, metric) in metrics)
// {
// metricData[path] = metric;
// }
}

// var updatedMetrics = false;
// var title = "";
// StringBuilder summary = new();
// if (metricData is { Count: > 0 })
// {
// var fileName = "CODE_METRICS.md";
// var fullPath = Path.Combine(inputs.Directory, fileName);
// var logger = Get<ILoggerFactory>(host).CreateLogger(nameof(StartAnalysisAsync));
// var fileExists = File.Exists(fullPath);
//
// logger.LogInformation(
// $"{(fileExists ? "Updating" : "Creating")} {fileName} markdown file with latest code metric data.");
//
// summary.AppendLine(
// title =
// $"{(fileExists ? "Updated" : "Created")} {fileName} file, analyzed metrics for {metricData.Count} projects.");
//
// foreach (var (path, _) in metricData)
// {
// summary.AppendLine($"- *{path}*");
// }
//
// var contents = metricData.ToMarkDownBody(inputs);
// await File.WriteAllTextAsync(
// fullPath,
// contents,
// tokenSource.Token);
//
// updatedMetrics = true;
// }
// else
// {
// summary.Append("No metrics were determined.");
// }
//
// // https://docs.github.com/actions/reference/workflow-commands-for-github-actions#setting-an-output-parameter
// Console.WriteLine($"::set-output name=updated-metrics::{updatedMetrics}");
// Console.WriteLine($"::set-output name=summary-title::{title}");
// Console.WriteLine($"::set-output name=summary-details::{summary}");

Environment.Exit(0);
}

var parser = Default.ParseArguments(() => new ActionInputs(), args);
parser.WithNotParsed(
errors =>
{
Get<ILoggerFactory>(host)
.CreateLogger("DotNet.GitHubAction.Program")
.LogError(
string.Join(Environment.NewLine, errors.Select(error => error.ToString())));

Environment.Exit(2);
});

await parser.WithParsedAsync(options => StartAnalysisAsync(options, host));
await host.RunAsync();
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<DockerDefaultTargetOS>Windows</DockerDefaultTargetOS>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="MarkdownBuilder" Version="0.2.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Metrics" Version="3.3.3" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.FileSystemGlobbing" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
</ItemGroup>

</Project>
17 changes: 17 additions & 0 deletions SimpleStateMachine.StructuralSearch.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleStateMachine.Structur
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleStateMachine.StructuralSearch.Sandbox", "src\SimpleStateMachine.StructuralSearch.Sandbox\SimpleStateMachine.StructuralSearch.Sandbox.csproj", "{263ABF7D-9728-4224-A584-5412E158D4BB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleStateMachine.StructuralSearch.Action", "SimpleStateMachine.StructuralSearch.Action\SimpleStateMachine.StructuralSearch.Action.csproj", "{E22FFF76-E929-4E01-B2B3-4B9283705EDE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6CB879CC-E497-41C0-AEBD-864E9D3807A6}"
ProjectSection(SolutionItems) = preProject
Dockerfile = Dockerfile
.dockerignore = .dockerignore
.gitignore = .gitignore
LICENSE = LICENSE
README.md = README.md
global.json = global.json
action.yml = action.yml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -31,6 +44,10 @@ Global
{263ABF7D-9728-4224-A584-5412E158D4BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{263ABF7D-9728-4224-A584-5412E158D4BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{263ABF7D-9728-4224-A584-5412E158D4BB}.Release|Any CPU.Build.0 = Release|Any CPU
{E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E22FFF76-E929-4E01-B2B3-4B9283705EDE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
43 changes: 43 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: 'Structural search'
description: 'A Github action that maintains a CODE_METRICS.md file, reporting cyclomatic complexity, maintainability index, etc.'
branding:
icon: sliders
color: purple
inputs:
owner:
description: 'The owner of the repo. Assign from github.repository_owner. Example, "dotnet".'
required: true
name:
description: 'The repository name. Example, "samples".'
required: true
branch:
description: 'The branch name. Assign from github.ref. Example, "refs/heads/main".'
required: true
dir:
description: 'The root directory to work from. Example, "path/to/code".'
required: true
workspace:
description: 'The workspace directory.'
required: false
default: '/github/workspace'
outputs:
summary-title:
description: 'The title of the code metrics action.'
summary-details:
description: 'A detailed summary of all the projects that were flagged.'
updated-metrics:
description: 'A boolean value, indicating whether or not the CODE_METRICS.md was updated as a result of running this action.'
runs:
using: 'docker'
image: 'Dockerfile'
args:
- '-o'
- ${{ inputs.owner }}
- '-n'
- ${{ inputs.name }}
- '-b'
- ${{ inputs.branch }}
- '-d'
- ${{ inputs.dir }}
- '-w'
- ${{ inputs.workspace }}
1 change: 1 addition & 0 deletions src/SimpleStateMachine.StructuralSearch.Sandbox/Expr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ public double Invoke()
BinaryOperatorType.Mul => Left.Invoke() * Right.Invoke(),
BinaryOperatorType.Div => Left.Invoke() / Right.Invoke(),
BinaryOperatorType.Sub => Left.Invoke() - Right.Invoke(),
_ => throw new ArgumentOutOfRangeException()
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
$var$ = $value1$;
FindRules:
- $sign$ In ("Is", "==", "!=", "is not")
- $value$ In ($value1$, "$value1$.Value", $value2$, "$value2$.Value")
- $value$ In ($value1$, "$value1$\.Value", $value2$, "$value2$\.Value")
ReplaceTemplate: |-
$var$ = $value1$ ?? $value2$;
ReplaceRules:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
$var$ = $value1$;
FindRules:
- $sign$ In ("Is", "==", "!=", "is not")
- $value$ In ($value1$, "$value1$.Value", $value2$, "$value2$.Value")
- $value$ In ($value1$, "$value1$\.Value", $value2$, "$value2$\.Value")
ReplaceTemplate: |-
$var$ = $value1$ ?? $value2$;
ReplaceRules:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
$sign$ In ("Is", "==", "!=", "is not")
$value$ In ($value1$, "$value1$.Value", $value2$, "$value2$.Value")
$value$ In ($value1$, "$value1$\.Value", $value2$, "$value2$\.Value")
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ public void FindRuleExprParsingShouldBeEqualsCustomResult(string ruleStr, string
Assert.NotNull(rule);
Assert.Equal(_ruleStr, customResult.ToLower());
}

[Theory]
[InlineData("FindRule/NullUnionOperator.txt", "$sign$ In \"Is\",\"==\",\"!=\",\"is not\"")]
[InlineData("FindRule/NullUnionOperator.txt", "$sign$ In \"Is\",\"==\",\"!=\",\"is not\"", "$value$ In $value1$,\"$value1$\\.Value\",$value2$,\"$value2$\\.Value\"")]
[InlineData("FindRule/AssignmentNullUnionOperator.txt", "$sign$ In \"Is\",\"==\",\"!=\",\"is not\"")]
public void FindRuleParsingFromFileShouldBeSuccess(string filePath, string customResult)
public void FindRuleParsingFromFileShouldBeSuccess(string filePath, params string[] customResult)
{
var ruleStr = File.ReadAllText(filePath);
var rule = StructuralSearch.ParseFindRule(ruleStr);
var _ruleStr = rule.ToString()?.ToLower();
Assert.NotNull(rule);
Assert.Equal(_ruleStr, customResult.ToLower());
var rules = ruleStr.Split(Constant.LineFeed)
.Select(StructuralSearch.ParseFindRule);
var rulesAsStr = rules.Select(x => x.ToString()).ToArray();

Assert.True(customResult.SequenceEqual(rulesAsStr));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class FindTemplateTests
[InlineData("FindTemplate/AssignmentNullUnionOperator.txt")]
[InlineData("FindTemplate/NestedParenthesised.txt")]
[InlineData("FindTemplate/TernaryOperator.txt")]
public void TemplateParsingShouldBeSuccess(string templatePath)
public void FindTemplateFromFileParsingShouldBeSuccess(string templatePath)
{
var findTemplate = File.ReadAllText(templatePath);
var template = StructuralSearch.ParseFindTemplate(findTemplate);
Expand Down Expand Up @@ -40,5 +40,19 @@ public void SourceParsingBeFindTemplateShouldBeSuccess(string templatePath, stri
Assert.NotNull(findParser);
Assert.Equal(match.Match.Lenght, source.Length);
}

[Theory]
[InlineData("( $var$")]
public void FindTemplateParsingShouldBeFail(string templateStr)
{
Assert.Throws<ParseException>(() => StructuralSearch.ParseFindTemplate(templateStr));
}

[Theory]
[InlineData("( $var$ )")]
public void FindTemplateParsingShouldBeSuccess(string templateStr)
{
var template = StructuralSearch.ParseFindTemplate(templateStr);
}
}
}
Loading