diff --git a/CHANGELOG.md b/CHANGELOG.md index 747a568..7c2f058 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,5 +9,6 @@ All notable changes to this project will be documented in this file. - Added provider configuration. - Added organizations data-source. - Added repositories data-source. +- Added repository actions secret resource. - Added teams data-source. - Added users data-source. diff --git a/docs/resources/repository_actions_secret.md b/docs/resources/repository_actions_secret.md new file mode 100644 index 0000000..1719661 --- /dev/null +++ b/docs/resources/repository_actions_secret.md @@ -0,0 +1,36 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "forgejo_repository_actions_secret Resource - terraform-provider-forgejo" +subcategory: "" +description: |- + Use this resource to create and manage a repository actions secret. +--- + +# forgejo_repository_actions_secret (Resource) + +Use this resource to create and manage a repository actions secret. + +## Example Usage + +```terraform +resource "forgejo_repository_actions_secret" { + data = "secret" + name = "test" + owner = "adyxax" + repository = "example" +} +``` + + +## Schema + +### Required + +- `data` (String, Sensitive) The secret's data. +- `name` (String) The secret's name. +- `owner` (String) The secret's owner. +- `repository` (String) The secret's repository. + +### Read-Only + +- `created_at` (String) The secret's creation date and time. diff --git a/examples/resources/forgejo_repository_actions_secret/resource.tf b/examples/resources/forgejo_repository_actions_secret/resource.tf new file mode 100644 index 0000000..aa53e60 --- /dev/null +++ b/examples/resources/forgejo_repository_actions_secret/resource.tf @@ -0,0 +1,6 @@ +resource "forgejo_repository_actions_secret" { + data = "secret" + name = "test" + owner = "adyxax" + repository = "example" +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 7ac274f..89da0af 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -75,7 +75,9 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest, } func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { - return []func() resource.Resource{} + return []func() resource.Resource{ + NewRepositoryActionsSecretResource, + } } func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSource { diff --git a/internal/provider/repository_actions_secret_resource.go b/internal/provider/repository_actions_secret_resource.go new file mode 100644 index 0000000..73650a7 --- /dev/null +++ b/internal/provider/repository_actions_secret_resource.go @@ -0,0 +1,183 @@ +package provider + +import ( + "context" + "fmt" + "strings" + + "git.adyxax.org/adyxax/terraform-provider-forgejo/internal/client" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "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/types" +) + +type RepositoryActionsSecretResource struct { + client *client.Client +} + +var _ resource.Resource = &RepositoryActionsSecretResource{} // Ensure provider defined types fully satisfy framework interfaces +func NewRepositoryActionsSecretResource() resource.Resource { + return &RepositoryActionsSecretResource{} +} + +type RepositoryActionsSecretResourceModel struct { + CreatedAt timetypes.RFC3339 `tfsdk:"created_at"` + Data types.String `tfsdk:"data"` + Name types.String `tfsdk:"name"` + Owner types.String `tfsdk:"owner"` + Repository types.String `tfsdk:"repository"` +} + +func (d *RepositoryActionsSecretResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_repository_actions_secret" +} + +func (d *RepositoryActionsSecretResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "created_at": schema.StringAttribute{ + Computed: true, + CustomType: timetypes.RFC3339Type{}, + MarkdownDescription: "The secret's creation date and time.", + }, + "data": schema.StringAttribute{ + MarkdownDescription: "The secret's data.", + Required: true, + Sensitive: true, + }, + "name": schema.StringAttribute{ + MarkdownDescription: "The secret's name.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Required: true, + }, + "owner": schema.StringAttribute{ + MarkdownDescription: "The secret's owner.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Required: true, + }, + "repository": schema.StringAttribute{ + MarkdownDescription: "The secret's repository.", + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Required: true, + }, + }, + MarkdownDescription: "Use this resource to create and manage a repository actions secret.", + } +} + +func (d *RepositoryActionsSecretResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + d.client, _ = req.ProviderData.(*client.Client) +} + +func (d *RepositoryActionsSecretResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data RepositoryActionsSecretResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + err := d.client.RepoActionSecretPut( + ctx, + data.Owner.ValueString(), + data.Repository.ValueString(), + data.Name.ValueString(), + data.Data.ValueString()) + if err != nil { + resp.Diagnostics.AddError("CreateRepositoryActionsSecret", fmt.Sprintf("failed to put repository actions secret: %s", err)) + return + } + created, err := d.getRepositoryActionsSecret(ctx, data.Owner, data.Repository, data.Name) + if err != nil { + resp.Diagnostics.AddError("CreateRepositoryActionsSecret", err.Error()) + return + } + data.CreatedAt = *created + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (d *RepositoryActionsSecretResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data RepositoryActionsSecretResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + err := d.client.RepoActionSecretDelete( + ctx, + data.Owner.ValueString(), + data.Repository.ValueString(), + data.Name.ValueString()) + if err != nil { + resp.Diagnostics.AddError("DeleteRepositoryActionsSecret", fmt.Sprintf("failed to delete repository actions secret: %s", err)) + return + } +} + +func (d *RepositoryActionsSecretResource) getRepositoryActionsSecret( + ctx context.Context, + owner types.String, + repository types.String, + name types.String, +) (*timetypes.RFC3339, error) { + secrets, err := d.client.RepoActionSecretsList( + ctx, + owner.ValueString(), + repository.ValueString()) + if err != nil { + return nil, fmt.Errorf("failed to list repository actions secrets: %w", err) + } + nameStr := strings.ToUpper(name.ValueString()) + for _, secret := range secrets { + if secret.Name == nameStr { + created := timetypes.NewRFC3339TimeValue(secret.CreatedAt) + return &created, nil + } + } + return nil, fmt.Errorf("failed to find repository actions secret") +} + +func (d *RepositoryActionsSecretResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data RepositoryActionsSecretResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + created, err := d.getRepositoryActionsSecret(ctx, data.Owner, data.Repository, data.Name) + if err != nil { + resp.Diagnostics.AddError("CreateRepositoryActionsSecret", err.Error()) + return + } + data.CreatedAt = *created + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (d *RepositoryActionsSecretResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data RepositoryActionsSecretResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + err := d.client.RepoActionSecretPut( + ctx, + data.Owner.ValueString(), + data.Repository.ValueString(), + data.Name.ValueString(), + data.Data.ValueString()) + if err != nil { + resp.Diagnostics.AddError("UpdateRepositoryActionsSecret", fmt.Sprintf("failed to put repository actions secret: %s", err)) + return + } + created, err := d.getRepositoryActionsSecret(ctx, data.Owner, data.Repository, data.Name) + if err != nil { + resp.Diagnostics.AddError("UpdateRepositoryActionsSecret", err.Error()) + return + } + data.CreatedAt = *created +}