Skip to content

Commit

Permalink
feat: project versioning strategy resource
Browse files Browse the repository at this point in the history
  • Loading branch information
domenicsim1 committed Dec 4, 2024
1 parent e709e02 commit 8e294e4
Show file tree
Hide file tree
Showing 4 changed files with 221 additions and 1 deletion.
1 change: 1 addition & 0 deletions octopusdeploy_framework/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewLibraryVariableSetFeedResource,
NewVariableResource,
NewProjectResource,
NewProjectVersioningStrategyResource,
NewMachineProxyResource,
NewTagResource,
NewDockerContainerRegistryFeedResource,
Expand Down
148 changes: 148 additions & 0 deletions octopusdeploy_framework/resource_project_versioning_strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package octopusdeploy_framework

import (
"context"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/packages"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"log"
"net/http"
)

var _ resource.Resource = &projectVersioningStrategyResource{}

type projectVersioningStrategyResource struct {
*Config
}

func NewProjectVersioningStrategyResource() resource.Resource {
return &projectVersioningStrategyResource{}
}

func (r *projectVersioningStrategyResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = util.GetTypeName(schemas.ProjectVersioningStrategyResourceName)
}

func (r *projectVersioningStrategyResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schemas.ProjectVersioningStrategySchema{}.GetResourceSchema()
}

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

func (r *projectVersioningStrategyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan projectResourceModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

}

func (r *projectVersioningStrategyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state schemas.ProjectVersioningStrategyModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

project, err := projects.GetByID(r.Client, state.SpaceID.ValueString(), state.ProjectID.ValueString())
if err != nil {
if apiError, ok := err.(*core.APIError); ok {
if apiError.StatusCode == http.StatusNotFound {
log.Printf("[INFO] associated project (%s) not found; deleting version strategy from state", state.ProjectID.ValueString())
resp.State.RemoveResource(ctx)
}
} else {
resp.Diagnostics.AddError("Failed to read associated project", err.Error())
}
return
}
mapProjectVersioningStrategyToState(project.VersioningStrategy, &state)

resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
}

func (r *projectVersioningStrategyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan schemas.ProjectVersioningStrategyModel
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

existingProject, err := projects.GetByID(r.Client, plan.SpaceID.ValueString(), plan.ProjectID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Error retrieving associated project", err.Error())
return
}

versioningStrategy := mapStateToProjectVersioningStrategy(&plan)
existingProject.VersioningStrategy = versioningStrategy

updatedProject, err := projects.Update(r.Client, existingProject)
if err != nil {
resp.Diagnostics.AddError("Error updating associated project", err.Error())
return
}

mapProjectVersioningStrategyToState(updatedProject.VersioningStrategy, &plan)
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
}

func (r *projectVersioningStrategyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var state schemas.ProjectVersioningStrategyModel
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

project, err := projects.GetByID(r.Client, state.SpaceID.ValueString(), state.ProjectID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Error retrieving project", err.Error())
return
}

project.VersioningStrategy = &projects.VersioningStrategy{}
_, err = projects.Update(r.Client, project)
if err != nil {
resp.Diagnostics.AddError("Error updating project to remove versioning strategy", err.Error())
return
}

resp.State.RemoveResource(ctx)
}

func mapStateToProjectVersioningStrategy(state *schemas.ProjectVersioningStrategyModel) *projects.VersioningStrategy {
var donorPackageStepID *string
donorPackageStepIDString := state.DonorPackageStepID.ValueString()
if donorPackageStepIDString != "" {
donorPackageStepID = &donorPackageStepIDString
}

return &projects.VersioningStrategy{
Template: state.Template.ValueString(),
DonorPackageStepID: donorPackageStepID,
DonorPackage: &packages.DeploymentActionPackage{
DeploymentAction: state.DonorPackage.DeploymentAction.ValueString(),
PackageReference: state.DonorPackage.PackageReference.ValueString(),
},
}
}

func mapProjectVersioningStrategyToState(versioningStrategy *projects.VersioningStrategy, state *schemas.ProjectVersioningStrategyModel) {
if versioningStrategy.DonorPackageStepID != nil {
state.DonorPackageStepID = types.StringValue(*versioningStrategy.DonorPackageStepID)
}
state.Template = types.StringValue(versioningStrategy.Template)
state.DonorPackage.PackageReference = types.StringValue(versioningStrategy.DonorPackage.PackageReference)
state.DonorPackage.DeploymentAction = types.StringValue(versioningStrategy.DonorPackage.DeploymentAction)
}
2 changes: 1 addition & 1 deletion octopusdeploy_framework/schemas/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ func (p ProjectSchema) GetResourceSchema() resourceSchema.Schema {
},
},
"versioning_strategy": resourceSchema.ListNestedBlock{
DeprecationMessage: "versioning_strategy is deprecated in favor of resource project_versioning strategy",
NestedObject: resourceSchema.NestedBlockObject{

Attributes: map[string]resourceSchema.Attribute{
"donor_package_step_id": util.ResourceString().Optional().Build(),
"template": util.ResourceString().Optional().Computed().Build(),
Expand Down
71 changes: 71 additions & 0 deletions octopusdeploy_framework/schemas/project_versioning_strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package schemas

import (
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type ProjectVersioningStrategySchema struct{}

var _ EntitySchema = ProjectVersioningStrategySchema{}

const ProjectVersioningStrategyResourceName = "project_versioning_strategy"

func (p ProjectVersioningStrategySchema) GetResourceSchema() resourceSchema.Schema {
return resourceSchema.Schema{
Attributes: map[string]resourceSchema.Attribute{
"project_id": util.ResourceString().
Description("The associated project ID.").
PlanModifiers(stringplanmodifier.RequiresReplace()).
Required().
Build(),
"space_id": util.ResourceString().
Description("Space ID of the associated project.").
Required().
Build(),
"donor_package_step_id": util.ResourceString().
Description("The associated donor package step ID.").
Optional().
Build(),
"template": util.ResourceString().
Optional().
Computed().
Build(),
"donor_package": resourceSchema.SingleNestedAttribute{
Required: true,
Description: "Donor Packages.",
Attributes: map[string]resourceSchema.Attribute{
"deployment_action": util.ResourceString().
Description("Deployment action.").
Optional().
Build(),
"package_reference": util.ResourceString().
Description("Package reference.").
Optional().
Build(),
},
},
},
}
}

func (p ProjectVersioningStrategySchema) GetDatasourceSchema() datasourceSchema.Schema {
// no datasource required, returned as part of project datasource
return datasourceSchema.Schema{}
}

type ProjectVersioningStrategyModel struct {
ProjectID types.String `tfsdk:"project_id"`
SpaceID types.String `tfsdk:"space_id"`
DonorPackageStepID types.String `tfsdk:"donor_package_step_id"`
Template types.String `tfsdk:"template"`
DonorPackage DonorPackageModel `tfsdk:"donor_package"`
}

type DonorPackageModel struct {
DeploymentAction types.String `tfsdk:"deployment_action"`
PackageReference types.String `tfsdk:"package_reference"`
}

0 comments on commit 8e294e4

Please sign in to comment.