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

feature/codescene-refactor #38

Merged
merged 13 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!--
Keep the pull request in draft mode until you are completely ready to receive reviews. That implies that the "checklist before requesting a review" below is completed and that all Github checks has passed.
-->

## Why is the change needed?

<!-- Add requirements -->

## What was changed?

<!-- Add changelog -->
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ obj
**/*.DotSettings.user

# JetBrains
.idea
.idea

# Temp file
temp.md
213 changes: 77 additions & 136 deletions AzureLiquid.Preview/PreviewProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
/// </summary>
public class PreviewProcess
{
/// <summary>
/// The argument parser.
/// </summary>
private readonly PreviewProcessArguments _args;

/// <summary>
/// Handles writing console output to private persisted log.
/// </summary>
Expand All @@ -32,6 +37,7 @@
/// </summary>
public PreviewProcess()
{
_args = new PreviewProcessArguments();
Template = string.Empty;
Content = string.Empty;
Output = "./preview.txt";
Expand Down Expand Up @@ -68,13 +74,13 @@
public string Output { get; set; }

/// <summary>
/// Gets a value indicating whether the process should watch for changes to template or content files.
/// Gets or sets a value indicating whether the process should watch for changes to template or content files.
/// </summary>
/// <value>
/// <c>true</c> if should watch; otherwise, <c>false</c>.
/// </value>
[ExcludeFromCodeCoverage]
private bool ShouldWatch { get; set; }

Check warning on line 83 in AzureLiquid.Preview/PreviewProcess.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Auto-property accessor is never used (private accessibility)

Auto-property accessor 'ShouldWatch.set' is never used

/// <summary>
/// Gets a value indicating whether this instance can parse the inputs and render the output.
Expand All @@ -87,16 +93,19 @@
/// <summary>
/// Start a new instance of the <see cref="PreviewProcess" /> class using the incoming arguments.
/// </summary>
/// <param name="args">The process arguments</param>
/// <param name="args">The process arguments.</param>
/// <returns>A new instance of the <see cref="PreviewProcess" /> class.</returns>
[ExcludeFromCodeCoverage]
public static PreviewProcess Create(string[] args)
{
var preview = new PreviewProcess();

// deepcode ignore XmlInjection: XML is not used by this application, it is passed back to the user, deepcode ignore XXE: <please specify a reason of ignoring this>
preview.ParseArguments(args);
preview.Template = preview._args.ParsePath(args, "template");
preview.Content = preview._args.ParsePath(args, "content");
preview.Output = preview._args.ParsePath(args, "output");

HandleNoArgumentsPassed(args, preview);

if (preview.CanRender)
{
RenderAndWatch(preview);
Expand All @@ -109,107 +118,6 @@
return preview;
}

/// <summary>Parses the arguments and sets process options.</summary>
/// <param name="args">
/// The arguments. Values are expected to be "--template", "--help", "--content", "--output" or
/// "--watch".
/// </param>
private void ParseArguments(string[] args)
{
for (var index = 0; index < args.Length; index++)
{
var arg = args[index];
var path = Directory.GetCurrentDirectory();
ParseTemplate(args, index, arg, path);
ParseContent(args, index, arg, path);
ParseOutputResults(args, index, arg, path);

// Switch watch param if needed
if (IsArgMatch(arg, "watch"))
{
ShouldWatch = true;
}

// Show help info
if (IsArgMatch(arg, "help"))
{
WriteHelpOutput();
}
}
}

/// <summary>
/// Parses the output results file path if specified.
/// </summary>
/// <param name="args">The passed command arguments.</param>
/// <param name="index">The parameter index.</param>
/// <param name="arg">The current argument.</param>
/// <param name="path">The target path.</param>
private void ParseOutputResults(string[] args, int index, string arg, string path)
{
if (!IsArgMatch(arg, "output") || index - 1 >= args.Length)
{
return;
}

try
{
Output = Path.GetFullPath(args[index + 1], path);
}
catch
{
WriteErrorLine($"Invalid output path: {args[index + 1]}");
}
}

/// <summary>
/// Parses the incoming content file path if specified.
/// </summary>
/// <param name="args">The passed command arguments.</param>
/// <param name="index">The parameter index.</param>
/// <param name="arg">The current argument.</param>
/// <param name="path">The target path.</param>
private void ParseContent(string[] args, int index, string arg, string path)
{
if (!IsArgMatch(arg, "content") || index - 1 >= args.Length)
{
return;
}

try
{
Content = Path.GetFullPath(args[index + 1], path);
}
catch
{
WriteErrorLine($"Invalid content path: {args[index + 1]}");
}
}

/// <summary>
/// Parses the incoming template file path if specified.
/// </summary>
/// <param name="args">The passed command arguments.</param>
/// <param name="index">The parameter index.</param>
/// <param name="arg">The current argument.</param>
/// <param name="path">The target path.</param>
private void ParseTemplate(string[] args, int index, string arg, string path)
{
if (!IsArgMatch(arg, "template") || index - 1 >= args.Length)
{
return;
}

try
{
Template = Path.GetFullPath(args[index + 1], path);
}
catch
{
WriteErrorLine($"Invalid template path: {args[index + 1]}");
}
}

/// <summary>
/// Renders the output and watches for changes if specified.
/// </summary>
Expand Down Expand Up @@ -295,7 +203,7 @@
/// <returns>
/// <c>true</c> if argument found; otherwise, <c>false</c>.
/// </returns>
private static bool IsArgMatch(string arg, string key)

Check warning on line 206 in AzureLiquid.Preview/PreviewProcess.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Type member is never used (private accessibility)

Method 'IsArgMatch' is never used
{
return string.CompareOrdinal(arg, "--" + key) == 0;
}
Expand All @@ -308,76 +216,109 @@
{
if (!CanRender)
{
WriteErrorLine("Unable to render as inputs our outputs not found or not specified");
WriteErrorLine("Unable to render as inputs or outputs not found or not specified");

Check warning on line 219 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L219

Added line #L219 was not covered by tests
return string.Empty;
}

string content;
try
var content = ReadFileContent(Content);
if (string.IsNullOrEmpty(content))
{
content = File.ReadAllText(Content);
return string.Empty;

Check warning on line 226 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L226

Added line #L226 was not covered by tests
}
catch (IOException)

var template = ReadFileContent(Template);
if (string.IsNullOrEmpty(template))
{
// Lock issue, wait and retry
Thread.Sleep(TimeSpan.FromSeconds(1));
return Render();
return string.Empty;

Check warning on line 232 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L232

Added line #L232 was not covered by tests
}

string template;
var parser = new LiquidParser();
if (!SetParserContent(parser, content))

Check notice on line 236 in AzureLiquid.Preview/PreviewProcess.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

'if-return' statement can be rewritten as 'return' statement

Convert into 'return' statement
{
return string.Empty;

Check warning on line 238 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L237-L238

Added lines #L237 - L238 were not covered by tests
}

return RenderTemplate(parser, template);
}

/// <summary>
/// Reads the file content.
/// </summary>
/// <param name="filePath">The file path.</param>
/// <returns>The file content.</returns>
private string ReadFileContent(string filePath)
{
try
{
template = File.ReadAllText(Template);
return File.ReadAllText(filePath);
}
catch (IOException)
{
// Lock issue, wait and retry
Thread.Sleep(TimeSpan.FromSeconds(1));
return Render();
return ReadFileContent(filePath);

Check warning on line 259 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L259

Added line #L259 was not covered by tests
}
catch (Exception e)
{
LogWarning($"Unable to read file: {filePath}", e);
return string.Empty;

Check warning on line 264 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L261-L264

Added lines #L261 - L264 were not covered by tests
}
Fixed Show fixed Hide fixed
}

var parser = new LiquidParser();

if (Content.ToLowerInvariant().EndsWith(".json"))
/// <summary>
/// Sets the parser content.
/// </summary>
/// <param name="parser">The parser.</param>
/// <param name="content">The content.</param>
/// <returns>
/// <c>true</c> if the content was set; otherwise, <c>false</c>.
/// </returns>
private bool SetParserContent(LiquidParser parser, string content)
{
try
{
try
if (Content.ToLowerInvariant().EndsWith(".json"))
{
parser.SetContentJson(content);
}
catch (Exception e)
{
LogWarning(" Unable to read input JSON file", e);
return string.Empty;
}
}

if (Content.ToLowerInvariant().EndsWith(".xml"))
{
try
else if (Content.ToLowerInvariant().EndsWith(".xml"))
{
parser.SetContentXml(content);
}
catch (Exception ex)
else
{
LogWarning(" Unable to read input XML file", ex);
return string.Empty;
WriteErrorLine("Unsupported content type");
return false;

Check warning on line 291 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L290-L291

Added lines #L290 - L291 were not covered by tests
}
}
catch (Exception e)
{
LogWarning("Unable to set parser content", e);
return false;

Check warning on line 297 in AzureLiquid.Preview/PreviewProcess.cs

View check run for this annotation

Codecov / codecov/patch

AzureLiquid.Preview/PreviewProcess.cs#L294-L297

Added lines #L294 - L297 were not covered by tests
}
Dismissed Show dismissed Hide dismissed

return true;
}

/// <summary>
/// Renders the template.
/// </summary>
/// <param name="parser">The parser.</param>
/// <param name="template">The template.</param>
/// <returns>The output from the template.</returns>
private string RenderTemplate(LiquidParser parser, string template)
{
try
{
var output = parser.Parse(template).Render();
File.WriteAllText(Output, output);

return output;
}
catch (Exception e)
{
WriteErrorLine($"Error: {e.Message}");
return string.Empty;
}

// TODO: Refactor this method
}

/// <summary>
Expand Down
63 changes: 63 additions & 0 deletions AzureLiquid.Preview/PreviewProcessArguments.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace AzureLiquid.Preview;

/// <summary>
/// Handles the arguments passed to the preview process.
/// </summary>
public class PreviewProcessArguments
{
/// <summary>
/// The current path of the process.
/// </summary>
private readonly string _path;

/// <summary>
/// Initializes a new instance of the <see cref="PreviewProcessArguments" /> class.
/// </summary>
public PreviewProcessArguments() => _path = Directory.GetCurrentDirectory();

/// <summary>
/// Gets the index of the argument, if it exists.
/// </summary>
/// <param name="key">The key.</param>
/// <returns>The index of the argument.</returns>
private static int GetArgumentIndex(string[] args, string key)

Check warning on line 23 in AzureLiquid.Preview/PreviewProcessArguments.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Invalid XML documentation comment

Parameter 'args' has no matching param tag in the XML comment for AzureLiquid.Preview.PreviewProcessArguments.GetArgumentIndex (but other parameters do)
{
for (int i = 0; i < args?.Length; i++)

Check warning on line 25 in AzureLiquid.Preview/PreviewProcessArguments.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Conditional access qualifier expression is not null according to nullable reference types' annotations

Conditional access qualifier expression is never null according to nullable reference types' annotations
{
if (IsArgMatch(args[i], key))
{
return i;
}
}

return -1;
}

/// <summary>
/// Determines whether the argument matches the partial argument key name.
/// </summary>
/// <param name="arg">The argument.</param>
/// <param name="key">The key.</param>
/// <returns>
/// <c>true</c> if argument found; otherwise, <c>false</c>.
/// </returns>
private static bool IsArgMatch(string arg, string key)
{
return string.CompareOrdinal(arg, "--" + key) == 0;
}

/// <summary>
/// Parses the argument value.
/// </summary>
/// <param name="args">The arguments.</param>
/// <param name="key">The key.</param>
/// <returns>The argument value.</returns>
public string ParsePath(string[] args, string key)
{
var index = GetArgumentIndex(args, key);
return
index == -1 || index - 1 >= args?.Length || args == null ? string.Empty : // No match, or no arguments passed

Check warning on line 59 in AzureLiquid.Preview/PreviewProcessArguments.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

Conditional access qualifier expression is not null according to nullable reference types' annotations

Conditional access qualifier expression is never null according to nullable reference types' annotations
Path.GetFullPath(args[index + 1], _path) // Argument found, parsing path
?? string.Empty; // Argument found, but path is invalid

Check warning on line 61 in AzureLiquid.Preview/PreviewProcessArguments.cs

View workflow job for this annotation

GitHub Actions / Qodana for .NET

'??' condition is never null according to nullable reference types' annotations

'??' left operand is never null according to nullable reference types' annotations
}
}
Loading
Loading