Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: support repository_custom_properties resource and datasource #2316

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a7e562c
add octokit sdk client
felixlut Jul 12, 2024
af0245a
stash half working solution
felixlut Jul 12, 2024
cdd112a
add repository custom properties data source
felixlut Jul 13, 2024
f9633fb
break out custom props parsing logic to its own function
felixlut Jul 13, 2024
5e0894d
use background ctx
felixlut Jul 14, 2024
2accb56
format provider.go
felixlut Jul 14, 2024
b3f44ca
fix error msg to include repoName instead of its pointer
felixlut Jul 15, 2024
98947a3
use type switch instead of if else
felixlut Jul 15, 2024
2125cab
fix linting errors
felixlut Jul 15, 2024
ec2755e
restructure datasource to take a property name and call it github_rep…
felixlut Jul 16, 2024
1e88e7a
formatting
felixlut Jul 16, 2024
31f9a2b
rename file to match datasource name
felixlut Jul 16, 2024
5ed47ba
Merge branch 'main' into repository-custom-properties
felixlut Jul 31, 2024
697c43c
remove go-sdk in favor of go-github
felixlut Oct 5, 2024
9933170
implement data_source_github_repository_custom_property with go-github
felixlut Oct 5, 2024
a7aefae
implement resource_github_repository_custom_property
felixlut Oct 5, 2024
ce87c42
update descriptions
felixlut Oct 5, 2024
6b76479
remove custom_property resource in favour of custom_propertIES one
felixlut Oct 9, 2024
d9ad9a9
add custom_property resource to provider.go
felixlut Oct 9, 2024
7982a1a
formatting
felixlut Oct 9, 2024
7366a88
add tests for repository_custom_property
felixlut Oct 9, 2024
fe5add1
update description of test
felixlut Oct 9, 2024
0dbd149
add tests for each custom_property type
felixlut Oct 9, 2024
d9f13fd
rollback repo changes
felixlut Oct 9, 2024
7615100
add tests for custom_property datasource
felixlut Oct 9, 2024
c72ce22
formatting
felixlut Oct 9, 2024
bc93a88
Merge branch 'main' into repository-custom-properties
felixlut Oct 9, 2024
d298e07
breakout parsing custom_property_value as a string slice to its own f…
felixlut Oct 9, 2024
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
103 changes: 103 additions & 0 deletions github/data_source_github_repository_custom_properties.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package github

import (
"context"
"fmt"

"github.com/google/go-github/v65/github"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceGithubRepositoryCustomProperties() *schema.Resource {
return &schema.Resource{
Read: dataSourceGithubOrgaRepositoryCustomProperties,

Schema: map[string]*schema.Schema{
"repository": {
Type: schema.TypeString,
Required: true,
Description: "Name of the repository which the custom properties should be on.",
},
"property": {
Type: schema.TypeSet,
Computed: true,
Description: "List of custom properties",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"property_name": {
Type: schema.TypeString,
Computed: true,
Description: "Name of the custom property.",
},
"property_value": {
Type: schema.TypeSet,
Computed: true,
Description: "Value of the custom property.",
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
},
}
}

func dataSourceGithubOrgaRepositoryCustomProperties(d *schema.ResourceData, meta interface{}) error {

client := meta.(*Owner).v3client
ctx := context.Background()

owner := meta.(*Owner).name

repoName := d.Get("repository").(string)

allCustomProperties, _, err := client.Repositories.GetAllCustomPropertyValues(ctx, owner, repoName)
if err != nil {
return err
}

results, err := flattenRepositoryCustomProperties(allCustomProperties)
if err != nil {
return err
}

d.SetId(buildTwoPartID(owner, repoName))
d.Set("repository", repoName)
d.Set("property", results)

return nil
}

func flattenRepositoryCustomProperties(customProperties []*github.CustomPropertyValue) ([]interface{}, error) {

results := make([]interface{}, 0)
for _, prop := range customProperties {
result := make(map[string]interface{})

result["property_name"] = prop.PropertyName

propertyValue, err := parseRepositoryCustomPropertyValueToStringSlice(prop)
if err != nil {
return nil, err
}

result["property_value"] = propertyValue

results = append(results, result)
}

return results, nil
}

func parseRepositoryCustomPropertyValueToStringSlice(prop *github.CustomPropertyValue) ([]string, error) {
switch value := prop.Value.(type) {
case string:
return []string{value}, nil
case []string:
return value, nil
default:
return nil, fmt.Errorf("custom property value couldn't be parsed as a string or a list of strings: %s", value)
}
}
229 changes: 229 additions & 0 deletions github/data_source_github_repository_custom_properties_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
package github

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccGithubRepositoryCustomPropertiesDataSource(t *testing.T) {

t.Skip("You need an org with custom properties already setup as described in the variables below") // TODO: at the time of writing org_custom_properties are not supported by this terraform provider, so cant be setup in the test itself for now
singleSelectPropertyName := "single-select" // Needs to be a of type single_select, and have "option1" as an option
multiSelectPropertyName := "multi-select" // Needs to be a of type multi_select, and have "option1" and "option2" as an options
trueFlasePropertyName := "true-false" // Needs to be a of type true_false, and have "option1" as an option
stringPropertyName := "string" // Needs to be a of type string, and have "option1" as an option

randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)

t.Run("creates custom property of type single_select without error", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
auto_init = true
}
resource "github_repository_custom_property" "test" {
repository = github_repository.test.name
property_name = "%s"
property_value = ["option1"]
}
data "github_repository_custom_properties" "test" {
repository = github_repository_custom_property.test.repository
}
`, randomID, singleSelectPropertyName)

check := resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs("data.github_repository_custom_properties.test",
"property.*", map[string]string{
"property_name": singleSelectPropertyName,
"property_value.#": "1",
"property_value.0": "option1",
}),
)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
t.Skip("individual account not supported for this operation")
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})

t.Run("creates custom property of type multi_select without error", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
auto_init = true
}
resource "github_repository_custom_property" "test" {
repository = github_repository.test.name
property_name = "%s"
property_value = ["option1", "option2"]
}
data "github_repository_custom_properties" "test" {
repository = github_repository_custom_property.test.repository
}
`, randomID, multiSelectPropertyName)

check := resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs("data.github_repository_custom_properties.test",
"property.*", map[string]string{
"property_name": multiSelectPropertyName,
"property_value.#": "2",
"property_value.0": "option1",
"property_value.1": "option2",
}),
)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
t.Skip("individual account not supported for this operation")
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})

t.Run("creates custom property of type true_false without error", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
auto_init = true
}
resource "github_repository_custom_property" "test" {
repository = github_repository.test.name
property_name = "%s"
property_value = ["true"]
}
data "github_repository_custom_properties" "test" {
repository = github_repository_custom_property.test.repository
}
`, randomID, trueFlasePropertyName)

check := resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs("data.github_repository_custom_properties.test",
"property.*", map[string]string{
"property_name": trueFlasePropertyName,
"property_value.#": "1",
"property_value.0": "true",
}),
)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
t.Skip("individual account not supported for this operation")
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})

t.Run("creates custom property of type single_select without error", func(t *testing.T) {

config := fmt.Sprintf(`
resource "github_repository" "test" {
name = "tf-acc-test-%s"
auto_init = true
}
resource "github_repository_custom_property" "test" {
repository = github_repository.test.name
property_name = "%s"
property_value = ["text"]
}
data "github_repository_custom_properties" "test" {
repository = github_repository_custom_property.test.repository
}
`, randomID, stringPropertyName)

check := resource.ComposeTestCheckFunc(
resource.TestCheckTypeSetElemNestedAttrs("data.github_repository_custom_properties.test",
"property.*", map[string]string{
"property_name": stringPropertyName,
"property_value.#": "1",
"property_value.0": "text",
}),
)

testCase := func(t *testing.T, mode string) {
resource.Test(t, resource.TestCase{
PreCheck: func() { skipUnlessMode(t, mode) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: config,
Check: check,
},
},
})
}

t.Run("with an anonymous account", func(t *testing.T) {
t.Skip("anonymous account not supported for this operation")
})

t.Run("with an individual account", func(t *testing.T) {
t.Skip("individual account not supported for this operation")
})

t.Run("with an organization account", func(t *testing.T) {
testCase(t, organization)
})
})
}
2 changes: 2 additions & 0 deletions github/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ func Provider() *schema.Provider {
"github_repository_dependabot_security_updates": resourceGithubRepositoryDependabotSecurityUpdates(),
"github_repository_collaborator": resourceGithubRepositoryCollaborator(),
"github_repository_collaborators": resourceGithubRepositoryCollaborators(),
"github_repository_custom_property": resourceGithubRepositoryCustomProperty(),
"github_repository_deploy_key": resourceGithubRepositoryDeployKey(),
"github_repository_deployment_branch_policy": resourceGithubRepositoryDeploymentBranchPolicy(),
"github_repository_environment": resourceGithubRepositoryEnvironment(),
Expand Down Expand Up @@ -242,6 +243,7 @@ func Provider() *schema.Provider {
"github_repository": dataSourceGithubRepository(),
"github_repository_autolink_references": dataSourceGithubRepositoryAutolinkReferences(),
"github_repository_branches": dataSourceGithubRepositoryBranches(),
"github_repository_custom_properties": dataSourceGithubRepositoryCustomProperties(),
"github_repository_environments": dataSourceGithubRepositoryEnvironments(),
"github_repository_deploy_keys": dataSourceGithubRepositoryDeployKeys(),
"github_repository_deployment_branch_policies": dataSourceGithubRepositoryDeploymentBranchPolicies(),
Expand Down
Loading
Loading