From f2e3a750cea202b3fe7cef639db7e47be8cacd6e Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Sat, 10 May 2025 00:57:55 +0200 Subject: [PATCH] feat(provider): add organizations data-source --- CHANGELOG.md | 1 + docs/data-sources/organizations.md | 40 ++++++ .../forgejo_organizations/data-source.tf | 1 + internal/client/organizations.go | 35 +++++ .../provider/organizations_data_source.go | 129 ++++++++++++++++++ internal/provider/provider.go | 1 + 6 files changed, 207 insertions(+) create mode 100644 docs/data-sources/organizations.md create mode 100644 examples/data-sources/forgejo_organizations/data-source.tf create mode 100644 internal/client/organizations.go create mode 100644 internal/provider/organizations_data_source.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 955ad70..fe771b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,4 +7,5 @@ All notable changes to this project will be documented in this file. ### Added - Added provider configuration. +- Added organizations data-source. - Added users data-source. diff --git a/docs/data-sources/organizations.md b/docs/data-sources/organizations.md new file mode 100644 index 0000000..7f0e567 --- /dev/null +++ b/docs/data-sources/organizations.md @@ -0,0 +1,40 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "forgejo_organizations Data Source - terraform-provider-forgejo" +subcategory: "" +description: |- + Use this data source to retrieve information about existing forgejo organizations. +--- + +# forgejo_organizations (Data Source) + +Use this data source to retrieve information about existing forgejo organizations. + +## Example Usage + +```terraform +data "forgejo_organizations" "example" {} +``` + + +## Schema + +### Read-Only + +- `elements` (Attributes List) The list of organizations. (see [below for nested schema](#nestedatt--elements)) + + +### Nested Schema for `elements` + +Read-Only: + +- `avatar_url` (String) The organization's avatar URL. +- `description` (String) A description string. +- `email` (String) The organization's email address. +- `full_name` (String) The organization's full name. +- `id` (Number) The identifier of the organization. +- `location` (String) The organization's advertised location. +- `name` (String) The name of the organization. +- `repo_admin_change_team_access` (Boolean) Whether an admin of a repository that belongs to this organization can change team access or not. +- `visibility` (String) The organization's visibility option: limited, private, public. +- `website` (String) The organization's advertised website. diff --git a/examples/data-sources/forgejo_organizations/data-source.tf b/examples/data-sources/forgejo_organizations/data-source.tf new file mode 100644 index 0000000..5a352e4 --- /dev/null +++ b/examples/data-sources/forgejo_organizations/data-source.tf @@ -0,0 +1 @@ +data "forgejo_organizations" "example" {} diff --git a/internal/client/organizations.go b/internal/client/organizations.go new file mode 100644 index 0000000..a3acb17 --- /dev/null +++ b/internal/client/organizations.go @@ -0,0 +1,35 @@ +package client + +import ( + "context" + "fmt" + "net/url" +) + +type Organization struct { + AvatarUrl string `json:"avatar_url"` + Description string `json:"description"` + Email string `json:"email"` + FullName string `json:"full_name"` + Id int64 `json:"id"` + Location string `json:"location"` + Name string `json:"name"` + RepoAdminChangeTeamAccess bool `json:"repo_admin_change_team_access"` + Visibility string `json:"visibility"` + Website string `json:"website"` +} + +func (c *Client) OrganizationsList(ctx context.Context) ([]Organization, error) { + var response []Organization + query := make(url.Values) + query.Set("limit", "50") + query.Set("page", "1") + uriRef := url.URL{ + Path: "api/v1/orgs", + RawQuery: query.Encode(), + } + if err := c.Send(ctx, "GET", &uriRef, nil, &response); err != nil { + return nil, fmt.Errorf("failed to get organizations: %w", err) + } + return response, nil +} diff --git a/internal/provider/organizations_data_source.go b/internal/provider/organizations_data_source.go new file mode 100644 index 0000000..c031364 --- /dev/null +++ b/internal/provider/organizations_data_source.go @@ -0,0 +1,129 @@ +package provider + +import ( + "context" + "fmt" + + "git.adyxax.org/adyxax/terraform-provider-forgejo/internal/client" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type OrganizationsDataSource struct { + client *client.Client +} + +var _ datasource.DataSource = &OrganizationsDataSource{} // Ensure provider defined types fully satisfy framework interfaces +func NewOrganizationsDataSource() datasource.DataSource { + return &OrganizationsDataSource{} +} + +type OrganizationsDataSourceModel struct { + Elements []OrganizationDataSourceModel `tfsdk:"elements"` +} +type OrganizationDataSourceModel struct { + AvatarUrl types.String `tfsdk:"avatar_url"` + Description types.String `tfsdk:"description"` + Email types.String `tfsdk:"email"` + FullName types.String `tfsdk:"full_name"` + Id types.Int64 `tfsdk:"id"` + Location types.String `tfsdk:"location"` + Name types.String `tfsdk:"name"` + RepoAdminChangeTeamAccess types.Bool `tfsdk:"repo_admin_change_team_access"` + Visibility types.String `tfsdk:"visibility"` + Website types.String `tfsdk:"website"` +} + +func (d *OrganizationsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_organizations" +} + +func (d *OrganizationsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "elements": schema.ListNestedAttribute{ + Computed: true, + MarkdownDescription: "The list of organizations.", + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "avatar_url": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The organization's avatar URL.", + }, + "description": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "A description string.", + }, + "email": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The organization's email address.", + }, + "full_name": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The organization's full name.", + }, + "id": schema.Int64Attribute{ + Computed: true, + MarkdownDescription: "The identifier of the organization.", + }, + "location": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The organization's advertised location.", + }, + "name": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The name of the organization.", + }, + "repo_admin_change_team_access": schema.BoolAttribute{ + Computed: true, + MarkdownDescription: "Whether an admin of a repository that belongs to this organization can change team access or not.", + }, + "visibility": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The organization's visibility option: limited, private, public.", + }, + "website": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "The organization's advertised website.", + }, + }, + }, + }, + }, + MarkdownDescription: "Use this data source to retrieve information about existing forgejo organizations.", + } +} + +func (d *OrganizationsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + d.client, _ = req.ProviderData.(*client.Client) +} + +func (d *OrganizationsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data OrganizationsDataSourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + organizations, err := d.client.OrganizationsList(ctx) + if err != nil { + resp.Diagnostics.AddError("ListOrganizations", fmt.Sprintf("Unable to list organizations, got error: %s", err)) + return + } + organizationList := make([]OrganizationDataSourceModel, len(organizations)) + for i, organization := range organizations { + organizationList[i] = OrganizationDataSourceModel{ + AvatarUrl: types.StringValue(organization.AvatarUrl), + Description: types.StringValue(organization.Description), + Email: types.StringValue(organization.Email), + Id: types.Int64Value(organization.Id), + Location: types.StringValue(organization.Location), + Name: types.StringValue(organization.Name), + RepoAdminChangeTeamAccess: types.BoolValue(organization.RepoAdminChangeTeamAccess), + Visibility: types.StringValue(organization.Visibility), + Website: types.StringValue(organization.Website), + } + } + data.Elements = organizationList + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 55b5847..90dcb0c 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -80,6 +80,7 @@ func (p *Provider) Resources(ctx context.Context) []func() resource.Resource { func (p *Provider) DataSources(ctx context.Context) []func() datasource.DataSource { return []func() datasource.DataSource{ + NewOrganizationsDataSource, NewUsersDataSource, } }