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

CLI Refactor #3460

Merged
merged 24 commits into from Jul 7, 2021
Merged

CLI Refactor #3460

merged 24 commits into from Jul 7, 2021

Conversation

nicktolhurst
Copy link
Contributor

@nicktolhurst nicktolhurst commented Jul 3, 2021

Contributing a feature

  • I have opened a new issue for the proposal, or commented on an existing one, and ensured that the Bicep maintainers are good with the design of the feature being implemented
  • I have included "Fixes #{issue_number}" in the PR description, so GitHub can link to the issue and close it when the PR is merged
  • I have appropriate test coverage of my new feature

Fixes #3373

The goal:

To make it easier to add new commands and features to the CLI by simply adding new:

  • Commands/NewCommand.cs
  • Arguments/NewArgument.cs

Keeping in mind that a lot of the implementation may be replaced in future with System.CommandLine, but the structure can can be very similar, see:

Summary:

Unless stated below in (see NOTE:), no implementation logic has changed.

  • For consistency, move the --output-dir validation to the arguments class.

    NOTE: This effects the output slightly. Previously, using the --output-dir flag with a directory that doesn't exist would print the disclaimer before the error message. The ArgumentParser tests that use the --output-dir flag require a valid directory. I've opted to use . in these cases.

  • Split BuildAndDecompileArguments into separate classes.

  • Root command logic should be handled consistently. E.g. bicep --help and bicep --version.

  • Loosen the coupling of services and commands with DI. Commands, services and the two loggers should be added to DI.

  • Use DI to hold the invocation context (test context, production context, etc).

  • Move tests around to better match their targets. Since the logic has been refactored into multiple classes, the tests should match these. RootCommandTests, BuildCommandTests, DecompileTests, ProgramTests, etc. In almost all cases the test implementations should be the same.

    • Consolidate the two 'run' implementations of the program. var (output, error, result) = Bicep("build", "--stdout", bicepFilePath);
    • Refactors the tests

- Adds invocation context to pass around lifetime invocation objects
- Splits build/decompile arguments and commands
- Adds service collection extension for dymanic handling of commands
- Refactors main compilation work out into separate service
- Updates/fixes tests
- Adds DI
  - adds invocationContext, logger, diagnostics logger and commands to
    DI container
 - Refactors file writing and console writing out of compilation methods
 - Adds writers to DI contianer and adds extension to resolve
 - Removes the unused ICoreArguments interface
@nicktolhurst
Copy link
Contributor Author

I've updated the PR ticket with a summary of the main bits that have been cleaned up.

I've also removed some duplicated logic from the tests and split the tests to match the CLI structure.

After running some perf analysis and it looks like there's been a small amount of performance degradation (~300ms -> ~400ms) for a simple decompile/compile process. This has been minimized wherever I could find it.

@nicktolhurst nicktolhurst marked this pull request as ready for review July 5, 2021 12:20
Copy link
Member

@anthony-c-martin anthony-c-martin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a really nice refactor - thank you for showing the CLI some love!

@alex-frankel
Copy link
Collaborator

thanks @nicktolhurst! Feel free to look through the issues list and let us know if there's something else you'd like to pick up

@@ -45,7 +46,7 @@ public void LogSummary()
this.logger.Log(ToLogLevel(DiagnosticLevel.Info), summary);
}

public int ErrorCount { get; private set; }
public int ErrorCount { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set

Why does error count need to be settable from outside this class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot! This needs reverting back to a private setter.

}
else
{
return PathHelper.GetDefaultDecompileOutputPath(inputPath);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetDefaultDecompileOutputPath

The ResolveOutputPath() function in DecompileCommand and BuildCommand only differs by which function provides the default path on L81 and L73.

Worth refactoring into a single helper that takes a Func<string>?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, absolutely! Just pushed a commit for that now.

@majastrz
Copy link
Collaborator

majastrz commented Jul 7, 2021

Yeah this looks really good! Thanks for doing it!

I added a couple of minor questions and comments. Can you take a look?

Copy link
Collaborator

@majastrz majastrz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@majastrz majastrz merged commit 02f1b4d into Azure:main Jul 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor suggestions for the CLI tool
4 participants