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 trigger functionality #835

Merged
merged 1 commit into from
Dec 9, 2024
Merged
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
45 changes: 45 additions & 0 deletions docs/resources/git_trigger.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "octopusdeploy_git_trigger Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
This resource manages Git triggers in Octopus Deploy
---

# octopusdeploy_git_trigger (Resource)

This resource manages Git triggers in Octopus Deploy



<!-- 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.
- `sources` (Attributes List) (see [below for nested schema](#nestedatt--sources))

### Optional

- `description` (String) The description of this Git trigger..
- `is_disabled` (Boolean) Disables the trigger from being run when set.
- `space_id` (String) The space ID associated with this Git trigger.

### Read-Only

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

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

Required:

- `deployment_action_slug` (String) The deployment action slug.
- `exclude_file_paths` (List of String) The file paths to exclude.
- `git_dependency_name` (String) The git dependency name.
- `include_file_paths` (List of String) The file paths to include.


1 change: 1 addition & 0 deletions octopusdeploy_framework/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewServiceAccountOIDCIdentity,
NewGenericOidcResource,
NewDeploymentFreezeTenantResource,
NewGitTriggerResource,
}
}

Expand Down
240 changes: 240 additions & 0 deletions octopusdeploy_framework/resource_git_trigger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package octopusdeploy_framework

import (
"context"
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/actions"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/filters"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/triggers"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

type gitTriggerResource struct {
*Config
}

func NewGitTriggerResource() resource.Resource {
return &gitTriggerResource{}
}

var _ resource.ResourceWithImportState = &gitTriggerResource{}

func (r *gitTriggerResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = util.GetTypeName("git_trigger")
}

func (r *gitTriggerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schemas.GitTriggerSchema{}.GetResourceSchema()
}

func (r *gitTriggerResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
r.Config = ResourceConfiguration(req, resp)
}

func (r *gitTriggerResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

func (r *gitTriggerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *schemas.GitTriggerResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

gitTriggerSources := convertListToGitTriggerSources(data.Sources)

action := actions.NewCreateReleaseAction(data.ChannelId.ValueString())
filter := filters.NewGitTriggerFilter(gitTriggerSources)

client := r.Config.Client

project, err := projects.GetByID(client, data.SpaceId.ValueString(), data.ProjectId.ValueString())

if err != nil {
resp.Diagnostics.AddError("error finding project", err.Error())
return
}

tflog.Info(ctx, fmt.Sprintf("creating Git trigger: %s", data.Name.ValueString()))

projectTrigger := triggers.NewProjectTrigger(data.Name.ValueString(), data.Description.ValueString(), data.IsDisabled.ValueBool(), project, action, filter)

createdGitTrigger, err := client.ProjectTriggers.Add(projectTrigger)

if err != nil {
resp.Diagnostics.AddError("unable to create Git trigger", err.Error())
return
}

data.ID = types.StringValue(createdGitTrigger.GetID())
data.Name = types.StringValue(createdGitTrigger.Name)
data.ProjectId = types.StringValue(createdGitTrigger.ProjectID)
data.SpaceId = types.StringValue(createdGitTrigger.SpaceID)
data.IsDisabled = types.BoolValue(createdGitTrigger.IsDisabled)
data.Sources = convertGitTriggerSourcesToList(createdGitTrigger.Filter.(*filters.GitTriggerFilter).Sources)

tflog.Info(ctx, fmt.Sprintf("Git trigger created (%s)", data.ID))
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *gitTriggerResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *schemas.GitTriggerResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Info(ctx, fmt.Sprintf("reading Git Trigger (%s)", data.ID))

client := r.Config.Client

gitTrigger, err := client.ProjectTriggers.GetByID(data.ID.ValueString())
if err != nil {
if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "error retrieving Git Trigger"); err != nil {
resp.Diagnostics.AddError("unable to load Git Trigger", err.Error())
}
return
}

data.ID = types.StringValue(gitTrigger.GetID())
data.Name = types.StringValue(gitTrigger.Name)
data.ProjectId = types.StringValue(gitTrigger.ProjectID)
data.SpaceId = types.StringValue(gitTrigger.SpaceID)
data.IsDisabled = types.BoolValue(gitTrigger.IsDisabled)
data.Sources = convertGitTriggerSourcesToList(gitTrigger.Filter.(*filters.GitTriggerFilter).Sources)

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *gitTriggerResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data, state *schemas.GitTriggerResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Debug(ctx, fmt.Sprintf("updating Git Trigger '%s'", data.ID.ValueString()))

client := r.Config.Client

gitTrigger, err := client.ProjectTriggers.GetByID(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("unable to load Git Trigger", err.Error())
return
}

gitTriggerSources := convertListToGitTriggerSources(data.Sources)
action := actions.NewCreateReleaseAction(data.ChannelId.ValueString())
filter := filters.NewGitTriggerFilter(gitTriggerSources)
project, err := projects.GetByID(client, data.SpaceId.ValueString(), data.ProjectId.ValueString())

if err != nil {
resp.Diagnostics.AddError("error finding project", err.Error())
return
}

updatedGitTrigger := triggers.NewProjectTrigger(data.Name.ValueString(), data.Description.ValueString(), data.IsDisabled.ValueBool(), project, action, filter)
updatedGitTrigger.ID = gitTrigger.ID

updatedGitTrigger, err = client.ProjectTriggers.Update(updatedGitTrigger)
tflog.Info(ctx, fmt.Sprintf("Git Trigger updated (%s)", data.ID))

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *gitTriggerResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data schemas.GitTriggerResourceModel

resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

client := r.Config.Client

if err := client.ProjectTriggers.DeleteByID(data.ID.ValueString()); err != nil {
resp.Diagnostics.AddError("unable to delete Git Trigger", err.Error())
return
}
}

func convertListToGitTriggerSources(list types.List) []filters.GitTriggerSource {
var gitTriggerSources []filters.GitTriggerSource

for _, elem := range list.Elements() {
obj := elem.(types.Object)
attrs := obj.Attributes()

deploymentActionSlug := attrs["deployment_action_slug"].(types.String).ValueString()
gitDependencyName := attrs["git_dependency_name"].(types.String).ValueString()
includeFilePaths := convertToStringSlice(attrs["include_file_paths"].(types.List))
excludeFilePaths := convertToStringSlice(attrs["exclude_file_paths"].(types.List))

gitTriggerSource := filters.GitTriggerSource{
DeploymentActionSlug: deploymentActionSlug,
GitDependencyName: gitDependencyName,
IncludeFilePaths: includeFilePaths,
ExcludeFilePaths: excludeFilePaths,
}

gitTriggerSources = append(gitTriggerSources, gitTriggerSource)
}

return gitTriggerSources
}

func convertToStringSlice(list types.List) []string {
var result []string
for _, elem := range list.Elements() {
result = append(result, elem.(types.String).ValueString())
}
return result
}

func convertGitTriggerSourcesToList(gitTriggerSources []filters.GitTriggerSource) types.List {
var elements []attr.Value

for _, source := range gitTriggerSources {
attributes := map[string]attr.Value{
"deployment_action_slug": types.StringValue(source.DeploymentActionSlug),
"git_dependency_name": types.StringValue(source.GitDependencyName),
"include_file_paths": convertStringSliceToList(source.IncludeFilePaths),
"exclude_file_paths": convertStringSliceToList(source.ExcludeFilePaths),
}
objectValue, _ := types.ObjectValue(sourcesObjectType(), attributes)
elements = append(elements, objectValue)
}

listValue, _ := types.ListValue(types.ObjectType{AttrTypes: sourcesObjectType()}, elements)
return listValue
}

func convertStringSliceToList(strings []string) types.List {
var elements []attr.Value

for _, str := range strings {
elements = append(elements, types.StringValue(str))
}

listValue, _ := types.ListValue(types.StringType, elements)
return listValue
}

func sourcesObjectType() map[string]attr.Type {
return map[string]attr.Type{
"deployment_action_slug": types.StringType,
"git_dependency_name": types.StringType,
"include_file_paths": types.ListType{ElemType: types.StringType},
"exclude_file_paths": types.ListType{ElemType: types.StringType},
}
}
Loading
Loading