diff --git a/src/main/java/com/cloudbees/hudson/plugins/folder/Folder.java b/src/main/java/com/cloudbees/hudson/plugins/folder/Folder.java
index fb4b84b6..bb4d9321 100644
--- a/src/main/java/com/cloudbees/hudson/plugins/folder/Folder.java
+++ b/src/main/java/com/cloudbees/hudson/plugins/folder/Folder.java
@@ -68,6 +68,9 @@
import org.kohsuke.stapler.StaplerResponse2;
import org.kohsuke.stapler.verb.POST;
+import com.cloudbees.hudson.plugins.folder.SaveAllJobsAction;
+
+
/**
* A mutable folder.
*/
@@ -414,7 +417,7 @@ public DescriptorImpl getDescriptor() {
@Override public void remove(TopLevelItem item) throws IOException, IllegalArgumentException {
items.remove(item.getName());
}
-
+
@Extension
public static class DescriptorImpl extends AbstractFolderDescriptor {
diff --git a/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsAction.java b/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsAction.java
new file mode 100644
index 00000000..f02972ce
--- /dev/null
+++ b/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsAction.java
@@ -0,0 +1,44 @@
+package com.cloudbees.hudson.plugins.folder;
+
+import hudson.model.Action;
+import hudson.model.Job;
+import java.io.IOException;
+import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerResponse;
+
+public class SaveAllJobsAction implements Action {
+
+ private final Folder folder;
+
+ public SaveAllJobsAction(Folder folder) {
+ this.folder = folder;
+ }
+
+ @Override
+ public String getIconFileName() {
+ return "save.png"; // small save icon
+ }
+
+ @Override
+ public String getDisplayName() {
+ return "Save All Jobs";
+ }
+
+ @Override
+ public String getUrlName() {
+ return "save-all-jobs";
+ }
+
+ // Called when the form is submitted
+ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException {
+ doSaveAll();
+ rsp.sendRedirect2("../"); // redirect back to folder page after saving
+ }
+
+ // Actual saving logic
+ public void doSaveAll() throws IOException {
+ for (Job, ?> job : folder.getAllJobs()) {
+ job.save();
+ }
+ }
+}
diff --git a/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsAction/index.jelly b/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsAction/index.jelly
new file mode 100644
index 00000000..0fe3df19
--- /dev/null
+++ b/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsAction/index.jelly
@@ -0,0 +1,12 @@
+
+
+
+
+ Save All Jobs in Folder
+
+
+
+
+
+
+
diff --git a/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsActionFactory.java b/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsActionFactory.java
new file mode 100644
index 00000000..94fd8bf7
--- /dev/null
+++ b/src/main/java/com/cloudbees/hudson/plugins/folder/SaveAllJobsActionFactory.java
@@ -0,0 +1,21 @@
+package com.cloudbees.hudson.plugins.folder;
+
+import hudson.Extension;
+import hudson.model.Action;
+import jenkins.model.TransientActionFactory;
+import java.util.Collection;
+import java.util.Collections;
+
+@Extension
+public class SaveAllJobsActionFactory extends TransientActionFactory {
+
+ @Override
+ public Class type() {
+ return Folder.class;
+ }
+
+ @Override
+ public Collection extends Action> createFor(Folder target) {
+ return Collections.singletonList(new SaveAllJobsAction(target));
+ }
+}
diff --git a/src/test/java/com/cloudbees/hudson/plugins/folder/FolderTest.java b/src/test/java/com/cloudbees/hudson/plugins/folder/FolderTest.java
index a2c8cd47..3ef1a511 100644
--- a/src/test/java/com/cloudbees/hudson/plugins/folder/FolderTest.java
+++ b/src/test/java/com/cloudbees/hudson/plugins/folder/FolderTest.java
@@ -29,6 +29,7 @@
import com.cloudbees.hudson.plugins.folder.health.FolderHealthMetricDescriptor;
import com.cloudbees.hudson.plugins.folder.properties.FolderCredentialsProvider;
import com.cloudbees.plugins.credentials.domains.DomainCredentials;
+import com.cloudbees.hudson.plugins.folder.SaveAllJobsAction;
import org.htmlunit.HttpMethod;
import org.htmlunit.WebRequest;
import org.htmlunit.html.*;
@@ -398,6 +399,19 @@ public void interruptOnDelete() throws Exception {
f.addAction(a);
assertNotNull(f.getAction(WhoAmI.class));
}
+
+ @Test public void testSaveAllJobsActionAppears() throws Exception {
+ Folder f = createFolder();
+ SaveAllJobsAction action = new SaveAllJobsAction(f);
+
+ // Check action is not null
+ assertNotNull(action);
+
+ // Check URL mapping and display name
+ assertEquals("save-all-jobs", action.getUrlName());
+ assertEquals("Save All Jobs", action.getDisplayName());
+ }
+
@Issue("JENKINS-32487")
@Test public void shouldAssignPropertyOwnerOnCreationAndReload() throws Exception {