Simple bash scripts to leverage GitHub's REST API

When starting a new project, I often repeat the same steps to create and configure a repository on GitHub. Here are some bash script to make this task easier.

The first script creates a new repository on GitHub. The second adds a new deploy key to the repository. Deploy keys are SSH keys that can be used to read / write to private repositories without having to share your account credentials. I use them all the time when working on remote server with an SSH connection. I create a deploy key for each (server, project) pair and revoke them as soon as I'm done working.

Creating repositories on GitHub

Using GitHub's REST API

I created a script to create a new repo on GitHub. To use it, first fetch an authentication token from GitHub. It a bit fastidious, but we'll reuse it for the other scripts.

~/bin/github-create-repo
#!/bin/bash

[ -z "$1" ] && echo 'Argument $1: GitHub authorization token' && exit 1
[ -z "$2" ] && echo 'Argument $2: GitHub user name' && exit 1
[ -z "$3" ] && echo 'Argument $3: Name of the repo to create' && exit 1
[ -z "$4" ] && echo 'Argument $4: Description of the repo' && exit 1
[ -z "$5" ] && echo 'Argument $5: Whether the repo is private' && exit 1

curl -i -H "Authorization: token $1" \
    -d '{
        "name": "'"$3"'",
        "description": "'"$4"'",
        "private": '"$5"'
        }' \
    https://api.github.com/user/repos \
&& git clone git@github.com:$2/$3

Notice my minimal argument parsing^^. If you call the script with the first arguments, it'll print which argument is missing in order.

The script can be used as follow (where $IS_PRIVATE can be either true or false):

 github-create-repo $TOKEN $USER_NAME $REPO_NAME $REPO_DESCR $IS_PRIVATE

You might want to create an alias to avoid typing the token and username variables each time. For instance:

git config --global alias.create '!github-create-repo <token> <user_name>' 

And then use it as follows:

git create $REPO_NAME $REPO_DESCR $IS_PRIVATE

Using GitHub cli

Another option is to install GitHub's cli. You need to go to the webpage to find the latest version. As of 05.27.2020 I installed it as follow:

wget https://github.com/cli/cli/releases/download/v0.9.0/gh_0.9.0_linux_amd64.deb -O /tmp/gh.deb
sudo apt install /tmp/gh.deb

Configure it to use SSH instead of HTTPS for remote URLs:

gh config set git_protocol ssh

To create a new repository:

gh repo create $REPO_NAME
gh repo create --public $PUBLIC_REPO_NAME

Creating deploy keys

I often work on remote servers using SSH. The simplest is to host my code directly on the server and save my progress on GitHub. Deploy keys are rsa keys that provide access only to one repository. We can use them to push into / pull from the repo without having to type a password and without having to copy our account's rsa key to the server.

After I've created a new repository, I'll want to add a new deploy key to this repo to be able to access it from the server. Here's a script to do so:

~/bin/github-deploy-key
#!/bin/bash

[ -z "$1" ] && echo 'Argument $1: GitHub authorization token' && exit 1
[ -z "$2" ] && echo 'Argument $2: GitHub username' && exit 1
[ -z "$3" ] && echo 'Argument $3: GitHub repository name' && exit 1
[ -z "$4" ] && echo 'Argument $5: deploy key title' && exit 1
[ -z "$5" ] && echo 'Argument $6: key has read-only access?' && exit 1
[ -z "$6" ] && echo 'Argument $7: password for the key' && exit 1

set -eou pipefail

ssh-keygen -t rsa -C "$4" -f /tmp/deploy-key -N "$6"  2>/dev/null <<< y >/dev/null

curl -i                                      \
   -H "Authorization: token $1"              \
   -d '{
          "title": "'"$4"'",
          "key": "'"$(</tmp/deploy-key.pub)"'",
          "read_only": '"$5"'
   }'                                        \
   https://api.github.com/repos/$2/$3/keys

echo "Deploy key written to /tmp/deploy-key"

The line with ssh-keygen generates a new rsa key. Here are the details of what it does:

# create a new rsa key
# -t rsa: means to use rsa encryption
# -C "comment": adds comment to the key
# -f /path/to/file: write key in file
# -N passwd: protect key using password "passwd"
# 2>/dev/null: discard stderr output
# <<< y: answer 'y' to any question ssh-keygen asks
# >/dev/null: discard stdout output
ssh-keygen -t rsa -C "$4" -f /tmp/deploy-key -N "$6"  2>/dev/null <<< y >/dev/null

The script can be used as follows:

github-deploy-key $TOKEN $USER_NAME $REPO_NAME $KEY_TITLE $READ_ONLY $KEY_PASSWD

As before, you might want to create an alias to avoid typing the token, user name and repo name. We can hardcode the user name in the alias because it's associated with the token. For the repo name, however, it's useful to parse it directly from the repo.

Inside a git repository whose origin is a GitHub URL, we can get the repo name as follows:

echo $(basename $(git remote get-url origin)) | sed 's/.git//g'

With this, we can create an alias for the script. The simplest is to edit ~/.gitconfig manually to avoid mixing quotes.

vim ~/.gitconfig

Under [alias], define a new alias:

~/.gitconfig
[alias]
    create = !github-create-repo <token> <user>
    add-key = !github-deploy-key <token> <user> "$(echo $(basename $(git remote get-url origin)) | sed 's/.git//g')"

Assuming the deploy key was written to /tmp/deploy-key.pub, the alias can be used as follows:

git add-key test@example.com true password

Then, upload the key to the remote server using scp:

scp /tmp/deploy-key* <host>:~/.ssh/

And make sure the permissions are correct:

ssh <host>
chmod 700 ~/.ssh
chmod 600 ~/.ssh/deploy-key*

Where <host> is the remote server where to upload the key. See my article about SSH for more info.

Remark: bash vs python

These scripts simply wrap a POST request to the GitHub API. Additional code is required to parse the arguments. It would have been more work to create a real command line interface (which is a severe issue with bash IMHO).

Another possibility was to create the scripts using python. There's a nice library named pygithub which wraps the REST api. See for instance the method Repository.create_key(title, key, read_only=False) to create a deployment key.

I never know whether to use pure bash or python. One the one hand bash requires no additional library, on the other hand python is much nicer to read, write and debug... And a real command line interface would have been easy to code in python (see my Complete guide to writing command-line tools in python).