]> git-server-git.apps.pok.os.sepia.ceph.com Git - teuthology.git/commitdiff
repo_utils: support github refs for branches 1339/head
authorKyr Shatskyy <kyrylo.shatskyy@gmail.com>
Tue, 22 Oct 2019 09:44:11 +0000 (11:44 +0200)
committerKyr Shatskyy <kyrylo.shatskyy@suse.com>
Tue, 12 Nov 2019 08:53:16 +0000 (09:53 +0100)
This adds possibility to checkout github pr providing
special purpose ref spec (like refs/pull/X/merge and
refs/pull/X/head) as branch parameter to teuthology,
for example, "teuthology-suite -t".

Signed-off-by: Kyr Shatskyy <kyrylo.shatskyy@suse.com>
teuthology/repo_utils.py

index bcff53af906102b85800d013be541319c8dedcd7..3af912f7049e73855561883c55b0f746f01e4684 100644 (file)
@@ -5,6 +5,7 @@ import shutil
 import subprocess
 import time
 
+from teuthology import misc
 from teuthology.util.flock import FileLock
 from teuthology.config import config
 from teuthology.contextutil import MaxWhileTries, safe_while
@@ -112,6 +113,9 @@ def clone_repo(repo_url, dest_path, branch, shallow=True):
     """
     validate_branch(branch)
     log.info("Cloning %s %s from upstream", repo_url, branch)
+    if branch.startswith('refs/'):
+        clone_repo_ref(repo_url, dest_path, branch)
+        return
     args = ['git', 'clone']
     if shallow:
         args.extend(['--depth', '1'])
@@ -138,6 +142,54 @@ def clone_repo(repo_url, dest_path, branch, shallow=True):
         raise GitError("git clone failed!")
 
 
+def rsstrip(s, suffix):
+    return s[:-len(suffix)] if s.endswith(suffix) else s
+
+
+def lsstrip(s, prefix):
+    return s[len(prefix):] if s.startswith(prefix) else s
+
+
+def remote_ref_from_ref(ref, remote='origin'):
+    if ref.startswith('refs/pull/'):
+        return 'refs/remotes/' + remote + lsstrip(ref, 'refs')
+    elif ref.startswith('refs/heads/'):
+        return 'refs/remotes/' + remote + lsstrip(ref, 'refs/heads')
+    raise GitError("Unsupported ref '%s'" % ref)
+
+
+def local_branch_from_ref(ref):
+    if ref.startswith('refs/pull/'):
+        s = lsstrip(ref, 'refs/pull/')
+        s = rsstrip(s, '/merge')
+        s = rsstrip(s, '/head')
+        return "PR#%s" % s
+    elif ref.startswith('refs/heads/'):
+        return lsstrip(ref, 'refs/heads/')
+    raise GitError("Unsupported ref '%s', try 'refs/heads/' or 'refs/pull/'" % ref)
+
+
+def fetch_refspec(ref):
+    if '/' in ref:
+        remote_ref = remote_ref_from_ref(ref)
+        return "+%s:%s" % (ref, remote_ref)
+    else:
+        # looks like a branch name
+        return ref
+
+
+def clone_repo_ref(repo_url, dest_path, ref):
+    branch_name = local_branch_from_ref(ref)
+    remote_ref = remote_ref_from_ref(ref)
+    misc.sh('git init %s' % dest_path)
+    misc.sh('git remote add origin %s' % repo_url, cwd=dest_path)
+    #misc.sh('git fetch --depth 1 origin %s' % fetch_refspec(ref),
+    #                                                        cwd=dest_path)
+    fetch_branch(dest_path, ref)
+    misc.sh('git checkout -b %s %s' % (branch_name, remote_ref),
+                                                            cwd=dest_path)
+
+
 def set_remote(repo_path, repo_url):
     """
     Call "git remote set-url origin <repo_url>"
@@ -188,11 +240,11 @@ def fetch_branch(repo_path, branch, shallow=True):
                       GitError for other errors
     """
     validate_branch(branch)
-    log.info("Fetching %s from upstream", branch)
+    log.info("Fetching %s from origin", branch)
     args = ['git', 'fetch']
     if shallow:
         args.extend(['--depth', '1'])
-    args.extend(['-p', 'origin', branch])
+    args.extend(['-p', 'origin', fetch_refspec(branch)])
     proc = subprocess.Popen(
         args,
         cwd=repo_path,
@@ -218,12 +270,16 @@ def reset_repo(repo_url, dest_path, branch):
                       GitError for other errors
     """
     validate_branch(branch)
-    log.info('Resetting repo at %s to branch %s', dest_path, branch)
+    if '/' in branch:
+        reset_branch = lsstrip(remote_ref_from_ref(branch), 'refs/remotes/')
+    else:
+        reset_branch = 'origin/%s' % branch
+    log.info('Resetting repo at %s to branch %s', dest_path, reset_branch)
     # This try/except block will notice if the requested branch doesn't
     # exist, whether it was cloned or fetched.
     try:
         subprocess.check_output(
-            ('git', 'reset', '--hard', 'origin/%s' % branch),
+            ('git', 'reset', '--hard', reset_branch),
             cwd=dest_path,
         )
     except subprocess.CalledProcessError:
@@ -255,7 +311,8 @@ def fetch_repo(url, branch, bootstrap=None, lock=True):
     src_base_path = config.src_base_path
     if not os.path.exists(src_base_path):
         os.mkdir(src_base_path)
-    dirname = '%s_%s' % (url_to_dirname(url), branch)
+    branch_dir = ref_to_dirname(branch)
+    dirname = '%s_%s' % (url_to_dirname(url), branch_dir)
     dest_path = os.path.join(src_base_path, dirname)
     # only let one worker create/update the checkout at a time
     lock_path = dest_path.rstrip('/') + '.lock'
@@ -278,6 +335,13 @@ def fetch_repo(url, branch, bootstrap=None, lock=True):
     return dest_path
 
 
+def ref_to_dirname(branch):
+    if '/' in branch:
+        return local_branch_from_ref(branch)
+    else:
+        return branch
+
+
 def url_to_dirname(url):
     """
     Given a URL, returns a string that's safe to use as a directory name.