LGTM Devlog 4: Technical Decisions - GitHub API and Python
Tags: devjournal, github, git, python
Published: 2020-12-28 11:47:18

Let's talk tech. A quick recap on the design ideas we have so far:

* Players start playing LGTM by Forking an/the LGTM repo, since that's the easiest way for us to start the game (two clicks on GitHub's web interface); with later activity requiring the player to create/accept shared repos
* The game backend posts Issues to the player's Fork, with tasks to do. These Issues are essentially "Quests/Missions" in usual game terms, and contain some narrative, and may contain NPCs commenting back and forth to add some realism (or maybe fictional setting to make it interesting)
* The player does the task needed by the issue. Which will primarily involve something requiring the use of a git client or GitHub
* The game backend detects the completed task, and issues new tasks

How do we achieve this?

# Language choice: Python or Javascript
I have at my disposal, two languages appropriate to this task: Python, and Javascript. When I pick languages for a new project, I like to be pragmatic about the choice and find the one that's most appropriate for the task, but balancing that with my familiarity with a language with my willingness to learn and expand my knowledge.

It's often said that "the best language for the task is the one you know". I think this should really be changed to "the best language for the task is some compromise between what you know, and what you're willing to learn based on possible future and career benefits", but that's not as catchy.

Since I have experience with both Python and Javascript, and have found knowledge of the two to be extremely useful and complementary to each other, I think either of these would be a good choice. And since this feels like a back-end heavy task, Python is the initial choice.

A quick check for libraries that I'll likely need shows there's no clear gaps and downsides to using Python for the backend, and no clear advantages, at least in my mind, of going with Javascript (though I'm sure Javascript devs will disagree). (As a side note, an example of where Python would have been a bad choice, is for example in dealing with GraphQL - the python ecosystem for this quite far behind Javascript right now, and had this project needed or benefitted from it, the choice would have swung strongly in favour of Javascript, as it has done in my other work)

As for front-end, though there's no real front-end for this game, I am sure a website with stats, and perhaps even a login for users to look at their progress, may be useful later. If we go there, then that's where the Javascript will come in. When it comes to web frameworks, I feel modern Javascript frontend frameworks are a better option than Python's web frameworks.

# GitHub API
One of the key things we will need is going to be GitHub's API, which allows us to programmatically do many of the above tasks such as posting Issues. While the GitHub API is a set of REST endpoints, it is often a lot easier to use a library that implements these endpoints to save us a lot of time and grief.  Having a quick Google for Python libraries, the PyGitHub library seems like the best way to go.

{% github PyGithub/PyGithub no-readme %}

The second thing we need to work with GitHub is a webserver that will respond to webhooks from GitHub itself, which are needed to receive notifications when certain things happen, like someone forks a repo. We'll discuss that in the next post.

# git itself
Since we are going to need to prepare git repositories, in exactly the state we need them for players to complete the task, we have a few options for this:

* Prepare them beforehand, and just send players a sort of "canned repo".
* Prepare them on-the-fly

There are pros and cons of each

## "Canned repo"
In this option, I would take an/the official LGTM repo (probably the one that the player forked earlier), and on my computer, use the git client and a text editor to manually apply what I want the repo to look like when the player has to do the task, probably in a separate branch. Then the game service can simply make a PR of that branch to the player's fork as part of the setup for a task.

Pros:
* Easy for me to do

Cons:
* Every piece of content of the game is available for players to inspect since they need to be on GitHub, in a public repo, to be able to be PR'd (but is this a bad thing?)

## On-the-fly
In this option, I would have code programmatically make the changes needed to a repo, and then commit it. The game service would effectively be generating the commits needed for the task on-the-fly, using a library such as this one:

{% github gitpython-developers/GitPython no-readme %}

Pros:
* Very flexible, can customize what got committed. Maybe this is useful from a narrative point of view?

Cons:
* Seems difficult
* Would not work well with a single public repo (works best with multiple private ones)

After some deliberation, it would appear that this option can't be used with the forked public repo, because I would end up generating a new set of game data for every player, solely for the purpose of setting up their repo.

Instead, this option would be ideal in the case where a player has shared a repo with us (or we've created a repo to share with the player) since we could dynamically apply the task commits, and commit it to their repo

## Conclusion
So the conclusion here is clear: If we go with the player starting off with the Forked repo, then we will have to go with the "canned repo" approach, that fork will have to contain ALL of the commits necessary for all Tasks that can be played on that fork.

Then, perhaps for later stages of the game, we can move to doing things on-the-fly. If this is the case, then I'm going to icebox this idea for the future to avoid scope creep at this stage. I will focus on the "canned repo" approach in the first version of the game to be released, and revisit it in the next major release that includes all the tasks that happen outside the Forked repo.