Allow defining workflow-scm type of jobs

- use common to be included to deduplicate code
- don't abuse salt fileserver
diff --git a/README.rst b/README.rst
index 44fe5ba..a83d61f 100644
--- a/README.rst
+++ b/README.rst
@@ -160,6 +160,39 @@
                 type: text
                 description: multi-liner
                 default: default_text
+          jobname_scm:
+            type: workflow-scm
+            concurrent: false
+            scm:
+              type: git
+              url: https://github.com/jenkinsci/docker.git
+              branch: master
+              script: Jenkinsfile
+              github:
+                url: https://github.com/jenkinsci/docker
+                name: "Jenkins Docker Image"
+            trigger:
+              github:
+              pollscm:
+                spec: "H/15 * * * *"
+              reverse:
+                projects:
+                 - test1
+                 - test2
+                state: SUCCESS
+            param:
+              bool_param:
+                type: boolean
+                description: true/false
+                default: true
+              string_param:
+                type: string
+                description: 1 liner
+                default: default_string
+              text_param:
+                type: text
+                description: multi-liner
+                default: default_text
 
 Inline Groovy script samples
 
diff --git a/jenkins/client/init.sls b/jenkins/client/init.sls
index 8b27b66..4a9fdc8 100644
--- a/jenkins/client/init.sls
+++ b/jenkins/client/init.sls
@@ -2,8 +2,8 @@
 {%- if client.enabled %}
 
 include:
-  - .source
-  - .job
+  - jenkins.client.source
+  - jenkins.client.job
 
 jenkins_client_install:
   pkg.installed:
@@ -17,12 +17,8 @@
 jenkins_client_dirs:
   file.directory:
   - names:
-    - {{ client.dir.jenkins_root }}
-    - {{ client.dir.salt_root }}/_jenkins/cache
+    - {{ client.dir.jenkins_source_root }}
+    - {{ client.dir.jenkins_jobs_root }}
   - makedirs: true
 
-{{ client.dir.salt_root }}/_jenkins/jobs:
-  file.symlink:
-    - target: {{ client.dir.jenkins_root }}
-
 {%- endif %}
diff --git a/jenkins/client/job.sls b/jenkins/client/job.sls
index 68647f6..dbf7cc2 100644
--- a/jenkins/client/job.sls
+++ b/jenkins/client/job.sls
@@ -5,22 +5,42 @@
 
 {%- for job_name, job in client.get('job', {}).iteritems() %}
 
-{{ client.dir.salt_root }}/_jenkins/cache/{{ job_name }}.xml:
+{%- if job.enabled|default(True) %}
+
+jenkins_job_{{ job_name }}_definition:
   file.managed:
+  - name: {{ client.dir.jenkins_jobs_root }}/{{ job_name }}.xml
   - source: salt://jenkins/files/jobs/{{ job.type }}.xml
   - mode: 400
   - template: jinja
   - defaults:
       job_name: {{ job_name }}
+      job: {{ job }}
   - require:
     - file: jenkins_client_dirs
 
-jenkins_job_{{ job_name }}_ensure:
+jenkins_job_{{ job_name }}_present:
   jenkins.present:
   - name: {{ job_name }}
-  - config: salt://_jenkins/cache/{{ job_name }}.xml
+  - config: {{ client.dir.jenkins_jobs_root }}/{{ job_name }}.xml
   - watch:
-    - file: {{ client.dir.salt_root }}/_jenkins/cache/{{ job_name }}.xml
+    - file: jenkins_job_{{ job_name }}_definition
     - file: /etc/salt/minion.d/_jenkins.conf
 
+{%- else %}
+
+jenkins_job_{{ job_name }}_definition:
+  file.absent:
+  - name: {{ client.dir.jenkins_jobs_root }}/{{ job_name }}.xml
+  - require:
+    - file: jenkins_client_dirs
+
+jenkins_job_{{ job_name }}_absent:
+  jenkins.absent:
+  - name: {{ job_name }}
+  - watch:
+    - file: /etc/salt/minion.d/_jenkins.conf
+
+{%- endif %}
+
 {%- endfor %}
diff --git a/jenkins/client/source.sls b/jenkins/client/source.sls
index 9657324..71e6500 100644
--- a/jenkins/client/source.sls
+++ b/jenkins/client/source.sls
@@ -10,15 +10,15 @@
 jenkins_{{ source_name }}_source:
   git.latest:
   - name: {{ source.address }}
-  - target: {{ client.dir.jenkins_root }}/{{ source_name }}
+  - target: {{ client.dir.jenkins_source_root }}/{{ source_name }}
   - rev: {{ source.branch }}
   - reload_pillar: True
 
 {%- elif client.source.engine == "local" %}
 
-jenkins_{{ source_name }}_dir:
+jenkins_{{ source_name }}_file:
   file.managed:
-  - name: {{ client.dir.jenkins_root }}/{{ source_name }}
+  - name: {{ client.dir.jenkins_source_root }}/{{ source_name }}
   - mode: 700
 
 {%- endif %}
diff --git a/jenkins/files/jobs/_common.xml b/jenkins/files/jobs/_common.xml
new file mode 100644
index 0000000..68fa370
--- /dev/null
+++ b/jenkins/files/jobs/_common.xml
@@ -0,0 +1,55 @@
+  <actions/>
+  <description>
+    Salt generated project, do not edit. Changes will be overwritten.
+    {{ job.get('description', '')|e }}
+  </description>
+  {%- if job.display_name is defined %}
+  <displayName>{{ job.display_name }}</displayName>
+  {%- endif %}
+  <keepDependencies>false</keepDependencies>
+  <properties>
+    {%- if not job.concurrent|default(False) %}
+    <org.jenkinsci.plugins.workflow.job.properties.DisableConcurrentBuildsJobProperty/>
+    {%- endif %}
+    {%- if job.scm.github is defined %}
+    <com.coravy.hudson.plugins.github.GithubProjectProperty plugin="github@1.21.1">
+      <projectUrl>{{ job.scm.github.url }}</projectUrl>
+      <displayName>{{ job.scm.github.name|default("") }}</displayName>
+    </com.coravy.hudson.plugins.github.GithubProjectProperty>
+    {%- endif %}
+    <org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
+      <triggers>
+        {%- for type, trigger in job.trigger.iteritems() %}
+        {%- if trigger.enabled|default(True) %}
+        {%- if type == 'reverse' %}
+        <jenkins.triggers.ReverseBuildTrigger>
+          <spec></spec>
+          <upstreamProjects>{{ trigger.projects.join(',') if trigger.projects is defined else trigger.project }}</upstreamProjects>
+          <threshold>
+            <name>{{ trigger.state|default('SUCCESS') }}</name>
+            <ordinal>{{ client.job_status.get(trigger.state|default('SUCCESS')).ordinal }}</ordinal>
+            <color>{{ client.job_status.get(trigger.state|default('SUCCESS')).color }}</color>
+            <completeBuild>{{ trigger.get('complete', True)|lower }}</completeBuild>
+          </threshold>
+        </jenkins.triggers.ReverseBuildTrigger>
+        {%- elif type == 'github' %}
+        <com.cloudbees.jenkins.GitHubPushTrigger plugin="github@1.21.1">
+          <spec></spec>
+        </com.cloudbees.jenkins.GitHubPushTrigger>
+        {%- elif type == 'pollscm' %}
+        <hudson.triggers.SCMTrigger>
+          <spec>{{ trigger.spec }}</spec>
+          <ignorePostCommitHooks>false</ignorePostCommitHooks>
+        </hudson.triggers.SCMTrigger>
+        {%- endif %}
+        {%- endif %}
+        {%- endfor %}
+      </triggers>
+    </org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
+    {%- include "jenkins/files/jobs/_parameters.xml" %}
+  </properties>
+  <triggers>
+  </triggers>
+{#-
+  vim: syntax=jinja sw=2 ts=2
+-#}
diff --git a/jenkins/files/jobs/_parameters.xml b/jenkins/files/jobs/_parameters.xml
new file mode 100644
index 0000000..ed0fa56
--- /dev/null
+++ b/jenkins/files/jobs/_parameters.xml
@@ -0,0 +1,27 @@
+    {%- if job.param is defined %}
+    <hudson.model.ParametersDefinitionProperty>
+      <parameterDefinitions>
+        {%- for param_name, param in job.param.iteritems() %}
+        <hudson.model.{{ param.get('type', 'string')|capitalize }}ParameterDefinition>
+          <name>{{ param_name }}</name>
+          <description>{{ param.get('description', '')|e }}</description>
+          {%- if param.get('type', 'string')|lower == "choice" %}
+          <choices class="java.util.Arrays$ArrayList">
+            <a class="string-array">
+              {%- for choice in param.choices %}
+              <string>{{ choice|e }}</string>
+              {%- endfor %}
+            </a>
+          </choices>
+          {%- endif %}
+          {%- if param.default is defined %}
+          <defaultValue>{{ param.default|e }}</defaultValue>
+          {%- endif %}
+        </hudson.model.{{ param.get('type', 'string')|capitalize }}ParameterDefinition>
+        {%- endfor %}
+      </parameterDefinitions>
+    </hudson.model.ParametersDefinitionProperty>
+    {%- endif %}
+{#-
+  vim: syntax=jinja sw=2 ts=2
+-#}
diff --git a/jenkins/files/jobs/workflow-scm.xml b/jenkins/files/jobs/workflow-scm.xml
new file mode 100644
index 0000000..82c1d71
--- /dev/null
+++ b/jenkins/files/jobs/workflow-scm.xml
@@ -0,0 +1,37 @@
+{%- from "jenkins/map.jinja" import client with context -%}
+<?xml version='1.0' encoding='UTF-8'?>
+<flow-definition plugin="workflow-job@2.6">
+  {%- include "jenkins/files/jobs/_common.xml" %}
+  <definition class="org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition" plugin="workflow-cps@2.13">
+    {%- if job.scm.get('type', 'git') == 'git' %}
+    <scm class="hudson.plugins.git.GitSCM" plugin="git@2.5.3">
+      <configVersion>2</configVersion>
+      <userRemoteConfigs>
+        <hudson.plugins.git.UserRemoteConfig>
+          <url>{{ job.scm.url }}</url>
+        </hudson.plugins.git.UserRemoteConfig>
+      </userRemoteConfigs>
+      <branches>
+        {%- if job.scm.branches is defined %}
+        {%- for branch in job.scm.branches %}
+        <hudson.plugins.git.BranchSpec>
+          <name>{{ branch }}</name>
+        </hudson.plugins.git.BranchSpec>
+        {%- endfor %}
+        {%- else %}
+        <hudson.plugins.git.BranchSpec>
+          <name>{{ job.scm.branch|default('*/master') }}</name>
+        </hudson.plugins.git.BranchSpec>
+        {%- endif %}
+      </branches>
+      <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
+      <submoduleCfg class="list"/>
+      <extensions/>
+    </scm>
+    {%- endif %}
+    <scriptPath>{{ job.scm.script|default('Jenkinsfile') }}</scriptPath>
+  </definition>
+</flow-definition>
+{#-
+  vim: syntax=jinja sw=2 ts=2
+-#}
diff --git a/jenkins/files/jobs/workflow.xml b/jenkins/files/jobs/workflow.xml
index aab96e8..6757fc4 100644
--- a/jenkins/files/jobs/workflow.xml
+++ b/jenkins/files/jobs/workflow.xml
@@ -1,52 +1,17 @@
-<?xml version='1.0' encoding='UTF-8'?>
 {%- from "jenkins/map.jinja" import client with context -%}
-{%- set job = salt['pillar.get']('jenkins:client:job:'+job_name) -%}
 {%- macro load_groovy_file() %}
-{%- set groovy_file='_jenkins/jobs/'+job.script.repository+'/'+job.script.file %}
+{%- set groovy_file=client.dir.jenkins_jobs_root+'/'+job.script.repository+'/'+job.script.file %}
 {%- include groovy_file %}
 {%- endmacro %}
+
 {%- macro load_groovy_lib(lib) %}
-{%- set groovy_file='_jenkins/jobs/'+lib.repository+'/'+lib.file %}
+{%- set groovy_file=client.dir.jenkins_jobs_root+'/'+lib.repository+'/'+lib.file %}
 {%- include groovy_file %}
 {%- endmacro %}
+
+<?xml version='1.0' encoding='UTF-8'?>
 <flow-definition plugin="workflow-job@2.5">
-  <description>
-    Salt generated project, do not edit. Changes will be overwritten.
-    {{ job.get('description', '')|e }}
-  </description>
-  {%- if job.display_name is defined %}
-  <displayName>{{ job.display_name }}</displayName>
-  {%- endif %}
-  <keepDependencies>false</keepDependencies>
-  <properties>
-    <org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
-      <triggers/>
-    </org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
-    {%- if job.param is defined %}
-    <hudson.model.ParametersDefinitionProperty>
-      <parameterDefinitions>
-        {%- for param_name, param in job.param.iteritems() %}
-        <hudson.model.{{ client.param[param.type] }}ParameterDefinition>
-          <name>{{ param_name }}</name>
-          <description>{{ param.get('description', '')|e }}</description>
-          {%- if param.type == "choice" %}
-          <choices class="java.util.Arrays$ArrayList">
-            <a class="string-array">
-              {%- for choice in param.choices %}
-              <string>{{ choice|e }}</string>
-              {%- endfor %}
-            </a>
-          </choices>
-          {%- endif %}
-          {%- if param.default is defined %}
-          <defaultValue>{{ param.default|e }}</defaultValue>
-          {%- endif %}
-        </hudson.model.{{ client.param[param.type] }}ParameterDefinition>
-        {%- endfor %}
-      </parameterDefinitions>
-    </hudson.model.ParametersDefinitionProperty>
-    {%- endif %}
-  </properties>
+  {%- include "jenkins/files/jobs/_common.xml" %}
   <definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps@2.12">
     <script>// libraries
 {%- if job.libs is defined %}
@@ -64,6 +29,7 @@
     </script>
     <sandbox>true</sandbox>
   </definition>
-  <triggers>
-  </triggers>
 </flow-definition>
+{#-
+  vim: syntax=jinja sw=2 ts=2
+-#}
diff --git a/jenkins/init.sls b/jenkins/init.sls
index db523b2..3552b49 100644
--- a/jenkins/init.sls
+++ b/jenkins/init.sls
@@ -5,10 +5,10 @@
 {%- endif %}
 {%- if pillar.jenkins.slave is defined %}
 - jenkins.slave
+{%- endif %}
 {%- if pillar.jenkins.job_builder is defined %}
 - jenkins.job_builder
 {%- endif %}
 {%- if pillar.jenkins.client is defined %}
 - jenkins.client
 {%- endif %}
-{%- endif %}
diff --git a/jenkins/map.jinja b/jenkins/map.jinja
index 9197f65..5118998 100644
--- a/jenkins/map.jinja
+++ b/jenkins/map.jinja
@@ -60,15 +60,28 @@
     },
 }, merge=salt['pillar.get']('jenkins:slave')) %}
 
-{% set param = {'bool': 'Boolean', 'string': 'String', 'text': 'Text', 'choice': 'Choice'}  %}
+{% set job_status = {
+    'SUCCESS': {
+        'ordinal': '0',
+        'color': 'BLUE'
+    },
+    'UNSTABLE': {
+        'ordinal': '1',
+        'color': 'YELLOW'
+    },
+    'FAILURE': {
+        'ordinal': '2',
+        'color': 'RED'
+    }
+} %}
 
 {% set client = salt['grains.filter_by']({
     'default': {
         'pkgs': ['python-jenkins'],
-        'param': param,
+        'job_status': job_status,
         'dir': {
-            'salt_root': '/srv/salt/env/dev',
-            'jenkins_root': '/srv/jenkins/client',
+            'jenkins_source_root': '/var/cache/salt/minion/jenkins/source',
+            'jenkins_jobs_root': '/var/cache/salt/minion/jenkins/jobs',
         }
     },
 }, merge=salt['pillar.get']('jenkins:client')) %}