-
Notifications
You must be signed in to change notification settings - Fork 157
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
[#1715] Add RepoSense CLI Wizard Walkthrough #1950
base: master
Are you sure you want to change the base?
Conversation
Add DES skeleton code
Add cli wizard flag and optional, view and repo prompts
Add UntilPrompt
Add documentation for init command Co-authored-by: Marcus Tang <[email protected]> Co-authored-by: Si Kai <[email protected]>
Some quick comments before reviewing:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some quick comments. I think the code is overall pretty well written and don't have too much to say in that direction. And regarding testing I'm also not too sure how much automated testing can be done
* | ||
* @param paths The repo paths. | ||
*/ | ||
public InputBuilder addRepos(String paths) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this work well with multiple quoted file path arguments that contain spaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, it simply passes the input entirely to RepoSense::main
, where it is parsed as if the user passed it via the cli, so all parsing functionality for file paths will be the same.
|
||
public boolean isShallowCloning() { | ||
return shallowCloning; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should only add the ones we are currently using into this class and delete the remaining. I don't think this feature will grow to implement many of the other flags
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, we will clean up the unused InputBuilder.java
functions.
@Override | ||
public Prompt[] run() { | ||
return new Prompt[] {}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is correct. It should be view or no view without specification. The -v
with argument is for when the user does not want to analyze anything and just wants to view a pre-analyzed report
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic for this is implemented in OptionalViewPrompt.java
, where the user is prompted with "Do you want to start a server to display the report?", allowing them to choose whether or not to use the ViewPrompt
. ViewPrompt
currently contains logic for configuration of the --view
flag if it is present.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand that. But the OptionalViewPrompt shouldn't spawn a ViewPrompt since they dont serve the same purpose. There is no need for the user to supply an argument for --view unless they simply want to view a report that has already been generated, so it doesn't really make sense at all in this wizard walkthrough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, for this I believe it will be better to drop the need for an argument as there is no way of changing the output directory immediately after generating it anyway.
new OptionalUntilPrompt(), | ||
new OptionalViewPrompt(), | ||
new RepoPrompt() | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried it myself and I don't think it makes a lot of sense to put the repo last. I think it should be first since I'm usually thinking of what I want to analyze and then the time interval to analyze rather than the other way around
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, lets change it to be the first.
…ilder, Update BasicWizard order
…0/RepoSense into 1715-reposense-cli-wizard
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation changes look good. I made quite a few comments and suggestions this time round after reviewing it again since I understand the PR better now.
Also wanted to know if you thought it might be better to include some fancy text like [RepoSense Wizard]:
to kind of denote that the program is 'talking to the user'.
// Repeat OptionalPrompt until a valid input is provided | ||
return new Prompt[] {this}; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a requested change but more a point of discussion. Was wondering if there is a point in creating the subclasses since you could get this class to have a constructor that takes in the description and an instance of the prompt to be shown if Yes is chosen.
I wrote this comment more from the perspective of testing since the subclass behaviors are almost identical I feel. See other comment about testing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what you mentioned, do you mean to have a single class per flag (e.g., SincePrompt should handle both asking if it should take in a SincePrompt, as well as actually taking in a SincePrompt)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was referring to the version Marcus mentioned. I don't think cyclic dependency is correct for it, the dependency relations are almost the same in either case and is not cyclic since Prompt doesnt depend on OptionalPrompt. This just changes a dependency to an association. Regardless, I don't think it's a big issue
.build(); | ||
assertEquals(expectedInput, wizardRunner.getBuiltInput()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering if it might be better to test individual prompts instead and have a separate test suite for input builder which tests combining multiple repo flags.
This way, you don't have to rewrite the inputs every time the ordering of prompts is changed.
Additionally, I think it's missing test cases for completely invalid inputs for the optional prompt queries since those are supposed to repeat on invalid inputs if I'm understanding it correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can implement a TestWizard
(similar to BasicWizard
) that takes in individual prompts. That way, we can test any individual prompts/combinations of prompts. In this way, we reduce the number of test cases for BasicWizard
as such, so that the re-writing of input doesn't have to happen for any of the possible new wizards we write, while still being able to test for correctness overall.
Just to check, the test case you mentioned is the one where we repeated input garbage to the OptionalPrompt, and finally a "yes"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I'm not sure if I'm misunderstanding this
Just to check, the test case you mentioned is the one where we repeated input garbage to the OptionalPrompt, and finally a "yes"?
But is that suggesting that such a test case exists already or that that is the test case I want. Because I don't think I see such a test case and yes that's kind of what I want.
In general, I'd like to see more individualized test cases and only a few combined ones that are preferably done in a way that is independent of the order of the actual prompts since those may be reordered arbitrarily and we wouldnt want to have to fix test cases every time we do that.
Also I guess I have to ask at this point what the difference between TestWizard and Wizard would be
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But is that suggesting that such a test case exists already or that that is the test case I want. Because I don't think I see such a test case and yes that's kind of what I want.
Sorry for the confusion, this is suggesting the test case that you want, and does not already exist.
In general, I'd like to see more individualized test cases and only a few combined ones that are preferably done in a way that is independent of the order of the actual prompts since those may be reordered arbitrarily and we wouldnt want to have to fix test cases every time we do that.
This would be a beneficial change. Though it is as you mentioned, there is still going to be some (but minimal number) of test cases with the ordered prompts.
Also I guess I have to ask at this point what the difference between TestWizard and Wizard would be
TestWizard would just be a concrete implementation of the abstract Wizard class. For example, we have a BasicWizard currently. TestWizard will be a new, test-specific implementation of the abstract Wizard class where we can input specific types of Prompts specifically to test the prompts within the TestWizard.
return addQuotationMarksToPath(path.toString()); | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I recall that there is an InputBuilder
class in a util package in test
. Was wondering if it might be worthwhile to move that class over (apologies about this in relation to my previous comment about unused input flags)
Hi, |
This PR was closed because it has been marked as stale for 7 days with no activity. |
Fixes #1715
This PR is co-authored with @MarcusTXK.
Proposed commit message
Other information
How to test
Pull from the PR branch and run reposense with the flag
--init
.Overview of the wizard implementation
The wizard is implemented using a discrete event simulator (DES) style. This allows us to avoid long if-else conditions for the prompting logic, as each prompt can invoke another prompt simply by creating it and adding it into the queue.
The
WizardRunner.java
acts as the simulator and takes inWizard.java
(implemented underBasicWizard.java
, so as to allow for different future Wizards).WizardRunner.java
maintains a Deque ofPrompt
, which is initially supplemented by a concrete implementation ofWizard.java
.Each
Prompt.java
may be used to add a config flag and its argument viaInputBuilder.java
by callingWizardRunner::buildInput(Scanner sc)
. At the end when no other prompts exist in the deque, the method ends. The complete input string is created whenWizardRunner::getBuiltInput()
and subsequently used whenWizardRunner::run()
is finally called. In a similar sense to that of the currentsystemtest
, the string is directly passed intoRepoSense::main
to produce the expected output and behavior.Each concrete implementation of
Prompt.java
can return even more prompts to the Deque, so aPrompt
is able to define the nextPrompt
that should be run. This is particularly useful in this example case where we ask the user a yes-or-no question if they want to indicate the start date for analysis, we can follow that up with a Prompt to get the date or choose to simply move on.OptionalPrompt
OptionalPrompt
is an abstract subclass ofPrompt
, as there were manyPrompt
that required a yes-or-no-to-have question, then requiring a follow-upPrompt
should the user answer yes. The follow-up is provided through theoptionallyRun
method defined only inOptionalPrompt
, such that theWizardRunner
sees no difference between anOptionalPrompt
and a regularPrompt
.Possible future improvements
Below are some possible future improvements that were not included in the interest of time and to ensure a minimal viable product.
RepoSense::main
. If a user were to mistype an input, they will have to go through the trouble of re-entering all the inputs. We can have better error prompts such that in the case of an invalid input, we can immediately correct and re-prompt, avoiding having to make the user go through the whole setup again just to correct an erroneous input.