-
Notifications
You must be signed in to change notification settings - Fork 773
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: support repository level custom_property resource and custom_pr…
…operties datasource (#2316) * add octokit sdk client * stash half working solution * add repository custom properties data source * break out custom props parsing logic to its own function * use background ctx * format provider.go * fix error msg to include repoName instead of its pointer * use type switch instead of if else * fix linting errors * restructure datasource to take a property name and call it github_repository_custom_property instead * formatting * rename file to match datasource name * implement data_source_github_repository_custom_property with go-github * implement resource_github_repository_custom_property * update descriptions * remove custom_property resource in favour of custom_propertIES one * add custom_property resource to provider.go * formatting * add tests for repository_custom_property * update description of test * add tests for each custom_property type * rollback repo changes * add tests for custom_property datasource * formatting * breakout parsing custom_property_value as a string slice to its own function * bump go-github to v66 for new files * add property_type as a required attribute * flip datasource to use typeList instead of typeSet * refactor tests for data source to use property_type * Update data_source_github_repository_custom_properties.go * cleanup incorrect comments * remove old comment * add docs * fix typo --------- Co-authored-by: felixlut <felix.luthman@snowsoftware.com> Co-authored-by: Keegan Campbell <me@kfcampbell.com>
- Loading branch information
1 parent
0419c6b
commit 1ca7092
Showing
7 changed files
with
788 additions
and
0 deletions.
There are no files selected for viewing
103 changes: 103 additions & 0 deletions
103
github/data_source_github_repository_custom_properties.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/google/go-github/v66/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) | ||
} | ||
} |
233 changes: 233 additions & 0 deletions
233
github/data_source_github_repository_custom_properties_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
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_type = "single_select" | ||
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_type = "multi_select" | ||
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_type = "true_false" | ||
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 string 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_type = "string" | ||
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) | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.