Skip to content

Commit

Permalink
Reduce code duplication in Framework (#167)
Browse files Browse the repository at this point in the history
* Replace all "_" with defaultCredentialDomain

* Add helpers to reduce code duplication
  • Loading branch information
taiidani authored Oct 12, 2023
1 parent 206f5ea commit 985ec97
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 266 deletions.
76 changes: 76 additions & 0 deletions jenkins/data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package jenkins

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
)

type (
// dataSourceHelper provides assistive snippets of logic to help reduce duplication in
// each data source definition.
dataSourceHelper struct {
client *jenkinsAdapter
}
)

func newDataSourceHelper() *dataSourceHelper {
return &dataSourceHelper{}
}

// Configure should register the client for the resource.
func (d *dataSourceHelper) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*jenkinsAdapter)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *jenkinsAdapter, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.client = client
}

func (d *dataSourceHelper) schema(s map[string]schema.Attribute) map[string]schema.Attribute {
s["id"] = schema.StringAttribute{
Computed: true,
MarkdownDescription: "The full canonical job path, e.g. `/job/job-name`",
}
s["name"] = schema.StringAttribute{
Required: true,
MarkdownDescription: "The name of the resource being read.",
}
s["folder"] = schema.StringAttribute{
MarkdownDescription: "The folder namespace containing this resource.",
Optional: true,
}
s["description"] = schema.StringAttribute{
MarkdownDescription: "A human readable description of the credentials being stored.",
Computed: true,
}

return s
}

func (d *dataSourceHelper) schemaCredential(s map[string]schema.Attribute) map[string]schema.Attribute {
s = d.schema(s)
s["domain"] = schema.StringAttribute{
MarkdownDescription: "The domain store containing this resource.",
Optional: true,
}
s["scope"] = schema.StringAttribute{
MarkdownDescription: `The visibility of the credentials to Jenkins agents. This will be either "GLOBAL" or "SYSTEM".`,
Computed: true,
}

return s
}
61 changes: 9 additions & 52 deletions jenkins/data_source_jenkins_credential_username.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package jenkins

import (
"context"
"fmt"

jenkins "github.com/bndr/gojenkins"
"github.com/hashicorp/terraform-plugin-framework/datasource"
Expand All @@ -14,81 +13,39 @@ import (
type credentialUsernameDataSourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Domain types.String `tfsdk:"domain"`
Folder types.String `tfsdk:"folder"`
Scope types.String `tfsdk:"scope"`
Description types.String `tfsdk:"description"`
Domain types.String `tfsdk:"domain"`
Scope types.String `tfsdk:"scope"`
Username types.String `tfsdk:"username"`
}

type credentialUsernameDataSource struct {
client *jenkinsAdapter
*dataSourceHelper
}

// Ensure the implementation satisfies the desired interfaces.
var _ datasource.DataSourceWithConfigure = &credentialUsernameDataSource{}

func newCredentialUsernameDataSource() datasource.DataSource {
return &credentialUsernameDataSource{}
return &credentialUsernameDataSource{
dataSourceHelper: newDataSourceHelper(),
}
}

func (d *credentialUsernameDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_credential_username"
}

// Configure should register the client for the resource.
func (d *credentialUsernameDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*jenkinsAdapter)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *jenkinsAdapter, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.client = client
}

func (d *credentialUsernameDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Get the attributes of a username credential within Jenkins.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
MarkdownDescription: "The full canonical job path, e.g. `/job/job-name`",
},
"name": schema.StringAttribute{
Required: true,
MarkdownDescription: "The name of the resource being read.",
},
"domain": schema.StringAttribute{
MarkdownDescription: "The domain store containing this resource.",
Optional: true,
},
"folder": schema.StringAttribute{
MarkdownDescription: "The folder namespace containing this resource.",
Optional: true,
},
"scope": schema.StringAttribute{
MarkdownDescription: `The visibility of the credentials to Jenkins agents. This will be either "GLOBAL" or "SYSTEM".`,
Computed: true,
},
"description": schema.StringAttribute{
MarkdownDescription: "A human readable description of the credentials being stored.",
Computed: true,
},
Attributes: d.schemaCredential(map[string]schema.Attribute{
"username": schema.StringAttribute{
MarkdownDescription: "The username associated with the credentials.",
Computed: true,
},
},
}),
}
}

Expand All @@ -105,7 +62,7 @@ func (d *credentialUsernameDataSource) Read(ctx context.Context, req datasource.
cm.Folder = formatFolderName(data.Folder.ValueString())

if data.Domain.IsNull() {
data.Domain = basetypes.NewStringValue(defaultValueDomain)
data.Domain = basetypes.NewStringValue(defaultCredentialDomain)
}

cred := jenkins.UsernameCredentials{}
Expand Down
4 changes: 2 additions & 2 deletions jenkins/data_source_jenkins_credential_username_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestAccJenkinsCredentialUsernameDataSource_basic(t *testing.T) {
data jenkins_credential_username foo {
name = jenkins_credential_username.foo.name
domain = "_"
domain = "`+defaultCredentialDomain+`"
}`, randString, randString),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("jenkins_credential_username.foo", "id", "/tf-acc-test-"+randString),
Expand Down Expand Up @@ -63,7 +63,7 @@ func TestAccJenkinsCredentialUsernameDataSource_nested(t *testing.T) {
data jenkins_credential_username sub {
name = jenkins_credential_username.sub.name
domain = "_"
domain = "`+defaultCredentialDomain+`"
folder = jenkins_credential_username.sub.folder
}`, randString, randString),
Check: resource.ComposeTestCheckFunc(
Expand Down
61 changes: 9 additions & 52 deletions jenkins/data_source_jenkins_credential_vault_approle.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package jenkins

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
Expand All @@ -13,78 +12,36 @@ import (
type credentialVaultAppRoleDataSourceModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Domain types.String `tfsdk:"domain"`
Folder types.String `tfsdk:"folder"`
Scope types.String `tfsdk:"scope"`
Description types.String `tfsdk:"description"`
Domain types.String `tfsdk:"domain"`
Scope types.String `tfsdk:"scope"`
Namespace types.String `tfsdk:"namespace"`
Path types.String `tfsdk:"path"`
RoleID types.String `tfsdk:"role_id"`
}

type credentialVaultAppRoleDataSource struct {
client *jenkinsAdapter
*dataSourceHelper
}

// Ensure the implementation satisfies the desired interfaces.
var _ datasource.DataSourceWithConfigure = &credentialVaultAppRoleDataSource{}

func newCredentialVaultAppRoleDataSource() datasource.DataSource {
return &credentialVaultAppRoleDataSource{}
return &credentialVaultAppRoleDataSource{
dataSourceHelper: newDataSourceHelper(),
}
}

func (d *credentialVaultAppRoleDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_credential_vault_approle"
}

// Configure should register the client for the resource.
func (d *credentialVaultAppRoleDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*jenkinsAdapter)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Resource Configure Type",
fmt.Sprintf("Expected *jenkinsAdapter, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.client = client
}

func (d *credentialVaultAppRoleDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "Get the attributes of a vault approle credential within Jenkins.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
MarkdownDescription: "The full canonical job path, e.g. `/job/job-name`",
},
"name": schema.StringAttribute{
Required: true,
MarkdownDescription: "The name of the resource being read.",
},
"domain": schema.StringAttribute{
MarkdownDescription: "The domain store containing this resource.",
Optional: true,
},
"folder": schema.StringAttribute{
MarkdownDescription: "The folder namespace containing this resource.",
Optional: true,
},
"scope": schema.StringAttribute{
MarkdownDescription: `The visibility of the credentials to Jenkins agents. This will be either "GLOBAL" or "SYSTEM".`,
Computed: true,
},
"description": schema.StringAttribute{
MarkdownDescription: "A human readable description of the credentials being stored.",
Computed: true,
},
Attributes: d.schemaCredential(map[string]schema.Attribute{
"namespace": schema.StringAttribute{
MarkdownDescription: "The Vault namespace of the approle credential.",
Computed: true,
Expand All @@ -97,7 +54,7 @@ func (d *credentialVaultAppRoleDataSource) Schema(ctx context.Context, req datas
MarkdownDescription: "The role_id associated with the credentials.",
Computed: true,
},
},
}),
}
}

Expand All @@ -114,7 +71,7 @@ func (d *credentialVaultAppRoleDataSource) Read(ctx context.Context, req datasou
cm.Folder = formatFolderName(data.Folder.ValueString())

if data.Domain.IsNull() {
data.Domain = basetypes.NewStringValue(defaultValueDomain)
data.Domain = basetypes.NewStringValue(defaultCredentialDomain)
}

cred := VaultAppRoleCredentials{}
Expand Down
8 changes: 4 additions & 4 deletions jenkins/data_source_jenkins_credential_vault_approle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestAccJenkinsCredentialVaultAppRoleDataSource_basic(t *testing.T) {
data jenkins_credential_vault_approle foo {
name = jenkins_credential_vault_approle.foo.name
domain = "_"
domain = "`+defaultCredentialDomain+`"
}`, randString, randString),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("jenkins_credential_vault_approle.foo", "id", "/tf-acc-test-"+randString),
Expand Down Expand Up @@ -63,7 +63,7 @@ func TestAccJenkinsCredentialVaultAppRoleDataSource_nested(t *testing.T) {
data jenkins_credential_vault_approle sub {
name = jenkins_credential_vault_approle.sub.name
domain = "_"
domain = "`+defaultCredentialDomain+`"
folder = jenkins_credential_vault_approle.sub.folder
}`, randString, randString),
Check: resource.ComposeTestCheckFunc(
Expand Down Expand Up @@ -98,7 +98,7 @@ func TestAccJenkinsCredentialVaultAppRoleDataSource_basic_namespaced(t *testing.
data jenkins_credential_vault_approle foo {
name = jenkins_credential_vault_approle.foo.name
domain = "_"
domain = "`+defaultCredentialDomain+`"
}`, randString, randString),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("jenkins_credential_vault_approle.foo", "id", "/tf-acc-test-"+randString),
Expand Down Expand Up @@ -137,7 +137,7 @@ func TestAccJenkinsCredentialVaultAppRoleDataSource_nested_namespaced(t *testing
data jenkins_credential_vault_approle sub {
name = jenkins_credential_vault_approle.sub.name
domain = "_"
domain = "`+defaultCredentialDomain+`"
folder = jenkins_credential_vault_approle.sub.folder
}`, randString, randString),
Check: resource.ComposeTestCheckFunc(
Expand Down
5 changes: 4 additions & 1 deletion jenkins/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import (
)

const (
defaultValueDomain = "_"
// defaultCredentialDomain is the default domain that all credentials go into.
//
// The value represents "All domains" in the Jenkins system.
defaultCredentialDomain = "_"
)

// Provider creates a new Jenkins provider.
Expand Down
Loading

0 comments on commit 985ec97

Please sign in to comment.