Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
0c9238b
docs: update organization_custom_properties documentation
mkushakov Feb 27, 2026
a0b4b95
feat(custom_property): add support for organization repository custom…
mkushakov Jun 14, 2026
bc12df1
chore(docs): mark organization custom properties as deprecated and up…
mkushakov Jun 14, 2026
0a60ab4
style: fix gofmt struct-field alignment in deprecated org custom prop…
mkushakov Aug 11, 2026
23d243b
refactor: align CRUD signatures with ARCHITECTURE.md and inline state…
mkushakov Aug 11, 2026
7ad83f8
test: randomize property names and parallelize acceptance tests
mkushakov Aug 11, 2026
5dd29f4
docs: align templates and examples with the repository_custom_propert…
mkushakov Aug 11, 2026
b004e5b
docs: track the new organization repository custom property in mainta…
mkushakov Aug 11, 2026
f674439
fix: support scalar and list default_value for all custom property types
mkushakov Aug 12, 2026
dcaf0b6
test: cover default_value round-trips, out-of-band deletion and updat…
mkushakov Aug 12, 2026
ea63aa1
docs: regenerate for list-shaped default_value and the timeouts block
mkushakov Aug 12, 2026
e98800e
refactor: move the custom property flatten helper to a domain util file
mkushakov Aug 12, 2026
6a978ba
docs: move the cross-reference note from the template into the example
mkushakov Aug 12, 2026
0c05a02
refactor: move the repository custom property value parser to the uti…
mkushakov Aug 13, 2026
468d8e8
fix: make custom property plan-time validation actually reject bad input
mkushakov Aug 13, 2026
255b43e
test: cover url defaults, delete-of-missing-property and the new vali…
mkushakov Aug 13, 2026
d4427c0
docs: drop the redundant per-resource templates and regenerate
mkushakov Aug 13, 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
2 changes: 2 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,13 +580,15 @@ The following resources are deprecated and will be removed in future versions:
| `github_project_card` | None (Classic Projects API removed) |
| `github_project_column` | None (Classic Projects API removed) |
| `github_repository_project` | None (Classic Projects API removed) |
| `github_organization_custom_properties` | `github_organization_repository_custom_property` |

### Deprecated Data Sources

| Deprecated Data Source | Replacement |
| ---------------------------------------------- | --------------------------------------------------- |
| `github_organization_custom_role` | `github_organization_repository_role` |
| `github_organization_security_managers` | `github_organization_role_teams` |
| `github_organization_custom_properties` | `github_organization_repository_custom_property` |
| `github_repository_deployment_branch_policies` | `github_repository_environment_deployment_policies` |

### Known Limitations
Expand Down
6 changes: 4 additions & 2 deletions RESOURCES.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@ The overall status of each resource or data source is captured in this document
| `github_membership` | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization` | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_app_installations` | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_custom_properties` | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_custom_properties` (🚫) | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_custom_role` (🚫) | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_external_identities` | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_ip_allow_list` | ⚠️ | ✅ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_members` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `github_organization_repositories` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `github_organization_repository_custom_property` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `github_organization_repository_role` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `github_organization_repository_roles` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `github_organization_role` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Expand Down Expand Up @@ -168,9 +169,10 @@ The overall status of each resource or data source is captured in this document
| `github_issue_labels` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_membership` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_block` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_custom_properties` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_custom_properties` (🚫) | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_custom_role` (🚫) | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_project` (🚫) | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_repository_custom_property` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `github_organization_repository_role` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_role` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
| `github_organization_role_team` | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ | ❓ |
Expand Down
2 changes: 2 additions & 0 deletions docs/data-sources/organization_custom_properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: |-

# github_organization_custom_properties (Data Source)

~> **Deprecated:** Use the singular [`github_organization_repository_custom_property`](organization_repository_custom_property) data source instead. This data source will be removed in a future major release.

Use this data source to retrieve information about a GitHub organization custom property.

## Example Usage
Expand Down
35 changes: 35 additions & 0 deletions docs/data-sources/organization_repository_custom_property.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
page_title: "github_organization_repository_custom_property (Data Source) - GitHub"
subcategory: ""
description: |-
Looks up a single GitHub organization custom property definition by name.
---

# github_organization_repository_custom_property (Data Source)

Looks up a single GitHub organization custom property definition by name.

## Example Usage

```terraform
data "github_organization_repository_custom_property" "environment" {
property_name = "environment"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `property_name` (String) Name of the custom property to look up.

### Read-Only

- `allowed_values` (List of String) Allowed values when `value_type` is `single_select` or `multi_select`.
- `default_value` (List of String) Default value applied to repositories that do not explicitly set the property. Holds multiple elements only when `value_type` is `multi_select`.
- `description` (String) Short description of the custom property.
- `id` (String) The ID of this resource.
- `required` (Boolean) Whether the custom property must be set on every repository.
- `value_type` (String) Type of the custom property.
- `values_editable_by` (String) Who can edit values of this property on repositories.
2 changes: 2 additions & 0 deletions docs/resources/organization_custom_properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: |-

# github_organization_custom_properties (Resource)

~> **Deprecated:** Use the singular [`github_organization_repository_custom_property`](organization_repository_custom_property) resource instead. This resource will be removed in a future major release.

This resource allows you to create and manage custom properties for a GitHub organization.

Custom properties enable you to add metadata to repositories within your organization. You can use custom properties to add context about repositories, such as who owns them, when they expire, or compliance requirements.
Expand Down
107 changes: 107 additions & 0 deletions docs/resources/organization_repository_custom_property.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
page_title: "github_organization_repository_custom_property (Resource) - GitHub"
subcategory: ""
description: |-
Manages a GitHub organization custom property definition. Custom properties defined here can later be assigned values on individual repositories.
---

# github_organization_repository_custom_property (Resource)

Manages a GitHub organization custom property definition. Custom properties defined here can later be assigned values on individual repositories.

## Example Usage

```terraform
# This resource defines the property itself at the organization level. To set a
# value for it on an individual repository, use `github_repository_custom_property`.
# See https://docs.github.com/rest/orgs/custom-properties for the underlying API.

# single_select property with a default value
resource "github_organization_repository_custom_property" "environment" {
property_name = "environment"
value_type = "single_select"
required = true
description = "The deployment environment for this repository"
default_value = ["development"]
allowed_values = [
"development",
"staging",
"production",
]
}

# string property that repository actors (not just org owners) can edit
resource "github_organization_repository_custom_property" "team_contact" {
property_name = "team_contact"
value_type = "string"
description = "Contact information for the team managing this repository"
values_editable_by = "org_and_repo_actors"
}

# true_false property
resource "github_organization_repository_custom_property" "archived" {
property_name = "archived"
value_type = "true_false"
description = "Whether this repository is archived"
default_value = ["false"]
}

# multi_select property; only this type accepts more than one default value
resource "github_organization_repository_custom_property" "compliance" {
property_name = "compliance"
value_type = "multi_select"
description = "Compliance regimes this repository is in scope for"
allowed_values = ["pci", "sox", "hipaa"]
default_value = ["pci", "sox"]
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `property_name` (String) Name of the custom property.
- `value_type` (String) Type of the custom property. One of: [string single_select multi_select true_false url].

### Optional

- `allowed_values` (List of String) Allowed values for `single_select` and `multi_select` property types. Must be omitted for other types.
- `default_value` (List of String) Default value applied to repositories that do not explicitly set the property. Exactly one element for the `string`, `single_select`, `true_false` and `url` types; one or more for `multi_select`. Once set, a default cannot be removed via the API, only changed.
- `description` (String) Short description of the custom property.
- `required` (Boolean) Whether the custom property must be set on every repository. GitHub may reject `required = true` unless a `default_value` is also provided.
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
- `values_editable_by` (String) Who can edit values of this property on repositories. One of: [org_actors org_and_repo_actors]. Defaults to `org_actors` server-side.

### Read-Only

- `id` (String) The ID of this resource.

<a id="nestedblock--timeouts"></a>
### Nested Schema for `timeouts`

Optional:

- `create` (String)
- `delete` (String)
- `read` (String)
- `update` (String)

## Import

Import is supported using the following syntax:

In Terraform v1.5.0 and later, the [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used with the `id` attribute, for example:

```terraform
import {
to = github_organization_repository_custom_property.environment
id = "environment"
}
```

The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:

```shell
terraform import github_organization_repository_custom_property.environment environment
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "github_organization_repository_custom_property" "environment" {
property_name = "environment"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {
to = github_organization_repository_custom_property.environment
id = "environment"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import github_organization_repository_custom_property.environment environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This resource defines the property itself at the organization level. To set a
# value for it on an individual repository, use `github_repository_custom_property`.
# See https://docs.github.com/rest/orgs/custom-properties for the underlying API.

# single_select property with a default value
resource "github_organization_repository_custom_property" "environment" {
property_name = "environment"
value_type = "single_select"
required = true
description = "The deployment environment for this repository"
default_value = ["development"]
allowed_values = [
"development",
"staging",
"production",
]
}

# string property that repository actors (not just org owners) can edit
resource "github_organization_repository_custom_property" "team_contact" {
property_name = "team_contact"
value_type = "string"
description = "Contact information for the team managing this repository"
values_editable_by = "org_and_repo_actors"
}

# true_false property
resource "github_organization_repository_custom_property" "archived" {
property_name = "archived"
value_type = "true_false"
description = "Whether this repository is archived"
default_value = ["false"]
}

# multi_select property; only this type accepts more than one default value
resource "github_organization_repository_custom_property" "compliance" {
property_name = "compliance"
value_type = "multi_select"
description = "Compliance regimes this repository is in scope for"
allowed_values = ["pci", "sox", "hipaa"]
default_value = ["pci", "sox"]
}
3 changes: 2 additions & 1 deletion github/data_source_github_organization_custom_properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import (

func dataSourceGithubOrganizationCustomProperties() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceGithubOrganizationCustomPropertiesRead,
DeprecationMessage: "This data source is deprecated and will be removed in a future release. Use github_organization_repository_custom_property (singular) instead.",
ReadContext: dataSourceGithubOrganizationCustomPropertiesRead,

Schema: map[string]*schema.Schema{
"property_name": {
Expand Down
121 changes: 121 additions & 0 deletions github/data_source_github_organization_repository_custom_property.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package github

import (
"context"
"errors"

"github.com/google/go-github/v89/github"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func dataSourceGithubOrganizationRepositoryCustomProperty() *schema.Resource {
return &schema.Resource{
Description: "Looks up a single GitHub organization custom property definition by name.",
ReadContext: dataSourceGithubOrganizationRepositoryCustomPropertyRead,

Schema: map[string]*schema.Schema{
"property_name": {
Type: schema.TypeString,
Required: true,
Description: "Name of the custom property to look up.",
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotEmpty),
},
"value_type": {
Type: schema.TypeString,
Computed: true,
Description: "Type of the custom property.",
},
"required": {
Type: schema.TypeBool,
Computed: true,
Description: "Whether the custom property must be set on every repository.",
},
"default_value": {
Type: schema.TypeList,
Computed: true,
Description: "Default value applied to repositories that do not explicitly set the property. Holds multiple elements only when `value_type` is `multi_select`.",
Elem: &schema.Schema{Type: schema.TypeString},
},
Comment thread
deiga marked this conversation as resolved.
"description": {
Type: schema.TypeString,
Computed: true,
Description: "Short description of the custom property.",
},
"allowed_values": {
Type: schema.TypeList,
Computed: true,
Description: "Allowed values when `value_type` is `single_select` or `multi_select`.",
Elem: &schema.Schema{Type: schema.TypeString},
},
"values_editable_by": {
Type: schema.TypeString,
Computed: true,
Description: "Who can edit values of this property on repositories.",
},
},
}
}

func dataSourceGithubOrganizationRepositoryCustomPropertyRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
meta, _ := m.(*Owner)
if ok, diags := checkOrganizationOK(meta); !ok {
return diags
}

client := meta.v3client
owner := meta.name
propertyName := d.Get("property_name").(string)

Check failure on line 70 in github/data_source_github_organization_repository_custom_property.go

View workflow job for this annotation

GitHub Actions / Strict linting of new code

type assertion must be checked (forcetypeassert)

tflog.Debug(ctx, "Reading organization custom property", map[string]any{"org": owner, "property": propertyName})

cp, _, err := client.Organizations.GetCustomProperty(ctx, owner, propertyName)
if err != nil {
if ghErr, ok := errors.AsType[*github.ErrorResponse](err); ok && ghErr.Response.StatusCode == 404 {
return diag.Errorf("organization custom property %q not found in %q", propertyName, owner)
}
return diag.Errorf("error reading organization custom property %q: %v", propertyName, err)
}

if cp.GetPropertyName() == "" {
return diag.Errorf("organization %q returned a custom property with an empty name when reading %q", owner, propertyName)
}

switch cp.ValueType {
case github.PropertyValueTypeSingleSelect, github.PropertyValueTypeMultiSelect:
default:
cp.AllowedValues = nil
}

defaultValue, err := flattenOrganizationRepositoryCustomPropertyDefaultValue(cp)
if err != nil {
return diag.Errorf("error reading organization custom property %q: %v", propertyName, err)
}

d.SetId(cp.GetPropertyName())
if err := d.Set("property_name", cp.GetPropertyName()); err != nil {
return diag.FromErr(err)
}
if err := d.Set("value_type", string(cp.ValueType)); err != nil {
return diag.FromErr(err)
}
if err := d.Set("required", cp.GetRequired()); err != nil {
return diag.FromErr(err)
}
if err := d.Set("default_value", defaultValue); err != nil {
return diag.FromErr(err)
}
if err := d.Set("description", cp.GetDescription()); err != nil {
return diag.FromErr(err)
}
if err := d.Set("allowed_values", cp.AllowedValues); err != nil {
return diag.FromErr(err)
}
if err := d.Set("values_editable_by", cp.GetValuesEditableBy()); err != nil {
return diag.FromErr(err)
}

return nil
}
Loading
Loading