slarse: Travis build is not triggering. Guess it's just one of those days.
codecov[bot]: # [Codecov](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=h1) Report
> Merging [#482](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=desc) into [master](https://codecov.io/gh/repobee/repobee/commit/c184fc066c6f7ed27e7fea84ac5f126c3420a0a4&el=desc) will **decrease** coverage by `3.78%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/repobee/repobee/pull/482/graphs/tree.svg?width=650&height=150&src=pr&token=5vOKgkphZe)](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #482      +/-   ##
==========================================
- Coverage   92.46%   88.67%   -3.79%     
==========================================
  Files          42       42              
  Lines        2215     2226      +11     
  Branches      380      379       -1     
==========================================
- Hits         2048     1974      -74     
- Misses        134      216      +82     
- Partials       33       36       +3     
```


| [Impacted Files](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/repobee\_plug/\_containers.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL3JlcG9iZWVfcGx1Zy9fY29udGFpbmVycy5weQ==) | `100.00% <ø> (ø)` | |
| [src/\_repobee/cli/dispatch.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL19yZXBvYmVlL2NsaS9kaXNwYXRjaC5weQ==) | `100.00% <100.00%> (ø)` | |
| [src/\_repobee/ext/gitlab.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL19yZXBvYmVlL2V4dC9naXRsYWIucHk=) | `64.25% <0.00%> (-28.08%)` | :arrow_down: |
| [src/\_repobee/git.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL19yZXBvYmVlL2dpdC5weQ==) | `96.62% <0.00%> (-3.38%)` | :arrow_down: |
| [src/\_repobee/command/repos.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL19yZXBvYmVlL2NvbW1hbmQvcmVwb3MucHk=) | `91.80% <0.00%> (-3.28%)` | :arrow_down: |
| [src/\_repobee/cli/parsing.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL19yZXBvYmVlL2NsaS9wYXJzaW5nLnB5) | `92.26% <0.00%> (-1.20%)` | :arrow_down: |
| [src/repobee\_plug/\_corehooks.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL3JlcG9iZWVfcGx1Zy9fY29yZWhvb2tzLnB5) | `100.00% <0.00%> (ø)` | |
| [src/repobee\_plug/\_exceptions.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL3JlcG9iZWVfcGx1Zy9fZXhjZXB0aW9ucy5weQ==) | `100.00% <0.00%> (ø)` | |
| [src/repobee\_plug/\_pluginmeta.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL3JlcG9iZWVfcGx1Zy9fcGx1Z2lubWV0YS5weQ==) | `100.00% <0.00%> (ø)` | |
| [src/\_repobee/ext/defaults/configwizard.py](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree#diff-c3JjL19yZXBvYmVlL2V4dC9kZWZhdWx0cy9jb25maWd3aXphcmQucHk=) | `100.00% <0.00%> (ø)` | |
| ... and [4 more](https://codecov.io/gh/repobee/repobee/pull/482/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=footer). Last update [c184fc0...3d775be](https://codecov.io/gh/repobee/repobee/pull/482?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/docs/repobee_plug/creating_plugins.rst b/docs/repobee_plug/creating_plugins.rst
index 8a98f4a..8321f9c 100644
--- a/docs/repobee_plug/creating_plugins.rst
+++ b/docs/repobee_plug/creating_plugins.rst
@@ -444,12 +444,11 @@ will look something like this instead:
 
     def callback(
         args: argparse.Namespace, api: Optional[plug.API]
-    ) -> Optional[Mapping[str, List[plug.Result]]]:
+    ) -> Optional[plug.Result]:
         # do whatever you want to do!
-        return {
-            PLUGIN_NAME: [plug.Result(
+        return plug.Result(
                 name=PLUGIN_NAME, status=plug.Status.SUCCESS, msg="Hello, world!"
-            )]
+            )
         }
 
     @plug.repobee_hook
diff --git a/src/_repobee/cli/dispatch.py b/src/_repobee/cli/dispatch.py
index bcf99e8..7d56c15 100644
--- a/src/_repobee/cli/dispatch.py
+++ b/src/_repobee/cli/dispatch.py
@@ -56,7 +56,7 @@ def dispatch_command(
     if is_ext_command:
         ext_cmd = ext_commands[ext_command_names.index(args.subparser)]
         res = ext_cmd.callback(args, api)
-        hook_results = res if res else hook_results
+        hook_results = {ext_cmd.name: [res]} if res else hook_results
     elif args.subparser == SETUP_PARSER:
         hook_results = command.setup_student_repos(
             args.master_repo_urls, args.students, api
diff --git a/src/repobee_plug/_containers.py b/src/repobee_plug/_containers.py
index 7d9c444..c750f23 100644
--- a/src/repobee_plug/_containers.py
+++ b/src/repobee_plug/_containers.py
@@ -184,8 +184,7 @@ class ExtensionCommand(
         help: str,
         description: str,
         callback: Callable[
-            [argparse.Namespace, Optional[_apimeta.API]],
-            Optional[Mapping[str, Result]],
+            [argparse.Namespace, Optional[_apimeta.API]], Optional[Result],
         ],
         requires_api: bool = False,
         requires_base_parsers: Optional[Iterable[BaseParser]] = None,
@@ -200,9 +199,8 @@ class ExtensionCommand(
                 describing the usage of the command.
             callback: A callback function that is called if this command is
                 used on the CLI. It is passed the parsed namespace and the
-                platform API. It may optionally return a result mapping on
-                the form (name: str -> List[Result]) that's reported by
-                RepoBee.
+                platform API. It may optionally return a plugin result that's
+                reported by RepoBee's CLI.
             requires_api: If True, the base arguments required for the platform
                 API are added as options to the extension command, and the
                 platform API is then passed to the callback function. It is

Extension command callbacks should just return a plug.Result, not a mapping
Currently, the extension command callbacks have the following signature:

```
def callback(
    args: argparse.Namespace, api: Optional[plug.API]
) -> Optional[Mapping[str, List[plug.Result]]]:
```
The return value makes absolutely no sense, as when you run an extension command, only one command can be run! So the mapping will always only contain a single key/value pair. It also doesn't make sense to return a list of `plug.Result`, as the extension command should do one thing.

The signature should really be this:

```
def callback(
    args: argparse.Namespace, api: Optional[plug.API]
) -> Optional[plug.Result]:
```
diff --git a/tests/unit_tests/repobee/test_cli.py b/tests/unit_tests/repobee/test_cli.py
index f8479f3..7e34e21 100644
--- a/tests/unit_tests/repobee/test_cli.py
+++ b/tests/unit_tests/repobee/test_cli.py
@@ -17,6 +17,7 @@ import _repobee.ext.defaults.github
 import _repobee.ext.query
 import _repobee.constants
 import _repobee.plugin
+import _repobee.ext.defaults.configwizard
 from _repobee.cli import mainparser
 from _repobee import exception
 
@@ -709,8 +710,12 @@ class TestExtensionCommands:
         """Return a mock callback function for use with an extension
         command.
         """
+        result = plug.Result(
+            name="mock", msg="Hello!", status=plug.Status.SUCCESS
+        )
         yield mock.MagicMock(
-            spec=_repobee.ext.defaults.configwizard.create_extension_command
+            spec=_repobee.ext.defaults.configwizard.callback,
+            return_value=result,
         )
 
     @pytest.fixture
@@ -805,13 +810,7 @@ class TestExtensionCommands:
             parsed_args, None, EMPTY_PATH, [ext_command]
         )
 
-        # for some reason, this completely sane assertion fails ALWAYS
-        # mock_callback.assert_called_once_with(
-        #   parsed_args, None)
-
-        # this is a workaround
-        assert len(mock_callback.call_args_list) == 1
-        assert mock_callback.call_args_list[0] == mock.call(parsed_args, None)
+        mock_callback.assert_called_once_with(parsed_args, None)
 
     def test_dispatch_ext_command_that_requires_api(
         self,
@@ -841,15 +840,7 @@ class TestExtensionCommands:
             parsed_args, api_instance_mock, EMPTY_PATH, [ext_command]
         )
 
-        # for some reason, this completely sane assertion fails ALWAYS
-        # mock_callback.assert_called_once_with(
-        #   parsed_args, api_instance_mock)
-
-        # this is a workaround
-        assert len(mock_callback.call_args_list) == 1
-        assert mock_callback.call_args_list[0] == mock.call(
-            parsed_args, api_instance_mock
-        )
+        mock_callback.assert_called_once_with(parsed_args, api_instance_mock)
 
     def test_parse_ext_command_that_requires_base_parsers(self):
         """The query command requires the students and repo names parsers."""

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-mock codecov bandit flake8 black
apt-get update apt-get install -y gcc
3.7
requirements/app.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
bandit==1.7.5
black==23.3.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
click==8.1.8
codecov==2.1.13
colored==1.4.4
coverage==7.2.7
cryptography==44.0.2
daiquiri==3.2.1
Deprecated==1.2.18
exceptiongroup==1.2.2
flake8==5.0.4
gitdb==4.0.12
GitPython==3.1.44
idna==3.10
importlib-metadata==4.2.0
iniconfig==2.0.0
markdown-it-py==2.2.0
mccabe==0.7.0
mdurl==0.1.2
mypy-extensions==1.0.0
packaging==24.0
pathspec==0.11.2
pbr==6.1.1
platformdirs==4.0.0
pluggy==0.13.1
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
PyGithub==2.3.0
Pygments==2.17.2
PyJWT==2.8.0
PyNaCl==1.5.0
pytest==7.4.4
pytest-cov==4.1.0
pytest-mock==3.11.1
python-gitlab==1.15.0
python-json-logger==3.0.1
PyYAML==6.0.1
-e git+https://github.com/repobee/repobee.git@c184fc066c6f7ed27e7fea84ac5f126c3420a0a4#egg=repobee
requests==2.31.0
rich==13.8.1
six==1.17.0
smmap==5.0.2
stevedore==3.5.2
tomli==2.0.1
typed-ast==1.5.5
typing_extensions==4.7.1
urllib3==2.0.7
wrapt==1.16.0
zipp==3.15.0

name: repobee
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - appdirs==1.4.4
      - bandit==1.7.5
      - black==23.3.0
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - click==8.1.8
      - codecov==2.1.13
      - colored==1.4.4
      - coverage==7.2.7
      - cryptography==44.0.2
      - daiquiri==3.2.1
      - deprecated==1.2.18
      - exceptiongroup==1.2.2
      - flake8==5.0.4
      - gitdb==4.0.12
      - gitpython==3.1.44
      - idna==3.10
      - importlib-metadata==4.2.0
      - iniconfig==2.0.0
      - markdown-it-py==2.2.0
      - mccabe==0.7.0
      - mdurl==0.1.2
      - mypy-extensions==1.0.0
      - packaging==24.0
      - pathspec==0.11.2
      - pbr==6.1.1
      - platformdirs==4.0.0
      - pluggy==0.13.1
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygithub==2.3.0
      - pygments==2.17.2
      - pyjwt==2.8.0
      - pynacl==1.5.0
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytest-mock==3.11.1
      - python-gitlab==1.15.0
      - python-json-logger==3.0.1
      - pyyaml==6.0.1
      - repobee==3.0.0a1
      - requests==2.31.0
      - rich==13.8.1
      - six==1.17.0
      - smmap==5.0.2
      - stevedore==3.5.2
      - tomli==2.0.1
      - typed-ast==1.5.5
      - typing-extensions==4.7.1
      - urllib3==2.0.7
      - wrapt==1.16.0
      - zipp==3.15.0
prefix: /opt/conda/envs/repobee

tests/unit_tests/repobee/test_cli.py::TestExtensionCommands::test_dispatch_ext_command_that_does_not_require_api tests/unit_tests/repobee/test_cli.py::TestExtensionCommands::test_dispatch_ext_command_that_requires_api
tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_writes_hook_results_correctly[clone-_repobee.command.clone_repos] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_writes_hook_results_correctly[list-issues-_repobee.command.list_issues] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_does_not_write_hook_results_if_there_are_none tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_raises_on_invalid_subparser_value tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[setup] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[update] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[clone] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[create-teams] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[migrate] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[open-issues] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[close-issues] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[list-issues] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[verify-settings] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[assign-reviews] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[end-reviews] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[show-config] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[check-reviews] tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_setup_student_repos_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_update_student_repos_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_create_teams_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_open_issue_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_close_issue_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_migrate_repos_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_clone_repos_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_verify_settings_called_with_correct_args tests/unit_tests/repobee/test_cli.py::TestDispatchCommand::test_verify_settings_called_with_master_org_name tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[setup] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[update] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[clone] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[create-teams] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[migrate] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[open-issues] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[close-issues] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[list-issues] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[verify-settings] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[assign-reviews] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[end-reviews] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[show-config] tests/unit_tests/repobee/test_cli.py::test_help_calls_add_arguments[check-reviews] tests/unit_tests/repobee/test_cli.py::test_create_parser_for_docs tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_show_all_opts_true_shows_configured_args tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_show_all_opts_false_hides_configured_args tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_raises_on_invalid_org tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_raises_on_bad_credentials tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_raises_on_invalid_base_url tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_master_org_overrides_target_org_for_master_repos[setup] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_master_org_overrides_target_org_for_master_repos[update] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_master_org_name_defaults_to_org_name[setup] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_master_org_name_defaults_to_org_name[update] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_token_env_variable_picked_up[setup] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_token_env_variable_picked_up[update] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_token_cli_arg_picked_up[setup] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_token_cli_arg_picked_up[update] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_raises_on_non_tls_api_url[http://some_enterprise_host/api/v3] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_raises_on_non_tls_api_url[ftp://some_enterprise_host/api/v3] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_raises_on_non_tls_api_url[some_enterprise_host/api/v3] tests/unit_tests/repobee/test_cli.py::TestBaseParsing::test_correctly_parses_create_teams tests/unit_tests/repobee/test_cli.py::TestExtensionCommands::test_parse_ext_command_that_does_not_require_api tests/unit_tests/repobee/test_cli.py::TestExtensionCommands::test_parse_ext_command_that_requires_api tests/unit_tests/repobee/test_cli.py::TestExtensionCommands::test_parse_ext_command_that_requires_base_parsers tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_listing_students[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_listing_students[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_listing_students[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_listing_students[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_student_file[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_student_file[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_student_file[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parser_student_file[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[setup|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[update|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[close-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[open-issues|['--mn', tests/unit_tests/repobee/test_cli.py::TestConfig::test_full_config[setup-extra_args0] tests/unit_tests/repobee/test_cli.py::TestConfig::test_full_config[update-extra_args1] tests/unit_tests/repobee/test_cli.py::TestConfig::test_full_config[open-issues-extra_args2] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_is_required[--bu] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_is_required[-u] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_is_required[--sf] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_is_required[-o] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_is_required[--mo] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_can_be_specified[--bu] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_can_be_specified[-u] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_can_be_specified[--sf] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_can_be_specified[-o] tests/unit_tests/repobee/test_cli.py::TestConfig::test_missing_option_can_be_specified[--mo] tests/unit_tests/repobee/test_cli.py::TestSetupAndUpdateParsers::test_happy_path[setup] tests/unit_tests/repobee/test_cli.py::TestSetupAndUpdateParsers::test_happy_path[update] tests/unit_tests/repobee/test_cli.py::TestSetupAndUpdateParsers::test_finds_local_repo[setup] tests/unit_tests/repobee/test_cli.py::TestSetupAndUpdateParsers::test_finds_local_repo[update] tests/unit_tests/repobee/test_cli.py::TestMigrateParser::test_happy_path tests/unit_tests/repobee/test_cli.py::TestVerifyParser::test_happy_path tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_happy_path tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[setup-extra_args0] tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[update-extra_args1] tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[open-issues-extra_args2] tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[close-issues-extra_args3] tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[verify-settings-extra_args4] tests/unit_tests/repobee/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[migrate-extra_args5] tests/unit_tests/repobee/test_cli.py::TestShowConfigParser::test_happy_path tests/unit_tests/repobee/test_cli.py::TestCommandDeprecation::test_deprecated_commands_parsed_to_current_commands[assign-peer-reviews-assign-reviews-sys_args0] tests/unit_tests/repobee/test_cli.py::TestCommandDeprecation::test_deprecated_commands_parsed_to_current_commands[purge-peer-review-teams-end-reviews-sys_args1] tests/unit_tests/repobee/test_cli.py::TestCommandDeprecation::test_deprecated_commands_parsed_to_current_commands[check-peer-review-progress-check-reviews-sys_args2]
src/repobee_plug/_containers.py src/_repobee/cli/dispatch.py docs/repobee_plug/creating_plugins.rst
src/repobee_plug/_containers.py src/_repobee/cli/dispatch.py docs/repobee_plug/creating_plugins.rst