diff --git a/pom.xml b/pom.xml
index 872f6b01..d12c681b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -189,6 +189,19 @@
tests
test
+
+ io.jenkins
+ configuration-as-code
+
+
+ io.jenkins.configuration-as-code
+ test-harness
+
+
+ org.jenkins-ci.plugins.workflow
+ workflow-cps
+ compile
+
diff --git a/src/main/java/org/jenkinsci/plugins/workflow/job/PipelineItemConfigurator.java b/src/main/java/org/jenkinsci/plugins/workflow/job/PipelineItemConfigurator.java
new file mode 100644
index 00000000..5b4347bb
--- /dev/null
+++ b/src/main/java/org/jenkinsci/plugins/workflow/job/PipelineItemConfigurator.java
@@ -0,0 +1,60 @@
+package org.jenkinsci.plugins.workflow.job;
+
+import hudson.Extension;
+import hudson.model.Descriptor;
+import io.jenkins.plugins.casc.ConfigurationContext;
+import io.jenkins.plugins.casc.ConfiguratorException;
+import io.jenkins.plugins.casc.ItemConfigurator;
+import io.jenkins.plugins.casc.model.CNode;
+import io.jenkins.plugins.casc.model.Mapping;
+import jenkins.model.Jenkins;
+import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
+
+import java.io.IOException;
+
+@Extension
+public class PipelineItemConfigurator implements ItemConfigurator {
+
+ @Override
+ public String getName() {
+ return "pipeline";
+ }
+
+ @Override
+ public Class getTarget() {
+ return WorkflowJob.class;
+ }
+
+ @Override
+ public WorkflowJob configure(String name, CNode config, ConfigurationContext context) throws ConfiguratorException {
+ try {
+ Jenkins jenkins = Jenkins.get();
+ WorkflowJob job = (WorkflowJob) jenkins.getItem(name);
+
+ if (job == null) {
+ job = jenkins.createProject(WorkflowJob.class, name);
+ }
+
+ Mapping mapping = config.asMapping();
+
+ if (mapping.containsKey("description")) {
+ job.setDescription(mapping.getScalarValue("description"));
+ }
+
+ CNode definitionNode = mapping.get("definition");
+ if (definitionNode != null) {
+ Mapping defMapping = definitionNode.asMapping();
+ if (defMapping.containsKey("cps")) {
+ String script = defMapping.get("cps").asMapping().getScalarValue("script");
+ job.setDefinition(new CpsFlowDefinition(script, true));
+ }
+ }
+
+ job.save();
+ return job;
+
+ } catch (IOException | Descriptor.FormException e) {
+ throw new ConfiguratorException("Failed to configure pipeline: " + name, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/org/jenkinsci/plugins/workflow/job/PipelineItemConfiguratorTest.java b/src/test/java/org/jenkinsci/plugins/workflow/job/PipelineItemConfiguratorTest.java
new file mode 100644
index 00000000..9292013a
--- /dev/null
+++ b/src/test/java/org/jenkinsci/plugins/workflow/job/PipelineItemConfiguratorTest.java
@@ -0,0 +1,55 @@
+package org.jenkinsci.plugins.workflow.job;
+
+import io.jenkins.plugins.casc.ConfigurationAsCode;
+import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
+import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
+import jenkins.model.Jenkins;
+import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.Objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public class PipelineItemConfiguratorTest {
+
+ @Rule
+ public JenkinsConfiguredWithCodeRule j = new JenkinsConfiguredWithCodeRule();
+
+ @Test
+ @ConfiguredWithCode("create-pipeline.yaml")
+ public void shouldCreateNewPipeline() {
+ WorkflowJob job = (WorkflowJob) Jenkins.get().getItem("my-new-pipeline");
+
+ assertNotNull("Pipeline job should have been created by JCasC", job);
+ assertEquals("A brand new pipeline created by JCasC", job.getDescription());
+
+ assertTrue("Definition should be CpsFlowDefinition", job.getDefinition() instanceof CpsFlowDefinition);
+ CpsFlowDefinition definition = (CpsFlowDefinition) job.getDefinition();
+ assertEquals("node { echo 'Hello, JCasC!' }", definition.getScript());
+ assertTrue("Sandbox should be true", definition.isSandbox());
+ }
+
+ @Test
+ public void shouldUpdateExistingPipeline() throws Exception {
+ WorkflowJob existingJob = j.jenkins.createProject(WorkflowJob.class, "existing-pipeline");
+ existingJob.setDescription("Old Description");
+ existingJob.setDefinition(new CpsFlowDefinition("node { echo 'Old script' }", false));
+
+ ConfigurationAsCode.get().configure(
+ Objects.requireNonNull(getClass().getResource("update-pipeline.yaml")).toExternalForm()
+ );
+
+ WorkflowJob updatedJob = (WorkflowJob) Jenkins.get().getItem("existing-pipeline");
+
+ assertNotNull(updatedJob);
+ assertEquals("Updated description via JCasC", updatedJob.getDescription());
+
+ CpsFlowDefinition definition = (CpsFlowDefinition) updatedJob.getDefinition();
+ assertEquals("node { echo 'Updated script!' }", definition.getScript());
+ assertTrue("Sandbox should be reset to true", definition.isSandbox());
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/job/create-pipeline.yaml b/src/test/resources/org/jenkinsci/plugins/workflow/job/create-pipeline.yaml
new file mode 100644
index 00000000..92f6dd27
--- /dev/null
+++ b/src/test/resources/org/jenkinsci/plugins/workflow/job/create-pipeline.yaml
@@ -0,0 +1,7 @@
+items:
+ - pipeline:
+ name: "my-new-pipeline"
+ description: "A brand new pipeline created by JCasC"
+ definition:
+ cps:
+ script: "node { echo 'Hello, JCasC!' }"
\ No newline at end of file
diff --git a/src/test/resources/org/jenkinsci/plugins/workflow/job/update-pipeline.yaml b/src/test/resources/org/jenkinsci/plugins/workflow/job/update-pipeline.yaml
new file mode 100644
index 00000000..1a05428c
--- /dev/null
+++ b/src/test/resources/org/jenkinsci/plugins/workflow/job/update-pipeline.yaml
@@ -0,0 +1,7 @@
+items:
+ - pipeline:
+ name: "existing-pipeline"
+ description: "Updated description via JCasC"
+ definition:
+ cps:
+ script: "node { echo 'Updated script!' }"
\ No newline at end of file