internal/provider/resource_gitlab_group_badge.go (204 lines of code) (raw):
package provider
import (
"context"
"fmt"
"strconv"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
gitlab "gitlab.com/gitlab-org/api/client-go"
"gitlab.com/gitlab-org/terraform-provider-gitlab/internal/provider/api"
"gitlab.com/gitlab-org/terraform-provider-gitlab/internal/provider/utils"
)
var (
_ resource.Resource = &gitlabGroupBadgeResource{}
_ resource.ResourceWithConfigure = &gitlabGroupBadgeResource{}
_ resource.ResourceWithImportState = &gitlabGroupBadgeResource{}
)
func init() {
registerResource(NewGitLabGroupBadgeResource)
}
// NewGitLabGroupBadgeResource is a helper function to simplify the provider implementation.
func NewGitLabGroupBadgeResource() resource.Resource {
return &gitlabGroupBadgeResource{}
}
type gitlabGroupBadgeResourceModel struct {
ID types.String `tfsdk:"id"`
Group types.String `tfsdk:"group"`
LinkURL types.String `tfsdk:"link_url"`
ImageURL types.String `tfsdk:"image_url"`
Name types.String `tfsdk:"name"`
RenderedLinkURL types.String `tfsdk:"rendered_link_url"`
RenderedImageURL types.String `tfsdk:"rendered_image_url"`
}
type gitlabGroupBadgeResource struct {
client *gitlab.Client
}
func (r *gitlabGroupBadgeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_group_badge"
}
func (r *gitlabGroupBadgeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: `The ` + "`gitlab_group_badge`" + ` resource allows to manage the lifecycle of group badges.
**Upstream API**: [GitLab REST API docs](https://docs.gitlab.com/user/project/badges/#group-badges)`,
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "The ID of this Terraform resource. In the format of `<group-id>:<badge-id>`.",
Computed: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
},
"group": schema.StringAttribute{
MarkdownDescription: "The ID or URL-encoded path of the group to add the badge to.",
Required: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"link_url": schema.StringAttribute{
MarkdownDescription: "The url linked with the badge.",
Required: true,
},
"image_url": schema.StringAttribute{
MarkdownDescription: "The image url which will be presented on group overview.",
Required: true,
},
"name": schema.StringAttribute{
MarkdownDescription: "The name of the badge.",
Optional: true,
Computed: true,
},
"rendered_link_url": schema.StringAttribute{
MarkdownDescription: "The link_url argument rendered (in case of use of placeholders).",
Computed: true,
},
"rendered_image_url": schema.StringAttribute{
MarkdownDescription: "The image_url argument rendered (in case of use of placeholders).",
Computed: true,
},
},
}
}
func (r *gitlabGroupBadgeResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}
resourceData := req.ProviderData.(*GitLabResourceData)
r.client = resourceData.Client
}
// ImportState imports the resource into the Terraform state.
func (r *gitlabGroupBadgeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
func (r *gitlabGroupBadgeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data *gitlabGroupBadgeResourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
group := data.Group.ValueString()
options := &gitlab.AddGroupBadgeOptions{
LinkURL: gitlab.Ptr(data.LinkURL.ValueString()),
ImageURL: gitlab.Ptr(data.ImageURL.ValueString()),
}
if !data.Name.IsNull() && !data.Name.IsUnknown() {
options.Name = gitlab.Ptr(data.Name.ValueString())
}
badge, _, err := r.client.GroupBadges.AddGroupBadge(group, options, gitlab.WithContext(ctx))
if err != nil {
resp.Diagnostics.AddError("GitLab API error occured", fmt.Sprintf("Unable to create group badge: %s", err.Error()))
return
}
badgeID := strconv.Itoa(badge.ID)
data.ID = types.StringValue(utils.BuildTwoPartID(&group, &badgeID))
data.modelToStateModel(badge, group)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r *gitlabGroupBadgeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data *gitlabGroupBadgeResourceModel
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
group, badgeID, err := data.ResourceGitlabGroupBadgeParseID(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Failed to read resource ID", fmt.Sprintf("Unable to parse resource ID: %s, %s", data.ID.ValueString(), err.Error()))
return
}
badge, _, err := r.client.GroupBadges.GetGroupBadge(group, badgeID, gitlab.WithContext(ctx))
if err != nil {
if api.Is404(err) {
resp.Diagnostics.AddWarning("GitLab API error occured", fmt.Sprintf("Group badge doesn't exist anymore, removing from state: %s", err.Error()))
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError("GitLab API error occured", fmt.Sprintf("Unable to get group badge: %s", err.Error()))
return
}
data.modelToStateModel(badge, group)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r *gitlabGroupBadgeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data *gitlabGroupBadgeResourceModel
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// Parse the resource ID to get group and badge IDs
group, badgeID, err := data.ResourceGitlabGroupBadgeParseID(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Failed to read resource ID", fmt.Sprintf("Unable to parse resource ID: %s, %s", data.ID.ValueString(), err.Error()))
return
}
options := &gitlab.EditGroupBadgeOptions{
LinkURL: gitlab.Ptr(data.LinkURL.ValueString()),
ImageURL: gitlab.Ptr(data.ImageURL.ValueString()),
}
if !data.Name.IsNull() && !data.Name.IsUnknown() {
options.Name = gitlab.Ptr(data.Name.ValueString())
}
badge, _, err := r.client.GroupBadges.EditGroupBadge(group, badgeID, options, gitlab.WithContext(ctx))
if err != nil {
resp.Diagnostics.AddError("GitLab API error occured", fmt.Sprintf("Unable to update group badge: %s", err.Error()))
return
}
data.modelToStateModel(badge, group)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
func (r *gitlabGroupBadgeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data *gitlabGroupBadgeResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
// Parse the resource ID to get group and badge IDs
group, badgeID, err := data.ResourceGitlabGroupBadgeParseID(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Failed to read resource ID", fmt.Sprintf("Unable to parse resource ID: %s, %s", data.ID.ValueString(), err.Error()))
return
}
_, err = r.client.GroupBadges.DeleteGroupBadge(group, badgeID, gitlab.WithContext(ctx))
if err != nil {
resp.Diagnostics.AddError("GitLab API error occured", fmt.Sprintf("Unable to delete group badge: %s", err.Error()))
return
}
resp.State.RemoveResource(ctx)
}
func (r *gitlabGroupBadgeResourceModel) modelToStateModel(b *gitlab.GroupBadge, group string) {
r.Group = types.StringValue(group)
r.LinkURL = types.StringValue(b.LinkURL)
r.ImageURL = types.StringValue(b.ImageURL)
r.Name = types.StringValue(b.Name)
r.RenderedLinkURL = types.StringValue(b.RenderedLinkURL)
r.RenderedImageURL = types.StringValue(b.RenderedImageURL)
}
func (d *gitlabGroupBadgeResourceModel) ResourceGitlabGroupBadgeParseID(id string) (string, int, error) {
group, rawBadgeId, err := utils.ParseTwoPartID(id)
if err != nil {
return "", 0, err
}
badgeId, err := strconv.Atoi(rawBadgeId)
if err != nil {
return "", 0, err
}
return group, badgeId, nil
}