Skip to content

Commit 8d65dfc

Browse files
authored
Merge pull request #179 from sean-morris/master
Handle default or non-existing branch name
2 parents 814682b + 12f25dd commit 8d65dfc

File tree

6 files changed

+114
-12
lines changed

6 files changed

+114
-12
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ data8assets/
1313
.autopull_list
1414
summer/
1515
test-repo/
16+
venv/
1617

1718
.ipynb_checkpoints
1819
docs/_build

nbgitpuller/handlers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def get(self):
5252

5353
try:
5454
repo = self.get_argument('repo')
55-
branch = self.get_argument('branch')
55+
branch = self.get_argument('branch', None)
5656
depth = self.get_argument('depth', None)
5757
if depth:
5858
depth = int(depth)
@@ -73,7 +73,7 @@ def get(self):
7373
self.set_header('content-type', 'text/event-stream')
7474
self.set_header('cache-control', 'no-cache')
7575

76-
gp = GitPuller(repo, branch, repo_dir, depth=depth, parent=self.settings['nbapp'])
76+
gp = GitPuller(repo, repo_dir, branch=branch, depth=depth, parent=self.settings['nbapp'])
7777

7878
q = Queue()
7979

@@ -149,7 +149,7 @@ def get(self):
149149
app_env = os.getenv('NBGITPULLER_APP', default='notebook')
150150

151151
repo = self.get_argument('repo')
152-
branch = self.get_argument('branch', 'master')
152+
branch = self.get_argument('branch', None)
153153
depth = self.get_argument('depth', None)
154154
urlPath = self.get_argument('urlpath', None) or \
155155
self.get_argument('urlPath', None)

nbgitpuller/pull.py

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,75 @@ def _depth_default(self):
6666
where the GitPuller class hadn't been loaded already."""
6767
return int(os.environ.get('NBGITPULLER_DEPTH', 1))
6868

69-
def __init__(self, git_url, branch_name, repo_dir, **kwargs):
70-
assert git_url and branch_name
69+
def __init__(self, git_url, repo_dir, **kwargs):
70+
assert git_url
7171

7272
self.git_url = git_url
73-
self.branch_name = branch_name
73+
self.branch_name = kwargs.pop("branch")
74+
75+
if self.branch_name is None:
76+
self.branch_name = self.resolve_default_branch()
77+
elif not self.branch_exists(self.branch_name):
78+
raise ValueError(f"Branch: {self.branch_name} -- not found in repo: {self.git_url}")
79+
7480
self.repo_dir = repo_dir
7581
newargs = {k: v for k, v in kwargs.items() if v is not None}
7682
super(GitPuller, self).__init__(**newargs)
7783

84+
def branch_exists(self, branch):
85+
"""
86+
This checks to make sure the branch we are told to access
87+
exists in the repo
88+
"""
89+
try:
90+
heads = subprocess.run(
91+
["git", "ls-remote", "--heads", self.git_url],
92+
capture_output=True,
93+
text=True,
94+
check=True
95+
)
96+
tags = subprocess.run(
97+
["git", "ls-remote", "--tags", self.git_url],
98+
capture_output=True,
99+
text=True,
100+
check=True
101+
)
102+
lines = heads.stdout.splitlines() + tags.stdout.splitlines()
103+
branches = []
104+
for line in lines:
105+
_, ref = line.split()
106+
refs, heads, branch_name = ref.split("/", 2)
107+
branches.append(branch_name)
108+
return branch in branches
109+
except subprocess.CalledProcessError:
110+
m = f"Problem accessing list of branches and/or tags: {self.git_url}"
111+
logging.exception(m)
112+
raise ValueError(m)
113+
114+
def resolve_default_branch(self):
115+
"""
116+
This will resolve the default branch of the repo in
117+
the case where the branch given does not exist
118+
"""
119+
try:
120+
head_branch = subprocess.run(
121+
["git", "ls-remote", "--symref", self.git_url, "HEAD"],
122+
capture_output=True,
123+
text=True,
124+
check=True
125+
)
126+
for line in head_branch.stdout.splitlines():
127+
if line.startswith("ref:"):
128+
# line resembles --> ref: refs/heads/main HEAD
129+
_, ref, head = line.split()
130+
refs, heads, branch_name = ref.split("/", 2)
131+
return branch_name
132+
raise ValueError(f"default branch not found in {self.git_url}")
133+
except subprocess.CalledProcessError:
134+
m = f"Problem accessing HEAD branch: {self.git_url}"
135+
logging.exception(m)
136+
raise ValueError(m)
137+
78138
def pull(self):
79139
"""
80140
Pull selected repo from a remote git repository,
@@ -243,13 +303,11 @@ def main():
243303

244304
parser = argparse.ArgumentParser(description='Synchronizes a github repository with a local repository.')
245305
parser.add_argument('git_url', help='Url of the repo to sync')
246-
parser.add_argument('branch_name', default='master', help='Branch of repo to sync', nargs='?')
247306
parser.add_argument('repo_dir', default='.', help='Path to clone repo under', nargs='?')
248307
args = parser.parse_args()
249308

250309
for line in GitPuller(
251310
args.git_url,
252-
args.branch_name,
253311
args.repo_dir
254312
).pull():
255313
print(line)

nbgitpuller/static/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ require([
4444
// Start git pulling handled by SyncHandler, declared in handlers.py
4545
var syncUrlParams = {
4646
repo: this.repo,
47-
branch: this.branch,
4847
targetpath: this.targetpath
4948
}
5049
if (typeof this.depth !== 'undefined' && this.depth != undefined) {
5150
syncUrlParams['depth'] = this.depth;
5251
}
52+
if (typeof this.branch !== 'undefined' && this.branch != undefined) {
53+
syncUrlParams['branch'] = this.branch;
54+
}
5355
var syncUrl = this.baseUrl + 'git-pull/api?' + $.param(syncUrlParams);
5456

5557
this.eventSource = new EventSource(syncUrl);

nbgitpuller/templates/status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
data-base-url="{{ base_url | urlencode }}"
66
data-repo="{{ repo | urlencode }}"
77
data-path="{{ path | urlencode }}"
8-
data-branch="{{ branch | urlencode }}"
8+
{% if branch %}data-branch="{{ branch | urlencode }}"{% endif %}
99
{% if depth %}data-depth="{{ depth | urlencode }}"{% endif %}
1010
data-targetpath="{{ targetpath | urlencode }}"
1111
{% endblock %}

tests/test_gitpuller.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ def push_file(self, path, content):
6161

6262

6363
class Puller(Repository):
64-
def __init__(self, remote, path='puller', *args, **kwargs):
64+
def __init__(self, remote, path='puller', branch="master", *args, **kwargs):
6565
super().__init__(path)
6666
remotepath = "file://%s" % os.path.abspath(remote.path)
67-
self.gp = GitPuller(remotepath, 'master', path, *args, **kwargs)
67+
self.gp = GitPuller(remotepath, path, branch=branch, *args, **kwargs)
6868

6969
def pull_all(self):
7070
for line in self.gp.pull():
@@ -96,6 +96,47 @@ def test_initialize():
9696
assert puller.git('rev-parse', 'HEAD') == pusher.git('rev-parse', 'HEAD')
9797

9898

99+
def test_branch_exists():
100+
with Remote() as remote, Pusher(remote) as pusher:
101+
pusher.push_file('README.md', '1')
102+
with Puller(remote, 'puller') as puller:
103+
assert not puller.gp.branch_exists("wrong")
104+
assert puller.gp.branch_exists("master")
105+
106+
107+
def test_exception_branch_exists():
108+
with Remote() as remote, Pusher(remote) as pusher:
109+
pusher.push_file('README.md', '1')
110+
with Puller(remote, 'puller') as puller:
111+
orig_url = puller.gp.git_url
112+
puller.gp.git_url = ""
113+
try:
114+
puller.gp.branch_exists("wrong")
115+
except Exception as e:
116+
assert type(e) == ValueError
117+
puller.gp.git_url = orig_url
118+
119+
120+
def test_resolve_default_branch():
121+
with Remote() as remote, Pusher(remote) as pusher:
122+
pusher.push_file('README.md', '1')
123+
with Puller(remote, 'puller') as puller:
124+
assert puller.gp.resolve_default_branch() == "master"
125+
126+
127+
def test_exception_resolve_default_branch():
128+
with Remote() as remote, Pusher(remote) as pusher:
129+
pusher.push_file('README.md', '1')
130+
with Puller(remote, 'puller') as puller:
131+
orig_url = puller.gp.git_url
132+
puller.gp.git_url = ""
133+
try:
134+
puller.gp.resolve_default_branch()
135+
except Exception as e:
136+
assert type(e) == ValueError
137+
puller.gp.git_url = orig_url
138+
139+
99140
def test_simple_push_pull():
100141
"""
101142
Test the 'happy path' push/pull interaction

0 commit comments

Comments
 (0)