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

Add Git Protection Rules #693

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 21 additions & 0 deletions docs/data-sources/channels.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ data "octopusdeploy_channels" "example" {
Read-Only:

- `description` (String) The description of this channel.
- `git_reference_rules` (List of String) List of rules to restrict which Git references can be used with this channel when creating releases for version controlled projects. References must be fully qualified e.g. `refs/heads/main`. Supports glob patten syntax.
- `git_resource_rules` (List of Object) List of rules to restrict which Git resources can be used with this channel when creating releases with external Git resources. Resources must be fully qualified e.g. `refs/heads/main`. Supports glob patten syntax. (see [below for nested schema](#nestedatt--channels--git_resource_rules))
- `id` (String) The unique ID for this resource.
- `is_default` (Boolean) Indicates if this is the default channel for the associated project.
- `lifecycle_id` (String) The lifecycle ID associated with this channel.
Expand All @@ -52,6 +54,25 @@ Read-Only:
- `space_id` (String) The space ID associated with this resource.
- `tenant_tags` (List of String) A list of tenant tags associated with this resource.

<a id="nestedatt--channels--git_resource_rules"></a>
### Nested Schema for `channels.git_resource_rules`

Read-Only:

- `git_dependency_actions` (List of Object) (see [below for nested schema](#nestedobjatt--channels--git_resource_rules--git_dependency_actions))
- `id` (String)
- `rules` (List of String)

<a id="nestedobjatt--channels--git_resource_rules--git_dependency_actions"></a>
### Nested Schema for `channels.git_resource_rules.git_dependency_actions`

Read-Only:

- `deployment_action_slug` (String)
- `git_dependency_name` (String)



<a id="nestedatt--channels--rule"></a>
### Nested Schema for `channels.rule`

Expand Down
4 changes: 2 additions & 2 deletions docs/resources/azure_subscription_account.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ resource "octopusdeploy_azure_subscription_account" "example" {

### Required

- `management_endpoint` (String)
- `name` (String) The name of this resource.
- `storage_endpoint_suffix` (String) The storage endpoint suffix associated with this Azure subscription account.
- `subscription_id` (String) The subscription ID of this resource.

### Optional
Expand All @@ -34,7 +32,9 @@ resource "octopusdeploy_azure_subscription_account" "example" {
- `certificate_thumbprint` (String, Sensitive)
- `description` (String) The description of this Azure subscription account.
- `environments` (List of String) A list of environment IDs associated with this resource.
- `management_endpoint` (String)
- `space_id` (String) The space ID associated with this resource.
- `storage_endpoint_suffix` (String) The storage endpoint suffix associated with this Azure subscription account.
- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
- `tenants` (List of String) A list of tenant IDs associated with this resource.
Expand Down
24 changes: 24 additions & 0 deletions docs/resources/channel.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,37 @@ resource "octopusdeploy_channel" "example" {
### Optional

- `description` (String) The description of this channel.
- `git_reference_rules` (List of String) List of rules to restrict which Git references can be used with this channel when creating releases for version controlled projects. References must be fully qualified e.g. `refs/heads/main`. Supports glob patten syntax.
- `git_resource_rules` (Block List) List of rules to restrict which Git resources can be used with this channel when creating releases with external Git resources. Resources must be fully qualified e.g. `refs/heads/main`. Supports glob patten syntax. (see [below for nested schema](#nestedblock--git_resource_rules))
- `id` (String) The unique ID for this resource.
- `is_default` (Boolean) Indicates if this is the default channel for the associated project.
- `lifecycle_id` (String) The lifecycle ID associated with this channel.
- `rule` (Block List) A list of rules associated with this channel. (see [below for nested schema](#nestedblock--rule))
- `space_id` (String) The space ID associated with this resource.
- `tenant_tags` (List of String) A list of tenant tags associated with this resource.

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

Required:

- `git_dependency_actions` (Block List, Min: 1) (see [below for nested schema](#nestedblock--git_resource_rules--git_dependency_actions))

Optional:

- `id` (String) The unique ID for this resource.
- `rules` (List of String)

<a id="nestedblock--git_resource_rules--git_dependency_actions"></a>
### Nested Schema for `git_resource_rules.git_dependency_actions`

Optional:

- `deployment_action_slug` (String)
- `git_dependency_name` (String)



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

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/OctopusDeploy/terraform-provider-octopusdeploy
go 1.21

require (
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.43.0
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.44.1
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240725054341-2848f54d101e
github.com/google/uuid v1.6.0
github.com/gruntwork-io/terratest v0.41.11
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ github.com/Microsoft/hcsshim v0.11.5 h1:haEcLNpj9Ka1gd3B3tAEs9CpE0c+1IhoL59w/exY
github.com/Microsoft/hcsshim v0.11.5/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.43.0 h1:fYwGBqG88xy3qHp5j1ySCztdqfw2NLfg2yp0N3XcBYg=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.43.0/go.mod h1:GZmFu6LmN8Yg0tEoZx3ytk9FnaH+84cWm7u5TdWZC6E=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.44.1 h1:e8aGPNAXEBr/PRSTghyE1FgKERJXYvCPh/12C11kmbE=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.44.1/go.mod h1:GZmFu6LmN8Yg0tEoZx3ytk9FnaH+84cWm7u5TdWZC6E=
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240725054341-2848f54d101e h1:FIvWa8wNg8IBG5uVhqkKvcBhaxx4TgN7T8/5Ed4VQUE=
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240725054341-2848f54d101e/go.mod h1:Oq9KbiRNDBB5jFmrwnrgLX0urIqR/1ptY18TzkqXm7M=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
Expand Down
52 changes: 43 additions & 9 deletions octopusdeploy/schema_channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ func expandChannel(d *schema.ResourceData) *channels.Channel {
}
}

if v, ok := d.GetOk("git_reference_rules"); ok {
channel.GitReferenceRules = expandArray(v.([]interface{}))
}

if v, ok := d.GetOk("git_resource_rules"); ok {
channelGitResourceRules := v.([]interface{})
for _, channelGitResourceRule := range channelGitResourceRules {
rule := expandChannelGitResourceRules(channelGitResourceRule.(map[string]interface{}))
channel.GitResourceRules = append(channel.GitResourceRules, rule)
}
}

return channel
}

Expand All @@ -52,15 +64,17 @@ func flattenChannel(channel *channels.Channel) map[string]interface{} {
}

return map[string]interface{}{
"description": channel.Description,
"id": channel.GetID(),
"is_default": channel.IsDefault,
"lifecycle_id": channel.LifecycleID,
"name": channel.Name,
"project_id": channel.ProjectID,
"rule": flattenChannelRules(channel.Rules),
"space_id": channel.SpaceID,
"tenant_tags": channel.TenantTags,
"description": channel.Description,
"id": channel.GetID(),
"is_default": channel.IsDefault,
"lifecycle_id": channel.LifecycleID,
"name": channel.Name,
"project_id": channel.ProjectID,
"rule": flattenChannelRules(channel.Rules),
"space_id": channel.SpaceID,
"tenant_tags": channel.TenantTags,
"git_reference_rules": flattenArray(channel.GitReferenceRules),
"git_resource_rules": flattenChannelGitResourceRules(channel.GitResourceRules),
}
}

Expand Down Expand Up @@ -112,6 +126,18 @@ func getChannelSchema() map[string]*schema.Schema {
},
"space_id": getSpaceIDSchema(),
"tenant_tags": getTenantTagsSchema(),
"git_reference_rules": {
Description: "List of rules to restrict which Git references can be used with this channel when creating releases for version controlled projects. References must be fully qualified e.g. `refs/heads/main`. Supports glob patten syntax.",
Optional: true,
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
"git_resource_rules": {
Description: "List of rules to restrict which Git resources can be used with this channel when creating releases with external Git resources. Resources must be fully qualified e.g. `refs/heads/main`. Supports glob patten syntax.",
Optional: true,
Type: schema.TypeList,
Elem: &schema.Resource{Schema: getChannelGitResourceRuleSchema()},
},
}
}

Expand All @@ -131,5 +157,13 @@ func setChannel(ctx context.Context, d *schema.ResourceData, channel *channels.C
return fmt.Errorf("error setting tenant_tags: %s", err)
}

if err := d.Set("git_reference_rules", channel.GitReferenceRules); err != nil {
return fmt.Errorf("error setting git_reference_rules: %s", err)
}

if err := d.Set("git_resource_rules", flattenChannelGitResourceRules(channel.GitResourceRules)); err != nil {
return fmt.Errorf("error setting git_resource_rules: %s", err)
}

return nil
}
51 changes: 51 additions & 0 deletions octopusdeploy/schema_channel_git_resource_rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package octopusdeploy

import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/channels"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func expandChannelGitResourceRules(ChannelGitResourceRule map[string]interface{}) channels.ChannelGitResourceRule {
if len(ChannelGitResourceRule) == 0 {
return channels.ChannelGitResourceRule{}
}

return channels.ChannelGitResourceRule{
Id: ChannelGitResourceRule["id"].(string),
GitDependencyActions: expandDeploymentActionGitDependencies(ChannelGitResourceRule["git_dependency_actions"]),
Rules: ChannelGitResourceRule["rules"].([]string),
}
}

func flattenChannelGitResourceRules(ChannelGitResourceRules []channels.ChannelGitResourceRule) []map[string]interface{} {
if len(ChannelGitResourceRules) == 0 {
return []map[string]interface{}{}
}

var flattenedRules = make([]map[string]interface{}, len(ChannelGitResourceRules))
for key, ChannelGitResourceRule := range ChannelGitResourceRules {
flattenedRules[key] = map[string]interface{}{
"id": ChannelGitResourceRule.Id,
"git_dependency_actions": flattenDeploymentActionGitDependencies(ChannelGitResourceRule.GitDependencyActions),
"rules": ChannelGitResourceRule.Rules,
}
}

return flattenedRules
}

func getChannelGitResourceRuleSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"id": getIDSchema(),
"git_dependency_actions": {
Elem: &schema.Resource{Schema: getDeploymentActionGitDependencySchema()},
Required: true,
Type: schema.TypeList,
},
"rules": {
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Type: schema.TypeList,
},
}
}
51 changes: 51 additions & 0 deletions octopusdeploy/schema_deployment_action_git_dependency.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package octopusdeploy

import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/gitdependencies"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func flattenDeploymentActionGitDependencies(deploymentActionGitDependencies []gitdependencies.DeploymentActionGitDependency) []interface{} {
if len(deploymentActionGitDependencies) == 0 {
return nil
}

var flattenedDeploymentActionPackages []interface{}
for _, v := range deploymentActionGitDependencies {
flattenedDeploymentActionPackage := map[string]interface{}{
"deployment_action_slug": v.DeploymentActionSlug,
"git_dependency_name": v.GitDependencyName,
}
flattenedDeploymentActionPackages = append(flattenedDeploymentActionPackages, flattenedDeploymentActionPackage)
}
return flattenedDeploymentActionPackages
}

func expandDeploymentActionGitDependencies(values interface{}) []gitdependencies.DeploymentActionGitDependency {
if values == nil {
return nil
}

var gitDependencies []gitdependencies.DeploymentActionGitDependency
for _, v := range values.([]interface{}) {
flattenedMap := v.(map[string]interface{})
gitDependencies = append(gitDependencies, gitdependencies.DeploymentActionGitDependency{
DeploymentActionSlug: flattenedMap["deployment_action_slug"].(string),
GitDependencyName: flattenedMap["git_dependency_name"].(string),
})
}
return gitDependencies
}

func getDeploymentActionGitDependencySchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"deployment_action_slug": {
Optional: true,
Type: schema.TypeString,
},
"git_dependency_name": {
Optional: true,
Type: schema.TypeString,
},
}
}
96 changes: 96 additions & 0 deletions octopusdeploy/schema_deployment_action_git_resource_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package octopusdeploy

import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/channels"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/gitdependencies"
"reflect"
"testing"
)

func TestExpandChannelGitResourceRules_WithValidData_ReturnsExpectedResult(t *testing.T) {
input := map[string]interface{}{
"id": "rule-1",
"git_dependency_actions": []interface{}{
map[string]interface{}{
"deployment_action_slug": "deploy-action-1",
"git_dependency_name": "",
},
},
"rules": []string{"rule1", "rule2"},
}

expected := channels.ChannelGitResourceRule{
Id: "rule-1",
GitDependencyActions: []gitdependencies.DeploymentActionGitDependency{
{
DeploymentActionSlug: "deploy-action-1",
GitDependencyName: "",
},
},
Rules: []string{"rule1", "rule2"},
}

actual := expandChannelGitResourceRules(input)

if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected %+v, got %+v", expected, actual)
}
}

func TestExpandChannelGitResourceRules_WithEmptyData_ReturnsEmptyStruct(t *testing.T) {
input := map[string]interface{}{}

expected := channels.ChannelGitResourceRule{}

actual := expandChannelGitResourceRules(input)

if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected %+v, got %+v", expected, actual)
}
}

func TestFlattenChannelGitResourceRules_WithValidData_ReturnsExpectedMap(t *testing.T) {
input := []channels.ChannelGitResourceRule{
{
Id: "rule-1",
GitDependencyActions: []gitdependencies.DeploymentActionGitDependency{
{
DeploymentActionSlug: "deploy-action-1",
GitDependencyName: "ref-1",
},
},
Rules: []string{"rule1", "rule2"},
},
}

expected := []map[string]interface{}{
{
"id": "rule-1",
"git_dependency_actions": []interface{}{
map[string]interface{}{
"deployment_action_slug": "deploy-action-1",
"git_dependency_name": "ref-1",
},
},
"rules": []string{"rule1", "rule2"},
},
}

actual := flattenChannelGitResourceRules(input)

if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected %+v, got %+v", expected, actual)
}
}

func TestFlattenChannelGitResourceRules_WithEmptyData_ReturnsEmptySlice(t *testing.T) {
input := []channels.ChannelGitResourceRule{}

expected := []map[string]interface{}{}

actual := flattenChannelGitResourceRules(input)

if !reflect.DeepEqual(actual, expected) {
t.Errorf("Expected %+v, got %+v", expected, actual)
}
}
Loading