Skip to content

Commit

Permalink
Fix reading tokens from ~/.github-token for GitHub Enterprise domains
Browse files Browse the repository at this point in the history
  • Loading branch information
PawelLipski committed Sep 5, 2023
1 parent d5a1860 commit 7225dea
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 13 deletions.
1 change: 1 addition & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## New in git-machete 3.18.2

- fixed: reading tokens from `~/.github-token` for GitHub Enterprise domains (reported by @mkondratek)
- fixed: `git machete github retarget-pr`, when invoked without `--ignore-if-missing`, actually fails now if there is no PR for the branch
- improved: GitHub tokens are automatically redacted from command outputs in `--debug` mode

Expand Down
2 changes: 1 addition & 1 deletion docs/man/git-machete.1
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "GIT-MACHETE" "1" "Aug 31, 2023" "" "git-machete"
.TH "GIT-MACHETE" "1" "Sep 05, 2023" "" "git-machete"
.SH NAME
git-machete \- git-machete 3.18.2
.sp
Expand Down
11 changes: 6 additions & 5 deletions git_machete/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def for_domain(cls, domain: str) -> Optional["GitHubToken"]:

@classmethod
def __get_token_from_env(cls) -> Optional["GitHubToken"]:
debug(f"1. Trying to authenticate via `{GITHUB_TOKEN_ENV_VAR}` environment variable...")
debug(f"1. Trying to find token in `{GITHUB_TOKEN_ENV_VAR}` environment variable...")
github_token = os.environ.get(GITHUB_TOKEN_ENV_VAR)
if github_token:
return cls(value=github_token,
Expand All @@ -88,12 +88,13 @@ def __get_token_from_env(cls) -> Optional["GitHubToken"]:

@classmethod
def __get_token_from_file_in_home_directory(cls, domain: str) -> Optional["GitHubToken"]:
debug("2. Trying to authenticate via `~/.github-token`...")
debug("2. Trying to find token in `~/.github-token`...")
required_file_name = '.github-token'
provider = f'auth token for {domain} from `~/.github-token`'
file_full_path = os.path.expanduser(f'~/{required_file_name}')

if os.path.isfile(file_full_path):
debug(f" File `{file_full_path}` exists")
with open(file_full_path) as file:
# ~/.github-token is a file with a structure similar to:
#
Expand All @@ -102,7 +103,7 @@ def __get_token_from_file_in_home_directory(cls, domain: str) -> Optional["GitHu
# ghp_yetanothertoken_for_git_example_com git.example.com

for line in file.readlines():
if line.endswith(" " + domain):
if line.rstrip().endswith(" " + domain):
token = line.split(" ")[0]
return cls(value=token, provider=provider)
elif domain == GitHubClient.DEFAULT_GITHUB_DOMAIN and " " not in line.rstrip():
Expand All @@ -111,7 +112,7 @@ def __get_token_from_file_in_home_directory(cls, domain: str) -> Optional["GitHu

@classmethod
def __get_token_from_gh(cls, domain: str) -> Optional["GitHubToken"]:
debug("3. Trying to authenticate via `gh` GitHub CLI...")
debug("3. Trying to find token via `gh` GitHub CLI...")
# Abort without error if `gh` isn't available
gh = shutil.which('gh')
if not gh:
Expand Down Expand Up @@ -161,7 +162,7 @@ def __get_token_from_gh(cls, domain: str) -> Optional["GitHubToken"]:

@classmethod
def __get_token_from_hub(cls, domain: str) -> Optional["GitHubToken"]:
debug("4. Trying to authenticate via `hub` GitHub CLI...")
debug("4. Trying to find token via `hub` GitHub CLI...")
home_path: str = str(Path.home())
config_hub_path: str = os.path.join(home_path, ".config", "hub")
if os.path.isfile(config_hub_path):
Expand Down
20 changes: 13 additions & 7 deletions tests/test_github.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,13 @@ def test_github_token_retrieval_order(self, mocker: MockerFixture) -> None:
)

expected_output = ["__get_token_from_env(cls=<class 'git_machete.github.GitHubToken'>): "
"1. Trying to authenticate via `GITHUB_TOKEN` environment variable...",
"1. Trying to find token in `GITHUB_TOKEN` environment variable...",
"__get_token_from_file_in_home_directory(cls=<class 'git_machete.github.GitHubToken'>, domain=github.com): "
"2. Trying to authenticate via `~/.github-token`...",
"2. Trying to find token in `~/.github-token`...",
"__get_token_from_gh(cls=<class 'git_machete.github.GitHubToken'>, domain=github.com): "
"3. Trying to authenticate via `gh` GitHub CLI...",
"3. Trying to find token via `gh` GitHub CLI...",
"__get_token_from_hub(cls=<class 'git_machete.github.GitHubToken'>, domain=github.com): "
"4. Trying to authenticate via `hub` GitHub CLI..."]
"4. Trying to find token via `hub` GitHub CLI..."]

assert list(itertools.dropwhile(
lambda line: '__get_token_from_env' not in line,
Expand All @@ -227,9 +227,7 @@ def test_github_get_token_from_file_in_home_directory(self, mocker: MockerFixtur
github_token_contents = ('ghp_mytoken_for_github_com\n'
'ghp_myothertoken_for_git_example_org git.example.org\n'
'ghp_yetanothertoken_for_git_example_com git.example.com')
_mock_open = mock_open(read_data=github_token_contents)
_mock_open.return_value.readlines.return_value = github_token_contents.split('\n')
self.patch_symbol(mocker, 'builtins.open', _mock_open)
self.patch_symbol(mocker, 'builtins.open', mock_open(read_data=github_token_contents))
self.patch_symbol(mocker, 'os.path.isfile', lambda _file: True)

domain = GitHubClient.DEFAULT_GITHUB_DOMAIN
Expand All @@ -238,12 +236,20 @@ def test_github_get_token_from_file_in_home_directory(self, mocker: MockerFixtur
assert github_token.provider == f'auth token for {domain} from `~/.github-token`'
assert github_token.value == 'ghp_mytoken_for_github_com'

# Line ends with \n
domain = 'git.example.org'
github_token = GitHubToken.for_domain(domain=domain)
assert github_token is not None
assert github_token.provider == f'auth token for {domain} from `~/.github-token`'
assert github_token.value == 'ghp_myothertoken_for_git_example_org'

# Last line, doesn't end with \n
domain = 'git.example.com'
github_token = GitHubToken.for_domain(domain=domain)
assert github_token is not None
assert github_token.provider == f'auth token for {domain} from `~/.github-token`'
assert github_token.value == 'ghp_yetanothertoken_for_git_example_com'

domain = 'git.example.net'
github_token = GitHubToken.for_domain(domain=domain)
assert github_token is None
Expand Down

0 comments on commit 7225dea

Please sign in to comment.