codecov-io: # [Codecov](https://codecov.io/gh/repobee/repobee/pull/281?src=pr&el=h1) Report
> Merging [#281](https://codecov.io/gh/repobee/repobee/pull/281?src=pr&el=desc) into [master](https://codecov.io/gh/repobee/repobee/commit/ee949e194694542a578c122c75923d45d2b5f762?src=pr&el=desc) will **decrease** coverage by `0.2%`.
> The diff coverage is `75%`.

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

```diff
@@            Coverage Diff             @@
##           master     #281      +/-   ##
==========================================
- Coverage   89.92%   89.72%   -0.21%     
==========================================
  Files          19       19              
  Lines        1410     1411       +1     
  Branches      255      256       +1     
==========================================
- Hits         1268     1266       -2     
- Misses        119      123       +4     
+ Partials       23       22       -1
```


| [Impacted Files](https://codecov.io/gh/repobee/repobee/pull/281?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [repobee/cli.py](https://codecov.io/gh/repobee/repobee/pull/281/diff?src=pr&el=tree#diff-cmVwb2JlZS9jbGkucHk=) | `97.65% <100%> (-0.79%)` | :arrow_down: |
| [repobee/ext/github.py](https://codecov.io/gh/repobee/repobee/pull/281/diff?src=pr&el=tree#diff-cmVwb2JlZS9leHQvZ2l0aHViLnB5) | `92.09% <33.33%> (-0.74%)` | :arrow_down: |
| [repobee/ext/gitlab.py](https://codecov.io/gh/repobee/repobee/pull/281/diff?src=pr&el=tree#diff-cmVwb2JlZS9leHQvZ2l0bGFiLnB5) | `64.59% <0%> (ø)` | :arrow_up: |
| [repobee/command.py](https://codecov.io/gh/repobee/repobee/pull/281/diff?src=pr&el=tree#diff-cmVwb2JlZS9jb21tYW5kLnB5) | `95.26% <0%> (+0.59%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/repobee/repobee/pull/281?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/281?src=pr&el=footer). Last update [ee949e1...dc59df9](https://codecov.io/gh/repobee/repobee/pull/281?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

diff --git a/repobee/cli.py b/repobee/cli.py
index 3b33755..7ff3eae 100644
--- a/repobee/cli.py
+++ b/repobee/cli.py
@@ -585,13 +585,11 @@ def _add_subparsers(parser):
     `base_` prefixed parser, of course).
     """
 
-    base_parser, base_student_parser, base_user_parser, master_org_parser = (
+    base_parser, base_student_parser, master_org_parser = (
         _create_base_parsers()
     )
 
-    repo_name_parser = argparse.ArgumentParser(
-        add_help=False, parents=[base_parser]
-    )
+    repo_name_parser = argparse.ArgumentParser(add_help=False)
     repo_name_parser.add_argument(
         "-mn",
         "--master-repo-names",
@@ -619,7 +617,7 @@ def _add_subparsers(parser):
             "will simply be skipped."
         ),
         parents=[
-            base_user_parser,
+            base_parser,
             base_student_parser,
             master_org_parser,
             repo_name_parser,
@@ -637,7 +635,7 @@ def _add_subparsers(parser):
             "something already)."
         ),
         parents=[
-            base_user_parser,
+            base_parser,
             base_student_parser,
             master_org_parser,
             repo_name_parser,
@@ -662,7 +660,7 @@ def _add_subparsers(parser):
             "The repos must be local on disk to be migrated. Note that "
             "migrated repos will be private."
         ),
-        parents=[repo_name_parser, base_user_parser],
+        parents=[repo_name_parser, base_parser],
         formatter_class=_OrderedFormatter,
     )
 
@@ -670,15 +668,17 @@ def _add_subparsers(parser):
         CLONE_PARSER,
         help="Clone student repos.",
         description="Clone student repos asynchronously in bulk.",
-        parents=[base_student_parser, repo_name_parser],
+        parents=[base_parser, base_student_parser, repo_name_parser],
         formatter_class=_OrderedFormatter,
     )
 
     plug.manager.hook.clone_parser_hook(clone_parser=clone)
 
-    _add_issue_parsers([base_student_parser, repo_name_parser], subparsers)
+    _add_issue_parsers(
+        [base_parser, base_student_parser, repo_name_parser], subparsers
+    )
     _add_peer_review_parsers(
-        [base_student_parser, repo_name_parser], subparsers
+        [base_parser, base_student_parser, repo_name_parser], subparsers
     )
 
     subparsers.add_parser(
@@ -696,7 +696,7 @@ def _add_subparsers(parser):
         VERIFY_PARSER,
         help="Verify core settings.",
         description="Verify core settings by trying various API requests.",
-        parents=[base_parser, base_user_parser, master_org_parser],
+        parents=[base_parser, master_org_parser],
         formatter_class=_OrderedFormatter,
     )
 
@@ -720,6 +720,15 @@ def _create_base_parsers():
         return arg_name in plug.manager.hook.api_init_requires()
 
     base_parser = argparse.ArgumentParser(add_help=False)
+    base_parser.add_argument(
+        "-u",
+        "--user",
+        help=("Your username."),
+        type=str,
+        required=not configured("user") and api_requires("user"),
+        default=default("user"),
+    )
+
     base_parser.add_argument(
         "-o",
         "--org-name",
@@ -775,19 +784,6 @@ def _create_base_parsers():
         nargs="+",
     )
 
-    # base parser for when files need to be pushed
-    base_user_parser = argparse.ArgumentParser(add_help=False)
-
-    # the username is required for any pushing
-    base_user_parser.add_argument(
-        "-u",
-        "--user",
-        help=("Your username."),
-        type=str,
-        required=not configured("user") and api_requires("user"),
-        default=default("user"),
-    )
-
     master_org_parser = argparse.ArgumentParser(add_help=False)
     master_org_parser.add_argument(
         "-mo",
@@ -798,12 +794,7 @@ def _create_base_parsers():
         default=default("master_org_name"),
     )
 
-    return (
-        base_parser,
-        base_student_parser,
-        base_user_parser,
-        master_org_parser,
-    )
+    return (base_parser, base_student_parser, master_org_parser)
 
 
 @contextmanager
diff --git a/repobee/ext/github.py b/repobee/ext/github.py
index 2a58236..09b6824 100644
--- a/repobee/ext/github.py
+++ b/repobee/ext/github.py
@@ -129,6 +129,8 @@ class GitHubAPI(apimeta.API):
             user: Name of the current user of the API.
             org_name: Name of the target organization.
         """
+        if not user:
+            raise TypeError("argument 'user' must not be empty")
         self._github = github.Github(login_or_token=token, base_url=base_url)
         self._org_name = org_name
         self._base_url = base_url
@@ -381,13 +383,7 @@ class GitHubAPI(apimeta.API):
                     repo_url
                 )
             )
-        # TODO in RepoBee 2.0, user will always be available
-        # user may not always be available
-        auth = (
-            self.token
-            if not self._user
-            else "{}:{}".format(self._user, self.token)
-        )
+        auth = "{}:{}".format(self._user, self.token)
         return repo_url.replace("https://", "https://{}@".format(auth))
 
     def get_issues(

Add `user` to base args
See #180 
diff --git a/tests/unit_tests/plugin_tests/test_github.py b/tests/unit_tests/plugin_tests/test_github.py
index a67017f..e55e41b 100644
--- a/tests/unit_tests/plugin_tests/test_github.py
+++ b/tests/unit_tests/plugin_tests/test_github.py
@@ -479,24 +479,6 @@ class TestCreateRepos:
 class TestGetRepoUrls:
     """Tests for get_repo_urls."""
 
-    @pytest.mark.skipif(
-        repobee.__version__ >= "2.0.0",
-        reason="Made obsolete by including user in every CLI command",
-    )
-    def test_with_token_without_user(self, repos, api):
-        """Test getting repo urls when the api has the token, but no user. The
-        token should be in the url anyway.
-        """
-        api._user = None
-        repo_names = [repo.name for repo in repos]
-        expected_urls = [api._insert_auth(repo.html_url) for repo in repos]
-
-        urls = api.get_repo_urls(repo_names)
-
-        assert sorted(urls) == sorted(expected_urls)
-        for url in urls:
-            assert TOKEN in url
-
     def test_with_token_and_user(self, repos, api):
         repo_names = [repo.name for repo in repos]
         api._user = USER
diff --git a/tests/unit_tests/test_cli.py b/tests/unit_tests/test_cli.py
index d8b16a2..b685b70 100644
--- a/tests/unit_tests/test_cli.py
+++ b/tests/unit_tests/test_cli.py
@@ -31,8 +31,8 @@ TOKEN = constants.TOKEN
 REPO_NAMES = ("week-1", "week-2", "week-3")
 REPO_URLS = tuple(map(lambda rn: generate_repo_url(rn, ORG_NAME), REPO_NAMES))
 
-BASE_ARGS = ["-bu", BASE_URL, "-o", ORG_NAME]
-BASE_PUSH_ARGS = ["-u", USER, "-mn", *REPO_NAMES]
+BASE_ARGS = ["-u", USER, "-bu", BASE_URL, "-o", ORG_NAME]
+BASE_PUSH_ARGS = ["-mn", *REPO_NAMES]
 COMPLETE_PUSH_ARGS = [*BASE_ARGS, *BASE_PUSH_ARGS]
 
 # parsed args without subparser
@@ -459,6 +459,8 @@ class TestBaseParsing:
         """
         sys_args = [
             cli.SETUP_PARSER,
+            "-u",
+            USER,
             "-o",
             ORG_NAME,
             "-bu",
@@ -809,14 +811,7 @@ class TestMigrateParser:
         assert parsed_args.master_repo_urls == self.LOCAL_URIS
 
     def test_happy_path(self):
-        sys_args = [
-            cli.MIGRATE_PARSER,
-            *BASE_ARGS,
-            "-u",
-            USER,
-            "-mn",
-            *self.NAMES,
-        ]
+        sys_args = [cli.MIGRATE_PARSER, *BASE_ARGS, "-mn", *self.NAMES]
 
         parsed_args, _ = cli.parse_args(sys_args)
 
@@ -827,7 +822,7 @@ class TestVerifyParser:
     """Tests for the VERIFY_PARSER."""
 
     def test_happy_path(self):
-        sys_args = [cli.VERIFY_PARSER, *BASE_ARGS, "-u", USER]
+        sys_args = [cli.VERIFY_PARSER, *BASE_ARGS]
 
         args, _ = cli.parse_args(sys_args)
 
@@ -871,25 +866,11 @@ class TestCloneParser:
         [
             (
                 cli.SETUP_PARSER,
-                [
-                    "-u",
-                    USER,
-                    "-s",
-                    *STUDENTS_STRING.split(),
-                    "-mn",
-                    *REPO_NAMES,
-                ],
+                ["-s", *STUDENTS_STRING.split(), "-mn", *REPO_NAMES],
             ),
             (
                 cli.UPDATE_PARSER,
-                [
-                    "-u",
-                    USER,
-                    "-s",
-                    *STUDENTS_STRING.split(),
-                    "-mn",
-                    *REPO_NAMES,
-                ],
+                ["-s", *STUDENTS_STRING.split(), "-mn", *REPO_NAMES],
             ),
             (
                 cli.OPEN_ISSUE_PARSER,
@@ -913,8 +894,8 @@ class TestCloneParser:
                     "some-regex",
                 ],
             ),
-            (cli.VERIFY_PARSER, ["-u", USER]),
-            (cli.MIGRATE_PARSER, ["-u", USER, "-mn", *REPO_NAMES]),
+            (cli.VERIFY_PARSER, []),
+            (cli.MIGRATE_PARSER, ["-mn", *REPO_NAMES]),
         ],
     )
     def test_no_other_parser_gets_parse_hook(

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-mock codecov
apt-get update apt-get install -y gcc
3.7
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
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
idna==3.10
importlib-metadata==6.7.0
iniconfig==2.0.0
packaging==24.0
pluggy==1.2.0
pycparser==2.21
PyGithub==2.3.0
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.8.0
python-json-logger==3.0.1
-e git+https://github.com/repobee/repobee.git@ee949e194694542a578c122c75923d45d2b5f762#egg=repobee
repobee-plug==0.6.0
requests==2.31.0
six==1.17.0
tomli==2.0.1
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
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - 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
      - idna==3.10
      - importlib-metadata==6.7.0
      - iniconfig==2.0.0
      - packaging==24.0
      - pluggy==1.2.0
      - pycparser==2.21
      - pygithub==2.3.0
      - 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.8.0
      - python-json-logger==3.0.1
      - repobee==1.6.0
      - repobee-plug==0.6.0
      - requests==2.31.0
      - six==1.17.0
      - tomli==2.0.1
      - 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/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[open-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_listing_students[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_listing_students[open-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_student_file[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_student_file[open-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[open-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[open-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[open-issues|['-mn', tests/unit_tests/test_cli.py::TestCloneParser::test_happy_path tests/unit_tests/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[open-issues-extra_args2] tests/unit_tests/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[close-issues-extra_args3] tests/unit_tests/test_cli.py::TestCommandDeprecation::test_deprecated_commands_parsed_to_current_commands[assign-peer-reviews-assign-reviews-sys_args0] tests/unit_tests/test_cli.py::TestCommandDeprecation::test_deprecated_commands_parsed_to_current_commands[purge-peer-review-teams-purge-review-teams-sys_args1] tests/unit_tests/test_cli.py::TestCommandDeprecation::test_deprecated_commands_parsed_to_current_commands[check-peer-review-progress-check-reviews-sys_args2]
tests/unit_tests/plugin_tests/test_github.py::TestEnsureTeamsAndMembers::test_no_previous_teams tests/unit_tests/plugin_tests/test_github.py::TestEnsureTeamsAndMembers::test_all_teams_exist_but_without_members tests/unit_tests/plugin_tests/test_github.py::TestEnsureTeamsAndMembers::test_raises_on_non_422_exception[unexpected_exc0] tests/unit_tests/plugin_tests/test_github.py::TestEnsureTeamsAndMembers::test_raises_on_non_422_exception[unexpected_exc1] tests/unit_tests/plugin_tests/test_github.py::TestEnsureTeamsAndMembers::test_raises_on_non_422_exception[unexpected_exc2] tests/unit_tests/plugin_tests/test_github.py::TestEnsureTeamsAndMembers::test_running_twice_has_no_ill_effects tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_creates_correct_repos tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_skips_existing_repos tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_raises_on_unexpected_error[unexpected_exception0] tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_raises_on_unexpected_error[unexpected_exception1] tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_raises_on_unexpected_error[unexpected_exception2] tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_returns_all_urls tests/unit_tests/plugin_tests/test_github.py::TestCreateRepos::test_create_repos_without_team_id tests/unit_tests/plugin_tests/test_github.py::TestGetRepoUrls::test_with_token_and_user tests/unit_tests/plugin_tests/test_github.py::TestGetRepoUrls::test_with_students tests/unit_tests/plugin_tests/test_github.py::TestOpenIssue::test_on_existing_repos tests/unit_tests/plugin_tests/test_github.py::TestOpenIssue::test_on_some_non_existing_repos tests/unit_tests/plugin_tests/test_github.py::TestOpenIssue::test_no_crash_when_no_repos_are_found tests/unit_tests/plugin_tests/test_github.py::TestCloseIssue::test_closes_correct_issues tests/unit_tests/plugin_tests/test_github.py::TestCloseIssue::test_no_crash_if_no_repos_found tests/unit_tests/plugin_tests/test_github.py::TestCloseIssue::test_no_crash_if_no_issues_found tests/unit_tests/plugin_tests/test_github.py::TestGetIssues::test_get_all_open_issues tests/unit_tests/plugin_tests/test_github.py::TestGetIssues::test_get_all_closed_issues tests/unit_tests/plugin_tests/test_github.py::TestGetIssues::test_get_issues_when_one_repo_doesnt_exist tests/unit_tests/plugin_tests/test_github.py::TestGetIssues::test_get_open_issues_by_regex tests/unit_tests/plugin_tests/test_github.py::TestAddReposToReviewTeams::test_with_default_issue tests/unit_tests/plugin_tests/test_github.py::TestAddReposToTeams::test_happy_path tests/unit_tests/plugin_tests/test_github.py::TestDeleteTeams::test_delete_non_existing_teams_does_not_crash tests/unit_tests/plugin_tests/test_github.py::TestDeleteTeams::test_delete_existing_teams tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_happy_path tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_empty_token_raises_bad_credentials tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_incorrect_info_raises_not_found_error[get_user] tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_incorrect_info_raises_not_found_error[get_organization] tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_bad_token_scope_raises tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_not_owner_raises tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_raises_unexpected_exception_on_unexpected_status tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_none_user_raises tests/unit_tests/plugin_tests/test_github.py::TestVerifySettings::test_mismatching_user_login_raises tests/unit_tests/plugin_tests/test_github.py::TestGetPeerReviewProgress::test_nothing_returns tests/unit_tests/plugin_tests/test_github.py::TestGetPeerReviewProgress::test_with_review_teams_but_no_repos tests/unit_tests/test_cli.py::TestDispatchCommand::test_raises_on_invalid_subparser_value tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[setup] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[update] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[clone] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[migrate] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[open-issues] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[close-issues] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[list-issues] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[verify-settings] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[assign-reviews] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[purge-review-teams] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[show-config] tests/unit_tests/test_cli.py::TestDispatchCommand::test_no_crash_on_valid_args[check-reviews] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[setup-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[setup-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[setup-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[setup-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[update-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[update-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[update-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[update-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[clone-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[clone-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[clone-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[clone-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[migrate-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[migrate-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[migrate-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[migrate-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[open-issues-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[open-issues-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[open-issues-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[open-issues-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[close-issues-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[close-issues-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[close-issues-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[close-issues-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[list-issues-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[list-issues-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[list-issues-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[list-issues-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[verify-settings-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[verify-settings-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[verify-settings-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[verify-settings-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[assign-reviews-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[assign-reviews-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[assign-reviews-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[assign-reviews-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[purge-review-teams-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[purge-review-teams-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[purge-review-teams-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[purge-review-teams-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[show-config-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[show-config-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[show-config-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[show-config-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[check-reviews-command_all_raise_mock0] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[check-reviews-command_all_raise_mock1] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[check-reviews-command_all_raise_mock2] tests/unit_tests/test_cli.py::TestDispatchCommand::test_expected_exception_results_in_system_exit[check-reviews-command_all_raise_mock3] tests/unit_tests/test_cli.py::TestDispatchCommand::test_setup_student_repos_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_update_student_repos_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_open_issue_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_close_issue_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_migrate_repos_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_clone_repos_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_verify_settings_called_with_correct_args tests/unit_tests/test_cli.py::TestDispatchCommand::test_verify_settings_called_with_master_org_name tests/unit_tests/test_cli.py::test_help_calls_add_arguments[setup] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[update] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[clone] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[migrate] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[open-issues] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[close-issues] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[list-issues] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[verify-settings] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[assign-reviews] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[purge-review-teams] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[show-config] tests/unit_tests/test_cli.py::test_help_calls_add_arguments[check-reviews] tests/unit_tests/test_cli.py::TestBaseParsing::test_raises_on_invalid_org tests/unit_tests/test_cli.py::TestBaseParsing::test_raises_on_bad_credentials tests/unit_tests/test_cli.py::TestBaseParsing::test_raises_on_invalid_base_url tests/unit_tests/test_cli.py::TestBaseParsing::test_master_org_overrides_target_org_for_master_repos[setup] tests/unit_tests/test_cli.py::TestBaseParsing::test_master_org_overrides_target_org_for_master_repos[update] tests/unit_tests/test_cli.py::TestBaseParsing::test_master_org_name_defaults_to_org_name[setup] tests/unit_tests/test_cli.py::TestBaseParsing::test_master_org_name_defaults_to_org_name[update] tests/unit_tests/test_cli.py::TestBaseParsing::test_token_env_variable_picked_up[setup] tests/unit_tests/test_cli.py::TestBaseParsing::test_token_env_variable_picked_up[update] tests/unit_tests/test_cli.py::TestBaseParsing::test_token_cli_arg_picked_up[setup] tests/unit_tests/test_cli.py::TestBaseParsing::test_token_cli_arg_picked_up[update] tests/unit_tests/test_cli.py::TestBaseParsing::test_raises_on_non_tls_api_url[http://some_enterprise_host/api/v3] tests/unit_tests/test_cli.py::TestBaseParsing::test_raises_on_non_tls_api_url[ftp://some_enterprise_host/api/v3] tests/unit_tests/test_cli.py::TestBaseParsing::test_raises_on_non_tls_api_url[some_enterprise_host/api/v3] tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_students_file_is_not_a_file[update|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_listing_students[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_listing_students[update|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_student_file[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parser_student_file[update|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_parsers_raise_on_empty_student_file[update|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[update|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[close-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_parsers_raise_if_both_file_and_listing[open-issues|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_student_groups_parsed_correcly[update|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[setup|['-mn', tests/unit_tests/test_cli.py::TestStudentParsing::test_raises_if_generated_team_name_too_long[update|['-mn', tests/unit_tests/test_cli.py::TestConfig::test_full_config[setup-extra_args0] tests/unit_tests/test_cli.py::TestConfig::test_full_config[update-extra_args1] tests/unit_tests/test_cli.py::TestConfig::test_full_config[open-issues-extra_args2] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_is_required[-bu] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_is_required[-u] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_is_required[-sf] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_is_required[-o] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_is_required[-mo] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_can_be_specified[-bu] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_can_be_specified[-u] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_can_be_specified[-sf] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_can_be_specified[-o] tests/unit_tests/test_cli.py::TestConfig::test_missing_option_can_be_specified[-mo] tests/unit_tests/test_cli.py::TestSetupAndUpdateParsers::test_happy_path[setup] tests/unit_tests/test_cli.py::TestSetupAndUpdateParsers::test_happy_path[update] tests/unit_tests/test_cli.py::TestSetupAndUpdateParsers::test_finds_local_repo[setup] tests/unit_tests/test_cli.py::TestSetupAndUpdateParsers::test_finds_local_repo[update] tests/unit_tests/test_cli.py::TestMigrateParser::test_happy_path tests/unit_tests/test_cli.py::TestVerifyParser::test_happy_path tests/unit_tests/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[setup-extra_args0] tests/unit_tests/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[update-extra_args1] tests/unit_tests/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[verify-settings-extra_args4] tests/unit_tests/test_cli.py::TestCloneParser::test_no_other_parser_gets_parse_hook[migrate-extra_args5] tests/unit_tests/test_cli.py::TestShowConfigParser::test_happy_path
repobee/cli.py repobee/ext/github.py
repobee/cli.py repobee/ext/github.py