Skip to content

Commit

Permalink
Fix corrupt git repo bug (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
alfinkel authored Dec 3, 2020
1 parent c6afc3e commit b2b0c01
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ repos:
files: "^(harvest|test)"
stages: [commit]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.8.3
rev: 3.8.4
hooks:
- id: flake8
args: [
Expand Down
11 changes: 8 additions & 3 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# 1.1.1 (2020-09-03)
# [1.2.0](https://github.com/ComplianceAsCode/auditree-harvest/releases/tag/v1.2.0)

- [FIXED] Invalid Git repo error is now handled by a refresh of the local Git repo.
- [ADDED] Local path to the Git repo was added as a Collator property.

# [1.1.1](https://github.com/ComplianceAsCode/auditree-harvest/releases/tag/v1.1.1)

- [FIXED] Credentials are no longer expected when running in local repo mode.

# 1.1.0 (2020-09-02)
# [1.1.0](https://github.com/ComplianceAsCode/auditree-harvest/releases/tag/v1.1.0)

- [ADDED] "local" `repo` positional argument option is now valid bypassing remote validation.

# 1.0.0 (2020-07-27)
# [1.0.0](https://github.com/ComplianceAsCode/auditree-harvest/releases/tag/v1.0.0)

- [ADDED] Made the Auditree Harvest tool public.
2 changes: 1 addition & 1 deletion harvest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@
# limitations under the License.
"""The Auditree file collating and reporting tool."""

__version__ = '1.1.1'
__version__ = '1.2.0'
70 changes: 40 additions & 30 deletions harvest/collator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
# limitations under the License.
"""Harvest file collator."""
import os
import shutil
import tempfile
from datetime import datetime, timedelta
from pathlib import PurePath
from urllib.parse import urlparse

import git
Expand All @@ -38,6 +40,14 @@ def __init__(self, repo_url, creds, branch, repo_path=None, validate=True):
self.git_repo = None
self.validate = validate

@property
def local_path(self):
"""Provide the local OS path to the Git repo."""
if self.repo_path:
return self.repo_path
tmpdir = PurePath(tempfile.gettempdir())
return str(tmpdir.joinpath('harvest', self.org, self.repo))

def read(self, filepath, from_dt, until_dt):
"""
Retrieve commits from the repository based on a date range.
Expand Down Expand Up @@ -93,43 +103,43 @@ def write(self, filepath, commits):
f.write(commit.tree[filepath].data_stream.read().decode())

def checkout(self):
"""Establish/Refresh the local git repository."""
"""Establish/Refresh the local Git repository."""
if self.repo_path and not self.git_repo:
self.git_repo = git.Repo(self.repo_path)
if self.git_repo:
if self.validate and not self._valid_repo():
raise ValueError(f'{self.org}/{self.repo} repository mismatch')
return
local_path = os.path.join(
tempfile.gettempdir(), 'harvest', self.org, self.repo
)
if os.path.isdir(os.path.join(local_path, '.git')):
self.git_repo = git.Repo(local_path)
self.git_repo.remote().fetch()
self.git_repo.remote().pull()
else:
token = None
if 'github.com' in self.hostname:
token = self.creds['github'].token
elif 'github' in self.hostname:
token = self.creds['github_enterprise'].token
elif 'bitbucket' in self.hostname:
token = self.creds['bitbucket'].token
elif 'gitlab' in self.hostname:
token = self.creds['gitlab'].token
url_path = f'{self.hostname}/{self.org}/{self.repo}.git'
if os.path.isdir(os.path.join(self.local_path, '.git')):
try:
self.git_repo = git.Repo.clone_from(
f'{self.scheme}://{token}@{url_path}',
local_path,
branch=self.branch
)
except git.exc.GitCommandError as e:
raise git.exc.GitCommandError(
[c.replace(token, f'{"":*<10}') for c in e.command],
e.status,
e.stderr.strip('\n')
) from None
self.git_repo = git.Repo(self.local_path)
self.git_repo.remote().fetch()
self.git_repo.remote().pull()
return
except git.exc.InvalidGitRepositoryError:
shutil.rmtree(self.local_path)
token = None
if 'github.com' in self.hostname:
token = self.creds['github'].token
elif 'github' in self.hostname:
token = self.creds['github_enterprise'].token
elif 'bitbucket' in self.hostname:
token = self.creds['bitbucket'].token
elif 'gitlab' in self.hostname:
token = self.creds['gitlab'].token
url_path = f'{self.hostname}/{self.org}/{self.repo}.git'
try:
self.git_repo = git.Repo.clone_from(
f'{self.scheme}://{token}@{url_path}',
self.local_path,
branch=self.branch
)
except git.exc.GitCommandError as e:
raise git.exc.GitCommandError(
[c.replace(token, f'{"":*<10}') for c in e.command],
e.status,
e.stderr.strip('\n')
) from None

def _valid_repo(self):
remote_url = self.git_repo.remotes.origin.url
Expand Down
6 changes: 6 additions & 0 deletions test/test_collator.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import tempfile
import unittest
from datetime import datetime
from pathlib import PurePath
from unittest.mock import MagicMock, call, create_autospec, mock_open, patch

from git import Commit, Remote, Repo
Expand Down Expand Up @@ -57,6 +58,10 @@ def test_constructor_default(self):
self.assertEqual(collator.branch, 'master')
self.assertIsNone(collator.repo_path)
self.assertIsNone(collator.git_repo)
tmpdir = PurePath(tempfile.gettempdir())
self.assertEqual(
collator.local_path, str(tmpdir.joinpath('harvest', 'foo', 'bar'))
)

def test_constructor_with_repo_path(self):
"""Ensures collate object is constructed as expected."""
Expand All @@ -69,6 +74,7 @@ def test_constructor_with_repo_path(self):
self.assertEqual(collator.branch, 'master')
self.assertEqual(collator.repo_path, 'my/repo/path')
self.assertIsNone(collator.git_repo)
self.assertEqual(collator.local_path, 'my/repo/path')

def test_read_date_comparison(self):
"""Ensures read returns commits when date logic triggers completion."""
Expand Down

0 comments on commit b2b0c01

Please sign in to comment.