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
Stop project generation if pre hook script fails #549
Stop project generation if pre hook script fails #549
Conversation
Current coverage is
|
Okay, coverage bot, I'll add tests and improve coverage once I get some consensus that this is a good-enough approach. :) |
Hi @eliasdorneles, thank you for your contribution! 🙇 Tbh, I'd rather raise an error instead of returning |
Hi @hackebrot :) |
Hey, sorry for the delay -- I updated the code to use a custom exception and added cleaning up the project dir when aborting the generation, and added a little test. |
Note: tests are broken because of issue addressed in this PR: #555 |
b17f77f
to
e19b739
Compare
Rebased to incorporate tests fix -- would appreciate some feedback. :) I'm particularly not sure about what should be the handling the |
I'd say we handle errors for More importantly, I feel we should definitely re-raise the exception after cleaning up the filesystem instead of returning None. We can catch the |
with utils.work_in(self.repo_path): | ||
with pytest.raises(exceptions.FailedHookException) as excinfo: | ||
hooks.run_hook('pre_gen_project', tests_dir, {}) | ||
assert 'Hook script failed' in str(excinfo) |
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 assert 'Hook script failed' in excinfo.value
should work too.
Thanks for reviewing @hackebrot -- I updated it with your suggestions. :) Only thing, I think it's best not to clean up the filesystem for |
IMHO if a For instance, if the rename_kv_file hook fails, the generated kivy app is corrupt and cannot be launched. 😟 So the question is why would you want to keep a broken project? I feel it is rather up to hook to use comprehensive logging messages to help users debug any error that might occur. |
Well, I don't have much experience using I think I was worrying unnecessarily, so lemme update this. |
2340b86
to
74ed88e
Compare
Does this look better? |
""" | ||
with work_in(repo_dir): | ||
try: | ||
run_hook('pre_gen_project', project_dir, context) |
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 guess 'pre_gen_project'
is supposed to be hook_name
. 😶
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.
ooops, lemme fix that! :D
hook_path = os.path.join(self.hooks_path, 'pre_gen_project.py') | ||
tests_dir = os.path.join(self.repo_path, 'input{{hooks}}') | ||
|
||
with open(hook_path, 'w') as f: |
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.
Uhhm, are you changing the test files at runtime? This may break other tests unintentionally... 😟
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.
self.repo_path
is destroyed in teardown_method
and recreated in setup_method
for each test:
https://github.com/audreyr/cookiecutter/pull/549/files#diff-392f380cd08f2c7cc3ac39b10cf80d95R94
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.
You are right 😪
Great work @eliasdorneles 👍 Let's see what the others think 😸 |
Cool, thanks for reviewing @hackebrot ! :) |
@@ -104,4 +110,4 @@ def run_hook(hook_name, project_dir, context): | |||
if script is None: | |||
logging.debug('No hooks found') | |||
return | |||
return run_script_with_context(script, project_dir, context) | |||
run_script_with_context(script, project_dir, context) |
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.
Why remove the ability to return a value?
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.
well, it was meant as a cleanup, run_script_with_context
was never returning anything, so I removed the return to make clear this function is a command not a query.
But I can revert the change, if you have other plans or I missed something. :)
This is a really nice feature that deserves documentation ;) |
Agreed, lemme add some docs! :) |
I added a note under the hook section -- does it look good? |
.. note:: | ||
Make sure your hook scripts work in a robust manner. If a hook script | ||
fails (that is, if it finishes with an exit status that is not one of | ||
success), the project generation will stop and the generated directory will |
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.
...with an exit status that is not 0
... ❔
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.
right, I was unsure if mentioning 0
would be more clear or more confusing.
I guess 0
is more clear. :)
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.
You could refer to the official sys.exit docs to be very explicit.
If it is an integer, zero is considered “successful termination” and any nonzero value is considered “abnormal termination” by shells and the like.
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.
Right, though the comment applies to shell script hooks too.
I'll link to it.
I think the example that you provided in the description of the PR would be a great example for using this new feature. Let's add it to the docs 😉 (if @eliasdorneles and @pydanny agree 😁 ) |
I've added an example and improved the wording -- looks good now? |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
Here is an example of script that validates a template variable | ||
before generating the project, to be used as ``hooks/pre_gen_project.py``:: |
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 feel sorry for being this picky... 🙊
PEP8 Imports recommends the following:
import re
import sys
Also you could enable syntax highlighting in rst via:
to be used as ``hooks/pre_gen_project.py``:
.. code-block:: python
import re
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.
haha, I don't mind the nitpicking, keep them coming. :)
who doesn't enjoy some bikeshedding? 🚲 🎪 :D
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.
although... python highlighting works for me without that markup. 😕
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.
done!
PS: wow, vim highlights sample code inline with .. code-block:: python
😮 :notbad:
.. note:: | ||
Make sure your hook scripts work in a robust manner. If a hook script fails | ||
(that is, `if it finishes with a nonzero exit status | ||
<https://docs.python.org/2/library/sys.html#sys.exit>`_), the project |
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.
@eliasdorneles It would be nice to indicate the Python3 documentation instead of Legacy Python.
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.
👍
😸 👍 |
Anything else, fellows? |
No, you're fine! 👍 We are just super busy atm. Apologies for the delay. 😟 Going to merge this guy once we get another upvote from a contributor. |
gotcha! btw, in Scrapy we find useful to rename the PR prefixing with |
LGTM! 👍 |
Stop project generation if pre hook script fails
Great work! 👍 👍 |
Thank you! =) |
I just realized we missed sth 😢 We need coverage for def _run_hook_from_repo_dir(repo_dir, hook_name, project_dir, context):
"""
Run hook from repo directory, cleaning up project directory if hook fails
"""
with work_in(repo_dir):
try:
run_hook(hook_name, project_dir, context)
except FailedHookException:
rmtree(project_dir)
logging.error("Stopping generation because %s"
" hook script didn't exit sucessfully" % hook_name)
raise |
Do you mind submitting a PR @eliasdorneles? |
oh, right.
|
No worries! Have fun 😸 |
Hey folks,
Would this be an adequate solution to address issue #464 ?
My use case is handling an invalid package name (see audreyfeldroy/cookiecutter-pypackage#6)
This proposal will stop the project generation if the pre hook script returns with an exit status different from 0 (indicating success).
With this proposal, we'd be able to handle that case with a
pre_gen_project
hook script like:Thoughts?