Skip to content

Commit

Permalink
Add jenkins_job_config data resource (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
wengchaoxi committed Aug 11, 2022
1 parent f04657e commit 6579586
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 0 deletions.
30 changes: 30 additions & 0 deletions docs/data-sources/job_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# jenkins_job_config Data Source

Get the XML configuration of a job within Jenkins.

## Example Usage

```hcl
data "jenkins_job_config" "example" {
name = "job-name"
xml_node = "xml-node-name"
}
```

## Argument Reference

The following arguments are supported:

* `name` - (Required) The name of the job being read.
* `folder` - (Optional) The folder namespace containing this job.
* `xml_node` - (Optional) The xml_node used to filter the XML configuration of the job.
* `regex` - (Optional) The regex used to filter the XML configuration of the job.

> Note: If both `xml_node` and `regex` are empty, the complete XML configuration of the job will be exported.
## Attribute Reference

In addition to all arguments above, the following attributes are exported:

* `id` - The full canonical job path, E.G. `/job/job-name`.
* `config` - The XML configuration of the job.
102 changes: 102 additions & 0 deletions jenkins/data_source_jenkins_job_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package jenkins

import (
"context"
"errors"
"fmt"
"log"
"regexp"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceJenkinsJobConfig() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceJenkinsJobConfigRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Description: "The unique name of the JenkinsCI job.",
Required: true,
ValidateDiagFunc: validateJobName,
},
"folder": {
Type: schema.TypeString,
Description: "The folder namespace that the job exists in.",
Optional: true,
ValidateDiagFunc: validateFolderName,
},
"xml_node": {
Type: schema.TypeString,
Optional: true,
Description: "The xml_node used to filter the job configuration.",
},
"regex": {
Type: schema.TypeString,
Optional: true,
Description: "The regex used to filter the job configuration.",
},
"config": {
Type: schema.TypeString,
Computed: true,
Description: "The XML configuration of the job.",
},
},
}
}

func dataSourceJenkinsJobConfigRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*jenkinsAdapter)

name := d.Get("name").(string)
folderName := d.Get("folder").(string)

id := formatFolderName(folderName + "/" + name)
job, err := client.GetJob(ctx, id)
if err != nil {
log.Printf("[DEBUG] jenkins::job::config - Could not find job %q: %s", id, err.Error())
return nil
}
config, err := job.GetConfig(ctx)
if err != nil {
return diag.FromErr(fmt.Errorf("jenkins::job::config - Error get config in job %q: %w", id, err))
}

xmlNode := d.Get("xml_node").(string)
if xmlNode != "" {
config, err = filterJobConfigByXMLNode(config, xmlNode)
if err != nil {
log.Printf("[DEBUG] jenkins::job::config - Job %q: %s", id, err.Error())
}
}

regex := d.Get("regex").(string)
if regex != "" && config != "" {
config, err = filterJobConfigByRegex(config, regex)
if err != nil {
log.Printf("[DEBUG] jenkins::job::config - Job %q: %s", id, err.Error())
}
}

d.Set("config", config)
d.SetId(job.Base)
return nil
}

func filterJobConfigByRegex(config string, regex string) (string, error) {
re := regexp.MustCompile(fmt.Sprintf("%s", regex))
result := re.FindStringSubmatch(config)
if len(result) == 0 {
return "", errors.New("no match result")
}
return result[0], nil
}

func filterJobConfigByXMLNode(config string, node string) (string, error) {
result, err := filterJobConfigByRegex(config, fmt.Sprintf(`<%s>[^\0]*</%s>|<%s/>`, node, node, node))
if err != nil {
return "", fmt.Errorf("not found XML node: %q", node)
}
return result, nil
}
84 changes: 84 additions & 0 deletions jenkins/data_source_jenkins_job_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package jenkins

import (
"fmt"
"os"
"path/filepath"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccJenkinsJobConfigDataSource_basic(t *testing.T) {
testDir := t.TempDir()
_ = os.WriteFile(filepath.Join(testDir, "test.xml"), testXML, 0644)
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource jenkins_job foo {
name = "tf-acc-test-%s"
template = templatefile("%s/test.xml", {
description = "Acceptance testing Jenkins provider"
})
}
data jenkins_job_config foo {
name = jenkins_job.foo.name
xml_node = "properties"
}`, randString, testDir),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("jenkins_job.foo", "id", "/job/tf-acc-test-"+randString),
resource.TestCheckResourceAttr("data.jenkins_job_config.foo", "id", "/job/tf-acc-test-"+randString),
resource.TestCheckResourceAttr("data.jenkins_job_config.foo", "name", "tf-acc-test-"+randString),
resource.TestCheckResourceAttr("data.jenkins_job_config.foo", "config", "<properties/>"),
),
},
},
})
}

func TestAccJenkinsJobConfigDataSource_nested(t *testing.T) {
testDir := t.TempDir()
_ = os.WriteFile(filepath.Join(testDir, "test.xml"), testXML, 0644)
randString := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource jenkins_folder foo {
name = "tf-acc-test-%s"
}
resource jenkins_job sub {
name = "subfolder"
folder = jenkins_folder.foo.id
template = templatefile("%s/test.xml", {
description = "Acceptance testing Jenkins provider"
})
}
data jenkins_job_config sub {
name = jenkins_job.sub.name
folder = jenkins_job.sub.folder
regex = "<properties>[^\\0]*</properties>|<properties/>"
}`, randString, testDir),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("jenkins_folder.foo", "id", "/job/tf-acc-test-"+randString),
resource.TestCheckResourceAttr("jenkins_job.sub", "id", "/job/tf-acc-test-"+randString+"/job/subfolder"),
resource.TestCheckResourceAttr("data.jenkins_job_config.sub", "name", "subfolder"),
resource.TestCheckResourceAttr("data.jenkins_job_config.sub", "folder", "/job/tf-acc-test-"+randString),
resource.TestCheckResourceAttr("data.jenkins_job_config.sub", "config", "<properties/>"),
),
},
},
})
}
1 change: 1 addition & 0 deletions jenkins/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func Provider() *schema.Provider {
"jenkins_credential_vault_approle": dataSourceJenkinsCredentialVaultAppRole(),
"jenkins_folder": dataSourceJenkinsFolder(),
"jenkins_job": dataSourceJenkinsJob(),
"jenkins_job_config": dataSourceJenkinsJobConfig(),
"jenkins_plugins": dataSourceJenkinsPlugins(),
},

Expand Down

0 comments on commit 6579586

Please sign in to comment.