Skip to content

schubergphilis/terraform-github-mcaf-repository

Repository files navigation

terraform-github-mcaf-repository

Terraform module to create and manage a GitHub repository.

Adding a license or .gitignore template

Take care when configuring either var.license_template or var.gitignore_template as the values are case sensitive. See here for a list of supported licenses or here for a list of supported gitignore templates - to use either, provide the file name without the extension, e.g. mit or Terraform respectively.

Setting one of these templates can only be done during creation of the repository. If you want to add a LICENSE or .gitignore file after repository creation, you'll need to do it like any other file.

Creating branches

Additional branches can be created and configured using var.branches. Any branches created here are in addition to the default branch (var.default_branch).

You can create branches by either adding them to var.branches:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  branches = {
    "develop" = {}
  }
}

Or by specifying the source branch or hash by setting source_branch or source_sha respectively:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  branches = {
    "develop" = {
      source_branch = "release"
    }
  }
}

See the github_branch resource for more details

Creating files

This module allows creating and managing files in a GitHub repository by using var.repository_files.

To create files:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  repository_files = {
    ".github/dependabot.yml" = {
      content = file("${path.root}/files/dependabot.yml")
    }
    "README.md" = {
      content = "Welcome to my project!"
      managed = false
    }
  }
}

The map key refers to the file path in the repository, and the content field contains the file content. By default, files created using this method are managed by Terraform, but this can be changed by setting the managed field to false, meaning any changes done outside of Terraform will be ignored.

Configuring (additional) branches

The default behaviour is for any branch created by this branch to inherit the default branch protection settings (var.default_branch_protection), but this can be overridden by either settings the branch_protection key or disabling branch protection by setting the use_branch_protection field to false.

To override the default branch protection settings, specify the branch_protection key:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  branches = {
    "develop" = {
      branch_protection = {
        enforce_admins         = true
        require_signed_commits = true
      }
    }
  }
}

In the event you want to create branches using Terraform but do not want any branch protection to be configured, you can set use_branch_protection to false:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  branches = {
    "develop" = {
      use_branch_protection = false
    }
  }
}

For more examples, see the branches examples.

Configuring autolink references

References to URLs, issues, pull requests, and commits are automatically shortened and converted into links. You can configure custom autolink references for a repository using the autolink_references variable.

You define custom autolinks by specifying a reference prefix and a target URL using var.autolink_references:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  autolink_references = {
    "JIRA" = { url_template = "https://my-jira-instance.atlassian.net/browse/<num>" }
  }
}

In the above example, JIRA-123 is converted to https://jira.example.com/issue?query=123 when viewing comments or commit messages.

Important

Reference prefixes cannot have overlapping names. For example, a repository cannot have two custom autolinks with prefixes such as TICKET and TICK, since both prefixes would match the string TICKET123a.

Configuring environments

Enviroments can be configured using the var.environments variable. This allows you to create environments with secrets, variables, and deployment policies.

You can also call the module directory, see its [README] for more details, or see the environments examples.

Granting access to a repository

This module manages repository access by granting access to pre-existing teams. To grant a team access, populate the access map, using the team name as the key and the desired level as the value, for example:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  access = {
    MyTeam   = "maintain"
    Everyone = "push"
  }
}

The module will use a data resource to look up the team ID and assign the team the desired permissions.

Important

If you're creating a GitHub team in the same run/workspace that assigns permissions to the repository, you must set an explicit dependency to ensure the team is created before repository:

resource "github_team" "myteam" {
  name = "MyTeam"
}

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  access = {
    MyTeam   = "maintain"
    Everyone = "push"
  }

  depends_on = [github_team.myteam]
}

Selecting a merge strategy

By default, the module will enable squash merges and disable merge commits and rebase merges. You can change this by setting the allow_merge_commit, allow_rebase_merge and allow_squash_merge variables to true or false.

To more easily select a single strategy, you can set the merge_strategy variable to one of the following values:

  • merge
  • rebase
  • squash

Using merge_strategy will override the above variables.

Managing files in a repository

It is possible to create (and manage) files within a GitHub repository using this module. We have a repository_files variable that takes a map of files to create; the key represents the name (and path) for the file, and the value is an object with the following attributes:

  • branch: optional value to specify the branch, defaults to the default branch
  • content: content of the file, can be a string or string sourced from a file or template using file() or templatefile() respectively.
  • managed: whether Terraform should manage this file, or if it is a one time commit and any changes done outside of Terraform, defaults to true
  • overwrite_on_create: whether to overwrite the file if it already exists when creating it, defaults to false

Example:

module "mcaf-repository" {
  source = "schubergphilis/mcaf-repository/github"

  name = "my-repo"

  repository_files = {
    "README.md" = {
      content = "# My repo"
      managed = false
    }
    ".github/workflows/ci.yml" = {
      content = templatefile("${path.module}/ci.yml.tpl", { name = "My repo" })
    }
    "docs/index.md" = {
      content = file("${path.module}/index.md")
    }
  }
}

Requirements

Name Version
terraform >= 1.9.0
github ~> 6.11

Providers

Name Version
github ~> 6.11

Modules

Name Source Version
environment ./modules/environment n/a

Resources

Name Type
github_actions_repository_access_level.actions_access_level resource
github_actions_secret.secrets resource
github_actions_variable.action_variables resource
github_app_installation_repository.default resource
github_branch.default resource
github_branch_default.default resource
github_branch_protection.default resource
github_dependabot_secret.encrypted resource
github_dependabot_secret.plaintext resource
github_repository.default resource
github_repository_autolink_reference.default resource
github_repository_custom_property.default resource
github_repository_dependabot_security_updates.default resource
github_repository_file.managed resource
github_repository_file.unmanaged resource
github_repository_ruleset.default resource
github_team_repository.default resource
github_workflow_repository_permissions.default resource
github_team.default data source

Inputs

Name Description Type Default Required
name The name of the repository string n/a yes
access An optional map with GitHub team names and their access level to the repository map(string) {} no
actions_access_level Control how this repository is used by GitHub Actions workflows in other repositories string null no
actions_secrets An optional map with GitHub action secrets map(string) {} no
actions_variables An optional map with GitHub Actions variables map(string) {} no
allow_auto_merge Enable allow auto-merging pull requests on the repository bool true no
allow_merge_commit Enable merge commits on the repository bool true no
allow_rebase_merge Enable rebase merges on the repository bool true no
allow_squash_merge Enable squash merges on the repository bool true no
allow_update_branch Enable to allow suggestions to update pull request branches bool true no
app_installation_ids Set of GitHub App installation IDs to associate with the repository set(string) [] no
archive_on_destroy Set to true to archive the repository instead of deleting on destroy bool false no
archived Specifies if the repository should be archived bool false no
auto_init Disable to not produce an initial commit in the repository bool true no
autolink_references Optional map with autolink reference key prefix and their corresponding URL templates
map(object({
is_alphanumeric = optional(bool, false)
url_template = string
}))
{} no
branches An optional map with GitHub branches to create
map(object({
source_branch = optional(string)
source_sha = optional(string)
use_branch_protection = optional(bool, true)

branch_protection = optional(object({
allows_force_pushes = optional(bool, false)
enforce_admins = optional(bool, false)
require_signed_commits = optional(bool, true)

required_checks = optional(object({
strict = optional(bool)
contexts = optional(list(string))
}))

restrict_pushes = optional(object({
blocks_creations = optional(bool)
push_allowances = optional(list(string))
}))

required_reviews = optional(object({
dismiss_stale_reviews = optional(bool, true)
dismissal_restrictions = optional(list(string))
pull_request_bypassers = optional(list(string))
require_code_owner_reviews = optional(bool, true)
require_last_push_approval = optional(bool, null)
required_approving_review_count = optional(number, 2)
}))
}), null)
}))
{} no
custom_properties An optional map of custom properties to set on the repository. The custom properties need to be defined on the org level beforehand to be used here.
map(object({
property_name = string
property_type = string
property_value = list(string)
}))
{} no
default_branch Name of the default branch for the GitHub repository string "main" no
default_branch_protection Default branch protection settings for managed branches
object({
allows_force_pushes = optional(bool, false)
enforce_admins = optional(bool, false)
require_signed_commits = optional(bool, true)

required_checks = optional(object({
strict = optional(bool)
contexts = optional(list(string))
}))

required_reviews = optional(object({
dismiss_stale_reviews = optional(bool, true)
dismissal_restrictions = optional(list(string))
pull_request_bypassers = optional(list(string))
require_code_owner_reviews = optional(bool, true)
require_last_push_approval = optional(bool, null)
required_approving_review_count = optional(number, 2)
}))

restrict_pushes = optional(object({
blocks_creations = optional(bool)
push_allowances = optional(list(string))
}))
})
{
"enforce_admins": false,
"require_signed_commits": true,
"required_reviews": {
"dismiss_stale_reviews": true,
"require_code_owner_reviews": true,
"required_approving_review_count": 2
}
}
no
delete_branch_on_merge Automatically delete head branch after a pull request is merged bool true no
dependabot_enabled Set to true to enable Dependabot alerts and security updates bool false no
dependabot_encrypted_secrets Map with encrypted Dependabot secrets map(string) {} no
dependabot_plaintext_secrets Map with plaintext Dependabot secrets map(string) {} no
description A description for the GitHub repository string null no
environments An optional map of GitHub environments to configure
map(object({
secrets = optional(map(string), {})
variables = optional(map(string), {})
wait_timer = optional(number, null)

deployment_policy = optional(object({
branch_patterns = optional(set(string), [])
tag_patterns = optional(set(string), [])
}))

reviewers = optional(object({
teams = optional(list(string)) # Use team names here
users = optional(list(string)) # Use user names here
}))
}))
{} no
gitignore_template The name of the template without the extension string null no
has_discussions To enable GitHub Discussions features on the repository bool false no
has_issues To enable GitHub Issues features on the repository bool false no
has_projects To enable GitHub Projects features on the repository bool false no
has_wiki To enable GitHub Wiki features on the repository bool false no
homepage_url URL of a page describing the project string null no
is_template To mark this repository as a template repository bool false no
license_template The name of the (case sensitive) license template to use string null no
merge_commit_message The default commit message for merge commits string "PR_BODY" no
merge_commit_title The default commit title for merge commits string "PR_TITLE" no
merge_strategy The merge strategy to use for pull requests string null no
pages The repository's GitHub Pages configuration.
object({
build_type = string
branch = optional(string)
cname = optional(string)
path = optional(string, "/")
})
null no
repository_files A map of GitHub repository files that should be created
map(object({
branch = optional(string)
commit_message = optional(string)
commit_prefix = optional(string)
content = string
managed = optional(bool, true)
overwrite_on_create = optional(bool, false)
skip_ci = optional(bool, false)
}))
{} no
source_repo The source repository to create this repository from in format owner/repo string null no
squash_merge_commit_message The default commit message for squash merges string "COMMIT_MESSAGES" no
squash_merge_commit_title The default commit title for squash merges string "PR_TITLE" no
tag_protection The repository tag protection pattern string null no
template_repository The settings of the template repostitory to use on creation
object({
owner = string
repository = string
})
null no
topics A list of topics to set on the repository list(string) [] no
visibility Set the GitHub repository as public, private or internal string "private" no
vulnerability_alerts Set to true to enable security alerts for vulnerable dependencies bool true no
workflow_permissions An optional object to configure GitHub Actions workflow permissions for the repository
object({
default_workflow_permissions = optional(string, null)
can_approve_pull_request_reviews = optional(bool, false)
})
null no

Outputs

Name Description
full_name The full 'organization/repository' name of the repository
name The name of the repository
repo_id The id of the repository

Licensing

100% Open Source and licensed under the Apache License Version 2.0. See LICENSE for full details.

Packages

 
 
 

Contributors