Skip to main content

Create Temporary GitHub Repos for Demos with Terraform

·733 words·4 mins
Terraform Github Automation

Lately, I’ve been creating many demos for work, user-groups, or just for fun. These demos often need one or more GitHub repositories with some code in them. Not that surprising, I suppose.

In this blog post I want to share the simple approach I use to set these demo repositories up using Terraform. This allows me to quickly set up everything I need for a demo without having to have demo repositories lying around just in case I would need them. With that said, of course you will need a repository to store the code to set up the demo repositories - unless you store the code somewhere else.

Use the GitHub provider for Terraform
#

In case you didn’t know (but you probably strongly suspected it after reading the introduction to this post) GitHub has a Terraform provider. This provider is developed by GitHub themselves (yes, I have gotten it confirmed by them). You can find the provider at the public Terraform registry.

The GitHub provider is available under the integrations namespace. Do not ask me where they got this name from, because I do not know! It’s the only provider under this namespace as you can see here.

As with many providers there are a number of ways you can configure it. When I set up a quick demo I almost always do it from my own local environment. In this environment I am authenticated to GitHub using the GitHub CLI - I highly recommend you install it and authenticate it to GitHub on your own machine.

Assuming you also use the GitHub CLI, all you need to do to use the GitHub provider is the following:

terraform {
  required_providers {
    github = {
      source  = "integrations/github"
      version = "~> 6.6.0"
    }
  }
}

provider "github" {
  owner = var.github_organization
}

Here I configure what GitHub organization (or personal account) I am targeting using the owner argument with the value from my github_organization variable.

If you usually use your own private GitHub handle, then you could add the following to your Terraform configuration:

variable "github_organization" {
  type        = string
  description = "GitHub organization name or personal handle"

  # replace with your own default value
  default = "mattias-fjellstrom" 
}

Provision a demo repository
#

I usually place the contents of the demo repository (or more commonly repositories) in a directory named repos. Inside repos I have one subdirectory for each demo repository I want to create for this particular demo.

To illustrate this, the directory structure might look something like this:

$ tree .
.
├── main.tf
└── repos
    ├── repo-1
    │   ├── main.tf
    │   ├── providers.tf
    │   └── variables.tf
    └── repo-2
        ├── main.tf
        ├── providers.tf
        └── variables.tf

To create the corresponding repository with the correct content I do this:

locals {
  # the path to where the repository content is
  path      = "${path.module}/repos/repo-1"

  # get all filenames in the content directory
  # instead of "**" representing all files and subdirectories you can use a pattern to get certain files
  filenames = fileset(local.path, "**")

  # create a map (filename => content)
  content   = { for filename in local.filenames : filename => file("${local.path}/${filename}") }
}

resource "github_repository" "demo" {
  name = "my-demo-repository"
}

resource "github_repository_file" "all" {
  for_each = local.content

  repository = github_repository.demo.name
  file       = each.key
  content    = each.value
}

And that’s it!

Note how I used the fileset function along with the ** pattern. If you only want to include certain files (like only your Terraform .tf files) you can control this in the pattern. However, I recommend that all files you place in the repository directories are suppose to be part of the repo (and in that case ** is a good pattern).

To work with multiple demo repositories you can turn the sample code shown here into a module that takes the content directory and any other required arguments as input.

Note, the content is committed to the repository one file at a time. This can lead to some unexpected behavior, like queuing up multiple runs on a HCP Terraform workspace (if you create a workspace and connect it to the repository in the same Terraform configuration). Use depends_on or other tactics to get around this behavior.

You can use the GitHub provider for Terraform for a lot more than what I did in this blog post. However, for creating demo repositories quickly you do not need more than this.

Mattias Fjellström
Author
Mattias Fjellström
Cloud architect · Author · HashiCorp Ambassador