terraform-provider-woodpecker/internal/provider.go

213 lines
5.5 KiB
Go

package internal
import (
"context"
"fmt"
"os"
"strings"
"github.com/Kichiyaki/terraform-provider-woodpecker/internal/woodpecker"
"github.com/Masterminds/semver/v3"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"golang.org/x/oauth2"
)
const importStateIDSeparator = "/"
type woodpeckerProvider struct {
version string
}
var _ provider.Provider = (*woodpeckerProvider)(nil)
func NewProvider(version string) func() provider.Provider {
return func() provider.Provider {
return &woodpeckerProvider{
version: version,
}
}
}
func (p *woodpeckerProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "woodpecker"
resp.Version = p.version
}
func (p *woodpeckerProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "A Terraform provider used to interact with" +
" [Woodpecker CI](https://woodpecker-ci.org/) resources." +
"\n\n\n- v0.2.x and later versions of the provider work with Woodpecker 2.x+" +
"\n- v0.1.x version of the provider works with Woodpecker 2.0.0>1.x>=1.0.0",
Attributes: map[string]schema.Attribute{
"server": schema.StringAttribute{
Optional: true,
Description: `This is the target Woodpecker CI base API endpoint. It must be provided, but
can also be sourced from the WOODPECKER_SERVER environment
variable.`,
},
"token": schema.StringAttribute{
Optional: true,
Description: `A Woodpecker CI Personal Access Token. It must be provided, but
can also be sourced from the WOODPECKER_TOKEN environment
variable.`,
},
},
}
}
func (p *woodpeckerProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
newUserDataSource,
newSecretDataSource,
newRepositoryDataSource,
newRepositorySecretDataSource,
newRepositoryCronDataSource,
newRepositoryRegistryDataSource,
}
}
func (p *woodpeckerProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
newUserResource,
newSecretResource,
newRepositoryResource,
newRepositorySecretResource,
newRepositoryCronResource,
newRepositoryRegistryResource,
}
}
func (p *woodpeckerProvider) Configure(
ctx context.Context,
req provider.ConfigureRequest,
resp *provider.ConfigureResponse,
) {
cfg := newProviderConfig(ctx, req, resp)
if resp.Diagnostics.HasError() {
return
}
client := newClient(ctx, cfg, resp)
if resp.Diagnostics.HasError() {
return
}
resp.DataSourceData = client
resp.ResourceData = client
}
type providerConfig struct {
Server types.String `tfsdk:"server"`
Token types.String `tfsdk:"token"`
}
func newProviderConfig(
ctx context.Context,
req provider.ConfigureRequest,
resp *provider.ConfigureResponse,
) providerConfig {
var config providerConfig
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
if resp.Diagnostics.HasError() {
return config
}
if config.Server.ValueString() == "" {
config.Server = types.StringValue(os.Getenv("WOODPECKER_SERVER"))
}
if config.Server.ValueString() == "" {
resp.Diagnostics.AddError(
"Missing Server URL Configuration",
"While configuring the provider, the server URL was not found in "+
"the WOODPECKER_SERVER environment variable or provider "+
"configuration block server attribute.",
)
}
if config.Token.ValueString() == "" {
config.Token = types.StringValue(os.Getenv("WOODPECKER_TOKEN"))
}
if config.Token.ValueString() == "" {
resp.Diagnostics.AddError(
"Missing API Token Configuration",
"While configuring the provider, the API token was not found in "+
"the WOODPECKER_TOKEN environment variable or provider "+
"configuration block token attribute.",
)
}
return config
}
func newClient(
ctx context.Context,
config providerConfig,
resp *provider.ConfigureResponse,
) woodpecker.Client {
client := woodpecker.NewClient(
config.Server.ValueString(),
(&oauth2.Config{}).Client(ctx, &oauth2.Token{
AccessToken: config.Token.ValueString(),
}),
)
_, err := client.Self()
if err != nil {
resp.Diagnostics.AddError("Couldn't get current user", err.Error())
return nil
}
c, err := semver.NewConstraint(">= 2.0.0")
if err != nil {
resp.Diagnostics.AddError(
"Couldn't parse woodpecker version constraint",
fmt.Sprintf(
"%s. Please report this issue to the provider developers.",
err,
),
)
return nil
}
ver, err := client.Version()
if err != nil {
resp.Diagnostics.AddError("Couldn't get woodpecker version", err.Error())
return nil
}
// split is required because in some cases the version looks like this: 2.0.0-f05c1631d2
parsedVer, err := semver.NewVersion(strings.Split(ver.Version, "-")[0])
if err != nil {
resp.Diagnostics.AddError(
"Couldn't parse woodpecker version",
fmt.Sprintf(
"%s. Please report this issue to the provider developers.",
err,
),
)
return nil
}
if !c.Check(parsedVer) {
resp.Diagnostics.AddError(
"Woodpecker version doesn't satisfy the constraint",
fmt.Sprintf(
"Current woodpecker version: %s, expected: %s."+
" Consider using an older version of the provider or update woodpecker.",
ver.Version,
c.String(),
),
)
return nil
}
return client
}