Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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-membership/.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
106 changes: 106 additions & 0 deletions modules/gh-membership/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<!-- BEGIN_TF_DOCS -->
# **GitHub Membership Terraform Module**

## Overview

This module manages GitHub organization-level membership (admin/member) and team memberships using a single strongly-typed `config` object.

It is designed for Prefapp’s Internal Developer Platform and automated user/team provisioning pipelines. The module accepts input directly from external programs via JSON.

## Key Features

- **Organization role**: Assign `member` or `admin` at organization level
- **Team relationships**: Add users to teams with `member` or `maintainer` roles
- **Single config object**: Everything in one `config` variable
- **Full validation**: Role enforcement and required fields
- **JSON-native**: Perfect for programmatic generation

## Basic Usage

### Using `terraform.tfvars.json` (recommended)

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

config = var.config
}

#### Inline example
```hcl
module "membership" {
source = "git::https://github.com/prefapp/tfm.git//modules/gh-membership"

Comment on lines +22 to +33
config = {
user = {
username = "johndoe"
role = "admin"
}
relationships = [
{
username = "johndoe"
teamId = "foo-all"
role = "member"
}
]
}
}
```
```

## 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_membership.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership) | resource |
| [github_team_membership.relationships](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_membership) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_config"></a> [config](#input\_config) | GitHub membership configuration (organization role + team relationships) | <pre>object({<br/> relationships = optional(list(object({<br/> username = string<br/> teamId = string # team slug (e.g. "jvazquez-prefapp-all")<br/> role = optional(string, "member") # member | maintainer<br/> })), [])<br/><br/> user = optional(object({<br/> username = string<br/> role = optional(string, "member") # member | admin<br/> }))<br/> })</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_organization_membership"></a> [organization\_membership](#output\_organization\_membership) | Organization-level membership |
| <a name="output_team_memberships"></a> [team\_memberships](#output\_team\_memberships) | Team memberships created |
| <a name="output_user"></a> [user](#output\_user) | User details |

### 3. `docs/footer.md`
```markdown
## Examples

For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/gh-membership/_examples):

- [basic](https://github.com/prefapp/tfm/tree/main/modules/gh-membership/_examples/basic) - Organization membership + team relationship

## Resources

- **github_membership**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership)
- **github_team_membership**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_membership)
- **GitHub Terraform Provider**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs)

## Support

For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues).
```
<!-- END_TF_DOCS -->
15 changes: 15 additions & 0 deletions modules/gh-membership/_examples/basic/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"config": {
"relationships": [
{
"username": "johndoe",
"teamId": "foo-all",
"role": "member"
}
],
"user": {
"username": "johndoe",
"role": "admin"
}
}
}
22 changes: 22 additions & 0 deletions modules/gh-membership/_examples/basic/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
terraform {
required_providers {
github = {
source = "integrations/github"
version = "~> 6.0"
}
}
}

module "membership" {
source = "../../"

config = jsondecode(file("${path.module}/config.json")).config
}

output "user_managed" {
value = module.membership.organization_membership
}

output "team_memberships" {
value = module.membership.team_memberships
}
20 changes: 20 additions & 0 deletions modules/gh-membership/docs/footer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

### 3. `docs/footer.md`
```markdown
## Examples
Comment on lines +2 to +4

For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/gh-membership/_examples):

- [basic](https://github.com/prefapp/tfm/tree/main/modules/gh-membership/_examples/basic) - Organization membership + team relationship

## Resources

- **github_membership**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/membership)
- **github_team_membership**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_membership)
- **GitHub Terraform Provider**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs)

## Support

For issues, questions, or contributions related to this module, please visit the [repository's issue tracker](https://github.com/prefapp/tfm/issues).
```

47 changes: 47 additions & 0 deletions modules/gh-membership/docs/header.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# **GitHub Membership Terraform Module**

## Overview

This module manages GitHub organization-level membership (admin/member) and team memberships using a single strongly-typed `config` object.

It is designed for Prefapp’s Internal Developer Platform and automated user/team provisioning pipelines. The module accepts input directly from external programs via JSON.

## Key Features

- **Organization role**: Assign `member` or `admin` at organization level
- **Team relationships**: Add users to teams with `member` or `maintainer` roles
- **Single config object**: Everything in one `config` variable
- **Full validation**: Role enforcement and required fields
- **JSON-native**: Perfect for programmatic generation

## Basic Usage

### Using `terraform.tfvars.json` (recommended)

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

config = var.config
}

#### Inline example
```hcl
module "membership" {
Comment on lines +21 to +30
source = "git::https://github.com/prefapp/tfm.git//modules/gh-membership"

config = {
user = {
username = "johndoe"
role = "admin"
}
relationships = [
{
username = "johndoe"
teamId = "foo-all"
role = "member"
}
]
}
}
```
18 changes: 18 additions & 0 deletions modules/gh-membership/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Organization membership (admin / member)
resource "github_membership" "this" {
count = var.config.user != null ? 1 : 0

username = var.config.user.username
role = var.config.user.role
}

# Team memberships
resource "github_team_membership" "relationships" {
for_each = {
for r in var.config.relationships : "${r.username}-${r.teamId}" => r
}

team_id = each.value.teamId # accepts slug directly
username = each.value.username
role = each.value.role
}
Comment on lines +10 to +18
Copy link
Contributor

Choose a reason for hiding this comment

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

Also included in gh-team module?
#953

23 changes: 23 additions & 0 deletions modules/gh-membership/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
output "organization_membership" {
description = "Organization-level membership"
value = var.config.user != null ? {
username = github_membership.this[0].username
role = github_membership.this[0].role
} : null
}

output "team_memberships" {
description = "Team memberships created"
value = [
for r in var.config.relationships : {
username = r.username
teamId = r.teamId
role = r.role
}
]
}

output "user" {
description = "User details"
value = var.config.user
}
27 changes: 27 additions & 0 deletions modules/gh-membership/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
variable "config" {
description = "GitHub membership configuration (organization role + team relationships)"
type = object({
relationships = optional(list(object({
username = string
teamId = string # team slug (e.g. "jvazquez-prefapp-all")
role = optional(string, "member") # member | maintainer
Comment on lines +5 to +7
})), [])

user = optional(object({
username = string
role = optional(string, "member") # member | admin
}))
})

validation {
condition = alltrue([
for r in var.config.relationships : contains(["member", "maintainer"], r.role)
])
error_message = "relationship.role must be 'member' or 'maintainer'."
}

validation {
condition = var.config.user == null || contains(["member", "admin"], var.config.user.role)
error_message = "user.role must be 'member' or 'admin'."
}
}
9 changes: 9 additions & 0 deletions modules/gh-membership/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,5 +151,8 @@
"modules/aws-secretsmanager-replication": {
"package-name": "aws-secretsmanager-replication"
}
"modules/gh-membership": {
"package-name": "gh-membership"
}
}
}
Loading