diff --git a/README.md b/README.md deleted file mode 100644 index ae019cfd4..000000000 --- a/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# ๐ Release Please Versioning Management - -Check action doc https://github.com/googleapis/release-please-action - -This repo is managed by Release Please. This is an automated Semver control System. - -## How release please works - -Release Please automates CHANGELOG generation, the creation of GitHub releases, -and version bumps for your projects. Release Please does so by parsing your -git history, looking for [Conventional Commit messages](https://www.conventionalcommits.org/), -and creating release PRs. - -### How should I write my commits? - -Release Please assumes you are using [Conventional Commit messages](https://www.conventionalcommits.org/). - -The most important prefixes you should have in mind are: - -* `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/) - patch. -* `feat:` which represents a new feature, and correlates to a SemVer minor. -* `feat!:`, or `fix!:`, `refactor!:`, etc., which represent a breaking change - (indicated by the `!`) and will result in a SemVer major. - -### What's a Release PR? - -Rather than continuously releasing what's landed to your default branch, -release-please maintains Release PRs: - -These Release PRs are kept up-to-date as additional work is merged. When you're -ready to tag a release, simply merge the release PR. - -### Troubleshooting - -If you merge accidentaly a conventional commit, you can move the commits starting analysis to another commit following this guide https://github.com/googleapis/release-please/blob/288949797c6bfd95e08d74a6222e7d26e0020a7c/docs/manifest-releaser.md?plain=1#L140-L153 diff --git a/modules/gh-team/.terraform-docs.yml b/modules/gh-team/.terraform-docs.yml new file mode 100644 index 000000000..3a69365ff --- /dev/null +++ b/modules/gh-team/.terraform-docs.yml @@ -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: |- + + {{ .Content }} + + +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 diff --git a/modules/gh-team/CHANGELOG.md b/modules/gh-team/CHANGELOG.md new file mode 100644 index 000000000..5d33d5ceb --- /dev/null +++ b/modules/gh-team/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## 0.1.0 (2026-02-27) + +### Features + diff --git a/modules/gh-team/README.md b/modules/gh-team/README.md new file mode 100644 index 000000000..7057c700f --- /dev/null +++ b/modules/gh-team/README.md @@ -0,0 +1,89 @@ + +# **GitHub Team Terraform Module** + +## Overview + +This module provisions a single GitHub Team and automatically manages its members using a single strongly-typed `config` object. +It supports nested teams (`parentTeamId`), privacy settings (`closed`/`secret`), and manages all members with the standard `member` role while keeping the external interface minimal and JSON-friendly. + +The module is designed for Prefappโs Internal Developer Platform and automated team provisioning pipelines. It accepts input directly from external programs (Python, Node.js, Go, etc.) via JSON, ensuring full Terraform validation and type safety. + +## Key Features + +- **Single complex object**: All configuration lives in one `config` variable โ perfect for programmatic generation. +- **Full validation**: Enforces name, privacy, username format, and required fields at plan time. +- **Nested team support**: Automatic `parent_team_id` handling. +- **JSON-native**: Feed `jsondecode(file("team-config.json"))` directly. +- **Clean outputs**: Every value is exposed as a separate output for easy consumption in larger pipelines. +- **GitHub Provider v6+**: Uses the latest official `integrations/github` provider. + +## Basic Usage + +### Minimal team with members + +```hcl +module "my_team" { + source = "git::https://github.com/prefapp/tfm.git//modules/gh-team" + + config = jsondecode(file("${path.root}/team-config.json")) +} +``` + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.7.0 | +| [github](#requirement\_github) | ~> 6.0 | + +## Providers + +| Name | Version | +|------|---------| +| [github](#provider\_github) | ~> 6.0 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [github_team.this](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team) | resource | +| [github_team_membership.members](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team_membership) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [config](#input\_config) | GitHub team configuration as a single complex object |
object({
group = object({
name = string
description = optional(string, "")
privacy = optional(string, "closed")
parentTeamId = optional(number, null) # null or team ID (number)
})
group_members = optional(list(object({
username = string
teamId = optional(string) # kept for compatibility, ignored during creation
})), [])
}) | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [team\_description](#output\_team\_description) | Description of the created GitHub team |
+| [team\_id](#output\_team\_id) | ID of the created GitHub team |
+| [team\_members](#output\_team\_members) | List of usernames added to the team |
+| [team\_name](#output\_team\_name) | Name of the created GitHub team |
+| [team\_parent\_id](#output\_team\_parent\_id) | Parent team ID (null if none) |
+| [team\_privacy](#output\_team\_privacy) | Privacy setting of the team (closed/secret) |
+| [team\_slug](#output\_team\_slug) | Slug of the created GitHub team |
+
+## Examples
+
+For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/github-team/_examples):
+
+- [basic](https://github.com/prefapp/tfm/tree/main/modules/github-team/_examples/basic) - Minimal team creation with JSON input
+
+## Resources
+
+- **github\_team**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team)
+- **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).
+
diff --git a/modules/gh-team/_examples/basic/config.json b/modules/gh-team/_examples/basic/config.json
new file mode 100644
index 000000000..e238015c6
--- /dev/null
+++ b/modules/gh-team/_examples/basic/config.json
@@ -0,0 +1,11 @@
+{
+ "group": {
+ "name": "็งใฎใใผใ ",
+ "description": "Prefapp all description",
+ "privacy": "closed",
+ "parentTeamId": null
+ },
+ "group_members": [
+ { "username": "frmadem-user", "teamId": "16210762" }
+ ]
+}
diff --git a/modules/gh-team/_examples/basic/main.tf b/modules/gh-team/_examples/basic/main.tf
new file mode 100644
index 000000000..e110e4174
--- /dev/null
+++ b/modules/gh-team/_examples/basic/main.tf
@@ -0,0 +1,18 @@
+terraform {
+ required_providers {
+ github = {
+ source = "integrations/github"
+ version = "~> 6.0"
+ }
+ }
+}
+
+module "example_team" {
+ source = "../../" # points to the module root
+
+ config = jsondecode(file("${path.module}/config.json"))
+}
+
+output "team_id" {
+ value = module.example_team.team_id
+}
diff --git a/modules/gh-team/docs/footer.md b/modules/gh-team/docs/footer.md
new file mode 100644
index 000000000..dba4e83f5
--- /dev/null
+++ b/modules/gh-team/docs/footer.md
@@ -0,0 +1,17 @@
+
+## Examples
+
+For detailed examples, refer to the [module examples](https://github.com/prefapp/tfm/tree/main/modules/github-team/_examples):
+
+- [basic](https://github.com/prefapp/tfm/tree/main/modules/github-team/_examples/basic) - Minimal team creation with JSON input
+
+## Resources
+
+- **github_team**: [Official Documentation](https://registry.terraform.io/providers/integrations/github/latest/docs/resources/team)
+- **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).
+
diff --git a/modules/gh-team/docs/header.md b/modules/gh-team/docs/header.md
new file mode 100644
index 000000000..0e45e945f
--- /dev/null
+++ b/modules/gh-team/docs/header.md
@@ -0,0 +1,29 @@
+# **GitHub Team Terraform Module**
+
+## Overview
+
+This module provisions a single GitHub Team and automatically manages its members using a single strongly-typed `config` object.
+It supports nested teams (`parentTeamId`), privacy settings (`closed`/`secret`), and manages all members with the standard `member` role while keeping the external interface minimal and JSON-friendly.
+
+The module is designed for Prefappโs Internal Developer Platform and automated team provisioning pipelines. It accepts input directly from external programs (Python, Node.js, Go, etc.) via JSON, ensuring full Terraform validation and type safety.
+
+## Key Features
+
+- **Single complex object**: All configuration lives in one `config` variable โ perfect for programmatic generation.
+- **Full validation**: Enforces name, privacy, username format, and required fields at plan time.
+- **Nested team support**: Automatic `parent_team_id` handling.
+- **JSON-native**: Feed `jsondecode(file("team-config.json"))` directly.
+- **Clean outputs**: Every value is exposed as a separate output for easy consumption in larger pipelines.
+- **GitHub Provider v6+**: Uses the latest official `integrations/github` provider.
+
+## Basic Usage
+
+### Minimal team with members
+
+```hcl
+module "my_team" {
+ source = "git::https://github.com/prefapp/tfm.git//modules/gh-team"
+
+ config = jsondecode(file("${path.root}/team-config.json"))
+}
+```
diff --git a/modules/gh-team/main.tf b/modules/gh-team/main.tf
new file mode 100644
index 000000000..0cdcbd2d6
--- /dev/null
+++ b/modules/gh-team/main.tf
@@ -0,0 +1,18 @@
+# Create the GitHub Team
+resource "github_team" "this" {
+ name = var.config.group.name
+ description = var.config.group.description
+ privacy = var.config.group.privacy
+ parent_team_id = var.config.group.parentTeamId
+}
+
+# Add team memberships
+resource "github_team_membership" "members" {
+ for_each = {
+ for m in var.config.group_members : m.username => m
+ }
+
+ team_id = github_team.this.id
+ username = each.value.username
+ role = "member"
+}
diff --git a/modules/gh-team/outputs.tf b/modules/gh-team/outputs.tf
new file mode 100644
index 000000000..896f01028
--- /dev/null
+++ b/modules/gh-team/outputs.tf
@@ -0,0 +1,36 @@
+# Outputs section
+
+output "team_id" {
+ description = "ID of the created GitHub team"
+ value = github_team.this.id
+}
+
+output "team_slug" {
+ description = "Slug of the created GitHub team"
+ value = github_team.this.slug
+}
+
+output "team_name" {
+ description = "Name of the created GitHub team"
+ value = github_team.this.name
+}
+
+output "team_description" {
+ description = "Description of the created GitHub team"
+ value = github_team.this.description
+}
+
+output "team_privacy" {
+ description = "Privacy setting of the team (closed/secret)"
+ value = github_team.this.privacy
+}
+
+output "team_members" {
+ description = "List of usernames added to the team"
+ value = [for m in var.config.group_members : m.username]
+}
+
+output "team_parent_id" {
+ description = "Parent team ID (null if none)"
+ value = github_team.this.parent_team_id
+}
diff --git a/modules/gh-team/variables.tf b/modules/gh-team/variables.tf
new file mode 100644
index 000000000..01a2ad42e
--- /dev/null
+++ b/modules/gh-team/variables.tf
@@ -0,0 +1,34 @@
+variable "config" {
+ description = "GitHub team configuration as a single complex object"
+ type = object({
+ group = object({
+ name = string
+ description = optional(string, "")
+ privacy = optional(string, "closed")
+ parentTeamId = optional(number, null) # null or team ID (number)
+ })
+
+ group_members = optional(list(object({
+ username = string
+ teamId = optional(string) # kept for compatibility, ignored during creation
+ })), [])
+ })
+
+ # โโโ Validations โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ validation {
+ condition = contains(["closed", "secret"], var.config.group.privacy)
+ error_message = "group.privacy must be 'closed' or 'secret'."
+ }
+
+ validation {
+ condition = length(trimspace(var.config.group.name)) > 0
+ error_message = "group.name cannot be empty."
+ }
+
+ validation {
+ condition = alltrue([
+ for m in var.config.group_members : length(trimspace(m.username)) > 0
+ ])
+ error_message = "Every member in group_members must have a non-empty username."
+ }
+}
diff --git a/modules/gh-team/versions.tf b/modules/gh-team/versions.tf
new file mode 100644
index 000000000..f47edaf42
--- /dev/null
+++ b/modules/gh-team/versions.tf
@@ -0,0 +1,12 @@
+terraform {
+
+ required_version = ">= 1.7.0"
+
+ required_providers {
+ github = {
+ source = "integrations/github"
+ version = "~> 6.0"
+ }
+ }
+}
+
diff --git a/release-please-config.json b/release-please-config.json
index 1791e861c..afeca0cac 100644
--- a/release-please-config.json
+++ b/release-please-config.json
@@ -151,6 +151,9 @@
"modules/aws-secretsmanager-replication": {
"package-name": "aws-secretsmanager-replication"
},
+ "modules/gh-team": {
+ "package-name": "gh-team"
+ },
"modules/azure-vnet-gateway": {
"package-name": "azure-vnet-gateway"
},