]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Add cwd post-write hook option
authorBen Mares <15216687+maresb@users.noreply.github.com>
Mon, 29 Mar 2021 20:44:36 +0000 (16:44 -0400)
committersqla-tester <sqla-tester@sqlalchemy.org>
Mon, 29 Mar 2021 20:44:36 +0000 (16:44 -0400)
Fixes #822

Implements a `.cwd` suboption for post-write hooks.

For example, one can do
```ini
[post_write_hooks]
hooks = pre-commit

pre-commit.type = console_scripts
pre-commit.entrypoint = pre-commit
pre-commit.options = run --files REVISION_SCRIPT_FILENAME
pre-commit.cwd = %(here)s
```

This feature is illustrated by the last line above.

### Description

* Improve the names of some variables recently created in #820 in order to make the code more readable.
* Add `cwd` as an option which is passed directly into `subprocess.run()`
* Add a brief description to the documentation, together with an example with `pre-commit`.
<!-- Describe your changes in detail -->

### Checklist
<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

A new feature implementation

- [X] please include the issue number, and create an issue if none exists, which must
- [X] include a complete example of how the feature would look.
- [X] Please include: `Fixes: #<issue number>` in the commit message
- [x] **please include tests.**

**Help requested:** I can't think of any simple way to write a test. Does anyone have a suggestion???

Closes: #823
Pull-request: https://github.com/sqlalchemy/alembic/pull/823
Pull-request-sha: 9a694a7fdfc55160d1e124f6119a7a5677ce019a

Change-Id: Iacbb06d52acc362588cff2cdfec442393be8594a

alembic/script/write_hooks.py
docs/build/autogenerate.rst
docs/build/unreleased/822.rst [new file with mode: 0644]
tests/test_post_write.py

index 27e9a48497f13fd2b51a64de2d20d3efede4336f..133bf0462722572a0cff02da0c401c3620e3072a 100644 (file)
@@ -88,7 +88,7 @@ def _run_hooks(path, hook_config):
             )
 
 
-def _parse_options(options_str, path):
+def _parse_cmdline_options(cmdline_options_str, path):
     """Parse options from a string into a list.
 
     Also substitutes the revision script token with the actual filename of
@@ -97,13 +97,14 @@ def _parse_options(options_str, path):
     If the revision script token doesn't occur in the options string, it is
     automatically prepended.
     """
-    if REVISION_SCRIPT_TOKEN not in options_str:
-        options_str = REVISION_SCRIPT_TOKEN + " " + options_str
-    options_list = shlex.split(options_str)
-    options_list = [
-        option.replace(REVISION_SCRIPT_TOKEN, path) for option in options_list
+    if REVISION_SCRIPT_TOKEN not in cmdline_options_str:
+        cmdline_options_str = REVISION_SCRIPT_TOKEN + " " + cmdline_options_str
+    cmdline_options_list = shlex.split(cmdline_options_str)
+    cmdline_options_list = [
+        option.replace(REVISION_SCRIPT_TOKEN, path)
+        for option in cmdline_options_list
     ]
-    return options_list
+    return cmdline_options_list
 
 
 @register("console_scripts")
@@ -122,8 +123,9 @@ def console_scripts(path, options):
         )
     iter_ = pkg_resources.iter_entry_points("console_scripts", entrypoint_name)
     impl = next(iter_)
-    options_str = options.get("options", "")
-    options_list = _parse_options(options_str, path)
+    cwd = options.get("cwd", None)
+    cmdline_options_str = options.get("options", "")
+    cmdline_options_list = _parse_cmdline_options(cmdline_options_str, path)
 
     subprocess.run(
         [
@@ -132,5 +134,6 @@ def console_scripts(path, options):
             "import %s; %s()"
             % (impl.module_name, ".".join((impl.module_name,) + impl.attrs)),
         ]
-        + options_list
+        + cmdline_options_list,
+        cwd=cwd,
     )
index a5129f8bcadb6bd418c582b8f43130e170953a7c..4a5b27ac2d233466c1799539dad1c0b4144e90e6 100644 (file)
@@ -753,15 +753,16 @@ configuration for the ``"black"`` post write hook, which includes:
   function, this configuration variable would refer to the name under
   which the custom hook was registered; see the next section for an example.
 
-* ``entrypoint`` - this part of the configuration is specific to the
-  ``"console_scripts"`` hook runner.  This is the name of the `setuptools entrypoint <https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points>`_
+The following configuration options are specific to the ``"console_scripts"``
+hook runner:
+
+* ``entrypoint`` - the name of the `setuptools entrypoint <https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points>`_
   that is used to define the console script.   Within the scope of standard
   Python console scripts, this name will match the name of the shell command
   that is usually run for the code formatting tool, in this case ``black``.
 
-* ``options`` - this is also specific to the ``"console_scripts"`` hook runner.
-  This is a line of command-line options that will be passed to the
-  code formatting tool.  In this case, we want to run the command
+* ``options`` - a line of command-line options that will be passed to
+  the code formatting tool.  In this case, we want to run the command
   ``black /path/to/revision.py -l 79``.  By default, the revision path is
   positioned as the first argument.  In order specify a different position,
   we can use the ``REVISION_SCRIPT_FILENAME`` token as illustrated by the
@@ -777,6 +778,7 @@ configuration for the ``"black"`` post write hook, which includes:
         autopep8.entrypoint = autopep8
         autopep8.options = --in-place REVISION_SCRIPT_FILENAME
 
+* ``cwd`` - optional working directory from which the console script is run.
 
 When running ``alembic revision -m "rev1"``, we will now see the ``black``
 tool's output as well::
@@ -811,6 +813,20 @@ configuration as follows::
 When using the above configuration, a newly generated revision file will
 be processed first by the "black" tool, then by the "zimports" tool.
 
+Alternatively, one can run pre-commit itself as follows::
+
+  [post_write_hooks]
+
+  hooks = pre-commit
+
+  pre-commit.type = console_scripts
+  pre-commit.entrypoint = pre-commit
+  pre-commit.options = run --files REVISION_SCRIPT_FILENAME
+  pre-commit.cwd = %(here)s
+
+(The last line helps to ensure that the ``.pre-commit-config.yaml`` file
+will always be found, regardless of from where the hook was called.)
+
 .. _post_write_hooks_custom:
 
 Writing Custom Hooks as Python Functions
diff --git a/docs/build/unreleased/822.rst b/docs/build/unreleased/822.rst
new file mode 100644 (file)
index 0000000..d3e16ce
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: feature
+    :tickets: 822
+
+    Implement a ``.cwd`` (current working directory) suboption for post-write hooks
+    (of type ``console_scripts``). This is useful for tools like pre-commit, which
+    rely on the working directory to locate the necessary config files. Add
+    pre-commit as an example to the documentation. Minor change: rename some variables
+    from ticket #819 to improve readability.
index 653e09cd372253e581dca983d842a45c27fd488b..9beb1f6a9ee036984160561367f7fb68112b8ac0 100644 (file)
@@ -126,7 +126,7 @@ class RunHookTest(TestBase):
         )
 
     def _run_black_with_config(
-        self, input_config, expected_additional_arguments_fn
+        self, input_config, expected_additional_arguments_fn, cwd=None
     ):
         self.cfg = _no_sql_testing_config(directives=input_config)
         impl = mock.Mock(attrs=("foo", "bar"), module_name="black_module")
@@ -149,7 +149,8 @@ class RunHookTest(TestBase):
                         "-c",
                         "import black_module; black_module.foo.bar()",
                     ]
-                    + expected_additional_arguments_fn(rev.path)
+                    + expected_additional_arguments_fn(rev.path),
+                    cwd=cwd,
                 )
             ],
         )
@@ -186,3 +187,19 @@ black.options = arg1 REVISION_SCRIPT_FILENAME 'multi-word arg' \
         self._run_black_with_config(
             input_config, expected_additional_arguments_fn
         )
+
+    def test_black_with_cwd(self):
+        input_config = """
+[post_write_hooks]
+hooks = black
+black.type = console_scripts
+black.entrypoint = black
+black.cwd = /path/to/cwd
+        """
+
+        def expected_additional_arguments_fn(rev_path):
+            return [rev_path]
+
+        self._run_black_with_config(
+            input_config, expected_additional_arguments_fn, cwd="/path/to/cwd"
+        )