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 Triggers #811

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
65 changes: 65 additions & 0 deletions docs/resources/git_trigger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "octopusdeploy_git_trigger Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
This resource manages Git repository triggers in Octopus Deploy.
---

# octopusdeploy_git_trigger (Resource)

This resource manages Git repository triggers in Octopus Deploy.

## Example Usage

```terraform
resource "octopusdeploy_git_trigger" "my_trigger" {
name = "My Git trigger"
space_id = "Spaces-1"
project_id = "Projects-1"
channel_id = "Channels-1"
sources {
deployment_action_slug = "deploy-action-slug"
git_dependency_name = ""

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 the formatting ended up a bit wonky here

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right I think its coming from the example file

include_file_paths = ["include/me", "include/me/too"]
exclude_file_paths = ["exclude/me", "exclude/me/too"]
}
}
```

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

### Required

- `channel_id` (String) The ID of the channel in which the release will be created if the action type is CreateRelease.
- `name` (String) The name of this resource.
- `project_id` (String) The ID of the project to attach the trigger.

### Optional

- `is_disabled` (Boolean) Disables the trigger from being run when set.
- `sources` (Block List) List of Git trigger sources. Contains details of the deployment action slug, the git dependency and what file paths to monitor. (see [below for nested schema](#nestedblock--sources))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are Git trigger sources optional? What happens if you supply an empty list, do we allow that? I suppose it just doesn't do anything which might be ok.

- `space_id` (String) The space ID associated with the project to attach the trigger.

### Read-Only

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

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

Required:

- `deployment_action_slug` (String)
- `exclude_file_paths` (List of String)
- `git_dependency_name` (String)
- `include_file_paths` (List of String)

## Import

Import is supported using the following syntax:

```shell
terraform import [options] octopusdeploy_git_trigger.<name> <trigger-id>
```
1 change: 1 addition & 0 deletions examples/resources/octopusdeploy_git_trigger/import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform import [options] octopusdeploy_git_trigger.<name> <trigger-id>
12 changes: 12 additions & 0 deletions examples/resources/octopusdeploy_git_trigger/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
resource "octopusdeploy_git_trigger" "my_trigger" {
name = "My Git trigger"
space_id = "Spaces-1"
project_id = "Projects-1"
channel_id = "Channels-1"
sources {
deployment_action_slug = "deploy-action-slug"
git_dependency_name = ""
include_file_paths = ["include/me", "include/me/too"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These support glob patterns, including single directory * and multi-directory **, might be good to include some examples of those in here.

exclude_file_paths = ["exclude/me", "exclude/me/too"]
}
}
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.55.0
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.56.0
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ github.com/Microsoft/hcsshim v0.12.4 h1:Ev7YUMHAHoWNm+aDSPzc5W9s6E2jyL1szpVDJeZ/
github.com/Microsoft/hcsshim v0.12.4/go.mod h1:Iyl1WVpZzr+UkzjekHZbV8o5Z9ZkxNGx6CtY2Qg/JVQ=
github.com/OctopusDeploy/go-octodiff v1.0.0 h1:U+ORg6azniwwYo+O44giOw6TiD5USk8S4VDhOQ0Ven0=
github.com/OctopusDeploy/go-octodiff v1.0.0/go.mod h1:Mze0+EkOWTgTmi8++fyUc6r0aLZT7qD9gX+31t8MmIU=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.55.0 h1:kX6qRRy8AgbqTiYdenqVNe69pGhntwJGEgJx9rtn9/8=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.55.0/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.56.0 h1:KALIOWdky6FR8a2npBo6wdYG0Rg08e3C++1kEHWFex4=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.56.0/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4 h1:QfbVf0bOIRMp/WHAWsuVDB7KHoWnRsGbvDuOf2ua7k4=
github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4/go.mod h1:Oq9KbiRNDBB5jFmrwnrgLX0urIqR/1ptY18TzkqXm7M=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
Expand Down
1 change: 1 addition & 0 deletions octopusdeploy/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func Provider() *schema.Provider {
"octopusdeploy_deployment_process": resourceDeploymentProcess(),
"octopusdeploy_dynamic_worker_pool": resourceDynamicWorkerPool(),
"octopusdeploy_gcp_account": resourceGoogleCloudPlatformAccount(),
"octopusdeploy_git_trigger": resourceGitTrigger(),
"octopusdeploy_kubernetes_agent_deployment_target": resourceKubernetesAgentDeploymentTarget(),
"octopusdeploy_kubernetes_agent_worker": resourceKubernetesAgentWorker(),
"octopusdeploy_kubernetes_cluster_deployment_target": resourceKubernetesClusterDeploymentTarget(),
Expand Down
130 changes: 130 additions & 0 deletions octopusdeploy/resource_git_trigger.go

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any way to add tests around these resource functions to prove that things get serialized/deserialized correctly?

Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package octopusdeploy

import (
"context"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects"
"log"

"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/actions"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/filters"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/triggers"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceGitTrigger() *schema.Resource {
return &schema.Resource{
CreateContext: resourceGitTriggerCreate,
DeleteContext: resourceGitTriggerDelete,
Description: "This resource manages Git repository triggers in Octopus Deploy.",
Importer: getImporter(),
ReadContext: resourceGitTriggerRead,
Schema: getGitTriggerSchema(),
UpdateContext: resourceGitTriggerUpdate,
}
}

func buildGitTriggerResource(d *schema.ResourceData, client *client.Client) (*triggers.ProjectTrigger, error) {
name := d.Get("name").(string)
spaceId := d.Get("space_id").(string)
projectId := d.Get("project_id").(string)
channelId := d.Get("channel_id").(string)

isDisabled := false
if v, ok := d.GetOk("is_disabled"); ok {
isDisabled = v.(bool)
}

flattenedGitTriggerSources := d.Get("sources")
gitTriggerSources := expandGitTriggerSources(flattenedGitTriggerSources)

action := actions.NewCreateReleaseAction(channelId)
filter := filters.NewGitTriggerFilter(gitTriggerSources)

project, err := projects.GetByID(client, spaceId, projectId)
if err != nil {
return nil, err
}

createReleaseTrigger := triggers.NewProjectTrigger(name, "", isDisabled, project, action, filter)

return createReleaseTrigger, nil
}

func resourceGitTriggerCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*client.Client)

projectTrigger, err := buildGitTriggerResource(d, client)
if err != nil {
return diag.FromErr(err)
}

resource, err := client.ProjectTriggers.Add(projectTrigger)
if err != nil {
return diag.FromErr(err)
}

if isEmpty(resource.GetID()) {
log.Println("ID is nil")
} else {
d.SetId(resource.GetID())
}

return nil
}

func resourceGitTriggerRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
id := d.Id()

client := m.(*client.Client)
projectTrigger, err := client.ProjectTriggers.GetByID(id)
if err != nil {
return diag.FromErr(err)
}
if projectTrigger == nil {
d.SetId("")
return nil
}

action := projectTrigger.Action.(*actions.CreateReleaseAction)
filter := projectTrigger.Filter.(*filters.GitTriggerFilter)

d.Set("name", projectTrigger.Name)
d.Set("space_id", projectTrigger.SpaceID)
d.Set("project_id", projectTrigger.ProjectID)
d.Set("is_disabled", projectTrigger.IsDisabled)
d.Set("channel_id", action.ChannelID)
d.Set("sources", flattenGitTriggerSources(filter.Sources))

return nil
}

func resourceGitTriggerUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*client.Client)
projectTrigger, err := buildGitTriggerResource(d, client)
if err != nil {
return diag.FromErr(err)
}
projectTrigger.ID = d.Id() // set ID so Octopus API knows which project trigger to update

resource, err := client.ProjectTriggers.Update(projectTrigger)
if err != nil {
return diag.FromErr(err)
}

d.SetId(resource.GetID())

return nil
}

func resourceGitTriggerDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
client := m.(*client.Client)
err := client.ProjectTriggers.DeleteByID(d.Id())
if err != nil {
return diag.FromErr(err)
}

d.SetId("")
return nil
}
42 changes: 42 additions & 0 deletions octopusdeploy/schema_git_trigger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package octopusdeploy

import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func getGitTriggerSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"name": getNameSchema(true),
"space_id": {
Optional: true,
Description: "The space ID associated with the project to attach the trigger.",
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
"project_id": {
Description: "The ID of the project to attach the trigger.",
Required: true,
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
"channel_id": {
Description: "The ID of the channel in which the release will be created if the action type is CreateRelease.",
Required: true,
Type: schema.TypeString,
ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
},
"sources": {
Description: "List of Git trigger sources. Contains details of the deployment action slug, the git dependency and what file paths to monitor.",
Optional: true,
Type: schema.TypeList,
Elem: &schema.Resource{Schema: getGitTriggerSourceSchema()},
},
"is_disabled": {
Description: "Disables the trigger from being run when set.",
Optional: true,
Default: false,
Type: schema.TypeBool,
},
}
}
66 changes: 66 additions & 0 deletions octopusdeploy/schema_git_trigger_source_package.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package octopusdeploy

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

func expandGitTriggerSources(values interface{}) []filters.GitTriggerSource {
if values == nil {
return nil
}

var gitTriggerSources []filters.GitTriggerSource
for _, v := range values.([]interface{}) {
flattenedMap := v.(map[string]interface{})
gitTriggerSources = append(gitTriggerSources, filters.GitTriggerSource{
DeploymentActionSlug: flattenedMap["deployment_action_slug"].(string),
GitDependencyName: flattenedMap["git_dependency_name"].(string),
IncludeFilePaths: flattenedMap["include_file_paths"].([]string),
ExcludeFilePaths: flattenedMap["exclude_file_paths"].([]string),
})
}

return gitTriggerSources
}

func flattenGitTriggerSources(gitTriggerSources []filters.GitTriggerSource) []interface{} {
if len(gitTriggerSources) == 0 {
return nil
}

flattenedGitTriggerSources := []interface{}{}
for _, v := range gitTriggerSources {
flattenedGitTriggerSources = append(flattenedGitTriggerSources, map[string]interface{}{
"deployment_action_slug": v.DeploymentActionSlug,
"git_dependency_name": v.GitDependencyName,
"include_file_paths": v.IncludeFilePaths,
"exclude_file_paths": v.ExcludeFilePaths,
})
}

return flattenedGitTriggerSources
}

func getGitTriggerSourceSchema() map[string]*schema.Schema {
return map[string]*schema.Schema{
"deployment_action_slug": {
Required: true,
Type: schema.TypeString,
},
"git_dependency_name": {
Required: true,
Type: schema.TypeString,
},
"include_file_paths": {
Required: true,
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
"exclude_file_paths": {
Required: true,
Type: schema.TypeList,
Elem: &schema.Schema{Type: schema.TypeString},
},
}
}
Loading