Repository: VirtusLab/git-machete (python)

Issue:
Does `/pulls` endpoint for a public GitHub repository really require authentication?
As @mkondratek reported:

I've tried to use `create-pr` with that result:

```sh
mikko@mikko-MS-7C91:~/IdeaProjects/git-machete-intellij-plugin$ git machete github create-pr
Fetching origin...
Creating a PR from hook-executors-improvements to develop...Given endpoint: https://api.github.com/repos/VirtusLab/git-machete-intellij-plugin/pulls, not found in GitHub or you don't have the permission to access it (expired token?).
```

I have no token (generated and) set so that's the reason. After that - works.

_Originally posted by @mkondratek in https://github.com/VirtusLab/git-machete/issues/493#issuecomment-1113174706_

---

My addition: note that https://api.github.com/repos/VirtusLab/git-machete-intellij-plugin/pulls can be readily accessed from browser and returns legit results. Let's check why this error happens when accessing GitHub API from git-machete CLI. If this can't be circumvented (e.g. for private repos), let's at least improve the error message (since it doesn't even clearly state that the token might be missing, only mentions expiry) :thinking:

Pull request:
Issue #506: Update error message when firing GitHub pulls API request without token
closes #506 

Patch:
diff --git a/git_machete/client.py b/git_machete/client.py
index d063583..19ef0c4 100644
--- a/git_machete/client.py
+++ b/git_machete/client.py
@@ -2109,7 +2109,7 @@ class MacheteClient:
         description_path = self.__git.get_main_git_subpath('info', 'description')
         description: str = utils.slurp_file_or_empty(description_path)
 
-        ok_str = ' <green><b>OK</b></green>'
+        ok_str = ' <green>-> <b>OK</b></green>'
         print(fmt(f'Creating a {"draft " if opt_draft else ""}PR from `{head}` to `{base}`...'), end='', flush=True)
         pr: GitHubPullRequest = create_pull_request(org, repo, head=head, base=base, title=commits[0].subject,
                                                     description=description, draft=opt_draft)
diff --git a/git_machete/github.py b/git_machete/github.py
index f8dc8c4..49f089b 100644
--- a/git_machete/github.py
+++ b/git_machete/github.py
@@ -181,8 +181,9 @@ def __fire_github_api_request(method: str, path: str, token: Optional[str], requ
                                  'Visit `https://github.com/settings/tokens` to generate a new one.')
         elif err.code == http.HTTPStatus.NOT_FOUND:
             raise MacheteException(
-                f'Given endpoint: {url}, not found in GitHub or you don\'t have'
-                f' the permission to access it (expired token?).')  # TODO (#164): make dedicated exception here
+                f'`{method} {url}` request ended up in 404 response from GitHub. A valid GitHub API token is required.\n'
+                f'Provide a GitHub API token with `repo` access via one of the: {get_github_token_possible_providers()} '
+                'Visit `https://github.com/settings/tokens` to generate a new one.')  # TODO (#164): make dedicated exception here
         else:
             first_line = fmt(f'GitHub API returned {err.code} HTTP status with error message: `{err.reason}`\n')
             raise MacheteException(first_line + "Please open an issue regarding this topic under link: https://github.com/VirtusLab/git-machete/issues/new")


Test patch:
diff --git a/tests/test_github.py b/tests/test_github.py
index 90fe555..d8fce10 100644
--- a/tests/test_github.py
+++ b/tests/test_github.py
@@ -454,7 +454,7 @@ class TestGithub:
 
         expected_msg = ("Fetching origin...\n"
                         "Warn: Base branch for this PR (`feature/api_handling`) is not found on remote, pushing...\n"
-                        "Creating a PR from `feature/api_exception_handling` to `feature/api_handling`... OK, see www.github.com\n")
+                        "Creating a PR from `feature/api_exception_handling` to `feature/api_handling`... -> OK, see www.github.com\n")
         assert_command(['github', 'create-pr'], expected_msg, strip_indentation=False)
         assert_command(
             ['status'],