Skip to content

Commit

Permalink
Merge pull request #2 from rjnichols/master
Browse files Browse the repository at this point in the history
JENKINS-16609:
New feature - only back up build results/artifacts on builds which are marked "Keep this build forever"
  • Loading branch information
tofuatjava committed Feb 2, 2013
2 parents 9b940cb + 8528287 commit 7bc0dc2
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 18 deletions.
Expand Up @@ -123,6 +123,7 @@ public void doSaveSettings(final StaplerRequest res, final StaplerResponse rsp,
@QueryParameter("cleanupDiff") final boolean cleanupDiff,
@QueryParameter("backupBuildResults") final boolean backupBuildResults,
@QueryParameter("backupBuildArchive") final boolean backupBuildArchive,
@QueryParameter("backupBuildsToKeepOnly") final boolean backupBuildsToKeepOnly,
@QueryParameter("backupUserContents") final boolean backupUserContents,
@QueryParameter("backupNextBuildNumber") final boolean backupNextBuildNumber,
@QueryParameter("waitForIdle") final boolean waitForIdle,
Expand All @@ -139,6 +140,7 @@ public void doSaveSettings(final StaplerRequest res, final StaplerResponse rsp,
plugin.setMoveOldBackupsToZipFile(moveOldBackupsToZipFile);
plugin.setBackupBuildResults(backupBuildResults);
plugin.setBackupBuildArchive(backupBuildArchive);
plugin.setBackupBuildsToKeepOnly(backupBuildsToKeepOnly);
plugin.setBackupUserContents(backupUserContents);
plugin.setBackupNextBuildNumber(backupNextBuildNumber);
plugin.setWaitForIdle(waitForIdle);
Expand Down
Expand Up @@ -53,6 +53,7 @@ public class ThinBackupPluginImpl extends Plugin {
private boolean backupBuildArchive = false;
private boolean backupUserContents = false;
private boolean backupNextBuildNumber = false;
private boolean backupBuildsToKeepOnly = false;

private static ThinBackupPluginImpl instance = null;

Expand Down Expand Up @@ -187,6 +188,14 @@ public boolean isBackupBuildArchive() {
return backupBuildArchive;
}

public void setBackupBuildsToKeepOnly(boolean backupBuildsToKeepOnly) {
this.backupBuildsToKeepOnly = backupBuildsToKeepOnly;
}

public boolean isBackupBuildsToKeepOnly() {
return backupBuildsToKeepOnly;
}

public void setBackupNextBuildNumber(final boolean backupNextBuildNumber) {
this.backupNextBuildNumber = backupNextBuildNumber;
}
Expand Down
Expand Up @@ -18,6 +18,11 @@

import hudson.PluginWrapper;
import hudson.model.Hudson;
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TopLevelItem;
import hudson.util.RunList;

import java.io.File;
import java.io.FileNotFoundException;
Expand Down Expand Up @@ -69,15 +74,17 @@ public class HudsonBackup {
private final BackupType backupType;
private final Date latestFullBackupDate;
private Pattern excludedFilesRegexPattern = null;
private ItemGroup<TopLevelItem> hudson;

public HudsonBackup(final ThinBackupPluginImpl plugin, final BackupType backupType) {
this(plugin, backupType, new Date());
this(plugin, backupType, new Date(), Hudson.getInstance());
}

/**
* package visible constructor for unit testing purposes only.
*/
protected HudsonBackup(final ThinBackupPluginImpl plugin, final BackupType backupType, final Date date) {
protected HudsonBackup(final ThinBackupPluginImpl plugin, final BackupType backupType, final Date date, ItemGroup<TopLevelItem> hudson) {
this.hudson = hudson;
this.plugin = plugin;
this.hudsonHome = plugin.getHudsonHome();

Expand Down Expand Up @@ -255,9 +262,10 @@ private void backupBuildsFor(final File jobDirectory, final File jobBackupDirect
if (buildsDir.exists() && buildsDir.isDirectory()) {
final Collection<String> builds = Arrays.asList(buildsDir.list());
if (builds != null) {
TopLevelItem job = hudson.getItem(jobDirectory.getName());
for (final String build : builds) {
final File srcDir = new File(buildsDir, build);
if (!isSymLinkFile(srcDir)) {
if (!isSymLinkFile(srcDir) && (!plugin.isBackupBuildsToKeepOnly() || isBuildToKeep(job, srcDir))) {
final File destDir = new File(new File(jobBackupDirectory, BUILDS_DIR_NAME), build);
backupBuildFiles(srcDir, destDir);
backupBuildArchive(srcDir, destDir);
Expand All @@ -267,7 +275,22 @@ private void backupBuildsFor(final File jobDirectory, final File jobBackupDirect
}
}
}


@SuppressWarnings({"unchecked", "rawtypes"})
private boolean isBuildToKeep(TopLevelItem item, File buildDir) {
if (item instanceof Job) {
Job job = (Job) item;
RunList<Run> builds = job.getBuilds();
for (Run run : builds) {
if (run.getRootDir().equals(buildDir)) {
return run.isKeepLog();
}
}
}
// default to true, in the case we can't resolve this folder in the Hudson instance
return true;
}

private void backupBuildFiles(final File srcDir, final File destDir) throws IOException {
final IOFileFilter changelogFilter = FileFilterUtils.andFileFilter(DirectoryFileFilter.DIRECTORY,
FileFilterUtils.nameFileFilter(CHANGELOG_HISTORY_PLUGIN_DIR_NAME));
Expand Down
Expand Up @@ -75,6 +75,10 @@
help="/plugin/thinBackup/help/help-backupBuildArchive.html"
checked="${it.configuration.backupBuildArchive}"
name="backupBuildArchive" />
<f:optionalBlock title="Backup only builds marked to keep"
help="/plugin/thinBackup/help/help-backupBuildToKeepOnly.html"
checked="${it.configuration.backupBuildsToKeepOnly}"
name="backupBuildsToKeepOnly" />
</f:optionalBlock>

<f:optionalBlock title="Backup 'userContent' folder"
Expand Down
29 changes: 29 additions & 0 deletions src/main/webapp/help/help-backupBuildToKeepOnly.html
@@ -0,0 +1,29 @@
<!--
The MIT License
Copyright (c) 2011, Borland (a Micro Focus Company), Matthias Steinkogler, Thomas Fuerer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->

<div>
<p>
If this option is enabled, only builds results/artifacts on builds which are marked "Keep this build forever" are backed up.
</p>
</div>
@@ -1,8 +1,8 @@
package org.jvnet.hudson.plugins.thinbackup.backup;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import hudson.model.ItemGroup;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
Expand All @@ -17,9 +17,10 @@
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPeriodicWork.BackupType;
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl;
import org.jvnet.hudson.plugins.thinbackup.utils.Utils;
import static org.mockito.Mockito.mock;

public class TestBackupMatrixJob {

private File backupDir;
private File jenkinsHome;

Expand Down Expand Up @@ -67,7 +68,7 @@ public void testFullBuildResultsBackup() throws IOException {

final ThinBackupPluginImpl mockPlugin = createMockPlugin();

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mock(ItemGroup.class)).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
Expand Down
@@ -1,5 +1,7 @@
package org.jvnet.hudson.plugins.thinbackup.backup;

import hudson.model.ItemGroup;

import java.io.File;
import java.io.IOException;
import java.util.Calendar;
Expand All @@ -14,6 +16,7 @@
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPeriodicWork.BackupType;
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl;
import org.jvnet.hudson.plugins.thinbackup.utils.Utils;
import static org.mockito.Mockito.mock;

public class TestBackupWithCloudBeesFolder {
private static final String TEST_FOLDER = "testFolder";
Expand Down Expand Up @@ -46,7 +49,7 @@ public void testCloudBeesFolderBackup() throws Exception {
cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE - 10));

final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mock(ItemGroup.class)).backup();

final File backup = new File(backupDir, backupDir.list()[0]);
File rootJobsFolder = new File(backup, HudsonBackup.JOBS_DIR_NAME);
Expand Down Expand Up @@ -75,7 +78,7 @@ public void testRecursiveFolderBackup() throws Exception {
cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE - 10));

final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mock(ItemGroup.class)).backup();

File subFolderJobsBackupDirectory = new File(backupDir, backupDir.list()[0]+"/jobs/"+TEST_FOLDER+"/jobs/subFolder/jobs");
String[] list = subFolderJobsBackupDirectory.list();
Expand Down
Expand Up @@ -16,13 +16,19 @@
*/
package org.jvnet.hudson.plugins.thinbackup.backup;

import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.ItemGroup;
import hudson.model.TopLevelItem;
import hudson.util.RunList;
import static org.mockito.Mockito.when;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

Expand All @@ -37,21 +43,25 @@
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPeriodicWork.BackupType;
import org.jvnet.hudson.plugins.thinbackup.ThinBackupPluginImpl;
import org.jvnet.hudson.plugins.thinbackup.utils.Utils;
import static org.mockito.Mockito.mock;

public class TestHudsonBackup {

private File backupDir;
private File jenkinsHome;
private File buildDir;
private ItemGroup<TopLevelItem> mockHudson;

@Before
public void setup() throws IOException {
mockHudson = mock(ItemGroup.class);

File base = new File(System.getProperty("java.io.tmpdir"));
backupDir = TestHelper.createBackupFolder(base);

jenkinsHome = TestHelper.createBasicFolderStructure(base);
File jobDir = TestHelper.createJob(jenkinsHome, TestHelper.TEST_JOB_NAME);
TestHelper.addNewBuildToJob(jobDir);

buildDir = TestHelper.addNewBuildToJob(jobDir);
}

@After
Expand All @@ -68,7 +78,7 @@ public void testBackup() throws Exception {

final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
Expand Down Expand Up @@ -100,7 +110,7 @@ public void testBackupWithExludes() throws Exception {
final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);
when(mockPlugin.getExcludedFilesRegex()).thenReturn("^.*\\.(log)$");

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
Expand Down Expand Up @@ -140,7 +150,7 @@ public void testBackupWithoutBuildResults() throws Exception {
final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);
when(mockPlugin.isBackupBuildResults()).thenReturn(false);

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
Expand All @@ -158,7 +168,7 @@ public void performHudsonDiffBackup(final ThinBackupPluginImpl mockPlugin) throw
final Calendar cal = Calendar.getInstance();
cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE - 10));

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

// fake modification
backupDir.listFiles((FileFilter) FileFilterUtils.prefixFileFilter(BackupType.FULL.toString()))[0]
Expand All @@ -168,7 +178,7 @@ public void performHudsonDiffBackup(final ThinBackupPluginImpl mockPlugin) throw
globalConfigFile.setLastModified(System.currentTimeMillis() - 60000 * 120);
}

new HudsonBackup(mockPlugin, BackupType.DIFF, new Date()).backup();
new HudsonBackup(mockPlugin, BackupType.DIFF, new Date(), mockHudson).backup();
}

@Test
Expand All @@ -190,7 +200,7 @@ public void testBackupNextBuildNumber() throws Exception {
final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);
when(mockPlugin.isBackupNextBuildNumber()).thenReturn(true);

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
Expand Down Expand Up @@ -222,7 +232,7 @@ public void testBackupArchive() throws Exception {
final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);
when(mockPlugin.isBackupBuildArchive()).thenReturn(true);

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime()).backup();
new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
Expand All @@ -246,4 +256,67 @@ public void testBackupArchive() throws Exception {
Assert.assertEquals(2, list.length);
}

@Test
public void testBackupKeptBuildsOnly_doNotKeep() throws Exception {
final Calendar cal = Calendar.getInstance();
cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE - 10));

final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);

when(mockPlugin.isBackupBuildsToKeepOnly()).thenReturn(true);

FreeStyleProject mockJob = mock(FreeStyleProject.class);
when(mockHudson.getItem(TestHelper.TEST_JOB_NAME)).thenReturn(mockJob);
FreeStyleBuild mockRun = mock(FreeStyleBuild.class);
when(mockJob.getBuilds()).thenReturn((RunList)RunList.fromRuns(Collections.singleton(mockRun)));
when(mockRun.getRootDir()).thenReturn(buildDir);

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
final File backup = new File(backupDir, list[0]);
list = backup.list();
Assert.assertEquals(6, list.length);

final File job = new File(new File(backup, HudsonBackup.JOBS_DIR_NAME), TestHelper.TEST_JOB_NAME);
list = job.list();
Assert.assertEquals(1, list.length);
Assert.assertEquals("config.xml", list[0]);
}

@Test
public void testBackupKeptBuildsOnly_keep() throws Exception {
final Calendar cal = Calendar.getInstance();
cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE - 10));

final ThinBackupPluginImpl mockPlugin = TestHelper.createMockPlugin(jenkinsHome, backupDir);

when(mockPlugin.isBackupBuildsToKeepOnly()).thenReturn(true);

FreeStyleProject mockJob = mock(FreeStyleProject.class);
when(mockHudson.getItem(TestHelper.TEST_JOB_NAME)).thenReturn(mockJob);
FreeStyleBuild mockRun = mock(FreeStyleBuild.class);
// for some reason Mockito has issues mocking this interface and so is is used to return true to isKeepLog()
when(mockRun.getWhyKeepLog()).thenReturn("x");
when(mockJob.getBuilds()).thenReturn((RunList)RunList.fromRuns(Collections.singleton(mockRun)));
when(mockRun.getRootDir()).thenReturn(buildDir);

new HudsonBackup(mockPlugin, BackupType.FULL, cal.getTime(), mockHudson).backup();

String[] list = backupDir.list();
Assert.assertEquals(1, list.length);
final File backup = new File(backupDir, list[0]);
list = backup.list();
Assert.assertEquals(6, list.length);

final File job = new File(new File(backup, HudsonBackup.JOBS_DIR_NAME), TestHelper.TEST_JOB_NAME);
final List<String> arrayList = Arrays.asList(job.list());
Assert.assertEquals(2, arrayList.size());
Assert.assertFalse(arrayList.contains(HudsonBackup.NEXT_BUILD_NUMBER_FILE_NAME));

final File build = new File(new File(job, HudsonBackup.BUILDS_DIR_NAME), TestHelper.CONCRET_BUILD_DIRECTORY_NAME);
list = build.list();
Assert.assertEquals(7, list.length);
}
}

0 comments on commit 7bc0dc2

Please sign in to comment.