diff --git a/jenkins_jobs/modules/publishers.py b/jenkins_jobs/modules/publishers.py
index 0e4001768..35b512368 100644
--- a/jenkins_jobs/modules/publishers.py
+++ b/jenkins_jobs/modules/publishers.py
@@ -3603,6 +3603,139 @@ def valgrind(parser, xml_parent, data):
         data.get('publish-if-failed', False)).lower()
 
 
+def build_trends_publisher(plugin_name, xml_element, data):
+    """Helper to create various trend publishers.
+    """
+
+    def append_thresholds(element, data, only_totals):
+        """Appends the status thresholds.
+        """
+
+        for status in ['unstable', 'failed']:
+            status_data = data.get(status, {})
+
+            limits = [
+                ('total-all', 'TotalAll'),
+                ('total-high', 'TotalHigh'),
+                ('total-normal', 'TotalNormal'),
+                ('total-low', 'TotalLow')]
+
+            if only_totals is False:
+                limits.extend([
+                    ('new-all', 'NewAll'),
+                    ('new-high', 'NewHigh'),
+                    ('new-normal', 'NewNormal'),
+                    ('new-low', 'NewLow')])
+
+            for key, tag_suffix in limits:
+                tag_name = status + tag_suffix
+                XML.SubElement(element, tag_name).text = str(
+                    status_data.get(key, ''))
+
+    # Tuples containing: setting name, tag name, default value
+    settings = [
+        ('healthy', 'healthy', ''),
+        ('unhealthy', 'unHealthy', ''),
+        ('health-threshold', 'thresholdLimit', 'low'),
+        ('plugin-name', 'pluginName', plugin_name),
+        ('default-encoding', 'defaultEncoding', ''),
+        ('can-run-on-failed', 'canRunOnFailed', False),
+        ('use-stable-build-as-reference', 'useStableBuildAsReference', False),
+        ('use-delta-values', 'useDeltaValues', False),
+        ('thresholds', 'thresholds', {}),
+        ('should-detect-modules', 'shouldDetectModules', False),
+        ('dont-compute-new', 'dontComputeNew', True),
+        ('do-not-resolve-relative-paths', 'doNotResolveRelativePaths', False),
+        ('pattern', 'pattern', '')]
+
+    thresholds = ['low', 'normal', 'high']
+
+    for key, tag_name, default in settings:
+        xml_config = XML.SubElement(xml_element, tag_name)
+        config_value = data.get(key, default)
+
+        if key == 'thresholds':
+            append_thresholds(
+                xml_config,
+                config_value,
+                data.get('dont-compute-new', True))
+        elif key == 'health-threshold' and config_value not in thresholds:
+            raise JenkinsJobsException("health-threshold must be one of %s" %
+                                       ", ".join(thresholds))
+        else:
+            if isinstance(default, bool):
+                xml_config.text = str(config_value).lower()
+            else:
+                xml_config.text = str(config_value)
+
+
+def pmd(parser, xml_parent, data):
+    """yaml: pmd
+    Publish trend reports with PMD.
+    Requires the Jenkins `PMD Plugin.
+    <https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin>`_
+
+    The PMD component accepts a dictionary with the following values:
+
+    :arg str pattern: Report filename pattern (optional)
+    :arg bool can-run-on-failed: Also runs for failed builds, instead of just
+      stable or unstable builds (default false)
+    :arg bool should-detect-modules: Determines if Ant or Maven modules should
+      be detected for all files that contain warnings (default false)
+    :arg int healthy: Sunny threshold (optional)
+    :arg int unhealthy: Stormy threshold (optional)
+    :arg str health-threshold: Threshold priority for health status
+      ('low', 'normal' or 'high', defaulted to 'low')
+    :arg dict thresholds: Mark build as failed or unstable if the number of
+      errors exceeds a threshold. (optional)
+
+        :thresholds:
+            * **unstable** (`dict`)
+                :unstable: * **total-all** (`int`)
+                           * **total-high** (`int`)
+                           * **total-normal** (`int`)
+                           * **total-low** (`int`)
+                           * **new-all** (`int`)
+                           * **new-high** (`int`)
+                           * **new-normal** (`int`)
+                           * **new-low** (`int`)
+
+            * **failed** (`dict`)
+                :failed: * **total-all** (`int`)
+                         * **total-high** (`int`)
+                         * **total-normal** (`int`)
+                         * **total-low** (`int`)
+                         * **new-all** (`int`)
+                         * **new-high** (`int`)
+                         * **new-normal** (`int`)
+                         * **new-low** (`int`)
+    :arg str default-encoding: Encoding for parsing or showing files (optional)
+    :arg bool do-not-resolve-relative-paths: (default false)
+    :arg bool dont-compute-new: If set to false, computes new warnings based on
+      the reference build (default true)
+    :arg bool use-stable-build-as-reference: The number of new warnings will be
+      calculated based on the last stable build, allowing reverts of unstable
+      builds where the number of warnings was decreased. (default false)
+    :arg bool use-delta-values: If set then the number of new warnings is
+      calculated by subtracting the total number of warnings of the current
+      build from the reference build.
+      (default false)
+
+    Example:
+
+    .. literalinclude::  /../../tests/publishers/fixtures/pmd001.yaml
+
+    Full example:
+
+    .. literalinclude::  /../../tests/publishers/fixtures/pmd002.yaml
+
+    """
+
+    xml_element = XML.SubElement(xml_parent, 'hudson.plugins.pmd.PmdPublisher')
+
+    build_trends_publisher('[PMD] ', xml_element, data)
+
+
 class Publishers(jenkins_jobs.modules.base.Base):
     sequence = 70
 
diff --git a/setup.cfg b/setup.cfg
index 1330c426a..3bb19fbb1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -143,8 +143,9 @@ jenkins_jobs.publishers =
     performance=jenkins_jobs.modules.publishers:performance
     pipeline=jenkins_jobs.modules.publishers:pipeline
     plot=jenkins_jobs.modules.publishers:plot
-    postbuildscript=jenkins_jobs.modules.publishers:postbuildscript
+    pmd=jenkins_jobs.modules.publishers:pmd
     post-tasks=jenkins_jobs.modules.publishers:post_tasks
+    postbuildscript=jenkins_jobs.modules.publishers:postbuildscript
     robot=jenkins_jobs.modules.publishers:robot
     ruby-metrics=jenkins_jobs.modules.publishers:ruby_metrics
     scp=jenkins_jobs.modules.publishers:scp
diff --git a/tests/publishers/fixtures/pmd001.xml b/tests/publishers/fixtures/pmd001.xml
new file mode 100644
index 000000000..8d046aa6d
--- /dev/null
+++ b/tests/publishers/fixtures/pmd001.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project>
+  <publishers>
+    <hudson.plugins.pmd.PmdPublisher>
+      <healthy>0</healthy>
+      <unHealthy>100</unHealthy>
+      <thresholdLimit>high</thresholdLimit>
+      <pluginName>[PMD] </pluginName>
+      <defaultEncoding/>
+      <canRunOnFailed>false</canRunOnFailed>
+      <useStableBuildAsReference>false</useStableBuildAsReference>
+      <useDeltaValues>false</useDeltaValues>
+      <thresholds>
+        <unstableTotalAll/>
+        <unstableTotalHigh>10</unstableTotalHigh>
+        <unstableTotalNormal/>
+        <unstableTotalLow/>
+        <failedTotalAll/>
+        <failedTotalHigh>1</failedTotalHigh>
+        <failedTotalNormal/>
+        <failedTotalLow/>
+      </thresholds>
+      <shouldDetectModules>false</shouldDetectModules>
+      <dontComputeNew>true</dontComputeNew>
+      <doNotResolveRelativePaths>false</doNotResolveRelativePaths>
+      <pattern>**/pmd-result.xml</pattern>
+    </hudson.plugins.pmd.PmdPublisher>
+  </publishers>
+</project>
diff --git a/tests/publishers/fixtures/pmd001.yaml b/tests/publishers/fixtures/pmd001.yaml
new file mode 100644
index 000000000..8aba6c5c5
--- /dev/null
+++ b/tests/publishers/fixtures/pmd001.yaml
@@ -0,0 +1,11 @@
+publishers:
+ - pmd:
+    pattern: '**/pmd-result.xml'
+    healthy: 0
+    unhealthy: 100
+    health-threshold: 'high'
+    thresholds:
+        unstable:
+            total-high: 10
+        failed:
+            total-high: 1
diff --git a/tests/publishers/fixtures/pmd002.xml b/tests/publishers/fixtures/pmd002.xml
new file mode 100644
index 000000000..044911a50
--- /dev/null
+++ b/tests/publishers/fixtures/pmd002.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project>
+  <publishers>
+    <hudson.plugins.pmd.PmdPublisher>
+      <healthy>0</healthy>
+      <unHealthy>100</unHealthy>
+      <thresholdLimit>high</thresholdLimit>
+      <pluginName>[PMD] </pluginName>
+      <defaultEncoding>utf-8</defaultEncoding>
+      <canRunOnFailed>true</canRunOnFailed>
+      <useStableBuildAsReference>false</useStableBuildAsReference>
+      <useDeltaValues>false</useDeltaValues>
+      <thresholds>
+        <unstableTotalAll>90</unstableTotalAll>
+        <unstableTotalHigh>80</unstableTotalHigh>
+        <unstableTotalNormal>70</unstableTotalNormal>
+        <unstableTotalLow>60</unstableTotalLow>
+        <failedTotalAll>90</failedTotalAll>
+        <failedTotalHigh>80</failedTotalHigh>
+        <failedTotalNormal>70</failedTotalNormal>
+        <failedTotalLow>60</failedTotalLow>
+      </thresholds>
+      <shouldDetectModules>true</shouldDetectModules>
+      <dontComputeNew>true</dontComputeNew>
+      <doNotResolveRelativePaths>false</doNotResolveRelativePaths>
+      <pattern>**/pmd-result.xml</pattern>
+    </hudson.plugins.pmd.PmdPublisher>
+  </publishers>
+</project>
diff --git a/tests/publishers/fixtures/pmd002.yaml b/tests/publishers/fixtures/pmd002.yaml
new file mode 100644
index 000000000..183015531
--- /dev/null
+++ b/tests/publishers/fixtures/pmd002.yaml
@@ -0,0 +1,20 @@
+publishers:
+ - pmd:
+    pattern: '**/pmd-result.xml'
+    can-run-on-failed: true
+    should-detect-modules: true
+    healthy: 0
+    unhealthy: 100
+    health-threshold: 'high'
+    thresholds:
+        unstable:
+            total-all: 90
+            total-high: 80
+            total-normal: 70
+            total-low: 60
+        failed:
+            total-all: 90
+            total-high: 80
+            total-normal: 70
+            total-low: 60
+    default-encoding: 'utf-8'
diff --git a/tests/publishers/fixtures/pmd003.xml b/tests/publishers/fixtures/pmd003.xml
new file mode 100644
index 000000000..9f0320dcb
--- /dev/null
+++ b/tests/publishers/fixtures/pmd003.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project>
+  <publishers>
+    <hudson.plugins.pmd.PmdPublisher>
+      <healthy/>
+      <unHealthy/>
+      <thresholdLimit>low</thresholdLimit>
+      <pluginName>[PMD] </pluginName>
+      <defaultEncoding/>
+      <canRunOnFailed>false</canRunOnFailed>
+      <useStableBuildAsReference>false</useStableBuildAsReference>
+      <useDeltaValues>false</useDeltaValues>
+      <thresholds>
+        <unstableTotalAll/>
+        <unstableTotalHigh/>
+        <unstableTotalNormal/>
+        <unstableTotalLow/>
+        <failedTotalAll/>
+        <failedTotalHigh/>
+        <failedTotalNormal/>
+        <failedTotalLow/>
+      </thresholds>
+      <shouldDetectModules>false</shouldDetectModules>
+      <dontComputeNew>true</dontComputeNew>
+      <doNotResolveRelativePaths>false</doNotResolveRelativePaths>
+      <pattern/>
+    </hudson.plugins.pmd.PmdPublisher>
+  </publishers>
+</project>
diff --git a/tests/publishers/fixtures/pmd003.yaml b/tests/publishers/fixtures/pmd003.yaml
new file mode 100644
index 000000000..4ece24be6
--- /dev/null
+++ b/tests/publishers/fixtures/pmd003.yaml
@@ -0,0 +1,2 @@
+publishers:
+  - pmd
diff --git a/tests/publishers/fixtures/pmd004.xml b/tests/publishers/fixtures/pmd004.xml
new file mode 100644
index 000000000..cfacbd4d7
--- /dev/null
+++ b/tests/publishers/fixtures/pmd004.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project>
+  <publishers>
+    <hudson.plugins.pmd.PmdPublisher>
+      <healthy>0</healthy>
+      <unHealthy>100</unHealthy>
+      <thresholdLimit>high</thresholdLimit>
+      <pluginName>[PMD] </pluginName>
+      <defaultEncoding>utf-8</defaultEncoding>
+      <canRunOnFailed>true</canRunOnFailed>
+      <useStableBuildAsReference>true</useStableBuildAsReference>
+      <useDeltaValues>true</useDeltaValues>
+      <thresholds>
+        <unstableTotalAll>90</unstableTotalAll>
+        <unstableTotalHigh>80</unstableTotalHigh>
+        <unstableTotalNormal>70</unstableTotalNormal>
+        <unstableTotalLow>60</unstableTotalLow>
+        <unstableNewAll>50</unstableNewAll>
+        <unstableNewHigh>40</unstableNewHigh>
+        <unstableNewNormal>30</unstableNewNormal>
+        <unstableNewLow>20</unstableNewLow>
+        <failedTotalAll>91</failedTotalAll>
+        <failedTotalHigh>81</failedTotalHigh>
+        <failedTotalNormal>71</failedTotalNormal>
+        <failedTotalLow>61</failedTotalLow>
+        <failedNewAll>51</failedNewAll>
+        <failedNewHigh>41</failedNewHigh>
+        <failedNewNormal>31</failedNewNormal>
+        <failedNewLow>21</failedNewLow>
+      </thresholds>
+      <shouldDetectModules>true</shouldDetectModules>
+      <dontComputeNew>false</dontComputeNew>
+      <doNotResolveRelativePaths>true</doNotResolveRelativePaths>
+      <pattern>**/pmd-result.xml</pattern>
+    </hudson.plugins.pmd.PmdPublisher>
+  </publishers>
+</project>
diff --git a/tests/publishers/fixtures/pmd004.yml b/tests/publishers/fixtures/pmd004.yml
new file mode 100644
index 000000000..1f418ff10
--- /dev/null
+++ b/tests/publishers/fixtures/pmd004.yml
@@ -0,0 +1,32 @@
+publishers:
+ - pmd:
+    pattern: '**/pmd-result.xml'
+    can-run-on-failed: true
+    should-detect-modules: true
+    healthy: 0
+    unhealthy: 100
+    health-threshold: 'high'
+    thresholds:
+        unstable:
+            total-all: 90
+            total-high: 80
+            total-normal: 70
+            total-low: 60
+            new-all: 50
+            new-high: 40
+            new-normal: 30
+            new-low: 20
+        failed:
+            total-all: 91
+            total-high: 81
+            total-normal: 71
+            total-low: 61
+            new-all: 51
+            new-high: 41
+            new-normal: 31
+            new-low: 21
+    default-encoding: 'utf-8'
+    do-not-resolve-relative-paths: true
+    dont-compute-new: false
+    use-stable-build-as-reference: true
+    use-delta-values: true