Skip to content
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
648bf41
feat: add new gh-files-set module
Mar 8, 2026
900aa51
WIP
Mar 8, 2026
0be8dbf
Fix
Mar 8, 2026
44ad6b2
WIP
Mar 8, 2026
35b7c2c
WIP
Mar 8, 2026
5aae430
WIP
Mar 8, 2026
51827d8
Add untrackable files
Mar 8, 2026
6fb689e
WIP
Mar 8, 2026
f046d0e
WIP
Mar 8, 2026
48c6e67
WIP
Mar 8, 2026
82d09b0
Add the files
Mar 8, 2026
e5d36cd
add untrack machinery
Mar 8, 2026
57b46d1
ADd
Mar 8, 2026
b1d49ee
ADd
Mar 8, 2026
70e31e0
Add
Mar 9, 2026
05c77f9
WIP
Mar 9, 2026
40a8360
WIP
Mar 9, 2026
a10780f
Fix
Mar 10, 2026
f1d8e98
Remove unnessary module
Mar 10, 2026
75c7937
Remove unnecesary module
Mar 10, 2026
fd9e16f
Merge branch 'main' into feat/969-poc-gh-files-set
frmadem Mar 17, 2026
7869fdc
Merge branch 'main' into feat/969-poc-gh-files-set
alambike Mar 20, 2026
5a88544
Make the system available only for one repo
Mar 20, 2026
7cb469e
Merge branch 'feat/969-poc-gh-files-set' of https://github.com/prefap…
Mar 20, 2026
2c09af2
Fix version
Mar 20, 2026
9aae9fb
Add
Mar 20, 2026
69b2c5f
Potential fix for pull request finding
frmadem Mar 20, 2026
258f05e
Fix docu
Mar 20, 2026
f760419
Merge branch 'feat/969-poc-gh-files-set' of https://github.com/prefap…
Mar 20, 2026
6ca12b3
Fix
Mar 20, 2026
d63731b
Fix
Mar 21, 2026
1b96a9e
Fix outputs
Mar 21, 2026
765e734
Update modules/gh-files-set/docs/header.md
frmadem Mar 21, 2026
82b89c3
improve docs
Mar 21, 2026
b62f590
Fix version
Mar 21, 2026
28bb910
Update readme
Mar 21, 2026
7220434
Update modules/gh-files-set/outputs.tf
frmadem Mar 21, 2026
e3fc0b5
Add validation
Mar 21, 2026
9266463
Update modules/gh-files-set/variables.tf
frmadem Mar 21, 2026
7cd8c44
Update modules/gh-files-set/variables.tf
frmadem Mar 21, 2026
e1377f6
Update modules/gh-files-set/variables.tf
frmadem Mar 21, 2026
6822db9
Update readme
Mar 21, 2026
65d3f92
Merge branch 'feat/969-poc-gh-files-set' of https://github.com/prefap…
Mar 21, 2026
a1fcb45
Update modules/gh-files-set/main.tf
frmadem Mar 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions modules/gh-files-set/.terraform-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
formatter: "markdown"

version: ""

header-from: docs/header.md
footer-from: docs/footer.md

recursive:
enabled: false
path: modules
include-main: true

sections:
hide: []
show: []

content: ""

output:
file: "README.md"
mode: inject
template: |-
<!-- BEGIN_TF_DOCS -->
{{ .Content }}
<!-- END_TF_DOCS -->

output-values:
enabled: false
from: ""

sort:
enabled: true
by: name

settings:
anchor: true
color: true
default: true
description: false
escape: true
hide-empty: false
html: true
indent: 2
lockfile: true
read-comments: true
required: true
sensitive: true
type: true
82 changes: 82 additions & 0 deletions modules/gh-files-set/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!-- BEGIN_TF_DOCS -->
# **GitHub Files Set Terraform Module**

## Overview

This module creates or updates one or more files in GitHub repositories using the `github_repository_file` resource.
It is designed to be used in automated repository bootstrapping / golden-path workflows.

It accepts a list of files in a single `config` object — ideal for YAML/JSON input from external tools.

## Key Features

- Multiple files in one module call
- Per-file branch, commit message, overwrite control
- Native GitHub provider integration
- Input validation on required fields
- Clean outputs for downstream usage

## Basic Usage

```hcl
module "files" {
source = "git::https://github.com/prefapp/tfm.git//modules/gh-files-set"

config = yamldecode(file("${path.module}/files.yaml"))
# or jsondecode(...) if using JSON
}
```

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_github"></a> [github](#requirement\_github) | ~> 6.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_github"></a> [github](#provider\_github) | ~> 6.0 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [github_repository_file.managed](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_file) | resource |
| [github_repository_file.user_managed](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_file) | resource |
| [github_repository.this](https://registry.terraform.io/providers/integrations/github/latest/docs/data-sources/repository) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_config"></a> [config](#input\_config) | GitHub files configuration — userManaged files are provisioned once and survive destroy | <pre>object({<br/> files = list(object({<br/> branch = string<br/> commitMessage = string<br/> content = string<br/> file = string<br/> repository = string<br/> overwriteOnCreate = optional(bool, true)<br/> userManaged = optional(bool, false)<br/> }))<br/><br/> repository = string<br/> })</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_user_managed_files"></a> [user\_managed\_files](#output\_user\_managed\_files) | Files marked as userManaged (will survive destroy) |

### 5. `docs/footer.md`

```markdown
## Examples

See [_examples/basic](https://github.com/prefapp/tfm/tree/main/modules/gh-files-set/_examples/basic)

## Resources

- **github_repository_file**
https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_file

## Support

Open issues in https://github.com/prefapp/tfm/issues
```
<!-- END_TF_DOCS -->
12 changes: 12 additions & 0 deletions modules/gh-files-set/_examples/basic/files.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
config:
repository: org/component_c
files:
- branch: main
commitMessage: "feat: hello-world-ee87ccfc-5d0a-4ad0-b9ee-4c142f40e00b main"
content: |
# Hello World!

From my-org/
file: hello.md
overwriteOnCreate: true
lifecycle: {} # optional / placeholder
12 changes: 12 additions & 0 deletions modules/gh-files-set/docs/footer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Examples

See [_examples/basic](https://github.com/prefapp/tfm/tree/main/modules/gh-files-set/_examples/basic)

## Resources

- **github_repository_file**
https://registry.terraform.io/providers/integrations/github/latest/docs/resources/repository_file

## Support

Open issues in https://github.com/prefapp/tfm/issues
27 changes: 27 additions & 0 deletions modules/gh-files-set/docs/header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# **GitHub Files Set Terraform Module**

## Overview

This module creates or updates one or more files in GitHub repositories using the `github_repository_file` resource.
It is designed to be used in automated repository bootstrapping / golden-path workflows.

It accepts a list of files in a single `config` object — ideal for YAML/JSON input from external tools.

## Key Features

- Multiple files in one module call
- Per-file branch, commit message, overwrite control
- Native GitHub provider integration
- Input validation on required fields
- Clean outputs for downstream usage

## Basic Usage

```hcl
module "files" {
source = "git::https://github.com/prefapp/tfm.git//modules/gh-files-set"

config = yamldecode(file("${path.module}/files.yaml"))
# or jsondecode(...) if using JSON
}
```
40 changes: 40 additions & 0 deletions modules/gh-files-set/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# ─────────────────────────────────────────────────────────────
# Fetch repository info (validates existence + gives canonical name)
# ─────────────────────────────────────────────────────────────
data "github_repository" "this" {
full_name = var.config.repository
}

# Normal files — Terraform fully enforces content
resource "github_repository_file" "managed" {
for_each = {
for f in var.config.files : "${f.repository}/${f.file}/${f.branch}" => f
if !f.userManaged
}

repository = data.github_repository.this.name
branch = each.value.branch
file = each.value.file
content = each.value.content
commit_message = each.value.commitMessage
overwrite_on_create = each.value.overwriteOnCreate
}

# User-managed files — provision once + ignore content drift
resource "github_repository_file" "user_managed" {
for_each = {
for f in var.config.files : "${f.repository}/${f.file}/${f.branch}" => f
if f.userManaged
}
Comment on lines +23 to +28
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says “provision once” for user_managed, but this resource will still be updated whenever non-ignored arguments change (e.g., commitMessage, overwriteOnCreate) and it will be deleted on destroy. Either align the comment/docs with the actual behavior, or expand the lifecycle settings/design to truly match “provision once / survive destroy”.

Copilot uses AI. Check for mistakes.

repository = data.github_repository.this.name
branch = each.value.branch
file = each.value.file
content = each.value.content
commit_message = each.value.commitMessage
overwrite_on_create = each.value.overwriteOnCreate

lifecycle {
ignore_changes = [content]
}
Comment on lines +23 to +39
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “user-managed files — provision once + ignore content drift” behavior isn’t achieved by ignore_changes = [content]: these resources will still be destroyed on terraform destroy, and changes to other arguments (e.g., commit_message, branch, file) will still drive updates/replacements. If the intent is only to ignore content drift, update the comment/docs accordingly; if the intent is to keep files on destroy/provision-once semantics, the implementation needs to change (and likely can’t be fully achieved with github_repository_file alone without impacting destroy behavior).

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot how we could avoid user-managed files to be destroyed on terraform destroy, but without blocking the destroy process, that is, the terraform state should be destroyed without altering the file's contents, please implement it if you see a solution.

}
4 changes: 4 additions & 0 deletions modules/gh-files-set/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "user_managed_files" {
description = "Files marked as userManaged (will survive destroy)"
value = [for f in var.config.files : "${f.repository}/${f.file}" if f.userManaged]
}
37 changes: 37 additions & 0 deletions modules/gh-files-set/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
variable "config" {
description = "GitHub files configuration — userManaged files are provisioned once and survive destroy"
type = object({
files = list(object({
branch = string
commitMessage = string
content = string
file = string
repository = string
overwriteOnCreate = optional(bool, true)
userManaged = optional(bool, false)
}))

repository = string
})

validation {
condition = length(var.config.files) > 0
error_message = "At least one file must be defined in config.files"
}

validation {
condition = can(regex("^[a-zA-Z0-9_-]+/[a-zA-Z0-9_.-]+$", var.config.repository))
error_message = "config.repository must be in 'owner/repo' format."
}

validation {
condition = alltrue([
for f in var.config.files :
length(trimspace(f.branch)) > 0 &&
length(trimspace(f.commitMessage)) > 0 &&
length(trimspace(f.file)) > 0 &&
length(trimspace(f.repository)) > 0
])
error_message = "Every file must have non-empty branch, commitMessage, file path, and repository."
}
}
9 changes: 9 additions & 0 deletions modules/gh-files-set/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_providers {
github = {
source = "integrations/github"
version = "~> 6.0"
}
}
}

3 changes: 3 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@
"modules/aws-secretsmanager-replication": {
"package-name": "aws-secretsmanager-replication"
},
"modules/gh-files-set": {
"package-name": "gh-files-set"
},
"modules/azure-vnet-gateway": {
"package-name": "azure-vnet-gateway"
},
Expand Down
Loading