Programmatically deploy your GitHub Repo on Netlify
Tags: python, netlify, github, tutorial
Published: 2024-01-10 08:46:29

Have you ever tried to publish a GitHub repo on Netlify programmatically?
If it ever happened to you to need or want to reach this and search the documentation for answers, chances are that, like me, you didn't find any official information about it and got lost among some forum posts, also quite confused.

After lots of research, many mistakes, and a large amount of frustration, I finally managed to deploy programmatically a repo from Github to Netlify, so I wanted to share with you how to do it and spare you hours of research!

- [Let's get Started](#lets-get-started)
- [The tricky part: connecting Github and Netlify](#the-tricky-part-connecting-github-and-netlify)
- [One last step](#one-last-step)
- [Conclusion](#conclusion)

## Let's get Started

So... first of all, you will need a **Netlify token** and your **username**; to create your access token, you need to login to your Netlify account and go on [user settings -> application](https://app.netlify.com/user/applications) 
Here, you can create a new access token to save in your env file with your username. 

Now we can start building the payload for our request, starting with a unique name for our site:

```python
sitename = str(time.time())+"site"

payload = {
    "name":sitename,
    "subdomain":sitename}
```

Using the UNIX timestamp is quite an easy way to have a unique site name for your account, but you can replace it with any other technique you choose.

After that, you will need some repository information to connect our app to the desired repo. 
I covered how to get the most common information from GitHub in a previous article, so I leave you a [link to that](https://dev.to/giuliano1993/one-api-to-git-them-all-e8c) for this part and just show you quickly how to do that same thing in python

```python
def getConfig(configName):
  configsFile = yaml.safe_load(open('./env.yaml'))
  return configsFile['configs'][configName]


def repoList():
    user = getConfig("gitUser")
    gitToken = getConfig('gitToken')
    url = f"https://api.github.com/users/{user}/repos?per_page=100"
    response = requests.get(
        url=url,
        headers={
            "Accept":"application/vnd.github+json",
            "Authorization": f"Bearer {gitToken}",
            "X-GitHub-Api-Version": "2022-11-28"
        }
    )
    return response.json()

```

Once you have the list of all repositories available in your profile, you can choose which one to use for your site. When developing CLIs with python, I love to use **inquirer** to handle user interactions; so, to install inquirer, run: 
```bash
pip install inquirer
```
and let's get to choose our repo ;) 

```python
#here we save in repos the result from github call
repos = repoList.repoList()
repoChoices = []
# We then create an array of choices for the user
for i, repo in enumerate(repos):
	choice = repo['full_name']
	repoChoices.append(choice)
# we prepare the prompt 
chooseRepo = [inquirer.List('pickRepo', message="choose a repo you want to link to the site", choices=repoChoices)]
#we ask the user which repo want to use and then we save it in the repo variable
answers = inquirer.prompt(chooseRepo)
index = repoChoices.index(answers['pickRepo'])
repo = repos[index]
```

## The tricky part: connecting Github and Netlify

Now that we have our repo, comes the hard part; there are, in fact, a couple of parameters in the site creation API that aren't quite well explained, which are the key to succeed in our task: the `deploy_key_id` and the `installation_id`.
The `deploy_key_id` is a public key we created and previously configured with our repo to enable automatic deployments on other websites (like Netlify). Without it, the deployment will result in an authorization error even if we properly connect the repository. The second important parameter is the `installation_id`, which stands for the id of our installation of Netlify app on GitHub. This allows GitHub to enable the connection through Netlify and keep deploying on the next pushes. 

You can create a **deploy key** with the APIs, but since this is not the article's topic, we will consider you already have a deploy key on your repo. If you don't know how to create and configure one, [check this doc out](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/managing-deploy-keys#deploy-keys). As you can see, briefly, you just need to create an **SSH Key** and upload it to Github trough the `Settings > Deploy Key` panel.
As said above, this can also be done through API, calling the `POST repos/{user}/{repo}/keys` endpoint, so if you want, you can try this way too.

You can then quickly get the `deploy_key` relative to your repo by making an API call to GitHub like this:

```python

user = getConfig("gitUser")
gitToken = getConfig('gitToken')
# Trough this endpoint we can retrieve all the deploy_keys related to a repository
url = f"https://api.github.com/repos/{user}/{repo}/keys"
response = requests.get(
	url=url,
	headers={
	    "Accept":"application/vnd.github+json",
		"Authorization": f"Bearer {gitToken}",
		"X-GitHub-Api-Version": "2022-11-28"
	},
)

# this is an oversemplification, considering you already know you have a deploy key configured.
deployKey = response.json()[0]
```


What about the installation ID? 
You need to connect Netlify and GitHub first; then you can get the ID of that connection; don't worry; you'll need to do this only once; that ID won't change.

To create your connection between Netlify and GitHub you just need to go on [netlify user settings](https://app.netlify.com/user/settings) and configure the connection with your GitHub account (grant access to all the repos to deploy further projects easily).
After doing this, you can navigate to [Github Application settings](https://github.com/settings/installations), click on configure, and copy the number appended at the end of the URL since that is your Installation ID. This process will be needed only once, and then you are set to go.

## One last step

So what's left to do? We now need to create our payload and send the request to  netlify!

```python
payload['repo'] = {
		#the branch you want to deploy
        "branch": repo['default_branch'],
        #the command to launch at build time
        "cmd": "npm run build",
        "deploy_key_id": depKey['id'],
        #the directory containing our packed project
        "dir": "dist/",
        #is the repo private?  
        "private": False,
        # our provider, could be github, gitlab or bitbucket
        "provider": "github",
        #the repo name in the format Author/Name
        "repo": repo['full_name'],
        #the repo id
        "repo_id": repo['id'],
        #the netlify installation id on github
        "installation_id": getConfig('installationId')
    }
    payload["build_settings"] = payload['repo']


user = getConfig("netlifyUser")
token = getConfig("netlifyToken")
reqUrl = f"https://api.netlify.com/api/v1/{user}/sites"
response = requests.request(
	method,
	url=reqUrl,
	headers={
		"content-type": "application/json",
		"Authorization": "Bearer "+token
	},
	json=payload
)

if(response.ok):
    print("New server was correctly created")
    print("New server ID = " + response.json()['id'])
else:
    print("There was an error:")
    print(str(response.status_code) + " : " + response.reason)
    print(response.json())
```


## Conclusion 

Here we are; we are done! Some of these functions aren't well documented, so I needed to do some research to build this, but it was totally worth it! I hope this can be useful as I looked for someone to explain this to me until some time ago! If you have any further and more accurate information, let me and the others know in the comments; it can really be helpful!

As always, I hope you appreciated this article! You can find a more complete version of this code on [this repo](https://github.com/Giuliano1993/ServerManPy). I'm also developing an open-source project you can use and contribute to, and you're very welcome to reach me on Github on [ServerMan](https://github.com/Giuliano1993/serverManNode)!
Any feedback on the article is welcome, as always! Hope you have a great time reading and learning!
Happy coding 0_1