Are you recently developing many hobby projects? And you are getting bored by creating GitHub repositories again and again? Yeah I know it’s kind of boring. But good news! We are going to use GitHub APIs with Python. So you don’t have to do the initial repeated tasks ever again. But let’s see, what we actually have to do when we will do that manually. First, we need to set up a project. It can be a PHP project or Python. It doesn’t matter. Then we had to initiate a git repository and commit the initial changes locally. After that, we used to visit our Github profile to create a repository. Then in local, we set the origin and push to master. Look, we should all have some tools or script which will be handy in this kind of case. Life gets easier. So let’s start.
Prerequisite
- Python3
- pip
- venv
- Github account
- Github access token
- requests~=2.23.0
- python-dotenv~=0.13.0
Objectives
- Create a repository in GitHub
- Push local changes to the master branch
- Stay home and stay safe
Project folder and file structure
. ├── github │ ├── __init__.py │ ├── run.py │ └── services.py ├── README.md ├── requirements.txt ├── settings.py ├── shell_scripts │ ├── github_push.sh └── utils ├── helpers.py └── __init__.py └──.env
Adding Shell Scripts
Now to add remote origin we need to add the below code in shell_scripts/github_push.sh.
#! /bin/bash set -e # shellcheck disable=SC2164 cd cd "$1" git remote add origin "$2" git push origin master
Config .env file
Now we need to add some credentials in our .env file.
GITHUB_ACCESS_TOKEN={Your github access token} GITHUB_USERNAME={Your github username}
To get GitHub access token visit here.
Config settings.py
Now let’s add some constants to use in our projects inside the settings.py file.
import os from dotenv import load_dotenv load_dotenv() GITHUB_ACCESS_TOKEN = os.getenv("GITHUB_ACCESS_TOKEN") GITHUB_USERNAME = os.getenv("GITHUB_USERNAME")
Helper methods
Now, let’s create some helper method to get a shell script from a directory and building a remote origin URL. To do that we will write those methods in utils/helpers.py file.
import os from settings import GITHUB_USERNAME def get_shell_script(file_name: str) -> dict: """ Get shell script from shell_scripts folder :param file_name: :return: """ try: # Get the root directory root_dir = os.path.dirname( os.path.realpath(__file__)).rsplit(os.sep, 1)[0] # Get the shell script, which will create the venv shell_script = os.path.join(root_dir, "shell_scripts", file_name) return dict(success=True, script=shell_script) except Exception as e: return dict(success=False, message=str(e)) def github_repo_remote_origin(repo_name: str) -> str: """ :param repo_name: :return: """ return "git@github.com:"+GITHUB_USERNAME+'/'+repo_name+'.git'
Developing a service for Github Automation
Let’s build a separate service for all the actions. But first, import all the necessary things.
import subprocess import requests from settings import GITHUB_ACCESS_TOKEN, GITHUB_USERNAME from utils.helpers import get_shell_script
Now let’s create a class with its properties.
class GithubService: """ Github service """ __github_push_shell_script: str = "github_push.sh" __repo_creation_end_point: str = "https://api.github.com/user/repos" __headers = { 'Authorization': 'token ' + GITHUB_ACCESS_TOKEN }
Let’s write an __init__ method with two arguments, one is repo_name and another is git_directory.
def __init__(self, repo_name, git_directory): """ :param repo_name: :param git_directory: """ self.repo_name = repo_name self.git_directory = git_directory
Now let’s write a method to get remote origin.
def __github_repo_remote_origin(self): """ :return: """ return "git@github.com:"+GITHUB_USERNAME+'/'+self.repo_name+'.git'
We need a method to create a Github repository. To do that we will need the help of python request. We will make a post request in __repo_creation_end_point with a repo name and it will create a repository in Github for us. Check out the PI documentation I have added below and you will find something like that in the repository section.
” alt=”” width=”630″ height=”630″ data-lazyloaded=”1″ data-placeholder-resp=”630×630″ data-src=”https://toptechytips.com/wp-content/uploads/2020/06/Screenshot-from-2020-06-17-22-01-04-300×300.png” data-srcset=”https://toptechytips.com/wp-content/uploads/2020/06/Screenshot-from-2020-06-17-22-01-04-300×300.png 300w, https://toptechytips.com/wp-content/uploads/2020/06/Screenshot-from-2020-06-17-22-01-04-150×150.png 150w” data-sizes=”(max-width: 630px) 100vw, 630px” />
def create_repo(self) -> dict: """ :return: """ try: with requests.Session() as s: s.headers.update(self.__headers) resp = s.post(self.__repo_creation_end_point, json={ "name": self.repo_name }) print(resp.content.decode()) return dict(success=True, message="Github repository has been created") except Exception as e: return dict(success=False, message=str(e))
Now we need to push our changes in Github right? To do that we need to add remote origin and push changes there. We will get our shell script first. Then we will run it in a subprocess.
def git_add_remote_origin_and_push_master(self): """ Will add remote origin and push changes to github repo :return: """ try: shell_script = get_shell_script(self.__github_push_shell_script) if not shell_script["success"]: return dict(success=False, message="Shell script not found") # execute and get the output of the shell script output = subprocess.check_output([ shell_script["script"], str(self.git_directory), str(self.__github_repo_remote_origin()), ]) print(output.decode()) return dict(success=True, message="Git push successfull") except Exception as e: print(e) return dict(success=False, message="Git push failed", error_message=str(e))
To run the whole process we need to write the below code in the github/run.py file.
from github.services import GithubService def create_repo_and_push_local_changes(repo_name: str, git_directory: str) -> dict: github_service = GithubService(repo_name, git_directory) repository_api_response = github_service.create_repo() if not repository_api_response["success"]: return repository_api_response push_response = github_service.git_add_remote_origin_and_push_master() if not push_response["success"]: return push_response return dict(success=True, message=dict( repository_api_response=repository_api_response["message"], push_response=push_response["message"], ))
If you check your Github you will find your repository there. One thing you have noticed that We have run shell scripts in the subprocess. The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions. In Linux, a subprocess is a child process, i.e. a process that has been launched by its parent to which it is a subprocess. An interactive shell is a command-line interpreter reading your input line by line and prompting you when a command is done.
Well, let me tell you about this tool. I have developed a tool to automate python projects. It will create a project in venv and do all the git and Github stuffs for me. I have shown you examples of Github API using python. We will discover more about the tool in the future. Till then write a tool for automating Github. You can do many actions with Github APIs. I have gave you all the thing you will need to know.
Happy coding!
Original tool Github repository: https://github.com/zim0101/jervis_the_bot
Python subprocess module: https://docs.python.org/3/library/subprocess.html
Github API documentation: https://developer.github.com/v3/