From 799061007476fac17feb59e0c9fb46033478b347 Mon Sep 17 00:00:00 2001 From: Lourens de Jager <165963988+lourens-octopus@users.noreply.github.com> Date: Tue, 12 Nov 2024 10:00:10 +1300 Subject: [PATCH] feat: Add Git Triggers --- docs/resources/git_trigger.md | 65 +++++++++ .../octopusdeploy_git_trigger/import.sh | 1 + .../octopusdeploy_git_trigger/resource.tf | 12 ++ go.mod | 2 +- go.sum | 4 +- octopusdeploy/provider.go | 1 + octopusdeploy/resource_git_trigger.go | 130 ++++++++++++++++++ octopusdeploy/schema_git_trigger.go | 42 ++++++ .../schema_git_trigger_source_package.go | 66 +++++++++ 9 files changed, 320 insertions(+), 3 deletions(-) create mode 100644 docs/resources/git_trigger.md create mode 100644 examples/resources/octopusdeploy_git_trigger/import.sh create mode 100644 examples/resources/octopusdeploy_git_trigger/resource.tf create mode 100644 octopusdeploy/resource_git_trigger.go create mode 100644 octopusdeploy/schema_git_trigger.go create mode 100644 octopusdeploy/schema_git_trigger_source_package.go diff --git a/docs/resources/git_trigger.md b/docs/resources/git_trigger.md new file mode 100644 index 00000000..f0f17868 --- /dev/null +++ b/docs/resources/git_trigger.md @@ -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 = "" + include_file_paths = ["include/me", "include/me/too"] + exclude_file_paths = ["exclude/me", "exclude/me/too"] + } +} +``` + + +## 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)) +- `space_id` (String) The space ID associated with the project to attach the trigger. + +### Read-Only + +- `id` (String) The ID of this resource. + + +### 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. +``` diff --git a/examples/resources/octopusdeploy_git_trigger/import.sh b/examples/resources/octopusdeploy_git_trigger/import.sh new file mode 100644 index 00000000..38f0466b --- /dev/null +++ b/examples/resources/octopusdeploy_git_trigger/import.sh @@ -0,0 +1 @@ +terraform import [options] octopusdeploy_git_trigger. \ No newline at end of file diff --git a/examples/resources/octopusdeploy_git_trigger/resource.tf b/examples/resources/octopusdeploy_git_trigger/resource.tf new file mode 100644 index 00000000..bed9184d --- /dev/null +++ b/examples/resources/octopusdeploy_git_trigger/resource.tf @@ -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"] + exclude_file_paths = ["exclude/me", "exclude/me/too"] + } +} diff --git a/go.mod b/go.mod index 8dcc68c2..b7605719 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 7a39471c..996851f8 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go index 58a85a55..362bfcb7 100644 --- a/octopusdeploy/provider.go +++ b/octopusdeploy/provider.go @@ -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(), diff --git a/octopusdeploy/resource_git_trigger.go b/octopusdeploy/resource_git_trigger.go new file mode 100644 index 00000000..6aa51ce7 --- /dev/null +++ b/octopusdeploy/resource_git_trigger.go @@ -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 +} diff --git a/octopusdeploy/schema_git_trigger.go b/octopusdeploy/schema_git_trigger.go new file mode 100644 index 00000000..2b83dbd7 --- /dev/null +++ b/octopusdeploy/schema_git_trigger.go @@ -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, + }, + } +} diff --git a/octopusdeploy/schema_git_trigger_source_package.go b/octopusdeploy/schema_git_trigger_source_package.go new file mode 100644 index 00000000..60a9fe5a --- /dev/null +++ b/octopusdeploy/schema_git_trigger_source_package.go @@ -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}, + }, + } +}