5
\$\begingroup\$

I recently wrote a python script that syncs your locally clone repository to its parent repository, so I would like you to review it and help me in improving it.

#!/usr/bin/python3
# coding=utf-8
__author__ = "Ratan Kulshreshtha"
__github__ = "RatanShreshtha"
import os
import sys
from subprocess import call, check_output
import requests
"""
 This script runs a bunch of boilerplate code to synchronise
 your locally cloned fork to its parent github repository.
"""
CURRENT_REPO_ORIGIN = ['git', 'config', '--get', 'remote.origin.url']
CURRENT_REPO_UPSTREAM = ['git', 'config', '--get', 'remote.upstream.url']
ADD_REMOTE_CMD = ['git', 'remote', 'add', 'upstream']
CHECK_REMOTES_CMD = ['git', 'remote', '-v']
FETCH_UPSTREAM_CMD = ['git', 'fetch', 'upstream']
CHECKOUT_MASTER_CMD = ['git', 'checkout', 'master']
MERGE_UPSTREAM_CMD = ['git', 'merge', 'upstream/master']
PUSH_TO_UPSTREAM_CMD = ['git', 'push', 'origin', 'master']
def checkGitRepository():
 """
 Returns True if the repository is a git repository.
 """
 return os.path.isdir('.git')
def getRepoOriginUrl():
 """
 Return origin url of the git repository.
 """
 try:
 repo_origin_url = str(check_output(CURRENT_REPO_ORIGIN))
 repo_origin_url = repo_origin_url.replace("b'", "").replace("\\n'", "")
 print("origin url for this repository:- ", repo_origin_url)
 return repo_origin_url
 except Exception as e:
 print("Unable to get origin url for the repository")
 print(e)
 raise
def getRepoUpstreamUrl():
 """
 Return upstream url of the git repository.
 """
 try:
 repo_upstream_url = str(check_output(CURRENT_REPO_UPSTREAM))
 repo_upstream_url = repo_upstream_url.replace("b'", "")
 repo_upstream_url = repo_upstream_url.replace("\\n'", "")
 print("upstream url for this repository:- ", repo_upstream_url)
 return repo_upstream_url
 except Exception as e:
 print("Unable to get upstream url for the repository")
 print(e)
 raise
def fetchUpstream():
 """
 Fetches upstream changes to your local repository.
 """
 try:
 print("Fetching upstream...")
 print(".........")
 call(FETCH_UPSTREAM_CMD)
 print("Upstream fetch done")
 except Exception as e:
 print("Unable to fetch upstream for the repository")
 print(e)
 raise
def checkoutMasterBranch():
 """
 Checkouts master branch of the repository.
 """
 try:
 print("Checking out master")
 print(".........")
 call(CHECKOUT_MASTER_CMD)
 print("Master checkout done")
 except Exception as e:
 print("Unable to checkout master branch")
 print(e)
 raise
def mergeUpstream():
 """
 Merges upstream and local branch.
 """
 try:
 print("Merging master")
 print("..........")
 call(MERGE_UPSTREAM_CMD)
 print("Syncing done.")
 except Exception as e:
 print("Unable to merge.")
 print(e)
 raise
def pushToOrigin():
 """
 Pushes the locally sysnced code to your remote fork.
 """
 try:
 print("Pushing to origin master")
 print("........")
 call(PUSH_TO_UPSTREAM_CMD)
 print("Push done.")
 except Exception as e:
 print("Unable to push to origin")
 print(e)
 raise
def addRepoUpstream():
 """
 Adds upstream url of parent repository to the locally cloned
 fork if upstream not available.
 """
 repo_origin_url = getRepoOriginUrl()
 if repo_origin_url[0] == "h":
 url_segments = repo_origin_url.split("https://github.com/")
 if repo_origin_url[0] == "g":
 url_segments = repo_origin_url.split("[email protected]:")
 user_and_repo = url_segments[1]
 user_and_repo = user_and_repo.replace(".git", "")
 user, repo = user_and_repo.split("/")
 print("Getting upstream url for the repo ...")
 url = "https://api.github.com/repos/{}/{}".format(user, repo)
 try:
 response = requests.get(url)
 repo_upstream_url = response.json()["parent"]["clone_url"]
 print("Upstream URL is:-", repo_upstream_url)
 ADD_REMOTE_CMD.append(repo_upstream_url)
 print(ADD_REMOTE_CMD)
 print("Upstream is added to the fork")
 call(ADD_REMOTE_CMD)
 except Exception as e:
 print("Unable to add upstream url to the repository")
 print(e)
 raise
def sync():
 """
 Main function to sync the local forks with parents repository.
 """
 print("-" * 120)
 print("|" + "Starting Fork Syncing Process".center(118) + "|")
 print("-" * 120)
 # Check if the current repository is a git repository
 assert checkGitRepository()
 # Check if the git repository has a origin
 assert getRepoOriginUrl()
 try:
 # Now try to get the upstream for the repository.
 assert getRepoUpstreamUrl()
 # If upstream is present do following.
 # First fetch the upstream
 fetchUpstream()
 # Then checkout master branch
 checkoutMasterBranch
 # Then merge upstream master and local branch
 mergeUpstream()
 # Now finally push the delta to the origin master
 pushToOrigin()
 except Exception as e:
 print(e)
 print("Trying to add upstream automatically.")
 # Since upstream is not present do following
 # First add the upstream of the parent repository.
 addRepoUpstream()
 # Then fetch the upstream
 fetchUpstream()
 # Then checkout master branch
 checkoutMasterBranch
 # Then merge upstream master and local branch
 mergeUpstream()
 # Now finally push the delta to the origin master
 pushToOrigin()
 print("-" * 120)
 print("|" + "Ending Fork Syncing Process".center(118) + "|")
 print("-" * 120)
if __name__ == '__main__':
 print(os.getcwd())
 if len(sys.argv) > 1:
 repository_to_be_synced = sys.argv[1]
 os.chdir(repository_to_be_synced)
 print(os.getcwd())
 sync()
asked Mar 31, 2017 at 15:44
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Overall, the code is organized in a modular fashion and it's clear what is going on. There are some things that need improvement though.

Code Style Improvements

  • follow Python naming conventions - you are using camel case style a lot, but, in Python, it is only used for class names
  • there are also some rules violated regarding the docstrings style. For instance, if it fits one line, don't add newlines; always start it with an upper case character and end with a dot

Other ideas

  • you can replace if repo_origin_url[0] == "h" (same for the g) with a more readable str.startswith() call:

    if repo_origin_url.startswith("h"):
    

    Or, you may even take it a step further and check for http and git substrings - it may be clearer from readability perspective.

Other high-level ideas

  • check out some git Python modules - you may replace manually constructing the git commands and subprocess calls with nice Python function calls. For example, there is that mature gitpython package
  • notice that most of your functions have the same layout - you have the main "meat" of the functions put into the try/except blocks. See if you can avoid that and just wrap the function calls with a single try/except instead
  • I think you are overloading the code with comments more than you should. The downside of putting a lot of comments is it they should always be up-to-date with the code they are attached to, it's easy to forget to update a comment after updating the relevant block of code. This may lead to confusing situations
answered Mar 31, 2017 at 16:12
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.