-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Add destroy command #487
Add destroy command #487
Conversation
Just ran into another issue with reusing |
@antonmoiseev wow this is a good one. If you allow me my two cents here. I think it would be best to use "remove" instead of destroy. Wording wise it would be a better approach |
@antonmoiseev Thanks so much for doing this PR!
|
I think "destroy" is a good name, as it's quite dangerous sounding, which reflects the truth of the command. You should think twice before you call it. |
@cannikin thank you for the feedback! Sorry for "ungenerate" though 😬, left "destroy" for now as Tom suggested. Just to give you an update on the progress - all commands seem to work fine now, but I need to get rid of empty dirs and add tests. One thing I'm not sure about is |
I think it’s okay to leave it. Checking if anything else uses it seems like more trouble than it’s worth.
… On May 1, 2020, at 10:48 PM, Anton Moiseev ***@***.***> wrote:
@cannikin thank you for the feedback! Sorry for "ungenerate" though 😬, left "destroy" for now as Tom suggested.
Just to give you an update on the progress - all commands seem to work fine now, but I need to get rid of empty dirs and add tests. One thing I'm not sure about is scaffold.css file. When destroying a scaffold there is no easy way to identify whether anyone else is still using scaffold.css file, so I cannot decide whether it needs to be cleaned up as well. I was thinking about searching for rw-scaffold CSS class within layout components, but probably it would be too much. Do you have any suggestions here?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
|
That log looks fine to me, I like seeing everything it's doing! |
Agreed, you definitely want a record of everything being deleted. |
Hi @antonmoiseev is this one ready for review + merge? Please disable "draft" and loop in Rob Cameron if so. Thanks! |
Feature-wise it's ready for review, but tests are missing. Destroy commands primarily consist of two parts:
Since destroy reuses @cannikin could you please review this PR? If you have any tests suggestions, please let me know, I'll address them. |
Hmmm... @peterp can you think of any way to test that files are being deleted? We discussed mocking out the filesystem at one point, but when we went to just testing the result of In Ruby there's a gem called mocha that lets you set expectations on method calls. So you can say " |
@RobertBroersma any test-related suggestions here? |
@thedavidprice I'm not familiar with the
@cannikin There certainly is something like that in Jest! There's spies (for "spying" on functions, but leaving them intact), and mocks, for faking out functions. The Jest docs on mocks actually feature an example for mocking Hope that helps! |
There is mock-fs package that can mock entire |
I don't have experience with testing stuff on the file system, but if it's workable without mocking it that would be cool! I would be surprised if there are no packages available for that! If not maybe we could make something simple with |
I have no idea what to do about testing these methods that are all wrapped up in As @RobertBroersma said:
If I was writing this in Ruby I would do exactly this—mock out the file system calls (like # The mocha library automatically hooks into all classes so you
# can `expects` on any class (like the file library `File`)
test "sdl destroyer deletes the sdl file" do
destroyer = SdlDestroyer.new
File.expects("delete").with("/path/to/project/api/src/graphql/post.sdl.js")
destroyer.handler(:post)
end No need to create fake files and have the OS actually delete them—we can be reasonably sure that will work as expected. We just want to make sure our code is making the proper calls to those low level functions. Maybe you can mock out that file system call and then invoke the destroyer's |
@cannikin @antonmoiseev Another Jest feature that could be useful for template testing is snapshots! https://jestjs.io/docs/en/snapshot-testing Instead of writing the file to the file system you keep a snapshot of the correct output. Jest Snapshots aren't often the right choice but I think this is a perfect fit! This doesn't really make sense for deleting files I guess. For that I agree it's probably easier to mock out the filesystem. |
Agreed this is messy. And I'm super guilty of this re: But this conversation made me curious about how/if you can isolate and run specific tasks within the Listr array. And, indeed, you can. The following runs the first task without any of the Listr elements (e.g. no display title, etc): const tasks = new Listr([ ... ])
tasks._tasks[0].run() Does isolating each task like this help with testing? FYI --> Here’s_ the Listr structure for an array of three tasks with titles "First", "Second", "Third": Click here to view object[
Task {
_isScalar: false,
observers: [],
closed: false,
isStopped: false,
hasError: false,
thrownError: null,
_listr: Listr {
_options: [Object],
_tasks: [Circular],
concurrency: 1,
_RendererClass: [Function: UpdateRenderer],
exitOnError: undefined
},
_options: {
showSubtasks: true,
concurrent: false,
renderer: 'default',
nonTTYRenderer: 'verbose'
},
_subtasks: [],
_enabledFn: undefined,
_isEnabled: true,
output: undefined,
title: 'First',
skip: [Function: defaultSkipFn],
task: [Function: task]
},
Task {
_isScalar: false,
observers: [],
closed: false,
isStopped: false,
hasError: false,
thrownError: null,
_listr: Listr {
_options: [Object],
_tasks: [Circular],
concurrency: 1,
_RendererClass: [Function: UpdateRenderer],
exitOnError: undefined
},
_options: {
showSubtasks: true,
concurrent: false,
renderer: 'default',
nonTTYRenderer: 'verbose'
},
_subtasks: [],
_enabledFn: undefined,
_isEnabled: true,
output: undefined,
title: 'Second',
skip: [Function: defaultSkipFn],
task: [Function: task]
},
Task {
_isScalar: false,
observers: [],
closed: false,
isStopped: false,
hasError: false,
thrownError: null,
_listr: Listr {
_options: [Object],
_tasks: [Circular],
concurrency: 1,
_RendererClass: [Function: UpdateRenderer],
exitOnError: undefined
},
_options: {
showSubtasks: true,
concurrent: false,
renderer: 'default',
nonTTYRenderer: 'verbose'
},
_subtasks: [],
_enabledFn: undefined,
_isEnabled: true,
output: undefined,
title: 'Third',
skip: [Function: defaultSkipFn],
task: [Function: task]
}
] |
It seems like being able to test the individual Listr commands would help...for the destroy one you'd still need the files to exist for them to actually successfully delete, though. I feel like just mocking out But yeah testing the Listr tasks seem like it would help for all the other stuff that aren't covered by any tests currently. We could go up a mocking level and just test that the Listr tasks call the correct methods in the generators, rather than testing the whole generator stack again. But too much of that and it starts getting pretty brittle...change anything anywhere and you've got this huge cascade of mocks to fix. Ugh. @antonmoiseev how do you feel about mocking out the file system calls as described here and just checking that |
@cannikin Sounds good, that's what I tried, but was mocking |
a728f83
to
711c520
Compare
@thedavidprice Totally; just put up #559. Just want to make sure I got the help message right: Output for
|
@jtoar Sorry for raising this question a bit too late after the work was already done. I was going to offer my help, but you were too quick! Thank you!
@thedavidprice I was referring specifically to |
@antonmoiseev No worries! It was a super simple fix so thank you for bringing it up--we can get it right before getting it out. |
@antonmoiseev Is there further work in progress here? If not, we are looking to release v0.7 tomorrow and it would be great to include this. But all good if need more time. Thanks! |
@thedavidprice Yep, I saw your RC release, so full steam ahead, aiming to push final tests in a couple of hours 😄. Hopefully it will make it into v0.7, but no worries if it won't be good enough or fully reviewed by tomorrow. |
@cannikin It's ready for review, however as soon as #559 is merged, I'll need to adjust /cc @thedavidprice |
#559 has been merged |
Adjusted to scaffold generator changes, merged with master, ready for review now. |
Thanks for this! It looks good to me, but I'm going to check it out and test locally. |
@peterp Thank you! |
I just started working on this (#80). It currently takes more exploration than actual code writing, but I'd rather open the PR early on to have a chance to ask questions, and hopefully get the feedback while it's still very little code to review.
Several questions that I have so far:
Probably the biggest concern currently is reusing
files()
from the correspondinggenerate
commands.files()
reads actual files content from disk and renders the templates, which is completely unnecessary fordestroy
command. Should we consider refactoring this and splitting file paths resolving and template rendering into separate functions? It could be done as another issue after the initial version ofdestroy
is done.Do you have a preference which word to use for console messages: "destroy", "delete" or "remove" (expand to see examples)?
After deleting generated files the directory might or might not be empty (users can create files manually). Do you think we should get rid of empty directories as well?
I find it ambiguous to refer to different types of entities that CLI can generate/destroy as "components":
Have you discussed this previously? Did you decide to settle on this term for now?