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

[#1715] Add RepoSense CLI Wizard Walkthrough #1950

Open
wants to merge 33 commits into
base: master
Choose a base branch
from

Conversation

sikai00
Copy link
Member

@sikai00 sikai00 commented Mar 15, 2023

Fixes #1715
This PR is co-authored with @MarcusTXK.

Proposed commit message

For a new user trying to get into RepoSense, the command line arguments
may be hard and intimidating to navigate and takes some effort to 
reference from the user guide. If a new user wants to try out RepoSense
(instead of immediately putting it to actual use), he may be put off 
by the effort needed for entry.

Let's implement a RepoSense CLI wizard. This makes it easier for a 
new user to understand how a run of RepoSense may work, understand 
some of the flags we have, and eases the learning curve required 
to use RepoSense.

Co-authored-by: Marcus Tang <txk.marcus@gmail.com>
Co-authored-by: Si Kai <sikai4111@gmail.com>

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.

└── wizard/
    ├── prompts/
    │   ├── Prompt.java
    │   ├── OptionalPrompt.java
    │   └── ...
    ├── WizardRunner.java
    ├── Wizard.java
    ├── BasicWizard.java
    └── InputBuilder.java

The WizardRunner.java acts as the simulator and takes in Wizard.java (implemented under BasicWizard.java, so as to allow for different future Wizards). WizardRunner.java maintains a Deque of Prompt, which is initially supplemented by a concrete implementation of Wizard.java.

Each Prompt.java may be used to add a config flag and its argument via InputBuilder.java by calling WizardRunner::buildInput(Scanner sc). At the end when no other prompts exist in the deque, the method ends. The complete input string is created when WizardRunner::getBuiltInput() and subsequently used when WizardRunner::run() is finally called. In a similar sense to that of the current systemtest, the string is directly passed into RepoSense::main to produce the expected output and behavior.

Each concrete implementation of Prompt.java can return even more prompts to the Deque, so a Prompt is able to define the next Prompt 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 of Prompt, as there were many Prompt that required a yes-or-no-to-have question, then requiring a follow-up Prompt should the user answer yes. The follow-up is provided through the optionallyRun method defined only in OptionalPrompt, such that the WizardRunner sees no difference between an OptionalPrompt and a regular Prompt.

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.

  1. Currently, errors are only detected when we pass the completed input string to 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.

@github-actions github-actions bot requested a deployment to dashboard-1950 March 15, 2023 16:45 Abandoned
@github-actions github-actions bot requested a deployment to docs-1950 March 15, 2023 16:45 Abandoned
MarcusTXK and others added 2 commits March 16, 2023 01:08
Add documentation for init command

Co-authored-by: Marcus Tang <txk.marcus@gmail.com>
Co-authored-by: Si Kai <sikai4111@gmail.com>
@chan-j-d
Copy link
Contributor

Some quick comments before reviewing:

  • Should probably add the command to test somewhere in the PR itself
  • The commit message's final line should be a short call to action. Something like 'Let's implement a setup walkthrough wizard'. The additional reasoning can be moved into the explanation portion of the commit message

Copy link
Contributor

@chan-j-d chan-j-d left a 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) {
Copy link
Contributor

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?

Copy link
Member

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;
}
Copy link
Contributor

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

Copy link
Member

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[] {};
}
Copy link
Contributor

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

Copy link
Member

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.

Copy link
Contributor

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

Copy link
Member Author

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()
};
Copy link
Contributor

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

Copy link
Member

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.

@github-actions github-actions bot requested a deployment to dashboard-1950 April 2, 2023 14:01 Abandoned
@github-actions github-actions bot requested a deployment to docs-1950 April 2, 2023 14:01 Abandoned
@github-actions github-actions bot requested a deployment to dashboard-1950 April 2, 2023 14:07 Abandoned
@github-actions github-actions bot requested a deployment to docs-1950 April 2, 2023 14:07 Abandoned
@github-actions github-actions bot temporarily deployed to dashboard-1950 April 2, 2023 14:08 Inactive
@github-actions github-actions bot temporarily deployed to docs-1950 April 2, 2023 14:08 Inactive
@github-actions github-actions bot requested a deployment to dashboard-1950 April 3, 2023 17:03 Abandoned
@github-actions github-actions bot requested a deployment to docs-1950 April 3, 2023 17:03 Abandoned
@MarcusTXK MarcusTXK requested a review from chan-j-d April 4, 2023 15:07
Copy link
Contributor

@chan-j-d chan-j-d left a 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};
}
}
Copy link
Contributor

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

Copy link
Member Author

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)?

Copy link
Member

Choose a reason for hiding this comment

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

In a previous implementation, it actually took in a Prompt in the constructor so we could avoid spawning optional subclasses. However, we decided that this design wass a little strange OOP-wise.

You can view the discussion me and @sikai00 had here.

Copy link
Contributor

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());
}
}
Copy link
Contributor

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.

Copy link
Member Author

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"?

Copy link
Contributor

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

Copy link
Member Author

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());
}

}
Copy link
Contributor

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)

@github-actions
Copy link
Contributor

Hi,
We are going to mark this PR as stale because it has been inactive for the past 30 days.
If no further activity occurs within the following 7 days, it will be automatically closed so that others can take up the issue.
If you are still working on this PR, please make a follow-up commit within 7 days and leave a comment to remove the stale label.
Do let us know if you are stuck so that we can help you!'

@github-actions github-actions bot added the Stale label May 13, 2023
@github-actions
Copy link
Contributor

This PR was closed because it has been marked as stale for 7 days with no activity.
Feel free to reopen this PR if you would like to continue working on it.

@github-actions github-actions bot closed this May 21, 2023
@ckcherry23 ckcherry23 reopened this Mar 9, 2024
@github-actions github-actions bot requested a deployment to dashboard-1950 March 9, 2024 14:34 Abandoned
@github-actions github-actions bot requested a deployment to docs-1950 March 9, 2024 14:34 Abandoned
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RepoSense CLI set-up walkthrough
5 participants