-
Notifications
You must be signed in to change notification settings - Fork 280
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
Adding new resource azuredevops_repository_policy_searchable_branches #1272
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package acceptancetests | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" | ||
"github.com/microsoft/terraform-provider-azuredevops/azuredevops/internal/acceptancetests/testutils" | ||
) | ||
|
||
func TestAccRepositoryPolicySearchableBranches(t *testing.T) { | ||
testutils.RunTestsInSequence(t, map[string]map[string]func(t *testing.T){ | ||
"RepositoryPolicies": { | ||
"basic": testAccRepositoryPolicySearchableBranchesBasic, | ||
"update": testAccRepositoryPolicySearchableBranchesUpdate, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccRepositoryPolicySearchableBranchesBasic(t *testing.T) { | ||
searchableBranchesTfNode := "azuredevops_repository_searchable_branches.test" | ||
projectName := testutils.GenerateResourceName() | ||
repoName := testutils.GenerateResourceName() | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testutils.PreCheck(t, nil) }, | ||
Providers: testutils.GetProviders(), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: hclRepoPolicySearchableBranchesResourceBasic(projectName, repoName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(searchableBranchesTfNode, "searchable_branches.#", "1"), | ||
), | ||
}, { | ||
ResourceName: searchableBranchesTfNode, | ||
ImportStateIdFunc: testutils.ComputeProjectQualifiedResourceImportID(searchableBranchesTfNode), | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccRepositoryPolicySearchableBranchesUpdate(t *testing.T) { | ||
searchableBranchesTfNode := "azuredevops_repository_searchable_branches.test" | ||
projectName := testutils.GenerateResourceName() | ||
repoName := testutils.GenerateResourceName() | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { testutils.PreCheck(t, nil) }, | ||
Providers: testutils.GetProviders(), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: hclRepoPolicySearchableBranchesResourceBasic(projectName, repoName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(searchableBranchesTfNode, "searchable_branches.#", "1"), | ||
), | ||
}, { | ||
Config: hclRepoPolicySearchableBranchesResourceUpdate(projectName, repoName), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr(searchableBranchesTfNode, "searchable_branches.#", "2"), | ||
), | ||
}, { | ||
ResourceName: searchableBranchesTfNode, | ||
ImportStateIdFunc: testutils.ComputeProjectQualifiedResourceImportID(searchableBranchesTfNode), | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func hclRepoPolicySearchableBranchesResourceTemplate(projectName string, repoName string) string { | ||
return fmt.Sprintf(` | ||
resource "azuredevops_project" "test" { | ||
name = "%s" | ||
description = "Test Project Description" | ||
visibility = "private" | ||
version_control = "Git" | ||
work_item_template = "Agile" | ||
} | ||
|
||
resource "azuredevops_git_repository" "test" { | ||
project_id = azuredevops_project.test.id | ||
name = "%s" | ||
initialization { | ||
init_type = "Clean" | ||
} | ||
} | ||
`, projectName, repoName) | ||
} | ||
|
||
func hclRepoPolicySearchableBranchesResourceBasic(projectName string, repoName string) string { | ||
projectAndRepo := hclRepoPolicySearchableBranchesResourceTemplate(projectName, repoName) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azuredevops_repository_policy_searchable_branches" "test" { | ||
project_id = azuredevops_project.test.id | ||
|
||
searchable_branches = ["testbranch"] | ||
repository_ids = [azuredevops_git_repository.test.id] | ||
}`, projectAndRepo) | ||
} | ||
|
||
func hclRepoPolicySearchableBranchesResourceUpdate(projectName string, repoName string) string { | ||
projectAndRepo := hclRepoPolicySearchableBranchesResourceTemplate(projectName, repoName) | ||
return fmt.Sprintf(` | ||
%s | ||
|
||
resource "azuredevops_repository_policy_searchable_branches" "test" { | ||
project_id = azuredevops_project.test.id | ||
|
||
searchable_branches = ["testbranch2"] | ||
repository_ids = [azuredevops_git_repository.test.id] | ||
}`, projectAndRepo) | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,81 @@ | ||||||
package repository | ||||||
|
||||||
import ( | ||||||
"maps" | ||||||
|
||||||
"github.com/google/uuid" | ||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" | ||||||
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" | ||||||
"github.com/microsoft/azure-devops-go-api/azuredevops/v7/policy" | ||||||
) | ||||||
|
||||||
type searchbranchesPolicySettings struct { | ||||||
SearchBranches []string `json:"searchBranches"` | ||||||
} | ||||||
|
||||||
func ResourceRepositorySearchableBranches() *schema.Resource { | ||||||
resource := genBasePolicyResource(&policyCrudArgs{ | ||||||
FlattenFunc: searchableBranchesFlattenFunc, | ||||||
ExpandFunc: searchableBranchesExpandFunc, | ||||||
PolicyType: SearchableBranches, | ||||||
}) | ||||||
|
||||||
maps.Copy(resource.Schema, map[string]*schema.Schema{ | ||||||
"searchable_branches": { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
Type: schema.TypeList, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be |
||||||
Required: true, | ||||||
Elem: &schema.Schema{ | ||||||
Type: schema.TypeString, | ||||||
ValidateFunc: validation.StringIsNotEmpty, | ||||||
}, | ||||||
}, | ||||||
"enabled": { | ||||||
Type: schema.TypeBool, | ||||||
Computed: true, | ||||||
}, | ||||||
"blocking": { | ||||||
Type: schema.TypeBool, | ||||||
Computed: true, | ||||||
}, | ||||||
// API only accepts a single repository as scope. | ||||||
"repository_ids": { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is legacy technical debt. Instead of using a generic scheme, you can add entire schemes as needed and handle create/update/read/delete yourself. Based on the information you shared, it is recommended to do this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, I just read this comment in order. :) So you're suggesting to not use the generic schema provided by common. Let me look into it 👍 |
||||||
Type: schema.TypeList, | ||||||
Required: true, | ||||||
MinItems: 1, | ||||||
MaxItems: 1, | ||||||
Elem: &schema.Schema{ | ||||||
Type: schema.TypeString, | ||||||
ValidateFunc: validation.IsUUID, | ||||||
}, | ||||||
}, | ||||||
Comment on lines
+32
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These properties are handled in the infrastructure and we can remove them There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true. The reason why I've added these is to override them, however. The thing with the Searchable Branches policy is that the API still expects these to be passed, but setting the And you can only scope this for 1 repository, plus I did not want to mess too much with the schema. Hence forcing the |
||||||
}) | ||||||
|
||||||
return resource | ||||||
} | ||||||
|
||||||
func searchableBranchesFlattenFunc(d *schema.ResourceData, policyConfig *policy.PolicyConfiguration, projectID *string) error { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
err := baseFlattenFunc(d, policyConfig, projectID) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
policySettings := policyConfig.Settings.(map[string]interface{}) | ||||||
_ = d.Set("searchable_branches", policySettings["searchBranches"].([]interface{})) | ||||||
return nil | ||||||
} | ||||||
|
||||||
func searchableBranchesExpandFunc(d *schema.ResourceData, typeID uuid.UUID) (*policy.PolicyConfiguration, *string, error) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
policyConfig, projectID, err := baseExpandFunc(d, typeID) | ||||||
if err != nil { | ||||||
return nil, nil, err | ||||||
} | ||||||
|
||||||
policySettings := policyConfig.Settings.(map[string]interface{}) | ||||||
policySettings["searchBranches"] = d.Get("searchable_branches") | ||||||
|
||||||
// Overriding blocking and enabled as it has no use for this policy setting | ||||||
policySettings["blocking"] = false | ||||||
policySettings["enabled"] = false | ||||||
|
||||||
return policyConfig, projectID, nil | ||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,64 @@ | ||||||||||||||||||||||
--- | ||||||||||||||||||||||
layout: "azuredevops" | ||||||||||||||||||||||
page_title: "AzureDevops: azuredevops_repository_policy_searchable_branches" | ||||||||||||||||||||||
description: |- Manages searchable branches repository policy within Azure DevOps project. | ||||||||||||||||||||||
--- | ||||||||||||||||||||||
|
||||||||||||||||||||||
# azuredevops_repository_policy_searchable_branches | ||||||||||||||||||||||
|
||||||||||||||||||||||
Manage searchable branches repository policy within Azure DevOps project. | ||||||||||||||||||||||
|
||||||||||||||||||||||
## Example Usage | ||||||||||||||||||||||
|
||||||||||||||||||||||
```hcl | ||||||||||||||||||||||
resource "azuredevops_project" "example" { | ||||||||||||||||||||||
name = "Example Project" | ||||||||||||||||||||||
visibility = "private" | ||||||||||||||||||||||
version_control = "Git" | ||||||||||||||||||||||
work_item_template = "Agile" | ||||||||||||||||||||||
description = "Managed by Terraform" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
resource "azuredevops_git_repository" "example" { | ||||||||||||||||||||||
project_id = azuredevops_project.example.id | ||||||||||||||||||||||
name = "Example Repository" | ||||||||||||||||||||||
initialization { | ||||||||||||||||||||||
init_type = "Clean" | ||||||||||||||||||||||
} | ||||||||||||||||||||||
} | ||||||||||||||||||||||
|
||||||||||||||||||||||
resource "azuredevops_repository_policy_searchable_branches" "example" { | ||||||||||||||||||||||
project_id = data.azuredevops_project.example.id | ||||||||||||||||||||||
searchable_branches = ["examplebranch"] | ||||||||||||||||||||||
repository_ids = [data.azuredevops_git_repository.example.id] | ||||||||||||||||||||||
|
||||||||||||||||||||||
} | ||||||||||||||||||||||
``` | ||||||||||||||||||||||
|
||||||||||||||||||||||
## Argument Reference | ||||||||||||||||||||||
|
||||||||||||||||||||||
The following arguments are supported: | ||||||||||||||||||||||
|
||||||||||||||||||||||
- `project_id` - (Required) The ID of the project in which the policy will be created. | ||||||||||||||||||||||
- `enabled` - (Computed) This is set to false by the provider and is not used. | ||||||||||||||||||||||
- `blocking` - (Computed) This is set to false by the provider and is not used. | ||||||||||||||||||||||
- `searchable_branches` - (Required) A list of branch names to be added as searchable branches for the repository. Branches do not have to exist. | ||||||||||||||||||||||
- `repository_ids` (Required) ID of repository for which the policy is enabled. Note: Due to the API implementation of this policy, this only accepts 1 repository id. | ||||||||||||||||||||||
|
||||||||||||||||||||||
## Attributes Reference | ||||||||||||||||||||||
|
||||||||||||||||||||||
In addition to all arguments above, the following attributes are exported: | ||||||||||||||||||||||
|
||||||||||||||||||||||
- `id` - The ID of the repository policy. | ||||||||||||||||||||||
|
||||||||||||||||||||||
## Relevant Links | ||||||||||||||||||||||
|
||||||||||||||||||||||
- [Azure DevOps Service REST API 7.0 - Policy Configurations](https://docs.microsoft.com/en-us/rest/api/azure/devops/policy/configurations?view=azure-devops-rest-7.0) | ||||||||||||||||||||||
|
||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||
## Import | ||||||||||||||||||||||
|
||||||||||||||||||||||
Azure DevOps repository policies can be imported using the projectID/policyID or projectName/policyID: | ||||||||||||||||||||||
|
||||||||||||||||||||||
```sh | ||||||||||||||||||||||
terraform import azuredevops_repository_policy_searchable_branches.example 00000000-0000-0000-0000-000000000000/0 | ||||||||||||||||||||||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code can be removed