DEV Community

Ian Knighton
Ian Knighton

Posted on • Originally published at ianknighton.com on

Using GitHub to Manage Your GitHub

Let me come out of the gate and say that this idea comes from a talk at GitHub Universe 2022. They go pretty deep into it, so I thought I would show a basic implementation I use as a primer for someone to build off of.

Also, as always, here's the actual source if you don't want to read the whole thing.

But, why?

I'll probably say this until I'm blue in the face, but if it can be code and in source control...it should be in code and source control. Everything becomes repeatable, trackable, and standardize-able.

Let's look at this in a small scenario:

You've been working on a small project and it's reached a point you're going to bring in a couple people to help you. As it's just been you, things like merging directly to main has been fine, but now that there are multiple people working on the project it's not really sustainable to not use branches. Since you're managing the project, you probably want a pull request for every feature and the ability to look at them before they go into main.

That's pretty simple click-ops.

Things go well and now you need to start working on splitting off a service. You've made the decision to move this to a new repository to separate out the concerns. Now you have to click-ops two repos to give your team access and turn on the branch protection and do any other configuration you've done on the main repository.

Times that by four or five and I think you can see how tedious that becomes. Especially if you decide to change your policy and you then have to go change it in multiple places and make sure it's correct across all of the repositories.

And then you bring in new members to the team when someone leaves...

You get the point.

Okay, how?

Creating the main.tf

We start simple...

We'll need a main.tf that has the GitHub provider configured and a variables.tf that sets our default organization.

terraform {
  required_providers {
    github = {
      source = "integrations/github"
      version = "6.9.0"
    }
  }
}

provider "github" {
  owner = var.github_organization
}
Enter fullscreen mode Exit fullscreen mode

main.tf file that adds the GitHub provider and configuration.

variable "github_organization" {
  description = "The GitHub organization where the repository will be created"
  type = string
  default = "{YOUR_ORG}"
}
Enter fullscreen mode Exit fullscreen mode

variables.tf file that sets the default organization for the GitHub provider.

At this point, you should be able to run terraform init and validate that you're able to complete that process. We've made no changes, but nothing going forward will work until you've ran the init and allowed Terraform to pull in the providers.

Creating a Repository Resource

Now that we're set, let's start by creating a resource for an existing repository. I like using the pattern github-repository-{REPOSITORY_NAME}.tf when creating these resources.

As an example, the code for this blog post is saved in a repo called jubilant-octo-spork, so the file name would be github-repository-jubilant-octo-spork.tf. The related resource inside of that file would look like this:

resource "github_repository" "jubilant_octo_spork" {
  name = "jubilant-octo-spork"
  description = "An example of using Terraform in GitHub to manage your GitHub"
  visibility = "public"
}
Enter fullscreen mode Exit fullscreen mode

Example terraform configuration for GitHub repository.

Note that the resource name uses _ instead of - as the separator. This is just to conform with Terraform standards and makes life a little easier when you're working with resources.

Importing an Existing Repository

If you were to run terraform plan at this phase, the output will tell you that it wants to create a repository. That's all well and good, but in this case this repo already exists so we don't want to do that. In order to fix that, we'll import the existing repos information into that resource we just created.

The command looks like:

terraform import github_repository.{RESOURCE_NAME} {REPOSITORY-NAME}
Enter fullscreen mode Exit fullscreen mode

So in our example case, it would be:

terraform import github_repository.jubilant_octo_spork jubilant-octo-spork

Enter fullscreen mode Exit fullscreen mode

This will run for a second as it uses the GitHub API to pull in the information and match it to the resource. From here forward, the repository itself is now part of the Terraform state and thus is being controlled by Terraform.

Plan Validation

To make sure we don't accidentally cause any issues, run a terraform plan to see what changes Terraform thinks need to be made in order to make the local state file match the actual resource.

Again, using the example case, the plan output looks like:

  # github_repository.jubilant_octo_spork will be updated in-place
  ~ resource "github_repository" "jubilant_octo_spork" {
      - has_downloads = true -> null
      - has_issues = true -> null
      - has_projects = true -> null
      - has_wiki = true -> null
        id = "jubilant-octo-spork"
        name = "jubilant-octo-spork"
        #
Enter fullscreen mode Exit fullscreen mode

What this is telling us is that in GitHub downloads, issues, projects, and wikis are all turned on but we don't have that in our current terraform configuration. In order to correct this, we'll just update our resource to make sure all of those settings match.

resource "github_repository" "jubilant_octo_spork" {
  name = "jubilant-octo-spork"
  description = "An example of using Terraform in GitHub to manage your GitHub"
  has_downloads = true
  has_issues = true
  has_projects = true
  has_wiki = true
  visibility = "public"
}
Enter fullscreen mode Exit fullscreen mode

Running the terraform plan again should give us a result that no changes are needed to be made.

No changes. Your infrastructure matches the configuration.
Enter fullscreen mode Exit fullscreen mode

Committing It

From here, there's a lot of rinse and repeat. Add the file and commit to the repo you're working in, push it into source control, and now you have version control around your GitHub resources. This can be applied to all GitHub resources outlined in the Terraform Registry documentation.

What's next?

In our current setup, this terraform is only manageable from the machine it was created on.

In your personal environment, that will work fine.

In a production/enterprise environment, you need to do something different.

This involves a remote state and maybe even a deployment pipeline. Considering as this has already gone a bit long, I'll come back and put together a post on how to do that step.

Top comments (0)